neba 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -15
- package/dist/components/blockquote/Blockquote.d.ts +65 -0
- package/dist/components/blockquote/Blockquote.js +1 -0
- package/dist/components/blockquote/index.d.ts +2 -0
- package/dist/components/blockquote/index.js +1 -0
- package/dist/components/carousel/Carousel.d.ts +74 -0
- package/dist/components/carousel/Carousel.js +1 -0
- package/dist/components/carousel/index.d.ts +2 -0
- package/dist/components/carousel/index.js +1 -0
- package/dist/components/checkbox/Checkbox.js +1 -1
- package/dist/components/combobox/Combobox.js +1 -1
- package/dist/components/container/Container.d.ts +55 -0
- package/dist/components/container/Container.js +1 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/container/index.js +1 -0
- package/dist/components/date-picker/DatePicker.d.ts +75 -0
- package/dist/components/date-picker/DatePicker.js +1 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-range-picker/DateRangePicker.d.ts +81 -0
- package/dist/components/date-range-picker/DateRangePicker.js +1 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.js +1 -0
- package/dist/components/date-time-picker/DateTimePicker.d.ts +68 -0
- package/dist/components/date-time-picker/DateTimePicker.js +1 -0
- package/dist/components/date-time-picker/index.d.ts +2 -0
- package/dist/components/date-time-picker/index.js +1 -0
- package/dist/components/dialog/Dialog.js +1 -1
- package/dist/components/divider/Divider.d.ts +19 -0
- package/dist/components/divider/Divider.js +1 -1
- package/dist/components/grid/Grid.d.ts +50 -0
- package/dist/components/grid/Grid.js +1 -0
- package/dist/components/grid/index.d.ts +2 -0
- package/dist/components/grid/index.js +1 -0
- package/dist/components/grid-container/GridContainer.d.ts +79 -0
- package/dist/components/grid-container/GridContainer.js +1 -0
- package/dist/components/grid-container/index.d.ts +2 -0
- package/dist/components/grid-container/index.js +1 -0
- package/dist/components/highlight/Highlight.d.ts +84 -0
- package/dist/components/highlight/Highlight.js +1 -0
- package/dist/components/highlight/index.d.ts +2 -0
- package/dist/components/highlight/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +58 -0
- package/dist/components/icon/Icon.js +1 -0
- package/dist/components/icon/index.d.ts +2 -0
- package/dist/components/icon/index.js +1 -0
- package/dist/components/icon-button/IconButton.d.ts +39 -0
- package/dist/components/icon-button/IconButton.js +1 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/icon-button/index.js +1 -0
- package/dist/components/pagination/Pagination.js +1 -1
- package/dist/components/pill/Pill.d.ts +80 -0
- package/dist/components/pill/Pill.js +1 -0
- package/dist/components/pill/index.d.ts +2 -0
- package/dist/components/pill/index.js +1 -0
- package/dist/components/radio-group/RadioGroup.js +1 -1
- package/dist/components/segmented-button/SegmentedButton.d.ts +77 -0
- package/dist/components/segmented-button/SegmentedButton.js +1 -0
- package/dist/components/segmented-button/index.d.ts +2 -0
- package/dist/components/segmented-button/index.js +1 -0
- package/dist/components/select/Select.js +1 -1
- package/dist/components/shortcut/Shortcut.d.ts +60 -0
- package/dist/components/shortcut/Shortcut.js +1 -0
- package/dist/components/shortcut/index.d.ts +2 -0
- package/dist/components/shortcut/index.js +1 -0
- package/dist/components/statistic/Statistic.d.ts +91 -0
- package/dist/components/statistic/Statistic.js +1 -0
- package/dist/components/statistic/index.d.ts +2 -0
- package/dist/components/statistic/index.js +1 -0
- package/dist/components/switch/Switch.js +1 -1
- package/dist/components/time-picker/TimePicker.d.ts +76 -0
- package/dist/components/time-picker/TimePicker.js +1 -0
- package/dist/components/time-picker/index.d.ts +2 -0
- package/dist/components/time-picker/index.js +1 -0
- package/dist/components/timeline/Timeline.d.ts +98 -0
- package/dist/components/timeline/Timeline.js +1 -0
- package/dist/components/timeline/index.d.ts +2 -0
- package/dist/components/timeline/index.js +1 -0
- package/dist/components/toolbar/Toolbar.d.ts +67 -0
- package/dist/components/toolbar/Toolbar.js +1 -0
- package/dist/components/toolbar/index.d.ts +2 -0
- package/dist/components/toolbar/index.js +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1 -1
- package/dist/internal/calendar.d.ts +149 -0
- package/dist/internal/calendar.js +1 -0
- package/dist/internal/date.d.ts +170 -0
- package/dist/internal/date.js +1 -0
- package/dist/internal/grid.d.ts +69 -0
- package/dist/internal/grid.js +1 -0
- package/dist/internal/icons.d.ts +31 -0
- package/dist/internal/icons.js +1 -1
- package/dist/internal/picker.d.ts +111 -0
- package/dist/internal/picker.js +1 -0
- package/dist/internal/sizer.d.ts +33 -0
- package/dist/internal/sizer.js +1 -0
- package/dist/internal/styles.d.ts +33 -0
- package/dist/internal/styles.js +1 -1
- package/dist/styles.css +2 -758
- package/dist/tailwind.css +892 -0
- package/dist/types.d.ts +65 -0
- package/package.json +18 -5
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
<img src=".github/128x128.png" alt="Neba UI" width="128" height="128" />
|
|
2
|
+
|
|
1
3
|
# Neba UI
|
|
2
4
|
|
|
3
5
|
[](https://github.com/jooy2/neba/blob/main/LICENSE)   [](https://www.npmjs.com/package/neba) [](https://www.npmjs.com/package/neba)  [](https://github.com/jooy2) 
|
|
4
6
|
|
|
5
7
|
### 📘 [**neba.cdget.com**](https://neba.cdget.com)
|
|
6
8
|
|
|
7
|
-
[](https://neba.cdget.com/
|
|
9
|
+
[](https://neba.cdget.com/examples/)
|
|
8
10
|
|
|
9
11
|
Live previews and full props for every component. This README is just the quick start.
|
|
10
12
|
|
|
@@ -12,7 +14,7 @@ Live previews and full props for every component. This README is just the quick
|
|
|
12
14
|
|
|
13
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.
|
|
14
16
|
|
|
15
|
-
You install one package, add
|
|
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.
|
|
16
18
|
|
|
17
19
|
- **A broad component set, still growing** — enough to build a whole screen without reaching elsewhere.
|
|
18
20
|
- **One shared vocabulary** — `size`, `color`, `variant`, `density`, `elevation`. An `md` is the same height on every control; `primary` is the same colour everywhere.
|
|
@@ -20,7 +22,7 @@ You install one package, add two lines to your CSS, and import components. There
|
|
|
20
22
|
- **Dark mode with no work** — follows the system, and can be forced either way per subtree.
|
|
21
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.
|
|
22
24
|
- **ESM only**, TypeScript declarations included, tree-shakeable — every component compiles to its own module.
|
|
23
|
-
- **One runtime dependency.** React 19, Node.js 18 or later.
|
|
25
|
+
- **One runtime dependency.** React 18 or 19, Node.js 18 or later.
|
|
24
26
|
|
|
25
27
|
## Documentation
|
|
26
28
|
|
|
@@ -31,9 +33,9 @@ Everything is documented at **[neba.cdget.com](https://neba.cdget.com)**, where
|
|
|
31
33
|
| [**Getting started**](https://neba.cdget.com/guide/getting-started) | Install and setup, end to end. |
|
|
32
34
|
| [**All components**](https://neba.cdget.com/components/) | Every component, one page each: live previews and the full props table. |
|
|
33
35
|
| [**Examples**](https://neba.cdget.com/examples/) | A whole sample screen, explained block by block. |
|
|
34
|
-
| [**Design language**](https://neba.cdget.com/
|
|
35
|
-
| [**Prop conventions**](https://neba.cdget.com/
|
|
36
|
-
| [**Color**](https://neba.cdget.com/
|
|
36
|
+
| [**Design language**](https://neba.cdget.com/design/design-language) | Why a Neba surface looks and behaves the way it does. |
|
|
37
|
+
| [**Prop conventions**](https://neba.cdget.com/design/prop-conventions) | The shared vocabulary every component draws from. |
|
|
38
|
+
| [**Color**](https://neba.cdget.com/design/color) | The token families, and how to theme them. |
|
|
37
39
|
|
|
38
40
|
Also available in Korean / 한국어 문서: **[neba.cdget.com/ko/](https://neba.cdget.com/ko/)**
|
|
39
41
|
|
|
@@ -47,21 +49,27 @@ npm install neba
|
|
|
47
49
|
pnpm add neba
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
`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
53
|
|
|
52
54
|
### Setup
|
|
53
55
|
|
|
54
|
-
Add
|
|
56
|
+
Add one line to your app's CSS entry point:
|
|
55
57
|
|
|
56
58
|
```css
|
|
57
|
-
@import 'tailwindcss';
|
|
58
59
|
@import 'neba/styles.css';
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
`neba/styles.css`
|
|
62
|
+
`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
63
|
|
|
63
64
|
That is the whole setup. No provider is required at the root, no theme object, no config file.
|
|
64
65
|
|
|
66
|
+
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:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
@import 'tailwindcss';
|
|
70
|
+
@import 'neba/tailwind.css';
|
|
71
|
+
```
|
|
72
|
+
|
|
65
73
|
## Usage
|
|
66
74
|
|
|
67
75
|
Import components from the package root:
|
|
@@ -93,7 +101,7 @@ The reason a Neba screen looks composed rather than assembled is that the props
|
|
|
93
101
|
| `density` | `default` `compact` | Padding only — never the height, never the type scale, so a compact control still lines up with a default one. |
|
|
94
102
|
| `elevation` | `0` `1` `2` `3` | How far a surface floats off the page. `0` is the default and means no shadow at all. |
|
|
95
103
|
|
|
96
|
-
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/
|
|
104
|
+
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).
|
|
97
105
|
|
|
98
106
|
```tsx
|
|
99
107
|
<Button size="sm" color="danger" variant="outline">Delete</Button>
|
|
@@ -102,15 +110,15 @@ Placement props are logical, not physical — `start`/`end` rather than `left`/`
|
|
|
102
110
|
|
|
103
111
|
### Components
|
|
104
112
|
|
|
105
|
-
**Inputs** — Button, ButtonGroup, TextField, NumberField, Select, Combobox, Checkbox, RadioGroup, Switch, Slider, Menu (with submenus, checkbox and radio items), ContextMenu, FilePicker, Pagination
|
|
113
|
+
**Inputs** — Button, IconButton, ButtonGroup, SegmentedButton, TextField, NumberField, Select, Combobox, Checkbox, RadioGroup, Switch, Slider, Menu (with submenus, checkbox and radio items), ContextMenu, FilePicker, Pagination, DatePicker, TimePicker, DateTimePicker, DateRangePicker
|
|
106
114
|
|
|
107
|
-
**Surfaces** — Box, Card, Accordion, Tabs
|
|
115
|
+
**Surfaces** — Box, Card, Accordion, Tabs, Carousel, Toolbar, Pill
|
|
108
116
|
|
|
109
|
-
**Display** — Typography, Divider, Chip, Badge, List, Table
|
|
117
|
+
**Display** — Typography, Blockquote, Highlight, Divider, Chip, Badge, Icon, Shortcut, Statistic, List, Table, Timeline
|
|
110
118
|
|
|
111
119
|
**Feedback** — Alert, Dialog, Toast, Tooltip, Overlay, ProgressLinear, ProgressCircular, ProgressBox
|
|
112
120
|
|
|
113
|
-
Recent additions: **
|
|
121
|
+
Recent additions: **Blockquote** (somebody else's words, with the `figure`/`figcaption` markup the spec actually asks for), **Shortcut** (a keyboard key or combination, where `Mod` resolves to Command on a Mac and Control everywhere else, and every glyph carries its name for a screen reader), **Highlight** (marks the words a reader searched for, walking into elements rather than demanding a plain string), **SegmentedButton** (exactly one of a set, in one pill, with a tile that slides between the choices and transforms nothing), and **Timeline** (a sequence of steps in the order they happen, vertical or as a horizontal stepper); before those, the four pickers — **DatePicker**, **TimePicker**, **DateTimePicker** and **DateRangePicker** — which take and return a plain `Date` and add no date library to your bundle.
|
|
114
122
|
|
|
115
123
|
Each one has its own page — live previews, every prop, and the variations worth seeing — under [**All components**](https://neba.cdget.com/components/).
|
|
116
124
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* The props are a `<figure>`'s rather than a `<blockquote>`'s, which is a
|
|
5
|
+
* consequence of where the drawing happens: everything a caller passes lands on
|
|
6
|
+
* the wrapper, and the wrapper is a figure or a div. Both are `HTMLElement`, so
|
|
7
|
+
* an event handler written against one works on the other.
|
|
8
|
+
*/
|
|
9
|
+
export interface BlockquoteProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'figure'>, 'color'> {
|
|
10
|
+
/**
|
|
11
|
+
* Drop shadow depth. `0` (the default) is flat — a quote is set *into* a page
|
|
12
|
+
* rather than floating over it, so this is raised even less often than on a
|
|
13
|
+
* Card.
|
|
14
|
+
* @default 0
|
|
15
|
+
*/
|
|
16
|
+
elevation?: NebaElevation;
|
|
17
|
+
/**
|
|
18
|
+
* Who said it. Its presence is what turns the quote into a `<figure>` with a
|
|
19
|
+
* `<figcaption>`, which is the markup the HTML spec asks for: an attribution
|
|
20
|
+
* is *about* the quote and is not part of what was said.
|
|
21
|
+
*/
|
|
22
|
+
author?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Where it is from — a book, a talk, a page. Rendered inside a `<cite>`, which
|
|
25
|
+
* is the element for the title of a work and, per the spec, never for the name
|
|
26
|
+
* of a person. That is what `author` is.
|
|
27
|
+
*/
|
|
28
|
+
source?: React.ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* URL of the document the quote was taken from. Lands on the `<blockquote>`'s
|
|
31
|
+
* own `cite` attribute, which is machine-readable and shown to nobody — use
|
|
32
|
+
* `source` for the part a reader should see.
|
|
33
|
+
*/
|
|
34
|
+
cite?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The mark drawn before the quote. Omit it for the house glyph, pass a node to
|
|
37
|
+
* replace it, pass `false` to take it away — the same three-way spelling Alert
|
|
38
|
+
* uses for the same idea.
|
|
39
|
+
*/
|
|
40
|
+
icon?: React.ReactNode | false;
|
|
41
|
+
/** What was said. */
|
|
42
|
+
children?: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Somebody else's words, set apart from your own.
|
|
46
|
+
*
|
|
47
|
+
* There is no Base UI primitive under this and there should not be: a quote has
|
|
48
|
+
* no state, no keyboard contract and nothing to interact with. What it has is
|
|
49
|
+
* markup that is easy to get wrong, and getting it right is most of the point.
|
|
50
|
+
*
|
|
51
|
+
* **Nothing is drawn on the `<blockquote>` itself.** The surface, the rule and
|
|
52
|
+
* the padding all belong to the element around it, and that is not tidiness —
|
|
53
|
+
* `blockquote` is one of the handful of tags a host stylesheet still styles by
|
|
54
|
+
* name. VitePress's `.vp-doc blockquote` sets a grey `border-left`, a
|
|
55
|
+
* `padding-left` and a `color`, all at a specificity a one-class utility cannot
|
|
56
|
+
* outrank, so a rule drawn on the quote itself would silently come out grey and
|
|
57
|
+
* a pixel too thin. Moving the drawing onto a wrapper is what lets the docs undo
|
|
58
|
+
* VitePress's version in `scope.css` without also undoing ours.
|
|
59
|
+
*
|
|
60
|
+
* The wrapper is a `<figure>` when there is an attribution and a `<div>` when
|
|
61
|
+
* there is not, because the HTML spec is explicit that the attribution goes
|
|
62
|
+
* *outside* the blockquote — a name inside it claims the speaker said their own
|
|
63
|
+
* name — and a `<figure>` with no `<figcaption>` in it is a figure of nothing.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Blockquote: React.ForwardRefExoticComponent<BlockquoteProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{boxPaddingClasses as n}from"../box/Box";import{hasContent as l,metaTextClasses as a,radiusClasses as o,surfaceClasses as i,surfaceSlots as s,transitionClasses as c}from"../../internal/styles";const m={xs:"text-[0.75rem]/[1.25rem]",sm:"text-[0.8125rem]/[1.375rem]",md:"text-[0.9375rem]/[1.625rem]",lg:"text-[1.0625rem]/[1.875rem]",xl:"text-[1.25rem]/[2.125rem]"},d="border-s-2 [border-inline-start-color:var(--n-accent)]",x={solid:[i,"bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[i,"border border-s-2 bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"bg-transparent"};function f(){return e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:e("path",{d:"M6.4 3.6c-2.3.9-3.7 2.8-3.7 5.1 0 2 1.2 3.3 2.8 3.3 1.4 0 2.5-1 2.5-2.4 0-1.3-.9-2.2-2.1-2.2-.2 0-.4 0-.6.1.3-1 1.1-1.8 2.2-2.3l-1.1-1.6ZM13.3 3.6c-2.3.9-3.7 2.8-3.7 5.1 0 2 1.2 3.3 2.8 3.3 1.4 0 2.5-1 2.5-2.4 0-1.3-.9-2.2-2.1-2.2-.2 0-.4 0-.6.1.3-1 1.1-1.8 2.2-2.3l-1.1-1.6Z",fill:"currentColor"})})}export const Blockquote=t.forwardRef(function({variant:t="text",size:i="md",color:u="primary",density:b="default",elevation:p=0,author:h,source:v,cite:g,icon:N,className:j,style:y,children:w,...B},k){const z=l(h)||l(v),q=void 0===N?e(f,{}):N,M=["flex flex-col text-(--neba-fg)",d,"text"===t?"":`${o[i]} rounded-s-none`,x[t],n[b][i],c,j??""].filter(Boolean).join(" "),Z=r("blockquote",{cite:g,className:m[i],children:[l(q)?e("span",{"aria-hidden":"true",className:"mb-1 block size-[2em] text-(--n-soft-press) [&>svg]:size-full",children:q}):null,w]}),C={...s(u,p),...y};return z?r("figure",{ref:k,className:M,style:C,...B,children:[Z,r("figcaption",{className:["mt-2 flex flex-wrap items-baseline gap-x-1.5 text-(--neba-muted-fg)",a[i]].join(" "),children:[l(h)?r("span",{className:"font-medium text-(--neba-fg)",children:[e("span",{"aria-hidden":"true",children:"— "}),h]}):null,l(v)?e("cite",{className:"not-italic",children:v}):null]})]}):e("div",{ref:k,className:M,style:C,...B,children:Z})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Blockquote}from"./Blockquote";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
export interface CarouselProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
/**
|
|
5
|
+
* Drop shadow depth of the frame. `0` — the default — is flat.
|
|
6
|
+
* @default 0
|
|
7
|
+
*/
|
|
8
|
+
elevation?: NebaElevation;
|
|
9
|
+
/** Which slide is showing, counted from 0. Use with `onValueChange`. */
|
|
10
|
+
value?: number;
|
|
11
|
+
/** Which starts showing, for an uncontrolled carousel. @default 0 */
|
|
12
|
+
defaultValue?: number;
|
|
13
|
+
onValueChange?: (index: number) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the arrows wrap from the last slide back to the first. With it off
|
|
16
|
+
* they go inert at the ends instead, which is the honest thing for a set that
|
|
17
|
+
* has a beginning and an end — a gallery of three photographs does, a rotating
|
|
18
|
+
* banner does not.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
loop?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Advances on its own.
|
|
24
|
+
*
|
|
25
|
+
* Off by default and deliberately so: a carousel that moves while it is being
|
|
26
|
+
* read is the most complained-about pattern on the web. It pauses on hover,
|
|
27
|
+
* on focus anywhere inside it, while the tab is in the background, and it does
|
|
28
|
+
* not start at all for a reader who has asked for reduced motion.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
autoPlay?: boolean;
|
|
32
|
+
/** How long each slide is held, in milliseconds. @default 5000 */
|
|
33
|
+
interval?: number;
|
|
34
|
+
/** The previous/next buttons. @default true */
|
|
35
|
+
arrows?: boolean;
|
|
36
|
+
/** The row of position dots under the frame. @default true */
|
|
37
|
+
indicators?: boolean;
|
|
38
|
+
/** The carousel's accessible name. @default 'Carousel' */
|
|
39
|
+
label?: string;
|
|
40
|
+
/** @default 'Previous slide' */
|
|
41
|
+
previousLabel?: string;
|
|
42
|
+
/** @default 'Next slide' */
|
|
43
|
+
nextLabel?: string;
|
|
44
|
+
/**
|
|
45
|
+
* How one slide is named to a screen reader, and how its dot is labelled.
|
|
46
|
+
* @default (index, count) => `Slide ${index} of ${count}`
|
|
47
|
+
*/
|
|
48
|
+
slideLabel?: (index: number, count: number) => string;
|
|
49
|
+
/** The slides. Every top-level child becomes one. */
|
|
50
|
+
children?: React.ReactNode;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A strip of slides, one of which is in view.
|
|
54
|
+
*
|
|
55
|
+
* The mechanism is a scroll container with CSS scroll snapping, and everything
|
|
56
|
+
* good about this component follows from that one choice. Swiping on a phone and
|
|
57
|
+
* two-finger dragging on a trackpad both work because they are the browser's own
|
|
58
|
+
* scrolling and not a gesture handler pretending to be it. The strip runs the
|
|
59
|
+
* other way under RTL without being told, because scrolling is directional and
|
|
60
|
+
* `translate` is not. And nothing is transformed — the house rule against moving
|
|
61
|
+
* a surface holds here for free, where a translated track would have had to
|
|
62
|
+
* argue for an exception.
|
|
63
|
+
*
|
|
64
|
+
* The motion is `scroll-behavior: smooth`, which means a reader who has asked
|
|
65
|
+
* for reduced motion gets an instant cut from the same code path rather than
|
|
66
|
+
* from a second one written to remember them.
|
|
67
|
+
*
|
|
68
|
+
* Slides are not a sub-component. Every top-level child is wrapped in its own
|
|
69
|
+
* slide, so `<Carousel><img /><img /></Carousel>` is the whole API — and the
|
|
70
|
+
* wrapper is what carries the snap point, the width and the
|
|
71
|
+
* `role="group"`/`aria-roledescription="slide"` pair a screen reader needs, none
|
|
72
|
+
* of which a caller should have to remember to put on a photograph.
|
|
73
|
+
*/
|
|
74
|
+
export declare const Carousel: React.ForwardRefExoticComponent<CarouselProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{IconButton as n}from"../icon-button/IconButton";import{ChevronIcon as a}from"../../internal/icons";import{radiusClasses as o,srOnlyClasses as i,surfaceClasses as l,surfaceSlots as s,transitionClasses as c}from"../../internal/styles";const u={solid:[l,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[l,"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"},d={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"},f={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"}},m=(e,r)=>`Slide ${e} of ${r}`;export const Carousel=t.forwardRef(function({variant:l="outline",size:p="md",color:v="primary",density:h="default",elevation:b=0,value:w,defaultValue:g=0,onValueChange:x,loop:N=!0,autoPlay:y=!1,interval:j=5e3,arrows:k=!0,indicators:C=!0,label:M="Carousel",previousLabel:R="Previous slide",nextLabel:$="Next slide",slideLabel:I=m,className:L,style:P,children:S,..._},z){const B=t.Children.toArray(S),E=B.length,[V,T]=t.useState(g),W=Math.min(Math.max(w??V,0),Math.max(E-1,0)),A=t.useRef(null),F=t.useRef([]),q=t.useRef(!1),D=t.useRef(!1),G=t.useRef(!1),[H,J]=t.useState(!1),K=t.useCallback((e,r=!1)=>{if(0===E)return;const t=N?(e%E+E)%E:Math.min(Math.max(e,0),E-1);q.current=r,void 0===w&&T(t),t!==W&&x?.(t)},[E,N,w,W,x]);t.useEffect(()=>{if(q.current)return void(q.current=!1);if(!D.current)return void(D.current=!0);F.current[W]?.scrollIntoView({block:"nearest",inline:"start"}),G.current=!0;const e=window.setTimeout(()=>{G.current=!1},700);return()=>window.clearTimeout(e)},[W]);t.useEffect(()=>{if(!y||H||E<2)return;if(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches)return;const e=window.setInterval(()=>{document.hidden||K(W+1)},j);return()=>window.clearInterval(e)},[y,H,E,j,W,K]);const O=W<=0,Q=W>=E-1;return r("div",{ref:z,role:"region","aria-roledescription":"carousel","aria-label":M,className:["flex flex-col",L??""].filter(Boolean).join(" "),style:{...s(v,b),...P},onPointerEnter:()=>J(!0),onPointerLeave:()=>J(!1),onFocus:()=>J(!0),onBlur:()=>J(!1),..._,children:[r("div",{className:["relative min-w-0 overflow-hidden",o[p],u[l],c].join(" "),children:[e("div",{ref:A,tabIndex:0,role:"group","aria-label":M,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=A.current;if(!e||0===e.clientWidth||G.current)return;const r=Math.round(Math.abs(e.scrollLeft)/e.clientWidth);r!==W&&r>=0&&r<E&&K(r,!0)},children:B.map((r,t)=>e("div",{ref:e=>{F.current[t]=e},role:"group","aria-roledescription":"slide","aria-label":I(t+1,E),className:"w-full shrink-0 grow-0 basis-full snap-start",children:r},t))}),k&&E>1?r("div",{className:`pointer-events-none absolute inset-y-0 flex items-center ${d[p]}`,children:[e(n,{variant:"solid",size:p,color:v,density:h,elevation:1,label:R,disabled:!N&&O,className:"pointer-events-auto",icon:e("span",{className:"flex items-center rotate-90 rtl:-rotate-90",children:e(a,{})}),onClick:()=>K(W-1)}),e("span",{className:"flex-1"}),e(n,{variant:"solid",size:p,color:v,density:h,elevation:1,label:$,disabled:!N&&Q,className:"pointer-events-auto",icon:e("span",{className:"flex items-center -rotate-90 rtl:rotate-90",children:e(a,{})}),onClick:()=>K(W+1)})]}):null]}),C&&E>1?e("div",{className:`flex shrink-0 items-center justify-center pt-2 ${f[p].gap}`,children:B.map((r,t)=>e("button",{type:"button","aria-label":I(t+1,E),"aria-current":t===W?"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===W?`${f[p].current} bg-(--n-accent)`:`${f[p].rest} bg-(--n-line-hover) hover:bg-(--n-accent)`].join(" "),onClick:()=>K(t)},t))}):null,e("span",{className:i,"aria-live":y?"off":"polite",children:E>0?I(W+1,E):""})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Carousel}from"./Carousel";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as r from"react";import{Checkbox as a}from"@base-ui/react/checkbox";import{Field as i}from"@base-ui/react/field";import{controlTextClasses as l,metaTextClasses as t,surfaceClasses as o,tickRadiusClasses as s,tickRowLeadingClasses as d,tickSizeClasses as c,transitionClasses as b}from"../../internal/styles";const h=["relative inline-flex shrink-0 items-center justify-center border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",b,"active:[transition-duration:0ms]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),f=[o,"cursor-pointer bg-(--n-panel) [border-color:var(--n-line)]","hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]","data-[checked]:hover:bg-(--n-fill-hover)","data-[indeterminate]:bg-(--n-fill) data-[indeterminate]:text-(--n-on-solid)","data-[indeterminate]:[border-color:transparent]"].join(" "),m=[o,"cursor-default bg-(--n-panel) [border-color:var(--n-line)]","[filter:saturate(0.55)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]"].join(" "),u=["cursor-not-allowed bg-transparent [border-color:var(--neba-disabled-border)]","text-(--neba-disabled-fg) shadow-none","data-[checked]:bg-(--neba-disabled-bg)","data-[indeterminate]:bg-(--neba-disabled-bg)"].join(" ");function v(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2 6.2 4.6 8.8 10 3.4",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function p(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2.5 6h7",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}export const Checkbox=r.forwardRef(function({size:r="md",color:o="primary",label:b,description:g,error:x,invalid:k,disabled:j=!1,readOnly:N=!1,className:$,style:y,...w},z){const C=null!=x&&!1!==x&&""!==x,L=k??C,B=L?"danger":o,R={"--n-fill":`var(--neba-${B}-fill)`,"--n-fill-hover":`var(--neba-${B}-fill-hover)`,"--n-on-solid":`var(--neba-${B}-on-solid)`,"--n-accent":`var(--neba-${B}-accent)`,"--n-panel":"var(--neba-panel)","--n-panel-hover":"var(--neba-panel-hover)","--n-line":`var(--neba-${B}-line)`,"--n-line-hover":`var(--neba-${B}-line-hover)`,"--n-ring":`var(--neba-${B}-ring)`},M=[h,c[r],s[r],j?u:N?m:f].join(" ");return n(i.Root,{disabled:j,invalid:L,className:["inline-flex flex-col gap-1 align-top",$??""].filter(Boolean).join(" "),style:{...R,...y},children:[n("div",{className:`flex items-start gap-2 ${l[r]} ${d}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(a.Root,{ref:z,className:M,disabled:j,readOnly:N,...w,children:e(a.Indicator,{className:"flex size-[70%] items-center justify-center",children:w.indeterminate?e(p,{}):e(v,{})})})}),b||g?n("span",{className:"flex min-w-0 flex-col gap-0.5",children:[b?e(i.Label,{className:["leading-[1.4]",j?"text-(--neba-disabled-fg)":"cursor-pointer text-(--neba-fg)"].join(" "),children:b}):null,g?e(i.Description,{className:`${t[r]} text-(--neba-muted-fg)`,children:g}):null]}):null]}),C?e(i.Error,{match:!0,className:`${t[r]} text-(--n-accent)`,children:x}):null]})});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Combobox as n}from"@base-ui/react/combobox";import{Field as t}from"@base-ui/react/field";import{Chip as i}from"../chip/Chip";import{CheckIcon as r,ChevronIcon as o,CloseIcon as s,PlusIcon as c}from"../../internal/icons";import{chipRemoveClasses as d,controlHeightClasses as u,controlTextLeadingClasses as m,disabledClasses as p,fieldReadOnlyClasses as h,fieldRestClasses as b,focusWithinRingClasses as f,gapClasses as g,hasContent as x,iconClasses as v,metaTextClasses as y,paddingXClasses as N,radiusClasses as w,stackGapClasses as C,surfaceClasses as j,surfaceSlots as L,transitionClasses as
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Combobox as n}from"@base-ui/react/combobox";import{Field as t}from"@base-ui/react/field";import{Chip as i}from"../chip/Chip";import{CheckIcon as r,ChevronIcon as o,CloseIcon as s,PlusIcon as c}from"../../internal/icons";import{chipRemoveClasses as d,controlHeightClasses as u,controlTextLeadingClasses as m,disabledClasses as p,fieldReadOnlyClasses as h,fieldRestClasses as b,focusWithinRingClasses as f,gapClasses as g,hasContent as x,iconClasses as v,metaTextClasses as y,paddingXClasses as N,radiusClasses as w,stackGapClasses as C,surfaceClasses as j,surfaceSlots as L,transitionClasses as $}from"../../internal/styles";const I=["group relative flex w-full cursor-text items-center","[-webkit-tap-highlight-color:transparent]",$,"focus-within:[transition-duration:0ms]",f,v].join(" "),S={xs:"min-h-5.5 py-0",sm:"min-h-6.5 py-[2px]",md:"min-h-8 py-[3px]",lg:"min-h-10 py-[4px]",xl:"min-h-12 py-[4px]"},O=[j,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","w-[var(--anchor-width)] border bg-(--n-panel-press) p-1","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]"].join(" "),V=["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--neba-radius-xs) py-1.5 pe-2 ps-7",$,"data-[highlighted]:bg-(--n-soft-hover) data-[highlighted]:text-(--n-accent)","data-[selected]:text-(--n-accent) data-[selected]:font-medium","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)","[outline:none]"].join(" "),_=["inline-flex h-[1lh] shrink-0 cursor-pointer items-center justify-center","rounded-(--neba-radius-xs) text-(--neba-muted-fg)","[transition:color_var(--neba-duration)_var(--neba-ease)]","hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1","disabled:cursor-not-allowed disabled:text-(--neba-disabled-fg)"].join(" ");function z(e){return null==e?[]:Array.isArray(e)?e.slice():[e]}export function Combobox({variant:f="outline",size:v="md",color:j="primary",density:$="default",elevation:A=0,items:R,multiple:k,value:T,defaultValue:q,onValueChange:E,onInputValueChange:F,allowCustom:M=!0,customLabel:P,clearable:B=!1,emptyMessage:D="No matches",limit:G,placeholder:H,label:W,description:J,error:K,invalid:Q,startIcon:U,fullWidth:X=!1,disabled:Y=!1,readOnly:Z=!1,required:ee=!1,name:ae,open:le,defaultOpen:ne,onOpenChange:te,clearLabel:ie="Clear",removeLabel:re=e=>`Remove ${e}`,inputRef:oe,id:se,className:ce,style:de}){const ue=x(K),me=Q??ue,pe=me?"danger":j,he=!0===k,be=l.useMemo(()=>R.map(e=>({value:e.value,label:e.label??String(e.value),disabled:e.disabled})),[R]),[fe,ge]=l.useState(()=>z(q)),xe=void 0===T?fe:z(T),[ve,ye]=l.useState(""),Ne=l.useCallback(e=>be.find(a=>a.value===e)??{value:e,label:String(e),custom:!0},[be]),we=ve.trim(),Ce=we.toLocaleLowerCase(),je=""===we||be.some(e=>e.label.toLocaleLowerCase()===Ce||String(e.value).toLocaleLowerCase()===Ce)||xe.some(e=>String(e).toLocaleLowerCase()===Ce),Le=!M||Z||Y||je?null:we,$e=l.useMemo(()=>null===Le?be:[...be,{value:Le,label:Le,custom:!0}],[be,Le]),Ie=he?xe.map(Ne):xe.length>0?Ne(xe[0]):null;const Se=N[$][v],Oe=[I,m[v],w[v],g[v],he?S[v]:u[v],`${Se} pe-1.5`,Y?p[f]:Z?h[f]:b[f]].join(" "),Ve=["min-w-0 flex-1 self-stretch bg-transparent [font:inherit] text-inherit","[outline:none]","placeholder:text-(--neba-muted-fg)","caret-(--n-accent) selection:bg-(--n-soft-press)","disabled:cursor-not-allowed"].join(" "),_e=a=>e(n.Input,{ref:oe,placeholder:H,className:he?`${Ve} min-w-16 ${a?"ms-1.5":""}`:Ve});return a(t.Root,{disabled:Y,invalid:me,className:["flex-col align-top",C[v],X?"flex w-full":"inline-flex",ce??""].filter(Boolean).join(" "),style:{...L(pe,A),...de},children:[W?e(t.Label,{className:[y[v],"font-medium",Y?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:W}):null,a(n.Root,{id:se,name:ae,items:$e,multiple:he,value:Ie,onValueChange:e=>{!function(e){void 0===T&&ge(e),E?.(he?e:e[0]??null)}((null===e?[]:Array.isArray(e)?e:[e]).map(e=>e.value))},onInputValueChange:e=>{ye(e),F?.(e)},open:le,defaultOpen:ne,onOpenChange:e=>te?.(e),autoHighlight:!0,itemToStringLabel:e=>e.label,itemToStringValue:e=>String(e.value),isItemEqualToValue:(e,a)=>e.value===a.value,limit:G,disabled:Y,readOnly:Z,required:ee,children:[a(n.InputGroup,{className:Oe,children:[U?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:U}):null,he?e(n.Chips,{className:"flex min-w-0 flex-1 flex-wrap items-center gap-1",children:e(n.Value,{children:t=>a(l.Fragment,{children:[t.map(a=>e(n.Chip,{render:e(i,{variant:"outline",size:v,color:pe,density:"compact",disabled:Y,endIcon:Z||Y?null:e(n.ChipRemove,{"aria-label":re(a.label),className:d,children:e(s,{})})}),children:a.label},String(a.value))),_e(t.length>0)]})})}):_e(!1),B&&!Z?e(n.Clear,{"aria-label":ie,className:_,children:e(s,{})}):null,e(n.Trigger,{"aria-label":"string"==typeof W?void 0:"Open",className:_,children:e(n.Icon,{className:["flex items-center","[transition:rotate_var(--neba-duration)_var(--neba-ease)]","data-[popup-open]:rotate-180"].join(" "),children:e(o,{})})})]}),e(n.Portal,{children:e(n.Positioner,{className:"neba-portal z-50 [outline:none]",sideOffset:6,children:a(n.Popup,{className:`${O} ${w[v]} ${m[v]}`,style:L(pe,3),children:[e(n.Empty,{className:"px-2 py-1.5 text-(--neba-muted-fg) empty:hidden",children:D}),e(n.List,{children:t=>e(n.Item,{value:t,disabled:t.disabled,className:V,children:t.custom?a(l.Fragment,{children:[e("span",{className:"absolute start-1.5 flex size-4 items-center justify-center text-(--n-accent) [&_svg]:size-4",children:e(c,{})}),e("span",{className:"truncate",children:P?P(t.label):`Add “${t.label}”`})]}):a(l.Fragment,{children:[e(n.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(r,{})}),e("span",{className:"truncate",children:t.label})]})},`${t.custom?"custom:":""}${String(t.value)}`)})]})})})]}),J?e(t.Description,{className:`${y[v]} text-(--neba-muted-fg)`,children:J}):null,ue?e(t.Error,{match:!0,className:`${y[v]} text-(--n-accent)`,children:K}):null]})}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaDensity, NebaSize } from '../../types';
|
|
4
|
+
export interface ContainerProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
5
|
+
/**
|
|
6
|
+
* How wide the content is allowed to get, on the same ladder the breakpoints
|
|
7
|
+
* use — `sm` 40rem, `md` 48rem, `lg` 64rem, `xl` 80rem, `xs` 30rem.
|
|
8
|
+
*
|
|
9
|
+
* `none`, the default, is no limit: a Container's job is the gutter, and a
|
|
10
|
+
* measure is a second decision that a page should have to ask for.
|
|
11
|
+
* @default 'none'
|
|
12
|
+
*/
|
|
13
|
+
maxWidth?: NebaSize | 'none';
|
|
14
|
+
/**
|
|
15
|
+
* The gutter, on the `size`/`density` scale. Turn it off to keep the
|
|
16
|
+
* centring and the measure without the padding.
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
padded?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The gutter's scale. As on Box, `size` here is the size of the *sheet* — it
|
|
22
|
+
* never touches a height or the type scale — and it is independent of
|
|
23
|
+
* `maxWidth`, which is how wide the content gets rather than how far it sits
|
|
24
|
+
* from the edge.
|
|
25
|
+
* @default 'md'
|
|
26
|
+
*/
|
|
27
|
+
size?: NebaSize;
|
|
28
|
+
/** @default 'default' */
|
|
29
|
+
density?: NebaDensity;
|
|
30
|
+
/**
|
|
31
|
+
* Centres the content once `maxWidth` is narrower than the page. No effect
|
|
32
|
+
* while `maxWidth` is `none`, because there is nothing left over to centre in.
|
|
33
|
+
* @default true
|
|
34
|
+
*/
|
|
35
|
+
centered?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Renders something other than a `<div>`: `render={<main />}`,
|
|
38
|
+
* `render={<section />}`. Base UI's own escape hatch.
|
|
39
|
+
*/
|
|
40
|
+
render?: useRender.RenderProp;
|
|
41
|
+
children?: React.ReactNode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Horizontal breathing room, and optionally a measure.
|
|
45
|
+
*
|
|
46
|
+
* Nothing to do with the grid — a Container holds a grid as happily as it holds
|
|
47
|
+
* a single paragraph, and a `GridContainer` needs no Container around it. The
|
|
48
|
+
* two are separate because the questions are separate: how far the content sits
|
|
49
|
+
* from the edge of the window, and how the content divides itself up.
|
|
50
|
+
*
|
|
51
|
+
* It draws no surface for the same reason `GridContainer` does not. The
|
|
52
|
+
* outermost element on a page is the one thing that must not decide what the
|
|
53
|
+
* page looks like.
|
|
54
|
+
*/
|
|
55
|
+
export declare const Container: React.ForwardRefExoticComponent<ContainerProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import*as e from"react";import{useRender as r}from"@base-ui/react/use-render";import{boxPaddingXClasses as m}from"../box/Box";const o={xs:"max-w-[30rem]",sm:"max-w-[40rem]",md:"max-w-[48rem]",lg:"max-w-[64rem]",xl:"max-w-[80rem]"};export const Container=e.forwardRef(function({maxWidth:e="none",padded:n=!0,size:a="md",density:t="default",centered:d=!0,render:s,className:i,children:c,...l},x){const f=["block w-full","none"===e?"":o[e],d?"mx-auto":"",n?m[t][a]:"",i??""].filter(Boolean).join(" ");return r({render:s,ref:x,props:{className:f,children:c,...l}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Container}from"./Container";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PickerLabels } from '../../internal/calendar';
|
|
3
|
+
import { type PickerShellProps } from '../../internal/picker';
|
|
4
|
+
import type { NebaWeekday } from '../../types';
|
|
5
|
+
/**
|
|
6
|
+
* What the four pickers agree on, so a caller who has learned one has learned
|
|
7
|
+
* the others. Spelled out here rather than in `internal/` because these are the
|
|
8
|
+
* props a reader of the docs is actually looking at.
|
|
9
|
+
*/
|
|
10
|
+
export interface DatePickerProps extends PickerShellProps {
|
|
11
|
+
/** The chosen day. Use with `onValueChange` for a controlled picker. */
|
|
12
|
+
value?: Date | null;
|
|
13
|
+
/** The day the picker starts on, for an uncontrolled one. */
|
|
14
|
+
defaultValue?: Date | null;
|
|
15
|
+
onValueChange?: (value: Date | null) => void;
|
|
16
|
+
/** Whether the calendar is open. Use with `onOpenChange` to control it. */
|
|
17
|
+
open?: boolean;
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
onOpenChange?: (open: boolean) => void;
|
|
20
|
+
/** Which month the calendar opens on when there is no value. @default this one */
|
|
21
|
+
defaultMonth?: Date;
|
|
22
|
+
/** The earliest day that may be chosen. Day-granular — the time is ignored. */
|
|
23
|
+
minDate?: Date | null;
|
|
24
|
+
/** The latest day that may be chosen. */
|
|
25
|
+
maxDate?: Date | null;
|
|
26
|
+
/**
|
|
27
|
+
* Blocks individual days that are inside the range but still not available —
|
|
28
|
+
* weekends, holidays, a room that is already booked.
|
|
29
|
+
*/
|
|
30
|
+
shouldDisableDate?: (date: Date) => boolean;
|
|
31
|
+
/**
|
|
32
|
+
* BCP 47 tag deciding the month and weekday names, the order of the header's
|
|
33
|
+
* two buttons, and how the trigger writes the date. Defaults to the browser's.
|
|
34
|
+
*/
|
|
35
|
+
locale?: string;
|
|
36
|
+
/** Which day the week starts on. Defaults to whatever the locale says. */
|
|
37
|
+
weekStartsOn?: NebaWeekday;
|
|
38
|
+
/**
|
|
39
|
+
* How the trigger writes the chosen date. Passed straight to `Intl`, so
|
|
40
|
+
* `{ dateStyle: 'full' }` and `{ year: '2-digit', month: 'narrow' }` both work.
|
|
41
|
+
* @default { dateStyle: 'medium' }
|
|
42
|
+
*/
|
|
43
|
+
format?: Intl.DateTimeFormatOptions;
|
|
44
|
+
/** Shown in the trigger while nothing is chosen. */
|
|
45
|
+
placeholder?: React.ReactNode;
|
|
46
|
+
/** Offers the × that empties the control. @default false */
|
|
47
|
+
clearable?: boolean;
|
|
48
|
+
/** Offers the shortcut to today in the footer. @default true */
|
|
49
|
+
showTodayButton?: boolean;
|
|
50
|
+
/** Closes the popup as soon as a day is chosen. @default true */
|
|
51
|
+
closeOnSelect?: boolean;
|
|
52
|
+
/** The strings a screen reader hears. Every one has an English default. */
|
|
53
|
+
labels?: Partial<PickerLabels>;
|
|
54
|
+
/** Identifies the field when a form is submitted, as `YYYY-MM-DD`. */
|
|
55
|
+
name?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One day, chosen from a calendar.
|
|
59
|
+
*
|
|
60
|
+
* The trigger is a TextField's shell wearing a calendar glyph, on purpose and
|
|
61
|
+
* for the reason Select's is: a form where the date field is a different height,
|
|
62
|
+
* radius or colour from the fields around it is a form that looks assembled.
|
|
63
|
+
*
|
|
64
|
+
* What the calendar is actually for is the header. A picker that only steps a
|
|
65
|
+
* month at a time puts a birthday thirty years back a hundred and eighty clicks
|
|
66
|
+
* away, so the month name and the year are each a button that opens a grid of
|
|
67
|
+
* its own — twelve months, then twelve years at a time. Any month of the year on
|
|
68
|
+
* screen is two clicks; any year at all is three.
|
|
69
|
+
*
|
|
70
|
+
* There is no typing into the trigger. Parsing a date out of free text is
|
|
71
|
+
* locale-dependent in a way that cannot be done honestly without a date library,
|
|
72
|
+
* and a field that understands `27/7/26` in one browser and not in the next is
|
|
73
|
+
* worse than one that never claimed to.
|
|
74
|
+
*/
|
|
75
|
+
export declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Button as l}from"../button/Button";import{Calendar as o,usePickerLabels as n}from"../../internal/calendar";import{CalendarIcon as r}from"../../internal/icons";import{PickerFooter as i,PickerShell as s}from"../../internal/picker";import{displaySamples as c,formatDate as d,isDayOutside as m,isValidDate as u,localeWeekStart as p,mergeDateAndTime as f,startOfDay as h,startOfMonth as b,toISODate as y,today as x,withPlaceholder as v}from"../../internal/date";import{cx as D}from"../../internal/styles";export const DatePicker=t.forwardRef(function({value:O,defaultValue:S,onValueChange:g,open:C,defaultOpen:k,onOpenChange:z,defaultMonth:w,minDate:j,maxDate:M,shouldDisableDate:V,locale:B,weekStartsOn:I,format:R={dateStyle:"medium"},placeholder:E,clearable:F=!1,showTodayButton:N=!0,closeOnSelect:P=!0,labels:T,name:q,size:A="md",color:G="primary",readOnly:H=!1,disabled:J=!1,startIcon:K,...L},Q){const U=n(T),W=I??p(B),[X,Y]=t.useState(S??null),Z=void 0!==O?O:X,[$,_]=t.useState(k??!1),ee=C??$,[ae,te]=t.useState(()=>b(u(Z)?Z:w??x()));t.useEffect(()=>{ee&&te(b(u(Z)?Z:w??x()))},[ee]);const le=e=>{e&&(H||J)||(void 0===C&&_(e),z?.(e))},oe=e=>{void 0===O&&Y(e),g?.(e)},ne=e=>{const a=u(Z)?f(e,Z):h(e);oe(a),te(b(a)),P&&le(!1)},re=x(),ie=m(re,j,M)||(V?.(re)??!1),se=N||F,ce=t.useMemo(()=>v(c(B,R),E),[B,R,E]);return e(s,{...L,size:A,color:G,readOnly:H,disabled:J,triggerRef:Q,startIcon:K??e(r,{}),display:u(Z)?d(Z,B,R):E??"",samples:ce,empty:!u(Z),clearable:F,onClear:()=>oe(null),open:ee,onOpenChange:le,labels:U,hiddenValues:q?[{name:q,value:u(Z)?y(Z):""}]:void 0,children:a("div",{className:D("flex flex-col",se&&"gap-1.5"),children:[e(o,{size:A,color:G,locale:B,weekStartsOn:W,month:ae,onMonthChange:te,selected:[Z],onSelect:ne,minDate:j,maxDate:M,shouldDisableDate:V,labels:U,autoFocus:!0}),se?a(i,{size:A,children:[F?e(l,{variant:"text",size:A,color:G,density:"compact",onClick:()=>{oe(null),le(!1)},children:U.clear}):null,N?e(l,{variant:"text",size:A,color:G,density:"compact",disabled:ie,onClick:()=>ne(re),children:U.today}):null]}):null]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{DatePicker}from"./DatePicker";
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PickerLabels } from '../../internal/calendar';
|
|
3
|
+
import { type PickerShellProps } from '../../internal/picker';
|
|
4
|
+
import type { NebaWeekday } from '../../types';
|
|
5
|
+
/**
|
|
6
|
+
* Two ends, either of which may be missing.
|
|
7
|
+
*
|
|
8
|
+
* An object rather than a `[Date, Date]` tuple, and rather than two props. A
|
|
9
|
+
* range is one value — it is chosen in one gesture, cleared in one gesture and
|
|
10
|
+
* validated as a whole — and the two names are what stop a caller writing the
|
|
11
|
+
* end into the start. Half a range is a real state: it is what the picker holds
|
|
12
|
+
* between the first click and the second.
|
|
13
|
+
*/
|
|
14
|
+
export interface DateRange {
|
|
15
|
+
start: Date | null;
|
|
16
|
+
end: Date | null;
|
|
17
|
+
}
|
|
18
|
+
/** A named range offered as a shortcut beside the calendars. */
|
|
19
|
+
export interface DateRangePreset {
|
|
20
|
+
label: React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* The range it stands for. A function when it depends on today, which is
|
|
23
|
+
* almost always — "the last 7 days" computed at render time is a range that
|
|
24
|
+
* would be wrong for anyone who left the tab open overnight.
|
|
25
|
+
*/
|
|
26
|
+
value: DateRange | (() => DateRange);
|
|
27
|
+
}
|
|
28
|
+
export interface DateRangePickerProps extends PickerShellProps {
|
|
29
|
+
/** The chosen range. Use with `onValueChange` for a controlled picker. */
|
|
30
|
+
value?: DateRange | null;
|
|
31
|
+
defaultValue?: DateRange | null;
|
|
32
|
+
/** Always called with an object. A cleared range is `{ start: null, end: null }`. */
|
|
33
|
+
onValueChange?: (value: DateRange) => void;
|
|
34
|
+
open?: boolean;
|
|
35
|
+
defaultOpen?: boolean;
|
|
36
|
+
onOpenChange?: (open: boolean) => void;
|
|
37
|
+
/** Which month the left calendar opens on when there is no value. */
|
|
38
|
+
defaultMonth?: Date;
|
|
39
|
+
minDate?: Date | null;
|
|
40
|
+
maxDate?: Date | null;
|
|
41
|
+
shouldDisableDate?: (date: Date) => boolean;
|
|
42
|
+
locale?: string;
|
|
43
|
+
weekStartsOn?: NebaWeekday;
|
|
44
|
+
/** @default { dateStyle: 'medium' } */
|
|
45
|
+
format?: Intl.DateTimeFormatOptions;
|
|
46
|
+
/**
|
|
47
|
+
* How many months are on screen at once. Two is the default because a range
|
|
48
|
+
* that crosses a month boundary is the ordinary case, not the exception.
|
|
49
|
+
* @default 2
|
|
50
|
+
*/
|
|
51
|
+
monthCount?: 1 | 2;
|
|
52
|
+
/** Shown in each half of the trigger while that end is unchosen. */
|
|
53
|
+
startPlaceholder?: React.ReactNode;
|
|
54
|
+
endPlaceholder?: React.ReactNode;
|
|
55
|
+
/** Shortcuts listed beside the calendars — "Last 7 days", "This month". */
|
|
56
|
+
presets?: readonly DateRangePreset[];
|
|
57
|
+
clearable?: boolean;
|
|
58
|
+
/** Closes the popup once both ends are chosen. @default true */
|
|
59
|
+
closeOnSelect?: boolean;
|
|
60
|
+
labels?: Partial<PickerLabels>;
|
|
61
|
+
/**
|
|
62
|
+
* Identifies the field when a form is submitted. Two hidden inputs of the same
|
|
63
|
+
* name, so the two ends arrive as `FormData.getAll(name)`.
|
|
64
|
+
*/
|
|
65
|
+
name?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A span between two days.
|
|
69
|
+
*
|
|
70
|
+
* Two months side by side, because a range that crosses a month boundary is the
|
|
71
|
+
* ordinary case and a one-month picker makes it a two-step navigation problem.
|
|
72
|
+
* The two panels are one calendar in two halves: the left one has no forward
|
|
73
|
+
* stepper, the right one has no back stepper, and either header's month and year
|
|
74
|
+
* buttons move both.
|
|
75
|
+
*
|
|
76
|
+
* The band between the ends is drawn as the pointer moves, before the second
|
|
77
|
+
* click lands. That preview is the whole affordance — without it the first click
|
|
78
|
+
* has no visible consequence and the control looks broken for the second or so
|
|
79
|
+
* between the two.
|
|
80
|
+
*/
|
|
81
|
+
export declare const DateRangePicker: React.ForwardRefExoticComponent<DateRangePickerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as n from"react";import{Button as a}from"../button/Button";import{Calendar as t,usePickerLabels as r}from"../../internal/calendar";import{ArrowRightIcon as s,CalendarIcon as o}from"../../internal/icons";import{PickerFooter as i,PickerShell as c}from"../../internal/picker";import{WidthSizer as u}from"../../internal/sizer";import{addMonths as d,compareDay as m,displaySamples as h,formatDate as p,isValidDate as f,localeWeekStart as x,startOfDay as v,startOfMonth as g,toISODate as b,today as w,withPlaceholder as y}from"../../internal/date";import{cx as N,gapClasses as S,metaTextClasses as C}from"../../internal/styles";const D={start:null,end:null};export const DateRangePicker=n.forwardRef(function({value:O,defaultValue:k,onValueChange:z,open:P,defaultOpen:j,onOpenChange:B,defaultMonth:M,minDate:R,maxDate:V,shouldDisableDate:E,locale:I,weekStartsOn:F,format:q={dateStyle:"medium"},monthCount:A=2,startPlaceholder:G,endPlaceholder:H,presets:J,clearable:K=!1,closeOnSelect:L=!0,labels:Q,name:T,size:U="md",color:W="primary",readOnly:X=!1,disabled:Y=!1,startIcon:Z,...$},_){const ee=r(Q),le=F??x(I),[ne,ae]=n.useState(k??D),te=void 0!==O?O??D:ne,re=f(te.start)?te.start:null,se=f(te.end)?te.end:null,[oe,ie]=n.useState(j??!1),ce=P??oe,[ue,de]=n.useState(null),[me,he]=n.useState(null),[pe,fe]=n.useState(()=>g(re??M??w()));n.useEffect(()=>{ce?fe(g(re??M??w())):(de(null),he(null))},[ce]);const xe=e=>{e&&(X||Y)||(void 0===P&&ie(e),B?.(e))},ve=e=>{void 0===O&&ae(e),z?.(e)},ge=ue??re,be=null!==ue?me:se,we=(l,n)=>f(l)?p(l,I,q):e("span",{className:"text-(--neba-muted-fg)",children:n??""}),ye=d(pe,1),Ne=2===A,Se=h(I,q),Ce=null!==ue?ee.end:null===re?ee.start:null,De={size:U,color:W,locale:I,weekStartsOn:le,selected:[re,se,ue],rangeStart:ge,rangeEnd:be,onSelect:e=>{const l=v(e);if(null===ue)return de(l),he(l),void ve({start:l,end:null});const[n,a]=m(l,ue)<0?[l,ue]:[ue,l];de(null),he(null),ve({start:n,end:a}),L&&xe(!1)},onPreviewChange:e=>{null!==ue&&he(e??ue)},minDate:R,maxDate:V,shouldDisableDate:E,showOutsideDays:!1,labels:ee};return e(c,{...$,size:U,color:W,readOnly:X,disabled:Y,triggerRef:_,startIcon:Z??e(o,{}),display:l("span",{className:"flex min-w-0 items-center gap-1.5",children:[l("span",{className:"flex min-w-0 flex-col",children:[e("span",{className:"truncate",children:we(re,G)}),e(u,{samples:y(Se,G)})]}),e("span",{"aria-hidden":"true",className:"flex shrink-0 items-center text-(--neba-muted-fg) rtl:rotate-180",children:e(s,{})}),l("span",{className:"flex min-w-0 flex-col",children:[e("span",{className:"truncate",children:we(se,H)}),e(u,{samples:y(Se,H)})]})]}),empty:null===re&&null===se,clearable:K,onClear:()=>ve(D),open:ce,onOpenChange:xe,labels:ee,hiddenValues:T?[{name:T,value:re?b(re):""},{name:T,value:se?b(se):""}]:void 0,children:l("div",{className:"flex flex-col gap-1.5",children:[l("div",{className:N("flex items-stretch",S[U]),children:[J&&J.length>0?e("div",{className:N("flex max-h-[calc(var(--n-cell,2rem)*8)] flex-col overflow-y-auto border-e pe-1.5","[border-color:var(--n-line)]"),children:J.map((l,n)=>e(a,{variant:"text",size:U,color:W,density:"compact",className:"justify-start whitespace-nowrap",onClick:()=>(e=>{const l="function"==typeof e.value?e.value():e.value;de(null),he(null),ve(l),f(l.start)&&fe(g(l.start)),L&&xe(!1)})(l),children:l.label},n))}):null,e(t,{...De,month:pe,onMonthChange:fe,showNextButton:!Ne,autoFocus:!0}),Ne?e(t,{...De,month:ye,onMonthChange:e=>fe(d(e,-1)),showPreviousButton:!1}):null]}),K||null!==Ce?l(i,{size:U,children:[null!==Ce?e("span",{className:N("me-auto text-(--neba-muted-fg)",C[U]),children:Ce}):null,K?e(a,{variant:"text",size:U,color:W,density:"compact",onClick:()=>{de(null),he(null),ve(D),xe(!1)},children:ee.clear}):null]}):null]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{DateRangePicker}from"./DateRangePicker";
|