neba 1.12.0 → 1.13.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 (117) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +43 -41
  3. package/dist/components/accordion/Accordion.d.ts +18 -0
  4. package/dist/components/accordion/Accordion.js +1 -1
  5. package/dist/components/anchor/Anchor.js +1 -1
  6. package/dist/components/animate-marquee/AnimateMarquee.d.ts +5 -3
  7. package/dist/components/animate-marquee/AnimateMarquee.js +1 -1
  8. package/dist/components/animate-scramble/AnimateScramble.js +1 -1
  9. package/dist/components/app-logo/AppLogo.js +1 -1
  10. package/dist/components/bottom-navigation/BottomNavigation.d.ts +10 -0
  11. package/dist/components/bottom-navigation/BottomNavigation.js +1 -1
  12. package/dist/components/button/Button.js +1 -1
  13. package/dist/components/calendar/Calendar.js +1 -1
  14. package/dist/components/carousel/Carousel.d.ts +13 -0
  15. package/dist/components/carousel/Carousel.js +1 -1
  16. package/dist/components/code-block/CodeBlock.js +1 -1
  17. package/dist/components/color-picker/ColorPicker.js +1 -1
  18. package/dist/components/combobox/Combobox.d.ts +18 -0
  19. package/dist/components/combobox/Combobox.js +1 -1
  20. package/dist/components/command-palette/CommandPalette.js +1 -1
  21. package/dist/components/data-table/DataTable.js +1 -1
  22. package/dist/components/date-picker/DatePicker.js +1 -1
  23. package/dist/components/date-range-picker/DateRangePicker.js +1 -1
  24. package/dist/components/date-time-picker/DateTimePicker.js +1 -1
  25. package/dist/components/dialog/Dialog.js +1 -1
  26. package/dist/components/drawer/Drawer.js +1 -1
  27. package/dist/components/gauge-chart/GaugeChart.js +1 -1
  28. package/dist/components/grid/Grid.d.ts +11 -1
  29. package/dist/components/grid/Grid.js +1 -1
  30. package/dist/components/hover-card/HoverCard.js +1 -1
  31. package/dist/components/image/Image.d.ts +32 -4
  32. package/dist/components/image/Image.js +1 -1
  33. package/dist/components/menu/Menu.js +1 -1
  34. package/dist/components/meter/Meter.d.ts +7 -0
  35. package/dist/components/meter/Meter.js +1 -1
  36. package/dist/components/navigation-menu/NavigationMenu.js +1 -1
  37. package/dist/components/number-field/NumberField.js +1 -1
  38. package/dist/components/otp-field/OtpField.js +1 -1
  39. package/dist/components/overlay/Overlay.js +1 -1
  40. package/dist/components/panes/Panes.js +1 -1
  41. package/dist/components/popover/Popover.js +1 -1
  42. package/dist/components/progress-circular/ProgressCircular.d.ts +10 -1
  43. package/dist/components/progress-circular/ProgressCircular.js +1 -1
  44. package/dist/components/progress-linear/ProgressLinear.d.ts +7 -1
  45. package/dist/components/progress-linear/ProgressLinear.js +1 -1
  46. package/dist/components/provider/NebaProvider.js +1 -1
  47. package/dist/components/scatter-chart/ScatterChart.js +1 -1
  48. package/dist/components/scroll-area/ScrollArea.js +1 -1
  49. package/dist/components/scroll-zone/ScrollZone.d.ts +8 -7
  50. package/dist/components/scroll-zone/ScrollZone.js +1 -1
  51. package/dist/components/select/Select.d.ts +13 -0
  52. package/dist/components/select/Select.js +1 -1
  53. package/dist/components/slider/Slider.d.ts +37 -2
  54. package/dist/components/slider/Slider.js +1 -1
  55. package/dist/components/tabs/Tabs.d.ts +18 -0
  56. package/dist/components/tabs/Tabs.js +1 -1
  57. package/dist/components/text-field/TextField.js +1 -1
  58. package/dist/components/time-picker/TimePicker.js +1 -1
  59. package/dist/components/timeline-chart/TimelineChart.js +1 -1
  60. package/dist/components/toast/Toast.js +1 -1
  61. package/dist/components/tooltip/Tooltip.js +1 -1
  62. package/dist/components/tour/Tour.js +1 -1
  63. package/dist/components/transfer/Transfer.js +1 -1
  64. package/dist/components/tree-select/TreeSelect.d.ts +2 -0
  65. package/dist/components/tree-select/TreeSelect.js +1 -1
  66. package/dist/components/typography/Typography.js +1 -1
  67. package/dist/internal/cache.d.ts +24 -0
  68. package/dist/internal/cache.js +1 -0
  69. package/dist/internal/calendar.d.ts +15 -42
  70. package/dist/internal/calendar.js +1 -1
  71. package/dist/internal/chart-frame.d.ts +16 -3
  72. package/dist/internal/chart-frame.js +1 -1
  73. package/dist/internal/date.js +1 -1
  74. package/dist/internal/drag.d.ts +8 -6
  75. package/dist/internal/drag.js +1 -1
  76. package/dist/internal/format.d.ts +21 -7
  77. package/dist/internal/format.js +1 -1
  78. package/dist/internal/grid.d.ts +16 -0
  79. package/dist/internal/grid.js +1 -1
  80. package/dist/internal/i18n.d.ts +72 -0
  81. package/dist/internal/i18n.js +1 -1
  82. package/dist/internal/icons.d.ts +25 -0
  83. package/dist/internal/icons.js +1 -1
  84. package/dist/internal/link.d.ts +5 -4
  85. package/dist/internal/media.js +1 -1
  86. package/dist/internal/observe.js +1 -1
  87. package/dist/internal/picker.d.ts +8 -3
  88. package/dist/internal/picker.js +1 -1
  89. package/dist/internal/progress.d.ts +24 -1
  90. package/dist/internal/progress.js +1 -1
  91. package/dist/internal/styles.d.ts +73 -3
  92. package/dist/internal/styles.js +1 -1
  93. package/dist/internal/text.d.ts +0 -10
  94. package/dist/internal/text.js +1 -1
  95. package/dist/internal/wheel.d.ts +38 -0
  96. package/dist/internal/wheel.js +1 -0
  97. package/dist/locales/ar.js +1 -1
  98. package/dist/locales/de.js +1 -1
  99. package/dist/locales/es.js +1 -1
  100. package/dist/locales/fr.js +1 -1
  101. package/dist/locales/hi.js +1 -1
  102. package/dist/locales/id.js +1 -1
  103. package/dist/locales/it.js +1 -1
  104. package/dist/locales/ja.js +1 -1
  105. package/dist/locales/ko.js +1 -1
  106. package/dist/locales/nl.js +1 -1
  107. package/dist/locales/pl.js +1 -1
  108. package/dist/locales/pt.js +1 -1
  109. package/dist/locales/ru.js +1 -1
  110. package/dist/locales/th.js +1 -1
  111. package/dist/locales/tr.js +1 -1
  112. package/dist/locales/vi.js +1 -1
  113. package/dist/locales/zh-hans.js +1 -1
  114. package/dist/locales/zh-hant.js +1 -1
  115. package/dist/styles.css +1 -1
  116. package/dist/tailwind.css +131 -6
  117. package/package.json +2 -2
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 CDGet <jooy2.contact@gmail.com> (https://cdget.com).
3
+ Copyright (c) 2025 CDGet (https://cdget.com).
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -12,27 +12,27 @@ Live previews and full props for every component. This README is just the quick
12
12
 
13
13
  ---
14
14
 
15
- **Neba UI is a React component library for building application interfaces.** It gives you the pieces a real product needs — buttons and form fields, menus and dialogs, tables and tabs, progress and notifications already styled, already accessible, and already agreeing with each other.
15
+ **Neba UI is a React component library for building application interfaces.** About 130 components, from buttons and form fields through menus, dialogs, tables and charts. They are styled and accessible out of the box, and they agree with each other because they draw from one set of props.
16
16
 
17
17
  You install one package, add one line to your CSS, and import components. There is nothing to configure, no theme object to assemble, and no per-component styling decisions to make before you can ship a screen.
18
18
 
19
- - **A broad component set, still growing** enough to build a whole screen without reaching elsewhere.
20
- - **One shared vocabulary** `size`, `color`, `variant`, `density`, `elevation`. An `md` is the same height on every control; `primary` is the same colour everywhere.
21
- - **Accessible by construction** real roles, labels, focus management and keyboard support, not `div`s with click handlers.
22
- - **Dark mode with no work** follows the system, and can be forced either way per subtree.
23
- - **A design language, not a theme file** a translucent acrylic surface with a hairline edge, one deliberate motion signature, and shadows that are opt-in.
24
- - **ESM only**, TypeScript declarations included, and genuinely tree-shakeable every component compiles to its own module, and importing one costs about what one costs. A `Button` is ~5 kB gzipped including its Base UI parts, a `Chip` is ~3 kB, and a twelve-component app is ~67 kB; the whole library, all one hundred and twenty-six exports at once, is ~215 kB.
25
- - **Two runtime dependencies** Base UI, and `highlight.js`, which only [CodeBlock](https://neba.cdget.com/components/display/code-block) reaches and only through a dynamic import, so it never lands in a bundle that did not ask for it. React 18 or 19, Node.js 18 or later.
19
+ - **A broad component set, still growing**: enough to build a whole screen without reaching elsewhere.
20
+ - **One shared vocabulary**: `size`, `color`, `variant`, `density`, `elevation`. An `md` is the same height on every control; `primary` is the same colour everywhere.
21
+ - **Accessible by construction**: real roles, labels, focus management and keyboard support, not `div`s with click handlers.
22
+ - **Dark mode with no work**: follows the system, and can be forced either way per subtree.
23
+ - **A design language, not a theme file**: a translucent acrylic surface with a hairline edge, one deliberate motion signature, and shadows that are opt-in.
24
+ - **ESM only**, TypeScript declarations included, and genuinely tree-shakeable: every component compiles to its own module, and importing one costs about what one costs. A `Button` is ~5 kB gzipped including its Base UI parts, a `Chip` is ~3 kB, and a twelve-component app is ~70 kB; the whole library, all one hundred and seventy-five exports at once, is ~265 kB.
25
+ - **Two runtime dependencies**: Base UI, and `highlight.js`, which only [CodeBlock](https://neba.cdget.com/components/display/code-block) reaches and only through a dynamic import, so it never lands in a bundle that did not ask for it. React 18 or 19, Node.js 18 or later.
26
26
 
27
27
  ## Documentation
28
28
 
29
- Everything is documented at **[neba.cdget.com](https://neba.cdget.com)**, where the previews are not screenshots they are the components, running in the page.
29
+ Everything is documented at **[neba.cdget.com](https://neba.cdget.com)**, where the previews are not screenshots. They are the components, running in the page.
30
30
 
31
31
  | Page | What you will find |
32
32
  | --- | --- |
33
33
  | [**Getting started**](https://neba.cdget.com/guide/getting-started) | Install and setup, end to end. |
34
34
  | [**All components**](https://neba.cdget.com/components/) | Every component, one page each: live previews and the full props table. |
35
- | [**Examples**](https://neba.cdget.com/examples/overview) | A whole sample screen explained block by block, plus three concept screens a landing page, an admin dashboard and a sign-up flow. |
35
+ | [**Examples**](https://neba.cdget.com/examples/overview) | A whole sample screen explained block by block, plus three concept screens: a landing page, an admin dashboard and a sign-up flow. |
36
36
  | [**Design language**](https://neba.cdget.com/design/design-language) | Why a Neba surface looks and behaves the way it does. |
37
37
  | [**Prop conventions**](https://neba.cdget.com/design/prop-conventions) | The shared vocabulary every component draws from. |
38
38
  | [**Color**](https://neba.cdget.com/design/color) | The token families, and how to theme them. |
@@ -48,7 +48,7 @@ npm install neba
48
48
  pnpm add neba
49
49
  ```
50
50
 
51
- `react` and `react-dom` are peer dependencies React 18 or 19. Neba uses the copy your project already has, and npm 7 and later will install them alongside it if it has none.
51
+ `react` and `react-dom` are peer dependencies: React 18 or 19. Neba uses the copy your project already has, and npm 7 and later will install them alongside it if it has none.
52
52
 
53
53
  ### Setup
54
54
 
@@ -58,11 +58,11 @@ Add one line to your app's CSS entry point:
58
58
  @import 'neba/styles.css';
59
59
  ```
60
60
 
61
- `neba/styles.css` is finished CSS the design tokens, the compiled rules for every utility class the components use, and a small reset whose every rule is specificity 0 so your own styles always win. [Tailwind CSS](https://tailwindcss.com) v4 builds this package; it does not have to be installed in yours.
61
+ `neba/styles.css` is finished CSS: the design tokens, the compiled rules for every utility class the components use, and a small reset whose every rule is specificity 0 so your own styles always win. [Tailwind CSS](https://tailwindcss.com) v4 builds this package; it does not have to be installed in yours.
62
62
 
63
63
  That is the whole setup. No provider is required at the root, no theme object, no config file.
64
64
 
65
- If your project already runs Tailwind v4, import `neba/tailwind.css` instead the token sheet, which registers the package as a style source so your own build generates the utilities in the same pass as your app's:
65
+ If your project already runs Tailwind v4, import `neba/tailwind.css` instead: the token sheet, which registers the package as a style source so your own build generates the utilities in the same pass as your app's:
66
66
 
67
67
  ```css
68
68
  @import 'tailwindcss';
@@ -88,11 +88,11 @@ export default function SignIn() {
88
88
 
89
89
  ### Next.js and React Server Components
90
90
 
91
- Every component carries `'use client'`, so it can be imported straight into a Server Component no wrapper, no `transpilePackages` entry. The directive marks a boundary, not a page: the page stays a Server Component and only the components it renders reach the browser. The ordinary rule about that boundary still applies an event handler defined in a Server Component cannot be passed across it.
91
+ Every component carries `'use client'`, so it can be imported straight into a Server Component: no wrapper, no `transpilePackages` entry. The directive marks a boundary, not a page: the page stays a Server Component and only the components it renders reach the browser. The ordinary rule about that boundary still applies: an event handler defined in a Server Component cannot be passed across it.
92
92
 
93
93
  The `neba` barrel and `neba/locales` are deliberately left unmarked, so a Server Component importing the barrel reaches the components behind it rather than a boundary of its own, and `registerMessages` stays a plain function. Bundlers that do not implement Server Components ignore the directive entirely.
94
94
 
95
- A few components provide context and are mounted once, near the root, only if you use them `ToastProvider` (paired with the `useToast()` hook) and `TooltipProvider`.
95
+ A few components provide context and are mounted once, near the root, only if you use them: `ToastProvider` (paired with the `useToast()` hook) and `TooltipProvider`.
96
96
 
97
97
  Every component is also its own entry point, named after its folder:
98
98
 
@@ -101,11 +101,11 @@ import { Button } from 'neba/button';
101
101
  import { TextField } from 'neba/text-field';
102
102
  ```
103
103
 
104
- Both forms produce the same bundle. The root barrel is the one to reach for; the subpath is there for a build that would rather not parse a hundred and ninety-eight modules to keep five, and as an escape hatch for a bundler that does not honour `sideEffects`.
104
+ Both forms produce the same bundle. The root barrel is the one to reach for; the subpath is there for a build that would rather not parse three hundred modules to keep five, and as an escape hatch for a bundler that does not honour `sideEffects`.
105
105
 
106
106
  ### Languages
107
107
 
108
- Neba writes very little text of its own a Button says what you hand it but a few components have to invent a string: the label on a Dialog's close button, the word under a chat message that says it was read, the sentence a screen reader hears after a link that opens a new tab.
108
+ Neba writes very little text of its own (a Button says what you hand it) but a few components have to invent a string: the label on a Dialog's close button, the word under a chat message that says it was read, the sentence a screen reader hears after a link that opens a new tab.
109
109
 
110
110
  Those ship in English. Eighteen other languages are included in the package and none of them is in your bundle until you say so:
111
111
 
@@ -121,9 +121,9 @@ Call it once, at module scope, before your first render. Then a `locale` prop tr
121
121
  <Dialog locale="ko" title="설정" showClose />
122
122
  ```
123
123
 
124
- A registered language costs about 1.9 kB gzipped and you pay only for the ones you name. Tags are matched by script, then by region, then by language registering `ko` answers `ko-KR`, and `zhHans` registered as `zh-hans` answers `zh-CN` and a bare `zh`. Available: `ko`, `ja`, `zhHans`, `zhHant`, `es`, `pt`, `fr`, `de`, `it`, `nl`, `pl`, `ru`, `tr`, `ar`, `hi`, `id`, `vi`, `th`, each also its own entry point (`neba/locales/ko`).
124
+ A registered language costs about 2.8 kB gzipped and you pay only for the ones you name. Tags are matched by script, then by region, then by language: registering `ko` answers `ko-KR`, and `zhHans` registered as `zh-hans` answers `zh-CN` and a bare `zh`. Available: `ko`, `ja`, `zhHans`, `zhHant`, `es`, `pt`, `fr`, `de`, `it`, `nl`, `pl`, `ru`, `tr`, `ar`, `hi`, `id`, `vi`, `th`, each also its own entry point (`neba/locales/ko`).
125
125
 
126
- Anything the platform already knows month names, weekday names, AM/PM, number and date formats comes from `Intl` and needs no registration. And every string a component invents also has a prop that overrides it, so a language Neba does not carry is never a dead end.
126
+ Anything the platform already knows (month names, weekday names, AM/PM, number and date formats) comes from `Intl` and needs no registration. And every string a component invents also has a prop that overrides it, so a language Neba does not carry is never a dead end.
127
127
 
128
128
  ### One place for your defaults
129
129
 
@@ -138,7 +138,7 @@ import { NebaProvider } from 'neba';
138
138
  </NebaProvider>;
139
139
  ```
140
140
 
141
- Optional, and every component works without it. It fills in `size`, `density`, `variant` and `locale` where a call site left them out the call site always wins owns the colour scheme (`useColorScheme()`, plus a `colorSchemeScript()` for the first-paint flash), and sets the writing direction. `color` and `elevation` are deliberately not defaultable; [the guide](https://neba.cdget.com/guide/provider) says why.
141
+ Optional, and every component works without it. It fills in `size`, `density`, `variant` and `locale` where a call site left them out (the call site always wins) owns the colour scheme (`useColorScheme()`, plus a `colorSchemeScript()` for the first-paint flash), and sets the writing direction. `color` and `elevation` are deliberately not defaultable; [the guide](https://neba.cdget.com/guide/provider) says why.
142
142
 
143
143
  ### Hooks
144
144
 
@@ -153,7 +153,7 @@ const desktop = useBreakpoint('lg');
153
153
  useShortcut('Mod+K', onOpen);
154
154
  ```
155
155
 
156
- `useDisclosure`, `useMediaQuery`, `useBreakpoint`, `usePrefersReducedMotion`, `useElementSize`, `useOnScreen`, `useShortcut`. Everything here is machinery the library needed for itself there is no general-purpose hook collection, and there is not going to be one. Full notes in [the hooks guide](https://neba.cdget.com/guide/hooks).
156
+ `useDisclosure`, `useMediaQuery`, `useBreakpoint`, `useCurrentBreakpoint`, `useBreakpointValue`, `usePrefersReducedMotion`, `useElementSize`, `useOnScreen`, `useShortcut`. Everything here is machinery the library needed for itself: there is no general-purpose hook collection, and there is not going to be one. Full notes in [the hooks guide](https://neba.cdget.com/guide/hooks).
157
157
 
158
158
  ### The shared prop vocabulary
159
159
 
@@ -164,10 +164,10 @@ The reason a Neba screen looks composed rather than assembled is that the props
164
164
  | `size` | `xs` `sm` `md` `lg` `xl` | The control's scale. `md` is the desktop default. |
165
165
  | `color` | `primary` `secondary` `success` `warning` `danger` `info` | The semantic colour family. |
166
166
  | `variant` | `solid` `outline` `text` | How much visual weight the surface carries. |
167
- | `density` | `default` `compact` | Padding only never the height, never the type scale, so a compact control still lines up with a default one. |
167
+ | `density` | `default` `compact` | Padding only: never the height, never the type scale, so a compact control still lines up with a default one. |
168
168
  | `elevation` | `0` `1` `2` `3` | How far a surface floats off the page. `0` is the default and means no shadow at all. |
169
169
 
170
- Placement props are logical, not physical `start`/`end` rather than `left`/`right` so layouts flip correctly under RTL. The full rules are in [**Prop conventions**](https://neba.cdget.com/design/prop-conventions).
170
+ Placement props are logical, not physical (`start`/`end` rather than `left`/`right`) so layouts flip correctly under RTL. The full rules are in [**Prop conventions**](https://neba.cdget.com/design/prop-conventions).
171
171
 
172
172
  ```tsx
173
173
  <Button size="sm" color="danger" variant="outline">Delete</Button>
@@ -176,23 +176,23 @@ Placement props are logical, not physical — `start`/`end` rather than `left`/`
176
176
 
177
177
  ### Components
178
178
 
179
- **Inputs** Button, IconButton, ButtonGroup, SegmentedButton, Toggle, ToggleGroup, Form, Fieldset, FloatingActionButton (with FloatingAction), TextField, NumberField, OtpField, Select, Combobox, TreeSelect, Checkbox, RadioGroup, Switch, Slider, Rating, Menu (with submenus, checkbox and radio items), ContextMenu, Menubar, NavigationMenu, CommandPalette, FilePicker, Transfer, Pagination, BottomNavigation, FloatingBottomNavigation, ColorPicker, Calendar, DatePicker, TimePicker, DateTimePicker, DateRangePicker
179
+ **Inputs**: Button, IconButton, ButtonGroup, SegmentedButton, Toggle, ToggleGroup, Form, Fieldset, FloatingActionButton (with FloatingAction), TextField, NumberField, OtpField, Select, Combobox, TreeSelect, Checkbox, RadioGroup, Switch, Slider, Rating, Menu (with submenus, checkbox and radio items), ContextMenu, Menubar, NavigationMenu, CommandPalette, FilePicker, Transfer, Pagination, BottomNavigation, FloatingBottomNavigation, ColorPicker, Calendar, DatePicker, TimePicker, DateTimePicker, DateRangePicker
180
180
 
181
- **Surfaces** Box, Card, Accordion, Collapsible, Tabs, Carousel, Toolbar, Pill, Spoiler, HowToSteps, ChatBubble, Drawer, Popover, Mockup, WindowPane, HoverCard
181
+ **Surfaces**: Box, Card, Accordion, Collapsible, Tabs, Carousel, Toolbar, Pill, Spoiler, HowToSteps, ChatBubble, Drawer, Popover, Mockup, WindowPane, HoverCard
182
182
 
183
- **Display** Typography, TextLink, Blockquote, Highlight, Divider, Chip, Badge, Avatar, AppLogo, Icon, Image, Gallery, Shortcut, List, DataList, Table, DataTable, CodeBlock, Timeline, Breadcrumb, Anchor, TreeView, VisuallyHidden
183
+ **Display**: Typography, TextLink, Blockquote, Highlight, Divider, Chip, Badge, Avatar, AppLogo, Icon, Image, Gallery, Shortcut, List, DataList, Table, DataTable, CodeBlock, Timeline, Breadcrumb, Anchor, TreeView, VisuallyHidden
184
184
 
185
- **Charts** Statistic, Sparkline, LineChart, AreaChart, BarChart, PieChart, ScatterChart, TimelineChart, HeatmapChart, GaugeChart
185
+ **Charts**: Statistic, Sparkline, LineChart, AreaChart, BarChart, PieChart, ScatterChart, TimelineChart, HeatmapChart, GaugeChart
186
186
 
187
- **Feedback** Alert, Dialog, Confirm, Popconfirm, Toast, Tooltip, Overlay, Skeleton, Empty, ProgressLinear, ProgressCircular, ProgressBox, Meter, Tour
187
+ **Feedback**: Alert, Dialog, Confirm, Popconfirm, Toast, Tooltip, Overlay, Skeleton, Empty, ProgressLinear, ProgressCircular, ProgressBox, Meter, Tour
188
188
 
189
- **Layout** PageLayout (with Header, Footer and Sidebar), Container, Grid (with GridContainer), Flex, Panes, Stack, Show, AspectRatio, Portal, ScrollZone, ScrollArea
189
+ **Layout**: PageLayout (with Header, Footer and Sidebar), Container, Grid (with GridContainer), Flex, Panes, Stack, Show, AspectRatio, Portal, ScrollZone, ScrollArea
190
190
 
191
- **Transitions** AnimateFade, AnimateGrow, AnimateZoom, AnimateSlide, AnimateRotate, AnimateBlink, AnimateReveal, AnimateFloat, AnimateShake, AnimateAppear, AnimateSplit, AnimateTyping, AnimateScramble, AnimateCounter, AnimateLighting, AnimateMarquee, AnimateHeadline
191
+ **Transitions**: AnimateFade, AnimateGrow, AnimateZoom, AnimateSlide, AnimateRotate, AnimateBlink, AnimateReveal, AnimateFloat, AnimateShake, AnimateAppear, AnimateSplit, AnimateTyping, AnimateScramble, AnimateCounter, AnimateLighting, AnimateMarquee, AnimateHeadline
192
192
 
193
- **Recently added** Gallery, Flex, Show, the six new `Animate*` (Reveal, Float, Shake, Split, Counter, Scramble), Stack, TreeSelect, Calendar, Image, Confirm, Popconfirm, VisuallyHidden, Portal, GaugeChart, CommandPalette, Tour, Transfer, Anchor, DataList, NavigationMenu, Menubar, Form (with Fieldset), ScrollArea, HoverCard, Meter, Toggle (with ToggleGroup), CodeBlock, HowToSteps, ScrollZone, FloatingBottomNavigation, WindowPane, Collapsible, Rating, BottomNavigation, FloatingActionButton, the charts (Sparkline, LineChart, AreaChart, BarChart, PieChart, ScatterChart, TimelineChart, HeatmapChart), DataTable, Empty, Mockup, the `Animate*` wrappers, ColorPicker, Drawer, Popover, Skeleton, AspectRatio
193
+ **Added in the last two releases**: Gallery, Flex, Show, Stack and the six new `Animate*` (Reveal, Float, Shake, Split, Counter, Scramble) in 1.12.0; Calendar, TreeSelect, Image, Confirm, Popconfirm and VisuallyHidden in 1.11.0. The [changelog](https://neba.cdget.com/changelog) has the rest.
194
194
 
195
- Each one has its own page live previews, every prop, and the variations worth seeing under [**All components**](https://neba.cdget.com/components/).
195
+ Each one has its own page (live previews, every prop, and the variations worth seeing) under [**All components**](https://neba.cdget.com/components/).
196
196
 
197
197
  ### Theming and dark mode
198
198
 
@@ -204,7 +204,7 @@ Colours, radii, and surface strengths are CSS custom properties declared in the
204
204
  }
205
205
  ```
206
206
 
207
- Dark mode responds to `prefers-color-scheme` on its own. To force it, put `.dark` or `[data-theme='dark']` (or `'light'`) on any ancestor it applies to that subtree, so a dark panel on a light page is one attribute.
207
+ Dark mode responds to `prefers-color-scheme` on its own. To force it, put `.dark` or `[data-theme='dark']` (or `'light'`) on any ancestor: it applies to that subtree, so a dark panel on a light page is one attribute.
208
208
 
209
209
  Adding a whole new colour family is two edits: an entry in `NebaColor` and five tokens; everything else derives from them.
210
210
 
@@ -214,7 +214,7 @@ Clone the repository and install dependencies, then:
214
214
 
215
215
  | Command | What it does |
216
216
  | --- | --- |
217
- | `npm run docs:dev` | Starts the documentation site (`docs/`) locally every component, rendered live, with HMR. |
217
+ | `npm run docs:dev` | Starts the documentation site (`docs/`) locally: every component, rendered live, with HMR. |
218
218
  | `npm test` | Runs the test suite once. |
219
219
  | `npm run test:watch` | Runs the test suite in watch mode. |
220
220
  | `npm run typecheck` | Type-checks the library, the tests, and the docs. |
@@ -226,16 +226,16 @@ All commands are run from the repository root.
226
226
 
227
227
  ### Project structure
228
228
 
229
- - `src/` the library source. Each component lives in `src/components/{name}/` and is re-exported from `src/index.ts`.
230
- - `src/internal/` what the library shares with itself: the size and spacing tables, the surface and focus-ring generators, the icons more than one component draws. Shipped, but not part of the public API.
231
- - `test/` the test suite, mirroring the `src/` tree.
232
- - `docs/` the VitePress documentation site, in English and Korean. It renders the real components from `src/`, so it is also where components are developed and eyeballed.
229
+ - `src/`: the library source. Each component lives in `src/components/{name}/` and is re-exported from `src/index.ts`.
230
+ - `src/internal/`: what the library shares with itself: the size and spacing tables, the surface and focus-ring generators, the icons more than one component draws. Shipped, but not part of the public API.
231
+ - `test/`: the test suite, mirroring the `src/` tree.
232
+ - `docs/`: the VitePress documentation site, in English and Korean. It renders the real components from `src/`, so it is also where components are developed and eyeballed.
233
233
 
234
234
  There is no separate demo app: `npm run docs:dev` is the develop-and-eyeball loop.
235
235
 
236
236
  ### Tests
237
237
 
238
- Tests run with [Vitest](https://vitest.dev) in browser mode, against a real headless browser driven by Playwright the components depend on browser APIs (`ResizeObserver`, the popover API, `dialog.showModal()`) that jsdom does not implement. Install the browser once before your first run:
238
+ Tests run with [Vitest](https://vitest.dev) in browser mode, against a real headless browser driven by Playwright. The components depend on browser APIs (`ResizeObserver`, the popover API, `dialog.showModal()`) that jsdom does not implement. Install the browser once before your first run:
239
239
 
240
240
  ```bash
241
241
  npx playwright install chromium
@@ -249,11 +249,13 @@ VITEST_BROWSER=firefox npm test
249
249
 
250
250
  CI runs the suite across Linux, Windows, and macOS in all three browser engines.
251
251
 
252
- Tests ship with the component they cover, in the same commit. Add a test at the path mirroring its source `src/components/button/Button.tsx` is covered by `test/components/button/Button.test.tsx`.
252
+ Tests ship with the component they cover, in the same commit. Add a test at the path mirroring its source: `src/components/button/Button.tsx` is covered by `test/components/button/Button.test.tsx`.
253
253
 
254
254
  ## Contributing
255
255
 
256
- Anyone can contribute to the project by reporting new issues or submitting a pull request. For more information, please see [CONTRIBUTING.md](CONTRIBUTING.md).
256
+ Anyone can contribute to the project by reporting new issues or submitting a pull request. For more information, please see [CONTRIBUTING.md](CONTRIBUTING.md). Participation is subject to the [Code of Conduct](CODE_OF_CONDUCT.md).
257
+
258
+ To report a security issue, please follow the process described in [SECURITY.md](SECURITY.md).
257
259
 
258
260
  ## License
259
261
 
@@ -31,6 +31,18 @@ export interface AccordionProps extends NebaStyleProps, Omit<React.ComponentProp
31
31
  dividers?: boolean;
32
32
  /** Unavailable. Every section stops answering. */
33
33
  disabled?: boolean;
34
+ /**
35
+ * Which heading every section's header is, in the page's own outline. An
36
+ * accordion under an `<h2>` wants `3`; one under an `<h3>` wants `4`.
37
+ *
38
+ * It belongs to the stack rather than to a fold in it — the sections are
39
+ * siblings, and a run of headings at different levels is an outline that
40
+ * lies. A `title` that is itself a styled heading nests one heading inside
41
+ * another, which this prop is the way out of: set the level here and pass
42
+ * plain text.
43
+ * @default 3
44
+ */
45
+ headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
34
46
  /**
35
47
  * Keeps closed panels in the DOM so the browser's own page search can find and
36
48
  * open them. Overrides `keepMounted`.
@@ -65,6 +77,12 @@ export interface AccordionItemProps extends Omit<React.ComponentPropsWithoutRef<
65
77
  * other. The same shape ListItem uses.
66
78
  */
67
79
  action?: React.ReactNode;
80
+ /**
81
+ * Cuts the title and the subtitle off after this many lines, with an
82
+ * ellipsis. Unset, both wrap — an FAQ's title is a sentence rather than a
83
+ * label, and ending it in an ellipsis loses the question.
84
+ */
85
+ lines?: number;
68
86
  /** Unavailable. This section stops folding; the rest keep working. */
69
87
  disabled?: boolean;
70
88
  /** The body. */
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as a from"react";import{Accordion as t}from"@base-ui/react/accordion";import{boxPaddingXClasses as l,boxPaddingYClasses as r}from"../box/Box.js";import{ChevronIcon as i}from"../../internal/icons.js";import{cx as s,focusRingClasses as o,gapClasses as d,hasContent as c,iconClasses as m,metaTextClasses as f,radiusClasses as u,sheetBodyClasses as h,sheetHeaderGapClasses as b,sheetTitleClasses as x,surfaceClasses as p,surfaceSlots as v,transitionClasses as g}from"../../internal/styles.js";import{useStyleDefaults as N}from"../../internal/defaults.js";const j=/*@__PURE__*/a.createContext({size:"md",density:"default",dividers:!0}),y={solid:[p,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[p,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},w={xs:u.xs,sm:u.xs,md:u.sm,lg:u.sm,xl:u.md};export const Accordion=/*@__PURE__*/a.forwardRef(function(n,l){const{variant:r="outline",size:i="md",color:o="primary",density:d="default",elevation:c=0,multiple:m=!1,value:f,defaultValue:h,onValueChange:b,dividers:x=!0,disabled:p=!1,hiddenUntilFound:w=!1,keepMounted:k=!1,className:z,style:C,children:V,...$}=N(n,["size","density","variant"]),_=a.useMemo(()=>({size:i,density:d,dividers:x}),[i,d,x]),A=s("flex flex-col",u[i],y[r],g,x?"overflow-hidden [&>div+div]:border-t [&>div+div]:[border-color:var(--n-line)]":"p-1",z??"");return e(j.Provider,{value:_,children:e(t.Root,{ref:l,multiple:m,value:f,defaultValue:h,onValueChange:e=>b?.(e),disabled:p,hiddenUntilFound:w,keepMounted:k,className:A,style:{...v(o,c),...C},...$,children:V})})});export const AccordionItem=/*@__PURE__*/a.forwardRef(function({value:u,title:p,subtitle:v,startIcon:N,action:y,disabled:k=!1,className:z,children:C,...V},$){const{size:_,density:A,dividers:I}=a.useContext(j),M=l[A][_],R=r[A][_];return n(t.Item,{ref:$,value:u,disabled:k,className:s("flex flex-col",z??""),...V,children:[n(t.Header,{className:"m-0 flex w-full items-center [font:inherit]",children:[n(t.Trigger,{className:s("flex min-w-0 flex-1 cursor-pointer items-center text-start",M,R,d[_],g,m,o,I?"":w[_],"hover:bg-(--n-soft)","data-[panel-open]:text-(--n-accent)","disabled:cursor-not-allowed disabled:bg-transparent disabled:text-(--neba-disabled-fg)"),children:[c(N)?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:N}):null,n("span",{className:`flex min-w-0 flex-1 flex-col ${b[_]}`,children:[c(p)?e("span",{className:`truncate font-semibold ${x[_]}`,children:p}):null,c(v)?e("span",{className:`truncate text-(--neba-muted-fg) ${f[_]}`,children:v}):null]}),e("span",{className:["flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)","[transition:rotate_var(--neba-duration)_var(--neba-ease)]","data-[panel-open]:rotate-180"].join(" "),children:e(i,{})})]}),c(y)?e("span",{className:`flex shrink-0 items-center ${M}`,children:y}):null]}),e(t.Panel,{className:["h-(--accordion-panel-height) overflow-hidden","[transition:height_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:h-0 data-[ending-style]:h-0"].join(" "),children:e("div",{className:["text-(--neba-muted-fg)",h[_],M,"compact"===A?"pb-2":"pb-4"].join(" "),children:C})})]})});
1
+ "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as a from"react";import{Accordion as t}from"@base-ui/react/accordion";import{boxPaddingXClasses as l,boxPaddingYClasses as i}from"../box/Box.js";import{ChevronIcon as r}from"../../internal/icons.js";import{clampClasses as s,cx as d,focusRingClasses as o,gapClasses as c,hasContent as m,iconClasses as f,metaTextClasses as h,radiusClasses as u,sheetBodyClasses as b,sheetHeaderGapClasses as x,sheetTitleClasses as v,surfaceClasses as p,surfaceSlots as g,transitionClasses as N}from"../../internal/styles.js";import{useStyleDefaults as j}from"../../internal/defaults.js";const y=/*@__PURE__*/a.createContext({size:"md",density:"default",dividers:!0,headingLevel:3}),w={solid:[p,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[p,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},k={xs:u.xs,sm:u.xs,md:u.sm,lg:u.sm,xl:u.md};export const Accordion=/*@__PURE__*/a.forwardRef(function(n,l){const{variant:i="outline",size:r="md",color:s="primary",density:o="default",elevation:c=0,multiple:m=!1,value:f,defaultValue:h,onValueChange:b,dividers:x=!0,headingLevel:v=3,disabled:p=!1,hiddenUntilFound:k=!1,keepMounted:z=!1,className:C,style:L,children:V,..._}=j(n,["size","density","variant"]),A=a.useMemo(()=>({size:r,density:o,dividers:x,headingLevel:v}),[r,o,x,v]),I=d("flex flex-col",u[r],w[i],N,x?"overflow-hidden [&>div+div]:border-t [&>div+div]:[border-color:var(--n-line)]":"p-1",C??"");return e(y.Provider,{value:A,children:e(t.Root,{ref:l,multiple:m,value:f,defaultValue:h,onValueChange:e=>b?.(e),disabled:p,hiddenUntilFound:k,keepMounted:z,className:I,style:{...g(s,c),...L},..._,children:V})})});export const AccordionItem=/*@__PURE__*/a.forwardRef(function({value:u,title:p,subtitle:g,startIcon:j,action:w,lines:z,disabled:C=!1,className:L,children:V,..._},A){const{size:I,density:M,dividers:R,headingLevel:$}=a.useContext(y),F=z?s(z):"",P=l[M][I],U=i[M][I];return n(t.Item,{ref:A,value:u,disabled:C,className:d("flex flex-col",L??""),..._,children:[n(t.Header,{className:"m-0 flex w-full items-center [font:inherit]",render:a.createElement(`h${$}`),children:[n(t.Trigger,{className:d("flex min-w-0 flex-1 cursor-pointer items-center text-start",P,U,c[I],N,f,o,R?"":k[I],"hover:bg-(--n-soft)","data-[panel-open]:text-(--n-accent)","disabled:cursor-not-allowed disabled:bg-transparent disabled:text-(--neba-disabled-fg)"),children:[m(j)?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:j}):null,n("span",{className:`flex min-w-0 flex-1 flex-col ${x[I]}`,children:[m(p)?e("span",{className:d("font-semibold",v[I],F),children:p}):null,m(g)?e("span",{className:d("text-(--neba-muted-fg)",h[I],F),children:g}):null]}),e("span",{className:["flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)","[transition:rotate_var(--neba-duration)_var(--neba-ease)]","data-[panel-open]:rotate-180"].join(" "),children:e(r,{})})]}),m(w)?e("span",{className:`flex shrink-0 items-center ${P}`,children:w}):null]}),e(t.Panel,{className:["h-(--accordion-panel-height) overflow-hidden","[transition:height_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:h-0 data-[ending-style]:h-0"].join(" "),children:e("div",{className:["text-(--neba-muted-fg)",b[I],P,"compact"===M?"pb-2":"pb-4"].join(" "),children:V})})]})});
@@ -1 +1 @@
1
- "use client";import{jsx as e}from"react/jsx-runtime";import*as n from"react";import{anchorMessages as r,useMessages as t}from"../../internal/i18n.js";import{controlTextLeadingClasses as o,cx as a,focusRingClasses as l,transitionClasses as i}from"../../internal/styles.js";import{useStyleDefaults as c}from"../../internal/defaults.js";const s={default:{xs:"py-1",sm:"py-1",md:"py-1.5",lg:"py-1.5",xl:"py-2"},compact:{xs:"py-0.5",sm:"py-0.5",md:"py-1",lg:"py-1",xl:"py-1"}},m={xs:8,sm:10,md:12,lg:14,xl:16},d=["block min-w-0 truncate no-underline","text-(--neba-muted-fg)",i,l,"hover:text-(--neba-fg)","aria-[current=location]:font-medium aria-[current=location]:text-(--n-accent)"].join(" "),u=["border-s [border-color:transparent]","[transition:border-color_var(--neba-duration)_var(--neba-ease)]","aria-[current=location]:[border-color:var(--n-accent)]"].join(" ");export const Anchor=/*@__PURE__*/n.forwardRef(function(l,i){const{items:f,activeHref:p,onActiveChange:h,offset:g=0,container:v,rail:b=!0,size:y="md",color:x="primary",density:w="default",locale:j,label:E,className:H,style:N,...R}=c(l,["size","density","locale"]),z=t(r,j),[A,L]=n.useState(null),B=void 0!==p,C=B?p:A,$=n.useRef(h);$.current=h;const F=n.useRef(f);F.current=f;const I=f.map(e=>e.href).join("\0");return n.useEffect(()=>{if(B)return;const e=v?.current??window;let n=0,r=null;const t=()=>{n=0;const e=function(e,n,r){const t=(r?r.getBoundingClientRect().top:0)+n+1;let o=null;for(const n of e){const e=document.getElementById(n.href.replace(/^#/,""));e&&e.getBoundingClientRect().top<=t&&(o=n.href)}return(r?r.scrollTop+r.clientHeight>=r.scrollHeight-2:window.innerHeight+window.scrollY>=document.documentElement.scrollHeight-2)&&e.length>0?e[e.length-1].href:o}(F.current,g,v?.current??null);e!==r&&(r=e,L(e),$.current?.(e))},o=()=>{0===n&&(n=requestAnimationFrame(t))};return t(),e.addEventListener("scroll",o,{passive:!0}),window.addEventListener("resize",o,{passive:!0}),()=>{0!==n&&cancelAnimationFrame(n),e.removeEventListener("scroll",o),window.removeEventListener("resize",o)}},[I,g,v,B]),e("nav",{ref:i,"aria-label":E??z.label,className:a("min-w-0",H??""),style:{"--n-accent":`var(--neba-${x}-accent)`,"--n-ring":`var(--neba-${x}-ring)`,...N},...R,children:e("ul",{className:a("m-0 flex list-none flex-col p-0",b?"border-s [border-color:var(--neba-border)]":""),children:f.map(n=>e("li",{className:b?"[margin-inline-start:-1px]":"",children:e("a",{href:n.href,"aria-current":C===n.href?"location":void 0,className:a(d,o[y],s[w][y],b?`${u} ps-3`:""),style:{marginInlineStart:n.depth?n.depth*m[y]:void 0},children:n.label})},n.href))})})});
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import*as n from"react";import{anchorMessages as r,useMessages as t}from"../../internal/i18n.js";import{controlTextLeadingClasses as o,cx as a,focusRingClasses as l,transitionClasses as i}from"../../internal/styles.js";import{useStyleDefaults as c}from"../../internal/defaults.js";const s={default:{xs:"py-1",sm:"py-1",md:"py-1.5",lg:"py-1.5",xl:"py-2"},compact:{xs:"py-0.5",sm:"py-0.5",md:"py-1",lg:"py-1",xl:"py-1"}},d={xs:8,sm:10,md:12,lg:14,xl:16},m=["block min-w-0 truncate no-underline","text-(--neba-muted-fg)",i,l,"hover:text-(--neba-fg)","aria-[current=location]:font-medium aria-[current=location]:text-(--n-accent)"].join(" "),u=["border-s [border-color:transparent]","[transition:border-color_var(--neba-duration)_var(--neba-ease)]","aria-[current=location]:[border-color:var(--n-accent)]"].join(" ");function f(e,n){const r=n.get(e);if(r?.isConnected)return r;const t=document.getElementById(e.replace(/^#/,""));return t?n.set(e,t):n.delete(e),t}export const Anchor=/*@__PURE__*/n.forwardRef(function(l,i){const{items:p,activeHref:h,onActiveChange:g,offset:v=0,container:b,rail:y=!0,size:x="md",color:w="primary",density:j="default",locale:E,label:H,className:N,style:R,...z}=c(l,["size","density","locale"]),A=t(r,E),[C,L]=n.useState(null),B=void 0!==h,$=B?h:C,F=n.useRef(g),I=n.useRef(p);n.useEffect(()=>{F.current=g,I.current=p});const S=p.map(e=>e.href).join("\0");return n.useEffect(()=>{if(B)return;const e=b?.current??window,n=new Map;let r=0,t=null;const o=()=>{r=0;const e=function(e,n,r,t){const o=(r?r.getBoundingClientRect().top:0)+n+1;let a=null;for(const n of e){const e=f(n.href,t);e&&e.getBoundingClientRect().top<=o&&(a=n.href)}return(r?r.scrollTop+r.clientHeight>=r.scrollHeight-2:window.innerHeight+window.scrollY>=document.documentElement.scrollHeight-2)&&e.length>0?e[e.length-1].href:a}(I.current,v,b?.current??null,n);e!==t&&(t=e,L(e),F.current?.(e))},a=()=>{0===r&&(r=requestAnimationFrame(o))};return o(),e.addEventListener("scroll",a,{passive:!0}),window.addEventListener("resize",a,{passive:!0}),()=>{0!==r&&cancelAnimationFrame(r),e.removeEventListener("scroll",a),window.removeEventListener("resize",a)}},[S,v,b,B]),e("nav",{ref:i,"aria-label":H??A.label,className:a("min-w-0",N??""),style:{"--n-accent":`var(--neba-${w}-accent)`,"--n-ring":`var(--neba-${w}-ring)`,...R},...z,children:e("ul",{className:a("m-0 flex list-none flex-col p-0",y?"border-s [border-color:var(--neba-border)]":""),children:p.map(n=>e("li",{className:y?"[margin-inline-start:-1px]":"",children:e("a",{href:n.href,"aria-current":$===n.href?"location":void 0,className:a(m,o[x],s[j][x],y?`${u} ps-3`:""),style:{marginInlineStart:n.depth?n.depth*d[x]:void 0},children:n.label})},n.href))})})});
@@ -32,8 +32,8 @@ export interface AnimateMarqueeProps extends NebaAnimateProps, React.ComponentPr
32
32
  */
33
33
  copies?: number;
34
34
  /**
35
- * Stops while the pointer is on it, so something scrolling past can actually
36
- * be read or clicked.
35
+ * Stops while the pointer is on it, or while the focus is inside it, so
36
+ * something scrolling past can actually be read, clicked or tabbed to.
37
37
  * @default true
38
38
  */
39
39
  pauseOnHover?: boolean;
@@ -56,7 +56,9 @@ export interface AnimateMarqueeProps extends NebaAnimateProps, React.ComponentPr
56
56
  *
57
57
  * `pauseOnHover` is on by default and is not decoration: content moving past a
58
58
  * pointer cannot be clicked reliably, and a link inside a marquee that never
59
- * stops is a link nobody can follow.
59
+ * stops is a link nobody can follow. It answers the focus as well as the
60
+ * pointer, or the same link would be unreachable to whoever tabs to it — the
61
+ * strip would be carrying it off the screen while it was being read.
60
62
  *
61
63
  * Only the first copy is read out. The rest carry `aria-hidden`, or a screen
62
64
  * reader would announce everything on the strip as many times as it was laid
@@ -1 +1 @@
1
- "use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{isInfinite as a,lengthValue as r,useAnimationRun as n}from"../../internal/animate.js";import{observeResize as i}from"../../internal/observe.js";import{cx as s}from"../../internal/styles.js";export const AnimateMarquee=/*@__PURE__*/t.forwardRef(function({duration:o,delay:m=0,repeat:l="infinite",alternate:u,paused:c,trigger:d="mount",play:f,once:p=!0,threshold:h=.2,easing:v,orientation:g="horizontal",reverse:y=!1,speed:b=60,gap:j="2rem",copies:q=2,pauseOnHover:x=!0,className:M,style:N,children:R,...S},w){const A=n({trigger:d,play:f,once:p,threshold:h,paused:c,infinite:a(l)}),G=t.useRef(null),H=t.useRef(null),[$,k]=t.useState(0),z="vertical"===g;t.useEffect(()=>{const e=G.current,t=H.current;if(!e||!t)return;const a=()=>{const a=getComputedStyle(e),r=parseFloat(z?a.rowGap:a.columnGap)||0,n=z?t.offsetHeight:t.offsetWidth;k(n+r)};a();const r=i(t,a),n=i(e,a);return()=>{r(),n()}},[z,R]);const C=o??($>0?$/b*1e3:12e3);return e("div",{ref:e=>{G.current=e,A.ref(e),"function"==typeof w?w(e):w&&(w.current=e)},className:s("neba-marquee",z&&"neba-marquee-vertical",M),style:{"--n-anim-gap":r(j),...v?{"--n-anim-ease":v}:{},"--n-anim-duration":`${Math.round(C)}ms`,"--n-anim-delay":`${m}ms`,"--n-anim-repeat":"infinite"===l?"infinite":String(l),"--n-anim-direction":y?u?"alternate-reverse":"reverse":u?"alternate":"normal","--n-anim-state":A.state,...N},"data-neba-animation":"marquee","data-state":A.state,"data-pause-on-hover":x?"":void 0,...A.handlers,...S,children:Array.from({length:Math.max(1,q)},(t,a)=>(t=>e("div",{ref:0===t?H:void 0,className:"neba-marquee-track","aria-hidden":0===t?void 0:"true",children:R},t))(a))})});
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{isInfinite as a,lengthValue as r,useAnimationRun as n}from"../../internal/animate.js";import{observeResize as i}from"../../internal/observe.js";import{cx as s}from"../../internal/styles.js";export const AnimateMarquee=/*@__PURE__*/t.forwardRef(function({duration:o,delay:l=0,repeat:m="infinite",alternate:u,paused:c,trigger:d="mount",play:f,once:p=!0,threshold:h=.2,easing:v,orientation:g="horizontal",reverse:y=!1,speed:b=60,gap:j="2rem",copies:q=2,pauseOnHover:x=!0,className:M,style:N,children:R,...S},k){const w=n({trigger:d,play:f,once:p,threshold:h,paused:c,infinite:a(m)}),A=t.useRef(null),C=t.useRef(null),[G,H]=t.useState(0),$="vertical"===g;t.useEffect(()=>{const e=A.current,t=C.current;if(!e||!t)return;const a=()=>{const a=getComputedStyle(e),r=parseFloat($?a.rowGap:a.columnGap)||0,n=$?t.offsetHeight:t.offsetWidth;H(n+r)};a();const r=i(t,a),n=i(e,a);return()=>{r(),n()}},[$,j]);const z=o??(G>0?G/b*1e3:12e3),E=w.ref,F=t.useCallback(e=>{A.current=e,E(e),"function"==typeof k?k(e):k&&(k.current=e)},[k,E]);return e("div",{ref:F,className:s("neba-marquee",$&&"neba-marquee-vertical",M),style:{"--n-anim-gap":r(j),...v?{"--n-anim-ease":v}:{},"--n-anim-duration":`${Math.round(z)}ms`,"--n-anim-delay":`${l}ms`,"--n-anim-repeat":"infinite"===m?"infinite":String(m),"--n-anim-direction":y?u?"alternate-reverse":"reverse":u?"alternate":"normal","--n-anim-state":w.state,...N},"data-neba-animation":"marquee","data-state":w.state,"data-pause-on-hover":x?"":void 0,...w.handlers,...S,children:Array.from({length:Math.max(1,q)},(t,a)=>(t=>e("div",{ref:0===t?C:void 0,className:"neba-marquee-track","aria-hidden":0===t?void 0:"true",children:R},t))(a))})});
@@ -1 +1 @@
1
- "use client";import{jsx as e,Fragment as t,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{useRender as s}from"@base-ui/react/use-render";import{isInfinite as n,useAnimationRun as i,usePrefersReducedMotion as o}from"../../internal/animate.js";import{graphemesOf as l,textOf as c}from"../../internal/text.js";import{srOnlyClasses as m}from"../../internal/styles.js";const d="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&$@*";export const AnimateScramble=/*@__PURE__*/a.forwardRef(function({text:u,speed:p=18,tick:h=45,characters:f=d,duration:g,delay:x=0,repeat:j=1,paused:M,trigger:y="mount",play:v,once:N=!0,threshold:b=.2,locale:I,render:T,className:w,style:R,children:S,...A},E){const F=i({trigger:y,play:v,once:N,threshold:b,paused:M,infinite:n(j)}),k=o(),B=u??c(S),C=a.useMemo(()=>l(B,I),[B,I]),D=C.length,[G,H]=a.useState(0),[,J]=a.useReducer(e=>e+1,0),K=a.useMemo(()=>void 0!==g&&D>0?Math.max(1,g/D):1e3/Math.max(1,p),[g,p,D]);a.useEffect(()=>{if(!F.started||M)return;if(k||0===D)return void H(D);let e,t=0;const r=()=>{t+=1,H(t),t<D?e=setTimeout(r,K):clearInterval(a)};H(0);const a=setInterval(J,h);return e=setTimeout(r,x+K),()=>{clearTimeout(e),clearInterval(a)}},[F.started,M,k,D,K,h,x]);const L=f.length>0?f:d,O=C.map((e,t)=>t<G||""===e.trim()?e:L[Math.floor(Math.random()*L.length)]).join("");return s({render:T,ref:[E,F.ref],props:{...A,className:w,style:R,"data-neba-animation":"scramble","data-state":F.state,...F.handlers,children:r(t,{children:[e("span",{className:m,children:B}),e("span",{"aria-hidden":"true",className:"whitespace-pre-wrap",children:O})]})}})});
1
+ "use client";import{jsx as e,Fragment as t,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{useRender as s}from"@base-ui/react/use-render";import{isInfinite as n,useAnimationRun as i,usePrefersReducedMotion as l}from"../../internal/animate.js";import{graphemesOf as o,textOf as m}from"../../internal/text.js";import{srOnlyClasses as c}from"../../internal/styles.js";const u="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#%&$@*";export const AnimateScramble=/*@__PURE__*/a.forwardRef(function({text:d,speed:h=18,tick:p=45,characters:f=u,duration:g,delay:x=0,repeat:M=1,paused:j,trigger:y="mount",play:v,once:N=!0,threshold:b=.2,locale:I,render:T,className:w,style:R,children:S,...A},E){const F=i({trigger:y,play:v,once:N,threshold:b,paused:j,infinite:n(M)}),k=l(),B=d??m(S),C=a.useMemo(()=>o(B,I),[B,I]),D=C.length,[G,H]=a.useState(0),[J,K]=a.useReducer(e=>e+1,0),L=a.useMemo(()=>void 0!==g&&D>0?Math.max(1,g/D):1e3/Math.max(1,h),[g,h,D]);a.useEffect(()=>{if(!F.started||j)return;if(k||0===D)return void H(D);let e,t=0;const r=()=>{t+=1,H(t),t<D?e=setTimeout(r,L):clearInterval(a)};H(0);const a=setInterval(K,p);return e=setTimeout(r,x+L),()=>{clearTimeout(e),clearInterval(a)}},[F.started,j,k,D,L,p,x]);const O=f.length>0?f:u,P=C.map((e,t)=>t<G||""===e.trim()?e:O[function(e,t,r){let a=Math.imul(e+1,2246822507)^Math.imul(t+1,3266489909);return a^=a>>>15,a=Math.imul(a,625341585),a^=a>>>13,(a>>>0)%r}(J,t,O.length)]).join("");return s({render:T,ref:[E,F.ref],props:{...A,className:w,style:R,"data-neba-animation":"scramble","data-state":F.state,...F.handlers,children:r(t,{children:[e("span",{className:c,children:B}),e("span",{"aria-hidden":"true",className:"whitespace-pre-wrap",children:P})]})}})});
@@ -1 +1 @@
1
- "use client";import{jsx as e,Fragment as r,jsxs as n}from"react/jsx-runtime";import*as t from"react";import{useRender as s}from"@base-ui/react/use-render";import{initialsOf as a}from"../../internal/initials.js";import{controlHeightClasses as l,controlSlots as i,controlSquareClasses as o,cx as m,gapClasses as d,hasContent as c,srOnlyClasses as u,surfaceClasses as x,toLength as f,transitionClasses as g}from"../../internal/styles.js";import{useStyleDefaults as h}from"../../internal/defaults.js";const p={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1.0625rem]",lg:"text-[1.375rem]",xl:"text-[1.625rem]"},v={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1.0625rem]",lg:"text-[1.3125rem]",xl:"text-[1.5625rem]"},b={xs:"rounded-[0.375rem]",sm:"rounded-[0.4375rem]",md:"rounded-[0.5625rem]",lg:"rounded-[0.6875rem]",xl:"rounded-[0.875rem]"},w={solid:[x,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[x,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--n-accent) bg-(--n-soft-press) [box-shadow:var(--n-elev)]"};export const AppLogo=/*@__PURE__*/t.forwardRef(function(t,x){const{src:j,srcSet:_,alt:y,name:N,initials:k,showName:z=!1,shape:S="bare",variant:A="solid",size:F="md",color:L="primary",elevation:P=0,padded:R=!0,height:$,href:q,imageProps:B,render:C,className:D,style:E,children:G,...H}=h(t,["size","variant"]),I="bare"!==S,J=c(G)?G:j?"image":null,K=I&&R,M=null===J&&!I,O=z&&!M&&c(N),Q=y??N,T=k??(N?a(N):""),U="image"===J&&!O&&c(Q),V=M||U,W=!V&&!O&&c(Q),X=f($),Y=X?{height:X,width:I?X:void 0}:null,Z=e("span",{"aria-hidden":!V||void 0,className:m("flex shrink-0 items-center justify-center overflow-hidden","font-semibold tracking-tight whitespace-nowrap",X?"":l[F],I?m(X?"":o[F],"circle"===S?"rounded-full":b[F],v[F],w[A]):m("w-auto text-(--neba-fg)",p[F]),"[&_svg]:w-auto [&_svg]:shrink-0",K?"[&_svg]:h-[72%] [&_svg]:max-w-[72%]":"[&_svg]:h-full [&_svg]:max-w-full",g),style:{...I?i(L,P,A):null,...Y},children:"image"===J?e("img",{src:j,srcSet:_,alt:U?Q??"":"",className:m("w-auto object-contain",K?"h-[72%] max-w-[72%]":"h-full max-w-full"),decoding:"async",...B}):J??(M?N:T)});return s({render:C??e(q?"a":"span",{}),ref:x,props:{href:q,className:m("inline-flex max-w-full min-w-0 items-center align-middle","text-(--neba-fg) no-underline select-none",d[F],q?"cursor-pointer rounded-(--neba-radius-sm)":"",q?"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2":"",D),style:{"--n-ring":`var(--neba-${L}-ring)`,...E},children:n(r,{children:[Z,O?e("span",{className:m("min-w-0 truncate font-semibold",p[F]),children:N}):null,W?e("span",{className:u,children:Q}):null]}),...H}})});
1
+ "use client";import{jsx as e,Fragment as r,jsxs as n}from"react/jsx-runtime";import*as t from"react";import{useRender as a}from"@base-ui/react/use-render";import{initialsOf as s}from"../../internal/initials.js";import{safeRel as l}from"../../internal/link.js";import{controlHeightClasses as i,controlSlots as o,controlSquareClasses as m,cx as d,gapClasses as c,hasContent as u,srOnlyClasses as x,surfaceClasses as f,toLength as g,transitionClasses as h}from"../../internal/styles.js";import{useStyleDefaults as p}from"../../internal/defaults.js";const v={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1.0625rem]",lg:"text-[1.375rem]",xl:"text-[1.625rem]"},b={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1.0625rem]",lg:"text-[1.3125rem]",xl:"text-[1.5625rem]"},w={xs:"rounded-[0.375rem]",sm:"rounded-[0.4375rem]",md:"rounded-[0.5625rem]",lg:"rounded-[0.6875rem]",xl:"rounded-[0.875rem]"},j={solid:[f,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[f,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--n-accent) bg-(--n-soft-press) [box-shadow:var(--n-elev)]"};export const AppLogo=/*@__PURE__*/t.forwardRef(function(t,f){const{src:_,srcSet:y,alt:N,name:k,initials:z,showName:S=!1,shape:A="bare",variant:F="solid",size:L="md",color:P="primary",elevation:R=0,padded:$=!0,height:q,href:B,target:C,rel:D,imageProps:E,render:G,className:H,style:I,children:J,...K}=p(t,["size","variant"]),M="bare"!==A,O=u(J)?J:_?"image":null,Q=M&&$,T=null===O&&!M,U=S&&!T&&u(k),V=N??k,W=z??(k?s(k):""),X="image"===O&&!U&&u(V),Y=T||X,Z=!Y&&!U&&u(V),ee=g(q),re=ee?{height:ee,width:M?ee:void 0}:null,ne=e("span",{"aria-hidden":!Y||void 0,className:d("flex shrink-0 items-center justify-center overflow-hidden","font-semibold tracking-tight whitespace-nowrap",ee?"":i[L],M?d(ee?"":m[L],"circle"===A?"rounded-full":w[L],b[L],j[F]):d("w-auto text-(--neba-fg)",v[L]),"[&_svg]:w-auto [&_svg]:shrink-0",Q?"[&_svg]:h-[72%] [&_svg]:max-w-[72%]":"[&_svg]:h-full [&_svg]:max-w-full",h),style:{...M?o(P,R,F):null,...re},children:"image"===O?e("img",{src:_,srcSet:y,alt:X?V??"":"",className:d("w-auto object-contain",Q?"h-[72%] max-w-[72%]":"h-full max-w-full"),decoding:"async",...E}):O??(T?k:W)});return a({render:G??e(B?"a":"span",{}),ref:f,props:{href:B,target:C,rel:l(C,D),className:d("inline-flex max-w-full min-w-0 items-center align-middle","text-(--neba-fg) no-underline select-none",c[L],B?"cursor-pointer rounded-(--neba-radius-sm)":"",B?"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2":"",H),style:{"--n-ring":`var(--neba-${P}-ring)`,...I},children:n(r,{children:[ne,U?e("span",{className:d("min-w-0 truncate font-semibold",v[L]),children:k}):null,Z?e("span",{className:x,children:V}):null]}),...K}})});
@@ -61,6 +61,16 @@ export interface BottomNavigationItemProps extends Omit<React.ComponentPropsWith
61
61
  icon?: React.ReactNode;
62
62
  /** Renders the item as a link rather than as a button. */
63
63
  href?: string;
64
+ /**
65
+ * Where an `href` opens. Meaningless without one.
66
+ *
67
+ * Anything other than this tab gets `noopener noreferrer` merged into `rel`,
68
+ * so a destination that opens a new window cannot hand it a handle back to
69
+ * the page that opened it.
70
+ */
71
+ target?: string;
72
+ /** The link's `rel`. Merged with the two tokens above rather than replaced. */
73
+ rel?: string;
64
74
  /** Unavailable, but still part of the set. */
65
75
  disabled?: boolean;
66
76
  /** The destination's name. Read out even when `labels` keeps it undrawn. */
@@ -1 +1 @@
1
- "use client";import{jsx as e,Fragment as t,jsxs as a}from"react/jsx-runtime";import*as n from"react";import{useRender as i}from"@base-ui/react/use-render";import{barMinHeightClasses as l,BottomNavigationContext as r}from"../../internal/bottom-navigation.js";import{cx as o,hasContent as s,iconSizeClasses as d,metaTextClasses as c,paddingXClasses as u,radiusClasses as m,srOnlyClasses as p,surfaceClasses as f,surfaceSlots as b,transitionClasses as g}from"../../internal/styles.js";import{useStyleDefaults as v}from"../../internal/defaults.js";const x={solid:[f,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[f,"text-(--neba-fg) bg-(--n-panel)","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},h={static:"",sticky:"sticky bottom-0 z-20",fixed:"fixed inset-x-0 bottom-0 z-30"},y={default:{xs:"p-1",sm:"p-1",md:"p-1.5",lg:"p-2",xl:"p-2.5"},compact:{xs:"p-0.5",sm:"p-0.5",md:"p-1",lg:"p-1",xl:"p-1.5"}},w={xs:"gap-0.5",sm:"gap-0.5",md:"gap-1",lg:"gap-1",xl:"gap-1.5"};export const BottomNavigation=/*@__PURE__*/n.forwardRef(function(t,a){const{variant:s="outline",size:d="md",color:c="primary",density:u="default",elevation:p=0,value:f,defaultValue:w=null,onValueChange:z,position:N="fixed",labels:j="all",divider:k=!0,safeArea:C=!0,disabled:B=!1,label:R,render:V,className:_,style:A,children:D,...F}=v(t,["size","density","variant"]),[I,M]=n.useState(w),P=void 0!==f,S=P?f:I,q=n.useCallback(e=>{P||M(e),z?.(e)},[P,z]),E=n.useMemo(()=>({value:S??null,change:q,size:d,density:u,labels:j,disabled:B,floating:!1}),[S,q,d,u,j,B]),G=o("w-full min-w-0","static"===N?m[d]:"",x[s],"outline"===s&&"static"===N?"border [border-color:var(--n-line)]":"",k?"border-t [border-color:var(--n-line)]":"",h[N],C?"pb-[env(safe-area-inset-bottom)]":"",g,_);return i({render:V??e("nav",{}),ref:a,props:{"aria-label":R,className:G,style:{...b(c,p),...A},children:e(r.Provider,{value:E,children:e("div",{className:o("flex w-full items-stretch",l[d],y[u][d]),children:D})}),...F}})});export const BottomNavigationItem=/*@__PURE__*/n.forwardRef(function({value:i,icon:l,href:f,disabled:b=!1,className:v,children:x,onClick:h,...y},z){const N=n.useContext(r),j=b||N.disabled,k=null!==N.value&&N.value===i,C="all"===N.labels||"selected"===N.labels&&k,B=o("flex min-w-0 flex-col items-center justify-center py-1.5",N.floating?o("relative z-10",u[N.density][N.size],"rounded-full"):o("flex-1 px-1",m[N.size]),w[N.size],"[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",g,"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]",j?"cursor-not-allowed text-(--neba-disabled-fg)":k?N.floating?"cursor-pointer font-medium text-(--n-accent)":"cursor-pointer font-medium text-(--n-accent) bg-(--n-soft) hover:bg-(--n-soft-hover)":"cursor-pointer text-(--neba-muted-fg) hover:text-(--neba-fg) hover:bg-(--n-panel-hover)",v),R=a(t,{children:[s(l)?e("span",{className:o("flex shrink-0 items-center justify-center",d[N.size]),children:l}):null,s(x)?N.floating&&"selected"===N.labels?e("span",{"data-drawn":C?"":void 0,className:o("grid justify-items-center [grid-template-rows:1fr]","[transition-property:grid-template-columns,opacity]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","motion-reduce:[transition-duration:0ms]",C?"[grid-template-columns:1fr] opacity-100":"[grid-template-columns:0fr] opacity-0"),children:e("span",{className:o("min-w-0 truncate leading-tight",c[N.size]),children:x})}):e("span",{"data-drawn":C?"":void 0,className:C?o("max-w-full truncate leading-tight",c[N.size]):p,children:x}):null]}),V=e=>{j?e.preventDefault():(N.change(i),h?.(e))};return f?e("a",{ref:z,"data-nav-item":"",href:j?void 0:f,"aria-current":k?"page":void 0,"aria-disabled":j||void 0,className:B,onClick:V,...y,children:R}):e("button",{ref:z,"data-nav-item":"",type:"button",disabled:j,"aria-current":k?"page":void 0,className:B,onClick:V,...y,children:R})});
1
+ "use client";import{jsx as e,Fragment as t,jsxs as a}from"react/jsx-runtime";import*as n from"react";import{useRender as i}from"@base-ui/react/use-render";import{barMinHeightClasses as r,BottomNavigationContext as l}from"../../internal/bottom-navigation.js";import{safeRel as o}from"../../internal/link.js";import{cx as s,hasContent as d,iconSizeClasses as c,metaTextClasses as m,paddingXClasses as u,radiusClasses as p,srOnlyClasses as f,surfaceClasses as g,surfaceSlots as b,transitionClasses as v}from"../../internal/styles.js";import{useStyleDefaults as x}from"../../internal/defaults.js";const h={solid:[g,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[g,"text-(--neba-fg) bg-(--n-panel)","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},y={static:"",sticky:"sticky bottom-0 z-20",fixed:"fixed inset-x-0 bottom-0 z-30"},w={default:{xs:"p-1",sm:"p-1",md:"p-1.5",lg:"p-2",xl:"p-2.5"},compact:{xs:"p-0.5",sm:"p-0.5",md:"p-1",lg:"p-1",xl:"p-1.5"}},j={xs:"gap-0.5",sm:"gap-0.5",md:"gap-1",lg:"gap-1",xl:"gap-1.5"};export const BottomNavigation=/*@__PURE__*/n.forwardRef(function(t,a){const{variant:o="outline",size:d="md",color:c="primary",density:m="default",elevation:u=0,value:f,defaultValue:g=null,onValueChange:j,position:z="fixed",labels:N="all",divider:k=!0,safeArea:C=!0,disabled:B=!1,label:R,render:V,className:_,style:A,children:D,...F}=x(t,["size","density","variant"]),[I,M]=n.useState(g),P=void 0!==f,S=P?f:I,q=n.useCallback(e=>{P||M(e),j?.(e)},[P,j]),E=n.useMemo(()=>({value:S??null,change:q,size:d,density:m,labels:N,disabled:B,floating:!1}),[S,q,d,m,N,B]),G=s("w-full min-w-0","static"===z?p[d]:"",h[o],"outline"===o&&"static"===z?"border [border-color:var(--n-line)]":"",k?"border-t [border-color:var(--n-line)]":"",y[z],C?"pb-[env(safe-area-inset-bottom)]":"",v,_);return i({render:V??e("nav",{}),ref:a,props:{"aria-label":R,className:G,style:{...b(c,u),...A},children:e(l.Provider,{value:E,children:e("div",{className:s("flex w-full items-stretch",r[d],w[m][d]),children:D})}),...F}})});export const BottomNavigationItem=/*@__PURE__*/n.forwardRef(function({value:i,icon:r,href:g,target:b,rel:x,disabled:h=!1,className:y,children:w,onClick:z,...N},k){const C=n.useContext(l),B=h||C.disabled,R=null!==C.value&&C.value===i,V="all"===C.labels||"selected"===C.labels&&R,_=s("flex min-w-0 flex-col items-center justify-center py-1.5",C.floating?s("relative z-10",u[C.density][C.size],"rounded-full"):s("flex-1 px-1",p[C.size]),j[C.size],"[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",v,"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]",B?"cursor-not-allowed text-(--neba-disabled-fg)":R?C.floating?"cursor-pointer font-medium text-(--n-accent)":"cursor-pointer font-medium text-(--n-accent) bg-(--n-soft) hover:bg-(--n-soft-hover)":"cursor-pointer text-(--neba-muted-fg) hover:text-(--neba-fg) hover:bg-(--n-panel-hover)",y),A=a(t,{children:[d(r)?e("span",{className:s("flex shrink-0 items-center justify-center",c[C.size]),children:r}):null,d(w)?C.floating&&"selected"===C.labels?e("span",{"data-drawn":V?"":void 0,className:s("grid justify-items-center [grid-template-rows:1fr]","[transition-property:grid-template-columns,opacity]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","motion-reduce:[transition-duration:0ms]",V?"[grid-template-columns:1fr] opacity-100":"[grid-template-columns:0fr] opacity-0"),children:e("span",{className:s("min-w-0 truncate leading-tight",m[C.size]),children:w})}):e("span",{"data-drawn":V?"":void 0,className:V?s("max-w-full truncate leading-tight",m[C.size]):f,children:w}):null]}),D=e=>{B?e.preventDefault():(C.change(i),z?.(e))};return g?e("a",{ref:k,"data-nav-item":"",href:B?void 0:g,"aria-current":R?"page":void 0,"aria-disabled":B||void 0,className:_,onClick:D,target:b,rel:o(b,x),...N,children:A}):e("button",{ref:k,"data-nav-item":"",type:"button",disabled:B,"aria-current":R?"page":void 0,className:_,onClick:D,...N,children:A})});
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as r,Fragment as o}from"react/jsx-runtime";import*as t from"react";import{Button as n}from"@base-ui/react/button";import{useRender as a}from"@base-ui/react/use-render";import{ButtonGroupContext as s}from"../../internal/button-group.js";import{controlHeightClasses as l,controlSlots as i,controlSquareClasses as d,controlTextClasses as c,cx as v,disabledClasses as p,focusRingClasses as x,gapClasses as b,iconClasses as m,paddingXClasses as u,pressTransitionClasses as f,radiusClasses as g,readOnlyFilterClasses as h,surfaceClasses as $,transitionClasses as y}from"../../internal/styles.js";import{useStyleDefaults as j}from"../../internal/defaults.js";const w={xs:`${l.xs} ${b.xs} ${g.xs} ${c.xs}`,sm:`${l.sm} ${b.sm} ${g.sm} ${c.sm}`,md:`${l.md} ${b.md} ${g.md} ${c.md}`,lg:`${l.lg} ${b.lg} ${g.lg} ${c.lg}`,xl:`${l.xl} ${b.xl} ${g.xl} ${c.xl}`},k={xs:`${d.xs} px-0`,sm:`${d.sm} px-0`,md:`${d.md} px-0`,lg:`${d.lg} px-0`,xl:`${d.xl} px-0`},C=["relative inline-flex shrink-0 select-none items-center justify-center","whitespace-nowrap align-middle font-medium leading-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",y,f,x,m].join(" "),P={solid:[$,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[$,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--n-accent) bg-transparent"},z={solid:["hover:bg-(--n-fill-hover)","hover:[box-shadow:var(--n-elev-hover),var(--neba-plate-solid)]","active:bg-(--n-fill-active)","active:[box-shadow:var(--n-elev-press),var(--neba-plate-solid)]"].join(" "),outline:["hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","hover:[box-shadow:var(--n-elev-hover),var(--neba-plate-glass)]","active:bg-(--n-panel-press)","active:[box-shadow:var(--n-elev-press),var(--neba-plate-glass)]"].join(" "),text:"hover:bg-(--n-soft) active:bg-(--n-soft-hover)"},B={solid:[$,h,"cursor-default text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--neba-plate-solid)]"].join(" "),outline:[$,h,"cursor-default border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)] [box-shadow:var(--neba-plate-glass)]"].join(" "),text:`${h} cursor-default text-(--n-accent) bg-transparent`};function M(){return r("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",className:"animate-spin",children:[e("circle",{cx:"8",cy:"8",r:"6.5",stroke:"currentColor",strokeOpacity:"0.25",strokeWidth:"2"}),e("path",{d:"M14.5 8A6.5 6.5 0 0 0 8 1.5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}export const Button=/*@__PURE__*/t.forwardRef(function(l,d){const{variant:c,size:x,color:b,density:m,elevation:f,startIcon:g,endIcon:h,loading:$=!1,readOnly:y=!1,fullWidth:N=!1,disabled:W,render:E,className:I,style:O,children:A,onClick:D,onPointerMove:F,...L}=j(l,["size","density","variant"]),R=t.useContext(s),T=c??R?.variant??"solid",X=x??R?.size??"md",Y=b??R?.color??"primary",q=m??R?.density??"default",G=f??R?.elevation??0,H=W??R?.disabled??!1,J=$||y,K=v(C,w[X],null==A||!1===A?k[X]:u[q][X],H?p[T]:y?B[T]:P[T],H||J?"":[z[T],"neba-glow","cursor-pointer"].join(" "),$?"cursor-progress":"",N?"w-full":"",I??"");return a({render:E??e(n,{disabled:H}),ref:d,props:{className:K,style:{...i(Y,G,T),...O},"aria-disabled":J||void 0,"aria-busy":$||void 0,"data-loading":$||void 0,"data-readonly":y||void 0,onClick:e=>{if(J)return e.preventDefault(),void e.stopPropagation();D?.(e)},onPointerMove:e=>{if(!H&&!J){const r=e.currentTarget;r.style.setProperty("--n-mx",`${e.nativeEvent.offsetX}px`),r.style.setProperty("--n-my",`${e.nativeEvent.offsetY}px`)}F?.(e)},...L,children:r(o,{children:[$?e(M,{}):g,A,h]})}})});
1
+ "use client";import{jsx as e,Fragment as n,jsxs as o}from"react/jsx-runtime";import*as t from"react";import{Button as r}from"@base-ui/react/button";import{useRender as a}from"@base-ui/react/use-render";import{ButtonGroupContext as l}from"../../internal/button-group.js";import{SpinnerIcon as s}from"../../internal/icons.js";import{controlHeightClasses as i,controlSlots as d,controlSquareClasses as v,controlTextClasses as c,cx as p,disabledClasses as x,focusRingClasses as b,gapClasses as m,iconClasses as u,paddingXClasses as f,pressTransitionClasses as g,radiusClasses as h,readOnlyFilterClasses as $,surfaceClasses as j,transitionClasses as y}from"../../internal/styles.js";import{useStyleDefaults as w}from"../../internal/defaults.js";const P={xs:`${i.xs} ${m.xs} ${h.xs} ${c.xs}`,sm:`${i.sm} ${m.sm} ${h.sm} ${c.sm}`,md:`${i.md} ${m.md} ${h.md} ${c.md}`,lg:`${i.lg} ${m.lg} ${h.lg} ${c.lg}`,xl:`${i.xl} ${m.xl} ${h.xl} ${c.xl}`},k={xs:`${v.xs} px-0`,sm:`${v.sm} px-0`,md:`${v.md} px-0`,lg:`${v.lg} px-0`,xl:`${v.xl} px-0`},z=["relative inline-flex shrink-0 select-none items-center justify-center","whitespace-nowrap align-middle font-medium leading-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",y,g,b,u].join(" "),C={solid:[j,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[j,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--n-accent) bg-transparent"},B={solid:["hover:bg-(--n-fill-hover)","hover:[box-shadow:var(--n-elev-hover),var(--neba-plate-solid)]","active:bg-(--n-fill-active)","active:[box-shadow:var(--n-elev-press),var(--neba-plate-solid)]"].join(" "),outline:["hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","hover:[box-shadow:var(--n-elev-hover),var(--neba-plate-glass)]","active:bg-(--n-panel-press)","active:[box-shadow:var(--n-elev-press),var(--neba-plate-glass)]"].join(" "),text:"hover:bg-(--n-soft) active:bg-(--n-soft-hover)"},E={solid:[j,$,"cursor-default text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--neba-plate-solid)]"].join(" "),outline:[j,$,"cursor-default border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)] [box-shadow:var(--neba-plate-glass)]"].join(" "),text:`${$} cursor-default text-(--n-accent) bg-transparent`};export const Button=/*@__PURE__*/t.forwardRef(function(i,v){const{variant:c,size:b,color:m,density:u,elevation:g,startIcon:h,endIcon:$,loading:j=!1,readOnly:y=!1,fullWidth:I=!1,disabled:M,render:N,className:D,style:F,children:O,onClick:R,onPointerMove:T,...W}=w(i,["size","density","variant"]),X=t.useContext(l),Y=c??X?.variant??"solid",q=b??X?.size??"md",A=m??X?.color??"primary",G=u??X?.density??"default",H=g??X?.elevation??0,J=M??X?.disabled??!1,K=j||y,L=p(z,P[q],null==O||!1===O?k[q]:f[G][q],J?x[Y]:y?E[Y]:C[Y],J||K?"":[B[Y],"neba-glow","cursor-pointer"].join(" "),j?"cursor-progress":"",I?"w-full":"",D??"");return a({render:N??e(r,{disabled:J}),ref:v,props:{className:L,style:{...d(A,H,Y),...F},"aria-disabled":K||void 0,"aria-busy":j||void 0,"data-loading":j||void 0,"data-readonly":y||void 0,onClick:e=>{if(K)return e.preventDefault(),void e.stopPropagation();R?.(e)},onPointerMove:e=>{if(!J&&!K){const n=e.currentTarget;n.style.setProperty("--n-mx",`${e.nativeEvent.offsetX}px`),n.style.setProperty("--n-my",`${e.nativeEvent.offsetY}px`)}T?.(e)},...W,children:o(n,{children:[j?e(s,{}):h,O,$]})}})});
@@ -1 +1 @@
1
- "use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{Calendar as n,usePickerLabels as r}from"../../internal/calendar.js";import{compareDay as a,isSameDay as l,isValidDate as s,localeWeekStart as o,startOfMonth as i,startOfUnit as d,today as u}from"../../internal/date.js";import{cx as m,radiusClasses as c,surfaceSlots as f}from"../../internal/styles.js";import{useStyleDefaults as g}from"../../internal/defaults.js";const h={single:null,multiple:[],range:{start:null,end:null}};function p(e,t){if("multiple"===e)return t??[];if("range"===e){const e=t??h.range;return[e.start,e.end]}return[t]}export const Calendar=/*@__PURE__*/t.forwardRef(function(D,y){const{mode:v="single",value:b,defaultValue:j,onValueChange:S,size:w="md",color:x="primary",elevation:C=0,bordered:O=!0,month:k,defaultMonth:z,onMonthChange:M,granularity:N="day",minDate:V,maxDate:E,shouldDisableDate:R,locale:q,weekStartsOn:A,showOutsideDays:B=!0,renderDay:F,labels:G,className:H,style:I,...J}=g(D,["size","locale"]),K=r(G),L=A??o(q),[P,Q]=t.useState(()=>j??h[v]),T=void 0!==b?b:P,U=p(v,T).find(s),[W,X]=t.useState(()=>i(U??z??u())),Y=k??W,Z=e=>{void 0===b&&Q(e),S?.(e)},$="range"===v?T??h.range:h.range;return e("div",{ref:y,className:m("inline-block",O&&"border p-3 [border-color:var(--n-line)] bg-(--n-panel-press)",O&&c[w],H),style:{...f(x,C),...I},...J,children:e(n,{size:w,color:x,locale:q,weekStartsOn:L,month:Y,onMonthChange:e=>{void 0===k&&X(e),M?.(e)},selected:p(v,T),rangeStart:$.start,rangeEnd:$.end,onSelect:e=>{const t=d(e,N);if("multiple"===v){const e=T??[],n=e.filter(e=>!l(e,t));return void Z(n.length===e.length?[...e,t]:n)}if("range"===v){const e=T??h.range;return!s(e.start)||s(e.end)?void Z({start:t,end:null}):void Z(a(t,e.start)<0?{start:t,end:null}:{start:e.start,end:t})}Z(t)},granularity:N,minDate:V,maxDate:E,shouldDisableDate:R,showOutsideDays:B,renderDay:F,labels:K})})});
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import*as t from"react";import{Calendar as n,usePickerLabels as r}from"../../internal/calendar.js";import{compareDay as a,isSameDay as l,isValidDate as s,localeWeekStart as o,startOfMonth as i,startOfUnit as d,today as u}from"../../internal/date.js";import{cx as m,radiusClasses as c,surfaceSlots as f}from"../../internal/styles.js";import{useStyleDefaults as g}from"../../internal/defaults.js";const h={single:null,multiple:[],range:{start:null,end:null}};function p(e,t){if("multiple"===e)return t??[];if("range"===e){const e=t??h.range;return[e.start,e.end]}return[t]}export const Calendar=/*@__PURE__*/t.forwardRef(function(D,y){const{mode:v="single",value:b,defaultValue:j,onValueChange:S,size:w="md",color:x="primary",elevation:C=0,bordered:O=!0,month:k,defaultMonth:z,onMonthChange:M,granularity:N="day",minDate:V,maxDate:E,shouldDisableDate:R,locale:q,weekStartsOn:A,showOutsideDays:B=!0,renderDay:F,labels:G,className:H,style:I,...J}=g(D,["size","locale"]),K=r(G,q),L=A??o(q),[P,Q]=t.useState(()=>j??h[v]),T=void 0!==b?b:P,U=p(v,T).find(s),[W,X]=t.useState(()=>i(U??z??u())),Y=k??W,Z=e=>{void 0===b&&Q(e),S?.(e)},$="range"===v?T??h.range:h.range;return e("div",{ref:y,className:m("inline-block",O&&"border p-3 [border-color:var(--n-line)] bg-(--n-panel-press)",O&&c[w],H),style:{...f(x,C),...I},...J,children:e(n,{size:w,color:x,locale:q,weekStartsOn:L,month:Y,onMonthChange:e=>{void 0===k&&X(e),M?.(e)},selected:p(v,T),rangeStart:$.start,rangeEnd:$.end,onSelect:e=>{const t=d(e,N);if("multiple"===v){const e=T??[],n=e.filter(e=>!l(e,t));return void Z(n.length===e.length?[...e,t]:n)}if("range"===v){const e=T??h.range;return!s(e.start)||s(e.end)?void Z({start:t,end:null}):void Z(a(t,e.start)<0?{start:t,end:null}:{start:e.start,end:t})}Z(t)},granularity:N,minDate:V,maxDate:E,shouldDisableDate:R,showOutsideDays:B,renderDay:F,labels:K})})});
@@ -26,6 +26,12 @@ export interface CarouselProps extends NebaStyleProps, Omit<React.ComponentProps
26
26
  * read is the most complained-about pattern on the web. It pauses on hover,
27
27
  * on focus anywhere inside it, while the tab is in the background, and it does
28
28
  * not start at all for a reader who has asked for reduced motion.
29
+ *
30
+ * Turning it on draws a button that stops it, in the row under the frame
31
+ * beside the dots. There is no prop to take that button away: hover and focus
32
+ * are not a mechanism for a reader holding a phone or a magnifier, and a
33
+ * caller who wants a control of their own can drive `value` and leave this
34
+ * off.
29
35
  * @default false
30
36
  */
31
37
  autoPlay?: boolean;
@@ -47,6 +53,13 @@ export interface CarouselProps extends NebaStyleProps, Omit<React.ComponentProps
47
53
  label?: string;
48
54
  previousLabel?: string;
49
55
  nextLabel?: string;
56
+ /**
57
+ * The rotation control's two names — what it says while the slides are
58
+ * advancing, and what it says once they have been stopped. Default to the
59
+ * `locale`'s wording.
60
+ */
61
+ pauseLabel?: string;
62
+ playLabel?: string;
50
63
  /**
51
64
  * How one slide is named to a screen reader, and how its dot is labelled.
52
65
  * Defaults to the `locale`'s wording.
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{IconButton as n}from"../icon-button/IconButton.js";import{carouselMessages as a,fillMessage as o,useMessages as l}from"../../internal/i18n.js";import{ChevronIcon as i}from"../../internal/icons.js";import{usePrefersReducedMotion as s}from"../../internal/media.js";import{cx as c,radiusClasses as u,srOnlyClasses as d,surfaceClasses as f,surfaceSlots as m,transitionClasses as p}from"../../internal/styles.js";import{useStyleDefaults as v}from"../../internal/defaults.js";const b={solid:[f,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[f,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},h={xs:"start-1 end-1",sm:"start-1.5 end-1.5",md:"start-2 end-2",lg:"start-3 end-3",xl:"start-4 end-4"},g={xs:{rest:"h-1 w-1",current:"h-1 w-3",gap:"gap-1"},sm:{rest:"h-1 w-1",current:"h-1 w-3.5",gap:"gap-1"},md:{rest:"h-1.5 w-1.5",current:"h-1.5 w-4",gap:"gap-1.5"},lg:{rest:"h-1.5 w-1.5",current:"h-1.5 w-5",gap:"gap-2"},xl:{rest:"h-2 w-2",current:"h-2 w-6",gap:"gap-2"}};export const Carousel=/*@__PURE__*/t.forwardRef(function(f,x){const{variant:w="outline",size:j="md",color:y="primary",density:N="default",elevation:k=0,value:C,defaultValue:M=0,onValueChange:R,loop:I=!0,autoPlay:L=!1,interval:S=5e3,arrows:z=!0,indicators:$=!0,locale:_,label:E,previousLabel:P,nextLabel:V,slideLabel:B,className:T,style:W,children:A,...F}=v(f,["size","density","variant","locale"]),q=l(a,_),D=B??((e,r)=>o(q.slide,{index:String(e),total:String(r)})),G=t.Children.toArray(A),H=G.length,[J,K]=t.useState(M),O=Math.min(Math.max(C??J,0),Math.max(H-1,0)),Q=t.useRef(null),U=t.useRef([]),X=t.useRef(!1),Y=t.useRef(!1),Z=t.useRef(!1),[ee,re]=t.useState(!1),te=t.useCallback((e,r=!1)=>{if(0===H)return;const t=I?(e%H+H)%H:Math.min(Math.max(e,0),H-1);X.current=r,void 0===C&&K(t),t!==O&&R?.(t)},[H,I,C,O,R]);t.useEffect(()=>{if(X.current)return void(X.current=!1);if(!Y.current)return void(Y.current=!0);U.current[O]?.scrollIntoView({block:"nearest",inline:"start"}),Z.current=!0;const e=window.setTimeout(()=>{Z.current=!1},700);return()=>window.clearTimeout(e)},[O]);const ne=s();t.useEffect(()=>{if(!L||ee||ne||H<2)return;const e=window.setInterval(()=>{document.hidden||te(O+1)},S);return()=>window.clearInterval(e)},[L,ee,ne,H,S,O,te]);const ae=O<=0,oe=O>=H-1;return r("div",{ref:x,role:"region","aria-roledescription":"carousel","aria-label":E??q.label,className:c("flex flex-col",T??""),style:{...m(y,k),...W},onPointerEnter:()=>re(!0),onPointerLeave:()=>re(!1),onFocus:()=>re(!0),onBlur:()=>re(!1),...F,children:[r("div",{className:["relative min-w-0 overflow-hidden",u[j],b[w],p].join(" "),children:[e("div",{ref:Q,tabIndex:0,role:"group","aria-label":E??q.label,className:["flex min-w-0 snap-x snap-mandatory overflow-x-auto scroll-smooth","motion-reduce:scroll-auto","[scrollbar-width:none] [&::-webkit-scrollbar]:hidden","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]"].join(" "),onScroll:()=>{const e=Q.current;if(Z.current||!e||0===e.clientWidth)return;const r=Math.round(Math.abs(e.scrollLeft)/e.clientWidth);r!==O&&r>=0&&r<H&&te(r,!0)},children:G.map((r,t)=>e("div",{ref:e=>{U.current[t]=e},role:"group","aria-roledescription":"slide","aria-label":D(t+1,H),className:"w-full shrink-0 grow-0 basis-full snap-start",children:r},t))}),z&&H>1?r("div",{className:`pointer-events-none absolute inset-y-0 flex items-center ${h[j]}`,children:[e(n,{variant:"solid",size:j,color:y,density:N,elevation:1,label:P??q.previous,disabled:!I&&ae,className:"pointer-events-auto",icon:e("span",{className:"flex items-center rotate-90 rtl:-rotate-90",children:e(i,{})}),onClick:()=>te(O-1)}),e("span",{className:"flex-1"}),e(n,{variant:"solid",size:j,color:y,density:N,elevation:1,label:V??q.next,disabled:!I&&oe,className:"pointer-events-auto",icon:e("span",{className:"flex items-center -rotate-90 rtl:rotate-90",children:e(i,{})}),onClick:()=>te(O+1)})]}):null]}),$&&H>1?e("div",{className:`flex shrink-0 items-center justify-center pt-2 ${g[j].gap}`,children:G.map((r,t)=>e("button",{type:"button","aria-label":D(t+1,H),"aria-current":t===O?"true":void 0,className:["cursor-pointer rounded-full","[transition-property:width,background-color]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2",t===O?`${g[j].current} bg-(--n-accent)`:`${g[j].rest} bg-(--n-line-hover) hover:bg-(--n-accent)`].join(" "),onClick:()=>te(t)},t))}):null,e("span",{className:d,"aria-live":L?"off":"polite",children:H>0?D(O+1,H):""})]})});
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as r from"react";import{IconButton as n}from"../icon-button/IconButton.js";import{carouselMessages as a,fillMessage as l,useMessages as i}from"../../internal/i18n.js";import{ChevronIcon as o,PauseIcon as s,PlayIcon as c}from"../../internal/icons.js";import{usePrefersReducedMotion as u}from"../../internal/media.js";import{cx as d,radiusClasses as f,srOnlyClasses as m,surfaceClasses as p,surfaceSlots as b,transitionClasses as v}from"../../internal/styles.js";import{useStyleDefaults as h}from"../../internal/defaults.js";const g={solid:[p,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[p,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},x={xs:"start-1 end-1",sm:"start-1.5 end-1.5",md:"start-2 end-2",lg:"start-3 end-3",xl:"start-4 end-4"},w={xs:{rest:"h-1 w-1",current:"h-1 w-3",gap:"gap-1"},sm:{rest:"h-1 w-1",current:"h-1 w-3.5",gap:"gap-1"},md:{rest:"h-1.5 w-1.5",current:"h-1.5 w-4",gap:"gap-1.5"},lg:{rest:"h-1.5 w-1.5",current:"h-1.5 w-5",gap:"gap-2"},xl:{rest:"h-2 w-2",current:"h-2 w-6",gap:"gap-2"}};export const Carousel=/*@__PURE__*/r.forwardRef(function(p,y){const{variant:N="outline",size:j="md",color:k="primary",density:C="default",elevation:L=0,value:M,defaultValue:R=0,onValueChange:S,loop:_=!0,autoPlay:z=!1,interval:I=5e3,arrows:$=!0,indicators:E=!0,locale:P,label:V,previousLabel:B,nextLabel:T,pauseLabel:W,playLabel:A,slideLabel:F,className:q,style:D,children:G,...H}=h(p,["size","density","variant","locale"]),J=i(a,P),K=F??((e,t)=>l(J.slide,{index:String(e),total:String(t)})),O=r.Children.toArray(G),Q=O.length,[U,X]=r.useState(R),Y=Math.min(Math.max(M??U,0),Math.max(Q-1,0)),Z=r.useRef(null),ee=r.useRef([]),te=r.useRef(!1),re=r.useRef(!1),ne=r.useRef(!1),[ae,le]=r.useState(!1),[ie,oe]=r.useState(!1),se=r.useCallback((e,t=!1)=>{if(0===Q)return;const r=_?(e%Q+Q)%Q:Math.min(Math.max(e,0),Q-1);te.current=t,void 0===M&&X(r),r!==Y&&S?.(r)},[Q,_,M,Y,S]);r.useEffect(()=>{if(te.current)return void(te.current=!1);if(!re.current)return void(re.current=!0);ee.current[Y]?.scrollIntoView({block:"nearest",inline:"start"}),ne.current=!0;const e=window.setTimeout(()=>{ne.current=!1},700);return()=>window.clearTimeout(e)},[Y]);const ce=u();r.useEffect(()=>{if(!z||ie||ae||ce||Q<2)return;const e=window.setInterval(()=>{document.hidden||se(Y+1)},I);return()=>window.clearInterval(e)},[z,ie,ae,ce,Q,I,Y,se]);const ue=Y<=0,de=Y>=Q-1,fe=z&&!ce&&Q>1,me=E&&Q>1;return t("div",{ref:y,role:"region","aria-roledescription":"carousel","aria-label":V??J.label,className:d("flex flex-col",q??""),style:{...b(k,L),...D},onPointerEnter:()=>le(!0),onPointerLeave:()=>le(!1),onFocus:()=>le(!0),onBlur:()=>le(!1),...H,children:[t("div",{className:["relative min-w-0 overflow-hidden",f[j],g[N],v].join(" "),children:[e("div",{ref:Z,tabIndex:0,role:"group","aria-label":V??J.label,className:["flex min-w-0 snap-x snap-mandatory overflow-x-auto scroll-smooth","motion-reduce:scroll-auto","[scrollbar-width:none] [&::-webkit-scrollbar]:hidden","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]"].join(" "),onScroll:()=>{const e=Z.current;if(ne.current||!e||0===e.clientWidth)return;const t=Math.round(Math.abs(e.scrollLeft)/e.clientWidth);t!==Y&&t>=0&&t<Q&&se(t,!0)},children:O.map((t,r)=>e("div",{ref:e=>{ee.current[r]=e},role:"group","aria-roledescription":"slide","aria-label":K(r+1,Q),className:"w-full shrink-0 grow-0 basis-full snap-start",children:t},r))}),$&&Q>1?t("div",{className:`pointer-events-none absolute inset-y-0 flex items-center ${x[j]}`,children:[e(n,{variant:"solid",size:j,color:k,density:C,elevation:1,label:B??J.previous,disabled:!_&&ue,className:"pointer-events-auto",icon:e("span",{className:"flex items-center rotate-90 rtl:-rotate-90",children:e(o,{})}),onClick:()=>se(Y-1)}),e("span",{className:"flex-1"}),e(n,{variant:"solid",size:j,color:k,density:C,elevation:1,label:T??J.next,disabled:!_&&de,className:"pointer-events-auto",icon:e("span",{className:"flex items-center -rotate-90 rtl:rotate-90",children:e(o,{})}),onClick:()=>se(Y+1)})]}):null]}),fe||me?t("div",{className:"grid shrink-0 grid-cols-[1fr_auto_1fr] items-center pt-2",children:[e("span",{className:"flex justify-start",children:fe?e(n,{variant:"text",size:j,color:k,density:C,label:ie?A??J.play:W??J.pause,icon:e(ie?c:s,{}),onClick:()=>oe(e=>!e)}):null}),e("span",{className:`flex items-center ${w[j].gap}`,children:me?O.map((t,r)=>e("button",{type:"button","aria-label":K(r+1,Q),"aria-current":r===Y?"true":void 0,className:["cursor-pointer rounded-full","[transition-property:width,background-color]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2",r===Y?`${w[j].current} bg-(--n-accent)`:`${w[j].rest} bg-(--n-line-hover) hover:bg-(--n-accent)`].join(" "),onClick:()=>se(r)},r)):null}),e("span",{})]}):null,e("span",{className:m,"aria-live":fe&&!ie?"off":"polite",children:Q>0?K(Y+1,Q):""})]})});