synthesisui 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/guide.js +102 -27
  2. package/package.json +1 -1
package/dist/guide.js CHANGED
@@ -1,5 +1,25 @@
1
1
  const kebab = (v) => v.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2
2
  const list = (items) => items.length ? items.map((i) => `\`${i}\``).join(", ") : "_(none)_";
3
+ const dataAttrs = (variants) => Object.entries(variants).map(([axis, opts]) => `data-${kebab(axis)}="${Object.keys(opts).join("|")}"`);
4
+ /** One entry per component: class, variant data-*, states, and multi-part anatomy. */
5
+ function componentEntry(cname, recipe) {
6
+ const cls = `.ds-${kebab(cname)}`;
7
+ const axes = dataAttrs(recipe.variants).map((a) => `\`${a}\``);
8
+ const variantsText = axes.length ? ` — variants: ${axes.join(", ")}` : "";
9
+ const states = Object.keys(recipe.states ?? {});
10
+ const statesText = states.length ? `\n states: ${list(states)}` : "";
11
+ const partEntries = Object.entries(recipe.parts ?? {});
12
+ let partsText = "";
13
+ if (partEntries.length) {
14
+ const items = partEntries.map(([pname, part]) => {
15
+ const pcls = `.ds-${kebab(cname)}-${kebab(pname)}`;
16
+ const paxes = dataAttrs(part.variants ?? {});
17
+ return paxes.length ? `\`${pcls}\` (${paxes.join(", ")})` : `\`${pcls}\``;
18
+ });
19
+ partsText = `\n parts: ${items.join(", ")}`;
20
+ }
21
+ return `- **${cname}** (\`${cls}\`)${variantsText}\n ${recipe.description}${partsText}${statesText}`;
22
+ }
3
23
  /**
4
24
  * Builds GUIDE.md — instructions *for the agent* on how to build components
5
25
  * that follow the design system. This is the piece that makes "I create the
@@ -10,19 +30,13 @@ export function buildGuide(payload) {
10
30
  const { document: doc, slug, name, version } = payload;
11
31
  const { meta, foundations, motion, components } = doc;
12
32
  const semanticRoles = Object.keys(foundations.color.semantic);
33
+ const weights = Object.keys(foundations.typography.weights);
13
34
  const hasAlt = foundations.color.semanticAlt &&
14
35
  Object.keys(foundations.color.semanticAlt).length > 0;
15
36
  const altScheme = meta.scheme === "light" ? "dark" : "light";
16
37
  const hasTailwind = "theme.css" in payload.artifacts;
17
- const componentLines = Object.entries(components).map(([cname, recipe]) => {
18
- const cls = `.ds-${kebab(cname)}`;
19
- const axes = Object.entries(recipe.variants).map(([axis, opts]) => {
20
- const options = Object.keys(opts);
21
- return `\`data-${kebab(axis)}="${options.join("|")}"\``;
22
- });
23
- const variantsText = axes.length ? ` — variants: ${axes.join(", ")}` : "";
24
- return `- **${cname}** (\`${cls}\`)${variantsText}\n ${recipe.description}`;
25
- });
38
+ const hasParts = Object.values(components).some((r) => r.parts && Object.keys(r.parts).length > 0);
39
+ const componentLines = Object.entries(components).map(([cname, recipe]) => componentEntry(cname, recipe));
26
40
  const artifactList = Object.keys(payload.artifacts)
27
41
  .map((f) => `\`${f}\``)
28
42
  .join(", ");
@@ -54,12 +68,18 @@ ${meta.narrative}
54
68
  <div data-ds="${slug}">…your UI here…</div>
55
69
  \`\`\`
56
70
  All \`--ds-*\` custom properties and \`.ds-*\` classes only apply inside that scope.
71
+ Applying \`data-ds="${slug}"\` at the app root (e.g. \`<body>\` or the root layout)
72
+ is the simplest choice — the whole app then wears the system.
57
73
  ${hasAlt
58
74
  ? `
59
75
  3. Light/dark: an ancestor with \`data-scheme="${altScheme}"\` switches the neutral roles to the opposite mode.
60
- \`\`\`html
76
+ \`\`\`tsx
61
77
  <div data-scheme="${altScheme}"><div data-ds="${slug}">…</div></div>
62
78
  \`\`\`
79
+ A theme toggle just adds/removes that attribute on the scope element:
80
+ \`\`\`tsx
81
+ root.toggleAttribute("data-scheme"); // present = ${altScheme}, absent = ${meta.scheme}
82
+ \`\`\`
63
83
  `
64
84
  : ""}${hasTailwind
65
85
  ? `
@@ -73,7 +93,7 @@ Import \`theme.css\` after \`tailwindcss\` and \`tokens.css\`:
73
93
  \`\`\`
74
94
  This maps the DS tokens onto Tailwind's theme, so inside \`[data-ds="${slug}"]\` you get utilities
75
95
  backed by the design system: \`bg-*\`/\`text-*\`/\`border-*\` (semantic colors), \`p-*\`/\`m-*\`/\`gap-*\`
76
- (spacing), \`rounded-*\`, \`shadow-*\`, \`font-*\`, \`ease-*\`.
96
+ (spacing), \`rounded-*\`, \`shadow-*\`, \`font-*\` (families **and** weights), \`text-*\` (type scale), \`ease-*\`.
77
97
 
78
98
  **Prefer these utilities for layout and new composition** — they are this project's idiom and read
79
99
  far better than inline \`style\`. Reach for inline \`var(--ds-*)\` only when no utility fits.
@@ -99,13 +119,76 @@ those, not the versioned ones. The pinned files for this version — ${artifactL
99
119
 
100
120
  ---
101
121
 
122
+ ## Building with the system
123
+
124
+ **This system is for building real product UI** — pages, layouts, dashboards, whole flows.
125
+ Compose the \`.ds-*\` recipes (and their parts) together with the DS-backed utilities to assemble
126
+ actual screens. There is **no "samples only" rule**: build the real app. An
127
+ \`app/synthesisui-samples/<component>/\` page is a fine *optional* scratch space to eyeball a single
128
+ component, but it is never required.
129
+
130
+ ### Layout & composition
131
+ The system defines the scale; these are sensible defaults for spending it:
132
+ - **Page gutter / container padding:** a large spacing step — ${list(Object.keys(foundations.spacing).filter((k) => /xl/.test(k)))}.
133
+ - **Section gaps:** \`lg\` (or the nearest large step). **Card/panel padding:** \`md\`.
134
+ - **Field / tight gaps:** \`2xs\`/\`3xs\`.
135
+ - The system imposes no content max-width — cap long-form/text columns yourself for readability.
136
+ ${hasParts
137
+ ? `
138
+ ### Multi-part components
139
+ Components that have **parts** compile to \`.ds-<name>-<part>\` classes you nest yourself; the exact
140
+ part classes and their \`data-*\` are listed per component below. Example — a table:
141
+ \`\`\`tsx
142
+ <table className="ds-table">
143
+ <thead className="ds-table-head">
144
+ <tr>
145
+ <th className="ds-table-cell-head">Name</th>
146
+ <th className="ds-table-cell-head" data-align="end">Updated</th>
147
+ </tr>
148
+ </thead>
149
+ <tbody>
150
+ <tr className="ds-table-row">
151
+ <td className="ds-table-cell">Halogen</td>
152
+ <td className="ds-table-cell" data-align="end">2h ago</td>
153
+ </tr>
154
+ </tbody>
155
+ </table>
156
+ \`\`\`
157
+ `
158
+ : ""}
159
+ ### Overlays & portals
160
+ Dialogs, menus and toasts are often rendered through a portal at the end of \`<body>\` — **outside**
161
+ your \`data-ds\` scope. Since \`.ds-*\`/\`--ds-*\` only resolve inside the scope, wrap any portalled UI
162
+ in its own \`<div data-ds="${slug}"${hasAlt ? ` data-scheme="…"` : ""}>\`, or apply \`data-ds\` at the
163
+ app root so everything (portals included) inherits it. Behavior (open/close, focus trap, positioning,
164
+ keyboard) is yours to wire — the system ships the **looks**, not the JavaScript.
165
+
166
+ ### Interactive recipes — the behavior contract
167
+ Several recipes are **static surfaces**: they ship the styling for every state, but never any
168
+ JavaScript. You own the interaction and drive each state by toggling the documented \`data-*\`
169
+ attributes (listed per component below). The recipe restyles itself; you wire the logic.
170
+ - **Open / close** (menu, select, modal, tooltip, popover): render the surface, then handle show/hide,
171
+ outside-click, focus trap, positioning and \`Esc\` yourself (or with a headless lib).
172
+ - **Selection / active** (tabs, sidebar, pagination): set \`data-active="true"\` on the chosen item from
173
+ your own state/router — the recipe lifts it onto a surface.
174
+ - **On / off** (switch): toggle \`data-state="on"\` on the track **and** its thumb together.
175
+ - **Command bar / ⌘K** (if your system ships one): the recipe is only the styled input row — wire the
176
+ shortcut, the palette list and filtering yourself.
177
+ - **Select** (native vs custom): \`.ds-select\` strips native chrome (\`appearance:none\`). On a real
178
+ \`<select>\`, wrap it and overlay your own chevron; on a custom trigger, nest \`.ds-select-chevron\`.
179
+
180
+ Pair these with the right ARIA (\`aria-expanded\`, \`role="dialog"\`, \`aria-current\`, …) — the system
181
+ styles it, you make it work.
182
+
183
+ ---
184
+
102
185
  ## Rules (follow them when creating components)
103
186
  ${hasTailwind
104
187
  ? `
105
188
  - **Styling mechanism:** prefer Tailwind utilities backed by the DS (\`bg-primary\`, \`p-md\`,
106
- \`font-display\`, …) for layout and new composition, and reuse the \`.ds-*\` recipes for components
107
- the DS already covers. Use inline \`style\` with \`var(--ds-*)\` only as a last resort. The token
108
- names below are the source vocabulary — every utility derives from them.`
189
+ \`font-display\`, \`font-medium\`, …) for layout and new composition, and reuse the \`.ds-*\` recipes
190
+ for components the DS already covers. Use inline \`style\` with \`var(--ds-*)\` only as a last resort.
191
+ The token names below are the source vocabulary — every utility derives from them.`
109
192
  : ""}
110
193
  - **Always use semantic tokens**, never raw values nor primitives directly.
111
194
  Color: \`var(--ds-color-semantic-<role>)\`${hasTailwind ? " (utility: `bg-<role>`/`text-<role>`)" : ""}. The roles are: ${list(semanticRoles)}.
@@ -115,7 +198,8 @@ ${hasTailwind
115
198
  - Radius → \`var(--ds-radius-<key>)\`: ${list(Object.keys(foundations.radius))}.
116
199
  - Shadow → \`var(--ds-shadow-<key>)\`: ${list(Object.keys(foundations.shadow))}.
117
200
  - Typography: families \`--ds-typography-families-{display,body,mono}\` (${foundations.typography.families.display}, ${foundations.typography.families.body}, ${foundations.typography.families.mono});
118
- scale \`--ds-typography-scale-<key>-font-size\` etc.: ${list(Object.keys(foundations.typography.scale))}.
201
+ weights${hasTailwind ? " (utility: `font-<key>`)" : ""}: ${list(weights)};
202
+ scale \`--ds-typography-scale-<key>-font-size\`${hasTailwind ? " (utility: `text-<key>`)" : ""}: ${list(Object.keys(foundations.typography.scale))}.
119
203
  - Motion: durations \`--ds-motion-durations-<key>\` (${list(Object.keys(motion.durations))}) and
120
204
  easings \`--ds-motion-easings-<key>\` (${list(Object.keys(motion.easings))}).
121
205
  - When **creating a new component** the DS does not cover yet: compose it from these semantic
@@ -123,20 +207,11 @@ ${hasTailwind
123
207
 
124
208
  ---
125
209
 
126
- ## Where to preview
127
-
128
- **Preview in isolation, never on a real page.** When creating or demoing a component, generate a
129
- dedicated sample page — \`app/synthesisui-samples/<component>/\` in the Next.js App Router (or the
130
- equivalent samples route/folder in the project's stack). **Do not** apply the component to real
131
- production pages (home, layout, existing routes) unless explicitly asked. Samples let you review the
132
- component in the context of the design system without touching the app.
133
-
134
- ---
135
-
136
210
  ## Ready-made components
137
211
 
138
- Each recipe becomes a \`.ds-<name>\` class (inside the \`[data-ds="${slug}"]\` scope).
139
- Variants are \`data-<axis>="<option>"\` attributes; states (hover/focus/active/disabled) ship in the CSS.
212
+ Each recipe becomes a \`.ds-<name>\` class (inside the \`[data-ds="${slug}"]\` scope). Variants are
213
+ \`data-<axis>="<option>"\` attributes; states (hover/focus/active/disabled) ship in the CSS;
214
+ multi-part components expose \`.ds-<name>-<part>\` classes (listed under each).
140
215
 
141
216
  ${componentLines.join("\n\n")}
142
217
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Traz design systems do SynthesisUI para qualquer projeto (materializa em _local/ds/).",
5
5
  "type": "module",
6
6
  "bin": {