@stealthscale/plugin-theming 0.0.0-stage → 0.2.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +135 -2
  3. package/dist/accessibility-Dg5Dh35o.js +409 -0
  4. package/dist/attributes-vx1W0PiK.js +26 -0
  5. package/dist/breakpoints-CJjhy79u.js +83 -0
  6. package/dist/code-DcoH6hCX.js +69 -0
  7. package/dist/conditions-CjjQwqro.js +338 -0
  8. package/dist/corners-CH5jyCks.js +92 -0
  9. package/dist/cursors-hl00ix41.js +54 -0
  10. package/dist/cyclonedx/bom.json +1 -0
  11. package/dist/density-DEW_j0I5.js +207 -0
  12. package/dist/depth-DCn3mAAJ.js +143 -0
  13. package/dist/doc-page-BQXdbP_h.js +439 -0
  14. package/dist/extending-CY7ry7Y4.js +31 -0
  15. package/dist/faces-D76c_Ryh.js +65 -0
  16. package/dist/gate-CoX2Yr9x.js +199 -0
  17. package/dist/index.d.ts +48 -0
  18. package/dist/index.js +39 -0
  19. package/dist/layers-BxdWdfPg.js +53 -0
  20. package/dist/looks-BrROho5Y.js +107 -0
  21. package/dist/measure-uwF7Fmpy.js +137 -0
  22. package/dist/mode-colors-Cf_ZPo3g.js +260 -0
  23. package/dist/mode-panels-Bmh0ec0U.js +54 -0
  24. package/dist/motion-DRbsuZZo.js +202 -0
  25. package/dist/overview-BbE82N2c.js +192 -0
  26. package/dist/palettes-CZo2HrNT.js +49 -0
  27. package/dist/parts-BVmqVMgo.js +25 -0
  28. package/dist/recipes-C88xVIGB.js +32 -0
  29. package/dist/rows-Dv8c7jye.js +18 -0
  30. package/dist/sampler-Ue67PX2n.js +27 -0
  31. package/dist/series-AvSZjk2b.js +63 -0
  32. package/dist/setting-BsgJKTlh.js +12 -0
  33. package/dist/sizes-B7LgvyBS.js +98 -0
  34. package/dist/spacing-DMyyV6vX.js +75 -0
  35. package/dist/surfaces-Db0HjMwB.js +76 -0
  36. package/dist/text-styles-BZnXaigP.js +233 -0
  37. package/dist/theme.d.ts +12 -0
  38. package/dist/theme.js +23 -0
  39. package/dist/themes-yClyRA9e.js +305 -0
  40. package/dist/theming-text.recipe-Dvcza4j1.js +308 -0
  41. package/dist/token-table-yrZh5kLy.js +182 -0
  42. package/dist/tokens-7Pm-eLiZ.js +138 -0
  43. package/dist/use-readings-D56mNtEc.js +77 -0
  44. package/dist/variables-ymFs3Bzn.js +43 -0
  45. package/dist/worn-D4HEJsJ2.js +15 -0
  46. package/dist/writing-b05oSPB2.js +31 -0
  47. package/package.json +124 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stealth Scale B.V.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,136 @@
1
- # Temporary Holding Version
1
+ # @stealthscale/plugin-theming
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `@stealthscale/plugin-theming` is the theming plugin. Its 25 pages document the theme a product's
4
+ page wears: the themes on offer, every token, style and condition the theme fills with the value the
5
+ stylesheet resolves in both color modes, the theme gate's pairs measured on the page, and how a
6
+ theme is written, extended and checked. Its contract and its words are in
7
+ `@stealthscale/plugin-theming-contract`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @stealthscale/plugin-theming
13
+ ```
14
+
15
+ The package peers on the component packages it renders (`component-actions`,
16
+ `component-collections`, `component-content`, `component-data`, `component-disclosure`,
17
+ `component-forms`, `component-layout`, `component-navigation`, `component-screen`,
18
+ `component-surfaces` and `component-typography`), on `hooks`, `provider-i18n`, `provider-router`,
19
+ `provider-shell`, `sdk-plugin` and `theme`, all under `@stealthscale`, and on `react`. It depends on
20
+ its contract package and `sdk-core`, and on `lucide-react` for the icons of the copy control on its
21
+ code samples.
22
+
23
+ ## Installing the plugin in a product
24
+
25
+ A product installs the manifest:
26
+
27
+ ```ts
28
+ // src/product.ts
29
+ import { manifest as theming } from "@stealthscale/plugin-theming";
30
+ import { defineProduct, installed } from "@stealthscale/sdk-core";
31
+
32
+ export default defineProduct({
33
+ name: "product.name",
34
+ plugins: [installed(theming)],
35
+ productId: "docs",
36
+ version: "1.0.0",
37
+ });
38
+ ```
39
+
40
+ The pages read every token by name while they run, so the product's `theme.config.ts` states
41
+ `tokens: "all"`. Without that setting the compiler writes only the tokens a recipe or the product's
42
+ own code uses, and the pages mark every other token as not in the stylesheet.
43
+
44
+ ```ts
45
+ // theme.config.ts
46
+ import { cinder } from "@stealthscale/theme-cinder";
47
+ import { ink } from "@stealthscale/theme-ink";
48
+ import { type Application } from "@stealthscale/theme/authoring";
49
+
50
+ export default {
51
+ themes: [ink, cinder],
52
+ tokens: "all",
53
+ } satisfies Application;
54
+ ```
55
+
56
+ The themes page shows a card per theme the product's `Shell` offers, and a product built with the
57
+ product layers offers every theme `theme.config.ts` lists. A product without themes shows the
58
+ foundation alone on every page.
59
+
60
+ ## The pages
61
+
62
+ | Menu | Page | Shows |
63
+ | -------- | --------------- | ---------------------------------------------------------------------------------- |
64
+ | | `overview` | What a theme is, how it styles a page, and a card per page of each menu |
65
+ | Basics | `themes` | A card per theme on offer, under its own attribute, with a button that wears it |
66
+ | | `tokens` | Reference and semantic tokens, how a recipe refers to one, their custom properties |
67
+ | | `recipes` | How a component styles through its recipe, its layers and its class names |
68
+ | | `conditions` | The foundation's fourteen conditions, and the ones the browser decides now |
69
+ | | `accessibility` | The gate's text, boundary and focus pairs measured on the page in both modes |
70
+ | Color | `palettes` | The eleven roles of each of the eight palettes, in both modes, with ratios |
71
+ | | `surfaces` | The backgrounds, inks and lines with their status members, in both modes |
72
+ | | `series` | The eight series colors on the page and on a panel |
73
+ | | `code` | The code inks on the page, on a panel and in a sample |
74
+ | | `looks` | Every layer style on a box |
75
+ | Type | `faces` | The three faces, the font sizes and the weights, each set in a sample |
76
+ | | `text-styles` | Every size style and role style set in a line, the line heights and the tracking |
77
+ | Space | `spacing` | The gap and inset scales, the grid, the marker, the ring and the safe area |
78
+ | | `sizes` | The control, icon and tag scales, the layout widths, the measures and the ratios |
79
+ | | `breakpoints` | The breakpoints and the container sizes |
80
+ | | `density` | The same controls at each density, and `dense()` |
81
+ | Shape | `corners` | The concentric corners, the reference radii, the stroke widths and the ring |
82
+ | | `depth` | The shadows in both modes, the blurs and the opacities |
83
+ | | `layers` | The stacking order |
84
+ | Motion | `motion` | The paces and curves, the reference durations and curves, every animation style |
85
+ | | `cursors` | Every cursor on a tile under the pointer |
86
+ | Building | `writing` | A shipped theme's whole statement, the axes, the colors and a derived theme |
87
+ | | `extending` | A theme's recipe extension, its scope and the keys it cannot state |
88
+ | | `gate` | `violations()`, the thresholds, the floor, skipping a check and `report()` |
89
+
90
+ Each page titles the document `<title> · <product name>`, and a rail beside its sections lists them
91
+ and marks the ones on screen. A section's text is Markdown, and each code sample has a copy control.
92
+
93
+ ## Reading the stylesheet
94
+
95
+ No page contains a value of a token. A page lists the token's names from the theme foundation's
96
+ `@stealthscale/theme/contract` entry and reads each value while it runs:
97
+
98
+ - A probe the page appends into the block and removes in the same task states the token's custom
99
+ property three times. A color is read as `color`, every other token as the custom property with
100
+ its references substituted, and a length's pixels as `inline-size`.
101
+ - A color or a shadow is read in two panels, one per mode, each with the worn theme's `data-theme`
102
+ and its own `data-color-mode`. The panels are side by side where each has `sizes.xl`, and stack
103
+ otherwise.
104
+ - A contrast ratio comes from the foundation's `contrast()`, on the same pairs and thresholds the
105
+ theme gate measures, so the page and the gate cannot disagree.
106
+ - A page marks a token the stylesheet does not declare as not in the stylesheet.
107
+
108
+ The values follow the theme the page wears. A person who wears another theme from its card or from
109
+ the bar's theme switcher sees the values of that theme.
110
+
111
+ ## The recipes it states
112
+
113
+ Every part a page renders is a component of the library. Five recipes style the samples, published
114
+ as a preset from `@stealthscale/plugin-theming/theme`:
115
+
116
+ | Recipe | Renders |
117
+ | ---------------- | ------------------------------------------------------------------------------ |
118
+ | `theming-panel` | The panel that shows a block in one color mode |
119
+ | `theming-sample` | A bar, a square, a line, a box at a ratio, a tile or words that show one token |
120
+ | `theming-look` | A box in each layer style |
121
+ | `theming-text` | A line in each text style |
122
+ | `theming-motion` | A tile that plays each animation style |
123
+
124
+ The look, text and motion recipes take their axes from the foundation's name lists, and every recipe
125
+ with an axis states each value under `staticCss`, so a product compiles every sample. A page passes
126
+ a token to a sample as a custom property, such as `--theming-radius`, which the sample's recipe
127
+ reads.
128
+
129
+ ## Words
130
+
131
+ Every word a page writes is a key in the `theming` namespace, in the contract package's
132
+ `locales/en/theming.json` and `locales/en/theming/<slug>.json`.
133
+
134
+ ## Licence
135
+
136
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,409 @@
1
+ import { n as colorOf, o as ratioOf } from "./measure-uwF7Fmpy.js";
2
+ import { n as variableOf } from "./variables-ymFs3Bzn.js";
3
+ import { n as useWords, t as DocPage } from "./doc-page-BQXdbP_h.js";
4
+ import { n as attributesOf } from "./attributes-vx1W0PiK.js";
5
+ import { t as useReadings } from "./use-readings-D56mNtEc.js";
6
+ import { t as useWornTheme } from "./worn-D4HEJsJ2.js";
7
+ import { PALETTES, THRESHOLDS, boundaryPairs, focusPairs, textPairs } from "@stealthscale/theme/contract";
8
+ import { c } from "react/compiler-runtime";
9
+ import { useState } from "react";
10
+ import { Stack } from "@stealthscale/component-layout";
11
+ import { ChevronRightIcon } from "lucide-react";
12
+ import { Table } from "@stealthscale/component-collections";
13
+ import { Badge, Format } from "@stealthscale/component-data";
14
+ import { Details } from "@stealthscale/component-disclosure";
15
+ import { Code, Text } from "@stealthscale/component-typography";
16
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
+ //#region src/blocks/pairs.ts
18
+ /**
19
+ * Returns the custom properties a list of pairs reads: each front and each back, once.
20
+ *
21
+ * @param pairs - The pairs, whose tokens are paths in the `colors` category.
22
+ */
23
+ function variablesOf(pairs) {
24
+ return [...new Set(pairs.flatMap(({ back, front }) => [variableOf("colors", front), variableOf("colors", back)]))];
25
+ }
26
+ /**
27
+ * Returns the ratio of one pair in one mode's readings.
28
+ */
29
+ function ratioIn(pair, readings) {
30
+ return ratioOf(colorOf(readings.get(variableOf("colors", pair.front))), colorOf(readings.get(variableOf("colors", pair.back))));
31
+ }
32
+ /**
33
+ * Measures every pair in both modes.
34
+ *
35
+ * @param pairs - The gate's pairs, whose tokens are paths in the `colors` category.
36
+ * @param light - The readings of the light mode.
37
+ * @param dark - The readings of the dark mode.
38
+ */
39
+ function measuredPairs(pairs, light, dark) {
40
+ return pairs.map((pair) => ({
41
+ ...pair,
42
+ dark: ratioIn(pair, dark),
43
+ light: ratioIn(pair, light)
44
+ }));
45
+ }
46
+ /**
47
+ * Returns true where a pair clears its ratio in both modes.
48
+ *
49
+ * @param pair - A measured pair.
50
+ */
51
+ function passes({ dark, light, minimum }) {
52
+ return light !== void 0 && dark !== void 0 && light >= minimum && dark >= minimum;
53
+ }
54
+ /**
55
+ * Sums a list of measured pairs: how many there are, how many pass, and the lowest ratio.
56
+ *
57
+ * @param pairs - The measured pairs.
58
+ */
59
+ function summaryOf(pairs) {
60
+ const ratios = pairs.flatMap(({ dark, light }) => [light, dark].filter((ratio) => ratio !== void 0));
61
+ return {
62
+ count: pairs.length,
63
+ lowest: ratios.length === 0 ? void 0 : Math.min(...ratios),
64
+ passing: pairs.filter((pair) => passes(pair)).length
65
+ };
66
+ }
67
+ //#endregion
68
+ //#region src/blocks/pair-summary.tsx
69
+ /**
70
+ * The digits a ratio is written with.
71
+ */
72
+ const DIGITS = {
73
+ maximumFractionDigits: 2,
74
+ minimumFractionDigits: 2
75
+ };
76
+ /**
77
+ * Returns a ratio cell: the ratio with two digits and a badge where it is below the pair's minimum,
78
+ * or nothing where it cannot be measured.
79
+ */
80
+ function ratioCell(ratio, minimum, below) {
81
+ if (ratio === void 0) return null;
82
+ return /* @__PURE__ */ jsxs(Stack, {
83
+ direction: "row",
84
+ gap: "xs",
85
+ justify: "end",
86
+ children: [/* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx(Format.Number, {
87
+ options: DIGITS,
88
+ value: ratio
89
+ }), ":1"] }), ratio < minimum ? /* @__PURE__ */ jsx(Badge, {
90
+ palette: "error",
91
+ size: "sm",
92
+ children: below
93
+ }) : null]
94
+ });
95
+ }
96
+ /**
97
+ * Returns a cell with a token's name in code.
98
+ */
99
+ function tokenCell(token) {
100
+ return /* @__PURE__ */ jsx(Code, { children: token });
101
+ }
102
+ /**
103
+ * Returns the table's columns: the two tokens, the minimum, and the ratio in each mode.
104
+ */
105
+ function columnsOf(headings) {
106
+ return [
107
+ {
108
+ cell: ({ front }) => tokenCell(front),
109
+ key: "front",
110
+ label: headings.front,
111
+ rowHeader: true
112
+ },
113
+ {
114
+ cell: ({ back }) => tokenCell(back),
115
+ key: "back",
116
+ label: headings.back
117
+ },
118
+ {
119
+ key: "minimum",
120
+ label: headings.minimum,
121
+ numeric: true
122
+ },
123
+ {
124
+ cell: ({ light, minimum }) => ratioCell(light, minimum, headings.below),
125
+ key: "light",
126
+ label: headings.light,
127
+ numeric: true
128
+ },
129
+ {
130
+ cell: ({ dark, minimum }) => ratioCell(dark, minimum, headings.below),
131
+ key: "dark",
132
+ label: headings.dark,
133
+ numeric: true
134
+ }
135
+ ];
136
+ }
137
+ /**
138
+ * Renders the sum of the pairs, and the pairs in a disclosure under it.
139
+ */
140
+ function PairSummary(t0) {
141
+ const $ = c(29);
142
+ const { caption, rows } = t0;
143
+ const { t } = useWords();
144
+ let T0;
145
+ let T1;
146
+ let t1;
147
+ let t2;
148
+ let t3;
149
+ if ($[0] !== rows || $[1] !== t) {
150
+ const { count, lowest, passing } = summaryOf(rows);
151
+ t3 = /* @__PURE__ */ jsx(Text, { children: t("blocks.pairs", {
152
+ count,
153
+ lowest: lowest?.toFixed(2) ?? "-",
154
+ passing
155
+ }) });
156
+ T1 = Details.Root;
157
+ T0 = Details.Summary;
158
+ if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
159
+ t1 = /* @__PURE__ */ jsx(Details.Indicator, { children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) });
160
+ $[7] = t1;
161
+ } else t1 = $[7];
162
+ t2 = t("blocks.everyPair", { count });
163
+ $[0] = rows;
164
+ $[1] = t;
165
+ $[2] = T0;
166
+ $[3] = T1;
167
+ $[4] = t1;
168
+ $[5] = t2;
169
+ $[6] = t3;
170
+ } else {
171
+ T0 = $[2];
172
+ T1 = $[3];
173
+ t1 = $[4];
174
+ t2 = $[5];
175
+ t3 = $[6];
176
+ }
177
+ let t4;
178
+ if ($[8] !== T0 || $[9] !== t1 || $[10] !== t2) {
179
+ t4 = /* @__PURE__ */ jsxs(T0, { children: [t1, t2] });
180
+ $[8] = T0;
181
+ $[9] = t1;
182
+ $[10] = t2;
183
+ $[11] = t4;
184
+ } else t4 = $[11];
185
+ let t5;
186
+ if ($[12] !== caption || $[13] !== t) {
187
+ t5 = t("blocks.tableOf", { name: caption });
188
+ $[12] = caption;
189
+ $[13] = t;
190
+ $[14] = t5;
191
+ } else t5 = $[14];
192
+ let t6;
193
+ if ($[15] !== t) {
194
+ t6 = columnsOf({
195
+ back: t("blocks.back"),
196
+ below: t("blocks.below"),
197
+ dark: t("blocks.dark"),
198
+ front: t("blocks.front"),
199
+ light: t("blocks.light"),
200
+ minimum: t("blocks.minimum")
201
+ });
202
+ $[15] = t;
203
+ $[16] = t6;
204
+ } else t6 = $[16];
205
+ let t7;
206
+ if ($[17] !== caption || $[18] !== rows || $[19] !== t5 || $[20] !== t6) {
207
+ t7 = /* @__PURE__ */ jsx(Details.Content, { children: /* @__PURE__ */ jsx(Table.Simple, {
208
+ "aria-label": t5,
209
+ caption,
210
+ columns: t6,
211
+ rows,
212
+ rowToKey: _temp
213
+ }) });
214
+ $[17] = caption;
215
+ $[18] = rows;
216
+ $[19] = t5;
217
+ $[20] = t6;
218
+ $[21] = t7;
219
+ } else t7 = $[21];
220
+ let t8;
221
+ if ($[22] !== T1 || $[23] !== t4 || $[24] !== t7) {
222
+ t8 = /* @__PURE__ */ jsxs(T1, { children: [t4, t7] });
223
+ $[22] = T1;
224
+ $[23] = t4;
225
+ $[24] = t7;
226
+ $[25] = t8;
227
+ } else t8 = $[25];
228
+ let t9;
229
+ if ($[26] !== t3 || $[27] !== t8) {
230
+ t9 = /* @__PURE__ */ jsxs(Fragment, { children: [t3, t8] });
231
+ $[26] = t3;
232
+ $[27] = t8;
233
+ $[28] = t9;
234
+ } else t9 = $[28];
235
+ return t9;
236
+ }
237
+ function _temp(t0) {
238
+ const { back, front } = t0;
239
+ return `${front} ${back}`;
240
+ }
241
+ //#endregion
242
+ //#region src/blocks/pair-table.tsx
243
+ /**
244
+ * Renders a class of the theme gate's pairs measured live on the theme the page wears.
245
+ */
246
+ /**
247
+ * Renders the pairs' sum and every pair, each measured in both modes.
248
+ *
249
+ * @remarks
250
+ * The pairs are read in two hidden elements, one per mode, each wearing the page's theme, so the
251
+ * ratios are the stylesheet's and not a copy of the gate's arithmetic.
252
+ */
253
+ function PairTable(t0) {
254
+ const $ = c(21);
255
+ const { caption, pairs } = t0;
256
+ const worn = useWornTheme();
257
+ const [light, setLight] = useState(null);
258
+ const [dark, setDark] = useState(null);
259
+ let t1;
260
+ if ($[0] !== pairs) {
261
+ t1 = variablesOf(pairs);
262
+ $[0] = pairs;
263
+ $[1] = t1;
264
+ } else t1 = $[1];
265
+ const variables = t1;
266
+ const t2 = useReadings(light, variables);
267
+ const t3 = useReadings(dark, variables);
268
+ let t4;
269
+ if ($[2] !== pairs || $[3] !== t2 || $[4] !== t3) {
270
+ t4 = measuredPairs(pairs, t2, t3);
271
+ $[2] = pairs;
272
+ $[3] = t2;
273
+ $[4] = t3;
274
+ $[5] = t4;
275
+ } else t4 = $[5];
276
+ const rows = t4;
277
+ let t5;
278
+ if ($[6] !== worn) {
279
+ t5 = attributesOf(worn, "light");
280
+ $[6] = worn;
281
+ $[7] = t5;
282
+ } else t5 = $[7];
283
+ let t6;
284
+ if ($[8] !== t5) {
285
+ t6 = /* @__PURE__ */ jsx("div", {
286
+ hidden: true,
287
+ ref: setLight,
288
+ ...t5
289
+ });
290
+ $[8] = t5;
291
+ $[9] = t6;
292
+ } else t6 = $[9];
293
+ let t7;
294
+ if ($[10] !== worn) {
295
+ t7 = attributesOf(worn, "dark");
296
+ $[10] = worn;
297
+ $[11] = t7;
298
+ } else t7 = $[11];
299
+ let t8;
300
+ if ($[12] !== t7) {
301
+ t8 = /* @__PURE__ */ jsx("div", {
302
+ hidden: true,
303
+ ref: setDark,
304
+ ...t7
305
+ });
306
+ $[12] = t7;
307
+ $[13] = t8;
308
+ } else t8 = $[13];
309
+ let t9;
310
+ if ($[14] !== caption || $[15] !== rows) {
311
+ t9 = /* @__PURE__ */ jsx(PairSummary, {
312
+ caption,
313
+ rows
314
+ });
315
+ $[14] = caption;
316
+ $[15] = rows;
317
+ $[16] = t9;
318
+ } else t9 = $[16];
319
+ let t10;
320
+ if ($[17] !== t6 || $[18] !== t8 || $[19] !== t9) {
321
+ t10 = /* @__PURE__ */ jsxs(Stack, {
322
+ gap: "md",
323
+ children: [
324
+ t6,
325
+ t8,
326
+ t9
327
+ ]
328
+ });
329
+ $[17] = t6;
330
+ $[18] = t8;
331
+ $[19] = t9;
332
+ $[20] = t10;
333
+ } else t10 = $[20];
334
+ return t10;
335
+ }
336
+ //#endregion
337
+ //#region src/pages/accessibility.tsx
338
+ /**
339
+ * Lists each class of pair the gate measures, by its section, with its pairs over the eight
340
+ * semantic palettes at the gate's own thresholds.
341
+ */
342
+ const CLASSES = [
343
+ {
344
+ id: "text",
345
+ pairs: textPairs(PALETTES, THRESHOLDS)
346
+ },
347
+ {
348
+ id: "boundary",
349
+ pairs: boundaryPairs(PALETTES, THRESHOLDS)
350
+ },
351
+ {
352
+ id: "focus",
353
+ pairs: focusPairs(PALETTES, THRESHOLDS)
354
+ }
355
+ ];
356
+ /**
357
+ * Renders the accessibility page.
358
+ */
359
+ function AccessibilityPage() {
360
+ const $ = c(6);
361
+ const { t } = useWords();
362
+ let t0;
363
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
364
+ t0 = { id: "gate" };
365
+ $[0] = t0;
366
+ } else t0 = $[0];
367
+ let t1;
368
+ if ($[1] !== t) {
369
+ let t3;
370
+ let t4;
371
+ let t5;
372
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
373
+ t3 = { id: "targets" };
374
+ t4 = { id: "motion" };
375
+ t5 = { id: "forced" };
376
+ $[3] = t3;
377
+ $[4] = t4;
378
+ $[5] = t5;
379
+ } else {
380
+ t3 = $[3];
381
+ t4 = $[4];
382
+ t5 = $[5];
383
+ }
384
+ t1 = /* @__PURE__ */ jsx(DocPage, {
385
+ page: "accessibility",
386
+ sections: [
387
+ t0,
388
+ ...CLASSES.map((t2) => {
389
+ const { id, pairs } = t2;
390
+ return {
391
+ block: /* @__PURE__ */ jsx(PairTable, {
392
+ caption: t(`accessibility.sections.${id}.title`, { defaultValue: id }),
393
+ pairs
394
+ }),
395
+ id
396
+ };
397
+ }),
398
+ t3,
399
+ t4,
400
+ t5
401
+ ]
402
+ });
403
+ $[1] = t;
404
+ $[2] = t1;
405
+ } else t1 = $[2];
406
+ return t1;
407
+ }
408
+ //#endregion
409
+ export { AccessibilityPage };
@@ -0,0 +1,26 @@
1
+ import { COLOR_MODE_ATTRIBUTE, THEME_ATTRIBUTE } from "@stealthscale/theme";
2
+ //#region src/reading/attributes.ts
3
+ /**
4
+ * Writes the attributes that switch an element to the worn theme in one color mode.
5
+ */
6
+ /**
7
+ * Lists the modes in the order a page shows them.
8
+ */
9
+ const MODES = ["light", "dark"];
10
+ /**
11
+ * Returns the attributes of an element in a mode: the mode, and the worn theme beside it.
12
+ *
13
+ * @remarks
14
+ * The theme is stated beside the mode, because the built stylesheet resolves a theme's colors on
15
+ * the element with the theme attribute. A product that offers no theme states the mode alone.
16
+ * @param worn - The theme the page wears, or undefined where the product offers none.
17
+ * @param mode - The color mode.
18
+ */
19
+ function attributesOf(worn, mode) {
20
+ return worn === void 0 ? { [COLOR_MODE_ATTRIBUTE]: mode } : {
21
+ [COLOR_MODE_ATTRIBUTE]: mode,
22
+ [THEME_ATTRIBUTE]: worn
23
+ };
24
+ }
25
+ //#endregion
26
+ export { attributesOf as n, MODES as t };
@@ -0,0 +1,83 @@
1
+ import { n as useWords, t as DocPage } from "./doc-page-BQXdbP_h.js";
2
+ import { t as tokenRows } from "./rows-Dv8c7jye.js";
3
+ import { t as TokenTable } from "./token-table-yrZh5kLy.js";
4
+ import { BREAKPOINTS, CONTAINERS } from "@stealthscale/theme/contract";
5
+ import { c } from "react/compiler-runtime";
6
+ import { Stack } from "@stealthscale/component-layout";
7
+ import { Code } from "@stealthscale/component-typography";
8
+ import { jsx } from "react/jsx-runtime";
9
+ //#region src/pages/breakpoints.tsx
10
+ /**
11
+ * The container sizes, each named in code.
12
+ *
13
+ * @remarks
14
+ * The compiler writes a container size into each query that names it and declares no custom
15
+ * property for it, so the page lists the names and the prose explains the query.
16
+ */
17
+ const SIZES = /* @__PURE__ */ jsx(Stack, {
18
+ direction: "row",
19
+ gap: "xs",
20
+ wrap: true,
21
+ children: CONTAINERS.map((size) => /* @__PURE__ */ jsx(Code, { children: size }, size))
22
+ });
23
+ /**
24
+ * Renders the breakpoints page.
25
+ */
26
+ function BreakpointsPage() {
27
+ const $ = c(9);
28
+ const { t } = useWords();
29
+ let t0;
30
+ if ($[0] !== t) {
31
+ t0 = t("breakpoints.sections.breakpoints.title");
32
+ $[0] = t;
33
+ $[1] = t0;
34
+ } else t0 = $[1];
35
+ let t1;
36
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
37
+ t1 = tokenRows("breakpoints", BREAKPOINTS);
38
+ $[2] = t1;
39
+ } else t1 = $[2];
40
+ let t2;
41
+ if ($[3] !== t0) {
42
+ t2 = {
43
+ block: /* @__PURE__ */ jsx(TokenTable, {
44
+ caption: t0,
45
+ lengths: true,
46
+ rows: t1
47
+ }),
48
+ id: "breakpoints"
49
+ };
50
+ $[3] = t0;
51
+ $[4] = t2;
52
+ } else t2 = $[4];
53
+ let t3;
54
+ let t4;
55
+ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
56
+ t3 = { id: "conditions" };
57
+ t4 = {
58
+ block: SIZES,
59
+ id: "containers"
60
+ };
61
+ $[5] = t3;
62
+ $[6] = t4;
63
+ } else {
64
+ t3 = $[5];
65
+ t4 = $[6];
66
+ }
67
+ let t5;
68
+ if ($[7] !== t2) {
69
+ t5 = /* @__PURE__ */ jsx(DocPage, {
70
+ page: "breakpoints",
71
+ sections: [
72
+ t2,
73
+ t3,
74
+ t4
75
+ ]
76
+ });
77
+ $[7] = t2;
78
+ $[8] = t5;
79
+ } else t5 = $[8];
80
+ return t5;
81
+ }
82
+ //#endregion
83
+ export { BreakpointsPage };