diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index cffc06258..af0e21f89 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -256,10 +256,10 @@ License breakdown: MIT (525), ISC (43), Apache-2.0 (12), Apache-2.0 OR MIT (12), | `@pierre/theme` | 2.0.0 | apache-2.0 | | `@pierre/theming` | 1.0.1 | apache-2.0 | | `@playwright/test` | 1.61.1 | Apache-2.0 | -| `@protolabsai/design` | 0.10.1 | MIT | +| `@protolabsai/design` | 0.11.0 | MIT | | `@protolabsai/design` | 0.9.2 | MIT | -| `@protolabsai/ui` | 0.63.0 | MIT | -| `@protolabsai/ui-css` | 0.63.0 | MIT | +| `@protolabsai/ui` | 0.66.1 | MIT | +| `@protolabsai/ui-css` | 0.66.1 | MIT | | `@protolabsai/vitepress-theme` | 0.3.12 | MIT | | `@radix-ui/primitive` | 1.1.4 | MIT | | `@radix-ui/react-arrow` | 1.1.10 | MIT | @@ -784,4 +784,4 @@ License breakdown: MIT (525), ISC (43), Apache-2.0 (12), Apache-2.0 OR MIT (12), | `zustand` | 5.0.14 | MIT | | `zwitch` | 2.0.4 | MIT | - + diff --git a/apps/web/package.json b/apps/web/package.json index af4c12362..52b7c0aad 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,8 +17,8 @@ }, "dependencies": { "@pierre/diffs": "1.5.0", - "@protolabsai/design": "^0.10.1", - "@protolabsai/ui": "^0.63.0", + "@protolabsai/design": "^0.11.0", + "@protolabsai/ui": "^0.66.1", "@shikijs/themes": "3.23.0", "@shikijs/transformers": "3.23.0", "@streamdown/code": "^1.1.1", diff --git a/apps/web/src/app/tokenNameGuard.test.ts b/apps/web/src/app/tokenNameGuard.test.ts index 797243c8b..8c7cabf1d 100644 --- a/apps/web/src/app/tokenNameGuard.test.ts +++ b/apps/web/src/app/tokenNameGuard.test.ts @@ -41,14 +41,14 @@ const EXEMPT = new Set([ // A `--pl-*` custom-property DECLARATION (`--pl-name:`), used to read what a stylesheet // defines. It cannot match a var() read: `var(--pl-x)` / `var(--pl-x, …)` have `)` or `,` // after the name, never the `:` this requires. -const DECL = /(--pl-[a-z0-9-]+)\s*:/g; +const DECL = /(--pl-[a-z0-9_-]+)\s*:/g; const declaredIn = (text: string): string[] => [...text.matchAll(DECL)].map((m) => m[1]); // The DEFINED set — every --pl-* the installed design system declares. Derived from the // installed packages, never hand-copied. Four live sources, unioned: // 1. PL_TOKEN_VARS — @protolabsai/design's tokens.json, flattened by PluginView exactly the -// way the DS build emits tokens.css. This is the load-bearing source at test time (~74 -// names on design ^0.10.0). +// way the DS build emits tokens.css. This is the load-bearing source at test time (~85 +// names on design ^0.11.0). // 2/3. @protolabsai/ui's plugin-kit.css and @protolabsai/design's tokens.css, parsed for // their `--pl-*:` declarations. Vitest stubs node_modules CSS imports to "" (the // `css.include` anchor deliberately covers only apps/web/src, to keep DS *component* CSS @@ -75,7 +75,7 @@ for (const [file, text] of Object.entries(SOURCES)) { // Built from a RegExp *string*, with `var(` split from `--pl-` at every use site, so this // file's own source never contains a bare `var(--pl-…)` the sweep (or a copy of it) could trip // on — belt-and-suspenders on top of the self-exemption above. -const VAR_REF = "var\\(\\s*(--pl-[a-z0-9-]+)"; +const VAR_REF = "var\\(\\s*(--pl-[a-z0-9_-]+)"; const refsIn = (line: string): string[] => [...line.matchAll(new RegExp(VAR_REF, "g"))].map((m) => m[1]); @@ -111,11 +111,26 @@ describe("every var(--pl-*) in the console is defined by the installed DS (#3682 expect(defined.size).toBeGreaterThan(40); expect(PL_TOKEN_VARS.length).toBeGreaterThan(40); // Spot-check well-known names that only appear if the derivation actually ran. - for (const n of ["--pl-color-fg", "--pl-color-accent", "--pl-color-status-error", "--pl-radius"]) { + for (const n of [ + "--pl-color-fg", + "--pl-color-accent", + "--pl-color-status-error", + "--pl-radius", + "--pl-radius-md", + "--pl-radius-pill", + "--pl-space-0_5", + "--pl-space-1_5", + "--pl-space-2_5", + ]) { expect(defined.has(n)).toBe(true); } }); + it("VAR_REF captures underscore token names whole (meta-guard, built by concat)", () => { + // `var(--pl-space-0_5)` must be captured as "--pl-space-0_5", not truncated to "--pl-space-0". + expect(refsIn("gap: " + "var(" + "--pl-space-0_5);")).toEqual(["--pl-space-0_5"]); + }); + it("sweeps the tree: no var(--pl-…) references a token the DS does not define", () => { expect(sweep()).toEqual([]); }); @@ -347,7 +362,7 @@ function matchParen(text: string, openIdx: number): number { // source carries no bare literal of its own. A nested var() that itself trails a literal (or more // values) is NOT entirely one var() read, so it fails here — and the inner var() is caught on its // own by the scan below anyway. -const NESTED_HEAD = new RegExp("^var\\(\\s*" + "--pl-" + "[a-z0-9-]+"); +const NESTED_HEAD = new RegExp("^var\\(\\s*" + "--pl-" + "[a-z0-9_-]+"); function isNestedTokenFallback(fallback: string): boolean { const t = fallback.trim(); if (!NESTED_HEAD.test(t)) return false; diff --git a/changelog.d/3887.changed.md b/changelog.d/3887.changed.md new file mode 100644 index 000000000..79dbc1333 --- /dev/null +++ b/changelog.d/3887.changed.md @@ -0,0 +1 @@ +- **Bump @protolabsai/design to ^0.11.0 and @protolabsai/ui to ^0.66.1; tokenNameGuard accepts `_` in token names (#3887).** Adds radius scale (`--pl-radius-md/-lg/-xl/-pill`) and spacing half-steps (`--pl-space-0_5/-1_5/-2_5`) to the installed DS. The token-name guard's `DECL` and `VAR_REF` regexes are widened from `[a-z0-9-]` to `[a-z0-9_-]` so `var(--pl-space-0_5)` is captured whole rather than truncated at the underscore. diff --git a/package-lock.json b/package-lock.json index dbcd18d01..79f1b244b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,8 +36,8 @@ "license": "MIT", "dependencies": { "@pierre/diffs": "1.5.0", - "@protolabsai/design": "^0.10.1", - "@protolabsai/ui": "^0.63.0", + "@protolabsai/design": "^0.11.0", + "@protolabsai/ui": "^0.66.1", "@shikijs/themes": "3.23.0", "@shikijs/transformers": "3.23.0", "@streamdown/code": "^1.1.1", @@ -66,9 +66,9 @@ } }, "apps/web/node_modules/@protolabsai/design": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.10.1.tgz", - "integrity": "sha512-IjUpjIZvvZCshp7ykggCP0tOvm2u3NlRBb+FSqO1/NdmqxgduT1536ktYFnn6sys4yO0tu/8cwywjtlmfETQiw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.11.0.tgz", + "integrity": "sha512-bI045stBOwK2+4KfjJSeOTgCN/6dwrg9bE9mTsDqGhoefKUSX8uIhRAf+YOzhXKrAloX8ZuTOfJax0R6QLjI2Q==", "license": "MIT", "bin": { "protolabs-sync-assets": "bin/sync-assets.mjs" @@ -1840,16 +1840,16 @@ } }, "node_modules/@protolabsai/ui": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@protolabsai/ui/-/ui-0.63.0.tgz", - "integrity": "sha512-In7lTsqswRQBCywwxbVongzB7cwouPAcp1Up+Lurj2IOdL9+OWLnGQSVRE4c+fRiKpFZp0qb/Je7so68GUUjcA==", + "version": "0.66.1", + "resolved": "https://registry.npmjs.org/@protolabsai/ui/-/ui-0.66.1.tgz", + "integrity": "sha512-ISBND67yl5g4wMLEggoUu0PhlFE3mugsKPUDmnJ8Ph5D7FIMFKlDSO7fx5s8PzhPd2sCXnaFW09iLivHFLwKpA==", "license": "MIT", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@protolabsai/design": "0.10.1", - "@protolabsai/ui-css": "0.63.0", + "@protolabsai/design": "0.11.0", + "@protolabsai/ui-css": "0.66.1", "@radix-ui/react-dropdown-menu": "^2.1.17", "@radix-ui/react-popover": "^1.1.16", "@radix-ui/react-tooltip": "^1.2.10", @@ -1868,27 +1868,27 @@ } }, "node_modules/@protolabsai/ui-css": { - "version": "0.63.0", - "resolved": "https://registry.npmjs.org/@protolabsai/ui-css/-/ui-css-0.63.0.tgz", - "integrity": "sha512-7uFvy/1Bf60GA6wwH5WeUdQXRBiLa+rtOrnYKYwgmybz8y2paBhchnNQNQxeowYRk1LJJta51axGh9MAXGOokg==", + "version": "0.66.1", + "resolved": "https://registry.npmjs.org/@protolabsai/ui-css/-/ui-css-0.66.1.tgz", + "integrity": "sha512-gQSWlpSQq0Ir13lp/eFl0Kb8ffDmJEX1cw2+J/i7euCnoqDctPafQ/bbYLrhWoPL4zGnACBu98R51fUbBdbang==", "license": "MIT", "dependencies": { - "@protolabsai/design": "0.10.1" + "@protolabsai/design": "0.11.0" } }, "node_modules/@protolabsai/ui-css/node_modules/@protolabsai/design": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.10.1.tgz", - "integrity": "sha512-IjUpjIZvvZCshp7ykggCP0tOvm2u3NlRBb+FSqO1/NdmqxgduT1536ktYFnn6sys4yO0tu/8cwywjtlmfETQiw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.11.0.tgz", + "integrity": "sha512-bI045stBOwK2+4KfjJSeOTgCN/6dwrg9bE9mTsDqGhoefKUSX8uIhRAf+YOzhXKrAloX8ZuTOfJax0R6QLjI2Q==", "license": "MIT", "bin": { "protolabs-sync-assets": "bin/sync-assets.mjs" } }, "node_modules/@protolabsai/ui/node_modules/@protolabsai/design": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.10.1.tgz", - "integrity": "sha512-IjUpjIZvvZCshp7ykggCP0tOvm2u3NlRBb+FSqO1/NdmqxgduT1536ktYFnn6sys4yO0tu/8cwywjtlmfETQiw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@protolabsai/design/-/design-0.11.0.tgz", + "integrity": "sha512-bI045stBOwK2+4KfjJSeOTgCN/6dwrg9bE9mTsDqGhoefKUSX8uIhRAf+YOzhXKrAloX8ZuTOfJax0R6QLjI2Q==", "license": "MIT", "bin": { "protolabs-sync-assets": "bin/sync-assets.mjs" diff --git a/tests/data/ds-plugin-kit-tokens.txt b/tests/data/ds-plugin-kit-tokens.txt index 00815ff1b..04844206f 100644 --- a/tests/data/ds-plugin-kit-tokens.txt +++ b/tests/data/ds-plugin-kit-tokens.txt @@ -47,6 +47,13 @@ --pl-font-line-height-heading --pl-font-mono --pl-font-sans +--pl-font-size-2xs +--pl-font-size-3xs +--pl-font-size-base +--pl-font-size-lg +--pl-font-size-sm +--pl-font-size-xl +--pl-font-size-xs --pl-font-weight-body --pl-font-weight-medium --pl-font-weight-semibold @@ -61,6 +68,10 @@ --pl-motion-status --pl-motion-theme --pl-radius +--pl-radius-lg +--pl-radius-md +--pl-radius-pill +--pl-radius-xl --pl-shadow-card --pl-shadow-glow --pl-shadow-popover