abaabil 1.2.0 → 1.4.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +179 -0
  2. package/README.md +274 -6
  3. package/dist/avatar/a11y.js +1 -0
  4. package/dist/avatar/avatar.css +1 -0
  5. package/dist/avatar/index.js +1 -0
  6. package/dist/avatar/styled.js +1 -0
  7. package/dist/badge/a11y.js +1 -0
  8. package/dist/badge/badge.css +1 -0
  9. package/dist/badge/index.js +1 -0
  10. package/dist/badge/styled.js +1 -0
  11. package/dist/breadcrumb/a11y.js +1 -0
  12. package/dist/breadcrumb/breadcrumb.css +1 -0
  13. package/dist/breadcrumb/index.js +1 -0
  14. package/dist/breadcrumb/styled.js +1 -0
  15. package/dist/file/a11y.js +2 -0
  16. package/dist/file/file.css +1 -0
  17. package/dist/file/index.js +1 -0
  18. package/dist/file/styled.js +1 -0
  19. package/dist/menu/a11y.js +2 -0
  20. package/dist/menu/index.js +1 -0
  21. package/dist/menu/menu.css +1 -0
  22. package/dist/menu/styled.js +1 -0
  23. package/dist/pagination/a11y.js +1 -0
  24. package/dist/pagination/index.js +1 -0
  25. package/dist/pagination/pagination.css +1 -0
  26. package/dist/pagination/styled.js +1 -0
  27. package/dist/popover/a11y.js +1 -1
  28. package/dist/progress/a11y.js +2 -0
  29. package/dist/progress/index.js +1 -0
  30. package/dist/progress/progress.css +1 -0
  31. package/dist/progress/styled.js +1 -0
  32. package/dist/slider/a11y.js +2 -0
  33. package/dist/slider/index.js +1 -0
  34. package/dist/slider/slider.css +1 -0
  35. package/dist/slider/styled.js +1 -0
  36. package/dist/styles.css +1 -1
  37. package/dist/theme.css +1 -1
  38. package/dist/toolbar/a11y.js +2 -0
  39. package/dist/toolbar/index.js +1 -0
  40. package/dist/toolbar/styled.js +1 -0
  41. package/dist/toolbar/toolbar.css +1 -0
  42. package/dist/tooltip/a11y.js +2 -0
  43. package/dist/tooltip/index.js +1 -0
  44. package/dist/tooltip/styled.js +1 -0
  45. package/dist/tooltip/tooltip.css +1 -0
  46. package/llms.txt +143 -0
  47. package/package.json +45 -4
package/CHANGELOG.md CHANGED
@@ -4,6 +4,185 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
 
7
+ ## [1.4.0] - 2026-09-21
8
+
9
+ ### Added
10
+
11
+ Five components, taking the library from eighteen to twenty-three. Two
12
+ carry real accessibility work, one wraps a native element that is
13
+ genuinely painful to do by hand, and two are the presentational pieces a
14
+ design system is expected to have, each with a trap worth encoding.
15
+
16
+ - **`abaabil/pagination`** - a `<nav>` around an ordered list of real
17
+ links, so a page is a URL you can open in a new tab and share; a
18
+ paginator built from buttons gives that up for nothing. Server
19
+ renderable at every tier. The gap is drawn in CSS so an ellipsis is
20
+ never read out between numbers, and it only appears when it stands in
21
+ for two or more pages. Every number is named "Page 7" rather than
22
+ announced as a bare "7", and all four labels are replaceable for
23
+ translation.
24
+ - **`abaabil/file`** - a real `<input type="file">`, not a button with a
25
+ hidden input behind it. That pattern reimplements the label
26
+ association, the keyboard activation and the announcement of the
27
+ chosen file, and usually manages one of the three;
28
+ `::file-selector-button` means the real control can be styled
29
+ instead. Warns when `accept` is set with nothing explaining it in
30
+ words, because `accept` is never announced and does not apply to a
31
+ dropped file.
32
+ - **`abaabil/toolbar`** - the APG toolbar pattern. The point is the tab
33
+ sequence: eight buttons are eight stops on the way past them, and as
34
+ a toolbar they are one. Takes arbitrary children rather than an items
35
+ array, since a toolbar's contents are heterogeneous by definition,
36
+ and manages `tabindex` on its focusable descendants directly because
37
+ cloning only reaches the top level. A control that needs the arrows
38
+ itself keeps them.
39
+ - **`abaabil/avatar`** - an image, or initials when there is none. No
40
+ fallback-on-load-error: that needs state, and would make every tier a
41
+ client component for a case the server usually already knows about.
42
+ The a11y tier asks whether the avatar repeats something already on
43
+ screen, because the answer changes per use and the component cannot
44
+ guess. The initials are never the accessible name; "FA" read aloud is
45
+ not a person.
46
+ - **`abaabil/badge`** - shorthand that only means something beside what
47
+ it is attached to. `context` supplies the rest of the sentence as
48
+ hidden text, so a badge draws "3" and announces "3 unread messages".
49
+ Hidden text rather than `aria-label`, because a `<span>` has no role
50
+ and discards it. That is not hypothetical: it is the bug found in
51
+ this library's own popover one release ago.
52
+
53
+ Fifty-one of the sixty-nine entry points carry no client directive.
54
+ Nine components are server-renderable at every tier, up from six.
55
+
56
+ ### Fixed
57
+
58
+ - **Re-theming only went halfway.** `--color-primary-hover` and
59
+ `--color-focus-ring` were pinned to blue primitives rather than
60
+ derived from `--color-primary`, so setting the primary colour to red
61
+ gave a red button with a blue hover state and a blue focus ring on
62
+ every control in the library, with nothing saying so. Both now follow
63
+ `--color-primary`. The stock theme is unchanged for the focus ring,
64
+ which was already the same value, and the default hover moves from
65
+ `#3b82f6` to `#467aee`, which is the same blue to look at.
66
+ `--abaabil-blue-400` existed only to feed the old hover and is
67
+ removed: a primitive nothing reads is one someone overrides expecting
68
+ a result, and gets none.
69
+ - `pageWindow` emitted a gap where it stood in for exactly one page, so
70
+ at page 4 of 12 an ellipsis replaced page 2: the same width as the
71
+ number it hid, carrying less. Caught by its own test rather than by
72
+ looking at it.
73
+
74
+ ## [1.3.0] - 2026-09-21
75
+
76
+ ### Added
77
+
78
+ Five components, taking the library from thirteen to eighteen. Two of
79
+ them are the things people ask for most and are hard; three are nearly
80
+ free because the platform already does the work.
81
+
82
+ - **`abaabil/menu`** - the W3C APG menu button pattern on top of the
83
+ native Popover API. The browser supplies the top layer, the
84
+ outside-click dismissal and Escape; this supplies `role="menu"`, a
85
+ roving tabindex, Up/Down with wrapping, Home/End, multi-character
86
+ typeahead, Tab to close, and focus moving into the menu on open and
87
+ back to the trigger on close. `aria-expanded` is driven by the panel's
88
+ own `toggle` event rather than a second copy of the open state, since
89
+ the browser can close the panel without telling the component. Its
90
+ docs say when a menu is the wrong widget: a button revealing
91
+ navigation links is a popover, not a menu.
92
+ - **`abaabil/tooltip`** - shows on `:hover` and `:focus-within`, which
93
+ are selectors, so the `normal` and `styled` tiers need no JavaScript
94
+ at all. The `a11y` tier adds the two things CSS cannot: the
95
+ `aria-describedby` that makes a screen reader read it, and Escape to
96
+ dismiss, which WCAG 1.4.13 requires. The docs lead with when not to
97
+ use one.
98
+ - **`abaabil/progress`** - native `<progress>`. `value` has no default,
99
+ so omitting it gives a genuinely indeterminate bar rather than one
100
+ claiming to be 0% done. `valueText` sets `aria-valuetext`, because a
101
+ bar whose number is not a percentage is otherwise announced as one.
102
+ - **`abaabil/slider`** - native `<input type="range">`, so the keyboard
103
+ support and the min/max/step arithmetic are the platform's.
104
+ `formatValue` sets `aria-valuetext` and the optional visible
105
+ `<output>`, which is marked `aria-hidden` so the value is not
106
+ announced twice.
107
+ - **`abaabil/breadcrumb`** - a `<nav>` around an ordered list, because
108
+ the order is the information. Server-renderable at every tier. The
109
+ separator is drawn in CSS so it is never read aloud, the `<nav>` is
110
+ named, and the last item renders as text with `aria-current="page"`.
111
+
112
+ Thirty-six of the fifty-four entry points now carry no client directive.
113
+ Six components are server-renderable at every tier including `a11y`, up
114
+ from four.
115
+
116
+ `role="tooltip"` is deliberately **not** in tooltip's `normal` tier,
117
+ unlike `role="switch"` in switch's. The difference: a switch's role
118
+ changes how a reachable interactive control is announced, so it does
119
+ something on its own. A tooltip is only ever reached through the
120
+ `aria-describedby` on its trigger, so the role without that association
121
+ announces nothing, and it belongs with the wiring that gives it meaning.
122
+
123
+ Three bugs were found by driving these in a real browser, after 511
124
+ jsdom tests had passed. All three are the same shape: jsdom does not run
125
+ the thing that was broken.
126
+
127
+ - Menu focused its first item inside `requestAnimationFrame`, which does
128
+ not fire in a background tab, so focus silently never moved there. The
129
+ `toggle` event already fires with the panel in the top layer and
130
+ focusable, so the focus call is synchronous now.
131
+ - Menu read the active index from state, so two keydowns arriving in the
132
+ same tick both moved one step from the same origin: holding ArrowDown
133
+ advanced one item and stopped. The index is a ref now. Covered by a
134
+ test that dispatches two raw events inside one `act`, which is the
135
+ only way to reproduce it, since `fireEvent` flushes between calls.
136
+ - Tooltip put its fade on the shown state, so whenever the transition
137
+ did not advance the bubble stayed at opacity 0 while every selector
138
+ said it should be visible: a tooltip that silently never appears. The
139
+ fade is on the hidden state now and showing is instant, which is also
140
+ the better behaviour for a tooltip.
141
+
142
+ Two more came out of a full accessibility audit of all eighteen
143
+ components, run with axe against a real browser. Both were silent: the
144
+ component looked right, the tests passed, and the thing it claimed to add
145
+ was being discarded.
146
+
147
+ - **`popover/a11y` was not naming its panel at all.** A bare
148
+ `<div popover>` has no role, and `aria-label` is prohibited on a
149
+ generic element, so the label was dropped: the panel computed to role
150
+ `null` with no accessible name, and axe flags it as
151
+ `aria-prohibited-attr`. The panel is `role="group"` now, overridable
152
+ with `role`. Naming the panel was this tier's entire contribution, so
153
+ until now it added 484 bytes and achieved nothing.
154
+ - **`progress/a11y` was not naming its bar.** `<progress>` is a labelable
155
+ element, so `<label for>` is not wrong, but no accessible name is
156
+ computed from it: axe names an `<input>` from identical markup and
157
+ names neither `<progress>` nor `<meter>`. `aria-labelledby` now points
158
+ at the label, making the name explicit instead of leaving it to differ
159
+ between implementations.
160
+
161
+ The audit itself had to be redone once. The first pass rendered the
162
+ dialog open, and a modal dialog makes everything behind it inert, so the
163
+ sweep that reported zero violations had not actually examined the other
164
+ seventeen components.
165
+
166
+ ### Fixed
167
+
168
+ - `dist/combobox/index.js` and `dist/combobox/styled.js` had no size
169
+ budget. Combobox was the first component built and only its `a11y`
170
+ tier was ever listed, so two entry points had been unwatched since
171
+ 1.0.0. Found by the new registration check, not by noticing.
172
+
173
+ ### Added (tooling)
174
+
175
+ - `llms.txt`, shipped inside the package. It is the short version of the
176
+ README written for coding agents: the rules that are easy to get wrong
177
+ (no root export, import `theme.css` once, prefer the `a11y` tier) and
178
+ the per-component traps (popover needs an explicit `id`, alert has to
179
+ exist before it has a message, combobox and tabs are uncontrolled). An
180
+ agent with `node_modules` can read it without the network. It reaches
181
+ npm with the next release.
182
+ - `AGENTS.md` at the repository root, for agents changing the library
183
+ rather than using it: the enforced architecture rules, the conventions,
184
+ and the seven steps for adding a component.
185
+
7
186
  ## [1.2.0] - 2026-09-21
8
187
 
9
188
  ### Added
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Minimal, themeable, accessible React components. Zero dependencies.
4
4
 
5
- Thirteen components: button, dialog, combobox, input, textarea, checkbox, radio, switch, select, accordion, tabs, popover, alert.
5
+ Twenty-three components: button, dialog, popover, menu, tooltip, combobox, input, textarea, file, checkbox, radio, switch, select, slider, accordion, tabs, toolbar, breadcrumb, pagination, progress, alert, avatar, badge.
6
6
 
7
7
  ```js
8
8
  import Button from 'abaabil/button/a11y'
@@ -103,7 +103,7 @@ import Accordion from 'abaabil/accordion/a11y'
103
103
 
104
104
  ### Bundler required for `styled` and `a11y` tiers
105
105
 
106
- The `styled` and `a11y` entry points (all twenty-six across the thirteen components) import their
106
+ The `styled` and `a11y` entry points (all forty-six across the twenty-three components) import their
107
107
  component's CSS as a JS side effect (`import 'abaabil/button/button.css'` style, resolved
108
108
  relative to the package). That works in any bundler that understands CSS imports, which
109
109
  covers Next.js, Vite, and webpack. It does **not** work if you run the built file directly in
@@ -160,6 +160,21 @@ abaabil ships design tokens in `abaabil/theme.css`. Override the CSS custom prop
160
160
  }
161
161
  ```
162
162
 
163
+ Setting `--color-primary` is enough. The hover shade and the focus ring are **derived** from it, so a purple theme gets a purple hover and a purple focus ring without naming either:
164
+
165
+ | Token | Default | Follows `--color-primary`? |
166
+ |---|---|---|
167
+ | `--color-primary` | `#2563eb` | is it |
168
+ | `--color-primary-hover` | `color-mix(in srgb, var(--color-primary) 85%, white)` | yes |
169
+ | `--color-focus-ring` | `var(--color-primary)` | yes |
170
+ | `--color-primary-fg` | `#ffffff` | **no**, see below |
171
+
172
+ Override any of them individually if the derived value is not what you want.
173
+
174
+ `--color-primary-fg` is the text and iconography drawn *on* the primary colour, and it does not derive, because deriving it needs a contrast decision CSS cannot make yet. It is white. If you set `--color-primary` to something light, set `--color-primary-fg` to something dark alongside it, or the text on your buttons will fail contrast.
175
+
176
+ `--color-danger`, `--color-success` and `--color-warning` are independent on purpose: an error is red whatever your brand colour is.
177
+
163
178
  abaabil's own component rules live inside `@layer abaabil.components`. CSS layers give unlayered rules the higher priority by default, so any selector you write in your normal (unlayered) application CSS beats the library's layered styles automatically, with no `!important` needed:
164
179
 
165
180
  ```css
@@ -214,15 +229,50 @@ Only the entry points that need interactivity are marked `"use client"`. The res
214
229
  | `abaabil/alert` | no |
215
230
  | `abaabil/alert/styled` | no |
216
231
  | `abaabil/alert/a11y` | no |
217
-
218
- Twenty-six of the thirty-nine entry points carry no client directive and render from a Server Component with zero client JS.
219
-
220
- Four components are server-renderable at **every** tier, `a11y` included, because they need no JavaScript at all:
232
+ | `abaabil/progress` | no |
233
+ | `abaabil/progress/styled` | no |
234
+ | `abaabil/progress/a11y` | yes |
235
+ | `abaabil/slider` | no |
236
+ | `abaabil/slider/styled` | no |
237
+ | `abaabil/slider/a11y` | yes |
238
+ | `abaabil/breadcrumb` | no |
239
+ | `abaabil/breadcrumb/styled` | no |
240
+ | `abaabil/breadcrumb/a11y` | no |
241
+ | `abaabil/tooltip` | no |
242
+ | `abaabil/tooltip/styled` | no |
243
+ | `abaabil/tooltip/a11y` | yes |
244
+ | `abaabil/menu` | no |
245
+ | `abaabil/menu/styled` | no |
246
+ | `abaabil/menu/a11y` | yes |
247
+ | `abaabil/pagination` | no |
248
+ | `abaabil/pagination/styled` | no |
249
+ | `abaabil/pagination/a11y` | no |
250
+ | `abaabil/file` | no |
251
+ | `abaabil/file/styled` | no |
252
+ | `abaabil/file/a11y` | yes |
253
+ | `abaabil/toolbar` | no |
254
+ | `abaabil/toolbar/styled` | no |
255
+ | `abaabil/toolbar/a11y` | yes |
256
+ | `abaabil/avatar` | no |
257
+ | `abaabil/avatar/styled` | no |
258
+ | `abaabil/avatar/a11y` | no |
259
+ | `abaabil/badge` | no |
260
+ | `abaabil/badge/styled` | no |
261
+ | `abaabil/badge/a11y` | no |
262
+
263
+ Fifty-one of the sixty-nine entry points carry no client directive and render from a Server Component with zero client JS.
264
+
265
+ Nine components are server-renderable at **every** tier, `a11y` included, because they need no JavaScript at all:
221
266
 
222
267
  - **button**, which attaches handlers only when you actually pass one (see the note at the end of this section).
223
268
  - **accordion**, where exclusive open/close comes from the native `name` attribute on `<details>`.
224
269
  - **popover**, where the trigger, the top layer, light-dismiss and Escape all come from the native Popover API.
225
270
  - **alert**, which is a live region and a border.
271
+ - **breadcrumb** and **pagination**, which are a `<nav>` and an ordered list.
272
+ - **avatar** and **badge**, which are markup and CSS.
273
+ - **progress** and **slider** at `normal` and `styled`; their `a11y` tiers need `useId`.
274
+
275
+ **tooltip** is the interesting case: it shows and hides on `:hover` and `:focus-within`, which are selectors, so its `normal` and `styled` tiers need no JavaScript to work at all. Only the tier that adds `aria-describedby` and Escape is a client component.
226
276
 
227
277
  Two components are client modules at every tier, because neither has a native element to build on and both need state to show one thing at a time: **combobox** and **tabs**.
228
278
 
@@ -525,6 +575,214 @@ Uncontrolled, like the combobox: observe the selection through `onChange`.
525
575
 
526
576
  **Read this before using it.** A live region is announced when its *contents change*, and assistive tech has to be watching the region before that happens. An alert that arrives in the DOM already carrying its message may not be announced at all, and behaviour differs between screen readers. If the message appears in response to something the user did, render the component with empty children from the start and fill it in, rather than mounting the whole alert at the moment you have something to say. Rendered empty it paints nothing.
527
577
 
578
+ ### Progress
579
+
580
+ Native `<progress>`. Omit `value` for an indeterminate bar; it has no default, because defaulting it to 0 would turn every unknown-duration operation into one claiming to be 0% done.
581
+
582
+ `normal` / `styled`:
583
+
584
+ | Prop | Type | Default | Description |
585
+ |---|---|---|---|
586
+ | `value` | `number` | - | Omit for indeterminate. |
587
+ | `max` | `number` | `100` | |
588
+ | `className` | `string` | - | Merged with the base class. |
589
+
590
+ `a11y` adds the label wiring and the one thing people get wrong about a progress bar, which is what it announces:
591
+
592
+ | Prop | Type | Default | Description |
593
+ |---|---|---|---|
594
+ | `label` | `string` | - | Rendered as a real `<label>`. |
595
+ | `hideLabel` | `boolean` | `false` | Hide it visually; it stays in the accessibility tree. |
596
+ | `description` | `string` | - | Help text, wired into `aria-describedby`. |
597
+ | `valueText` | `string` | - | Announced instead of the percentage. A bare `<progress value="3" max="8">` says "38 percent"; pass `"3 of 8 files"` when the number means something else. |
598
+
599
+ ### Slider
600
+
601
+ Native `<input type="range">`. The keyboard support, the min/max/step arithmetic and the announced role all come from the platform, which is why this is under 200 bytes at the lower tiers.
602
+
603
+ `normal` / `styled`:
604
+
605
+ | Prop | Type | Default | Description |
606
+ |---|---|---|---|
607
+ | `min` / `max` / `step` | `number` | `0` / `100` / `1` | |
608
+ | `className` | `string` | - | Merged with the base class. |
609
+
610
+ `a11y`:
611
+
612
+ | Prop | Type | Default | Description |
613
+ |---|---|---|---|
614
+ | `label` | `string` | - | Rendered as a real `<label>`. |
615
+ | `hideLabel` | `boolean` | `false` | |
616
+ | `description` | `string` | - | Wired into `aria-describedby`. |
617
+ | `showValue` | `boolean` | `false` | Renders the value in an `<output>`, marked `aria-hidden` because the input already announces it. |
618
+ | `formatValue` | `(value: number) => string` | - | Sets `aria-valuetext` and the visible output. A price slider announces "50" without it. |
619
+
620
+ Uncontrolled by default; pass `defaultValue` and read `onChange`. An uncontrolled slider starts at the midpoint, matching the native thumb.
621
+
622
+ ### Breadcrumb
623
+
624
+ A `<nav>` around an ordered list, because the order is the information. All three tiers are server-renderable.
625
+
626
+ The separator is drawn in CSS, never rendered as text, so a screen reader is not reading punctuation between the steps.
627
+
628
+ | Prop | Type | Default | Description |
629
+ |---|---|---|---|
630
+ | `items` | `Array<{ key?, label, href? }>` | - | Root first. An item with no `href` renders as text. |
631
+ | `className` | `string` | - | |
632
+
633
+ `a11y` adds the two things a hand-rolled breadcrumb almost always misses:
634
+
635
+ | Prop | Type | Default | Description |
636
+ |---|---|---|---|
637
+ | `label` | `string` | `'Breadcrumb'` | Names the `<nav>`. A page usually has several navigation landmarks, and unnamed ones are announced as "navigation, navigation, navigation". |
638
+ | `linkCurrent` | `boolean` | `false` | By default the last item renders as text even if given an `href`, because a link to the page you are on is a link that does nothing. Either way it gets `aria-current="page"`. |
639
+
640
+ ### Tooltip
641
+
642
+ **Read this before using one.** A tooltip is the control most often used for the wrong job.
643
+
644
+ - **Never put essential information in one.** There is no hover on touch, so it is simply unreachable there.
645
+ - **Never put interactive content in one.** Moving towards a link inside a tooltip dismisses the tooltip. If you need that, you want a popover.
646
+ - **The trigger must be focusable.** A tooltip on a plain `<span>` does not exist for keyboard users. The `a11y` tier warns when its child cannot receive props.
647
+
648
+ Showing and hiding is done in CSS, by `:hover` and `:focus-within`. Those are the two events that should reveal a tooltip and both are expressible as selectors, so the `normal` and `styled` tiers need no JavaScript.
649
+
650
+ | Prop | Type | Default | Description |
651
+ |---|---|---|---|
652
+ | `content` | `ReactNode` | - | The tooltip text. |
653
+ | `placement` | `'top' \| 'bottom'` | `'top'` | |
654
+ | `children` | `ReactElement` | - | The trigger. |
655
+
656
+ `a11y` adds the two things CSS cannot: `aria-describedby` from the trigger to the bubble, which is what makes a screen reader read it at all, and Escape to dismiss, which WCAG 1.4.13 requires for content revealed on hover. It clones the child to attach them, so the trigger stays your element rather than a wrapper of ours.
657
+
658
+ ### Menu
659
+
660
+ The W3C APG menu button pattern, on top of the native Popover API. The browser supplies the top layer, the outside-click dismissal and Escape; this component supplies the menu semantics and keyboard.
661
+
662
+ Like popover, `id` is required rather than generated.
663
+
664
+ **When not to use it.** `role="menu"` means a list of *actions*, in the application-menu sense. A button revealing a few navigation links is not a menu, and marking it up as one makes a screen reader announce a widget the user then cannot operate as one. Use `abaabil/popover` with links in it.
665
+
666
+ | Prop | Type | Default | Description |
667
+ |---|---|---|---|
668
+ | `id` | `string` | - | Panel id; also wires the trigger. Required. |
669
+ | `trigger` | `ReactNode` | - | Button content. |
670
+ | `items` | `Array<{ key?, label, href?, onSelect?, disabled? }>` | - | An item with `href` renders an `<a>`, otherwise a `<button>`. |
671
+ | `triggerProps` | `object` | - | Spread onto the trigger. |
672
+
673
+ `a11y` adds:
674
+
675
+ | Prop | Type | Default | Description |
676
+ |---|---|---|---|
677
+ | `label` | `string` | - | Names the menu itself. Without it the menu is named by its trigger. |
678
+
679
+ plus `aria-haspopup`, a live `aria-expanded` kept in step with the panel's own `toggle` event, `role="menu"`/`role="menuitem"`, a roving tabindex, Up/Down with wrapping, Home/End, multi-character typeahead, Tab to close, and focus moving to the first item on open and back to the trigger on close.
680
+
681
+ ### Pagination
682
+
683
+ A `<nav>` around an ordered list of real links, so each page is a URL you can open in a new tab, bookmark and share. A paginator built from buttons takes all of that away for nothing. Server-renderable at every tier.
684
+
685
+ | Prop | Type | Default | Description |
686
+ |---|---|---|---|
687
+ | `page` | `number` | - | Current page, 1-based. |
688
+ | `pageCount` | `number` | - | Total pages. |
689
+ | `href` | `(page) => string` | - | Builds each page's URL. |
690
+ | `siblings` | `number` | `1` | Pages shown either side of the current one before the list collapses. |
691
+ | `className` | `string` | - | |
692
+
693
+ The gap is drawn in CSS, never rendered as text, so an ellipsis is never read out between numbers. It also only ever appears when it stands in for **two or more** pages: a gap replacing a single number takes the same room and says less.
694
+
695
+ `a11y` adds the four things a hand-rolled paginator usually misses:
696
+
697
+ | Prop | Type | Default | Description |
698
+ |---|---|---|---|
699
+ | `label` | `string` | `'Pagination'` | Names the `<nav>`. |
700
+ | `pageLabel` | `(n) => string` | `` `Page ${n}` `` | Names each number. A link whose whole content is "7" is announced as "7", which in a list of links means nothing. Replace to translate. |
701
+ | `previousLabel` | `string` | `'Previous page'` | |
702
+ | `nextLabel` | `string` | `'Next page'` | |
703
+
704
+ plus `aria-current="page"` on the current page. At either end, Previous and Next are not links at all, so nothing dead stays in the tab order.
705
+
706
+ ### File
707
+
708
+ A native `<input type="file">`, not a `<button>` with a hidden input behind it. That pattern has to reimplement the label association, the keyboard activation and the announcement of the chosen file, and usually manages one of the three. The real control does all three, and it is stylable: `::file-selector-button` is a real pseudo-element.
709
+
710
+ | Prop | Type | Default | Description |
711
+ |---|---|---|---|
712
+ | `className` | `string` | - | Merged with the base class. |
713
+
714
+ `a11y` adds the same label, description and error wiring as `input`:
715
+
716
+ | Prop | Type | Default | Description |
717
+ |---|---|---|---|
718
+ | `label` | `string` | - | Rendered as a real `<label>`. |
719
+ | `hideLabel` | `boolean` | `false` | |
720
+ | `description` | `string` | - | Wired into `aria-describedby`. |
721
+ | `error` | `string` | - | Sets `aria-invalid` and joins `aria-describedby`. |
722
+ | `required` | `boolean` | `false` | |
723
+
724
+ It also warns when you pass `accept` without a `description`. `accept` filters the file dialog silently: it is never announced, and it does not apply to a file dropped onto the control. Say what you take in words.
725
+
726
+ ### Toolbar
727
+
728
+ The W3C APG toolbar pattern. The point of it is the tab sequence: a row of eight buttons is eight stops on the way to the rest of the page, and as a toolbar it is one, with the arrow keys moving between the controls inside. A toolbar that does not do that is a `<div>` with a role on it.
729
+
730
+ | Prop | Type | Default | Description |
731
+ |---|---|---|---|
732
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Chooses the arrow pair. |
733
+ | `className` | `string` | - | |
734
+
735
+ `a11y` adds `role="toolbar"`, `aria-orientation`, a roving tabindex, arrow keys following the orientation, and Home/End:
736
+
737
+ | Prop | Type | Default | Description |
738
+ |---|---|---|---|
739
+ | `label` | `string` | - | Accessible name. An unnamed toolbar is announced as "toolbar" and nothing else. |
740
+ | `labelledBy` | `string` | - | Id of an element naming it. |
741
+
742
+ It takes arbitrary children rather than an `items` array, because a toolbar's contents are heterogeneous by definition, and manages `tabindex` on its focusable descendants directly: cloning would only reach the top level. A control that needs the arrows itself, such as a `<select>` or a text field, keeps them.
743
+
744
+ ### Avatar
745
+
746
+ An image when there is one, initials when there is not. There is no fallback-on-load-error, which would need state and make every tier a client component for a case the server usually already knows about: pass no `src` and you get initials.
747
+
748
+ | Prop | Type | Default | Description |
749
+ |---|---|---|---|
750
+ | `src` | `string` | - | Omit for initials. |
751
+ | `name` | `string` | - | Used for the initials. |
752
+ | `alt` | `string` | `''` | Empty by default, which is right more often than not. |
753
+ | `className` | `string` | - | |
754
+
755
+ `a11y` asks the question the component cannot answer for you:
756
+
757
+ | Prop | Type | Default | Description |
758
+ |---|---|---|---|
759
+ | `decorative` | `boolean` | `true` | Whether the avatar repeats something already on screen. |
760
+
761
+ Beside a visible name an avatar is **decorative**: it says nothing the text does not, and naming it means hearing the person twice. Alone, in a stack of collaborators or a comment with no byline, it is the only thing identifying someone and needs a name, so pass `decorative={false}`.
762
+
763
+ The initials are never the accessible name. "FA" read aloud is not a person: when meaningful, the letters are hidden and the name is carried by a `role="img"` that can hold one.
764
+
765
+ ### Badge
766
+
767
+ A small piece of status text. Server-renderable at every tier.
768
+
769
+ | Prop | Type | Default | Description |
770
+ |---|---|---|---|
771
+ | `variant` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Applied as `data-variant`. |
772
+ | `className` | `string` | - | |
773
+
774
+ `a11y` adds the one thing that makes a badge worth a component:
775
+
776
+ | Prop | Type | Default | Description |
777
+ |---|---|---|---|
778
+ | `context` | `string` | - | The rest of the sentence, announced but not drawn. |
779
+
780
+ A badge is shorthand that only means something beside what it is attached to. "3" next to an inbox icon, read out on its own in a list of everything on the page, is noise: the user hears "three" with no way to know three of what. `context` supplies the rest as visually hidden text, so the badge still draws "3" and announces "3 unread messages".
781
+
782
+ It is hidden text rather than `aria-label`, deliberately. A badge is a `<span>`, a span has no role, and `aria-label` is prohibited on a generic element: set it there and it is discarded, leaving the badge as unlabelled as before while looking fixed. That exact mistake shipped in this library's own popover, and is why this component does it the other way.
783
+
784
+ A badge is not a live region. A count that changes while the page is open does not announce itself, and this does not make it do so; wrap it in `abaabil/alert` if the change is worth interrupting for, which for an unread count it usually is not.
785
+
528
786
  ## Combobox: uncontrolled in 1.x
529
787
 
530
788
  The combobox is uncontrolled in this release: it does not accept a `value` prop. Observe the selected value through the `onChange` callback instead of driving it from external state.
@@ -554,6 +812,16 @@ Where the panel appears is a separate question from whether it works. Attaching
554
812
  - Tabs implement the [WAI-ARIA Authoring Practices Guide tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/), including a roving tabindex so Tab steps past the tablist rather than through every tab in it.
555
813
  - Switch carries `role="switch"` from its `normal` tier, so it never looks like a switch while announcing itself as a checkbox.
556
814
  - Alert derives `role="status"` or `role="alert"` from its variant, so a confirmation does not interrupt and an error does. Read the note in its props section about when live regions actually announce.
815
+ - Menu implements the [WAI-ARIA Authoring Practices Guide menu button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/), and its docs say when a menu is the wrong widget.
816
+ - Tooltip shows on both hover and focus, dismisses on Escape as WCAG 1.4.13 requires, and its bubble is never a pointer target so it cannot be hovered instead of its trigger.
817
+ - Progress accepts `valueText`, because a bar whose number is not a percentage is otherwise announced as one.
818
+ - Slider is a native range input, so its keyboard support is the platform's rather than a reimplementation; `formatValue` sets `aria-valuetext` for values that are not self-explanatory.
819
+ - Breadcrumb names its `<nav>` and marks the current page with `aria-current`, and draws its separators in CSS so they are never read aloud.
820
+ - Toolbar implements the [WAI-ARIA Authoring Practices Guide toolbar pattern](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/), collapsing a row of controls to one tab stop with arrow-key movement inside.
821
+ - Pagination names its `<nav>`, gives every number a real name rather than a bare digit, marks the current page with `aria-current`, and draws its gap in CSS so it is never read aloud.
822
+ - File warns when `accept` is set with nothing explaining it in words, because `accept` is never announced and does not apply to a dropped file.
823
+ - Avatar treats decorative and meaningful as different cases, and never uses the initials as the accessible name.
824
+ - Badge carries its context as visually hidden text rather than `aria-label`, which a `<span>` discards.
557
825
  - `a11y` tiers are the recommended default for production use; `normal` and `styled` tiers exist for cases where you want to compose your own accessibility behavior.
558
826
 
559
827
  ## License
@@ -0,0 +1 @@
1
+ import{jsx as a}from"react/jsx-runtime";import"./avatar.css";import{initials as c}from"./index.js";function m({src:n,name:e,decorative:i=!0,className:s,children:t,...l}){const o=s?`abaabil-avatar ${s}`:"abaabil-avatar";typeof process<"u"&&process.env.NODE_ENV!=="production"&&!i&&!e&&console.warn("abaabil/avatar: decorative={false} means this avatar is the only thing identifying someone, so it needs a `name`. Without one it is announced as an unlabelled image.");const r=t??c(e);return a("span",{className:o,...l,children:n?a("img",{src:n,alt:i?"":e||"",className:"abaabil-avatar__image"}):i?a("span",{className:"abaabil-avatar__initials","aria-hidden":"true",children:r}):a("span",{className:"abaabil-avatar__initials",role:"img","aria-label":e,children:a("span",{"aria-hidden":"true",children:r})})})}export{m as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-avatar{--avatar-size:2.5rem;inline-size:var(--avatar-size);block-size:var(--avatar-size);background:var(--color-muted);color:var(--color-text);font-size:calc(var(--avatar-size) * .4);font-weight:var(--font-weight-semibold);-webkit-user-select:none;user-select:none;border-radius:50%;flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex;overflow:clip}.abaabil-avatar__image{object-fit:cover;object-position:center 30%;block-size:100%;inline-size:100%}.abaabil-avatar__initials{letter-spacing:.02em;text-indent:.02em}}
@@ -0,0 +1 @@
1
+ import{jsx as l}from"react/jsx-runtime";function o({src:t,name:a,alt:n="",className:e,children:r,...i}){const c=e?`abaabil-avatar ${e}`:"abaabil-avatar";return l("span",{className:c,...i,children:t?l("img",{src:t,alt:n,className:"abaabil-avatar__image"}):l("span",{className:"abaabil-avatar__initials",children:r??s(a)})})}function s(t){if(!t)return"";const a=String(t).trim().split(/\s+/).filter(Boolean);if(!a.length)return"";const n=e=>{if(typeof Intl<"u"&&Intl.Segmenter){const[r]=new Intl.Segmenter().segment(e);return r?r.segment:e[0]}return[...e][0]};return a.length===1?n(a[0]).toUpperCase():(n(a[0])+n(a[a.length-1])).toUpperCase()}export{o as default,s as initials};
@@ -0,0 +1 @@
1
+ import"./avatar.css";import{default as r,initials as a}from"./index.js";export{r as default,a as initials};
@@ -0,0 +1 @@
1
+ import{jsxs as r}from"react/jsx-runtime";import"./badge.css";import s from"./index.js";function t({variant:e="neutral",context:a,className:l,children:n,...i}){return r(s,{variant:e,className:l,...i,children:[n,a?r("span",{className:"abaabil-visually-hidden",children:[" ",a]}):null]})}export{t as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-badge{--badge-accent:var(--color-text-muted);align-items:center;gap:var(--space-1);padding-block:.1em;padding-inline:var(--space-2);border:1px solid color-mix(in srgb, var(--badge-accent) 35%, var(--color-surface));background:color-mix(in srgb, var(--badge-accent) 12%, var(--color-surface));color:var(--color-text);font-size:max(.75rem,.8em);font-weight:var(--font-weight-semibold);white-space:nowrap;border-radius:999px;line-height:1.4;display:inline-flex}.abaabil-badge[data-variant=info]{--badge-accent:var(--color-primary)}.abaabil-badge[data-variant=success]{--badge-accent:var(--color-success)}.abaabil-badge[data-variant=warning]{--badge-accent:var(--color-warning)}.abaabil-badge[data-variant=danger]{--badge-accent:var(--color-danger)}}
@@ -0,0 +1 @@
1
+ import{jsx as i}from"react/jsx-runtime";function l({variant:e="neutral",className:a,children:n,...r}){const t=a?`abaabil-badge ${a}`:"abaabil-badge";return i("span",{className:t,"data-variant":e,...r,children:n})}export{l as default};
@@ -0,0 +1 @@
1
+ import"./badge.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1 @@
1
+ import{jsx as e}from"react/jsx-runtime";import"./breadcrumb.css";function u({items:l,label:c="Breadcrumb",linkCurrent:m=!1,className:b,...s}){const n=b?`abaabil-breadcrumb ${b}`:"abaabil-breadcrumb",t=l.length-1;return e("nav",{className:n,"aria-label":c,...s,children:e("ol",{className:"abaabil-breadcrumb__list",children:l.map((a,i)=>{const r=i===t,d=a.href&&(!r||m);return e("li",{className:"abaabil-breadcrumb__item",children:d?e("a",{href:a.href,className:"abaabil-breadcrumb__link","aria-current":r?"page":void 0,children:a.label}):e("span",{className:"abaabil-breadcrumb__current","aria-current":r?"page":void 0,children:a.label})},a.key??i)})})})}export{u as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-breadcrumb__list{align-items:center;gap:var(--space-2);font-size:var(--font-size-sm);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}.abaabil-breadcrumb__item{align-items:center;gap:var(--space-2);color:var(--color-text-muted);display:flex}.abaabil-breadcrumb__item+.abaabil-breadcrumb__item:before{content:"";opacity:.6;border-block-start:1.5px solid;border-inline-end:1.5px solid;flex:none;block-size:.35rem;inline-size:.35rem;rotate:45deg}.abaabil-breadcrumb__list:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)) .abaabil-breadcrumb__item+.abaabil-breadcrumb__item:before{rotate:-135deg}.abaabil-breadcrumb__link{color:var(--color-text-muted);text-underline-offset:.2em;border-radius:var(--radius-md);text-decoration:underline}.abaabil-breadcrumb__link:hover{color:var(--color-text)}.abaabil-breadcrumb__link:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-breadcrumb__current{color:var(--color-text);font-weight:var(--font-weight-semibold)}}
@@ -0,0 +1 @@
1
+ import{jsx as e}from"react/jsx-runtime";function s({items:b,className:r,...l}){const c=r?`abaabil-breadcrumb ${r}`:"abaabil-breadcrumb";return e("nav",{className:c,...l,children:e("ol",{className:"abaabil-breadcrumb__list",children:b.map((a,i)=>e("li",{className:"abaabil-breadcrumb__item",children:a.href?e("a",{href:a.href,className:"abaabil-breadcrumb__link",children:a.label}):e("span",{className:"abaabil-breadcrumb__current",children:a.label})},a.key??i))})})}export{s as default};
@@ -0,0 +1 @@
1
+ import"./breadcrumb.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsxs as m,jsx as i}from"react/jsx-runtime";import{useId as h}from"react";import"./file.css";import v from"./index.js";function y({label:r,hideLabel:t=!1,description:e,error:a,required:b=!1,id:c,"aria-describedby":p,...l}){const o=h(),s=c??`${o}-file`,n=`${o}-description`,d=`${o}-error`,f=!!(r||l["aria-label"]||l["aria-labelledby"]);typeof process<"u"&&process.env.NODE_ENV!=="production"&&!f&&console.warn("abaabil/file: no `label` given, so the file input has no accessible name. Pass `label`, `aria-label`, or `aria-labelledby`."),typeof process<"u"&&process.env.NODE_ENV!=="production"&&l.accept&&!e&&console.warn("abaabil/file: `accept` filters the file dialog but is never announced, and it does not apply to files dropped onto the control. Pass a `description` saying what is accepted.");const u=[p,e?n:null,a?d:null].filter(Boolean).join(" ")||void 0;return m("div",{className:"abaabil-file-group",children:[r?i("label",{htmlFor:s,className:t?"abaabil-file__label abaabil-visually-hidden":"abaabil-file__label",children:r}):null,i(v,{...l,id:s,required:b,"aria-invalid":a?!0:void 0,"aria-describedby":u}),e?i("div",{id:n,className:"abaabil-file__description",children:e}):null,a?i("div",{id:d,className:"abaabil-file__error",role:"alert",children:a}):null]})}export{y as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-file{--file-border:var(--color-border);inline-size:100%;padding:var(--space-2);border:1px solid var(--file-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);cursor:pointer;display:block}.abaabil-file::file-selector-button{padding-block:var(--space-1);padding-inline:var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-muted);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);cursor:pointer;transition:background-color var(--duration-fast) ease;margin-inline-end:var(--space-3)}.abaabil-file::file-selector-button:hover{background:var(--color-border)}.abaabil-file:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-file:disabled{opacity:.5;cursor:not-allowed}.abaabil-file:disabled::file-selector-button{opacity:.5;cursor:not-allowed}.abaabil-file[aria-invalid=true]{--file-border:var(--color-danger)}.abaabil-file-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-file__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-file__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}.abaabil-file__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-file::file-selector-button{transition:none}}}
@@ -0,0 +1 @@
1
+ import{jsx as t}from"react/jsx-runtime";function l({className:a,...e}){const i=a?`abaabil-file ${a}`:"abaabil-file";return t("input",{type:"file",className:i,...e})}export{l as default};
@@ -0,0 +1 @@
1
+ import"./file.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsxs as P,Fragment as T,jsx as c}from"react/jsx-runtime";import{useRef as u,useState as D,useEffect as $}from"react";import"./menu.css";import{anchorNameFor as x}from"./index.js";function q({id:l,trigger:F,items:i,label:N,triggerProps:C,className:d,...E}){const f=u(null),h=u(null),m=u([]),[L,K]=D(!1),[S,_]=D(0),g=u(0),b=e=>{g.current=e,_(e)},v=u({buffer:"",at:0}),A=d?`abaabil-menu ${d}`:"abaabil-menu",t=i.map((e,r)=>e.disabled?null:r).filter(e=>e!==null);$(()=>{const e=f.current;if(!e)return;function r(a){const n=a.newState==="open";if(K(n),n){const s=t[0]??0;b(s),m.current[s]?.focus()}else v.current={buffer:"",at:0}}return e.addEventListener("toggle",r),()=>e.removeEventListener("toggle",r)},[]);function p({restoreFocus:e=!0}={}){f.current?.hidePopover(),e&&h.current?.focus()}function o(e){b(e),m.current[e]?.focus()}function y(e,r){if(!t.length)return e;const a=(t.indexOf(e)+r+t.length)%t.length;return t[a]}function O(e){const r=g.current;switch(e.key){case"ArrowDown":e.preventDefault(),o(y(r,1));return;case"ArrowUp":e.preventDefault(),o(y(r,-1));return;case"Home":e.preventDefault(),o(t[0]??0);return;case"End":e.preventDefault(),o(t[t.length-1]??0);return;case"Tab":p({restoreFocus:!1});return}if(e.key.length!==1||e.metaKey||e.ctrlKey||e.altKey)return;const a=Date.now(),n=v.current;n.buffer=a-n.at>500?e.key:n.buffer+e.key,n.at=a;const s=n.buffer.toLowerCase(),w=t.indexOf(r)+1,k=[...t.slice(w),...t.slice(0,w)].find(j=>String(i[j].label).toLowerCase().startsWith(s));k!==void 0&&(e.preventDefault(),o(k))}return P(T,{children:[c("button",{type:"button",ref:h,popoverTarget:l,"aria-haspopup":"menu","aria-expanded":L,className:"abaabil-menu__trigger",style:{anchorName:x(l)},...C,children:F}),c("div",{id:l,popover:"auto",ref:f,role:"menu","aria-label":N,className:A,style:{positionAnchor:x(l)},onKeyDown:O,...E,children:i.map((e,r)=>{const a={role:"menuitem",className:"abaabil-menu__item",tabIndex:r===S?0:-1,ref:n=>{m.current[r]=n},onFocus:()=>b(r)};return e.href?c("a",{href:e.href,...a,onClick:()=>p({restoreFocus:!1}),children:e.label},e.key??r):c("button",{type:"button",disabled:e.disabled,...a,onClick:()=>{e.onSelect?.(),p()},children:e.label},e.key??r)})})]})}export{q as default};
@@ -0,0 +1 @@
1
+ import{jsxs as b,Fragment as d,jsx as n}from"react/jsx-runtime";function o(e){return`--abaabil-menu-${String(e).replace(/[^\w-]/g,"-")}`}function p({id:e,trigger:r,items:l,triggerProps:s,className:a,...t}){const i=a?`abaabil-menu ${a}`:"abaabil-menu";return b(d,{children:[n("button",{type:"button",popoverTarget:e,className:"abaabil-menu__trigger",style:{anchorName:o(e)},...s,children:r}),n("div",{id:e,popover:"auto",className:i,style:{positionAnchor:o(e)},...t,children:l.map((m,u)=>n(c,{...m},m.key??u))})]})}function c({label:e,href:r,onSelect:l,disabled:s,className:a,...t}){const i=a?`abaabil-menu__item ${a}`:"abaabil-menu__item";return r?n("a",{href:r,className:i,...t,children:e}):n("button",{type:"button",className:i,onClick:l,disabled:s,...t,children:e})}export{c as MenuItem,o as anchorNameFor,p as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-menu{inline-size:max-content;min-inline-size:10rem;max-inline-size:min(18rem,100vw - 2rem);padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text)}.abaabil-menu::backdrop{background:0 0}.abaabil-menu__trigger{font:inherit;color:inherit}.abaabil-menu__item{appearance:none;inline-size:100%;padding-block:var(--space-2);padding-inline:var(--space-3);border-radius:var(--radius-md);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);text-align:start;white-space:nowrap;cursor:pointer;background:0 0;border:0;text-decoration:none;display:block}.abaabil-menu__item:hover{background:var(--color-muted)}.abaabil-menu__item:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px;background:var(--color-muted)}.abaabil-menu__item:disabled{opacity:.5;cursor:not-allowed}.abaabil-menu__item:disabled:hover{background:0 0}@supports (anchor-name:--x){.abaabil-menu{position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end, block-end span-inline-start;margin:0;margin-block-start:var(--space-1);position:fixed;inset:auto}}@starting-style{.abaabil-menu:popover-open{opacity:0}}.abaabil-menu:popover-open{opacity:1;transition:opacity var(--duration-fast) ease}@media (prefers-reduced-motion:reduce){.abaabil-menu:popover-open{transition:none}@starting-style{.abaabil-menu:popover-open{opacity:1}}}}
@@ -0,0 +1 @@
1
+ import"./menu.css";import{MenuItem as m,anchorNameFor as t,default as a}from"./index.js";export{m as MenuItem,t as anchorNameFor,a as default};
@@ -0,0 +1 @@
1
+ import{jsx as a,jsxs as b}from"react/jsx-runtime";import"./pagination.css";import{pageWindow as u,GAP as v}from"./index.js";function x({page:i,pageCount:t,href:n,siblings:r=1,label:o="Pagination",pageLabel:l=s=>`Page ${s}`,previousLabel:_="Previous page",nextLabel:c="Next page",className:p,...g}){const s=p?`abaabil-pagination ${p}`:"abaabil-pagination",m=u(i,t,r),d=i>1,h=i<t;return a("nav",{className:s,"aria-label":o,...g,children:b("ol",{className:"abaabil-pagination__list",children:[a("li",{className:"abaabil-pagination__item",children:d?a("a",{href:n(i-1),className:"abaabil-pagination__step abaabil-pagination__step--prev","aria-label":`${_}, ${l(i-1)}`,children:"Previous"}):a("span",{className:"abaabil-pagination__step abaabil-pagination__step--prev abaabil-pagination__step--unavailable",children:"Previous"})}),m.map((e,N)=>e===v?a("li",{className:"abaabil-pagination__item",children:a("span",{className:"abaabil-pagination__gap"})},`gap-${N}`):a("li",{className:"abaabil-pagination__item",children:e===i?b("span",{className:"abaabil-pagination__current","aria-current":"page",children:[a("span",{"aria-hidden":"true",children:e}),a("span",{className:"abaabil-visually-hidden",children:l(e)})]}):a("a",{href:n(e),className:"abaabil-pagination__link","aria-label":l(e),children:e})},e)),a("li",{className:"abaabil-pagination__item",children:h?a("a",{href:n(i+1),className:"abaabil-pagination__step abaabil-pagination__step--next","aria-label":`${c}, ${l(i+1)}`,children:"Next"}):a("span",{className:"abaabil-pagination__step abaabil-pagination__step--next abaabil-pagination__step--unavailable",children:"Next"})})]})})}export{x as default};
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as _}from"react/jsx-runtime";function m({page:a,pageCount:n,href:l,siblings:p=1,className:t,...i}){const s=t?`abaabil-pagination ${t}`:"abaabil-pagination",r=g(a,n,p);return e("nav",{className:s,...i,children:_("ol",{className:"abaabil-pagination__list",children:[e("li",{className:"abaabil-pagination__item",children:e(h,{to:a-1,page:a,pageCount:n,href:l,kind:"prev",children:"Previous"})}),r.map((o,b)=>o===c?e("li",{className:"abaabil-pagination__item",children:e("span",{className:"abaabil-pagination__gap"})},`gap-${b}`):e("li",{className:"abaabil-pagination__item",children:o===a?e("span",{className:"abaabil-pagination__current",children:o}):e("a",{href:l(o),className:"abaabil-pagination__link",children:o})},o)),e("li",{className:"abaabil-pagination__item",children:e(h,{to:a+1,page:a,pageCount:n,href:l,kind:"next",children:"Next"})})]})})}function h({to:a,page:n,pageCount:l,href:p,kind:t,children:i}){const s=a>=1&&a<=l,r=`abaabil-pagination__step abaabil-pagination__step--${t}`;return s?e("a",{href:p(a),className:r,children:i}):e("span",{className:`${r} abaabil-pagination__step--unavailable`,children:i})}const c="gap";function g(a,n,l=1){if(n<=l*2+5)return Array.from({length:n},(s,r)=>r+1);const p=Math.max(2,a-l),t=Math.min(n-1,a+l),i=[1];p>3?i.push(c):p===3&&i.push(2);for(let s=p;s<=t;s++)i.push(s);return t<n-2?i.push(c):t===n-2&&i.push(n-1),i.push(n),i}export{c as GAP,m as default,g as pageWindow};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-pagination__list{align-items:center;gap:var(--space-1);font-size:var(--font-size-sm);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}.abaabil-pagination__link,.abaabil-pagination__current,.abaabil-pagination__step{min-inline-size:var(--control-height-md);block-size:var(--control-height-md);padding-inline:var(--space-2);border-radius:var(--radius-md);color:var(--color-text);font-variant-numeric:tabular-nums;border:1px solid #0000;justify-content:center;align-items:center;text-decoration:none;display:inline-flex}.abaabil-pagination__link:hover{background:var(--color-muted)}.abaabil-pagination__link:focus-visible,.abaabil-pagination__step:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-pagination__current{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg);font-weight:var(--font-weight-semibold)}.abaabil-pagination__gap:before{content:"…"}.abaabil-pagination__gap{min-inline-size:var(--control-height-md);block-size:var(--control-height-md);color:var(--color-text-muted);justify-content:center;align-items:center;display:inline-flex}.abaabil-pagination__step{border-color:var(--color-border)}.abaabil-pagination__step:hover{background:var(--color-muted)}.abaabil-pagination__step--unavailable{color:var(--color-text-muted);opacity:.6;border-color:#0000}}
@@ -0,0 +1 @@
1
+ import"./pagination.css";import{GAP as r,default as t,pageWindow as a}from"./index.js";export{r as GAP,t as default,a as pageWindow};
@@ -1 +1 @@
1
- import{jsx as t}from"react/jsx-runtime";import"./popover.css";import{Popover as d}from"./index.js";import{PopoverPanel as v,PopoverTrigger as P}from"./index.js";function b({id:a,trigger:l,label:r,labelledBy:o,triggerProps:n,mode:i="auto",children:p,...e}){const s=!!(r||o||e["aria-label"]||e["aria-labelledby"]);return typeof process<"u"&&process.env.NODE_ENV!=="production"&&!s&&console.warn("abaabil/popover: no `label` or `labelledBy` given, so the panel has no accessible name and screen readers announce it as an unnamed group."),t(d,{id:a,trigger:l,triggerProps:n,mode:i,"aria-label":r,"aria-labelledby":o,...e,children:p})}export{v as PopoverPanel,P as PopoverTrigger,b as default};
1
+ import{jsx as d}from"react/jsx-runtime";import"./popover.css";import{Popover as g}from"./index.js";import{PopoverPanel as P,PopoverTrigger as y}from"./index.js";function b({id:a,trigger:l,label:r,labelledBy:o,role:n="group",triggerProps:i,mode:p="auto",children:t,...e}){const s=!!(r||o||e["aria-label"]||e["aria-labelledby"]);return typeof process<"u"&&process.env.NODE_ENV!=="production"&&!s&&console.warn("abaabil/popover: no `label` or `labelledBy` given, so the panel has no accessible name and screen readers announce it as an unnamed group."),d(g,{id:a,trigger:l,triggerProps:i,mode:p,role:n,"aria-label":r,"aria-labelledby":o,...e,children:t})}export{P as PopoverPanel,y as PopoverTrigger,b as default};
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsxs as g,jsx as i}from"react/jsx-runtime";import{useId as f}from"react";import"./progress.css";import h from"./index.js";function x({label:a,hideLabel:d=!1,description:l,valueText:n,value:t,max:c=100,id:p,"aria-describedby":u,...e}){const r=f(),s=p??`${r}-progress`,o=`${r}-description`,b=`${r}-label`,m=!!(a||e["aria-label"]||e["aria-labelledby"]);typeof process<"u"&&process.env.NODE_ENV!=="production"&&!m&&console.warn("abaabil/progress: no `label` given, so the progress bar has no accessible name. Pass `label`, `aria-label`, or `aria-labelledby`.");const v=[u,l?o:null].filter(Boolean).join(" ")||void 0;return g("div",{className:"abaabil-progress-group",children:[a?i("label",{id:b,htmlFor:s,className:d?"abaabil-progress__label abaabil-visually-hidden":"abaabil-progress__label",children:a}):null,i(h,{...e,id:s,value:t,max:c,"aria-valuetext":n,"aria-labelledby":a?b:void 0,"aria-describedby":v}),l?i("div",{id:o,className:"abaabil-progress__description",children:l}):null]})}export{x as default};
@@ -0,0 +1 @@
1
+ import{jsx as o}from"react/jsx-runtime";function m({value:s,max:e=100,className:a,...r}){const l=a?`abaabil-progress ${a}`:"abaabil-progress";return o("progress",{className:l,value:s,max:e,...r})}export{m as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-progress{appearance:none;background:var(--color-muted);block-size:.5rem;inline-size:100%;color:var(--color-primary);border:0;border-radius:999px;display:block;overflow:hidden}.abaabil-progress::-webkit-progress-bar{background:var(--color-muted);border-radius:999px}.abaabil-progress::-webkit-progress-value{background:var(--color-primary);transition:inline-size var(--duration-fast) ease;border-radius:999px}.abaabil-progress::-moz-progress-bar{background:var(--color-primary);border-radius:999px}.abaabil-progress:indeterminate{background:linear-gradient(90deg, var(--color-primary) 0 35%, transparent 35% 100%) 0 0 / 250% 100% no-repeat var(--color-muted);animation:1.4s linear infinite abaabil-progress-slide}.abaabil-progress:indeterminate::-webkit-progress-bar{background:0 0}.abaabil-progress:indeterminate::-moz-progress-bar{background:0 0}@keyframes abaabil-progress-slide{0%{background-position:-60% 0}to{background-position:160% 0}}.abaabil-progress-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-progress__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-progress__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}@media (prefers-reduced-motion:reduce){.abaabil-progress::-webkit-progress-value{transition:none}.abaabil-progress:indeterminate{background-position:40% 0;animation:none}}}
@@ -0,0 +1 @@
1
+ import"./progress.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsxs as N,jsx as e}from"react/jsx-runtime";import{useId as E,useState as F}from"react";import"./slider.css";import S from"./index.js";function B({label:l,hideLabel:v=!1,description:i,showValue:_=!1,formatValue:n,min:r=0,max:s=100,value:o,defaultValue:x,onChange:y,id:g,"aria-describedby":V,...d}){const u=E(),b=g??`${u}-slider`,m=`${u}-description`,t=o!==void 0,c=a=>Math.min(Math.max(Number(a),Number(r)),Number(s)),[h,M]=F(()=>c(x??Math.floor((Number(r)+Number(s))/2))),f=t?c(o):h,j=!!(l||d["aria-label"]||d["aria-labelledby"]);typeof process<"u"&&process.env.NODE_ENV!=="production"&&!j&&console.warn("abaabil/slider: no `label` given, so the slider has no accessible name. Pass `label`, `aria-label`, or `aria-labelledby`.");const w=[V,i?m:null].filter(Boolean).join(" ")||void 0,p=n?n(Number(f)):void 0;function C(a){t||M(a.target.value),y?.(a)}return N("div",{className:"abaabil-slider-group",children:[N("div",{className:"abaabil-slider__header",children:[l?e("label",{htmlFor:b,className:v?"abaabil-slider__label abaabil-visually-hidden":"abaabil-slider__label",children:l}):null,_?e("output",{htmlFor:b,className:"abaabil-slider__output","aria-hidden":"true",children:p??f}):null]}),e(S,{...d,id:b,min:r,max:s,...t?{value:o}:{defaultValue:h},onChange:C,"aria-valuetext":p,"aria-describedby":w}),i?e("div",{id:m,className:"abaabil-slider__description",children:i}):null]})}export{B as default};
@@ -0,0 +1 @@
1
+ import{jsx as m}from"react/jsx-runtime";function n({min:e=0,max:s=100,step:t=1,className:a,...i}){const r=a?`abaabil-slider ${a}`:"abaabil-slider";return m("input",{type:"range",className:r,min:e,max:s,step:t,...i})}export{n as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-slider{--slider-track:.3rem;--slider-thumb:1.1rem;appearance:none;inline-size:100%;block-size:var(--slider-thumb);cursor:pointer;background:0 0;margin:0}.abaabil-slider::-webkit-slider-runnable-track{block-size:var(--slider-track);background:var(--color-muted);border-radius:999px}.abaabil-slider::-moz-range-track{block-size:var(--slider-track);background:var(--color-muted);border-radius:999px}.abaabil-slider::-webkit-slider-thumb{appearance:none;inline-size:var(--slider-thumb);block-size:var(--slider-thumb);border:2px solid var(--color-surface);background:var(--color-primary);border-radius:50%;margin-block-start:calc((var(--slider-track) - var(--slider-thumb)) / 2)}.abaabil-slider::-moz-range-thumb{inline-size:var(--slider-thumb);block-size:var(--slider-thumb);border:2px solid var(--color-surface);background:var(--color-primary);border-radius:50%}.abaabil-slider::-moz-range-progress{block-size:var(--slider-track);background:var(--color-primary);border-radius:999px}.abaabil-slider:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:4px;border-radius:999px}.abaabil-slider:disabled{opacity:.5;cursor:not-allowed}.abaabil-slider-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-slider__header{justify-content:space-between;align-items:baseline;gap:var(--space-2);display:flex}.abaabil-slider__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-slider__output{font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums;color:var(--color-text)}.abaabil-slider__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}}
@@ -0,0 +1 @@
1
+ import"./slider.css";import{default as e}from"./index.js";export{e as default};
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- @layer abaabil.reset;@layer abaabil.tokens{:root{--abaabil-blue-500:#2563eb;--abaabil-blue-400:#3b82f6;--abaabil-gray-900:#111827;--abaabil-gray-300:#d1d5db;--abaabil-gray-100:#f3f4f6;--abaabil-white:#fff;--abaabil-red-600:#dc2626;--abaabil-green-600:#16a34a;--abaabil-amber-600:#b45309;--color-primary:var(--abaabil-blue-500);--color-primary-hover:var(--abaabil-blue-400);--color-primary-fg:var(--abaabil-white);--color-surface:var(--abaabil-white);--color-text:var(--abaabil-gray-900);--color-border:var(--abaabil-gray-300);--color-muted:var(--abaabil-gray-100);--color-danger:var(--abaabil-red-600);--color-success:var(--abaabil-green-600);--color-warning:var(--abaabil-amber-600);--color-focus-ring:var(--abaabil-blue-500);--color-overlay:#00000080;--color-text-muted:#6b7280;--color-placeholder:#9ca3af;--radius-md:.375rem;--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--font-size-sm:.875rem;--font-size-lg:1.125rem;--font-weight-semibold:600;--control-height-md:2.5rem;--duration-fast:.15s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}:root[data-theme=dark]{--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}@layer abaabil.base{.abaabil-visually-hidden{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}@layer abaabil.components{.abaabil-accordion-group{border:1px solid var(--color-border);border-radius:var(--radius-md);overflow:clip}.abaabil-accordion-group .abaabil-accordion+.abaabil-accordion{border-top:1px solid var(--color-border)}.abaabil-accordion{color:var(--color-text)}.abaabil-accordion__summary{list-style:none}.abaabil-accordion__summary::-webkit-details-marker{display:none}.abaabil-accordion__summary{justify-content:space-between;align-items:center;gap:var(--space-2);min-height:var(--control-height-md);padding:var(--space-3) var(--space-4);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);cursor:pointer;-webkit-user-select:none;user-select:none;line-height:1.3;display:flex}.abaabil-accordion__summary:hover{background:var(--color-muted)}.abaabil-accordion__summary:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px}.abaabil-accordion__summary:after{content:"";block-size:.5rem;inline-size:.5rem;transition:transform var(--duration-fast) ease;border-bottom:2px solid;border-right:2px solid;flex:none;transform:rotate(45deg)}.abaabil-accordion[open]>.abaabil-accordion__summary:after{transform:rotate(-135deg)}.abaabil-accordion__panel{padding:0 var(--space-4) var(--space-3)}@media (prefers-reduced-motion:reduce){.abaabil-accordion__summary:after{transition:none}}.abaabil-alert{--alert-accent:var(--color-primary);gap:var(--space-1);padding-block:var(--space-2);padding-inline:var(--space-3);border:1px solid color-mix(in srgb, var(--alert-accent) 35%, var(--color-surface));border-inline-start:3px solid var(--alert-accent);border-radius:var(--radius-md);background:color-mix(in srgb, var(--alert-accent) 8%, var(--color-surface));color:var(--color-text);font-size:var(--font-size-sm);flex-direction:column;line-height:1.5;display:flex}.abaabil-alert[data-variant=success]{--alert-accent:var(--color-success)}.abaabil-alert[data-variant=warning]{--alert-accent:var(--color-warning)}.abaabil-alert[data-variant=danger]{--alert-accent:var(--color-danger)}.abaabil-alert__title{font-weight:var(--font-weight-semibold);color:var(--color-text)}.abaabil-alert:empty{display:none}.abaabil-button{--btn-bg:var(--color-primary);--btn-fg:var(--color-primary-fg);--btn-border:var(--color-primary);--btn-height:var(--control-height-md);--btn-padding-x:max(.375rem, calc((var(--btn-height) - var(--font-size-sm)) / 2));--btn-radius:var(--radius-md);justify-content:center;align-items:center;gap:var(--space-2);height:var(--btn-height);padding-inline:var(--btn-padding-x);border:1px solid var(--btn-border);border-radius:var(--btn-radius);background:var(--btn-bg);color:var(--btn-fg);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);white-space:nowrap;cursor:pointer;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;line-height:1;text-decoration:none;display:inline-flex}.abaabil-button:hover{--btn-bg:var(--color-primary-hover);--btn-border:var(--color-primary-hover)}.abaabil-button:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-button[data-variant=secondary]{--btn-bg:transparent;--btn-fg:var(--color-text);--btn-border:var(--color-border)}.abaabil-button[data-variant=ghost]{--btn-bg:transparent;--btn-fg:var(--color-text);--btn-border:transparent}.abaabil-button[data-size=sm]{--btn-height:2rem}.abaabil-button[data-size=lg]{--btn-height:3rem}.abaabil-button:disabled,.abaabil-button[aria-disabled=true]{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.abaabil-button{transition:none}}.abaabil-checkbox{--checkbox-radius:min(var(--radius-md), .25rem);appearance:none;border:1px solid var(--color-border);border-radius:var(--checkbox-radius);background:var(--color-surface);cursor:pointer;width:1.125rem;height:1.125rem;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;flex-shrink:0;place-content:center;margin:0;display:inline-grid}.abaabil-checkbox:before{content:"";background:var(--color-primary-fg);clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0%,43% 62%);width:.65rem;height:.65rem;transition:transform var(--duration-fast) ease;transform:scale(0)}.abaabil-checkbox:checked,.abaabil-checkbox:indeterminate{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-checkbox:checked:before,.abaabil-checkbox:indeterminate:before{transform:scale(1)}.abaabil-checkbox:indeterminate:before{clip-path:none;border-radius:1px;width:.65rem;height:.125rem}.abaabil-checkbox:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-checkbox:disabled{opacity:.5;cursor:not-allowed}.abaabil-checkbox__wrapper{align-items:flex-start;gap:var(--space-2);display:inline-flex}.abaabil-checkbox__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-checkbox__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;display:block}.abaabil-checkbox-group{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-3)}.abaabil-checkbox-group__legend{padding-inline:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text)}@media (prefers-reduced-motion:reduce){.abaabil-checkbox,.abaabil-checkbox:before{transition:none}}.abaabil-combobox{display:inline-block;position:relative}.abaabil-combobox__label{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.abaabil-combobox__label--visible{margin-bottom:var(--space-1);font-size:var(--font-size-sm);color:var(--color-text);display:block}.abaabil-combobox__input{height:var(--control-height-md);--input-padding-x:max(.375rem, calc((var(--control-height-md) - var(--font-size-sm)) / 2));padding-inline:var(--input-padding-x);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm);width:100%}.abaabil-combobox__input:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-combobox__list{z-index:10;width:100%;max-height:15rem;padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);margin:0;list-style:none;position:absolute;inset-block-start:calc(100% + var(--space-1));inset-inline-start:0;overflow-y:auto}.abaabil-combobox__option{padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-combobox__option:hover,.abaabil-combobox__option[data-active=true]{background:var(--color-muted)}@supports (anchor-name:--x){.abaabil-combobox__input{anchor-name:--abaabil-combobox-input}.abaabil-combobox__list{position-anchor:--abaabil-combobox-input;position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end;width:anchor-size(width);position:fixed;inset:auto}}.abaabil-dialog{--dialog-width:32rem;--dialog-padding:var(--space-4);width:min(var(--dialog-width), calc(100vw - 2rem));padding:var(--dialog-padding);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text)}.abaabil-dialog::backdrop{background:var(--color-overlay)}.abaabil-dialog__title{margin:0 0 var(--space-3);font-size:var(--font-size-lg);font-weight:var(--font-weight-semibold)}@starting-style{.abaabil-dialog[open]{opacity:0;transform:translateY(.5rem)}}.abaabil-dialog[open]{opacity:1;transition:opacity var(--duration-fast) ease, transform var(--duration-fast) ease;transform:none}@media (prefers-reduced-motion:reduce){.abaabil-dialog[open]{transition:none}@starting-style{.abaabil-dialog[open]{opacity:1;transform:none}}}.abaabil-input{--input-height:var(--control-height-md);--input-padding-x:max(.375rem, calc((var(--input-height) - var(--font-size-sm)) / 2));--input-border:var(--color-border);--input-placeholder-fg:var(--color-placeholder);width:100%;height:var(--input-height);padding-inline:var(--input-padding-x);border:1px solid var(--input-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm);transition:border-color var(--duration-fast) ease;display:block}.abaabil-input::placeholder{color:var(--input-placeholder-fg)}.abaabil-input:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-input:disabled{opacity:.5;cursor:not-allowed}.abaabil-input[aria-invalid=true]{--input-border:var(--color-danger)}.abaabil-input-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-input__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-input__description{--input-description-fg:var(--color-text-muted);font-size:var(--font-size-sm);color:var(--input-description-fg)}.abaabil-input__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-input{transition:none}}.abaabil-popover{inline-size:max-content;max-inline-size:min(22rem,100vw - 2rem);padding:var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm)}.abaabil-popover:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-popover::backdrop{background:0 0}.abaabil-popover__trigger{font:inherit;color:inherit}@supports (anchor-name:--x){.abaabil-popover{position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end, block-end span-inline-start;margin:0;margin-block-start:var(--space-1);position:fixed;inset:auto}}@starting-style{.abaabil-popover:popover-open{opacity:0}}.abaabil-popover:popover-open{opacity:1;transition:opacity var(--duration-fast) ease}@media (prefers-reduced-motion:reduce){.abaabil-popover:popover-open{transition:none}@starting-style{.abaabil-popover:popover-open{opacity:1}}}.abaabil-radio{appearance:none;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;width:1.125rem;height:1.125rem;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;border-radius:50%;flex-shrink:0;place-content:center;margin:0;display:inline-grid}.abaabil-radio:before{content:"";background:var(--color-primary-fg);width:.5rem;height:.5rem;transition:transform var(--duration-fast) ease;border-radius:50%;transform:scale(0)}.abaabil-radio:checked{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-radio:checked:before{transform:scale(1)}.abaabil-radio:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-radio:disabled{opacity:.5;cursor:not-allowed}.abaabil-radio__wrapper{align-items:flex-start;gap:var(--space-2);display:inline-flex}.abaabil-radio__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-radio__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;display:block}.abaabil-radio-group{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-3)}.abaabil-radio-group__legend{padding-inline:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text)}@media (prefers-reduced-motion:reduce){.abaabil-radio,.abaabil-radio:before{transition:none}}.abaabil-select{--select-height:var(--control-height-md);--select-padding-x:max(.375rem, calc((var(--select-height) - var(--font-size-sm)) / 2));appearance:none;height:var(--select-height);padding-inline:var(--select-padding-x);border:1px solid var(--color-border);border-radius:var(--radius-md);background-color:var(--color-surface);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--select-padding-x) center;color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;transition:border-color var(--duration-fast) ease;background-size:.75rem .75rem;padding-inline-end:calc(var(--select-padding-x) + 1.125rem);line-height:1}.abaabil-select:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){background-position:left var(--select-padding-x) center;padding-inline-start:calc(var(--select-padding-x) + 1.125rem);padding-inline-end:var(--select-padding-x)}.abaabil-select:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-select:disabled{opacity:.5;cursor:not-allowed}.abaabil-select-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-select__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-select__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;margin:0}.abaabil-select__error{font-size:var(--font-size-sm);color:var(--color-danger);margin:0}.abaabil-select[aria-invalid=true]{border-color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-select{transition:none}}.abaabil-switch{--switch-width:2.25rem;--switch-height:1.25rem;--switch-gap:2px;--switch-thumb:calc(var(--switch-height) - (var(--switch-gap) * 2));appearance:none;inline-size:var(--switch-width);block-size:var(--switch-height);border:1px solid var(--color-border);background:var(--color-muted);cursor:pointer;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;border-radius:999px;flex-shrink:0;margin:0;position:relative}.abaabil-switch:before{content:"";inline-size:var(--switch-thumb);block-size:var(--switch-thumb);background:var(--color-surface);transition:inset-inline-start var(--duration-fast) ease;border-radius:50%;position:absolute;inset-block-start:50%;inset-inline-start:var(--switch-gap);translate:0 -50%}.abaabil-switch:checked{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-switch:checked:before{inset-inline-start:calc(100% - var(--switch-thumb) - var(--switch-gap))}.abaabil-switch:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-switch:disabled{opacity:.5;cursor:not-allowed}.abaabil-switch__wrapper{align-items:center;gap:var(--space-2);flex-wrap:wrap;display:inline-flex}.abaabil-switch__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-switch__description{font-size:var(--font-size-sm);color:var(--color-text-muted);flex-basis:100%;display:block}@media (prefers-reduced-motion:reduce){.abaabil-switch,.abaabil-switch:before{transition:none}}.abaabil-tabs{gap:var(--space-3);flex-direction:column;display:flex}.abaabil-tabs__list{gap:var(--space-1);border-block-end:1px solid var(--color-border);display:flex}.abaabil-tabs__tab{appearance:none;padding-block:var(--space-2);padding-inline:var(--space-3);border:0;color:var(--color-text-muted);font:inherit;font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);white-space:nowrap;cursor:pointer;transition:color var(--duration-fast) ease, border-color var(--duration-fast) ease;background:0 0;border-block-end:2px solid #0000;margin-block-end:-1px;line-height:1.3}.abaabil-tabs__tab:hover{color:var(--color-text)}.abaabil-tabs__tab[data-selected=true]{color:var(--color-text);border-block-end-color:var(--color-primary)}.abaabil-tabs__tab:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px}.abaabil-tabs__tab:disabled{opacity:.5;cursor:not-allowed}.abaabil-tabs__list[data-orientation=vertical]{border-block-end:0;border-inline-end:1px solid var(--color-border);flex-direction:column}.abaabil-tabs__list[data-orientation=vertical] .abaabil-tabs__tab{text-align:start;border-block-end:0;border-inline-end:2px solid #0000;margin-block-end:0;margin-inline-end:-1px}.abaabil-tabs__list[data-orientation=vertical] .abaabil-tabs__tab[data-selected=true]{border-inline-end-color:var(--color-primary)}.abaabil-tabs__panel:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}@media (prefers-reduced-motion:reduce){.abaabil-tabs__tab{transition:none}}.abaabil-textarea{--textarea-padding-block:var(--space-2);--textarea-padding-x:var(--space-3);--textarea-border:var(--color-border);--textarea-placeholder-fg:var(--color-placeholder);width:100%;padding-block:var(--textarea-padding-block);padding-inline:var(--textarea-padding-x);border:1px solid var(--textarea-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);resize:block;transition:border-color var(--duration-fast) ease;line-height:1.5;display:block}.abaabil-textarea::placeholder{color:var(--textarea-placeholder-fg)}.abaabil-textarea:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-textarea:disabled{opacity:.5;cursor:not-allowed;resize:none}.abaabil-textarea[aria-invalid=true]{--textarea-border:var(--color-danger)}.abaabil-textarea-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-textarea__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-textarea__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}.abaabil-textarea__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-textarea{transition:none}}}
1
+ @layer abaabil.reset;@layer abaabil.tokens{:root{--abaabil-blue-500:#2563eb;--abaabil-gray-900:#111827;--abaabil-gray-300:#d1d5db;--abaabil-gray-100:#f3f4f6;--abaabil-white:#fff;--abaabil-red-600:#dc2626;--abaabil-green-600:#16a34a;--abaabil-amber-600:#b45309;--color-primary:var(--abaabil-blue-500);--color-primary-hover:color-mix(in srgb, var(--color-primary) 85%, white);--color-primary-fg:var(--abaabil-white);--color-surface:var(--abaabil-white);--color-text:var(--abaabil-gray-900);--color-border:var(--abaabil-gray-300);--color-muted:var(--abaabil-gray-100);--color-danger:var(--abaabil-red-600);--color-success:var(--abaabil-green-600);--color-warning:var(--abaabil-amber-600);--color-focus-ring:var(--color-primary);--color-overlay:#00000080;--color-text-muted:#6b7280;--color-placeholder:#9ca3af;--radius-md:.375rem;--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--font-size-sm:.875rem;--font-size-lg:1.125rem;--font-weight-semibold:600;--control-height-md:2.5rem;--duration-fast:.15s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}:root[data-theme=dark]{--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}@layer abaabil.base{.abaabil-visually-hidden{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}@layer abaabil.components{.abaabil-accordion-group{border:1px solid var(--color-border);border-radius:var(--radius-md);overflow:clip}.abaabil-accordion-group .abaabil-accordion+.abaabil-accordion{border-top:1px solid var(--color-border)}.abaabil-accordion{color:var(--color-text)}.abaabil-accordion__summary{list-style:none}.abaabil-accordion__summary::-webkit-details-marker{display:none}.abaabil-accordion__summary{justify-content:space-between;align-items:center;gap:var(--space-2);min-height:var(--control-height-md);padding:var(--space-3) var(--space-4);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);cursor:pointer;-webkit-user-select:none;user-select:none;line-height:1.3;display:flex}.abaabil-accordion__summary:hover{background:var(--color-muted)}.abaabil-accordion__summary:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px}.abaabil-accordion__summary:after{content:"";block-size:.5rem;inline-size:.5rem;transition:transform var(--duration-fast) ease;border-bottom:2px solid;border-right:2px solid;flex:none;transform:rotate(45deg)}.abaabil-accordion[open]>.abaabil-accordion__summary:after{transform:rotate(-135deg)}.abaabil-accordion__panel{padding:0 var(--space-4) var(--space-3)}@media (prefers-reduced-motion:reduce){.abaabil-accordion__summary:after{transition:none}}.abaabil-alert{--alert-accent:var(--color-primary);gap:var(--space-1);padding-block:var(--space-2);padding-inline:var(--space-3);border:1px solid color-mix(in srgb, var(--alert-accent) 35%, var(--color-surface));border-inline-start:3px solid var(--alert-accent);border-radius:var(--radius-md);background:color-mix(in srgb, var(--alert-accent) 8%, var(--color-surface));color:var(--color-text);font-size:var(--font-size-sm);flex-direction:column;line-height:1.5;display:flex}.abaabil-alert[data-variant=success]{--alert-accent:var(--color-success)}.abaabil-alert[data-variant=warning]{--alert-accent:var(--color-warning)}.abaabil-alert[data-variant=danger]{--alert-accent:var(--color-danger)}.abaabil-alert__title{font-weight:var(--font-weight-semibold);color:var(--color-text)}.abaabil-alert:empty{display:none}.abaabil-avatar{--avatar-size:2.5rem;inline-size:var(--avatar-size);block-size:var(--avatar-size);background:var(--color-muted);color:var(--color-text);font-size:calc(var(--avatar-size) * .4);font-weight:var(--font-weight-semibold);-webkit-user-select:none;user-select:none;border-radius:50%;flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex;overflow:clip}.abaabil-avatar__image{object-fit:cover;object-position:center 30%;block-size:100%;inline-size:100%}.abaabil-avatar__initials{letter-spacing:.02em;text-indent:.02em}.abaabil-badge{--badge-accent:var(--color-text-muted);align-items:center;gap:var(--space-1);padding-block:.1em;padding-inline:var(--space-2);border:1px solid color-mix(in srgb, var(--badge-accent) 35%, var(--color-surface));background:color-mix(in srgb, var(--badge-accent) 12%, var(--color-surface));color:var(--color-text);font-size:max(.75rem,.8em);font-weight:var(--font-weight-semibold);white-space:nowrap;border-radius:999px;line-height:1.4;display:inline-flex}.abaabil-badge[data-variant=info]{--badge-accent:var(--color-primary)}.abaabil-badge[data-variant=success]{--badge-accent:var(--color-success)}.abaabil-badge[data-variant=warning]{--badge-accent:var(--color-warning)}.abaabil-badge[data-variant=danger]{--badge-accent:var(--color-danger)}.abaabil-breadcrumb__list{align-items:center;gap:var(--space-2);font-size:var(--font-size-sm);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}.abaabil-breadcrumb__item{align-items:center;gap:var(--space-2);color:var(--color-text-muted);display:flex}.abaabil-breadcrumb__item+.abaabil-breadcrumb__item:before{content:"";opacity:.6;border-block-start:1.5px solid;border-inline-end:1.5px solid;flex:none;block-size:.35rem;inline-size:.35rem;rotate:45deg}.abaabil-breadcrumb__list:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)) .abaabil-breadcrumb__item+.abaabil-breadcrumb__item:before{rotate:-135deg}.abaabil-breadcrumb__link{color:var(--color-text-muted);text-underline-offset:.2em;border-radius:var(--radius-md);text-decoration:underline}.abaabil-breadcrumb__link:hover{color:var(--color-text)}.abaabil-breadcrumb__link:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-breadcrumb__current{color:var(--color-text);font-weight:var(--font-weight-semibold)}.abaabil-button{--btn-bg:var(--color-primary);--btn-fg:var(--color-primary-fg);--btn-border:var(--color-primary);--btn-height:var(--control-height-md);--btn-padding-x:max(.375rem, calc((var(--btn-height) - var(--font-size-sm)) / 2));--btn-radius:var(--radius-md);justify-content:center;align-items:center;gap:var(--space-2);height:var(--btn-height);padding-inline:var(--btn-padding-x);border:1px solid var(--btn-border);border-radius:var(--btn-radius);background:var(--btn-bg);color:var(--btn-fg);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);white-space:nowrap;cursor:pointer;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;line-height:1;text-decoration:none;display:inline-flex}.abaabil-button:hover{--btn-bg:var(--color-primary-hover);--btn-border:var(--color-primary-hover)}.abaabil-button:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-button[data-variant=secondary]{--btn-bg:transparent;--btn-fg:var(--color-text);--btn-border:var(--color-border)}.abaabil-button[data-variant=ghost]{--btn-bg:transparent;--btn-fg:var(--color-text);--btn-border:transparent}.abaabil-button[data-size=sm]{--btn-height:2rem}.abaabil-button[data-size=lg]{--btn-height:3rem}.abaabil-button:disabled,.abaabil-button[aria-disabled=true]{opacity:.5;cursor:not-allowed}@media (prefers-reduced-motion:reduce){.abaabil-button{transition:none}}.abaabil-checkbox{--checkbox-radius:min(var(--radius-md), .25rem);appearance:none;border:1px solid var(--color-border);border-radius:var(--checkbox-radius);background:var(--color-surface);cursor:pointer;width:1.125rem;height:1.125rem;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;flex-shrink:0;place-content:center;margin:0;display:inline-grid}.abaabil-checkbox:before{content:"";background:var(--color-primary-fg);clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0%,43% 62%);width:.65rem;height:.65rem;transition:transform var(--duration-fast) ease;transform:scale(0)}.abaabil-checkbox:checked,.abaabil-checkbox:indeterminate{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-checkbox:checked:before,.abaabil-checkbox:indeterminate:before{transform:scale(1)}.abaabil-checkbox:indeterminate:before{clip-path:none;border-radius:1px;width:.65rem;height:.125rem}.abaabil-checkbox:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-checkbox:disabled{opacity:.5;cursor:not-allowed}.abaabil-checkbox__wrapper{align-items:flex-start;gap:var(--space-2);display:inline-flex}.abaabil-checkbox__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-checkbox__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;display:block}.abaabil-checkbox-group{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-3)}.abaabil-checkbox-group__legend{padding-inline:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text)}@media (prefers-reduced-motion:reduce){.abaabil-checkbox,.abaabil-checkbox:before{transition:none}}.abaabil-combobox{display:inline-block;position:relative}.abaabil-combobox__label{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.abaabil-combobox__label--visible{margin-bottom:var(--space-1);font-size:var(--font-size-sm);color:var(--color-text);display:block}.abaabil-combobox__input{height:var(--control-height-md);--input-padding-x:max(.375rem, calc((var(--control-height-md) - var(--font-size-sm)) / 2));padding-inline:var(--input-padding-x);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm);width:100%}.abaabil-combobox__input:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-combobox__list{z-index:10;width:100%;max-height:15rem;padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);margin:0;list-style:none;position:absolute;inset-block-start:calc(100% + var(--space-1));inset-inline-start:0;overflow-y:auto}.abaabil-combobox__option{padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-combobox__option:hover,.abaabil-combobox__option[data-active=true]{background:var(--color-muted)}@supports (anchor-name:--x){.abaabil-combobox__input{anchor-name:--abaabil-combobox-input}.abaabil-combobox__list{position-anchor:--abaabil-combobox-input;position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end;width:anchor-size(width);position:fixed;inset:auto}}.abaabil-dialog{--dialog-width:32rem;--dialog-padding:var(--space-4);width:min(var(--dialog-width), calc(100vw - 2rem));padding:var(--dialog-padding);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text)}.abaabil-dialog::backdrop{background:var(--color-overlay)}.abaabil-dialog__title{margin:0 0 var(--space-3);font-size:var(--font-size-lg);font-weight:var(--font-weight-semibold)}@starting-style{.abaabil-dialog[open]{opacity:0;transform:translateY(.5rem)}}.abaabil-dialog[open]{opacity:1;transition:opacity var(--duration-fast) ease, transform var(--duration-fast) ease;transform:none}@media (prefers-reduced-motion:reduce){.abaabil-dialog[open]{transition:none}@starting-style{.abaabil-dialog[open]{opacity:1;transform:none}}}.abaabil-file{--file-border:var(--color-border);inline-size:100%;padding:var(--space-2);border:1px solid var(--file-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);cursor:pointer;display:block}.abaabil-file::file-selector-button{padding-block:var(--space-1);padding-inline:var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-muted);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);cursor:pointer;transition:background-color var(--duration-fast) ease;margin-inline-end:var(--space-3)}.abaabil-file::file-selector-button:hover{background:var(--color-border)}.abaabil-file:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-file:disabled{opacity:.5;cursor:not-allowed}.abaabil-file:disabled::file-selector-button{opacity:.5;cursor:not-allowed}.abaabil-file[aria-invalid=true]{--file-border:var(--color-danger)}.abaabil-file-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-file__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-file__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}.abaabil-file__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-file::file-selector-button{transition:none}}.abaabil-input{--input-height:var(--control-height-md);--input-padding-x:max(.375rem, calc((var(--input-height) - var(--font-size-sm)) / 2));--input-border:var(--color-border);--input-placeholder-fg:var(--color-placeholder);width:100%;height:var(--input-height);padding-inline:var(--input-padding-x);border:1px solid var(--input-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm);transition:border-color var(--duration-fast) ease;display:block}.abaabil-input::placeholder{color:var(--input-placeholder-fg)}.abaabil-input:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-input:disabled{opacity:.5;cursor:not-allowed}.abaabil-input[aria-invalid=true]{--input-border:var(--color-danger)}.abaabil-input-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-input__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-input__description{--input-description-fg:var(--color-text-muted);font-size:var(--font-size-sm);color:var(--input-description-fg)}.abaabil-input__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-input{transition:none}}.abaabil-menu{inline-size:max-content;min-inline-size:10rem;max-inline-size:min(18rem,100vw - 2rem);padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text)}.abaabil-menu::backdrop{background:0 0}.abaabil-menu__trigger{font:inherit;color:inherit}.abaabil-menu__item{appearance:none;inline-size:100%;padding-block:var(--space-2);padding-inline:var(--space-3);border-radius:var(--radius-md);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);text-align:start;white-space:nowrap;cursor:pointer;background:0 0;border:0;text-decoration:none;display:block}.abaabil-menu__item:hover{background:var(--color-muted)}.abaabil-menu__item:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px;background:var(--color-muted)}.abaabil-menu__item:disabled{opacity:.5;cursor:not-allowed}.abaabil-menu__item:disabled:hover{background:0 0}@supports (anchor-name:--x){.abaabil-menu{position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end, block-end span-inline-start;margin:0;margin-block-start:var(--space-1);position:fixed;inset:auto}}@starting-style{.abaabil-menu:popover-open{opacity:0}}.abaabil-menu:popover-open{opacity:1;transition:opacity var(--duration-fast) ease}@media (prefers-reduced-motion:reduce){.abaabil-menu:popover-open{transition:none}@starting-style{.abaabil-menu:popover-open{opacity:1}}}.abaabil-pagination__list{align-items:center;gap:var(--space-1);font-size:var(--font-size-sm);flex-wrap:wrap;margin:0;padding:0;list-style:none;display:flex}.abaabil-pagination__link,.abaabil-pagination__current,.abaabil-pagination__step{min-inline-size:var(--control-height-md);block-size:var(--control-height-md);padding-inline:var(--space-2);border-radius:var(--radius-md);color:var(--color-text);font-variant-numeric:tabular-nums;border:1px solid #0000;justify-content:center;align-items:center;text-decoration:none;display:inline-flex}.abaabil-pagination__link:hover{background:var(--color-muted)}.abaabil-pagination__link:focus-visible,.abaabil-pagination__step:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-pagination__current{background:var(--color-primary);border-color:var(--color-primary);color:var(--color-primary-fg);font-weight:var(--font-weight-semibold)}.abaabil-pagination__gap:before{content:"…"}.abaabil-pagination__gap{min-inline-size:var(--control-height-md);block-size:var(--control-height-md);color:var(--color-text-muted);justify-content:center;align-items:center;display:inline-flex}.abaabil-pagination__step{border-color:var(--color-border)}.abaabil-pagination__step:hover{background:var(--color-muted)}.abaabil-pagination__step--unavailable{color:var(--color-text-muted);opacity:.6;border-color:#0000}.abaabil-popover{inline-size:max-content;max-inline-size:min(22rem,100vw - 2rem);padding:var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font-size:var(--font-size-sm)}.abaabil-popover:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-popover::backdrop{background:0 0}.abaabil-popover__trigger{font:inherit;color:inherit}@supports (anchor-name:--x){.abaabil-popover{position-area:block-end span-inline-end;position-try-fallbacks:block-start span-inline-end, block-end span-inline-start;margin:0;margin-block-start:var(--space-1);position:fixed;inset:auto}}@starting-style{.abaabil-popover:popover-open{opacity:0}}.abaabil-popover:popover-open{opacity:1;transition:opacity var(--duration-fast) ease}@media (prefers-reduced-motion:reduce){.abaabil-popover:popover-open{transition:none}@starting-style{.abaabil-popover:popover-open{opacity:1}}}.abaabil-progress{appearance:none;background:var(--color-muted);block-size:.5rem;inline-size:100%;color:var(--color-primary);border:0;border-radius:999px;display:block;overflow:hidden}.abaabil-progress::-webkit-progress-bar{background:var(--color-muted);border-radius:999px}.abaabil-progress::-webkit-progress-value{background:var(--color-primary);transition:inline-size var(--duration-fast) ease;border-radius:999px}.abaabil-progress::-moz-progress-bar{background:var(--color-primary);border-radius:999px}.abaabil-progress:indeterminate{background:linear-gradient(90deg, var(--color-primary) 0 35%, transparent 35% 100%) 0 0 / 250% 100% no-repeat var(--color-muted);animation:1.4s linear infinite abaabil-progress-slide}.abaabil-progress:indeterminate::-webkit-progress-bar{background:0 0}.abaabil-progress:indeterminate::-moz-progress-bar{background:0 0}@keyframes abaabil-progress-slide{0%{background-position:-60% 0}to{background-position:160% 0}}.abaabil-progress-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-progress__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-progress__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}@media (prefers-reduced-motion:reduce){.abaabil-progress::-webkit-progress-value{transition:none}.abaabil-progress:indeterminate{background-position:40% 0;animation:none}}.abaabil-radio{appearance:none;border:1px solid var(--color-border);background:var(--color-surface);cursor:pointer;width:1.125rem;height:1.125rem;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;border-radius:50%;flex-shrink:0;place-content:center;margin:0;display:inline-grid}.abaabil-radio:before{content:"";background:var(--color-primary-fg);width:.5rem;height:.5rem;transition:transform var(--duration-fast) ease;border-radius:50%;transform:scale(0)}.abaabil-radio:checked{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-radio:checked:before{transform:scale(1)}.abaabil-radio:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-radio:disabled{opacity:.5;cursor:not-allowed}.abaabil-radio__wrapper{align-items:flex-start;gap:var(--space-2);display:inline-flex}.abaabil-radio__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-radio__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;display:block}.abaabil-radio-group{border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-3)}.abaabil-radio-group__legend{padding-inline:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);color:var(--color-text)}@media (prefers-reduced-motion:reduce){.abaabil-radio,.abaabil-radio:before{transition:none}}.abaabil-select{--select-height:var(--control-height-md);--select-padding-x:max(.375rem, calc((var(--select-height) - var(--font-size-sm)) / 2));appearance:none;height:var(--select-height);padding-inline:var(--select-padding-x);border:1px solid var(--color-border);border-radius:var(--radius-md);background-color:var(--color-surface);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' stroke='currentColor' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--select-padding-x) center;color:var(--color-text);font-size:var(--font-size-sm);cursor:pointer;transition:border-color var(--duration-fast) ease;background-size:.75rem .75rem;padding-inline-end:calc(var(--select-padding-x) + 1.125rem);line-height:1}.abaabil-select:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){background-position:left var(--select-padding-x) center;padding-inline-start:calc(var(--select-padding-x) + 1.125rem);padding-inline-end:var(--select-padding-x)}.abaabil-select:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-select:disabled{opacity:.5;cursor:not-allowed}.abaabil-select-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-select__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-select__description{font-size:var(--font-size-sm);color:var(--color-text);opacity:.75;margin:0}.abaabil-select__error{font-size:var(--font-size-sm);color:var(--color-danger);margin:0}.abaabil-select[aria-invalid=true]{border-color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-select{transition:none}}.abaabil-slider{--slider-track:.3rem;--slider-thumb:1.1rem;appearance:none;inline-size:100%;block-size:var(--slider-thumb);cursor:pointer;background:0 0;margin:0}.abaabil-slider::-webkit-slider-runnable-track{block-size:var(--slider-track);background:var(--color-muted);border-radius:999px}.abaabil-slider::-moz-range-track{block-size:var(--slider-track);background:var(--color-muted);border-radius:999px}.abaabil-slider::-webkit-slider-thumb{appearance:none;inline-size:var(--slider-thumb);block-size:var(--slider-thumb);border:2px solid var(--color-surface);background:var(--color-primary);border-radius:50%;margin-block-start:calc((var(--slider-track) - var(--slider-thumb)) / 2)}.abaabil-slider::-moz-range-thumb{inline-size:var(--slider-thumb);block-size:var(--slider-thumb);border:2px solid var(--color-surface);background:var(--color-primary);border-radius:50%}.abaabil-slider::-moz-range-progress{block-size:var(--slider-track);background:var(--color-primary);border-radius:999px}.abaabil-slider:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:4px;border-radius:999px}.abaabil-slider:disabled{opacity:.5;cursor:not-allowed}.abaabil-slider-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-slider__header{justify-content:space-between;align-items:baseline;gap:var(--space-2);display:flex}.abaabil-slider__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-slider__output{font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums;color:var(--color-text)}.abaabil-slider__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}.abaabil-switch{--switch-width:2.25rem;--switch-height:1.25rem;--switch-gap:2px;--switch-thumb:calc(var(--switch-height) - (var(--switch-gap) * 2));appearance:none;inline-size:var(--switch-width);block-size:var(--switch-height);border:1px solid var(--color-border);background:var(--color-muted);cursor:pointer;transition:background-color var(--duration-fast) ease, border-color var(--duration-fast) ease;border-radius:999px;flex-shrink:0;margin:0;position:relative}.abaabil-switch:before{content:"";inline-size:var(--switch-thumb);block-size:var(--switch-thumb);background:var(--color-surface);transition:inset-inline-start var(--duration-fast) ease;border-radius:50%;position:absolute;inset-block-start:50%;inset-inline-start:var(--switch-gap);translate:0 -50%}.abaabil-switch:checked{background:var(--color-primary);border-color:var(--color-primary)}.abaabil-switch:checked:before{inset-inline-start:calc(100% - var(--switch-thumb) - var(--switch-gap))}.abaabil-switch:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-switch:disabled{opacity:.5;cursor:not-allowed}.abaabil-switch__wrapper{align-items:center;gap:var(--space-2);flex-wrap:wrap;display:inline-flex}.abaabil-switch__label{font-size:var(--font-size-sm);color:var(--color-text);cursor:pointer}.abaabil-switch__description{font-size:var(--font-size-sm);color:var(--color-text-muted);flex-basis:100%;display:block}@media (prefers-reduced-motion:reduce){.abaabil-switch,.abaabil-switch:before{transition:none}}.abaabil-tabs{gap:var(--space-3);flex-direction:column;display:flex}.abaabil-tabs__list{gap:var(--space-1);border-block-end:1px solid var(--color-border);display:flex}.abaabil-tabs__tab{appearance:none;padding-block:var(--space-2);padding-inline:var(--space-3);border:0;color:var(--color-text-muted);font:inherit;font-size:var(--font-size-sm);font-weight:var(--font-weight-semibold);white-space:nowrap;cursor:pointer;transition:color var(--duration-fast) ease, border-color var(--duration-fast) ease;background:0 0;border-block-end:2px solid #0000;margin-block-end:-1px;line-height:1.3}.abaabil-tabs__tab:hover{color:var(--color-text)}.abaabil-tabs__tab[data-selected=true]{color:var(--color-text);border-block-end-color:var(--color-primary)}.abaabil-tabs__tab:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:-2px}.abaabil-tabs__tab:disabled{opacity:.5;cursor:not-allowed}.abaabil-tabs__list[data-orientation=vertical]{border-block-end:0;border-inline-end:1px solid var(--color-border);flex-direction:column}.abaabil-tabs__list[data-orientation=vertical] .abaabil-tabs__tab{text-align:start;border-block-end:0;border-inline-end:2px solid #0000;margin-block-end:0;margin-inline-end:-1px}.abaabil-tabs__list[data-orientation=vertical] .abaabil-tabs__tab[data-selected=true]{border-inline-end-color:var(--color-primary)}.abaabil-tabs__panel:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}@media (prefers-reduced-motion:reduce){.abaabil-tabs__tab{transition:none}}.abaabil-textarea{--textarea-padding-block:var(--space-2);--textarea-padding-x:var(--space-3);--textarea-border:var(--color-border);--textarea-placeholder-fg:var(--color-placeholder);width:100%;padding-block:var(--textarea-padding-block);padding-inline:var(--textarea-padding-x);border:1px solid var(--textarea-border);border-radius:var(--radius-md);background:var(--color-surface);color:var(--color-text);font:inherit;font-size:var(--font-size-sm);resize:block;transition:border-color var(--duration-fast) ease;line-height:1.5;display:block}.abaabil-textarea::placeholder{color:var(--textarea-placeholder-fg)}.abaabil-textarea:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}.abaabil-textarea:disabled{opacity:.5;cursor:not-allowed;resize:none}.abaabil-textarea[aria-invalid=true]{--textarea-border:var(--color-danger)}.abaabil-textarea-group{gap:var(--space-1);flex-direction:column;display:flex}.abaabil-textarea__label{font-size:var(--font-size-sm);color:var(--color-text)}.abaabil-textarea__description{font-size:var(--font-size-sm);color:var(--color-text-muted)}.abaabil-textarea__error{font-size:var(--font-size-sm);color:var(--color-danger)}@media (prefers-reduced-motion:reduce){.abaabil-textarea{transition:none}}.abaabil-toolbar{align-items:center;gap:var(--space-1);padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);display:flex}.abaabil-toolbar[data-orientation=vertical]{flex-direction:column;align-items:stretch;inline-size:max-content}.abaabil-toolbar hr{block-size:auto;inline-size:1px;margin-block:var(--space-1);margin-inline:var(--space-1);background:var(--color-border);border:0;align-self:stretch}.abaabil-toolbar[data-orientation=vertical] hr{block-size:1px;inline-size:auto;margin-block:var(--space-1);margin-inline:var(--space-1)}.abaabil-tooltip{display:inline-flex;position:relative}.abaabil-tooltip__bubble{z-index:20;inline-size:max-content;max-inline-size:16rem;padding-block:var(--space-1);padding-inline:var(--space-2);border-radius:var(--radius-md);background:var(--color-text);color:var(--color-surface);font-size:var(--font-size-sm);text-align:start;opacity:0;visibility:hidden;transition:opacity var(--duration-fast) ease, visibility 0s linear var(--duration-fast);pointer-events:none;line-height:1.4;position:absolute;inset-inline-start:50%;translate:-50%}.abaabil-tooltip[data-placement=top] .abaabil-tooltip__bubble{inset-block-end:calc(100% + var(--space-1))}.abaabil-tooltip[data-placement=bottom] .abaabil-tooltip__bubble{inset-block-start:calc(100% + var(--space-1))}.abaabil-tooltip:hover .abaabil-tooltip__bubble,.abaabil-tooltip:focus-within .abaabil-tooltip__bubble{opacity:1;visibility:visible;transition:none}.abaabil-tooltip[data-dismissed=true] .abaabil-tooltip__bubble{opacity:0;visibility:hidden}@media (prefers-reduced-motion:reduce){.abaabil-tooltip__bubble{transition:none}}}
package/dist/theme.css CHANGED
@@ -1 +1 @@
1
- @layer abaabil.reset;@layer abaabil.tokens{:root{--abaabil-blue-500:#2563eb;--abaabil-blue-400:#3b82f6;--abaabil-gray-900:#111827;--abaabil-gray-300:#d1d5db;--abaabil-gray-100:#f3f4f6;--abaabil-white:#fff;--abaabil-red-600:#dc2626;--abaabil-green-600:#16a34a;--abaabil-amber-600:#b45309;--color-primary:var(--abaabil-blue-500);--color-primary-hover:var(--abaabil-blue-400);--color-primary-fg:var(--abaabil-white);--color-surface:var(--abaabil-white);--color-text:var(--abaabil-gray-900);--color-border:var(--abaabil-gray-300);--color-muted:var(--abaabil-gray-100);--color-danger:var(--abaabil-red-600);--color-success:var(--abaabil-green-600);--color-warning:var(--abaabil-amber-600);--color-focus-ring:var(--abaabil-blue-500);--color-overlay:#00000080;--color-text-muted:#6b7280;--color-placeholder:#9ca3af;--radius-md:.375rem;--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--font-size-sm:.875rem;--font-size-lg:1.125rem;--font-weight-semibold:600;--control-height-md:2.5rem;--duration-fast:.15s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}:root[data-theme=dark]{--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}@layer abaabil.base{.abaabil-visually-hidden{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}@layer abaabil.components;
1
+ @layer abaabil.reset;@layer abaabil.tokens{:root{--abaabil-blue-500:#2563eb;--abaabil-gray-900:#111827;--abaabil-gray-300:#d1d5db;--abaabil-gray-100:#f3f4f6;--abaabil-white:#fff;--abaabil-red-600:#dc2626;--abaabil-green-600:#16a34a;--abaabil-amber-600:#b45309;--color-primary:var(--abaabil-blue-500);--color-primary-hover:color-mix(in srgb, var(--color-primary) 85%, white);--color-primary-fg:var(--abaabil-white);--color-surface:var(--abaabil-white);--color-text:var(--abaabil-gray-900);--color-border:var(--abaabil-gray-300);--color-muted:var(--abaabil-gray-100);--color-danger:var(--abaabil-red-600);--color-success:var(--abaabil-green-600);--color-warning:var(--abaabil-amber-600);--color-focus-ring:var(--color-primary);--color-overlay:#00000080;--color-text-muted:#6b7280;--color-placeholder:#9ca3af;--radius-md:.375rem;--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--font-size-sm:.875rem;--font-size-lg:1.125rem;--font-weight-semibold:600;--control-height-md:2.5rem;--duration-fast:.15s}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}:root[data-theme=dark]{--color-surface:#0b0f19;--color-text:#e5e7eb;--color-border:#374151;--color-muted:#1f2937;--color-text-muted:#9ca3af;--color-placeholder:#6b7280}}@layer abaabil.base{.abaabil-visually-hidden{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}}@layer abaabil.components;
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsx as g}from"react/jsx-runtime";import{useRef as w,useCallback as E,useEffect as k}from"react";import"./toolbar.css";const A=["button:not([disabled])","a[href]",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])",'[tabindex]:not([tabindex^="-"])'].join(",");function v({label:b,labelledBy:d,orientation:r="horizontal",className:f,children:u,...i}){const s=w(null),h=f?`abaabil-toolbar ${f}`:"abaabil-toolbar";typeof process<"u"&&process.env.NODE_ENV!=="production"&&!(b||d||i["aria-label"]||i["aria-labelledby"])&&console.warn("abaabil/toolbar: no `label` or `labelledBy` given, so the toolbar has no accessible name and is announced as an unnamed toolbar.");const c=E(()=>s.current?[...s.current.querySelectorAll(A)]:[],[]);k(()=>{const e=c();if(!e.length)return;const t=e.find(n=>n.tabIndex===0)??e[0];for(const n of e)n.tabIndex=n===t?0:-1});function m(e){const t=c();if(!t.length)return;const n=Math.max(0,Math.min(e,t.length-1));for(const o of t)o.tabIndex=o===t[n]?0:-1;t[n].focus()}function y(e){const t=e.target,n=t.tagName;if(n==="SELECT"||n==="TEXTAREA"||n==="INPUT"&&!["button","checkbox","radio","submit","reset"].includes(t.type))return;const o=c(),a=o.indexOf(t);if(a===-1)return;const p=r==="vertical"?"ArrowDown":"ArrowRight",x=r==="vertical"?"ArrowUp":"ArrowLeft";let l=null;if(e.key===p)l=a===o.length-1?0:a+1;else if(e.key===x)l=a===0?o.length-1:a-1;else if(e.key==="Home")l=0;else if(e.key==="End")l=o.length-1;else return;e.preventDefault(),m(l)}return g("div",{ref:s,role:"toolbar","aria-label":b,"aria-labelledby":d,"aria-orientation":r,"data-orientation":r,className:h,onKeyDown:y,...i,children:u})}export{v as default};
@@ -0,0 +1 @@
1
+ import{jsx as n}from"react/jsx-runtime";function l({orientation:o="horizontal",className:a,children:t,...i}){const r=a?`abaabil-toolbar ${a}`:"abaabil-toolbar";return n("div",{className:r,"data-orientation":o,...i,children:t})}export{l as default};
@@ -0,0 +1 @@
1
+ import"./toolbar.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-toolbar{align-items:center;gap:var(--space-1);padding:var(--space-1);border:1px solid var(--color-border);border-radius:var(--radius-md);background:var(--color-surface);display:flex}.abaabil-toolbar[data-orientation=vertical]{flex-direction:column;align-items:stretch;inline-size:max-content}.abaabil-toolbar hr{block-size:auto;inline-size:1px;margin-block:var(--space-1);margin-inline:var(--space-1);background:var(--color-border);border:0;align-self:stretch}.abaabil-toolbar[data-orientation=vertical] hr{block-size:1px;inline-size:auto;margin-block:var(--space-1);margin-inline:var(--space-1)}}
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{jsxs as m,jsx as f}from"react/jsx-runtime";import{useId as y,useState as E,useRef as h,isValidElement as s,cloneElement as N}from"react";import"./tooltip.css";function g({content:i,placement:l="top",className:o,children:e,...r}){const n=y(),[t,a]=E(!1),c=h(null),p=o?`abaabil-tooltip ${o}`:"abaabil-tooltip";typeof process<"u"&&process.env.NODE_ENV!=="production"&&(s(e)||console.warn("abaabil/tooltip: children must be a single element that can receive props (a button, a link, an input). A string or fragment cannot be described, and a tooltip on a non-focusable element is invisible to keyboard users."));function b(u){u.key==="Escape"&&!t&&a(!0)}const d=s(e)?N(e,{"aria-describedby":[e.props["aria-describedby"],n].filter(Boolean).join(" ")}):e;return m("span",{ref:c,className:p,"data-placement":l,"data-dismissed":t?"true":void 0,onKeyDown:b,onPointerEnter:()=>a(!1),onFocus:()=>a(!1),...r,children:[d,f("span",{id:n,className:"abaabil-tooltip__bubble",role:"tooltip",children:i})]})}export{g as default};
@@ -0,0 +1 @@
1
+ import{jsxs as s,jsx as c}from"react/jsx-runtime";function i({content:t,placement:l="top",className:a,children:e,...n}){const o=a?`abaabil-tooltip ${a}`:"abaabil-tooltip";return s("span",{className:o,"data-placement":l,...n,children:[e,c("span",{className:"abaabil-tooltip__bubble",children:t})]})}export{i as default};
@@ -0,0 +1 @@
1
+ import"./tooltip.css";import{default as e}from"./index.js";export{e as default};
@@ -0,0 +1 @@
1
+ @layer abaabil.components{.abaabil-tooltip{display:inline-flex;position:relative}.abaabil-tooltip__bubble{z-index:20;inline-size:max-content;max-inline-size:16rem;padding-block:var(--space-1);padding-inline:var(--space-2);border-radius:var(--radius-md);background:var(--color-text);color:var(--color-surface);font-size:var(--font-size-sm);text-align:start;opacity:0;visibility:hidden;transition:opacity var(--duration-fast) ease, visibility 0s linear var(--duration-fast);pointer-events:none;line-height:1.4;position:absolute;inset-inline-start:50%;translate:-50%}.abaabil-tooltip[data-placement=top] .abaabil-tooltip__bubble{inset-block-end:calc(100% + var(--space-1))}.abaabil-tooltip[data-placement=bottom] .abaabil-tooltip__bubble{inset-block-start:calc(100% + var(--space-1))}.abaabil-tooltip:hover .abaabil-tooltip__bubble,.abaabil-tooltip:focus-within .abaabil-tooltip__bubble{opacity:1;visibility:visible;transition:none}.abaabil-tooltip[data-dismissed=true] .abaabil-tooltip__bubble{opacity:0;visibility:hidden}@media (prefers-reduced-motion:reduce){.abaabil-tooltip__bubble{transition:none}}}
package/llms.txt ADDED
@@ -0,0 +1,143 @@
1
+ # abaabil
2
+
3
+ > A small React component library: twenty-three components, three import tiers
4
+ > each, plain CSS in cascade layers, zero runtime dependencies. React 19 is
5
+ > the only peer dependency.
6
+
7
+ This file is for language models and coding agents. It is the short version
8
+ of README.md: the rules you need to write correct code with this library,
9
+ and the mistakes that are easy to make. Full docs: https://www.abaabil.com
10
+ and https://www.abaabil.com/llms-full.txt
11
+
12
+ ## The three rules that matter most
13
+
14
+ 1. **There is no root export.** `import { Button } from 'abaabil'` throws.
15
+ Import the entry point: `import Button from 'abaabil/button/a11y'`.
16
+ 2. **Import `abaabil/theme.css` once, at your app root.** Without it the
17
+ components render unthemed, because every stylesheet reads custom
18
+ properties that file defines.
19
+ 3. **Use the `a11y` tier** unless you have a specific reason not to. The
20
+ other two exist so you can opt out of CSS or ARIA deliberately, not
21
+ because they are lighter defaults.
22
+
23
+ ## Import shape
24
+
25
+ Every component has exactly three entry points:
26
+
27
+ abaabil/<name> structure only, no CSS, no ARIA
28
+ abaabil/<name>/styled + the component's stylesheet
29
+ abaabil/<name>/a11y + labels, ARIA wiring, keyboard behaviour
30
+
31
+ Each tier default-exports its main component. Components with extra parts
32
+ also export them by name: `CheckboxGroup`, `RadioGroup`, `Disclosure`,
33
+ `Accordion`, `PopoverTrigger`, `PopoverPanel`.
34
+
35
+ Names: button, dialog, popover, menu, tooltip, combobox, input, textarea,
36
+ file, checkbox, radio, switch, select, slider, accordion, tabs, toolbar,
37
+ breadcrumb, pagination, progress, alert, avatar, badge.
38
+
39
+ Stylesheets are also importable on their own as `abaabil/<name>.css`, and
40
+ `abaabil/styles.css` is every component's CSS in one file.
41
+
42
+ ## Per-component notes an agent will otherwise get wrong
43
+
44
+ - **popover** requires an explicit `id` prop. It is not generated, because
45
+ generating it would need `useId` and that would make the component a
46
+ client component. `<Popover id="menu" trigger="Options" label="...">`.
47
+ - **alert** is a live region. It is announced when its *contents change*,
48
+ so render it empty from the start and fill it in. Mounting the whole
49
+ component at the moment you have a message often announces nothing.
50
+ Its role follows `variant`: info/success are polite, warning/danger
51
+ interrupt.
52
+ - **switch** carries `role="switch"` at every tier, including `normal`.
53
+ Use it for a setting that applies immediately; use `checkbox` for a
54
+ value the form submits later.
55
+ - **combobox** and **tabs** are uncontrolled. There is no `value` or
56
+ `selectedIndex` prop; observe changes through `onChange`.
57
+ - **accordion** exclusivity comes from the native `name` attribute on
58
+ `<details>`, which defaults to a shared value. Pass `name={undefined}`
59
+ to allow several panels open at once.
60
+ - **checkbox** takes `indeterminate` as a prop because the DOM property
61
+ has no HTML attribute.
62
+ - **dialog** is the native `<dialog>` with `showModal()`. Do not add a
63
+ focus trap; the browser already contains focus.
64
+ - **menu** requires an explicit `id`, like popover. Use it only for a
65
+ list of *actions*. A button revealing navigation links is not a menu;
66
+ that is `popover` with links inside, and marking it `role="menu"`
67
+ announces a widget the user cannot operate as one.
68
+ - **tooltip** takes a single focusable element as its child and clones
69
+ it. Never put essential information or anything interactive in one:
70
+ there is no hover on touch, and moving towards a link inside a tooltip
71
+ dismisses it. If you need either, use `popover`.
72
+ - **progress** leaves `value` unset for an indeterminate bar. Pass
73
+ `valueText` whenever the number is not a percentage, or "3 of 8 files"
74
+ is announced as "38 percent".
75
+ - **slider** is a native range input. Pass `formatValue` when the raw
76
+ number is not self-explanatory; it sets `aria-valuetext`.
77
+ - **breadcrumb** renders the last item as text rather than a link, and
78
+ marks it `aria-current="page"`. Pass items root first.
79
+ - **pagination** takes `page`, `pageCount` and `href`, and renders real
80
+ links. Override `pageLabel`, `previousLabel` and `nextLabel` to
81
+ translate; every number is named "Page 7", not "7".
82
+ - **toolbar** takes arbitrary children, not an items array, and
83
+ collapses them to one tab stop with arrow keys inside. It needs a
84
+ `label`.
85
+ - **file** is a real `<input type="file">`. Pass a `description` saying
86
+ what you accept: `accept` filters the dialog silently and does not
87
+ apply to a dropped file.
88
+ - **avatar** is decorative by default, which is right beside a visible
89
+ name. Pass `decorative={false}` when the avatar is the only thing
90
+ identifying someone, and give it a `name`.
91
+ - **badge** takes `context` for the rest of the sentence: `<Badge
92
+ context="unread messages">3</Badge>` draws "3" and announces "3 unread
93
+ messages". Do not reach for `aria-label`; a span discards it.
94
+ - Components needing an accessible name (**input**, **textarea**,
95
+ **select**, **checkbox**, **radio**, **switch**, **combobox**,
96
+ **popover**, **tabs**, **progress**, **slider**, **file**,
97
+ **toolbar**) warn in development when given none. Pass
98
+ `label`, or `aria-label`/`aria-labelledby`.
99
+
100
+ ## Server Components
101
+
102
+ Fifty-one of the sixty-nine entry points carry no `"use client"` and
103
+ render inside a React Server Component tree.
104
+
105
+ - Server-safe at **every** tier: button, accordion, popover, alert,
106
+ breadcrumb, pagination, avatar, badge. Tooltip too at `normal` and
107
+ `styled`, because it shows and hides in CSS rather than JavaScript.
108
+ - Client at **every** tier: combobox, tabs. Neither has a native element
109
+ to build on, so both need state.
110
+ - Everything else is server-safe at `normal` and `styled`, and a client
111
+ component at `a11y`, where `useId` mints the ids that tie labels to
112
+ controls.
113
+
114
+ ## Theming
115
+
116
+ CSS custom properties only. No provider, no context, no JS theme object.
117
+ Set `--color-primary`, `--radius-md`, `--control-height-md` and the rest on
118
+ `:root` or on any scope element.
119
+
120
+ Setting `--color-primary` is enough: `--color-primary-hover` and
121
+ `--color-focus-ring` are derived from it. `--color-primary-fg` is not, and
122
+ is white, so if you set a light primary set a dark `--color-primary-fg`
123
+ too or text on buttons fails contrast. `--color-danger`, `--color-success`
124
+ and `--color-warning` are deliberately independent of the brand colour. Dark mode is the same tokens redefined
125
+ under `prefers-color-scheme` and `[data-theme="dark"]`, both of which the
126
+ shipped theme already handles.
127
+
128
+ Component CSS lives in the `abaabil.components` cascade layer, so ordinary
129
+ unlayered CSS in your own app beats it without `!important`.
130
+
131
+ ## Browser floor
132
+
133
+ Chrome 99, Firefox 98, Safari 15.4, set by `@layer` and `<dialog>`.
134
+ `abaabil/popover` is the exception: the Popover API needs Chrome 114,
135
+ Firefox 125, Safari 17. Below that the panel renders as an always-visible
136
+ block instead of opening and closing.
137
+
138
+ ## What this library deliberately does not do
139
+
140
+ No focus trap, no layout or spacing utilities, no theming runtime, no
141
+ `headingLevel` on accordion, no controlled combobox or tabs, no date
142
+ picker, no data table, no drag and drop. Each is a
143
+ decision with a reason, documented at https://www.abaabil.com/why.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abaabil",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Minimal, themeable, accessible React components. Zero dependencies.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,7 +31,8 @@
31
31
  ],
32
32
  "files": [
33
33
  "dist",
34
- "CHANGELOG.md"
34
+ "CHANGELOG.md",
35
+ "llms.txt"
35
36
  ],
36
37
  "exports": {
37
38
  "./package.json": "./package.json",
@@ -74,6 +75,36 @@
74
75
  "./alert": "./dist/alert/index.js",
75
76
  "./alert/styled": "./dist/alert/styled.js",
76
77
  "./alert/a11y": "./dist/alert/a11y.js",
78
+ "./progress": "./dist/progress/index.js",
79
+ "./progress/styled": "./dist/progress/styled.js",
80
+ "./progress/a11y": "./dist/progress/a11y.js",
81
+ "./slider": "./dist/slider/index.js",
82
+ "./slider/styled": "./dist/slider/styled.js",
83
+ "./slider/a11y": "./dist/slider/a11y.js",
84
+ "./breadcrumb": "./dist/breadcrumb/index.js",
85
+ "./breadcrumb/styled": "./dist/breadcrumb/styled.js",
86
+ "./breadcrumb/a11y": "./dist/breadcrumb/a11y.js",
87
+ "./tooltip": "./dist/tooltip/index.js",
88
+ "./tooltip/styled": "./dist/tooltip/styled.js",
89
+ "./tooltip/a11y": "./dist/tooltip/a11y.js",
90
+ "./menu": "./dist/menu/index.js",
91
+ "./menu/styled": "./dist/menu/styled.js",
92
+ "./menu/a11y": "./dist/menu/a11y.js",
93
+ "./pagination": "./dist/pagination/index.js",
94
+ "./pagination/styled": "./dist/pagination/styled.js",
95
+ "./pagination/a11y": "./dist/pagination/a11y.js",
96
+ "./file": "./dist/file/index.js",
97
+ "./file/styled": "./dist/file/styled.js",
98
+ "./file/a11y": "./dist/file/a11y.js",
99
+ "./toolbar": "./dist/toolbar/index.js",
100
+ "./toolbar/styled": "./dist/toolbar/styled.js",
101
+ "./toolbar/a11y": "./dist/toolbar/a11y.js",
102
+ "./avatar": "./dist/avatar/index.js",
103
+ "./avatar/styled": "./dist/avatar/styled.js",
104
+ "./avatar/a11y": "./dist/avatar/a11y.js",
105
+ "./badge": "./dist/badge/index.js",
106
+ "./badge/styled": "./dist/badge/styled.js",
107
+ "./badge/a11y": "./dist/badge/a11y.js",
77
108
  "./theme.css": "./dist/theme.css",
78
109
  "./styles.css": "./dist/styles.css",
79
110
  "./button.css": "./dist/button/button.css",
@@ -88,10 +119,20 @@
88
119
  "./switch.css": "./dist/switch/switch.css",
89
120
  "./popover.css": "./dist/popover/popover.css",
90
121
  "./tabs.css": "./dist/tabs/tabs.css",
91
- "./alert.css": "./dist/alert/alert.css"
122
+ "./alert.css": "./dist/alert/alert.css",
123
+ "./progress.css": "./dist/progress/progress.css",
124
+ "./slider.css": "./dist/slider/slider.css",
125
+ "./breadcrumb.css": "./dist/breadcrumb/breadcrumb.css",
126
+ "./tooltip.css": "./dist/tooltip/tooltip.css",
127
+ "./menu.css": "./dist/menu/menu.css",
128
+ "./pagination.css": "./dist/pagination/pagination.css",
129
+ "./file.css": "./dist/file/file.css",
130
+ "./toolbar.css": "./dist/toolbar/toolbar.css",
131
+ "./avatar.css": "./dist/avatar/avatar.css",
132
+ "./badge.css": "./dist/badge/badge.css"
92
133
  },
93
134
  "scripts": {
94
- "build": "node scripts/build-css.js && rollup -c && node scripts/check-directives.js && node scripts/measure.js",
135
+ "build": "node scripts/build-css.js && rollup -c && node scripts/check-directives.js && node scripts/check-complete.js && node scripts/measure.js",
95
136
  "test": "vitest run",
96
137
  "test:watch": "vitest",
97
138
  "prepublishOnly": "npm run build && node scripts/check-package.js"