better-design 0.43.0 → 0.43.1
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/index.js +22 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -330,7 +330,7 @@ var init_constants = __esm({
|
|
|
330
330
|
RULE_BODY = `## Better Design
|
|
331
331
|
|
|
332
332
|
For every UI build, run these steps in order, and never present a page that skipped step 2 or 4:
|
|
333
|
-
1. Design system: \`find-design-system\`, then \`get-design-system-kit\`. For a product with a live site, \`extract-from-url\` gives its tokens.
|
|
333
|
+
1. Design system: \`find-design-system\`, then \`get-design-system-kit\`. For a product with a live site, \`extract-from-url\` gives its tokens; an app screen takes only the accent and font from them.
|
|
334
334
|
2. Principles: \`get-ui-principle\` before styling, \`get-ux-principle\` before behavior.
|
|
335
335
|
3. Build.
|
|
336
336
|
4. Review: \`get-review-rules\`, \`check-comprehension\` and \`inspect-spacing\`. Fix every critical and serious finding.
|
|
@@ -1075,7 +1075,7 @@ var MCP_IMPLEMENTATION_VERSION;
|
|
|
1075
1075
|
var init_version = __esm({
|
|
1076
1076
|
"../shared/src/mcp/version.ts"() {
|
|
1077
1077
|
"use strict";
|
|
1078
|
-
MCP_IMPLEMENTATION_VERSION = "0.43.
|
|
1078
|
+
MCP_IMPLEMENTATION_VERSION = "0.43.1";
|
|
1079
1079
|
}
|
|
1080
1080
|
});
|
|
1081
1081
|
|
|
@@ -1936,8 +1936,8 @@ ${PRESENTATION_RUNTIME_RULE}
|
|
|
1936
1936
|
|
|
1937
1937
|
## Build or modify UI, in order
|
|
1938
1938
|
${DESIGN_TRADEOFF_REMINDER}
|
|
1939
|
-
Classify: repair, polish
|
|
1940
|
-
1. Design system: keep the selected DS and its icons. Else find-design-system and show ~4 choices (unattended: take the top one); custom brand: create-design-system, poll status. Then get-design-system-kit: "react" with files/terminal, "html" in inline canvases; real components, never runtime @iconify/react. Live
|
|
1939
|
+
Classify: repair, polish or redesign. Redesign needs layout/component changes and before/after at matching widths. Follow the kit's scope contract.
|
|
1940
|
+
1. Design system: keep the selected DS and its icons. Else find-design-system and show ~4 choices (unattended: take the top one); custom brand: create-design-system, poll status. Then get-design-system-kit: "react" with files/terminal, "html" in inline canvases; real components, never runtime @iconify/react. Live site: extract-from-url tokens (app screen: accent, font only).
|
|
1941
1941
|
2. get-ui-principle before styling; get-ux-principle before behavior.
|
|
1942
1942
|
3. Build: semantic HTML, keyboard access, WCAG AA.
|
|
1943
1943
|
4. Review: get-review-rules (copy/AI-tell rules), check-comprehension, inspect-spacing; fix critical/serious findings. Dashboards need a VALID finalize-dashboard-review receipt. No rendered evidence means unverified.
|
|
@@ -2529,7 +2529,7 @@ and never leave a \`var(--font-*)\` reference undefined. In the rendered app, aw
|
|
|
2529
2529
|
\`document.fonts.ready\`, inspect the computed font-family on the page and a heading,
|
|
2530
2530
|
and confirm the intended family loaded before presenting the screen.
|
|
2531
2531
|
|
|
2532
|
-
Hierarchy is pass/fail, not polish. Give the first view one P0 task and at most one P1 summary; move P2 history, standings, detailed metadata, and empty-state chrome below it or behind a tab/disclosure. Unless the
|
|
2532
|
+
Hierarchy is pass/fail, not polish. Give the first view one P0 task and at most one P1 summary; move P2 history, standings, detailed metadata, and empty-state chrome below it or behind a tab/disclosure. Unless the screen is a dense tool (traces, logs, tables and dashboards) or the user asked for density, fail and simplify any first view with more than three major regions, five immediately visible actions, or 25 visible text fragments. A dense tool keeps its summary stats, its records and the selected record's detail in one view: order them with hierarchy instead of cutting them. Do not make density look compact by shrinking everything: the primary display must be at least 1.5\xD7 base UI text, section anchors at least 1.2\xD7, and bold must be reserved for the primary display, section anchors, and active values. Labels are a last resort; remove captions that restate obvious values.
|
|
2533
2533
|
|
|
2534
2534
|
Dashboard quality is pass-fail. Start with the domain page title, one supporting line, and one primary action
|
|
2535
2535
|
in the same header group. Preserve this scan order: metrics \u2192 records \u2192 interpretation.
|
|
@@ -18049,7 +18049,7 @@ function resolveCopy(input) {
|
|
|
18049
18049
|
return {
|
|
18050
18050
|
headline: input.headline?.trim() || extracted?.headline || null,
|
|
18051
18051
|
body: input.body?.length ? input.body : extracted?.body ?? [],
|
|
18052
|
-
actions: input.actions?.length ? input.actions : extracted?.actions ?? [],
|
|
18052
|
+
actions: (input.actions?.length ? input.actions : extracted?.actions ?? []).filter((a) => !NOT_AN_ACTION.test(a.trim())),
|
|
18053
18053
|
unlabelledControls: extracted?.unlabelledControls ?? 0
|
|
18054
18054
|
};
|
|
18055
18055
|
}
|
|
@@ -18244,13 +18244,14 @@ function analyzeComprehension(input) {
|
|
|
18244
18244
|
}
|
|
18245
18245
|
};
|
|
18246
18246
|
}
|
|
18247
|
-
var WORD_BOUNDARY_SAFE;
|
|
18247
|
+
var WORD_BOUNDARY_SAFE, NOT_AN_ACTION;
|
|
18248
18248
|
var init_analyze = __esm({
|
|
18249
18249
|
"../shared/src/mcp/comprehension/analyze.ts"() {
|
|
18250
18250
|
"use strict";
|
|
18251
18251
|
init_extract();
|
|
18252
18252
|
init_lexicon();
|
|
18253
18253
|
WORD_BOUNDARY_SAFE = /[.*+?^${}()|[\]\\]/g;
|
|
18254
|
+
NOT_AN_ACTION = /^(?:search|filter|sort|all|any)\b/i;
|
|
18254
18255
|
}
|
|
18255
18256
|
});
|
|
18256
18257
|
|
|
@@ -18375,7 +18376,7 @@ Use knownTerms for words your audience genuinely knows, so the check stops flagg
|
|
|
18375
18376
|
screen: z13.string().trim().min(1).max(120).describe("What this screen is, e.g. 'lesson end card', 'billing page'."),
|
|
18376
18377
|
headline: z13.string().trim().max(300).optional().describe("The screen's title, if you are passing copy rather than markup."),
|
|
18377
18378
|
body: z13.array(z13.string().trim().min(1).max(2e3)).max(50).optional().describe("Supporting copy, one string per visible line or paragraph."),
|
|
18378
|
-
actions: z13.array(z13.string().trim().min(1).max(120)).max(20).optional().describe("Visible button and link labels, e.g. ['Claim badge', 'Not now']."),
|
|
18379
|
+
actions: z13.array(z13.string().trim().min(1).max(120)).max(20).optional().describe("Visible button and link labels, e.g. ['Claim badge', 'Not now']. Search fields, filters and selects are not actions."),
|
|
18379
18380
|
code: z13.string().max(6e4).optional().describe("JSX, TSX or HTML for the screen. Copy is extracted from it when headline/body/actions are omitted."),
|
|
18380
18381
|
knownTerms: z13.array(z13.string().trim().min(1).max(60)).max(50).optional().describe("Words this audience already knows, so they are not flagged as insider language."),
|
|
18381
18382
|
surface: z13.enum(["screen", "slide"]).optional().describe('"slide" adds the slide density test and withholds a pass until a screenshot review. Defaults to "slide" when the screen name says slide, deck or presentation.'),
|
|
@@ -19140,8 +19141,8 @@ align in a column.
|
|
|
19140
19141
|
|
|
19141
19142
|
**Hierarchy is pass/fail.** Give the first view one P0 task and at most one P1
|
|
19142
19143
|
summary; move P2 history, standings, detailed metadata, and empty-state chrome
|
|
19143
|
-
below it or behind a tab/disclosure. Unless the
|
|
19144
|
-
|
|
19144
|
+
below it or behind a tab/disclosure. Unless the screen is a dense tool (traces, logs,
|
|
19145
|
+
tables and dashboards) or the user asked for density, simplify any first view with more than three major regions, five
|
|
19145
19146
|
immediately visible actions, or 25 visible text fragments. Do not shrink everything
|
|
19146
19147
|
to make it fit: the primary display must be at least 1.5\xD7 base UI text, section
|
|
19147
19148
|
anchors at least 1.2\xD7, and labels are a last resort. Reserve bold for the primary
|
|
@@ -19421,7 +19422,7 @@ APP_ROOT :where(h1,h2,h3,h4,h5,h6,p,strong,label,legend,li,dt,dd,small):not(.ds-
|
|
|
19421
19422
|
].join(" ");
|
|
19422
19423
|
INLINE_HIERARCHY_POLICY = [
|
|
19423
19424
|
"Give the first view one P0 task and at most one P1 summary; move P2 history, standings, detailed metadata, and empty-state chrome below the first view or behind a tab or disclosure.",
|
|
19424
|
-
"At the actual inline-canvas size, the first view fails when it exposes more than three major regions, more than five immediately visible actions, or more than 25 visible text fragments unless the user
|
|
19425
|
+
"At the actual inline-canvas size, the first view fails when it exposes more than three major regions, more than five immediately visible actions, or more than 25 visible text fragments unless the screen is a dense tool (traces, logs, tables and dashboards) or the user asked for density.",
|
|
19425
19426
|
"Do not make a busy screen feel compact by shrinking everything. Use `ds-display` only inside the one P0 composition: once for a single primary task or value, or on co-equal peers within the same event, such as opposing teams. It must compute to at least 1.5\xD7 the base UI text. Use `ds-section-title` for scan anchors at at least 1.2\xD7 the base UI text, and `ds-supporting` for genuinely secondary copy.",
|
|
19426
19427
|
"Labels are a last resort: remove captions that restate an obvious value, do not label the same fact twice, and keep no more than two supporting metadata items around the primary entity.",
|
|
19427
19428
|
"Bold is selective hierarchy, not decoration: emphasize the primary display, section anchors, and the active value; keep labels, metadata, table headers, and helper copy quieter."
|
|
@@ -19567,7 +19568,7 @@ APP_ROOT :where(h1,h2,h3,h4,h5,h6,p,strong,label,legend,li,dt,dd,small):not(.ds-
|
|
|
19567
19568
|
"2. Wrap the entire artifact in `.ds` and use the kit's `ds-*` classes for component styling. Custom CSS is layout-only; do not replace the selected system's components, tokens, states, radii or shadows.",
|
|
19568
19569
|
'3. This class contract is pass/fail: do not rename `ds-*` to an app-specific prefix. Before presenting, inspect the artifact source. If it does not contain a root `class="ds"` and `ds-*` component classes, revise the artifact instead of presenting it.',
|
|
19569
19570
|
"4. Paste `hostIsolationCssTemplate` after host/base CSS, replacing `APP_ROOT` with the real root. Follow `textColorPolicy`: never use surface tokens as text colors, never dim text with opacity, and use `--muted-foreground` for secondary copy.",
|
|
19570
|
-
"5. First-view hierarchy is pass/fail: one P0 task, at most one P1 summary; unless a dense
|
|
19571
|
+
"5. First-view hierarchy is pass/fail: one P0 task, at most one P1 summary; unless the screen is a dense tool (traces, logs, tables and dashboards) or density was requested, no more than three major regions, five immediately visible actions, or 25 visible text fragments.",
|
|
19571
19572
|
"6. Composition is pass/fail: one identity, content-sized task, aligned field/action, accurate paired assets, and event-only decoration.",
|
|
19572
19573
|
"",
|
|
19573
19574
|
"## Before you show it (mandatory)",
|
|
@@ -26345,7 +26346,7 @@ var init_build_loop = __esm({
|
|
|
26345
26346
|
"use strict";
|
|
26346
26347
|
BUILD_LOOP = [
|
|
26347
26348
|
"Required, in this order, before you present any UI:",
|
|
26348
|
-
"1. Design system: install the system you take with `get-design-system-kit`.
|
|
26349
|
+
"1. Design system: install the system you take with `get-design-system-kit`. For a marketing page of a product with a live site, its `extract-from-url` tokens are this step. For a product screen, take only its accent colour and font from `extract-from-url`, never its backgrounds, borders or input styles: those come from the kit.",
|
|
26349
26350
|
"2. Principles: call `get-ui-principle` before styling and `get-ux-principle` before behavior.",
|
|
26350
26351
|
"3. Build with those tokens and principles.",
|
|
26351
26352
|
"4. Review: call `get-review-rules`, then `check-comprehension` with the page's real copy, and `inspect-spacing` on the rendered page. Fix every critical and serious finding.",
|
|
@@ -28683,7 +28684,7 @@ function extractFromSources(sources, name) {
|
|
|
28683
28684
|
Object.assign(light, parsed.light);
|
|
28684
28685
|
Object.assign(dark, parsed.dark);
|
|
28685
28686
|
} else if (kind === "computed") {
|
|
28686
|
-
Object.assign(light, computedToVars(source.content));
|
|
28687
|
+
Object.assign(source.scheme === "dark" ? dark : light, computedToVars(source.content));
|
|
28687
28688
|
} else {
|
|
28688
28689
|
Object.assign(light, tokensToVars(source.content));
|
|
28689
28690
|
}
|
|
@@ -39515,11 +39516,17 @@ function partsReport(body, css = "") {
|
|
|
39515
39516
|
}
|
|
39516
39517
|
return report;
|
|
39517
39518
|
}
|
|
39519
|
+
function kitVariantsAfter(componentCss) {
|
|
39520
|
+
return DS_KIT_CSS.split("\n").filter((line2) => {
|
|
39521
|
+
const variant = /^\.(ds-[a-z]+-[a-z0-9-]+)\{/.exec(line2)?.[1];
|
|
39522
|
+
return variant !== void 0 && !componentCss.includes(`.${variant}`);
|
|
39523
|
+
}).join("\n");
|
|
39524
|
+
}
|
|
39518
39525
|
function modelPrototypeDocument(input) {
|
|
39519
39526
|
const { system } = input;
|
|
39520
39527
|
const css = input.css.replace(/</g, "");
|
|
39521
39528
|
const body = withoutUnsafeMarkup(input.body);
|
|
39522
|
-
const kitCss = [compactTokensCss(system.tokensCss), DS_KIT_CSS, system.componentCss].filter(Boolean).join("\n");
|
|
39529
|
+
const kitCss = [compactTokensCss(system.tokensCss), DS_KIT_CSS, system.componentCss, system.componentCss ? kitVariantsAfter(system.componentCss) : ""].filter(Boolean).join("\n");
|
|
39523
39530
|
return [
|
|
39524
39531
|
"<!doctype html>",
|
|
39525
39532
|
'<html lang="en">',
|