synthesisui 0.1.4 → 0.1.6

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 +107 -31
  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,27 +68,45 @@ ${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
  ? `
66
- ## Using it with Tailwind v4 (optional)
86
+ ## Styling with Tailwind v4 (preferred in this project)
67
87
 
68
- If the project uses Tailwind v4, import \`theme.css\` after \`tailwindcss\` and \`tokens.css\`:
88
+ Import \`theme.css\` after \`tailwindcss\` and \`tokens.css\`:
69
89
  \`\`\`css
70
90
  @import "tailwindcss";
71
91
  @import "./_synthesisui/ds/${slug}/tokens.css";
72
92
  @import "./_synthesisui/ds/${slug}/theme.css";
73
93
  \`\`\`
74
- This maps the DS tokens onto Tailwind's theme, so inside \`[data-ds="${slug}"]\` you can use
75
- utilities such as \`bg-primary\`, \`text-foreground\`, \`p-md\`, \`rounded-lg\`, \`shadow-*\`,
76
- \`font-*\` and \`ease-*\` all backed by the design system. Prefer these utilities (or the
77
- \`.ds-*\` recipes) over raw values.
94
+ This maps the DS tokens onto Tailwind's theme, so inside \`[data-ds="${slug}"]\` you get utilities
95
+ backed by the design system: \`bg-*\`/\`text-*\`/\`border-*\` (semantic colors), \`p-*\`/\`m-*\`/\`gap-*\`
96
+ (spacing), \`rounded-*\`, \`shadow-*\`, \`font-*\` (families **and** weights), \`text-*\` (type scale), \`ease-*\`.
97
+
98
+ **Prefer these utilities for layout and new composition** — they are this project's idiom and read
99
+ far better than inline \`style\`. Reach for inline \`var(--ds-*)\` only when no utility fits.
100
+
101
+ \`\`\`tsx
102
+ // ✅ preferred — Tailwind utilities backed by the DS
103
+ <main className="bg-canvas text-foreground p-2xl flex flex-col gap-md">
104
+ <button className="ds-button" data-intent="primary">Save</button>
105
+ </main>
106
+
107
+ // ❌ avoid — inline styles with raw var() when a utility exists
108
+ <main style={{ background: "var(--ds-color-semantic-canvas)", padding: "var(--ds-spacing-2xl)" }}>
109
+ \`\`\`
78
110
 
79
111
  ---
80
112
  `
@@ -87,17 +119,70 @@ those, not the versioned ones. The pinned files for this version — ${artifactL
87
119
 
88
120
  ---
89
121
 
90
- ## Rules (follow them when creating components)
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
+ ---
91
167
 
168
+ ## Rules (follow them when creating components)
169
+ ${hasTailwind
170
+ ? `
171
+ - **Styling mechanism:** prefer Tailwind utilities backed by the DS (\`bg-primary\`, \`p-md\`,
172
+ \`font-display\`, \`font-medium\`, …) for layout and new composition, and reuse the \`.ds-*\` recipes
173
+ for components the DS already covers. Use inline \`style\` with \`var(--ds-*)\` only as a last resort.
174
+ The token names below are the source vocabulary — every utility derives from them.`
175
+ : ""}
92
176
  - **Always use semantic tokens**, never raw values nor primitives directly.
93
- Color: \`var(--ds-color-semantic-<role>)\`. The roles are: ${list(semanticRoles)}.
177
+ Color: \`var(--ds-color-semantic-<role>)\`${hasTailwind ? " (utility: `bg-<role>`/`text-<role>`)" : ""}. The roles are: ${list(semanticRoles)}.
94
178
  - Primitives (\`--ds-color-<palette>-<step>\`) exist but should **not** be referenced directly —
95
179
  they feed the semantic roles.
96
180
  - Spacing → \`var(--ds-spacing-<key>)\`: ${list(Object.keys(foundations.spacing))}.
97
181
  - Radius → \`var(--ds-radius-<key>)\`: ${list(Object.keys(foundations.radius))}.
98
182
  - Shadow → \`var(--ds-shadow-<key>)\`: ${list(Object.keys(foundations.shadow))}.
99
183
  - Typography: families \`--ds-typography-families-{display,body,mono}\` (${foundations.typography.families.display}, ${foundations.typography.families.body}, ${foundations.typography.families.mono});
100
- scale \`--ds-typography-scale-<key>-font-size\` etc.: ${list(Object.keys(foundations.typography.scale))}.
184
+ weights${hasTailwind ? " (utility: `font-<key>`)" : ""}: ${list(weights)};
185
+ scale \`--ds-typography-scale-<key>-font-size\`${hasTailwind ? " (utility: `text-<key>`)" : ""}: ${list(Object.keys(foundations.typography.scale))}.
101
186
  - Motion: durations \`--ds-motion-durations-<key>\` (${list(Object.keys(motion.durations))}) and
102
187
  easings \`--ds-motion-easings-<key>\` (${list(Object.keys(motion.easings))}).
103
188
  - When **creating a new component** the DS does not cover yet: compose it from these semantic
@@ -105,20 +190,11 @@ those, not the versioned ones. The pinned files for this version — ${artifactL
105
190
 
106
191
  ---
107
192
 
108
- ## Where to preview
109
-
110
- **Preview in isolation, never on a real page.** When creating or demoing a component, generate a
111
- dedicated sample page — \`app/synthesisui-samples/<component>/\` in the Next.js App Router (or the
112
- equivalent samples route/folder in the project's stack). **Do not** apply the component to real
113
- production pages (home, layout, existing routes) unless explicitly asked. Samples let you review the
114
- component in the context of the design system without touching the app.
115
-
116
- ---
117
-
118
193
  ## Ready-made components
119
194
 
120
- Each recipe becomes a \`.ds-<name>\` class (inside the \`[data-ds="${slug}"]\` scope).
121
- Variants are \`data-<axis>="<option>"\` attributes; states (hover/focus/active/disabled) ship in the CSS.
195
+ Each recipe becomes a \`.ds-<name>\` class (inside the \`[data-ds="${slug}"]\` scope). Variants are
196
+ \`data-<axis>="<option>"\` attributes; states (hover/focus/active/disabled) ship in the CSS;
197
+ multi-part components expose \`.ds-<name>-<part>\` classes (listed under each).
122
198
 
123
199
  ${componentLines.join("\n\n")}
124
200
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Traz design systems do SynthesisUI para qualquer projeto (materializa em _local/ds/).",
5
5
  "type": "module",
6
6
  "bin": {