synthesisui 0.16.122 → 0.16.123
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.
- package/dist/doctor/variant-read.js +29 -4
- package/dist/guide.js +19 -1
- package/package.json +1 -1
|
@@ -508,14 +508,39 @@ export function readVariants(source) {
|
|
|
508
508
|
* Read separately from `cva` because a file can have both, and because this shape is
|
|
509
509
|
* what a codebase that never adopted a variant library uses everywhere.
|
|
510
510
|
*/
|
|
511
|
-
|
|
511
|
+
/**
|
|
512
|
+
* THE `!` HAS TO BE PART OF THE MATCH, or the two opposite branches of one `cn()` become
|
|
513
|
+
* the same condition.
|
|
514
|
+
*
|
|
515
|
+
* `!` is not in `[A-Za-z_$]`, so `!isLoading && "cursor-pointer"` matched starting at
|
|
516
|
+
* `isLoading` and the negation fell outside the match, in silence. Their collapsible card
|
|
517
|
+
* writes both branches:
|
|
518
|
+
*
|
|
519
|
+
* !isLoading && "cursor-pointer hover:bg-lightgray-200/50"
|
|
520
|
+
* isLoading && "cursor-not-allowed opacity-80"
|
|
521
|
+
*
|
|
522
|
+
* and both arrived as `{isLoading: "true"}` - so the same state carried `cursor: pointer`
|
|
523
|
+
* AND `cursor: not-allowed`, with whichever came last winning. A dead rule is bad; a rule
|
|
524
|
+
* that says the opposite of their code is worse (dono, 04/08). Measured on his library: 8
|
|
525
|
+
* inline conditions with a class list, 2 of them negated.
|
|
526
|
+
*/
|
|
527
|
+
const INLINE_COND = /(!?)\s*([A-Za-z_$][\w$.]*)\s*(?:===|==)\s*["']([^"']+)["']\s*&&\s*(["'`])((?:(?!\4).)*)\4|(!?)\s*([A-Za-z_$][\w$]*)\s*&&\s*(["'`])((?:(?!\8).)*)\8/g;
|
|
512
528
|
export function readInlineConditions(source) {
|
|
513
529
|
const layers = [];
|
|
514
530
|
INLINE_COND.lastIndex = 0;
|
|
515
531
|
for (const m of source.matchAll(INLINE_COND)) {
|
|
516
|
-
const
|
|
517
|
-
const
|
|
518
|
-
const raw = m[
|
|
532
|
+
const negated = (m[1] ?? m[6]) === "!";
|
|
533
|
+
const prop = (m[2] ?? m[7] ?? "").split(".").pop() ?? "";
|
|
534
|
+
const raw = m[5] ?? m[9] ?? "";
|
|
535
|
+
/**
|
|
536
|
+
* `!status === "loading"` is not a thing anybody writes, and negating a comparison we
|
|
537
|
+
* cannot invert would guess. A comparison is taken as written; only the bare boolean
|
|
538
|
+
* flips, and it flips to the option `false` - which is what `data-x="false"` means.
|
|
539
|
+
*/
|
|
540
|
+
const compared = m[3];
|
|
541
|
+
if (compared != null && negated)
|
|
542
|
+
continue;
|
|
543
|
+
const option = compared ?? (negated ? "false" : "true");
|
|
519
544
|
if (!prop || raw.includes("${"))
|
|
520
545
|
continue;
|
|
521
546
|
const classes = raw.split(/\s+/).filter(Boolean);
|
package/dist/guide.js
CHANGED
|
@@ -198,6 +198,16 @@ function componentEntry(cname, recipe) {
|
|
|
198
198
|
/** Its own laws, computed from its own usage - and nothing read them (dono, 04/08). */
|
|
199
199
|
const laws = (recipe.usage ?? []).map((law) => `\n - ${law}`).join("");
|
|
200
200
|
const lawsText = laws ? `\n it obeys:${laws}` : "";
|
|
201
|
+
/**
|
|
202
|
+
* WHAT IT DOES, beside what it obeys - and they are not the same reader.
|
|
203
|
+
*
|
|
204
|
+
* `usage` is law: short, imperative, checkable, injected into a Build Script. This is the
|
|
205
|
+
* briefing for somebody rebuilding the component in a project that has none of these prop
|
|
206
|
+
* names, which is the question the guide exists to answer (dono, 04/08). Measured on a
|
|
207
|
+
* real system: 23 of 35 components have something derived to say here.
|
|
208
|
+
*/
|
|
209
|
+
const does = (recipe.behaviour ?? []).map((line) => `\n - ${line}`).join("");
|
|
210
|
+
const doesText = does ? `\n what it does:${does}` : "";
|
|
201
211
|
const behaviour = behaviourLine(cname, recipe);
|
|
202
212
|
const behaviourText = behaviour ? `\n ${behaviour}` : "";
|
|
203
213
|
/**
|
|
@@ -240,7 +250,7 @@ function componentEntry(cname, recipe) {
|
|
|
240
250
|
const anatomyText = anatomy.length
|
|
241
251
|
? `\n anatomy, in this nesting:\n${anatomy.join("\n")}`
|
|
242
252
|
: "";
|
|
243
|
-
return `- **${cname}** (\`${cls}\`)${variantsText}\n ${recipe.description}${factsText}${defaultsText}${partsText}${statesText}${behaviourText}${contractText}${anatomyText}${lawsText}`;
|
|
253
|
+
return `- **${cname}** (\`${cls}\`)${variantsText}\n ${recipe.description}${factsText}${defaultsText}${partsText}${statesText}${behaviourText}${contractText}${anatomyText}${doesText}${lawsText}`;
|
|
244
254
|
}
|
|
245
255
|
/**
|
|
246
256
|
* Builds GUIDE.md - instructions *for the agent* on how to build components
|
|
@@ -402,6 +412,14 @@ It writes \`<componentsDir>/button/\` with \`button.tsx\` (+ colocated \`button.
|
|
|
402
412
|
The boundary: tokens are global (\`tokens.css\` + the \`data-ds\` root attribute, once per app);
|
|
403
413
|
everything a component owns lives in its own folder.
|
|
404
414
|
|
|
415
|
+
**A component's conditional classes are decided at the call site, not in the stylesheet.** A recipe
|
|
416
|
+
carries the look of a state as a rule keyed on a data attribute (\`[data-size="lg"]\`), and the caller
|
|
417
|
+
is what turns it on. \`synthesisui component\` emits this system's own \`cn()\` beside the component: it
|
|
418
|
+
resolves two utilities that set the SAME property in favour of the one the caller passed, which plain
|
|
419
|
+
Tailwind decides by emission order instead. Compose with it and an override wins; concatenate strings
|
|
420
|
+
and which one applies is a coin flip. Where a component needs an attribute nobody sets by default, its
|
|
421
|
+
own entry below says so.
|
|
422
|
+
|
|
405
423
|
---
|
|
406
424
|
`
|
|
407
425
|
: "";
|
package/package.json
CHANGED