@stealthscale/component-disclosure 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 ADDED
@@ -0,0 +1,429 @@
1
+ # @stealthscale/component-disclosure
2
+
3
+ Draws what is shown and hidden on the reader's say-so. Every component binds a recipe and draws
4
+ nothing of its own, so a theme restyles all of them by extending the recipe. The preset under
5
+ `./theme` registers the recipes with an application's compiler.
6
+
7
+ Every value a theme can change on a component is an axis of its recipe, so a caller sets it as a
8
+ prop and writes no style. A caller changes the element a component draws with `as`.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @stealthscale/component-disclosure
14
+ ```
15
+
16
+ The package peers on `react`, `@stealthscale/hooks` and `@stealthscale/theme`, and installs the
17
+ state machines it draws from. An application lists the preset under `./theme` among the presets its
18
+ compiler installs.
19
+
20
+ ## Collapsible
21
+
22
+ Shows and hides the block beneath a control, composed as `Collapsible.Root` holding a trigger and
23
+ the block.
24
+
25
+ ```tsx
26
+ import { Collapsible } from "@stealthscale/component-disclosure";
27
+
28
+ <Collapsible.Root variant="outline">
29
+ <Collapsible.Trigger>
30
+ Delivery details
31
+ <Collapsible.Indicator>
32
+ <ChevronIcon />
33
+ </Collapsible.Indicator>
34
+ </Collapsible.Trigger>
35
+ <Collapsible.Content>Arrives Thursday.</Collapsible.Content>
36
+ </Collapsible.Root>;
37
+ ```
38
+
39
+ | Axis | Values | Default |
40
+ | --------- | ------------------------------------------------- | ------- |
41
+ | `variant` | `plain`, `outline`, `subtle`, `surface` | `plain` |
42
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `md` |
43
+ | `motion` | `slide`, `fade`, `none` | `slide` |
44
+
45
+ The size sets the trigger, the block and the mark from one step of the scale. The trigger reads the
46
+ control scale, so a collapsible lines up with a button of the same size beside it.
47
+
48
+ ### The machine's settings
49
+
50
+ Beside the axes, the root takes the settings the machine reads. None of them is a style.
51
+
52
+ | Setting | What it does |
53
+ | --------------------- | ------------------------------------------------------ |
54
+ | `open`, `defaultOpen` | Sets the state from outside, or sets where it starts |
55
+ | `onOpenChange` | Called each time it opens or closes |
56
+ | `disabled` | Stops the control opening it |
57
+ | `collapsedHeight` | Leaves a strip of the block showing while it is closed |
58
+ | `onExitComplete` | Runs once the closing animation has finished |
59
+ | `id` | Names the machine, which builds its ARIA references |
60
+ | `dir` | Sets which way the line runs |
61
+
62
+ `collapsedHeight` is what turns a disclosure into a preview. The block keeps the height you name
63
+ while closed, so a reader still sees the first line or two and the control reveals the rest.
64
+
65
+ ```tsx
66
+ <Collapsible.Root collapsedHeight="3lh" defaultOpen={false}>
67
+ ```
68
+
69
+ Name an `id` where you want a stable one, in a test or where the markup is rendered on a server.
70
+ Pass it to the root rather than to an element, because the machine builds the reference between the
71
+ control and the block from it. The root takes no element `id` or `dir` for that reason.
72
+
73
+ ### The accessibility the machine writes
74
+
75
+ None of this is a prop you can forget, because the machine writes all of it:
76
+
77
+ - **The control reports its state.** It carries `aria-expanded` and points at the block with
78
+ `aria-controls`.
79
+ - **A closed block is out of reach.** It is hidden from a screen reader and from the tab order, so a
80
+ keyboard passes over any control inside one.
81
+ - **The mark is not announced.** The control already reports whether the block is expanded, so the
82
+ indicator is kept out of the accessibility tree and turns on the state alone.
83
+
84
+ The mark turns half a revolution as the block opens, and holds still for a reader who asked for
85
+ reduced motion. Both motions read animation styles the theme owns, so a theme decides the pace and
86
+ the reduced-motion behaviour once for everything.
87
+
88
+ A block that starts open does not animate in. The machine holds its state attribute back on the
89
+ first render for exactly that reason, and writes it from the first animation frame onwards.
90
+
91
+ ## Tabs
92
+
93
+ Shows one panel at a time, chosen from a strip of controls, composed as `Tabs.Root` holding a list
94
+ and a panel for each control.
95
+
96
+ ```tsx
97
+ import { Tabs } from "@stealthscale/component-disclosure";
98
+
99
+ <Tabs.Root defaultValue="overview">
100
+ <Tabs.List>
101
+ <Tabs.Trigger value="overview">Overview</Tabs.Trigger>
102
+ <Tabs.Trigger value="activity">Activity</Tabs.Trigger>
103
+ <Tabs.Indicator />
104
+ </Tabs.List>
105
+ <Tabs.Content value="overview">What the account holds.</Tabs.Content>
106
+ <Tabs.Content value="activity">What has happened lately.</Tabs.Content>
107
+ </Tabs.Root>;
108
+ ```
109
+
110
+ | Axis | Values | Default |
111
+ | --------- | ------------------------------------------------------- | ------- |
112
+ | `variant` | `line`, `enclosed`, `subtle`, `plain` | `line` |
113
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `md` |
114
+ | `justify` | `start`, `center`, `end`, `between`, `around`, `evenly` | none |
115
+ | `fitted` | `true` | off |
116
+
117
+ `fitted` shares the strip's width between the controls, which suits a set of two or three filling a
118
+ panel. `justify` decides where they sit when they do not fill it.
119
+
120
+ Each control names the panel it shows with `value`, and each panel names its control the same way.
121
+ Nothing else here is yours to state, because the machine derives the rest.
122
+
123
+ Which way the set runs is not an axis. The machine states it, writes it onto every part, and the
124
+ recipe reads it, so the strip turns into a column and the bar moves to its inline edge without being
125
+ stated twice.
126
+
127
+ ### The machine's settings
128
+
129
+ | Setting | What it does |
130
+ | ----------------------- | ------------------------------------------------------- |
131
+ | `value`, `defaultValue` | Sets the panel from outside, or which panel opens first |
132
+ | `onValueChange` | Called each time the panel changes |
133
+ | `orientation` | Runs the strip across or down |
134
+ | `activationMode` | Chooses a panel on focus, or only on a press |
135
+ | `loopFocus` | Joins the ends of the strip up |
136
+ | `deselectable` | Lets a person close the panel they are on |
137
+ | `id` | Names the machine, which builds its ARIA references |
138
+
139
+ `activationMode` decides when a panel is chosen. It chooses on focus by default, so an arrow key
140
+ both moves and selects. A set whose panels are expensive to draw sets it to `manual`, and then an
141
+ arrow moves the focus and a press chooses.
142
+
143
+ ### The accessibility the machine writes
144
+
145
+ - **The strip is one set.** It carries the tablist role and reports which way it runs, so a screen
146
+ reader announces the count and the arrows move inside it.
147
+ - **The strip is one tab stop.** Only the control in force is reachable by Tab, and the arrows move
148
+ between them, so a person tabbing through a page steps over the set rather than through it.
149
+ - **Each panel is reachable.** A panel holding nothing focusable takes a tab stop of its own, so
150
+ tabbing out of the strip moves to what was just chosen rather than past it.
151
+ - **A panel nobody chose is removed.** It is out of the tab order and out of the accessibility tree.
152
+
153
+ The bar that marks the control in force is positioned from measurements the machine takes, so the
154
+ recipe states its thickness and its colour and never its place. It is hidden until there is
155
+ something to measure, which keeps it from appearing at the start of the strip on the first render.
156
+
157
+ ## Popover
158
+
159
+ Opens a panel beside a control, composed as `Popover.Root` holding the control and the panel.
160
+
161
+ ```tsx
162
+ import { Popover } from "@stealthscale/component-disclosure";
163
+
164
+ <Popover.Root>
165
+ <Popover.Trigger>
166
+ Filters
167
+ <Popover.Indicator>
168
+ <ChevronIcon />
169
+ </Popover.Indicator>
170
+ </Popover.Trigger>
171
+ <Popover.Positioner>
172
+ <Popover.Content>
173
+ <Popover.Arrow>
174
+ <Popover.ArrowTip />
175
+ </Popover.Arrow>
176
+ <Popover.Title>Filter the list</Popover.Title>
177
+ <Popover.Description>Only rows matching all of these are shown.</Popover.Description>
178
+ <Popover.CloseTrigger>
179
+ <CloseIcon />
180
+ </Popover.CloseTrigger>
181
+ </Popover.Content>
182
+ </Popover.Positioner>
183
+ </Popover.Root>;
184
+ ```
185
+
186
+ | Axis | Values | Default |
187
+ | --------- | ------------------------------------------------- | --------- |
188
+ | `variant` | `surface`, `elevated`, `glass` | `surface` |
189
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `md` |
190
+
191
+ A popover carries more than a tooltip. It holds a heading, a paragraph and often a control, so it
192
+ reads at body text and takes the room a panel needs. The size sets the panel's room, the heading's
193
+ size and the paragraph's together.
194
+
195
+ `Popover.Anchor` is for a panel positioned against something other than the control that opens it,
196
+ such as a whole row. Draw it around that thing and the machine measures it instead.
197
+
198
+ ### The machine's settings
199
+
200
+ | Setting | What it does |
201
+ | --------------------------------------------- | --------------------------------------------------------------- |
202
+ | `open`, `defaultOpen` | Sets the state from outside, or opens it to begin with |
203
+ | `onOpenChange` | Called each time the panel opens or shuts |
204
+ | `modal` | Traps focus and hides the rest of the page from a screen reader |
205
+ | `autoFocus`, `initialFocusEl`, `finalFocusEl` | Where focus goes on opening and on closing |
206
+ | `closeOnEscape`, `closeOnInteractOutside` | What shuts the panel |
207
+ | `persistentElements` | What a click inside does not count as outside |
208
+ | `positioning` | Which side it opens on, and how far from the control |
209
+ | `id` | Names the machine, which builds its ARIA references |
210
+
211
+ ### The accessibility the machine writes
212
+
213
+ - **The panel is a dialog.** It carries the dialog role, and the control says whether it is open and
214
+ which panel it controls.
215
+ - **The panel is announced by its own words.** The heading names it and the paragraph describes it,
216
+ both wired by the machine, so a panel with a `Title` needs nothing else to be announced.
217
+ - **Focus goes in and comes back.** The panel takes focus as it opens and returns it to the control
218
+ as it shuts, so a keyboard never loses its place.
219
+ - **Escape shuts it.** So does a click outside.
220
+
221
+ Like the tooltip, nothing here portals. Wrap `Popover.Positioner` in the portal you want where the
222
+ panel is clipped or stacked wrongly.
223
+
224
+ ## Tooltip
225
+
226
+ Shows a short label beside whatever a pointer rests on, composed as `Tooltip.Root` holding a control
227
+ and the box it opens.
228
+
229
+ ```tsx
230
+ import { Tooltip } from "@stealthscale/component-disclosure";
231
+
232
+ <Tooltip.Root>
233
+ <Tooltip.Trigger as={IconButton} aria-label="Save">
234
+ <SaveIcon />
235
+ </Tooltip.Trigger>
236
+ <Tooltip.Positioner>
237
+ <Tooltip.Content>
238
+ <Tooltip.Arrow>
239
+ <Tooltip.ArrowTip />
240
+ </Tooltip.Arrow>
241
+ Saves without closing
242
+ </Tooltip.Content>
243
+ </Tooltip.Positioner>
244
+ </Tooltip.Root>;
245
+ ```
246
+
247
+ | Axis | Values | Default |
248
+ | --------- | ------------------------------------------------- | ---------- |
249
+ | `variant` | `inverted`, `surface` | `inverted` |
250
+ | `size` | `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl` | `md` |
251
+
252
+ The root draws an element, which the machine has no part for, because the control and the box are
253
+ siblings and the recipe passes its variants down from above them both. It is drawn with
254
+ `display: contents`, so it takes part in no layout and a tooltip attached to a control inside a row
255
+ leaves that row as it was.
256
+
257
+ The box states its surface once as a custom property and the point reads it from there, so the two
258
+ are never filled in different colours whichever look is picked.
259
+
260
+ ### The machine's settings
261
+
262
+ | Setting | What it does |
263
+ | ---------------------------------------------------------------------- | ------------------------------------------------------ |
264
+ | `open`, `defaultOpen` | Sets the state from outside, or opens it to begin with |
265
+ | `onOpenChange` | Called each time the box opens or shuts |
266
+ | `openDelay`, `closeDelay` | How long a pointer rests before it opens, and after |
267
+ | `disabled` | Stops it opening at all |
268
+ | `interactive` | Keeps it open while a pointer is inside the box |
269
+ | `closeOnClick`, `closeOnEscape`, `closeOnScroll`, `closeOnPointerDown` | What shuts it |
270
+ | `positioning` | Which side it opens on, and how far from the control |
271
+ | `id` | Names the machine, which builds its ARIA references |
272
+
273
+ Set `interactive` where the box holds a link. It is off by default, because a tooltip held open
274
+ under a pointer covers whatever is behind it.
275
+
276
+ ### Putting the box somewhere else
277
+
278
+ Nothing here portals. A page whose tooltip is clipped or stacked wrongly wraps the positioner in the
279
+ portal it wants:
280
+
281
+ ```tsx
282
+ import { Portal } from "@stealthscale/component-primitives";
283
+
284
+ <Portal>
285
+ <Tooltip.Positioner>…</Tooltip.Positioner>
286
+ </Portal>;
287
+ ```
288
+
289
+ That keeps the choice of portal with the page rather than with the component, and it is why this
290
+ package peers on no other component package.
291
+
292
+ ### The accessibility the machine writes
293
+
294
+ - **The words describe the control.** The control points at the box with `aria-describedby`, so a
295
+ screen reader reads the words as part of reading the control rather than as something beside it.
296
+ - **A keyboard opens it.** Focus opens the box, but only where the focus came from a keyboard, so
297
+ clicking a control does not leave a tooltip hanging over the page.
298
+ - **Escape shuts it.** So does scrolling, and pressing the control.
299
+
300
+ The default element for the control is `button`, because a keyboard never reaches a tooltip attached
301
+ to something a browser does not focus. Pass `as` for a control you have already built.
302
+
303
+ ## Menu
304
+
305
+ Opens a list of things a reader chooses from, composed as `Menu.Root` holding the control and the
306
+ panel of rows.
307
+
308
+ ```tsx
309
+ import { Menu } from "@stealthscale/component-disclosure";
310
+
311
+ <Menu.Root>
312
+ <Menu.Trigger>
313
+ Actions
314
+ <Menu.Indicator>
315
+ <ChevronIcon />
316
+ </Menu.Indicator>
317
+ </Menu.Trigger>
318
+ <Menu.Positioner>
319
+ <Menu.Content>
320
+ <Menu.Item value="rename">Rename</Menu.Item>
321
+ <Menu.Item value="duplicate">Duplicate</Menu.Item>
322
+ <Menu.Separator />
323
+ <Menu.Item tone="critical" value="delete">
324
+ Delete
325
+ </Menu.Item>
326
+ </Menu.Content>
327
+ </Menu.Positioner>
328
+ </Menu.Root>;
329
+ ```
330
+
331
+ | Axis | Values | Default |
332
+ | ----------- | ------------------------------ | --------- |
333
+ | `variant` | `surface`, `elevated`, `glass` | `surface` |
334
+ | `size` | `sm`, `md`, `lg` | `md` |
335
+ | `highlight` | `tint`, `fill`, `bar` | `tint` |
336
+ | `inset` | `true` | unset |
337
+
338
+ `highlight` decides how the row the reader is on is marked. `tint` and `fill` change the row's
339
+ background. `bar` draws a line down the leading edge as well, which a reader who cannot separate the
340
+ two colours still sees.
341
+
342
+ `inset` leaves every row the gutter a mark is drawn in, for a menu whose rows lead with an icon. A
343
+ row that carries a mark is inset whatever the axis says, so a list of options does not step sideways
344
+ as the marks appear.
345
+
346
+ The panel states no width of its own, so it is as wide as its widest row. Set
347
+ `positioning: { sameWidth: true }` to match the control's width instead.
348
+
349
+ ### Rows that carry a choice
350
+
351
+ `Menu.OptionItem` draws a tick a reader turns on and off, or one of a set. The caller states both
352
+ the kind and whether it is on. The machine reports a change and the caller decides what it means.
353
+ That is how one radio set clears the rest.
354
+
355
+ ```tsx
356
+ <Menu.OptionItem checked={dense} onCheckedChange={setDense} type="checkbox" value="dense">
357
+ <Menu.ItemIndicator>
358
+ <CheckIcon />
359
+ </Menu.ItemIndicator>
360
+ <Menu.ItemText>Compact rows</Menu.ItemText>
361
+ </Menu.OptionItem>
362
+ ```
363
+
364
+ The row passes its value down. `Menu.ItemText` and `Menu.ItemIndicator` take no props of their own.
365
+ Group rows with `Menu.ItemGroup` and `Menu.ItemGroupLabel`. The two share one `value`.
366
+
367
+ ### Submenus
368
+
369
+ Write a `Menu.Root` inside the panel of another. The inner root finds the menu above it and joins
370
+ the two machines. It draws itself in the variants that menu was given, unless it picks its own.
371
+
372
+ ```tsx
373
+ <Menu.Content>
374
+ <Menu.Item value="new">New</Menu.Item>
375
+ <Menu.Root>
376
+ <Menu.TriggerItem>Share</Menu.TriggerItem>
377
+ <Menu.Positioner>
378
+ <Menu.Content>
379
+ <Menu.Item value="email">Email</Menu.Item>
380
+ </Menu.Content>
381
+ </Menu.Positioner>
382
+ </Menu.Root>
383
+ </Menu.Content>
384
+ ```
385
+
386
+ `Menu.TriggerItem` is both a row of the menu above and the control of the menu below. It opens when
387
+ a pointer rests on it or the arrow towards the submenu is pressed, and it throws where the menu it
388
+ belongs to opens from no other menu.
389
+
390
+ ### Right-click menus
391
+
392
+ `Menu.ContextTrigger` opens the menu at the point the pointer is at rather than beside a control. It
393
+ responds to a long press as well as a right-click, and it stops the browser drawing its own menu
394
+ over this one. Use it in place of `Menu.Trigger`.
395
+
396
+ ### The machine's settings
397
+
398
+ | Setting | What it does |
399
+ | --------------------------------------- | ------------------------------------------------------ |
400
+ | `open`, `defaultOpen` | Sets the state from outside, or opens it to begin with |
401
+ | `onOpenChange` | Called each time the rows open or shut |
402
+ | `onSelect` | Called with the row the reader chose |
403
+ | `highlightedValue`, `onHighlightChange` | Sets the row the reader is on, or reports it changing |
404
+ | `closeOnSelect` | Whether choosing a row shuts the menu |
405
+ | `typeahead`, `loopFocus` | Whether typing jumps to a row, and whether arrows wrap |
406
+ | `navigate` | Follows a row drawn as a link through a router |
407
+ | `positioning` | Which side it opens on, and how far from the control |
408
+ | `triggerValue`, `onTriggerValueChange` | Tracks which of several controls opened it |
409
+ | `anchorPoint` | Opens it at a point rather than beside a control |
410
+ | `id` | Names the machine, which builds its ARIA references |
411
+
412
+ ### The accessibility the machine writes
413
+
414
+ - **The panel is a menu.** It carries the menu role, and the control says whether it is open and
415
+ which panel it opens.
416
+ - **The focus stays on the panel.** The machine moves a highlight over the rows and points a screen
417
+ reader at it with `aria-activedescendant`, which is what the menu pattern asks for.
418
+ - **Every row responds to the keyboard.** The arrows move the highlight. The arrow towards a submenu
419
+ opens it and the arrow back closes it. Typing jumps to a row by its words, and Escape shuts the
420
+ menu and returns focus to the control.
421
+ - **A row that carries a choice reports it.** The checkbox and radio menu item roles carry
422
+ `aria-checked`, and the mark beside them is hidden so it is not read out twice.
423
+
424
+ Nothing here portals. Wrap `Menu.Positioner` in the portal you want where the panel is clipped or
425
+ stacked wrongly.
426
+
427
+ ## Licence
428
+
429
+ 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.7"},{"type":"application","name":"vite","version":"8.2.2"},{"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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#foundations/hooks","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#foundations/theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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-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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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-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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config-theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/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":"focus-visible","group":"@zag-js","version":"1.43.3","bom-ref":"pkg:npm/%40zag-js/focus-visible@1.43.3","author":"Segun Adebayo <sage@adebayosegun.com>","description":"Focus visible polyfill utility based on WICG","hashes":[{"alg":"SHA-512","content":"df6976d67414237dbc9df3537b669d5f25e3fbcb7596d0da126ec84069a1b40c3f0ee20abe3a449212591cbd73512969e3b40635fb9818f783f995da65615630"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40zag-js/focus-visible@1.43.3","externalReferences":[{"url":"https://github.com/chakra-ui/zag/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/chakra-ui/zag/tree/main/packages/utilities/focus-visible","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://github.com/chakra-ui/zag#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"babel-plugin-react-compiler","version":"1.0.0","bom-ref":"pkg:npm/babel-plugin-react-compiler@1.0.0","description":"Babel plugin for React Compiler.","hashes":[{"alg":"SHA-512","content":"2319bcb457e828a20f61d0822984ecaaff85778209d0342a3321229a8fa9c5438c511f5c54f9704eb16df40beefb771be99a77980ce5fadd4cac6d9fc712acc7"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/babel-plugin-react-compiler@1.0.0","externalReferences":[{"url":"git+https://github.com/facebook/react.git#compiler/packages/babel-plugin-react-compiler","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}]},{"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":"oxc-transform-react","version":"0.149.0","bom-ref":"pkg:npm/oxc-transform-react@0.149.0","author":"Boshen and oxc contributors","description":"Oxc React Compiler Node API","hashes":[{"alg":"SHA-512","content":"69bdddc5c3ed90349f211f6d35dc4752d9a974bd258479ddb010fd214014e41c6d26dc061bff39367473b367f62b0a2e3641e5edc692b3030b41e52fc3714447"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/oxc-transform-react@0.149.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":"4.1.11","bom-ref":"pkg:npm/vitest@4.1.11","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"7e1002acd5d489d21b19206be4595bb8190eed5582d59c8b9740cee025360eb42800fc57f3862cc6cf877864298a2e656565754388016534eee3d985f80e8477"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@4.1.11","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":"^20.0.0 || ^22.0.0 || >=24.0.0"}]}]},"component":{"type":"library","name":"component-disclosure","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/component-disclosure@0.1.0","description":"Draws what is shown and hidden on the reader's say-so.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/component-disclosure@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#components/disclosure","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/components/disclosure#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-disclosure@0.1.0"}]}