diff --git a/.gitignore b/.gitignore index accf480170221..a2f5d1577607e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ npm-debug.log # Ignore Mac files .DS_Store +.claude/playwright-* # Ignore Visual Studio project and settings files *.sln *.suo diff --git a/packages/main/FIGMA_CODE_CONNECT_FINDINGS.md b/packages/main/FIGMA_CODE_CONNECT_FINDINGS.md new file mode 100644 index 0000000000000..c4802d40ef1b9 --- /dev/null +++ b/packages/main/FIGMA_CODE_CONNECT_FINDINGS.md @@ -0,0 +1,155 @@ +# Figma Code Connect — what doesn't work / what's assumed + +## How to connect a component (setup + runbook) + +**Figma file:** SAP Web UI Kit — fileKey `SILcWzK5uFghKun9jx6D7c`. +**Everything below runs from `packages/main`.** + +### One-time setup + +**1. Clone the repo and install** (from the repo root): +``` +git clone https://github.com/UI5/webcomponents.git +cd webcomponents +yarn # installs all workspace deps +``` +> On the branch that carries this Code Connect work, `@figma/code-connect` and the +> config files are already present (skip steps 2–3). On a clean `main` checkout +> they are **not** — do steps 2–3 first. + +**2. Add the Code Connect dependency** to `packages/main` (only if not already there): +``` +cd packages/main +yarn add -D @figma/code-connect # this repo uses ^1.4.9 +``` + +**3. Create the two config files** in `packages/main`, one per label: + +`figma.config.json` (Web Components): +```jsonc +{ "codeConnect": { + "include": ["src/**/*.figma.ts"], "exclude": ["node_modules/**", "dist/**"], + "parser": "html", "label": "Web Components" } } +``` +`figma.config.react.json` (React): +```jsonc +{ "codeConnect": { + "include": ["src/**/*.figma.tsx"], "exclude": ["node_modules/**", "dist/**"], + "parser": "react", "label": "React" } } +``` + +**4. Generate a Figma token:** figma.com → **profile → Settings → Security → +Personal access tokens → Generate**. Scope: file content read/write for Code +Connect. Keep it out of git; pass it inline (`FIGMA_ACCESS_TOKEN=…`) or export it. + +### Per component + +**5. Create the two mapping files** in `packages/main/src/`: +- `src/.figma.ts` (Web Components) and `src/.figma.tsx` (React) — + each a single `figma.connect(, { props, example })`. +- Get the node id from the Figma URL (`?node-id=1-2` → `1:2`). To scaffold a + starter pre-filled with the node's readable props: + ``` + FIGMA_ACCESS_TOKEN= npx figma connect create "" --outDir /tmp/cc + ``` + +**6. Dry-run** (no token — catches parser errors): +``` +npx figma connect publish --dry-run -c figma.config.json +npx figma connect publish --dry-run -c figma.config.react.json +``` + +**7. Publish** (needs the token; run from `packages/main`): +``` +FIGMA_ACCESS_TOKEN= npx figma connect publish -c figma.config.json --force +FIGMA_ACCESS_TOKEN= npx figma connect publish -c figma.config.react.json --force +``` +- `--force` overwrites any pre-existing (UI-created) mapping on the node. +- ⚠️ MUST run from `packages/main` — from the repo root the CLI can't find the + config and silently falls back to the html parser. Always confirm the output + says `Using label "React"` (not "Web Components") for the React publish. + +**8. Verify in Figma Dev Mode** — parsing/upload success ≠ correct output. Open +the node, check the real snippet under each framework label. + +**Connected so far (11, both WC + React):** +Button `91702:11733` · Input `148569:1004` · CheckBox `154589:905` · +RadioButton `154597:1967` · StepInput `148569:1727` · MessageStrip `910:2517` · +Select `181557:7507` · SegmentedButton `91702:11986` · Switch `24087:10369` · +Link `187:305` · Avatar `573:3623`. +(Icon `983:5876` is unpublishable — a plain frame, not a component set.) + +## ⚠️ Global: reading the swapped icon (nuanced — tested) +In Figma an icon is an **INSTANCE_SWAP** property — the designer swaps in an icon +*component* from the library. What Code Connect can and can't do with it: + +- **As a name STRING → NO.** `figma.string`/`figma.enum` cannot read which + component was swapped in. So attribute-style icons (`icon="globe"`, `endIcon=`, + `fallback-icon=`) can't be made dynamic this way and stay **hardcoded** + placeholders (`"globe"`, `"inspect"`, `"home"`, `"employee"`); consumer edits. +- **As an ELEMENT via `figma.instance()` → YES, conditionally.** If the icon + library is **Code-Connected** (each icon emits ``) AND the + host's icon instance carries a `mainComponent` link, `figma.instance("Icon")` + resolves the **selected** icon's element. **Tested:** ✅ worked on Button + (`` resolved); ❌ empty on MessageStrip (its instance + had no `mainComponent` link). Only fits **slot/child** placements — its output + is an element, not a bare string, so it still can't feed an `icon=` attribute. + +**Owner fixes:** (a) add an `Icon Name` **text property** alongside the swap → +`figma.string` reads it → works for the attribute cases; (b) **Code-Connect the +icon library** (generated, ~1400 entries) → `figma.instance` resolves the +element for slot cases on link-carrying hosts. + + +## 1. Button — ui5-button (node 91702:11733) +**Doesn't work:** +- badge `text` — **HARDCODED `"72"`, NOT read from Figma.** The count is in an unexposed nested layer; the snippet always emits `text="72"` and won't track the Figma number. *Owner fix: expose the count as a readable text prop.* + + +**Assumed (design rule):** +- badge `design` ← Form Factor: Compact → InlineText, Cozy → OverlayText (per kit owners). *Confirm by toggling Form Factor with a counter badge on.* + + +## 2. Input — ui5-input (node 148569:1004) +**Doesn't work:** +- `Content` (Placeholder vs Typed Text) — Figma-only display toggle; can't gate which text emits, so both `value` and `placeholder` are always emitted. + +## 3. Select — ui5-select (node 181557:7507) +**Doesn't work:** + +-`options` → placeholder options + + What: The generated always shows generic Option 1/2/3, + never the real dropdown choices from the design. + + Why: Options are slotted children (same as SegmentedButton labels). In Figma the Select is + drawn as a closed control — it's essentially an embedded Input showing the selected text, + with no readable list of the option values behind it. So there's nothing to read → fixed + placeholders. + +- `Drop-Down` (True/False) → Figma-only runtime open state + + Figma has a Drop-Down variant (closed vs open-showing-the-list). But "open/closed" is a + runtime interaction state, not a component property in code — you don't write as a design intent. So there's nothing meaningful to emit from it; it's a Figma-only + concept. + + +## 4. SegmentedButton — ui5-segmented-button (node 91702:11986) + +**Doesn't work:** + +- segment `labels` — the item text ("Option 1"…) lives in Figma slots (⿻ Text Segments), + which are light-DOM projection, not a readable property. So real labels can't be read → + placeholders. (Different from the icon issue: this is slotted content, not instance-swap.) +- selected `segment` — which segment is pressed isn't exposed as a readable prop at all, so I + just mark item 1 selected as a stand-in — it won't match the actually-selected one in the + design. + + +## 5. Avatar — ui5-avatar (node 573:3623) +**Doesn't work:** +- `image` slot — slotted image, not readable. +- `badge` slot ← Badge boolean — presence only, not content. + + diff --git a/packages/main/FIGMA_ICON_NAME_PROPOSAL.md b/packages/main/FIGMA_ICON_NAME_PROPOSAL.md new file mode 100644 index 0000000000000..2e038652477d9 --- /dev/null +++ b/packages/main/FIGMA_ICON_NAME_PROPOSAL.md @@ -0,0 +1,86 @@ +# Proposal: make icon names readable in Code Connect (SAP Web UI Kit) + +**Audience:** SAP Web UI Kit Figma owners + webcomponents/tooling team +**File:** SAP Web UI Kit, `SILcWzK5uFghKun9jx6D7c` +**Date:** 2026-08-13 + +## The problem + +Several components' Code Connect mappings (Button, Link, StepInput, Avatar, +SegmentedButton, MessageStrip) can detect that an icon is **present** — and often +**where** it sits (Link's Icon Position, Avatar's Type=Icon) — but they **cannot +emit which icon it is**. Every `icon=` / `endIcon=` / `fallback-icon=` in the +generated snippets is a **hardcoded placeholder** (`"globe"`, `"inspect"`, +`"home"`, `"employee"`, `"information"`) that the consumer must edit by hand. + +### Why (root cause) + +In Figma an icon is an **INSTANCE_SWAP** property — the designer swaps in an icon +*component* from the icon library. Code Connect's mapping primitives are: + +`figma.string` (reads a **text** property) · `figma.boolean` · `figma.enum` +(fixed lookup over known variant options) · `figma.instance` · `figma.children` +· `figma.textContent` · `figma.nestedProps`. + +**None of them return "the name of the component currently swapped into an +instance-swap slot" as a string.** The name is visible in Figma's UI and exists +as instance metadata (`mainComponentName`), but it is not exposed to the mapping +author through any `figma.*` call. `figma.string` only reads text fields, and the +icon is not a text field. So the mapping can toggle the attribute on/off but must +hardcode the value. + +## Two fixes (complementary) + +### Option A — add an `Icon Name` text property → **Figma owner, quick win** + +On each component that has an icon instance-swap, add a plain **text property** +(e.g. `Icon Name`) holding the icon's registry name. The mapping then reads it: + +```ts +icon: figma.string("Icon Name") // → icon="employee" dynamically +``` + +- **Pro:** trivial, pure Figma-side, unlocks dynamic icon names immediately. +- **Con:** duplicated data — the designer must keep the typed name in sync with + the icon actually swapped in, so it can drift. + +### Option B — Code-Connect the icon library → **webcomponents/tooling team, durable** + +Give **each icon component** in the kit its own tiny Code Connect entry whose only +output is its own registry name. Then, on any host component: + +```ts +icon: figma.instance("Icon") // resolves to the SELECTED icon's name +``` + +because `figma.instance` resolves a swapped instance **through that instance's own +Code Connect entry**. + +- **This is generated, not hand-written.** The kit already names each icon + instance by its icon (`mainComponentName: "information"`), and the icons package + already has the full name registry. A script iterates the icon set and emits one + `figma.connect()` per icon (each outputting its name), using the icon library's + Figma node IDs (from the Figma API). +- **Pro:** correct forever, zero designer effort, no drift. +- **Con:** ~1400 published connections (one-time), needs the icon library node IDs, + re-run the generator when the icon set changes. + +**Can we drive this from our own `@ui5/webcomponents-icons` package?** Yes — that +package is the source of truth for icon names, so it's the natural input to the +generator in Option B. The only Figma-side dependency is the mapping from each +icon name to its Figma component node ID, which the Figma API provides. + +## Recommendation + +- **Option A now** — one text property per component, immediate dynamic icons. +- **Option B as the durable solution** — generated from `@ui5/webcomponents-icons`, + owned by the webcomponents team, no drift. + +Until either lands, icon **presence/position** is mapped but the **name** is a +placeholder the consumer edits. + +## Same class of issue (for context) + +The badge **count** on Button (`text="72"`) is hardcoded for the same reason — it +lives in an unexposed nested layer, not a readable property. Exposing it as a +`Badge Count` text property (like Option A) would make it dynamic too. diff --git a/packages/main/figma.config.json b/packages/main/figma.config.json new file mode 100644 index 0000000000000..1f9362e1ad338 --- /dev/null +++ b/packages/main/figma.config.json @@ -0,0 +1,8 @@ +{ + "codeConnect": { + "include": ["src/**/*.figma.ts"], + "exclude": ["node_modules/**", "dist/**"], + "parser": "html", + "label": "Web Components" + } +} diff --git a/packages/main/figma.config.react.json b/packages/main/figma.config.react.json new file mode 100644 index 0000000000000..375f916fcfe1e --- /dev/null +++ b/packages/main/figma.config.react.json @@ -0,0 +1,8 @@ +{ + "codeConnect": { + "include": ["src/**/*.figma.tsx"], + "exclude": ["node_modules/**", "dist/**"], + "parser": "react", + "label": "React" + } +} diff --git a/packages/main/package.json b/packages/main/package.json index c27df482a3151..c0ddca34c1ccf 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -65,6 +65,7 @@ }, "devDependencies": { "@custom-elements-manifest/analyzer": "^0.10.10", + "@figma/code-connect": "^1.4.9", "@ui5/cypress-internal": "0.1.0", "@ui5/webcomponents-tools": "2.25.0-rc.0", "cypress": "15.18.1", diff --git a/packages/main/src/Avatar.figma.ts b/packages/main/src/Avatar.figma.ts new file mode 100644 index 0000000000000..74f4555226f3c --- /dev/null +++ b/packages/main/src/Avatar.figma.ts @@ -0,0 +1,84 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Avatar". + * Node: 573:3623. Emits . + * + * See FIGMA_CODE_CONNECT_FINDINGS.md § Avatar. Pseudo-states ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=573-3623", + { + props: { + // Size → size (1:1). + size: figma.enum("Size", { + XS: 'size="XS"', + S: 'size="S"', + M: 'size="M"', + L: 'size="L"', + XL: 'size="XL"', + }), + // Color axis → color-scheme. 1..10 → Accent1..Accent10; Transparent/ + // Placeholder map 1:1; Image/Tile have no color-scheme equivalent. + colorScheme: figma.enum("Color", { + "1": 'color-scheme="Accent1"', + "2": 'color-scheme="Accent2"', + "3": 'color-scheme="Accent3"', + "4": 'color-scheme="Accent4"', + "5": 'color-scheme="Accent5"', + "6": 'color-scheme="Accent6"', + "7": 'color-scheme="Accent7"', + "8": 'color-scheme="Accent8"', + "9": 'color-scheme="Accent9"', + "10": 'color-scheme="Accent10"', + Transparent: 'color-scheme="Transparent"', + Placeholder: 'color-scheme="Placeholder"', + Image: "", + Tile: "", + }), + // Content → shape. Person → Circle, Object → Square. + // VERIFIED by screenshot of node 573:3623: Person column renders circles, + // Object column renders squares. NOTE misalignment: in Figma shape is + // COUPLED to Content (content source), but in the WC `shape` is an + // INDEPENDENT prop — Figma can't express e.g. a square person avatar. + shape: figma.enum("Content", { + Person: 'shape="Circle"', + Object: 'shape="Square"', + }), + // Interaction State = Disabled → disabled. + disabled: figma.enum("Interaction State", { + Disabled: "disabled", + Regular: "", + Hover: "", + Active: "", + "Toggled Hover": "", + }), + // Initials text — the Figma Initials layer only exists on Type=Initials + // variants, so this resolves empty (attribute omitted) on Image/Icon. + initials: figma.string("✏️ Initials"), + // Type=Icon → icon="employee" (WC default). Icon NAME is a placeholder — + // Person/Object Icon are instance-swaps, not readable. Emitted only for + // the Icon type. + icon: figma.enum("Type", { + Icon: 'icon="employee"', + Image: "", + Initials: "", + }), + // Type=Image → slotted with a placeholder URL (the actual image + // fill isn't readable). Consumer swaps the src. + image: figma.enum("Type", { + Image: html``, + Icon: "", + Initials: "", + }), + // Badge boolean → slotted with placeholder icon="edit" + // (badge content isn't readable — presence only). + badge: figma.boolean("Badge", { + true: html``, + false: "", + }), + }, + example: ({ size, colorScheme, shape, disabled, initials, icon, image, badge }) => + html`${image}${badge}`, + } +); diff --git a/packages/main/src/Avatar.figma.tsx b/packages/main/src/Avatar.figma.tsx new file mode 100644 index 0000000000000..42fd4a45feae2 --- /dev/null +++ b/packages/main/src/Avatar.figma.tsx @@ -0,0 +1,74 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Avatar". + * Node 573:3623. Mirrors Avatar.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Avatar, AvatarBadge } from "@ui5/webcomponents-react"; + +figma.connect( + Avatar, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=573-3623", + { + props: { + size: figma.enum("Size", { + XS: "XS", + S: "S", + M: "M", + L: "L", + XL: "XL", + }), + colorScheme: figma.enum("Color", { + "1": "Accent1", + "2": "Accent2", + "3": "Accent3", + "4": "Accent4", + "5": "Accent5", + "6": "Accent6", + "7": "Accent7", + "8": "Accent8", + "9": "Accent9", + "10": "Accent10", + Transparent: "Transparent", + Placeholder: "Placeholder", + Image: undefined, + Tile: undefined, + }), + shape: figma.enum("Content", { + Person: "Circle", + Object: "Square", + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + Active: false, + "Toggled Hover": false, + }), + initials: figma.string("✏️ Initials"), + // Type=Icon → icon="employee" (WC default). Name is a placeholder — + // Person/Object Icon are instance-swaps, not readable. Icon type only. + icon: figma.enum("Type", { + Icon: "employee", + Image: undefined, + Initials: undefined, + }), + // Type=Image → slotted placeholder (actual fill not readable). + image: figma.enum("Type", { + Image: , + Icon: undefined, + Initials: undefined, + }), + // Badge boolean → placeholder (content not readable). + badge: figma.boolean("Badge", { + true: , + false: undefined, + }), + }, + example: ({ size, colorScheme, shape, disabled, initials, icon, image, badge }) => ( + + {image} + + ), + } +); diff --git a/packages/main/src/Button.figma.ts b/packages/main/src/Button.figma.ts new file mode 100644 index 0000000000000..2d4f70f3d5fe1 --- /dev/null +++ b/packages/main/src/Button.figma.ts @@ -0,0 +1,83 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Button". + * + * This maps the SAME Figma Button component set (node 91702:11733) that is + * already connected under the "React" label (@ui5/webcomponents-react) — but + * under the "Web Components" label. With both labels present, Figma Dev Mode + * shows a framework switcher (React / Web Components) on the Button. + * + * The snippet targets the framework-agnostic UI5 Web Component , + * usable from plain HTML, Angular, Vue, and React alike. + * + * Uses the single-argument figma.connect() signature: there is no code + * component to import, we render a custom-element tag from a template. + * + * HTML-parser rules (stricter than the React parser): + * - No inline conditionals/ternaries in the template — every attribute value + * is resolved to a final string inside `props` via figma.enum/figma.boolean. + * - Nested child elements (the badge) are provided as html`` partials so they + * render as real elements rather than escaped text. + * - The button label is a text *layer* named "Text", so it is read with + * figma.textContent (not figma.string, which expects a component property). + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=91702-11733", + { + props: { + // Button label — "Text" is a text layer, not a component property. + label: figma.textContent("Text"), + + // Figma "Type" variant → ui5-button `design` attribute. + design: figma.enum("Type", { + Primary: "Emphasized", + Secondary: "Default", + Tertiary: "Transparent", + Accept: "Positive", + Reject: "Negative", + Attention: "Attention", + }), + + // Only the "Disabled" interaction state emits the `disabled` attribute. + disabledAttr: figma.enum("Interaction State", { + Disabled: "disabled", + Regular: "", + Hover: "", + Down: "", + }), + + // Leading icon presence → `icon="…"`. + // LIMITATION: icon NAME hardcoded to "globe". Button takes the icon as a + // name-string attribute (icon="globe"), but Figma models it as an + // INSTANCE_SWAP. figma.instance() returns the icon ELEMENT (), + // not a bare string, so it can't feed icon="…". Only Option A (an + // `Icon Name` text prop + figma.string) makes this dynamic. See + // FIGMA_ICON_NAME_PROPOSAL.md. + iconAttr: figma.boolean("Icon Left", { + true: 'icon="globe"', + false: "", + }), + + // Counter badge → slotted . Counter Badge is a Figma + // VARIANT (True/False), NOT a boolean. + // design="OverlayText" HARDCODED: it CANNOT be driven by Form Factor — + // both a nested figma.enum in the template AND a cross-prop ${prop} ref + // emit VERBATIM (parser resolves neither inside a prop's template value). + // text="72" HARDCODED: count is in an unexposed nested layer, not readable. + counterBadge: figma.enum("Counter Badge", { + True: html``, + False: "", + }), + + // Attention badge → slotted attention dot. + // Attention Badge IS a real Figma BOOLEAN. + attentionBadge: figma.boolean("Attention Badge", { + true: html``, + false: "", + }), + }, + example: ({ label, design, disabledAttr, iconAttr, counterBadge, attentionBadge }) => + html`${label}${counterBadge}${attentionBadge}`, + } +); diff --git a/packages/main/src/Button.figma.tsx b/packages/main/src/Button.figma.tsx new file mode 100644 index 0000000000000..abd06a818e2eb --- /dev/null +++ b/packages/main/src/Button.figma.tsx @@ -0,0 +1,67 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Button". + * + * Same Figma node (91702:11733) and same prop mapping as the Web Components + * mapping in `Button.figma.ts`, but emitting @ui5/webcomponents-react syntax + * under the "React" label. With both labels present on the node, Figma Dev Mode + * shows a React / Web Components framework switcher. + * + * Published from this repo via `figma.config.react.json` (parser: "react"). + * The React parser only reads the import string — @ui5/webcomponents-react does + * not need to be installed here for publishing to succeed. + * + * NOTE: the same Figma-side limitations documented in FIGMA_CODE_CONNECT_FINDINGS.md + * apply here — the icon name and badge design/text are hardcoded because Figma + * does not expose them as readable properties. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Button, ButtonBadge, ButtonBadgeDesign } from "@ui5/webcomponents-react"; + +figma.connect( + Button, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=91702-11733", + { + props: { + // Button label — "Text" is a text layer, not a component property. + label: figma.textContent("Text"), + + // Figma "Type" variant → ui5 Button `design` prop. + design: figma.enum("Type", { + Primary: "Emphasized", + Secondary: "Default", + Tertiary: "Transparent", + Accept: "Positive", + Reject: "Negative", + Attention: "Attention", + }), + + // Only the "Disabled" interaction state sets `disabled`. + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + Down: false, + }), + + // Counter badge presence → child on the `badge` prop. + // Counter Badge is a Figma VARIANT (True/False), NOT a boolean — use + // figma.enum. design HARDCODED to OverlayText: it CANNOT be driven by + // Form Factor (a nested figma.enum emits verbatim). text="72" HARDCODED + // (count in unexposed nested layer, not readable). + // + // REACT ASYMMETRY: the `badge` prop references ONE Figma axis, so React + // drives it from Counter Badge only; the Attention Badge is NOT + // expressible here (WC emits both). See findings § Button. + badge: figma.enum("Counter Badge", { + True: , + False: undefined, + }), + }, + example: ({ label, design, disabled, badge }) => ( + + ), + } +); diff --git a/packages/main/src/CheckBox.figma.ts b/packages/main/src/CheckBox.figma.ts new file mode 100644 index 0000000000000..b2eaa03f5e8e7 --- /dev/null +++ b/packages/main/src/CheckBox.figma.ts @@ -0,0 +1,49 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Check Box". + * Node: 154589:905. Emits . + * + * Every readable Figma prop mapped; unmappable ones documented in + * FIGMA_CODE_CONNECT_FINDINGS.md § CheckBox. Form Factor + Hover ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=154589-905", + { + props: { + valueState: figma.enum("Value State", { + None: "", + Negative: 'value-state="Negative"', + Critical: 'value-state="Critical"', + Positive: 'value-state="Positive"', + Information: 'value-state="Information"', + }), + // Check → checked / indeterminate (Tristate = indeterminate). + checkAttr: figma.enum("Check", { + Checked: "checked", + Tristate: "indeterminate", + Unchecked: "", + }), + // Interaction State → disabled / readonly. + // "Display Only" has NO ui5-checkbox equivalent — approximated as readonly + // (documented in FIGMA_CODE_CONNECT_FINDINGS.md § CheckBox). + stateAttr: figma.enum("Interaction State", { + Disabled: "disabled", + "Read Only": "readonly", + "Display Only": "readonly", + Regular: "", + Hover: "", + }), + // Label switch gates the text: OFF → empty; ON → the typed ✏️ Text value. + // NOTE: the nested figma.string must be resolved into a PROP (below) and + // referenced as a plain ${text} placeholder — a figma.* call cannot live + // inside an html`` template literal (it would be emitted verbatim). + text: figma.boolean("Label", { + true: figma.string("✏️ Text"), + false: "", + }), + }, + example: ({ valueState, checkAttr, stateAttr, text }) => + html``, + } +); diff --git a/packages/main/src/CheckBox.figma.tsx b/packages/main/src/CheckBox.figma.tsx new file mode 100644 index 0000000000000..2638109e98abc --- /dev/null +++ b/packages/main/src/CheckBox.figma.tsx @@ -0,0 +1,62 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Check Box". Node 154589:905. + * Mirrors CheckBox.figma.ts under the "React" label. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { CheckBox } from "@ui5/webcomponents-react"; + +figma.connect( + CheckBox, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=154589-905", + { + props: { + valueState: figma.enum("Value State", { + None: undefined, + Negative: "Negative", + Critical: "Critical", + Positive: "Positive", + Information: "Information", + }), + checked: figma.enum("Check", { + Checked: true, + Tristate: false, + Unchecked: false, + }), + indeterminate: figma.enum("Check", { + Tristate: true, + Checked: false, + Unchecked: false, + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + "Read Only": false, + "Display Only": false, + }), + readonly: figma.enum("Interaction State", { + "Read Only": true, + "Display Only": true, + Regular: false, + Hover: false, + Disabled: false, + }), + // Label switch gates the text: OFF → text undefined; ON → typed ✏️ Text. + text: figma.boolean("Label", { + true: figma.string("✏️ Text"), + false: undefined, + }), + }, + example: ({ text, checked, indeterminate, valueState, disabled, readonly }) => ( + + ), + } +); diff --git a/packages/main/src/Icon.figma.ts.todo b/packages/main/src/Icon.figma.ts.todo new file mode 100644 index 0000000000000..72d935b104ddc --- /dev/null +++ b/packages/main/src/Icon.figma.ts.todo @@ -0,0 +1,23 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit icons. + * Node: 983:5876 (the "SAP Icons" frame). Emits . + * + * ⚠️ MAJOR LIMITATION: this frame contains ~1400 INDIVIDUAL icon components, + * one per icon (accept, add, employee, …). Code Connect connects a NODE to a + * snippet — it cannot read "which icon" into the `name` attribute from a single + * mapping. To make the icon name dynamic, EACH icon component must get its own + * figma.connect emitting its own name (best generated, ~1400 entries). + * This single mapping is a placeholder for the frame. See FIGMA_CODE_CONNECT.md + * § "Icon is not dynamic" — this is the same registry/instance-swap problem as + * the Button icon. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=983-5876", + { + props: {}, + // Placeholder name — cannot reflect the selected icon (see limitation). + example: () => html``, + } +); diff --git a/packages/main/src/Icons.figma.ts b/packages/main/src/Icons.figma.ts new file mode 100644 index 0000000000000..dd1dd4c0cad9c --- /dev/null +++ b/packages/main/src/Icons.figma.ts @@ -0,0 +1,33 @@ +/** + * PROTOTYPE (Option B): Code Connect entries for individual icons. + * + * Proves that connecting each icon component to emit its own name lets a host + * component read the SELECTED icon via figma.instance() — making icon names + * dynamic instead of hardcoded placeholders. + * + * Hand-written for a handful of icons as proof of concept. The parser requires + * a LITERAL URL per figma.connect (no loops/computed URLs), so the real thing + * would be GENERATED from @ui5/webcomponents-icons + the icon node IDs. + * See FIGMA_ICON_NAME_PROPOSAL.md. Icons live on page "❖ Iconography". + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=1095-2437", + { example: () => html`` } +); + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=1105-2390", + { example: () => html`` } +); + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=1105-2394", + { example: () => html`` } +); + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=1105-2344", + { example: () => html`` } +); diff --git a/packages/main/src/Input.figma.ts b/packages/main/src/Input.figma.ts new file mode 100644 index 0000000000000..7bea77e9f6421 --- /dev/null +++ b/packages/main/src/Input.figma.ts @@ -0,0 +1,55 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Input". + * Node: 148569:1004. Emits under the "Web Components" label. + * + * Every READABLE Figma property is mapped dynamically below. Properties that + * cannot be made dynamic are listed in FIGMA_CODE_CONNECT_FINDINGS.md § Input with the + * reason. Form Factor (Compact/Cozy) and the Hover/Active visual states are + * intentionally ignored (density is global in UI5; pseudo-states have no attr). + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=148569-1004", + { + props: { + // Value State → value-state (1:1). + valueState: figma.enum("Value State", { + None: "", + Negative: 'value-state="Negative"', + Critical: 'value-state="Critical"', + Positive: 'value-state="Positive"', + Information: 'value-state="Information"', + }), + // Interaction State → disabled / readonly (Regular/Hover/Active ignored). + stateAttr: figma.enum("Interaction State", { + Disabled: "disabled", + "Read Only": "readonly", + Regular: "", + Hover: "", + Active: "", + }), + // Text properties. + placeholder: figma.string("✏️ Placeholder"), + value: figma.string("✏️ Typed Text"), + // Value-state message text from the nested "Input Message Popover" + // instance. MUST be a TOP-LEVEL prop (not inlined in the template) — a + // figma.* call nested inside html`` emits verbatim. Referenced below as + // the plain resolved value ${msg.text}. + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + // CANNOT MAP (see FIGMA_CODE_CONNECT_FINDINGS.md § Input): + // - `Content` (Placeholder vs Typed Text) can't pick which text to emit, + // so both are emitted; + // - `Trailing Action`, `2nd Action` reference slotted icon content; + // - `Description Text` has no ui5-input attr. + // NOTE: the value-state message slot is ALWAYS emitted (can't be gated on + // the Message Popover boolean without re-breaking the text — gating + + // resolved-text can't coexist). The text only has meaningful content on + // variants where the popover exists; elsewhere it resolves to empty. + example: ({ valueState, stateAttr, placeholder, value, msg }) => + html`
${msg.text}
`, + } +); diff --git a/packages/main/src/Input.figma.tsx b/packages/main/src/Input.figma.tsx new file mode 100644 index 0000000000000..91f757c434fda --- /dev/null +++ b/packages/main/src/Input.figma.tsx @@ -0,0 +1,57 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Input". Node 148569:1004. + * Mirrors Input.figma.ts under the "React" label. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Input } from "@ui5/webcomponents-react"; + +figma.connect( + Input, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=148569-1004", + { + props: { + valueState: figma.enum("Value State", { + None: undefined, + Negative: "Negative", + Critical: "Critical", + Positive: "Positive", + Information: "Information", + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + Active: false, + "Read Only": false, + }), + readonly: figma.enum("Interaction State", { + "Read Only": true, + Regular: false, + Hover: false, + Active: false, + Disabled: false, + }), + placeholder: figma.string("✏️ Placeholder"), + value: figma.string("✏️ Typed Text"), + // Value-state message text from the nested "Input Message Popover" + // instance. MUST be a top-level prop (a figma.* call inlined in JSX emits + // verbatim) — referenced below as the resolved {msg.text}. + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + // NOTE: the value-state message slot is always emitted (can't be gated on + // the Message Popover boolean without re-breaking the resolved text). + example: ({ value, placeholder, valueState, disabled, readonly, msg }) => ( + {msg.text}} + /> + ), + } +); diff --git a/packages/main/src/Link.figma.ts b/packages/main/src/Link.figma.ts new file mode 100644 index 0000000000000..d48b7488fea50 --- /dev/null +++ b/packages/main/src/Link.figma.ts @@ -0,0 +1,42 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Link". + * Node: 187:305. Emits . + * + * See FIGMA_CODE_CONNECT_FINDINGS.md § Link. Pseudo-states (Hover/Visited/Down) ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=187-305", + { + props: { + // Type → design. Icon Link has no design equivalent → Default. + design: figma.enum("Type", { + Regular: "", + Emphasized: 'design="Emphasized"', + Subtle: 'design="Subtle"', + "Icon Link": "", + }), + // Interaction State = Disabled → disabled. + disabled: figma.enum("Interaction State", { + Disabled: "disabled", + Regular: "", + Hover: "", + Visited: "", + Down: "", + }), + // Link label text (default slot). + label: figma.textContent("Text"), + // Icon Position → icon (Left) / end-icon (Right). The icon NAME is a + // placeholder ("inspect", the kit's default) — the Icon instance-swap + // name isn't readable. Left→icon, Right→end-icon, N/A→neither. + iconAttr: figma.enum("Icon Position", { + Left: 'icon="inspect"', + Right: 'end-icon="inspect"', + "N/A": "", + }), + }, + example: ({ design, disabled, label, iconAttr }) => + html`${label}`, + } +); diff --git a/packages/main/src/Link.figma.tsx b/packages/main/src/Link.figma.tsx new file mode 100644 index 0000000000000..0564d2de396f8 --- /dev/null +++ b/packages/main/src/Link.figma.tsx @@ -0,0 +1,47 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Link". + * Node 187:305. Mirrors Link.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Link } from "@ui5/webcomponents-react"; + +figma.connect( + Link, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=187-305", + { + props: { + design: figma.enum("Type", { + Regular: "Default", + Emphasized: "Emphasized", + Subtle: "Subtle", + "Icon Link": "Default", + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + Visited: false, + Down: false, + }), + label: figma.textContent("Text"), + // Icon Position → icon (Left) / endIcon (Right). Name is a placeholder + // ("inspect") — the Icon instance-swap name isn't readable. + icon: figma.enum("Icon Position", { + Left: "inspect", + Right: undefined, + "N/A": undefined, + }), + endIcon: figma.enum("Icon Position", { + Right: "inspect", + Left: undefined, + "N/A": undefined, + }), + }, + example: ({ design, disabled, label, icon, endIcon }) => ( + + {label} + + ), + } +); diff --git a/packages/main/src/MessageStrip.figma.ts b/packages/main/src/MessageStrip.figma.ts new file mode 100644 index 0000000000000..bd46b970a9978 --- /dev/null +++ b/packages/main/src/MessageStrip.figma.ts @@ -0,0 +1,78 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Message Strip". + * Node: 910:2517. Emits . + * + * See FIGMA_CODE_CONNECT_FINDINGS.md § MessageStrip. Form Factor ignored. + * + * Design comes from TWO mutually-exclusive Figma axes: + * - "Value State" carries the 4 semantic designs (Information/Positive/ + * Critical/Negative); its "Indication Color" option defers to the Color axis. + * - "Color" carries the 20 custom colours as a single enum: Indication 1..10 → + * design="ColorSet1" color-scheme="1".."10", and 1b..10b → ColorSet2 + scheme. + * When a semantic state is selected, Color is "None" (empty); when a custom + * colour is selected, Value State is "Indication Color" (empty). So the two + * placeholders never both emit a `design`. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=910-2517", + { + props: { + // Semantic designs. "Indication Color" defers to the Color axis (empty here). + designSemantic: figma.enum("Value State", { + Information: 'design="Information"', + Positive: 'design="Positive"', + Critical: 'design="Critical"', + Negative: 'design="Negative"', + "Indication Color": "", + }), + // Custom colours: ColorSet1/2 + color-scheme 1..10 from a single axis. + designColorSet: figma.enum("Color", { + None: "", + "Indication 1": 'design="ColorSet1" color-scheme="1"', + "Indication 2": 'design="ColorSet1" color-scheme="2"', + "Indication 3": 'design="ColorSet1" color-scheme="3"', + "Indication 4": 'design="ColorSet1" color-scheme="4"', + "Indication 5": 'design="ColorSet1" color-scheme="5"', + "Indication 6": 'design="ColorSet1" color-scheme="6"', + "Indication 7": 'design="ColorSet1" color-scheme="7"', + "Indication 8": 'design="ColorSet1" color-scheme="8"', + "Indication 9": 'design="ColorSet1" color-scheme="9"', + "Indication 10": 'design="ColorSet1" color-scheme="10"', + "Indication 1b": 'design="ColorSet2" color-scheme="1"', + "Indication 2b": 'design="ColorSet2" color-scheme="2"', + "Indication 3b": 'design="ColorSet2" color-scheme="3"', + "Indication 4b": 'design="ColorSet2" color-scheme="4"', + "Indication 5b": 'design="ColorSet2" color-scheme="5"', + "Indication 6b": 'design="ColorSet2" color-scheme="6"', + "Indication 7b": 'design="ColorSet2" color-scheme="7"', + "Indication 8b": 'design="ColorSet2" color-scheme="8"', + "Indication 9b": 'design="ColorSet2" color-scheme="9"', + "Indication 10b": 'design="ColorSet2" color-scheme="10"', + }), + // Icon variant False → hide-icon. + hideIcon: figma.enum("Icon", { + False: "hide-icon", + True: "", + }), + // Close Button boolean False → hide-close-button. + hideClose: figma.boolean("Close Button", { + true: "", + false: "hide-close-button", + }), + // Message text — read the "Text Message" layer directly. + message: figma.textContent("Text Message"), + // Custom icon slot when Icon=True. Name is a placeholder ("information") — + // the Icon instance-swap name isn't readable. (figma.instance("Icon") was + // tried to resolve the real icon via Code-Connected icons — it emitted + // EMPTY, so the placeholder is kept. See FIGMA_ICON_NAME_PROPOSAL.md.) + iconSlot: figma.enum("Icon", { + True: html``, + False: "", + }), + }, + example: ({ designSemantic, designColorSet, hideIcon, hideClose, message, iconSlot }) => + html`${iconSlot}${message}`, + } +); diff --git a/packages/main/src/MessageStrip.figma.tsx b/packages/main/src/MessageStrip.figma.tsx new file mode 100644 index 0000000000000..9a2c056ed82f2 --- /dev/null +++ b/packages/main/src/MessageStrip.figma.tsx @@ -0,0 +1,77 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Message Strip". + * Node 910:2517. Mirrors MessageStrip.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + * + * NOTE (React vs WC asymmetry): the React parser requires each prop to be a + * single enum ref and cannot merge two axes into one `design` attribute, so + * `design` is driven by "Value State" only (Indication Color → ColorSet1) while + * `colorScheme` is made dynamic from the "Color" axis (1..10). ColorSet2 (the + * "…b" colours) is therefore NOT reachable in the React variant — the WC variant + * (MessageStrip.figma.ts) maps it fully via raw-string template fragments. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { MessageStrip, Icon } from "@ui5/webcomponents-react"; + +figma.connect( + MessageStrip, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=910-2517", + { + props: { + // Value State → design. "Indication Color" → ColorSet1 (ColorSet2 not reachable here). + design: figma.enum("Value State", { + Information: "Information", + Positive: "Positive", + Critical: "Critical", + Negative: "Negative", + "Indication Color": "ColorSet1", + }), + // Color axis → color-scheme "1".."10" (both the base and "…b" rows map to + // the same scheme number; the ColorSet1-vs-2 distinction is lost, see note). + colorScheme: figma.enum("Color", { + None: undefined, + "Indication 1": "1", + "Indication 2": "2", + "Indication 3": "3", + "Indication 4": "4", + "Indication 5": "5", + "Indication 6": "6", + "Indication 7": "7", + "Indication 8": "8", + "Indication 9": "9", + "Indication 10": "10", + "Indication 1b": "1", + "Indication 2b": "2", + "Indication 3b": "3", + "Indication 4b": "4", + "Indication 5b": "5", + "Indication 6b": "6", + "Indication 7b": "7", + "Indication 8b": "8", + "Indication 9b": "9", + "Indication 10b": "10", + }), + hideIcon: figma.enum("Icon", { + False: true, + True: false, + }), + hideCloseButton: figma.boolean("Close Button", { + true: false, + false: true, + }), + // Message text — read the "Text Message" layer directly. + message: figma.textContent("Text Message"), + // Custom icon slot when Icon=True. Name is a placeholder ("information") — + // the Icon instance-swap name isn't readable. + icon: figma.enum("Icon", { + True: , + False: undefined, + }), + }, + example: ({ design, colorScheme, hideIcon, hideCloseButton, message, icon }) => ( + + {message} + + ), + } +); diff --git a/packages/main/src/RadioButton.figma.ts b/packages/main/src/RadioButton.figma.ts new file mode 100644 index 0000000000000..16a0f107dbac8 --- /dev/null +++ b/packages/main/src/RadioButton.figma.ts @@ -0,0 +1,44 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Radio Button". + * Node: 154597:1967. Emits . + * + * Cleanest of the set — every Figma axis maps. See FIGMA_CODE_CONNECT_FINDINGS.md + * § RadioButton. Form Factor + Hover ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=154597-1967", + { + props: { + valueState: figma.enum("Value State", { + None: "", + Negative: 'value-state="Negative"', + Critical: 'value-state="Critical"', + Positive: 'value-state="Positive"', + Information: 'value-state="Information"', + }), + // Selected → checked. + checkedAttr: figma.enum("Selected", { + True: "checked", + False: "", + }), + // Interaction State → disabled / readonly. + stateAttr: figma.enum("Interaction State", { + Disabled: "disabled", + "Read Only": "readonly", + Regular: "", + Hover: "", + }), + // Label switch gates the text: OFF → empty; ON → the typed ✏️ Text value. + // Resolved into a PROP and referenced as ${text} — a figma.* call cannot + // live inside the html`` template literal. + text: figma.boolean("Label", { + true: figma.string("✏️ Text"), + false: "", + }), + }, + example: ({ valueState, checkedAttr, stateAttr, text }) => + html``, + } +); diff --git a/packages/main/src/RadioButton.figma.tsx b/packages/main/src/RadioButton.figma.tsx new file mode 100644 index 0000000000000..4dba4ba6e710c --- /dev/null +++ b/packages/main/src/RadioButton.figma.tsx @@ -0,0 +1,53 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Radio Button". + * Node 154597:1967. Mirrors RadioButton.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { RadioButton } from "@ui5/webcomponents-react"; + +figma.connect( + RadioButton, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=154597-1967", + { + props: { + valueState: figma.enum("Value State", { + None: undefined, + Negative: "Negative", + Critical: "Critical", + Positive: "Positive", + Information: "Information", + }), + checked: figma.enum("Selected", { + True: true, + False: false, + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + "Read Only": false, + }), + readonly: figma.enum("Interaction State", { + "Read Only": true, + Regular: false, + Hover: false, + Disabled: false, + }), + // Label switch gates the text: OFF → text undefined; ON → typed ✏️ Text. + text: figma.boolean("Label", { + true: figma.string("✏️ Text"), + false: undefined, + }), + }, + example: ({ text, checked, valueState, disabled, readonly }) => ( + + ), + } +); diff --git a/packages/main/src/SegmentedButton.figma.ts b/packages/main/src/SegmentedButton.figma.ts new file mode 100644 index 0000000000000..5585a3c024448 --- /dev/null +++ b/packages/main/src/SegmentedButton.figma.ts @@ -0,0 +1,60 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Segmented Button". + * Node: 91702:11986. Emits with slotted items. + * + * LIMITATIONS (see FIGMA_CODE_CONNECT_FINDINGS.md § SegmentedButton): + * - Item labels are placeholders — the real text lives in Figma slots + * (⿻ Text/Icon Segments), not readable. + * - Icon NAMES are placeholders ("home") — instance-swap, not readable. + * - `Type` (Text/Icon) IS readable and switches each item between text form + * and icon form. + * - The `selected` item can't be read from Figma; item 1 is marked selected + * as a representative default (does NOT reflect the actually-pressed segment). + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=91702-11986", + { + props: { + // Type → text-vs-icon form for the two always-present items. + // Item 1 keeps `selected` (representative default — not readable). + item1: figma.enum("Type", { + Text: html`Option 1`, + Icon: html``, + }), + item2: figma.enum("Type", { + Text: html`Option 2`, + Icon: html``, + }), + // 3rd/4th/5th optional segments — presence from booleans, form from Type. + thirdItem: figma.boolean("3rd Button", { + true: figma.enum("Type", { + Text: html`Option 3`, + Icon: html``, + }), + false: "", + }), + fourthItem: figma.boolean("4th Button", { + true: figma.enum("Type", { + Text: html`Option 4`, + Icon: html``, + }), + false: "", + }), + fifthItem: figma.boolean("5th Button", { + true: figma.enum("Type", { + Text: html`Option 5`, + Icon: html``, + }), + false: "", + }), + }, + example: ({ item1, item2, thirdItem, fourthItem, fifthItem }) => + html` + ${item1} + ${item2} + ${thirdItem}${fourthItem}${fifthItem} +`, + } +); diff --git a/packages/main/src/SegmentedButton.figma.tsx b/packages/main/src/SegmentedButton.figma.tsx new file mode 100644 index 0000000000000..fdd8165277419 --- /dev/null +++ b/packages/main/src/SegmentedButton.figma.tsx @@ -0,0 +1,57 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Segmented Button". + * Node 91702:11986. Mirrors SegmentedButton.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { SegmentedButton, SegmentedButtonItem } from "@ui5/webcomponents-react"; + +figma.connect( + SegmentedButton, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=91702-11986", + { + props: { + // Type → text-vs-icon form. Item 1 keeps `selected` (representative + // default — not readable from Figma). Icon names are placeholders + // ("home") — instance-swap, not readable. + item1: figma.enum("Type", { + Text: Option 1, + Icon: , + }), + item2: figma.enum("Type", { + Text: Option 2, + Icon: , + }), + thirdItem: figma.boolean("3rd Button", { + true: figma.enum("Type", { + Text: Option 3, + Icon: , + }), + false: undefined, + }), + fourthItem: figma.boolean("4th Button", { + true: figma.enum("Type", { + Text: Option 4, + Icon: , + }), + false: undefined, + }), + fifthItem: figma.boolean("5th Button", { + true: figma.enum("Type", { + Text: Option 5, + Icon: , + }), + false: undefined, + }), + }, + example: ({ item1, item2, thirdItem, fourthItem, fifthItem }) => ( + + {item1} + {item2} + {thirdItem} + {fourthItem} + {fifthItem} + + ), + } +); diff --git a/packages/main/src/Select.figma.ts b/packages/main/src/Select.figma.ts new file mode 100644 index 0000000000000..4814923856918 --- /dev/null +++ b/packages/main/src/Select.figma.ts @@ -0,0 +1,35 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Select". + * Node: 181557:7507. Emits . + * + * ⚠️ LARGELY UNMAPPABLE — see FIGMA_CODE_CONNECT_FINDINGS.md § Select. The only Figma + * axes are `Form Factor` (global density, ignored) and `Drop-Down` (open/closed + * popover — a runtime visual state, NOT a component prop). The options are a + * slotted Input instance with no readable option list. So there is nothing + * dynamic to map; this emits a representative static example. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=181557-7507", + { + props: { + // Value-state message text from the nested "Input Message Popover" + // instance (deeply nested under Drop-Down > Value Message). Same pattern + // as Input — top-level prop, referenced as the resolved ${msg.text}. + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + // Options are a slotted Input instance with no readable option list, so the + // options are representative placeholders. valueStateMessage slot is always + // emitted (text resolves empty on non-popover variants). + example: ({ msg }) => + html` + Option 1 + Option 2 + Option 3 +
${msg.text}
+
`, + } +); diff --git a/packages/main/src/Select.figma.tsx b/packages/main/src/Select.figma.tsx new file mode 100644 index 0000000000000..f72f3bae805e5 --- /dev/null +++ b/packages/main/src/Select.figma.tsx @@ -0,0 +1,28 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Select". Node 181557:7507. + * Mirrors Select.figma.ts. Largely static — see FIGMA_CODE_CONNECT_FINDINGS.md § Select. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Select, Option } from "@ui5/webcomponents-react"; + +figma.connect( + Select, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=181557-7507", + { + props: { + // Value-state message text from the nested "Input Message Popover" + // instance (top-level prop → resolved {msg.text}, same as Input). + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + example: ({ msg }) => ( + + ), + } +); diff --git a/packages/main/src/StepInput.figma.ts b/packages/main/src/StepInput.figma.ts new file mode 100644 index 0000000000000..6d6b44a0c3063 --- /dev/null +++ b/packages/main/src/StepInput.figma.ts @@ -0,0 +1,43 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Step Input". + * Node: 148569:1727. Emits . + * + * See FIGMA_CODE_CONNECT_FINDINGS.md § StepInput. Form Factor + Hover/Active ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=148569-1727", + { + props: { + valueState: figma.enum("Value State", { + None: "", + Negative: 'value-state="Negative"', + Critical: 'value-state="Critical"', + Positive: 'value-state="Positive"', + Information: 'value-state="Information"', + }), + stateAttr: figma.enum("Interaction State", { + Disabled: "disabled", + "Read Only": "readonly", + Regular: "", + Hover: "", + Active: "", + }), + // Numeric value (Figma stores it as a text prop). + value: figma.string("✏️ Value"), + // Value-state message text from the nested "Input Message Popover" + // instance (same pattern as Input). MUST be a top-level prop — a figma.* + // call inlined in the template emits verbatim. Referenced as ${msg.text}. + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + // CANNOT MAP (FIGMA_CODE_CONNECT_FINDINGS.md § StepInput): min/max/step are + // not in Figma; the +/- button icons are instance-swaps (registry problem). + // NOTE: valueStateMessage slot is always emitted (gating + resolved text + // can't coexist); text resolves empty on non-popover variants. + example: ({ valueState, stateAttr, value, msg }) => + html`
${msg.text}
`, + } +); diff --git a/packages/main/src/StepInput.figma.tsx b/packages/main/src/StepInput.figma.tsx new file mode 100644 index 0000000000000..9ea939199d623 --- /dev/null +++ b/packages/main/src/StepInput.figma.tsx @@ -0,0 +1,52 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Step Input". + * Node 148569:1727. Mirrors StepInput.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { StepInput } from "@ui5/webcomponents-react"; + +figma.connect( + StepInput, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=148569-1727", + { + props: { + valueState: figma.enum("Value State", { + None: undefined, + Negative: "Negative", + Critical: "Critical", + Positive: "Positive", + Information: "Information", + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + Active: false, + "Read Only": false, + }), + readonly: figma.enum("Interaction State", { + "Read Only": true, + Regular: false, + Hover: false, + Active: false, + Disabled: false, + }), + value: figma.string("✏️ Value"), + // Value-state message text from the nested "Input Message Popover" + // instance (top-level prop → resolved {msg.text}, same as Input). + msg: figma.nestedProps("Input Message Popover", { + text: figma.string("✏️ Text"), + }), + }, + example: ({ value, valueState, disabled, readonly, msg }) => ( + {msg.text}} + /> + ), + } +); diff --git a/packages/main/src/Switch.figma.ts b/packages/main/src/Switch.figma.ts new file mode 100644 index 0000000000000..136e5024dc531 --- /dev/null +++ b/packages/main/src/Switch.figma.ts @@ -0,0 +1,38 @@ +/** + * Web Components Code Connect mapping for the SAP Web UI Kit "Switch". + * Node: 24087:10369. Emits . + * + * See FIGMA_CODE_CONNECT_FINDINGS.md § Switch. Form Factor + pseudo-states ignored. + */ +import figma, { html } from "@figma/code-connect/html"; + +figma.connect( + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=24087-10369", + { + props: { + // Figma "Type" → design. Non-Semantic (neutral blue/grey ✓/dash icons) → + // Textual; Semantic (green ✓ / red ✗) → Graphical. NOTE: "Textual" does + // NOT mean text — with no textOn/textOff it still renders check/dash icons + // in blue/grey, which is exactly the Non-Semantic group. "Graphical" is + // the positive/negative-icon variant = Semantic. + design: figma.enum("Type", { + "Non-Semantic": 'design="Textual"', + Semantic: 'design="Graphical"', + }), + // Checked variant → checked. + checked: figma.enum("Checked", { + True: "checked", + False: "", + }), + // Interaction State = Disabled → disabled. + disabled: figma.enum("Interaction State", { + Disabled: "disabled", + Regular: "", + Hover: "", + }), + }, + // textOn/textOff aren't modelled in Figma — omitted. + example: ({ design, checked, disabled }) => + html``, + } +); diff --git a/packages/main/src/Switch.figma.tsx b/packages/main/src/Switch.figma.tsx new file mode 100644 index 0000000000000..51a3a8232a34d --- /dev/null +++ b/packages/main/src/Switch.figma.tsx @@ -0,0 +1,35 @@ +/** + * React Code Connect mapping for the SAP Web UI Kit "Switch". + * Node 24087:10369. Mirrors Switch.figma.ts. See FIGMA_CODE_CONNECT_FINDINGS.md. + */ +import figma from "@figma/code-connect/react"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { Switch } from "@ui5/webcomponents-react"; + +figma.connect( + Switch, + "https://www.figma.com/design/SILcWzK5uFghKun9jx6D7c/SAP-Web-UI-Kit?node-id=24087-10369", + { + props: { + // Figma "Type" → design. Non-Semantic (neutral ✓/dash icons) → Textual; + // Semantic (green ✓ / red ✗) → Graphical. "Textual" still renders icons + // in blue/grey when no textOn/textOff — matches the Non-Semantic group. + design: figma.enum("Type", { + "Non-Semantic": "Textual", + Semantic: "Graphical", + }), + checked: figma.enum("Checked", { + True: true, + False: false, + }), + disabled: figma.enum("Interaction State", { + Disabled: true, + Regular: false, + Hover: false, + }), + }, + example: ({ design, checked, disabled }) => ( + + ), + } +); diff --git a/yarn.lock b/yarn.lock index ae4c9acafe12c..9be9f40d1590c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -263,6 +263,19 @@ __metadata: languageName: node linkType: hard +"@asamuzakjp/css-color@npm:^3.2.0": + version: 3.2.0 + resolution: "@asamuzakjp/css-color@npm:3.2.0" + dependencies: + "@csstools/css-calc": "npm:^2.1.3" + "@csstools/css-color-parser": "npm:^3.0.9" + "@csstools/css-parser-algorithms": "npm:^3.0.4" + "@csstools/css-tokenizer": "npm:^3.0.3" + lru-cache: "npm:^10.4.3" + checksum: 10c0/a4bf1c831751b1fae46b437e37e8a38c0b5bd58d23230157ae210bd1e905fe509b89b7c243e63d1522d852668a6292ed730a160e21342772b4e5b7b8ea14c092 + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -2517,7 +2530,7 @@ __metadata: languageName: node linkType: hard -"@csstools/css-calc@npm:^2.1.4": +"@csstools/css-calc@npm:^2.1.3, @csstools/css-calc@npm:^2.1.4": version: 2.1.4 resolution: "@csstools/css-calc@npm:2.1.4" peerDependencies: @@ -2540,7 +2553,7 @@ __metadata: languageName: node linkType: hard -"@csstools/css-color-parser@npm:^3.1.0": +"@csstools/css-color-parser@npm:^3.0.9, @csstools/css-color-parser@npm:^3.1.0": version: 3.1.0 resolution: "@csstools/css-color-parser@npm:3.1.0" dependencies: @@ -4530,6 +4543,38 @@ __metadata: languageName: node linkType: hard +"@figma/code-connect@npm:^1.4.9": + version: 1.4.9 + resolution: "@figma/code-connect@npm:1.4.9" + dependencies: + boxen: "npm:5.1.1" + chalk: "npm:^4.1.2" + commander: "npm:^11.1.0" + compare-versions: "npm:^6.1.0" + cross-spawn: "npm:^7.0.3" + dotenv: "npm:^16.3.1" + fast-fuzzy: "npm:^1.12.0" + find-up: "npm:^5.0.0" + glob: "npm:^11.0.4" + jsdom: "npm:^24.1.1" + lodash: "npm:4.18.1" + minimatch: "npm:^9.0.3" + ora: "npm:^5.4.1" + parse5: "npm:^7.1.2" + prettier: "npm:^2.8.8" + prompts: "npm:^2.4.2" + strip-ansi: "npm:^6.0.0" + ts-morph: "npm:^27.0.0" + typescript: "npm:6.0.3" + undici: "npm:^7.19.1" + zod: "npm:3.25.58" + zod-validation-error: "npm:^3.2.0" + bin: + figma: bin/figma + checksum: 10c0/6ea62ed07490526190bb6b2bae70d0864a7799aa437572c757dbdfd4b00979d73928775432e5bc5db9009533b067a4196135a4c4242e43345cad5d844746cc7e + languageName: node + linkType: hard + "@github/catalyst@npm:^1.6.0": version: 1.6.0 resolution: "@github/catalyst@npm:1.6.0" @@ -7665,6 +7710,17 @@ __metadata: languageName: node linkType: hard +"@ts-morph/common@npm:~0.28.1": + version: 0.28.1 + resolution: "@ts-morph/common@npm:0.28.1" + dependencies: + minimatch: "npm:^10.0.1" + path-browserify: "npm:^1.0.1" + tinyglobby: "npm:^0.2.14" + checksum: 10c0/d51276d840997e0f8f83e04f8b1689135bb12588a7ddbed575f87848d5737eeae31e242685d6449de27573e8ed30892157fea643393cb875e175f2711200bc50 + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.9 resolution: "@tsconfig/node10@npm:1.0.9" @@ -9120,6 +9176,7 @@ __metadata: resolution: "@ui5/webcomponents@workspace:packages/main" dependencies: "@custom-elements-manifest/analyzer": "npm:^0.10.10" + "@figma/code-connect": "npm:^1.4.9" "@ui5/cypress-internal": "npm:0.1.0" "@ui5/webcomponents-base": "npm:2.25.0-rc.0" "@ui5/webcomponents-icons": "npm:2.25.0-rc.0" @@ -10151,7 +10208,7 @@ __metadata: languageName: node linkType: hard -"ansi-align@npm:^3.0.1": +"ansi-align@npm:^3.0.0, ansi-align@npm:^3.0.1": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" dependencies: @@ -10842,6 +10899,13 @@ __metadata: languageName: node linkType: hard +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + "base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -11027,6 +11091,22 @@ __metadata: languageName: node linkType: hard +"boxen@npm:5.1.1": + version: 5.1.1 + resolution: "boxen@npm:5.1.1" + dependencies: + ansi-align: "npm:^3.0.0" + camelcase: "npm:^6.2.0" + chalk: "npm:^4.1.0" + cli-boxes: "npm:^2.2.1" + string-width: "npm:^4.2.2" + type-fest: "npm:^0.20.2" + widest-line: "npm:^3.1.0" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4b8631b6794c80464d0c4ef78cd0e56257edd8cc4e6debf45fcc8ea4d20b069743d3fa78c9da7c9eee7e6a55fd43b22a0ecfc821c978d4f85b047dbaa9e72821 + languageName: node + linkType: hard + "boxen@npm:^6.2.1": version: 6.2.1 resolution: "boxen@npm:6.2.1" @@ -11078,6 +11158,24 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^2.0.2": + version: 2.1.2 + resolution: "brace-expansion@npm:2.1.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/5442ecab84045d21826268bc56c81a6ef4215327ee1f5ee153f67928e93f7a915d130ecec9966623143277fa3cce036ebb50020024bcc4d78853cdd6af9a19f8 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.5": + version: 5.0.7 + resolution: "brace-expansion@npm:5.0.7" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/4769109c3c082de178e449a371bcad50d51ab468f644bce2dd9188efe0cf0a080ed102105d7fc8577382cedc45bad7e6443a91bf3d8102264ee8cf927dbaf205 + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -11867,6 +11965,13 @@ __metadata: languageName: node linkType: hard +"cli-boxes@npm:^2.2.1": + version: 2.2.1 + resolution: "cli-boxes@npm:2.2.1" + checksum: 10c0/6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 + languageName: node + linkType: hard + "cli-boxes@npm:^3.0.0": version: 3.0.0 resolution: "cli-boxes@npm:3.0.0" @@ -12067,6 +12172,13 @@ __metadata: languageName: node linkType: hard +"code-block-writer@npm:^13.0.3": + version: 13.0.3 + resolution: "code-block-writer@npm:13.0.3" + checksum: 10c0/87db97b37583f71cfd7eced8bf3f0a0a0ca53af912751a734372b36c08cd27f3e8a4878ec05591c0cd9ae11bea8add1423e132d660edd86aab952656dd41fd66 + languageName: node + linkType: hard + "collapse-white-space@npm:^2.0.0": version: 2.1.0 resolution: "collapse-white-space@npm:2.1.0" @@ -12214,6 +12326,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^11.1.0": + version: 11.1.0 + resolution: "commander@npm:11.1.0" + checksum: 10c0/13cc6ac875e48780250f723fb81c1c1178d35c5decb1abb1b628b3177af08a8554e76b2c0f29de72d69eef7c864d12613272a71fabef8047922bc622ab75a179 + languageName: node + linkType: hard + "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -12301,6 +12420,13 @@ __metadata: languageName: node linkType: hard +"compare-versions@npm:^6.1.0": + version: 6.1.1 + resolution: "compare-versions@npm:6.1.1" + checksum: 10c0/415205c7627f9e4f358f571266422980c9fe2d99086be0c9a48008ef7c771f32b0fbe8e97a441ffedc3910872f917a0675fe0fe3c3b6d331cda6d8690be06338 + languageName: node + linkType: hard + "compress-commons@npm:^4.1.0": version: 4.1.1 resolution: "compress-commons@npm:4.1.1" @@ -13089,6 +13215,16 @@ __metadata: languageName: node linkType: hard +"cssstyle@npm:^4.0.1": + version: 4.6.0 + resolution: "cssstyle@npm:4.6.0" + dependencies: + "@asamuzakjp/css-color": "npm:^3.2.0" + rrweb-cssom: "npm:^0.8.0" + checksum: 10c0/71add1b0ffafa1bedbef6855db6189b9523d3320e015a0bf3fbd504760efb9a81e1f1a225228d5fa892ee58e56d06994ca372e7f4e461cda7c4c9985fe075f65 + languageName: node + linkType: hard + "cssstyle@npm:^4.2.1": version: 4.2.1 resolution: "cssstyle@npm:4.2.1" @@ -14043,6 +14179,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.3.1": + version: 16.6.1 + resolution: "dotenv@npm:16.6.1" + checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc + languageName: node + linkType: hard + "dotenv@npm:^16.5.0": version: 16.5.0 resolution: "dotenv@npm:16.5.0" @@ -14292,6 +14435,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10c0/ed836ddac5acb34341094eb495185d527bd70e8632b6c0d59548cbfa23defdbae70b96f9a405c82904efa421230b5b3fd2283752447d737beffd3f3e6ee74414 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0, env-paths@npm:^2.2.1": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -15626,6 +15776,15 @@ __metadata: languageName: node linkType: hard +"fast-fuzzy@npm:^1.12.0": + version: 1.12.0 + resolution: "fast-fuzzy@npm:1.12.0" + dependencies: + graphemesplit: "npm:^2.4.1" + checksum: 10c0/c4adb03b21472b655414c9cb4680f217790ae641a9974148f55f7778da9a2cac26325996073b1082f76da5ab0f11f845122a6f717a5a99329c17e12ba625f3d6 + languageName: node + linkType: hard + "fast-glob@npm:^3.1.1": version: 3.3.1 resolution: "fast-glob@npm:3.3.1" @@ -15991,6 +16150,19 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.0": + version: 4.0.6 + resolution: "form-data@npm:4.0.6" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + es-set-tostringtag: "npm:^2.1.0" + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff + languageName: node + linkType: hard + "form-data@npm:^4.0.1": version: 4.0.1 resolution: "form-data@npm:4.0.1" @@ -16696,6 +16868,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^11.0.4": + version: 11.1.0 + resolution: "glob@npm:11.1.0" + dependencies: + foreground-child: "npm:^3.3.1" + jackspeak: "npm:^4.1.1" + minimatch: "npm:^10.1.1" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^2.0.0" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/1ceae07f23e316a6fa74581d9a74be6e8c2e590d2f7205034dd5c0435c53f5f7b712c2be00c3b65bf0a49294a1c6f4b98cd84c7637e29453b5aa13b79f1763a2 + languageName: node + linkType: hard + "glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -16971,6 +17159,16 @@ __metadata: languageName: node linkType: hard +"graphemesplit@npm:^2.4.1": + version: 2.6.0 + resolution: "graphemesplit@npm:2.6.0" + dependencies: + js-base64: "npm:^3.6.0" + unicode-trie: "npm:^2.0.0" + checksum: 10c0/da90b1ec5dc82f8b70dac251573f44fe341d6c63aa02e2098cbc7678dec450397733de9069746461c97bd686a41775dda2deaed9d26348e5c97e5ebae470116c + languageName: node + linkType: hard + "gzip-size@npm:^6.0.0": version: 6.0.0 resolution: "gzip-size@npm:6.0.0" @@ -17159,6 +17357,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 + languageName: node + linkType: hard + "hast-util-from-parse5@npm:^6.0.0": version: 6.0.1 resolution: "hast-util-from-parse5@npm:6.0.1" @@ -17753,7 +17960,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.6": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.5, https-proxy-agent@npm:^7.0.6": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" dependencies: @@ -19195,6 +19402,13 @@ __metadata: languageName: node linkType: hard +"js-base64@npm:^3.6.0": + version: 3.9.1 + resolution: "js-base64@npm:3.9.1" + checksum: 10c0/5de18a23c249eac1dbbd78ad893bb36245684d099f4eeb3344734eb7e28b7817a0f5a7bd2a188dcc2d0f90324d20690b54e68edc49bb8087630abb55dbb17dd5 + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -19239,6 +19453,40 @@ __metadata: languageName: node linkType: hard +"jsdom@npm:^24.1.1": + version: 24.1.3 + resolution: "jsdom@npm:24.1.3" + dependencies: + cssstyle: "npm:^4.0.1" + data-urls: "npm:^5.0.0" + decimal.js: "npm:^10.4.3" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.2" + https-proxy-agent: "npm:^7.0.5" + is-potential-custom-element-name: "npm:^1.0.1" + nwsapi: "npm:^2.2.12" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.7.1" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.4" + w3c-xmlserializer: "npm:^5.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + ws: "npm:^8.18.0" + xml-name-validator: "npm:^5.0.0" + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + checksum: 10c0/e48b342afacd7418a23dac204a62deea729c50f4d072a7c04c09fd32355fdb4335f8779fa79fd0277a2dbeb2d356250a950955719d00047324b251233b11277f + languageName: node + linkType: hard + "jsdom@npm:^26.0.0": version: 26.0.0 resolution: "jsdom@npm:26.0.0" @@ -20027,6 +20275,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:4.18.1, lodash@npm:^4.17.23": + version: 4.18.1 + resolution: "lodash@npm:4.18.1" + checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 + languageName: node + linkType: hard + "lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.23 resolution: "lodash@npm:4.17.23" @@ -20034,13 +20289,6 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.23": - version: 4.18.1 - resolution: "lodash@npm:4.18.1" - checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 - languageName: node - linkType: hard - "log-symbols@npm:4.1.0, log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" @@ -21245,7 +21493,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.35, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -21378,6 +21626,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.0.1, minimatch@npm:^10.1.1": + version: 10.2.5 + resolution: "minimatch@npm:10.2.5" + dependencies: + brace-expansion: "npm:^5.0.5" + checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd + languageName: node + linkType: hard + "minimatch@npm:^10.0.3": version: 10.1.1 resolution: "minimatch@npm:10.1.1" @@ -21423,6 +21680,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^9.0.3": + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" + dependencies: + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 + languageName: node + linkType: hard + "minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" @@ -22297,6 +22563,13 @@ __metadata: languageName: node linkType: hard +"nwsapi@npm:^2.2.12": + version: 2.2.24 + resolution: "nwsapi@npm:2.2.24" + checksum: 10c0/9bc04ee9c7698f1b5506778d36f7382962f71667205d441d6a50f6180ee92328e770b76be78b907817ee103241b29984d3a17ae387e4723aebe0aeaed7a7c3a1 + languageName: node + linkType: hard + "nwsapi@npm:^2.2.16": version: 2.2.16 resolution: "nwsapi@npm:2.2.16" @@ -23015,6 +23288,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^0.2.5": + version: 0.2.9 + resolution: "pako@npm:0.2.9" + checksum: 10c0/79c1806ebcf325b60ae599e4d7227c2e346d7b829dc20f5cf24cef07c934079dc3a61c5b3c8278a2f7a190c4a613e343ea11e5302dbe252efd11712df4b6b041 + languageName: node + linkType: hard + "pako@npm:^2.1.0": version: 2.1.0 resolution: "pako@npm:2.1.0" @@ -23157,6 +23437,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.1.2": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: "npm:^6.0.0" + checksum: 10c0/7fd2e4e247e85241d6f2a464d0085eed599a26d7b0a5233790c49f53473232eb85350e8133344d9b3fd58b89339e7ad7270fe1f89d28abe50674ec97b87f80b5 + languageName: node + linkType: hard + "parse5@npm:^7.2.1": version: 7.2.1 resolution: "parse5@npm:7.2.1" @@ -23183,6 +23472,13 @@ __metadata: languageName: node linkType: hard +"path-browserify@npm:^1.0.1": + version: 1.0.1 + resolution: "path-browserify@npm:1.0.1" + checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66 + languageName: node + linkType: hard + "path-exists@npm:^2.0.0": version: 2.1.0 resolution: "path-exists@npm:2.1.0" @@ -24482,7 +24778,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.7.1, prettier@npm:^2.8.0": +"prettier@npm:^2.7.1, prettier@npm:^2.8.0, prettier@npm:^2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -26160,6 +26456,13 @@ __metadata: languageName: unknown linkType: soft +"rrweb-cssom@npm:^0.7.1": + version: 0.7.1 + resolution: "rrweb-cssom@npm:0.7.1" + checksum: 10c0/127b8ca6c8aac45e2755abbae6138d4a813b1bedc2caabf79466ae83ab3cfc84b5bfab513b7033f0aa4561c7753edf787d0dd01163ceacdee2e8eb1b6bf7237e + languageName: node + linkType: hard + "rrweb-cssom@npm:^0.8.0": version: 0.8.0 resolution: "rrweb-cssom@npm:0.8.0" @@ -27327,7 +27630,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -27970,6 +28273,13 @@ __metadata: languageName: node linkType: hard +"tiny-inflate@npm:^1.0.0": + version: 1.0.3 + resolution: "tiny-inflate@npm:1.0.3" + checksum: 10c0/fab687537254f6ec44c9a2e880048fe70da3542aba28f73cda3e74c95cabf342a339372f2a6c032e322324f01accc03ca26c04ba2bad9b3eb8cf3ee99bba7f9b + languageName: node + linkType: hard + "tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.3.3": version: 1.3.3 resolution: "tiny-invariant@npm:1.3.3" @@ -28150,7 +28460,7 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:^4.1.3": +"tough-cookie@npm:^4.1.3, tough-cookie@npm:^4.1.4": version: 4.1.4 resolution: "tough-cookie@npm:4.1.4" dependencies: @@ -28256,6 +28566,16 @@ __metadata: languageName: node linkType: hard +"ts-morph@npm:^27.0.0": + version: 27.0.2 + resolution: "ts-morph@npm:27.0.2" + dependencies: + "@ts-morph/common": "npm:~0.28.1" + code-block-writer: "npm:^13.0.3" + checksum: 10c0/224715cc6d97b8ff5afd3986f9629f912a0ebd83eaecbdca91c35cf10a98f607c663f666e7ea5e6afab00563d00dc80fa7a13552cc7f1cef735261c3217d0863 + languageName: node + linkType: hard + "ts-node@npm:^10.8.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" @@ -28661,6 +28981,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:6.0.3": + version: 6.0.3 + resolution: "typescript@npm:6.0.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 + languageName: node + linkType: hard + "typescript@npm:>=3 < 6": version: 5.5.2 resolution: "typescript@npm:5.5.2" @@ -28701,6 +29031,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A6.0.3#optional!builtin": + version: 6.0.3 + resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A>=3 < 6#optional!builtin": version: 5.5.2 resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin::version=5.5.2&hash=379a07" @@ -28798,6 +29138,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:^7.19.1": + version: 7.28.0 + resolution: "undici@npm:7.28.0" + checksum: 10c0/fe781983a26098795e99bb1f64906cbb7d0bcaa029a26baade007b53ea67f2631d189b8f9671a31f4c8d0cb3773b7559608628ba54452fef51fec90e7c78bb0d + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -28843,6 +29190,16 @@ __metadata: languageName: node linkType: hard +"unicode-trie@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-trie@npm:2.0.0" + dependencies: + pako: "npm:^0.2.5" + tiny-inflate: "npm:^1.0.0" + checksum: 10c0/2422368645249f315640a1c9e9506046aa7738fc9c5d59e15c207cdd6ec66101c35b0b9f75dc3ac28fe7be19aaf1efc898bbea074fa1e8e295ef736aeb7904bb + languageName: node + linkType: hard + "unicorn-magic@npm:^0.1.0": version: 0.1.0 resolution: "unicorn-magic@npm:0.1.0" @@ -30329,6 +30686,15 @@ __metadata: languageName: node linkType: hard +"widest-line@npm:^3.1.0": + version: 3.1.0 + resolution: "widest-line@npm:3.1.0" + dependencies: + string-width: "npm:^4.0.0" + checksum: 10c0/b1e623adcfb9df35350dd7fc61295d6d4a1eaa65a406ba39c4b8360045b614af95ad10e05abf704936ed022569be438c4bfa02d6d031863c4166a238c301119f + languageName: node + linkType: hard + "widest-line@npm:^4.0.1": version: 4.0.1 resolution: "widest-line@npm:4.0.1" @@ -30844,6 +31210,22 @@ __metadata: languageName: node linkType: hard +"zod-validation-error@npm:^3.2.0": + version: 3.5.4 + resolution: "zod-validation-error@npm:3.5.4" + peerDependencies: + zod: ^3.24.4 + checksum: 10c0/fccfe09fc27d4d6ba59beab8eeee06a27befc0f491ec81a2951d7b82e7a08eca07bc74ef4fff82586fc7710a3ef777ec607c685defa06c70cd11849af0b9882c + languageName: node + linkType: hard + +"zod@npm:3.25.58": + version: 3.25.58 + resolution: "zod@npm:3.25.58" + checksum: 10c0/3525e9104adcb84b48ff2c166a44175e2f4fd502bcab045bde7cb898097a3ff0cc8b03469d949f1c14455266fd9bedeea0b411ec624b42827db48ad942ffb3b1 + languageName: node + linkType: hard + "zwitch@npm:^1.0.0": version: 1.0.5 resolution: "zwitch@npm:1.0.5"