@stealthscale/component-typography 0.0.0-stage → 0.1.0

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/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,413 @@
1
- # Temporary Holding Version
1
+ # @stealthscale/component-typography
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
+ Text components: a paragraph, a heading, inline code, keycaps, runs of stressed, important,
4
+ highlighted and quoted text, the matches of a search, an icon, a list and a block quotation. Each
5
+ component binds a recipe, and a theme restyles it by extending the recipe. Every value a theme can
6
+ change is an axis of the recipe, so a caller sets it as a prop. `as` changes the element. A
7
+ component with parts is a namespace, such as `Kbd.Root` and `List.Item`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @stealthscale/component-typography
13
+ ```
14
+
15
+ The package peers on `react`, `@stealthscale/theme` and `@stealthscale/hooks`, whose `useHighlight`
16
+ finds the matches `Highlight` marks. Add the preset under `./theme` to the presets of the
17
+ application's compiler.
18
+
19
+ ## Text
20
+
21
+ `Text` renders a paragraph in a `p` element. Set `as="span"` for text inside a line.
22
+
23
+ ```tsx
24
+ import { Text } from "@stealthscale/component-typography";
25
+
26
+ <Text size="lg" tone="muted" weight="medium">
27
+ Your session ends in five minutes.
28
+ </Text>;
29
+ <Text align="center" truncate>
30
+ Payouts settle within two business days in 34 countries.
31
+ </Text>;
32
+ ```
33
+
34
+ `truncate` hides the end of the text and `mask` fades part of it. Show the full text elsewhere, such
35
+ as in a detail view. Set the `inverted` ink only on a `bg.inverted` surface. It fails the text
36
+ contrast ratio on the page.
37
+
38
+ | Axis | Values | Default |
39
+ | ---------- | ------------------------------------------------------------------------------- | --------- |
40
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl` | `md` |
41
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
42
+ | `weight` | `normal`, `medium`, `semibold`, `bold` | inherited |
43
+ | `align` | `start`, `center`, `end`, `justify` | inherited |
44
+ | `truncate` | `true` | off |
45
+ | `motion` | `fade`, `rise`, `reveal` | none |
46
+ | `mask` | `bottom`, `edges`, `radial` | none |
47
+
48
+ ## Heading
49
+
50
+ `Heading` renders a heading in an `h2` element. `as` sets another level. `size` sets the prominence
51
+ and is independent of the level.
52
+
53
+ ```tsx
54
+ import { Heading } from "@stealthscale/component-typography";
55
+
56
+ <Heading as="h1" display size="4xl">
57
+ Welcome back, Ada
58
+ </Heading>;
59
+ <Heading as="h3" size="md" tone="muted">
60
+ Account settings
61
+ </Heading>;
62
+ ```
63
+
64
+ `display` sets the display text role: its `sm` step at `2xl`, its `lg` step at `4xl` and its `md`
65
+ step at every other size. `Text` and `Heading` set `overflow-wrap: anywhere`, so a word wider than
66
+ its container breaks.
67
+
68
+ | Axis | Values | Default |
69
+ | ---------- | ------------------------------------------------------------------------------- | --------- |
70
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `lg` |
71
+ | `display` | `true` | off |
72
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
73
+ | `effect` | `gradient`, `shine` | none |
74
+ | `motion` | `fade`, `rise`, `reveal` | none |
75
+ | `truncate` | `true` | off |
76
+
77
+ ## Code
78
+
79
+ `Code` renders code inside a line of text in a `code` element. A block of code with lines, a title
80
+ and a copy control is `CodeBlock` in `@stealthscale/component-content`.
81
+
82
+ ```tsx
83
+ import { Code, Text } from "@stealthscale/component-typography";
84
+
85
+ <Text>
86
+ Run <Code>pnpm add @stealthscale/theme</Code> in the application's directory.
87
+ </Text>;
88
+ <Code palette="error" variant="solid">
89
+ ENOENT
90
+ </Code>;
91
+ ```
92
+
93
+ | Axis | Values | Default |
94
+ | --------- | ---------------------------------------------------------------------------------- | --------- |
95
+ | `variant` | `solid`, `subtle`, `surface`, `outline`, `plain` | `subtle` |
96
+ | `size` | `sm`, `md` | `md` |
97
+ | `palette` | `primary`, `secondary`, `accent`, `neutral`, `info`, `success`, `warning`, `error` | `neutral` |
98
+
99
+ ## Em
100
+
101
+ `Em` marks stressed text in an `em` element, which has the `emphasis` role. The recipe sets the
102
+ italic face.
103
+
104
+ ```tsx
105
+ import { Em, Text } from "@stealthscale/component-typography";
106
+
107
+ <Text>
108
+ The export starts <Em>after</Em> the backup finishes.
109
+ </Text>;
110
+ <Em as="i">Stealth Scale</Em>;
111
+ ```
112
+
113
+ Set `as="i"` for italic text with no stress, such as a product name or a term. An `i` element has no
114
+ role.
115
+
116
+ | Axis | Values | Default |
117
+ | -------- | ------------------------------------------------------------------------------- | --------- |
118
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
119
+ | `motion` | `fade`, `rise`, `reveal` | none |
120
+
121
+ ## Strong
122
+
123
+ `Strong` marks text as more important than the surrounding text, in a `strong` element, which has
124
+ the `strong` role. The `weight` axis has no `normal` value.
125
+
126
+ ```tsx
127
+ import { Strong, Text } from "@stealthscale/component-typography";
128
+
129
+ <Text>
130
+ Deleting a workspace <Strong tone="error">cannot be undone.</Strong>
131
+ </Text>;
132
+ ```
133
+
134
+ Set `as="b"` for bold text with no importance, such as a keyword in a definition. A `b` element has
135
+ no role.
136
+
137
+ | Axis | Values | Default |
138
+ | -------- | ------------------------------------------------------------------------------- | ---------- |
139
+ | `weight` | `medium`, `semibold`, `bold` | `semibold` |
140
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
141
+ | `motion` | `fade`, `rise`, `reveal` | none |
142
+
143
+ ## Mark
144
+
145
+ `Mark` highlights text inside a line, such as a search hit, in a `mark` element, which has the
146
+ `mark` role. `MarkPropsProvider` sets the variants of every mark below it.
147
+
148
+ ```tsx
149
+ import { Mark, MarkPropsProvider, Text } from "@stealthscale/component-typography";
150
+
151
+ <Text>
152
+ Found <Mark>chassis</Mark> in 3 files.
153
+ </Text>;
154
+ <MarkPropsProvider value={{ palette: "warning", variant: "solid" }}>
155
+ <SearchResults />
156
+ </MarkPropsProvider>;
157
+ ```
158
+
159
+ A highlight that conveys meaning needs a second cue. The `text` look sets a heavier weight, and a
160
+ `VisuallyHidden` beside the run states the meaning to a screen reader. Most screen readers announce
161
+ a `mark` only when the user enables it, and WCAG 1.4.1 fails a distinction made by colour alone.
162
+
163
+ | Axis | Values | Default |
164
+ | --------- | ---------------------------------------------------------------------------------- | --------- |
165
+ | `variant` | `solid`, `subtle`, `surface`, `outline`, `plain`, `text` | `subtle` |
166
+ | `palette` | `primary`, `secondary`, `accent`, `neutral`, `info`, `success`, `warning`, `error` | inherited |
167
+ | `radius` | `l1`, `l2`, `l3`, `full` | `l1` |
168
+ | `inset` | `none`, `xs`, `sm`, `md`. The `plain` and `text` looks set no inset | `xs` |
169
+ | `motion` | `fade`, `rise`, `reveal` | none |
170
+ | `effect` | `glow`, `shine` | none |
171
+
172
+ `none` is for a match inside a word, where padding splits the word: "Pay" marked in "Payout" reads
173
+ "Pay out" at `xs`.
174
+
175
+ ## Highlight
176
+
177
+ `Highlight` renders a string with every match of a search query in a `Mark`, so a reader sees why a
178
+ result matched.
179
+
180
+ ```tsx
181
+ import { Highlight, Text } from "@stealthscale/component-typography";
182
+
183
+ <Text>
184
+ <Highlight query={query}>{article.title}</Highlight>
185
+ </Text>;
186
+ <Highlight palette="warning" query={["refund", "chargeback"]} variant="solid">
187
+ {entry.summary}
188
+ </Highlight>;
189
+ ```
190
+
191
+ | Prop | Values | Default |
192
+ | ------------ | ------------------------------------ | ---------- |
193
+ | `children` | the text, a string | required |
194
+ | `query` | a term, or an array of terms | required |
195
+ | `ignoreCase` | `true`, `false` | `true` |
196
+ | `inset` | the mark's insets | `none` |
197
+ | every other | the mark's axes and a `mark`'s props | the mark's |
198
+
199
+ - The matching is `useHighlight`'s from `@stealthscale/hooks`: every occurrence of every term, by
200
+ substring, letter case ignored unless `ignoreCase` is false, each term trimmed, the longer term
201
+ first. It matches as a filter scope keeps rows, so a result the filter keeps shows its match.
202
+ - Every match renders in `Mark` with the props the caller passes, at the `none` inset unless the
203
+ caller passes another.
204
+ - The component renders no element of its own. The text between the matches renders as it is, so a
205
+ highlight goes wherever its string would.
206
+ - A screen reader announces a `mark` only where its user turns highlights on.
207
+
208
+ Not offered:
209
+
210
+ - Marking the first occurrence alone.
211
+ - Matching whole words only.
212
+ - Matching `cafe` to `café`, which a filter scope does not match either.
213
+
214
+ ## Quote
215
+
216
+ `Quote` renders a quotation inside a line of text in a `q` element. The browser adds the quotation
217
+ marks of the language in `lang`, so the text contains no marks. `cite` takes the address of the
218
+ source.
219
+
220
+ ```tsx
221
+ import { Quote, Text } from "@stealthscale/component-typography";
222
+
223
+ <Text>
224
+ The auditor called the report{" "}
225
+ <Quote cite="https://example.org/audit">complete and accurate</Quote>.
226
+ </Text>;
227
+ ```
228
+
229
+ Set `marks="none"` for text that contains its own punctuation, such as a quotation inside another. A
230
+ quotation set as its own block is `Blockquote.Root`.
231
+
232
+ | Axis | Values | Default |
233
+ | -------- | ------------------------------------------------------------------------------- | --------- |
234
+ | `marks` | `auto`, `none` | `auto` |
235
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
236
+ | `motion` | `fade`, `rise`, `reveal` | none |
237
+
238
+ ## Span
239
+
240
+ `Span` renders text inside a line in a `span` element, which has no semantics. The recipe has no
241
+ `size` axis, so a span inherits the font of its line. `Text` with `as="span"` sets the `md` body
242
+ size, which resets the size inside a heading.
243
+
244
+ ```tsx
245
+ import { Span, Text } from "@stealthscale/component-typography";
246
+
247
+ <Text>
248
+ Due <Span weight="semibold">€1,024.00</Span>
249
+ </Text>;
250
+ <Span truncate>/var/log/nginx/access.log.2026-09-19.gz</Span>;
251
+ ```
252
+
253
+ Use the element with semantics where one applies: `Em` for stress, `Strong` for importance, `Mark`
254
+ for a highlight and `Quote` for a quotation.
255
+
256
+ | Axis | Values | Default |
257
+ | ---------- | ------------------------------------------------------------------------------- | --------- |
258
+ | `tone` | `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | inherited |
259
+ | `weight` | `normal`, `medium`, `semibold`, `bold` | inherited |
260
+ | `truncate` | `true` | off |
261
+ | `motion` | `fade`, `rise`, `reveal` | none |
262
+
263
+ ## Kbd
264
+
265
+ `Kbd.Root` renders one keycap in a `kbd` element. `Kbd.Group` renders a key combination: a `kbd`
266
+ around one `kbd` per key, which is the HTML markup for a combination. The group sets its `size`,
267
+ `variant` and `palette` on every keycap inside it, and a value set on a keycap takes precedence.
268
+
269
+ ```tsx
270
+ import { Kbd, Text } from "@stealthscale/component-typography";
271
+
272
+ <Text>
273
+ Press{" "}
274
+ <Kbd.Group>
275
+ <Kbd.Root>⌘</Kbd.Root>
276
+ <Kbd.Root>K</Kbd.Root>
277
+ </Kbd.Group>{" "}
278
+ to search.
279
+ </Text>;
280
+ <Kbd.Root variant="outline">Esc</Kbd.Root>;
281
+ ```
282
+
283
+ A keycap is 19.2, 21.6 or 24px tall at `sm`, `md` and `lg`, so it fits a 24px line of body text. A
284
+ one-character key is square. The keycap uses the body face, which renders `⌘`, `⇧` and `⌥` at the
285
+ height of the letters.
286
+
287
+ | Axis | Values | Default |
288
+ | --------- | ---------------------------------------------------------------------------------- | --------- |
289
+ | `variant` | `raised`, `outline`, `subtle`, `plain` | `raised` |
290
+ | `size` | `sm`, `md`, `lg` | `md` |
291
+ | `palette` | `primary`, `secondary`, `accent`, `neutral`, `info`, `success`, `warning`, `error` | `neutral` |
292
+
293
+ ## Icon
294
+
295
+ `Icon` renders an icon in an `svg` element with the `img` role. Pass the artwork as paths in the
296
+ children, or pass an icon component through `as`. The icon is hidden from assistive technology by
297
+ default. For an icon without text beside it, set `aria-hidden={false}` and `aria-label`.
298
+
299
+ ```tsx
300
+ import { StarIcon } from "lucide-react";
301
+
302
+ import { Icon } from "@stealthscale/component-typography";
303
+
304
+ <Icon aria-hidden={false} aria-label="Favourite" as={StarIcon} size="lg" tone="warning" />;
305
+ <Icon viewBox="0 0 24 24">
306
+ <path d="M12 2 2 22h20Z" />
307
+ </Icon>;
308
+ ```
309
+
310
+ An `svg` without a `fill` attribute fills with the current colour. An icon that sets `fill`, such as
311
+ a lucide icon with `fill="none"`, keeps it. Set `mirrored` on an icon that points, such as an arrow.
312
+ The icon then flips in a right-to-left page.
313
+
314
+ | Axis | Values | Default |
315
+ | ---------- | ------------------------------------------------------------------------------------------ | --------- |
316
+ | `size` | `inherit`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `inherit` |
317
+ | `tone` | `current`, `default`, `muted`, `subtle`, `inverted`, `info`, `success`, `warning`, `error` | `current` |
318
+ | `motion` | `spin`, `float`, `twinkle` | none |
319
+ | `mirrored` | `true` | off |
320
+
321
+ ## List
322
+
323
+ `List.Root` renders a `ul` element with `List.Item` entries. Set `as="ol"` for a numbered list. The
324
+ `plain` look removes the browser's markers, and each item renders its mark in a `List.Indicator`.
325
+ The indicator is one line tall and centres its content. Assistive technology skips it, as it skips
326
+ the browser's marker. Put the meaning of a mark, such as a done state, in the item's text.
327
+
328
+ ```tsx
329
+ import { CheckIcon } from "lucide-react";
330
+
331
+ import { Icon, List } from "@stealthscale/component-typography";
332
+
333
+ <List.Root as="ol" gap="sm">
334
+ <List.Item>Verify your email address</List.Item>
335
+ <List.Item>Connect a bank account</List.Item>
336
+ </List.Root>;
337
+ <List.Root variant="plain">
338
+ <List.Item>
339
+ <List.Indicator>
340
+ <Icon as={CheckIcon} tone="success" />
341
+ </List.Indicator>
342
+ Unlimited invoices
343
+ </List.Item>
344
+ </List.Root>;
345
+ ```
346
+
347
+ | Axis | Values | Default | Styles |
348
+ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------- | --------------------- |
349
+ | `variant` | `marker`, `plain` | `marker` | the root and the item |
350
+ | `gap` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `md` | the root |
351
+ | `align` | `start`, `center`, `end` | `start` | the item |
352
+ | `marker` | `disc`, `circle`, `square`, `dash`, `decimal`, `leading-zero`, `lower-roman`, `upper-roman`, `lower-alpha`, `upper-alpha`, `lower-greek` | the element's | the item |
353
+ | `motion` | `rise`, `reveal` | none | the item |
354
+
355
+ ## Blockquote
356
+
357
+ A block quotation is a `Blockquote.Root` `figure` that contains `Blockquote.Icon`,
358
+ `Blockquote.Content` (a `blockquote`) and `Blockquote.Caption` (a `figcaption`).
359
+
360
+ ```tsx
361
+ import { Blockquote } from "@stealthscale/component-typography";
362
+
363
+ <Blockquote.Root palette="accent" variant="surface">
364
+ <Blockquote.Icon />
365
+ <Blockquote.Content>
366
+ Moving billing to one ledger cut our month-end close from nine days to two.
367
+ </Blockquote.Content>
368
+ <Blockquote.Caption>Priya Raman, Head of Finance at Northwind</Blockquote.Caption>
369
+ </Blockquote.Root>;
370
+ ```
371
+
372
+ - `Blockquote.Icon` renders the library's quote mark when it has no children. Children replace the
373
+ mark, such as a lucide icon with `viewBox="0 0 24 24"` on the part.
374
+ - The icon is one line of the quotation tall at every size. At `justify="start"` it hangs in a start
375
+ gutter beside the quotation and the caption. At `center` and `end` the icon is above the
376
+ quotation.
377
+ - The quotation is upright. Use `Em` for stress inside it.
378
+
379
+ | Axis | Values | Default | Styles |
380
+ | --------- | ---------------------------------------------------------------------------------- | --------- | --------------------- |
381
+ | `variant` | `subtle`, `solid`, `surface`, `plain`, `glass` | `subtle` | the root and the icon |
382
+ | `palette` | `primary`, `secondary`, `accent`, `neutral`, `info`, `success`, `warning`, `error` | `neutral` | the root |
383
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl` | `md` | the root |
384
+ | `justify` | `start`, `center`, `end` | `start` | the root and the icon |
385
+ | `motion` | `rise`, `reveal` | none | the root |
386
+
387
+ ## Types
388
+
389
+ | Type | Props of |
390
+ | ------------------------- | ------------------------------------------------------------------ |
391
+ | `TextProps` | `Text`: the recipe's variants and a `p` element's props |
392
+ | `HeadingProps` | `Heading`: the recipe's variants and an `h2` element's props |
393
+ | `CodeProps` | `Code`: the recipe's variants and a `code` element's props |
394
+ | `EmProps` | `Em`: the recipe's variants and an `em` element's props |
395
+ | `StrongProps` | `Strong`: the recipe's variants and a `strong` element's props |
396
+ | `MarkProps` | `Mark`: the recipe's variants and a `mark` element's props |
397
+ | `HighlightProps` | `Highlight`: the text, the query, `ignoreCase` and `MarkProps` |
398
+ | `QuoteProps` | `Quote`: the recipe's variants and a `q` element's props |
399
+ | `SpanProps` | `Span`: the recipe's variants and a `span` element's props |
400
+ | `Kbd.RootProps` | `Kbd.Root`: the recipe's variants and a `kbd` element's props |
401
+ | `Kbd.GroupProps` | `Kbd.Group`: `size`, `variant`, `palette` and a `kbd`'s props |
402
+ | `IconProps` | `Icon`: the recipe's variants and an `svg` element's props |
403
+ | `List.RootProps` | `List.Root`: the recipe's variants and a `ul` element's props |
404
+ | `List.ItemProps` | `List.Item`: an `li` element's props |
405
+ | `List.IndicatorProps` | `List.Indicator`: a `span` element's props |
406
+ | `Blockquote.RootProps` | `Blockquote.Root`: the recipe's variants and a `figure`'s props |
407
+ | `Blockquote.IconProps` | `Blockquote.Icon`: the icon recipe's variants and an `svg`'s props |
408
+ | `Blockquote.ContentProps` | `Blockquote.Content`: a `blockquote` element's props |
409
+ | `Blockquote.CaptionProps` | `Blockquote.Caption`: a `figcaption` element's props |
410
+
411
+ ## Licence
412
+
413
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1 @@
1
+ {"$schema":"http://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","version":1,"metadata":{"lifecycles":[{"phase":"build"}],"tools":{"components":[{"type":"application","name":"rolldown","version":"1.2.11"},{"type":"application","name":"vite","version":"8.3.1"},{"type":"library","name":"core","group":"@arethetypeswrong","version":"0.18.5","bom-ref":"pkg:npm/%40arethetypeswrong/core@0.18.5","author":"Andrew Branch","description":"The API behind arethetypeswrong.github.io","hashes":[{"alg":"SHA-512","content":"f72b63cc6c318e6f54cfb23d6af7dbb79be542deae93db914444b3263aabce797a58abc8e9dc184e8faf277534d96aeafe64778aa97f3f386f1e129d2480230d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40arethetypeswrong/core@0.18.5","externalReferences":[{"url":"https://github.com/arethetypeswrong/arethetypeswrong.github.io.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20"}]},{"type":"library","name":"hooks","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/hooks@0.1.0","description":"The React hooks a component uses to read the page it draws into: how the page is read, what it measures, and what a value was on the previous render.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/hooks@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#foundations/hooks","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/foundations/hooks#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"theme","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/theme@0.3.0","description":"Publishes the foundation every recipe is written against, the runtime every component binds its recipe with, and the vocabulary a theme is written in.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/theme@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#foundations/theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/foundations/theme#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-i18n","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-i18n@0.1.0","description":"Configures a package or an application with words: the catalogue plugin, and the words in scope for its specifications.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-i18n@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-i18n","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-i18n#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-react","group":"@stealthscale","version":"0.8.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","description":"Adds the JSX transform, the React lint rules, a test document and an MDX compiler to a package that renders.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-react#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-specimen","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-specimen@0.1.0","description":"Configures an application that shows a catalogue, and the workspace root the specimens sit under.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-specimen@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-specimen","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-specimen#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-theme","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-theme@0.1.0","description":"Adds the runtime generator to a design-system package and the stylesheet compiler to an application.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-theme@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-theme#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-typescript","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","description":"Sets the TypeScript options every stealthscale package compiles with.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-typescript#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config","group":"@stealthscale","version":"0.6.0","bom-ref":"pkg:npm/%40stealthscale/vite-config@0.6.0","description":"Configures a package from five Vite+ tiers and a named layer for every block.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config@0.6.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"react","group":"@testing-library","version":"16.3.3","bom-ref":"pkg:npm/%40testing-library/react@16.3.3","author":"Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)","description":"Simple and complete React DOM testing utilities that encourage good testing practices.","hashes":[{"alg":"SHA-512","content":"528d7ddcd8106cf333ea5aeb86d45040570c0ba45efc42cb15b6ee54bdf4583959c65a597fdfe53074c05713d12f0d6ad62bbd389991d5cd812e210d46cb5d06"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40testing-library/react@16.3.3","externalReferences":[{"url":"https://github.com/testing-library/react-testing-library/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/testing-library/react-testing-library","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://github.com/testing-library/react-testing-library#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=18"}]},{"type":"library","name":"react-dom","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react-dom@19.3.0","description":"TypeScript definitions for react-dom","hashes":[{"alg":"SHA-512","content":"648edb538da66575ca1e7fea34b130d88adb888354ed7e7ebdf81d8b10479023696165e32a07d0fcffaec866f90a338b07d51c9d37a0debca542d5768729b8e1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react@19.3.0","description":"TypeScript definitions for react","hashes":[{"alg":"SHA-512","content":"374ac50ae1fd628c46f7f9bad65f4c7e924a7e62ce554d1e9bb8a9233e9346049292f45e2c1f6f2fce4607ecabf01b3995eaa9be0f7a252c05e194b5b38be242"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"happy-dom","version":"20.14.5","bom-ref":"pkg:npm/happy-dom@20.14.5","author":"David Ortner","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.","hashes":[{"alg":"SHA-512","content":"c7f47392958ee346d38c8a13df4890b6deb814b2e61ff89171408dd97fff6cbc7b1f789f91d7cf5f2aacae8fce62dab32008622cc300ee69a2391f42dcd38a8d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/happy-dom@20.14.5","externalReferences":[{"url":"https://github.com/capricorn86/happy-dom","type":"vcs","comment":"as detected from PackageJson property \"repository\""},{"url":"https://github.com/capricorn86/happy-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20.0.0"}]},{"type":"library","name":"lucide-react","version":"1.48.0","bom-ref":"pkg:npm/lucide-react@1.48.0","author":"Eric Fennis","description":"A Lucide icon library package for React applications.","hashes":[{"alg":"SHA-512","content":"474088298fdf5e20bacbdc510400e0b0af955b6a7fa5c4c938c84b65fd53fae1bebc952fc94474da718e8262080bb30f92234ae0ec7c4039dba85f2b25858f65"}],"licenses":[{"license":{"id":"ISC"}}],"purl":"pkg:npm/lucide-react@1.48.0","externalReferences":[{"url":"https://github.com/lucide-icons/lucide/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"https://github.com/lucide-icons/lucide.git#packages/lucide-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://lucide.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"oxc-transform-react","version":"0.151.0","bom-ref":"pkg:npm/oxc-transform-react@0.151.0","author":"Boshen and oxc contributors","description":"Oxc React Compiler Node API","hashes":[{"alg":"SHA-512","content":"60ed7f62cdc5202fee060ca37b1bc6b084d05085c318d9b1272eafa906ddf1663b263ccc0f5faf095879f65cdaf7f3f4dbf4d135a517c94eceaf6c70c7f29b77"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/oxc-transform-react@0.151.0","externalReferences":[{"url":"https://github.com/oxc-project/oxc/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/oxc-project/oxc.git#napi/transform-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://oxc.rs","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.19.0 || >=22.12.0"}]},{"type":"library","name":"react-dom","version":"19.3.0","bom-ref":"pkg:npm/react-dom@19.3.0","description":"React package for working with the DOM.","hashes":[{"alg":"SHA-512","content":"24393c76089fe753a31680c4ef4f8e4fd202c98afeebd1e59a284dc29d7e36c7db9dadede6c22209af59264b43990e3fd5bfeb9f6ea1200476b985c332be6bd1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/react/react.git#packages/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","version":"19.3.0","bom-ref":"pkg:npm/react@19.3.0","description":"React is a JavaScript library for building user interfaces.","hashes":[{"alg":"SHA-512","content":"13c2d471bb415addb46db9766281dfc7864305dc554df38ab42667f5c0d227897afe7ba8029729201723e3bb76c19a155fc836647b8c1db892860091d53e52a2"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"https://github.com/react/react.git#packages/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=0.10.0"}]},{"type":"library","name":"typescript","version":"7.0.2","bom-ref":"pkg:npm/typescript@7.0.2","author":"Microsoft Corp.","description":"TypeScript is a language for application scale JavaScript development","hashes":[{"alg":"SHA-512","content":"f0561abbdea8dcd28e85b8ca8bfa8dbc6fd6e63873c646dd9b9b23f406d9ff94f9b16aa7de12602df1b1dbbb11299593bf2cc23fc74b4414dfe6d05349155434"}],"licenses":[{"license":{"id":"Apache-2.0"}}],"purl":"pkg:npm/typescript@7.0.2","externalReferences":[{"url":"https://github.com/microsoft/TypeScript/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/microsoft/TypeScript.git","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://www.typescriptlang.org/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=16.20.0"}]},{"type":"library","name":"vitest","version":"5.0.1","bom-ref":"pkg:npm/vitest@5.0.1","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"880f799506ca124bebb5391d0209d66d77db8a95a28967bf8439763f9b4c8ba585c03efa1b43715c01a9fccf4439c62ea5e18946beb0a6931cec2a00e354d08e"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@5.0.1","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/vitest","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^22.12.0 || ^24.0.0 || >=26.0.0"}]}]},"component":{"type":"library","name":"component-typography","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/component-typography@0.1.0","description":"Draws the components that are text: a heading, a paragraph, a snippet of code, a key a reader is asked to press.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/component-typography@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#components/typography","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/components/typography#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}],"evidence":{"licenses":[{"license":{"name":"file: LICENSE","text":{"content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNiBTdGVhbHRoIFNjYWxlIEIuVi4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==","contentType":"text/plain","encoding":"base64"}}}]}},"supplier":{"name":"Stealth Scale B.V.","url":["https://stealthscale.io"]}},"components":[],"dependencies":[{"ref":"pkg:npm/%40stealthscale/component-typography@0.1.0"}]}