@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 +21 -0
- package/README.md +429 -0
- package/dist/cyclonedx/bom.json +1 -0
- package/dist/index.d.ts +919 -0
- package/dist/index.js +2072 -0
- package/dist/recipe-BdO9ZFWU.js +708 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/theme.d.ts +12 -0
- package/dist/theme.js +23 -0
- package/package.json +81 -0
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"}]}
|