Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unlayer/elements
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: unlayer/elements
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: dx/agent-friendly-props
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 10 commits
  • 20 files changed
  • 2 contributors

Commits on Jun 23, 2026

  1. fix(elements): pin image display width for Builder round-trip

    An explicit image width was emitted with autoWidth:true, so the Builder
    auto-sized the image to its natural width and dropped the intended width when
    the image was selected. Now an explicit width — passed inside `src`, as a flat
    `width=` prop, or via the `values.src` escape hatch — emits autoWidth:false +
    maxWidth:"<w>px", pinning the display width independent of the natural size.
    
    All user-provided src fields are merged (defensively; base.src may be a string),
    flat src props are no longer clobbered, an explicit maxWidth alone also pins, and
    an explicit autoWidth is honored. A string `values.src` is normalized to { url }
    before mapping so it is not character-spread when a flat src prop is also present.
    No explicit sizing stays responsive. Adds regression tests for the flat-prop and
    escape-hatch paths.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 23, 2026
    Configuration menu
    Copy the full SHA
    827c618 View commit details
    Browse the repository at this point in the history
  2. fix(elements): pin button width for Builder round-trip

    Same class as the image fix: an explicit button width set size.width but left
    size.autoWidth:true, so the Builder auto-sized the button to its content and
    dropped the width on selection. The pin now reads the mapped size (covering the
    flat prop, nested prop, and `values` escape hatch) and sets size.autoWidth:false
    when a width is present, unless the user set autoWidth themselves. The size is
    guarded as a plain object before mutation so a malformed escape-hatch value is
    ignored rather than throwing. Adds regression tests.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 23, 2026
    Configuration menu
    Copy the full SHA
    d6d85e8 View commit details
    Browse the repository at this point in the history
  3. fix(elements): let an explicit maxWidth win over a natural width

    src={{ url, width: 1600, maxWidth: "50%" }} serialized to maxWidth:"1600px",
    clobbering the caller's display width. width is the natural size and maxWidth is
    the display size, so an explicit maxWidth must take precedence — derive maxWidth
    from the numeric width only when no maxWidth was provided. Adds a regression test.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 23, 2026
    Configuration menu
    Copy the full SHA
    58e150a View commit details
    Browse the repository at this point in the history

Commits on Jun 24, 2026

  1. feat(elements): normalize CSS-idiom prop values so natural forms render

    Authors (human and AI) reach for CSS habits that type-check but render blank or
    invalid because flat props are loosely typed. mapSemanticProps now coerces the
    natural form to the shape the exporters expect:
    - fontFamily: "Arial" -> { label, value } (a bare string was char-spread into
      the fontFamily group, dropping the font entirely)
    - fontWeight: "700" -> 700 (keyword strings like "bold" are left as-is)
    - fontSize / padding / borderRadius: bare number or unit-less string -> "<n>px"
    - lineHeight: 1.4 -> "1.4"
    
    Image sizing now accepts CSS-style width: a px string ("300px") and bare number
    pin the display width (autoWidth:false + maxWidth), and a percent ("50%") routes
    to the display maxWidth. Previously only a numeric width pinned, so width="300px"
    silently rendered full-width and re-triggered the select-resize round-trip.
    
    Runtime only; the types are tightened separately. Full suite green.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    e0e7d7d View commit details
    Browse the repository at this point in the history
  2. feat(elements): agent-friendly prop types for the natural authoring f…

    …orms
    
    The public prop types were generated from the canonical model, so the flattened
    semantic props were typed `any` (wrong forms type-checked and rendered broken)
    while the strict object forms rejected the documented/working code. Replace the
    `any` flat keys via Omit + re-declare with the real accepted unions:
    
    - Image `src` accepts a plain URL string or the value object; `width`/`maxWidth`
      accept a number, px, or percent.
    - Text components accept fontFamily as a string or { label, value }, fontWeight
      as a number/numeric-string/keyword, fontSize/lineHeight as number or string.
    - Heading gains the `level` alias and h1–h6 (was h1–h4); Paragraph types `text`.
    
    These pair with the runtime normalization so the natural form type-checks AND
    renders correctly, and clear garbage is now rejected. Adds dx-contract.test.tsx,
    a tsc-enforced guard (@ts-expect-error) over the should-pass / should-fail forms.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    34760dc View commit details
    Browse the repository at this point in the history
  3. fix(elements): make Table columns/rows render an empty grid instead o…

    …f crashing
    
    The documented numeric API (columns/rows) type-checked but crashed: the flat
    `rows` prop collided with the nested `table.rows` data key, so the exporter
    iterated a number. Intercept `columns`/`rows` in the propMapper (like
    headers/data), set the top-level counts, and build an empty columns x rows grid
    when no data is given. headers/data shorthand is unchanged.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    a936328 View commit details
    Browse the repository at this point in the history
  4. docs(elements): document the accepted natural prop forms; add Spotify…

    … example
    
    The README previously listed the CSS-idiom forms (string fontFamily, string
    fontWeight, numeric fontSize, padding "0", Paragraph text) as mistakes — they now
    work, so the guidance was actively steering authors away from working code.
    Updated the Critical Rules and Common Mistakes, and noted the recommended forms.
    Adds a Spotify Premium welcome story written in the natural form (string src +
    width="300px") as a living example.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    e20a4cd View commit details
    Browse the repository at this point in the history
  5. fix(elements): treat Image width/maxWidth "100%" as responsive, not p…

    …inned
    
    A "100%" display width means fill-the-container (the default responsive image
    behavior), so it should map to autoWidth:true rather than being pinned with
    autoWidth:false. Smaller percents and px widths still pin (autoWidth:false).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    40e9d26 View commit details
    Browse the repository at this point in the history
  6. feat(elements): loosen container padding type; add four agent example…

    … stories
    
    Reconstructing the fresh-agent example templates surfaced one more footgun: an
    idiomatic multi-value padding with a bare 0 token ("0 48px", "8px 40px 0 40px")
    was type-rejected because the canonical padding type requires px on every token,
    even though it is valid CSS and renders fine. Loosen padding/containerPadding on
    Row/Column/Body to SizeInput (string | number) via Omit + re-declare.
    
    Adds four example stories under src/examples/ (Airbnb, Stripe, Nike, Linear)
    written in the natural authoring forms, as living proof the DX holds end to end.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    d802100 View commit details
    Browse the repository at this point in the history
  7. fix(elements): handle JSX children, flat Column borders, and previewT…

    …ext round-trip
    
    Three medium-severity gaps from the DX audit:
    - JSX/element children on text components stringified to "[object Object]".
      Flatten the children tree to its text content (framework-free duck-typing) so
      e.g. <Heading>Hi <b>x</b></Heading> renders "Hi x" instead of garbage. Use the
      `html` prop for inline formatting.
    - Flat Column border props (borderTopWidth, …) were dropped because the Column
      default ships an empty `border: {}` the nested-group detector can't read. Gather
      flat border-side props into `border` when the component declares that field.
    - previewText was excluded from renderToJson, so it never round-tripped to the
      editor. Map it to the schema's preheaderText in the body JSON.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    ivoIturrieta and claude committed Jun 24, 2026
    Configuration menu
    Copy the full SHA
    c81afda View commit details
    Browse the repository at this point in the history
Loading