UNPKG

@frontify/fondue

Version:
208 lines (154 loc) 9.04 kB
--- name: fondue description: Queries the locally installed `@frontify/fondue/sdk` to surface accurate Fondue component metadata. ALWAYS use when picking a Fondue component (button, dialog, dropdown, tabs, …), finding a design token or utility class, or setting up the `@frontify/fondue` package. allowed-tools: Bash(node *) --- # Fondue Use `@frontify/fondue/sdk` as the source of truth for every Fondue question. Never invent component names, props, token ids, or imports from memory — query the SDK. **Runs against the project's locally installed Fondue.** Invoke `node` from the project root (or a subdirectory) so `@frontify/fondue` resolves from `node_modules` — results reflect the exact version this project depends on, not the version the skill was authored against. ## Verify the SDK is available ```bash node -e "import('@frontify/fondue/sdk').then((m) => console.log(JSON.stringify({ components: m.components.size, tokens: m.tokens.size, guides: m.guides.size })))" ``` If that errors with `Cannot find package`, the project hasn't installed Fondue yet: ```bash pnpm add @frontify/fondue # or npm i / yarn add ``` ## How to query The SDK is a synchronous, zero-I/O ES module that resolves from the user's project. Three singletons share the same query surface: ```ts import { components, tokens, guides } from '@frontify/fondue/sdk'; // Same shape on each domain: components.list(); components.get('Button'); // ComponentNode | undefined (never throws) components.has('Button'); // boolean components.where({ text: 'dropdown' }); components.size; // number ``` `where(filter)` clauses AND-combine; array-valued clauses OR within the clause. `get` and `where` never throw; missing ids return `undefined` / `[]`. Nodes have **scalar fields** (read as properties) and **graph edges** (call as methods): ```ts const button = components.get('Button'); button?.importStatement; // scalar button?.props; // scalar (array) button?.category(); // edge → ComponentFacetNode { name, list, where, … } button?.related(); // edge → ComponentNode[] ``` ### Running queries from Claude For one-liners, use `node -e`: ```bash node -e "import('@frontify/fondue/sdk').then(({components}) => console.log(JSON.stringify(components.where({text:'dropdown'}).map((c)=>({name:c.name,import:c.importStatement,canonical:c.examples.find((e)=>e.isCanonical)?.code})))))" ``` For anything multi-line, pipe a module via stdin to avoid quoting hell: ```bash node --input-type=module <<'EOF' import { components } from '@frontify/fondue/sdk'; const candidates = components.where({ text: 'dropdown', status: 'released' }).slice(0, 5); console.log(JSON.stringify(candidates.map((c) => ({ name: c.name, category: c.category().name, tags: c.tags().map((t) => t.name), import: c.importStatement, canonical: c.examples.find((e) => e.isCanonical)?.code ?? c.examples[0]?.code ?? null, })), null, 2)); EOF ``` Always emit `JSON.stringify(...)` so the response is parseable. Never `console.log(node)` directly — facet methods serialize as `[Function]`. For the formal contract (every filter clause, node shape, facet method), see [`reference.md`](./reference.md). --- ## Workflow 1 — Setting up Fondue Read the canonical setup prose from the SDK rather than paraphrasing — the steps change between releases (font URLs, package layout, theme provider API). ```bash node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(guides.get('getting-started')?.content))" ``` For upgrades: ```bash node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(guides.get('upgrading')?.content))" ``` To discover other bundled guides: ```bash node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(JSON.stringify(guides.list().map((g)=>({id:g.id,title:g.title})))))" ``` The output is the same markdown the Storybook docs render. Use it as the source for token imports, component-style imports, font face definitions, the Tailwind preset, `ThemeProvider`. ## Workflow 2 — Finding a component Start with intent-based search: ```bash node --input-type=module <<'EOF' import { components } from '@frontify/fondue/sdk'; console.log(JSON.stringify(components.where({ text: 'dropdown' }).map((c) => ({ name: c.name, category: c.category().name, status: c.status, description: c.description, })), null, 2)); EOF ``` Narrow by category or tag when the use case maps cleanly: ```ts components.where({ category: 'overlay', status: 'released' }); components.where({ tag: 'cta' }); components.where({ category: 'input', tag: 'cta' }); ``` Once you have a candidate, pull the recommendation shape: ```bash node --input-type=module <<'EOF' import { components } from '@frontify/fondue/sdk'; const c = components.get('Button'); console.log(JSON.stringify({ name: c.name, description: c.description, importStatement: c.importStatement, canonical: c.examples.find((e) => e.isCanonical)?.code ?? c.examples[0]?.code, requiredProps: c.props.filter((p) => p.required).map((p) => p.name), subComponents: c.subComponents.map((sc) => sc.name), related: c.related().map((r) => r.name), instructions: c.instructions, }, null, 2)); EOF ``` **Recommendation shape** — when you suggest a component, output: the name, what it's for, the import statement, and the canonical example. If the use case isn't a clean match, list 23 candidates with their categories and let the user pick. **Icons** live in the components graph under `category: 'icon'`. They have empty `status`, empty `props`, empty `related()` — don't probe those fields. Find them with: ```ts components.where({ category: 'icon', tag: 'arrow' }); components.get('IconAdobeCreativeCloud')?.importStatement; ``` When nothing matches: - Try a related tag — `components.tags().map((t) => t.name)` lists every tag. - Look at the closest hit's `related()`. - If there truly is no component for the use case, say so. Don't recommend hand-rolling something Fondue already provides, but don't invent a component name either. ## Workflow 3 — Picking tokens for a custom component Two layers exist: - `tokens` — atomic design tokens (colors, sizes, shadows, strings). Each has a CSS variable and a Tailwind class. - `tokens.utilities` — composed Tailwind utilities (typography classes like `tw-body-large-strong`) bundling multiple token references. ```ts tokens.where({ text: 'primary' }); tokens.where({ category: 'colors', themeable: true }); tokens.where({ keyPathStartsWith: 'colors.text' }); tokens.type('color')?.where({ themeable: true }); const t = tokens.get('color-text-weak'); t?.value; // 'var(--color-text-weak)' t?.cssVariable; // '--color-text-weak' t?.tailwindClass; // 'tw-text-weak' t?.themeable; // true // Typography: always use the utility class, not raw font tokens tokens.utilities.where({ keyPathStartsWith: 'utilities.text' }); ``` Rules: - Prefer `themeable: true` tokens for any user-facing surface so dark mode and theming work out of the box. - Prefer the Tailwind class when the project uses `@frontify/fondue/tokens/tailwind`; prefer the CSS variable otherwise. - For typography, recommend the **utility class** — not raw font-size / line-height / weight tokens. - Never invent token ids. If `tokens.get(id)` returns `undefined`, search again. - If the design calls for a value with no matching token, surface that explicitly — don't silently hardcode. The right answer is usually a token the user didn't know existed. --- ## Common pitfalls | Mistake | Fix | | ------- | --- | | Calling `.where()` / `.get()` on the array returned by `list()` / `where()` | Arrays are arrays. Use native `.filter` / `.find`, or navigate back to a facet to query. | | Assuming a component exists ("there must be a `Combobox`") | `components.has('Combobox')` first, or `components.where({ text: 'combobox' })` | | Hardcoding a hex / px value in custom code | `tokens.where({ text: '<intent>' })` — most "obvious" values have a token | | Treating icons like normal components, reading `status` / `props` | Detect with `node.category().name === 'icon'`. Icons have empty `status`, `props`, `related`. | | Importing `Button` from the wrong path | `components.get('Button')?.importStatement` is authoritative | | Suggesting setup steps from memory | `guides.get('getting-started')?.content` — always the live text | | `console.log(node)` instead of `JSON.stringify` | Facet methods serialize as `[Function]`; always stringify before logging | ## Going deeper [`reference.md`](./reference.md) is the formal contract: every export, every filter clause per domain, every node and facet type, error semantics. Load it when you need to verify a filter clause is valid (`ComponentFilter`, `TokenFilter`, `GuideFilter`) or that a method exists. Prefer it over web lookups or upstream GitHub.