@qeetrix/react 0.0.1 → 0.0.2
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/CHANGELOG.md +173 -0
- package/README.md +141 -4
- package/dist/accordion/accordion.d.ts +42 -0
- package/dist/accordion/accordion.js +72 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +1 -0
- package/dist/avatar/avatar.d.ts +21 -0
- package/dist/avatar/avatar.js +43 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +1 -0
- package/dist/badge/badge.d.ts +14 -0
- package/dist/badge/badge.js +25 -0
- package/dist/badge/index.d.ts +2 -0
- package/dist/badge/index.js +1 -0
- package/dist/box/box.d.ts +27 -0
- package/dist/box/box.js +21 -0
- package/dist/box/index.d.ts +2 -0
- package/dist/box/index.js +1 -0
- package/dist/button/button.d.ts +46 -0
- package/dist/button/button.js +74 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.js +1 -0
- package/dist/card/card.d.ts +30 -0
- package/dist/card/card.js +56 -0
- package/dist/card/index.d.ts +2 -0
- package/dist/card/index.js +1 -0
- package/dist/checkbox/checkbox.d.ts +33 -0
- package/dist/checkbox/checkbox.js +61 -0
- package/dist/checkbox/index.d.ts +2 -0
- package/dist/checkbox/index.js +1 -0
- package/dist/css/accordion.css +73 -0
- package/dist/css/avatar.css +44 -0
- package/dist/css/badge.css +53 -0
- package/dist/css/box.css +163 -0
- package/dist/css/button.css +168 -0
- package/dist/css/card.css +75 -0
- package/dist/css/checkbox.css +58 -0
- package/dist/css/dialog.css +121 -0
- package/dist/css/drawer.css +123 -0
- package/dist/css/field.css +121 -0
- package/dist/css/fieldset.css +37 -0
- package/dist/css/grid.css +86 -0
- package/dist/css/heading.css +93 -0
- package/dist/css/inline.css +85 -0
- package/dist/css/input.css +98 -0
- package/dist/css/link.css +45 -0
- package/dist/css/menu.css +149 -0
- package/dist/css/popover.css +72 -0
- package/dist/css/progress.css +88 -0
- package/dist/css/radio.css +54 -0
- package/dist/css/scroll-area.css +63 -0
- package/dist/css/select.css +173 -0
- package/dist/css/separator.css +28 -0
- package/dist/css/skeleton.css +33 -0
- package/dist/css/skip-link.css +33 -0
- package/dist/css/slider.css +86 -0
- package/dist/css/spinner.css +55 -0
- package/dist/css/stack.css +76 -0
- package/dist/css/switch.css +79 -0
- package/dist/css/table.css +68 -0
- package/dist/css/tabs.css +112 -0
- package/dist/css/text-field.css +4 -0
- package/dist/css/text.css +106 -0
- package/dist/css/toast.css +108 -0
- package/dist/css/toggle.css +112 -0
- package/dist/css/tooltip.css +41 -0
- package/dist/css/visually-hidden.css +15 -0
- package/dist/dialog/dialog.d.ts +51 -0
- package/dist/dialog/dialog.js +120 -0
- package/dist/dialog/index.d.ts +2 -0
- package/dist/dialog/index.js +1 -0
- package/dist/drawer/drawer.d.ts +46 -0
- package/dist/drawer/drawer.js +101 -0
- package/dist/drawer/index.d.ts +2 -0
- package/dist/drawer/index.js +1 -0
- package/dist/field/choice.d.ts +21 -0
- package/dist/field/choice.js +67 -0
- package/dist/field/field.d.ts +28 -0
- package/dist/field/field.js +77 -0
- package/dist/field/index.d.ts +3 -0
- package/dist/field/index.js +1 -0
- package/dist/fieldset/fieldset.d.ts +19 -0
- package/dist/fieldset/fieldset.js +29 -0
- package/dist/fieldset/index.d.ts +2 -0
- package/dist/fieldset/index.js +1 -0
- package/dist/grid/grid.d.ts +30 -0
- package/dist/grid/grid.js +36 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/grid/index.js +1 -0
- package/dist/heading/heading.d.ts +23 -0
- package/dist/heading/heading.js +30 -0
- package/dist/heading/index.d.ts +2 -0
- package/dist/heading/index.js +1 -0
- package/dist/index.d.ts +80 -1
- package/dist/index.js +38 -0
- package/dist/inline/index.d.ts +2 -0
- package/dist/inline/index.js +1 -0
- package/dist/inline/inline.d.ts +19 -0
- package/dist/inline/inline.js +16 -0
- package/dist/input/index.d.ts +2 -0
- package/dist/input/index.js +1 -0
- package/dist/input/input.d.ts +37 -0
- package/dist/input/input.js +63 -0
- package/dist/internal/control.d.ts +9 -0
- package/dist/internal/control.js +4 -0
- package/dist/internal/cx.js +7 -0
- package/dist/internal/messages.js +22 -0
- package/dist/internal/refs.js +23 -0
- package/dist/internal/render.d.ts +6 -0
- package/dist/internal/render.js +22 -0
- package/dist/internal/space.d.ts +9 -0
- package/dist/internal/text.d.ts +5 -0
- package/dist/internal/text.js +18 -0
- package/dist/link/index.d.ts +2 -0
- package/dist/link/index.js +1 -0
- package/dist/link/link.d.ts +13 -0
- package/dist/link/link.js +31 -0
- package/dist/menu/index.d.ts +2 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/menu.d.ts +76 -0
- package/dist/menu/menu.js +172 -0
- package/dist/popover/index.d.ts +2 -0
- package/dist/popover/index.js +1 -0
- package/dist/popover/popover.d.ts +33 -0
- package/dist/popover/popover.js +48 -0
- package/dist/progress/index.d.ts +2 -0
- package/dist/progress/index.js +1 -0
- package/dist/progress/progress.d.ts +26 -0
- package/dist/progress/progress.js +57 -0
- package/dist/radio/index.d.ts +2 -0
- package/dist/radio/index.js +1 -0
- package/dist/radio/radio.d.ts +31 -0
- package/dist/radio/radio.js +47 -0
- package/dist/scroll-area/index.d.ts +2 -0
- package/dist/scroll-area/index.js +1 -0
- package/dist/scroll-area/scroll-area.d.ts +18 -0
- package/dist/scroll-area/scroll-area.js +39 -0
- package/dist/select/index.d.ts +2 -0
- package/dist/select/index.js +1 -0
- package/dist/select/select.d.ts +36 -0
- package/dist/select/select.js +82 -0
- package/dist/separator/index.d.ts +2 -0
- package/dist/separator/index.js +1 -0
- package/dist/separator/separator.d.ts +16 -0
- package/dist/separator/separator.js +16 -0
- package/dist/skeleton/index.d.ts +2 -0
- package/dist/skeleton/index.js +1 -0
- package/dist/skeleton/skeleton.d.ts +12 -0
- package/dist/skeleton/skeleton.js +18 -0
- package/dist/skip-link/index.d.ts +2 -0
- package/dist/skip-link/index.js +1 -0
- package/dist/skip-link/skip-link.d.ts +13 -0
- package/dist/skip-link/skip-link.js +18 -0
- package/dist/slider/index.d.ts +2 -0
- package/dist/slider/index.js +1 -0
- package/dist/slider/slider.d.ts +17 -0
- package/dist/slider/slider.js +51 -0
- package/dist/spinner/index.d.ts +2 -0
- package/dist/spinner/index.js +1 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +19 -0
- package/dist/stack/index.d.ts +2 -0
- package/dist/stack/index.js +1 -0
- package/dist/stack/stack.d.ts +17 -0
- package/dist/stack/stack.js +15 -0
- package/dist/styles.css +2948 -0
- package/dist/switch/index.d.ts +2 -0
- package/dist/switch/index.js +1 -0
- package/dist/switch/switch.d.ts +18 -0
- package/dist/switch/switch.js +31 -0
- package/dist/table/index.d.ts +2 -0
- package/dist/table/index.js +1 -0
- package/dist/table/table.d.ts +36 -0
- package/dist/table/table.js +69 -0
- package/dist/tabs/index.d.ts +2 -0
- package/dist/tabs/index.js +1 -0
- package/dist/tabs/tabs.d.ts +43 -0
- package/dist/tabs/tabs.js +66 -0
- package/dist/text/index.d.ts +3 -0
- package/dist/text/index.js +1 -0
- package/dist/text/text.d.ts +24 -0
- package/dist/text/text.js +24 -0
- package/dist/text-field/index.d.ts +2 -0
- package/dist/text-field/index.js +1 -0
- package/dist/text-field/text-field.d.ts +15 -0
- package/dist/text-field/text-field.js +41 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +1 -0
- package/dist/toast/toast.d.ts +54 -0
- package/dist/toast/toast.js +123 -0
- package/dist/toggle/index.d.ts +2 -0
- package/dist/toggle/index.js +1 -0
- package/dist/toggle/toggle.d.ts +48 -0
- package/dist/toggle/toggle.js +54 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/tooltip.d.ts +26 -0
- package/dist/tooltip/tooltip.js +39 -0
- package/dist/visually-hidden/index.d.ts +2 -0
- package/dist/visually-hidden/index.js +1 -0
- package/dist/visually-hidden/visually-hidden.d.ts +8 -0
- package/dist/visually-hidden/visually-hidden.js +12 -0
- package/package.json +153 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,178 @@
|
|
|
1
1
|
# @qeetrix/react
|
|
2
2
|
|
|
3
|
+
## 0.0.2
|
|
4
|
+
|
|
5
|
+
Every primitive, in six increments: the foundation, actions, form controls, overlays, selection and
|
|
6
|
+
disclosure, and display and status.
|
|
7
|
+
|
|
8
|
+
### Foundation
|
|
9
|
+
|
|
10
|
+
All nine are server-safe and render in React Server Components.
|
|
11
|
+
|
|
12
|
+
- **Layout:**
|
|
13
|
+
- `Box`: a token-only surface (padding, background, border, corners);
|
|
14
|
+
- `Stack` and `Inline`: vertical and horizontal flows with token gaps;
|
|
15
|
+
- `Grid`: responsive equal columns on the window size classes.
|
|
16
|
+
- **Type:**
|
|
17
|
+
- `Text`: body roles, weights, tones, monospace, truncation;
|
|
18
|
+
- `Heading`: the level sets the element, the size sets the look; Geo letterforms for display.
|
|
19
|
+
- **`Separator`:** 1px, horizontal or vertical, optionally decorative.
|
|
20
|
+
- **Accessibility:**
|
|
21
|
+
- `VisuallyHidden`: screen-reader-only content;
|
|
22
|
+
- `SkipLink`: the first focusable element on a page, hidden until focused.
|
|
23
|
+
- **Shared types:** `Space`, `Inset`, `TextAlign`, `RenderProp`.
|
|
24
|
+
- **Imports:** every component also has its own entry point (`@qeetrix/react/stack`) and stylesheet
|
|
25
|
+
(`@qeetrix/react/css/stack.css`).
|
|
26
|
+
|
|
27
|
+
### Actions
|
|
28
|
+
|
|
29
|
+
- **`Button`** (on Base UI Button):
|
|
30
|
+
- the label comes first, with an optional sharp trailing icon;
|
|
31
|
+
- variants `solid` (Ember primary), `soft` (warm-graphite secondary) and `ghost`; tones `brand` and
|
|
32
|
+
`danger`; sizes that follow the density;
|
|
33
|
+
- `loading` sets `aria-busy` and shows a spinner in the icon's place;
|
|
34
|
+
- a disabled button stays focusable, so its reason can be read.
|
|
35
|
+
- **`IconButton`:** square and icon-only; its `aria-label` is required by its type.
|
|
36
|
+
- **`Link`:** default, subtle and inherit tones. `external` opens a new tab with
|
|
37
|
+
`rel="noopener noreferrer"`, an arrow mark and a screen-reader note.
|
|
38
|
+
- **`Toggle` and `ToggleGroup`** (on Base UI):
|
|
39
|
+
- pressed state with `onPressedChange`, and `filledWhenPressed` swaps to the icon's filled drawing;
|
|
40
|
+
- groups are segmented or separate, single-choice or `multiple`, with arrow-key focus.
|
|
41
|
+
- **`Spinner`:** four sizes. It is announced as a status unless `decorative`, and fades instead of
|
|
42
|
+
spinning under reduced motion.
|
|
43
|
+
- **Shared types:** `ControlSize`, `QeetrixIcon`.
|
|
44
|
+
- **Dependencies:**
|
|
45
|
+
- new peer `@base-ui/react` ^1.9.0;
|
|
46
|
+
- new dependency `@qeetrix/icons` ^1.0.12, for the external-link mark.
|
|
47
|
+
|
|
48
|
+
### Form controls
|
|
49
|
+
|
|
50
|
+
All are client components on Base UI's Field, Fieldset, Input, Checkbox, Radio Group and Switch, so
|
|
51
|
+
labels, descriptions and errors link to their controls without ids. On every form control, `ref` and
|
|
52
|
+
extra props go to the control, while `className` and `style` place the row.
|
|
53
|
+
|
|
54
|
+
- **`Field`:**
|
|
55
|
+
- a label, help text and error around any control;
|
|
56
|
+
- `optional` adds "(optional)", and Qeetrix never marks required fields;
|
|
57
|
+
- `error` shows a message now (from the server, say) and marks the field invalid. Without it, the
|
|
58
|
+
browser's or `validate`'s message shows with a sharp alert icon;
|
|
59
|
+
- the error replaces the help text;
|
|
60
|
+
- `hideLabel` is for toolbar searches only.
|
|
61
|
+
- **`Input`:** the filled box with a bottom line, a leading `icon`, and start and end adornments.
|
|
62
|
+
It takes its focus, invalid, read-only and disabled looks from the input.
|
|
63
|
+
- **`Textarea`:** the same look. It grows with its content between `rows` and `maxRows` through CSS
|
|
64
|
+
`field-sizing`, with no script.
|
|
65
|
+
- **`TextField`:** Field and Input in one, the default form row.
|
|
66
|
+
- **`Fieldset`:** a section of fields under a `title.sm` legend, spaced by the density's form gap.
|
|
67
|
+
`disabled` disables everything inside.
|
|
68
|
+
- **`Checkbox` and `CheckboxGroup`:**
|
|
69
|
+
- the 16px box with a sharp tick, and the mixed state with a dash;
|
|
70
|
+
- a `parent` checkbox selects the whole group;
|
|
71
|
+
- the label row is at least 24px tall.
|
|
72
|
+
- **`Radio` and `RadioGroup`:** the 5px Ember ring. Arrow keys move and select, and RadioGroup is
|
|
73
|
+
generic over its value type.
|
|
74
|
+
- **`Switch`:** a 32×18 track with a square thumb that moves to the end side, in either text
|
|
75
|
+
direction.
|
|
76
|
+
- With no visible label, Checkbox, Radio and Switch require `aria-label` or `aria-labelledby` by
|
|
77
|
+
their type.
|
|
78
|
+
- **Shared types:** `FieldMessageProps`, `ChoiceLabelProps`, `ChoiceOrientation`.
|
|
79
|
+
|
|
80
|
+
### Overlays
|
|
81
|
+
|
|
82
|
+
All are client components on Base UI. Each has a root, a trigger that renders your control, and a
|
|
83
|
+
content part that assembles the portal, positioner and popup.
|
|
84
|
+
|
|
85
|
+
- **`Popover`:** an anchored panel with an optional title and description. Focus moves in on open
|
|
86
|
+
and returns to the trigger on close.
|
|
87
|
+
- **`Tooltip`:** one component around its trigger. It opens after 500ms of hover or at once on
|
|
88
|
+
focus. `TooltipProvider` groups neighbours, so the next one opens at once.
|
|
89
|
+
- **`Menu`:**
|
|
90
|
+
- items with sharp icons, shortcuts and a `danger` tone;
|
|
91
|
+
- checkbox and radio items in a 16px mark column;
|
|
92
|
+
- group labels, separators and submenus;
|
|
93
|
+
- the 2px Ember start bar on the highlighted item, which follows the text direction.
|
|
94
|
+
- **`Dialog`:**
|
|
95
|
+
- `intent` is `standard`, `danger` or `warning`, the last two as alert dialogs with a red or amber
|
|
96
|
+
intent line;
|
|
97
|
+
- `dismissible`, off by default for `danger`, so only its actions close it;
|
|
98
|
+
- sizes 400, 560 and 800px;
|
|
99
|
+
- the close button comes last in the focus order, so a dialog opens on its first field or its
|
|
100
|
+
least destructive action.
|
|
101
|
+
- **`Drawer`:**
|
|
102
|
+
- a full-height side panel at the `end` or `start` edge;
|
|
103
|
+
- ruled header and footer, and a scrolling body;
|
|
104
|
+
- focus goes to the first field, except on touch;
|
|
105
|
+
- it can be swiped away.
|
|
106
|
+
- **`ToastProvider` and `useToast`:**
|
|
107
|
+
- `add`, `close`, `update` and `promise`;
|
|
108
|
+
- tones `info`, `success`, `warning` and `danger`, each with a 3px status edge and a sharp icon;
|
|
109
|
+
- one action at most;
|
|
110
|
+
- `danger` toasts stay until dismissed and are announced at once.
|
|
111
|
+
- **`IconButton`** now shows its `aria-label` as a tooltip. `tooltip={false}` turns it off, and
|
|
112
|
+
other text replaces it.
|
|
113
|
+
- **Stacking:** anchored layers use `z.popover`, so a menu opened in a dialog sits above it.
|
|
114
|
+
|
|
115
|
+
### Selection and disclosure
|
|
116
|
+
|
|
117
|
+
- **`Select`:**
|
|
118
|
+
- a field-style trigger with a chevron, and a menu-style list below it;
|
|
119
|
+
- the chosen option carries an Ember check;
|
|
120
|
+
- `items` can be flat or grouped, and `multiple` lists the chosen labels;
|
|
121
|
+
- generic over the value. A Field labels it.
|
|
122
|
+
- **`Tabs`, `TabsList`, `Tab`, `TabsPanel`:**
|
|
123
|
+
- the 3px Ember bar slides under the selected tab, and `TabsList` draws it;
|
|
124
|
+
- a selected tab has weight 600 and can fill its icon;
|
|
125
|
+
- padding is 12px at compact density and 16px otherwise;
|
|
126
|
+
- `activateOnFocus` is on by default;
|
|
127
|
+
- vertical tabs carry the line and bar on the start edge.
|
|
128
|
+
- **`Slider`:**
|
|
129
|
+
- a 4px track, the Ember range, and a 16px square thumb ringed in the surface colour;
|
|
130
|
+
- `label` and `showValue` with `Intl` formatting;
|
|
131
|
+
- a range renders one thumb per value, named Minimum and Maximum.
|
|
132
|
+
- **`Accordion`, `AccordionItem`:**
|
|
133
|
+
- ruled sections with a `title.sm` trigger inside a heading (`headingLevel`), and a turning
|
|
134
|
+
chevron;
|
|
135
|
+
- the panel's height animates;
|
|
136
|
+
- find in page opens a closed section that holds the match.
|
|
137
|
+
- **`Collapsible`, `CollapsibleTrigger`, `CollapsiblePanel`:** one unruled section.
|
|
138
|
+
- **`ScrollArea`:** 8px scrollbars that show on hover, while scrolling and on keyboard focus. The
|
|
139
|
+
region takes focus when it overflows.
|
|
140
|
+
|
|
141
|
+
### Display and status
|
|
142
|
+
|
|
143
|
+
- **`Card`:**
|
|
144
|
+
- a raised surface with a 1px line, 4px corners and no shadow;
|
|
145
|
+
- a ruled header with `title`, the required heading `level`, `description` and `actions`, and an
|
|
146
|
+
optional ruled `footer`;
|
|
147
|
+
- a titled card is a section labelled by its title, and a table in the body runs edge to edge.
|
|
148
|
+
- Server-safe.
|
|
149
|
+
- **`Table`, `TableCaption`, `TableHeader`, `TableBody`, `TableRow`, `TableHead`, `TableCell`:**
|
|
150
|
+
- a neutral header band and row heights from the density;
|
|
151
|
+
- `numeric` cells use tabular figures, end-aligned;
|
|
152
|
+
- `selected` rows keep their Ember tint under the pointer.
|
|
153
|
+
- Server-safe.
|
|
154
|
+
- **`Badge`:** pills in six tones with an optional sharp icon. The `brand` fill is
|
|
155
|
+
`bg.brand.subtle`, so its text meets AA. Server-safe.
|
|
156
|
+
- **`Avatar`:** a circle with the photo, or initials while it loads or when it fails. The initials
|
|
157
|
+
use whole graphemes, so Indic names stay intact. It can be `decorative`.
|
|
158
|
+
- **`Progress` and `Meter`:** Slider's header, a 4px track and an Ember indicator (Meter takes a
|
|
159
|
+
status tone). Indeterminate progress slides, and fades under reduced motion.
|
|
160
|
+
- **`Skeleton`:** `text`, `block` or `circle`. It pulses, holds still under reduced motion, and is
|
|
161
|
+
always hidden from assistive technology. Server-safe.
|
|
162
|
+
|
|
163
|
+
### Platform
|
|
164
|
+
|
|
165
|
+
- Each family's stylesheet (`css/<family>.css`) now imports the base layer and the stylesheets of
|
|
166
|
+
the families it renders, so it works on its own.
|
|
167
|
+
- Screenshots wait for transitions to finish, and overlays are captured across the whole viewport.
|
|
168
|
+
The accessibility check also waits, since contrast measured mid-fade isn't real. It skips Base
|
|
169
|
+
UI's aria-hidden focus guards, which hand focus on the moment it lands.
|
|
170
|
+
- A type-only import between families no longer pulls in the other family's stylesheet.
|
|
171
|
+
- Screenshots freeze endless animations (spinner, skeleton, indeterminate progress), so they match
|
|
172
|
+
every run.
|
|
173
|
+
- The nightly Firefox and WebKit run tests without V8 coverage, which works only in Chromium.
|
|
174
|
+
Every browser test passes in all three engines.
|
|
175
|
+
|
|
3
176
|
## 0.0.1
|
|
4
177
|
|
|
5
178
|
The engineering platform, with no components yet:
|
package/README.md
CHANGED
|
@@ -3,16 +3,19 @@
|
|
|
3
3
|
The React components of **Qeetrix**, the Qeet Group design system: accessible, token-driven
|
|
4
4
|
primitives built on [Base UI](https://base-ui.com), styled by the Qeetrix design language.
|
|
5
5
|
|
|
6
|
-
> **Status: 0.0.x
|
|
7
|
-
>
|
|
8
|
-
>
|
|
6
|
+
> **Status: 0.0.x.** Every primitive is here: foundation, actions, form controls, overlays, selection
|
|
7
|
+
> and disclosure, and display and status. Components and patterns follow as Qeet products ask for
|
|
8
|
+
> them.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
bun add @qeetrix/react @qeetrix/tokens
|
|
13
|
+
bun add @qeetrix/react @qeetrix/tokens @base-ui/react @qeetrix/icons
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
`@base-ui/react` powers the interactive components. Icons come from `@qeetrix/icons`: a component's
|
|
17
|
+
`icon` prop takes any of its icons, e.g. `icon={PlusIcon}`.
|
|
18
|
+
|
|
16
19
|
## Styles
|
|
17
20
|
|
|
18
21
|
Load the tokens, then the component styles, once at the root of your app:
|
|
@@ -26,6 +29,140 @@ The stylesheet is precompiled. Your Tailwind setup doesn't need to scan this pac
|
|
|
26
29
|
utility classes. Qeetrix styles sit in the `qx.base` and `qx.components` cascade layers, so your own
|
|
27
30
|
layout utilities override them without `!important`.
|
|
28
31
|
|
|
32
|
+
## Use
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { PlusIcon } from "@qeetrix/icons/icons/plus";
|
|
36
|
+
import { Box, Button, Grid, Heading, Inline, SkipLink, Stack, Text } from "@qeetrix/react";
|
|
37
|
+
|
|
38
|
+
export function Invoices() {
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<SkipLink />
|
|
42
|
+
<main id="main">
|
|
43
|
+
<Stack gap="xl">
|
|
44
|
+
<Inline justify="between">
|
|
45
|
+
<Heading level={1}>Invoices</Heading>
|
|
46
|
+
<Button icon={PlusIcon}>New invoice</Button>
|
|
47
|
+
</Inline>
|
|
48
|
+
<Grid columns={{ base: 1, medium: 2, large: 3 }} gap="md">
|
|
49
|
+
<Box padding="lg" background="raised" border="default" radius="surface">
|
|
50
|
+
<Text tone="subtle">Due this month</Text>
|
|
51
|
+
</Box>
|
|
52
|
+
</Grid>
|
|
53
|
+
</Stack>
|
|
54
|
+
</main>
|
|
55
|
+
</>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- **Server-safe:** layout, type, `Link`, `Spinner`, `Card`, `Table`, `Badge` and `Skeleton` render in
|
|
61
|
+
React Server Components. Everything built on Base UI is a client component; its `"use client"`
|
|
62
|
+
directive ships in the build.
|
|
63
|
+
- **`render` prop:** renders a different element with the same props, e.g. `render={<section />}`.
|
|
64
|
+
- **Per-component entry points:** `@qeetrix/react/stack`, plus its own stylesheet at
|
|
65
|
+
`@qeetrix/react/css/stack.css` if you'd rather not load the full one. A family's stylesheet brings
|
|
66
|
+
the base styles and those of the components it renders (`css/text-field.css` brings Field and
|
|
67
|
+
Input).
|
|
68
|
+
|
|
69
|
+
| Component | For |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `Box` | A token-only surface: padding, background, border, corners |
|
|
72
|
+
| `Stack`, `Inline` | Vertical and horizontal flows with token gaps (`none` … `4xl`) |
|
|
73
|
+
| `Grid` | Equal columns per window size class (600 / 840 / 1200 / 1600px) |
|
|
74
|
+
| `Text` | Body text: size, weight, tone, monospace, truncation |
|
|
75
|
+
| `Heading` | `level` sets h1–h6; `size` sets the look (display, heading, title) |
|
|
76
|
+
| `Separator` | A 1px line, horizontal or vertical |
|
|
77
|
+
| `VisuallyHidden` | Content for screen readers only |
|
|
78
|
+
| `SkipLink` | "Skip to main content", hidden until focused |
|
|
79
|
+
| `Button` | Label first, an optional trailing icon; solid (primary), soft (secondary), ghost; brand or danger; `loading` |
|
|
80
|
+
| `IconButton` | A square, icon-only button; `aria-label` is required by its type and shows as a tooltip |
|
|
81
|
+
| `Link` | Inline navigation; `external` opens a new tab safely and says so to screen readers |
|
|
82
|
+
| `Toggle`, `ToggleGroup` | Pressed or not; segmented or separate groups, single or `multiple` |
|
|
83
|
+
| `Spinner` | An indeterminate wait, announced as a status unless `decorative` |
|
|
84
|
+
| `TextField` | Label, input, help text and error in one: the default form row |
|
|
85
|
+
| `Field` | The label, help text and error around any control; `optional` adds "(optional)" |
|
|
86
|
+
| `Input`, `Textarea` | The filled text box with a bottom line; Textarea grows with its content |
|
|
87
|
+
| `Fieldset` | A section of fields under a heading, spaced by the density's form gap |
|
|
88
|
+
| `Checkbox`, `CheckboxGroup` | On/off or several of a set; mixed state; a `parent` checkbox selects all |
|
|
89
|
+
| `Radio`, `RadioGroup` | One of a set; arrow keys move and select |
|
|
90
|
+
| `Switch` | A setting that applies at once |
|
|
91
|
+
| `Popover` | A panel anchored to a trigger: filters, details, a short form |
|
|
92
|
+
| `Tooltip` | A short label for a control; `TooltipProvider` groups neighbours |
|
|
93
|
+
| `Menu` | Actions and options from a trigger: icons, shortcuts, checkbox and radio items, submenus |
|
|
94
|
+
| `Dialog` | A focused task or decision; `intent="danger"` makes a confirmation only its actions close |
|
|
95
|
+
| `Drawer` | A side panel for details or an edit form, swipeable on touch |
|
|
96
|
+
| `ToastProvider`, `useToast` | Brief notifications with a status edge; errors stay until dismissed |
|
|
97
|
+
| `Select` | One option, or several, from up to about 15; looks like a field, opens like a menu |
|
|
98
|
+
| `Tabs` | Views of one context, with the sliding Ember bar |
|
|
99
|
+
| `Slider` | A number or a range on a scale, with a formatted value |
|
|
100
|
+
| `Accordion`, `Collapsible` | Ruled sections, or one section, that show and hide |
|
|
101
|
+
| `ScrollArea` | A scrolling region with Qeetrix scrollbars |
|
|
102
|
+
| `Card` | A raised, ruled surface with a title, actions and footer; a table inside runs edge to edge |
|
|
103
|
+
| `Table` | Semantic table parts with the header band, density row heights and selected rows |
|
|
104
|
+
| `Badge` | A static status pill in six tones |
|
|
105
|
+
| `Avatar` | A person's photo, or their initials |
|
|
106
|
+
| `Progress`, `Meter` | A task advancing, or a measurement within a range |
|
|
107
|
+
| `Skeleton` | A placeholder shaped like the content that's loading |
|
|
108
|
+
|
|
109
|
+
**Layout:** `className` is for placement only (margin, width, grid placement). Visual changes go
|
|
110
|
+
through props, so every Qeet product looks the same. On a form control, `className` and `style` place
|
|
111
|
+
the whole row, while `ref` and every other prop go to the control itself.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { Checkbox, CheckboxGroup, Fieldset, Radio, RadioGroup, TextField } from "@qeetrix/react";
|
|
115
|
+
|
|
116
|
+
<Fieldset legend="Company">
|
|
117
|
+
<TextField label="Trade name" name="tradeName" optional />
|
|
118
|
+
<TextField label="GSTIN" name="gstin" required description="15 characters." />
|
|
119
|
+
<RadioGroup label="Billing cycle" name="cycle" defaultValue="monthly">
|
|
120
|
+
<Radio value="monthly" label="Monthly" />
|
|
121
|
+
<Radio value="yearly" label="Yearly" description="Two months free." />
|
|
122
|
+
</RadioGroup>
|
|
123
|
+
<CheckboxGroup label="Notify me by" name="notify" orientation="horizontal">
|
|
124
|
+
<Checkbox value="email" label="Email" />
|
|
125
|
+
<Checkbox value="sms" label="SMS" />
|
|
126
|
+
</CheckboxGroup>
|
|
127
|
+
</Fieldset>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Overlays
|
|
131
|
+
|
|
132
|
+
Overlays share one shape: a root that holds the state, a trigger that renders your control, and a
|
|
133
|
+
content part that assembles everything else. Wrap the app once in `ToastProvider` (and, if you like,
|
|
134
|
+
`TooltipProvider`).
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import {
|
|
138
|
+
Button, Dialog, DialogClose, DialogContent, DialogFooter, DialogTrigger, useToast,
|
|
139
|
+
} from "@qeetrix/react";
|
|
140
|
+
|
|
141
|
+
function RevokeKey({ onRevoke }: { onRevoke: () => Promise<void> }) {
|
|
142
|
+
const toast = useToast();
|
|
143
|
+
return (
|
|
144
|
+
<Dialog intent="danger">
|
|
145
|
+
<DialogTrigger render={<Button tone="danger">Revoke key</Button>} />
|
|
146
|
+
<DialogContent title="Revoke this API key?" description="Apps using it stop working at once.">
|
|
147
|
+
<DialogFooter>
|
|
148
|
+
<DialogClose render={<Button variant="ghost">Cancel</Button>} />
|
|
149
|
+
<DialogClose
|
|
150
|
+
render={<Button tone="danger">Revoke key</Button>}
|
|
151
|
+
onClick={() =>
|
|
152
|
+
toast.promise(onRevoke(), {
|
|
153
|
+
loading: { title: "Revoking…" },
|
|
154
|
+
success: { title: "Key revoked" },
|
|
155
|
+
error: { title: "Couldn't revoke the key" },
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
/>
|
|
159
|
+
</DialogFooter>
|
|
160
|
+
</DialogContent>
|
|
161
|
+
</Dialog>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
29
166
|
## License
|
|
30
167
|
|
|
31
168
|
[MIT](https://github.com/qeetgroup/qeetrix-react/blob/main/LICENSE) © Qeet Group
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { HeadingLevel } from "../heading/heading.js";
|
|
2
|
+
import { Accordion } from "@base-ui/react/accordion";
|
|
3
|
+
import { Collapsible } from "@base-ui/react/collapsible";
|
|
4
|
+
import { CSSProperties, ReactElement, ReactNode } from "react";
|
|
5
|
+
export interface AccordionProps<Value = string> extends Omit<Accordion.Root.Props<Value>, "className" | "style"> {
|
|
6
|
+
/** Placement only. */
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
export interface AccordionItemProps extends Omit<Accordion.Item.Props, "className" | "style" | "title" | "children"> {
|
|
11
|
+
/** The section's title: the trigger's text. */
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
/** The heading level that wraps the trigger. Default 3. */
|
|
14
|
+
headingLevel?: Exclude<HeadingLevel, 1>;
|
|
15
|
+
/** The section's content. */
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
className?: string;
|
|
18
|
+
style?: CSSProperties;
|
|
19
|
+
}
|
|
20
|
+
export type CollapsibleProps = Collapsible.Root.Props;
|
|
21
|
+
export type CollapsibleTriggerProps = Collapsible.Trigger.Props;
|
|
22
|
+
export interface CollapsiblePanelProps extends Omit<Collapsible.Panel.Props, "className" | "style"> {
|
|
23
|
+
className?: string;
|
|
24
|
+
style?: CSSProperties;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Stacked sections that show and hide, ruled between (06-component-specs.md, increment 5):
|
|
28
|
+
* `value` / `defaultValue` / `onValueChange(value[], details)`, `multiple`, `disabled`.
|
|
29
|
+
*/
|
|
30
|
+
declare function Accordion$1<Value = string>({ className, ...props }: AccordionProps<Value>): ReactElement;
|
|
31
|
+
/**
|
|
32
|
+
* One section: a full-width trigger with a chevron, inside a heading, then the panel. Find in page
|
|
33
|
+
* opens a closed section that holds the match.
|
|
34
|
+
*/
|
|
35
|
+
export declare function AccordionItem({ title, headingLevel, className, children, ...props }: AccordionItemProps): ReactElement;
|
|
36
|
+
/** One section without the rules, for "Show more" or advanced options. */
|
|
37
|
+
declare function Collapsible$1(props: CollapsibleProps): ReactElement;
|
|
38
|
+
/** Shows and hides the panel. Render your own control: `render={<Button variant="ghost" />}`. */
|
|
39
|
+
export declare function CollapsibleTrigger(props: CollapsibleTriggerProps): ReactElement;
|
|
40
|
+
/** The content that shows and hides, with the accordion's height animation. */
|
|
41
|
+
export declare function CollapsiblePanel({ className, ...props }: CollapsiblePanelProps): ReactElement;
|
|
42
|
+
export { Accordion$1 as Accordion, Collapsible$1 as Collapsible };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../internal/cx.js";
|
|
3
|
+
import { Accordion } from "@base-ui/react/accordion";
|
|
4
|
+
import { Collapsible } from "@base-ui/react/collapsible";
|
|
5
|
+
import { ChevronDownIcon } from "@qeetrix/icons/icons/chevron-down";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
// src/accordion/accordion.tsx
|
|
8
|
+
/**
|
|
9
|
+
* Stacked sections that show and hide, ruled between (06-component-specs.md, increment 5):
|
|
10
|
+
* `value` / `defaultValue` / `onValueChange(value[], details)`, `multiple`, `disabled`.
|
|
11
|
+
*/
|
|
12
|
+
function Accordion$1({ className, ...props }) {
|
|
13
|
+
return /* @__PURE__ */ jsx(Accordion.Root, {
|
|
14
|
+
...props,
|
|
15
|
+
className: cx("qx-accordion", className),
|
|
16
|
+
"data-slot": "accordion"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* One section: a full-width trigger with a chevron, inside a heading, then the panel. Find in page
|
|
21
|
+
* opens a closed section that holds the match.
|
|
22
|
+
*/
|
|
23
|
+
function AccordionItem({ title, headingLevel = 3, className, children, ...props }) {
|
|
24
|
+
const Heading = `h${headingLevel}`;
|
|
25
|
+
return /* @__PURE__ */ jsxs(Accordion.Item, {
|
|
26
|
+
...props,
|
|
27
|
+
className: cx("qx-accordion-item", className),
|
|
28
|
+
"data-slot": "accordion-item",
|
|
29
|
+
children: [/* @__PURE__ */ jsx(Accordion.Header, {
|
|
30
|
+
render: /* @__PURE__ */ jsx(Heading, {}),
|
|
31
|
+
className: "qx-accordion-header",
|
|
32
|
+
children: /* @__PURE__ */ jsxs(Accordion.Trigger, {
|
|
33
|
+
className: "qx-accordion-trigger",
|
|
34
|
+
"data-slot": "accordion-trigger",
|
|
35
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
36
|
+
className: "qx-accordion-title",
|
|
37
|
+
children: title
|
|
38
|
+
}), /* @__PURE__ */ jsx(ChevronDownIcon, {
|
|
39
|
+
shape: "sharp",
|
|
40
|
+
size: 16,
|
|
41
|
+
"aria-hidden": true,
|
|
42
|
+
className: "qx-accordion-icon"
|
|
43
|
+
})]
|
|
44
|
+
})
|
|
45
|
+
}), /* @__PURE__ */ jsx(Accordion.Panel, {
|
|
46
|
+
hiddenUntilFound: true,
|
|
47
|
+
className: "qx-accordion-panel",
|
|
48
|
+
"data-slot": "accordion-panel",
|
|
49
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
50
|
+
className: "qx-accordion-content",
|
|
51
|
+
children
|
|
52
|
+
})
|
|
53
|
+
})]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/** One section without the rules, for "Show more" or advanced options. */
|
|
57
|
+
function Collapsible$1(props) {
|
|
58
|
+
return /* @__PURE__ */ jsx(Collapsible.Root, { ...props });
|
|
59
|
+
}
|
|
60
|
+
/** Shows and hides the panel. Render your own control: `render={<Button variant="ghost" />}`. */
|
|
61
|
+
function CollapsibleTrigger(props) {
|
|
62
|
+
return /* @__PURE__ */ jsx(Collapsible.Trigger, { ...props });
|
|
63
|
+
}
|
|
64
|
+
/** The content that shows and hides, with the accordion's height animation. */
|
|
65
|
+
function CollapsiblePanel({ className, ...props }) {
|
|
66
|
+
return /* @__PURE__ */ jsx(Collapsible.Panel, {
|
|
67
|
+
...props,
|
|
68
|
+
className: cx("qx-collapsible-panel", className),
|
|
69
|
+
"data-slot": "collapsible-panel"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export { Accordion$1 as Accordion, AccordionItem, Collapsible$1 as Collapsible, CollapsiblePanel, CollapsibleTrigger };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Accordion, AccordionItem, AccordionItemProps, AccordionProps, Collapsible, CollapsiblePanel, CollapsiblePanelProps, CollapsibleProps, CollapsibleTrigger, CollapsibleTriggerProps } from "./accordion.js";
|
|
2
|
+
export { Accordion, AccordionItem, type AccordionItemProps, type AccordionProps, Collapsible, CollapsiblePanel, type CollapsiblePanelProps, type CollapsibleProps, CollapsibleTrigger, type CollapsibleTriggerProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Accordion, AccordionItem, Collapsible, CollapsiblePanel, CollapsibleTrigger } from "./accordion.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Avatar } from "@base-ui/react/avatar";
|
|
2
|
+
import { CSSProperties, ReactElement } from "react";
|
|
3
|
+
export type AvatarSize = "sm" | "md" | "lg" | "xl";
|
|
4
|
+
export interface AvatarProps extends Omit<Avatar.Root.Props, "className" | "style" | "children"> {
|
|
5
|
+
/** The person's name: the image's text alternative, and the source of the initials. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** The photo. The initials show while it loads, and if it fails. */
|
|
8
|
+
src?: string;
|
|
9
|
+
/** `sm` 24, `md` 32 (default), `lg` 40 or `xl` 48px. */
|
|
10
|
+
size?: AvatarSize;
|
|
11
|
+
/** The name is shown beside it: hide the avatar from assistive technology. */
|
|
12
|
+
decorative?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
style?: CSSProperties;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A person: their photo, or their initials (06-component-specs.md, increment 6). A circle, since
|
|
18
|
+
* people are one of the two soft shapes. It's named by `name`, unless `decorative`.
|
|
19
|
+
*/
|
|
20
|
+
declare function Avatar$1({ name, src, size, decorative, className, ...props }: AvatarProps): ReactElement;
|
|
21
|
+
export { Avatar$1 as Avatar };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../internal/cx.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Avatar } from "@base-ui/react/avatar";
|
|
5
|
+
// src/avatar/avatar.tsx
|
|
6
|
+
const graphemes = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : void 0;
|
|
7
|
+
function firstGrapheme(word) {
|
|
8
|
+
if (!graphemes) return Array.from(word)[0] ?? "";
|
|
9
|
+
for (const { segment } of graphemes.segment(word)) return segment;
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
/** The first grapheme of the first and last words: "Priya Sharma" is "PS". */
|
|
13
|
+
function initials(name) {
|
|
14
|
+
const words = name.trim().split(/\s+/).filter(Boolean);
|
|
15
|
+
const first = words[0] ?? "";
|
|
16
|
+
const last = words.length > 1 ? words.at(-1) ?? "" : "";
|
|
17
|
+
return (firstGrapheme(first) + firstGrapheme(last)).toLocaleUpperCase();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A person: their photo, or their initials (06-component-specs.md, increment 6). A circle, since
|
|
21
|
+
* people are one of the two soft shapes. It's named by `name`, unless `decorative`.
|
|
22
|
+
*/
|
|
23
|
+
function Avatar$1({ name, src, size = "md", decorative, className, ...props }) {
|
|
24
|
+
return /* @__PURE__ */ jsxs(Avatar.Root, {
|
|
25
|
+
...props,
|
|
26
|
+
role: decorative ? void 0 : "img",
|
|
27
|
+
"aria-label": decorative ? void 0 : name,
|
|
28
|
+
"aria-hidden": decorative || void 0,
|
|
29
|
+
className: cx("qx-avatar", className),
|
|
30
|
+
"data-slot": "avatar",
|
|
31
|
+
"data-size": size,
|
|
32
|
+
children: [src && /* @__PURE__ */ jsx(Avatar.Image, {
|
|
33
|
+
src,
|
|
34
|
+
alt: "",
|
|
35
|
+
className: "qx-avatar-image"
|
|
36
|
+
}), /* @__PURE__ */ jsx(Avatar.Fallback, {
|
|
37
|
+
className: "qx-avatar-fallback",
|
|
38
|
+
"aria-hidden": true,
|
|
39
|
+
children: initials(name)
|
|
40
|
+
})]
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export { Avatar$1 as Avatar };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Avatar } from "./avatar.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { QeetrixIcon } from "../internal/control.js";
|
|
2
|
+
import { ComponentProps, ReactElement } from "react";
|
|
3
|
+
export type BadgeTone = "neutral" | "brand" | "info" | "success" | "warning" | "danger";
|
|
4
|
+
export interface BadgeProps extends ComponentProps<"span"> {
|
|
5
|
+
/** Default `neutral`. The word carries the meaning; the tone only reinforces it. */
|
|
6
|
+
tone?: BadgeTone;
|
|
7
|
+
/** A leading icon from `@qeetrix/icons`: sharp, 12px, decorative. */
|
|
8
|
+
icon?: QeetrixIcon;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A short, static status or count: one or two words (06-component-specs.md §10). It truncates with
|
|
12
|
+
* an ellipsis; pass `title` with the full text where it may be cut. Server-safe.
|
|
13
|
+
*/
|
|
14
|
+
export declare function Badge({ tone, icon: Icon, className, children, ...props }: BadgeProps): ReactElement;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { cx } from "../internal/cx.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
// src/badge/badge.tsx
|
|
4
|
+
/**
|
|
5
|
+
* A short, static status or count: one or two words (06-component-specs.md §10). It truncates with
|
|
6
|
+
* an ellipsis; pass `title` with the full text where it may be cut. Server-safe.
|
|
7
|
+
*/
|
|
8
|
+
function Badge({ tone = "neutral", icon: Icon, className, children, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
10
|
+
...props,
|
|
11
|
+
className: cx("qx-badge", className),
|
|
12
|
+
"data-slot": "badge",
|
|
13
|
+
"data-tone": tone,
|
|
14
|
+
children: [Icon && /* @__PURE__ */ jsx(Icon, {
|
|
15
|
+
shape: "sharp",
|
|
16
|
+
size: 12,
|
|
17
|
+
"aria-hidden": true,
|
|
18
|
+
className: "qx-badge-icon"
|
|
19
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
20
|
+
className: "qx-badge-label",
|
|
21
|
+
children
|
|
22
|
+
})]
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export { Badge };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Badge } from "./badge.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { RenderProp } from "../internal/render.js";
|
|
2
|
+
import { Inset } from "../internal/space.js";
|
|
3
|
+
import { ComponentProps, ReactElement } from "react";
|
|
4
|
+
export type BoxBackground = "canvas" | "default" | "raised" | "sunken" | "overlay" | "inverse" | "neutral" | "brand" | "selected";
|
|
5
|
+
export type BoxBorder = "none" | "subtle" | "default" | "strong";
|
|
6
|
+
export type BoxRadius = "none" | "sm" | "control" | "surface" | "overlay" | "modal" | "chip" | "full";
|
|
7
|
+
export interface BoxProps extends ComponentProps<"div"> {
|
|
8
|
+
/** Padding on every side, from the inset tokens. */
|
|
9
|
+
padding?: Inset;
|
|
10
|
+
/** Padding at the start and end; overrides `padding` on those sides. */
|
|
11
|
+
paddingInline?: Inset;
|
|
12
|
+
/** Padding at the top and bottom; overrides `padding` on those sides. */
|
|
13
|
+
paddingBlock?: Inset;
|
|
14
|
+
/** A surface or tint from the tokens. `inverse` also sets inverse text colour. */
|
|
15
|
+
background?: BoxBackground;
|
|
16
|
+
/** A 1px border in a token colour. */
|
|
17
|
+
border?: BoxBorder;
|
|
18
|
+
/** Corners from the radius tokens. */
|
|
19
|
+
radius?: BoxRadius;
|
|
20
|
+
/** Render a different element, e.g. `<section />`. */
|
|
21
|
+
render?: RenderProp;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A token-only surface: the sanctioned way to give a region padding, a background, a border or
|
|
25
|
+
* corners. It has no margin: space between siblings belongs to the parent's `gap`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function Box({ padding, paddingInline, paddingBlock, background, border, radius, render, className, ...props }: BoxProps): ReactElement;
|
package/dist/box/box.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cx } from "../internal/cx.js";
|
|
2
|
+
import { renderElement } from "../internal/render.js";
|
|
3
|
+
// src/box/box.tsx
|
|
4
|
+
/**
|
|
5
|
+
* A token-only surface: the sanctioned way to give a region padding, a background, a border or
|
|
6
|
+
* corners. It has no margin: space between siblings belongs to the parent's `gap`.
|
|
7
|
+
*/
|
|
8
|
+
function Box({ padding, paddingInline, paddingBlock, background, border, radius, render, className, ...props }) {
|
|
9
|
+
return renderElement("div", render, {
|
|
10
|
+
...props,
|
|
11
|
+
className: cx("qx-box", className),
|
|
12
|
+
"data-slot": "box",
|
|
13
|
+
"data-padding": padding,
|
|
14
|
+
"data-padding-inline": paddingInline,
|
|
15
|
+
"data-padding-block": paddingBlock,
|
|
16
|
+
"data-background": background,
|
|
17
|
+
"data-border": border,
|
|
18
|
+
"data-radius": radius
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export { Box };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Box } from "./box.js";
|