neba 0.0.1 → 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 +177 -2
- package/dist/components/accordion/Accordion.d.ts +97 -0
- package/dist/components/accordion/Accordion.js +1 -0
- package/dist/components/accordion/index.d.ts +2 -0
- package/dist/components/accordion/index.js +1 -0
- package/dist/components/alert/Alert.d.ts +47 -0
- package/dist/components/alert/Alert.js +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/badge/Badge.d.ts +80 -0
- package/dist/components/badge/Badge.js +1 -0
- package/dist/components/badge/index.d.ts +2 -0
- package/dist/components/badge/index.js +1 -0
- 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/box/Box.d.ts +50 -0
- package/dist/components/box/Box.js +1 -0
- package/dist/components/box/index.d.ts +2 -0
- package/dist/components/box/index.js +1 -0
- package/dist/components/button/Button.d.ts +25 -3
- package/dist/components/button/Button.js +1 -1
- package/dist/components/button/index.d.ts +1 -0
- package/dist/components/button-group/ButtonGroup.d.ts +31 -0
- package/dist/components/button-group/ButtonGroup.js +1 -0
- package/dist/components/button-group/index.d.ts +2 -0
- package/dist/components/button-group/index.js +1 -0
- package/dist/components/card/Card.d.ts +45 -0
- package/dist/components/card/Card.js +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/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.d.ts +39 -0
- package/dist/components/checkbox/Checkbox.js +1 -0
- package/dist/components/checkbox/index.d.ts +2 -0
- package/dist/components/checkbox/index.js +1 -0
- package/dist/components/chip/Chip.d.ts +50 -0
- package/dist/components/chip/Chip.js +1 -0
- package/dist/components/chip/index.d.ts +2 -0
- package/dist/components/chip/index.js +1 -0
- package/dist/components/combobox/Combobox.d.ts +131 -0
- package/dist/components/combobox/Combobox.js +1 -0
- package/dist/components/combobox/index.d.ts +2 -0
- package/dist/components/combobox/index.js +1 -0
- 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.d.ts +111 -0
- package/dist/components/dialog/Dialog.js +1 -0
- package/dist/components/dialog/index.d.ts +2 -0
- package/dist/components/dialog/index.js +1 -0
- package/dist/components/divider/Divider.d.ts +67 -0
- package/dist/components/divider/Divider.js +1 -0
- package/dist/components/divider/index.d.ts +2 -0
- package/dist/components/divider/index.js +1 -0
- package/dist/components/file-picker/FilePicker.d.ts +103 -0
- package/dist/components/file-picker/FilePicker.js +1 -0
- package/dist/components/file-picker/index.d.ts +2 -0
- package/dist/components/file-picker/index.js +1 -0
- 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/list/List.d.ts +81 -0
- package/dist/components/list/List.js +1 -0
- package/dist/components/list/index.d.ts +2 -0
- package/dist/components/list/index.js +1 -0
- package/dist/components/menu/Menu.d.ts +216 -0
- package/dist/components/menu/Menu.js +1 -0
- package/dist/components/menu/index.d.ts +2 -0
- package/dist/components/menu/index.js +1 -0
- package/dist/components/number-field/NumberField.d.ts +113 -0
- package/dist/components/number-field/NumberField.js +1 -0
- package/dist/components/number-field/index.d.ts +2 -0
- package/dist/components/number-field/index.js +1 -0
- package/dist/components/overlay/Overlay.d.ts +85 -0
- package/dist/components/overlay/Overlay.js +1 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.js +1 -0
- package/dist/components/pagination/Pagination.d.ts +65 -0
- package/dist/components/pagination/Pagination.js +1 -0
- package/dist/components/pagination/index.d.ts +2 -0
- package/dist/components/pagination/index.js +1 -0
- 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/progress-box/ProgressBox.d.ts +33 -0
- package/dist/components/progress-box/ProgressBox.js +1 -0
- package/dist/components/progress-box/index.d.ts +2 -0
- package/dist/components/progress-box/index.js +1 -0
- package/dist/components/progress-circular/ProgressCircular.d.ts +19 -0
- package/dist/components/progress-circular/ProgressCircular.js +1 -0
- package/dist/components/progress-circular/index.d.ts +2 -0
- package/dist/components/progress-circular/index.js +1 -0
- package/dist/components/progress-linear/ProgressLinear.d.ts +20 -0
- package/dist/components/progress-linear/ProgressLinear.js +1 -0
- package/dist/components/progress-linear/index.d.ts +2 -0
- package/dist/components/progress-linear/index.js +1 -0
- package/dist/components/radio-group/RadioGroup.d.ts +51 -0
- package/dist/components/radio-group/RadioGroup.js +1 -0
- package/dist/components/radio-group/index.d.ts +2 -0
- package/dist/components/radio-group/index.js +1 -0
- 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.d.ts +76 -0
- package/dist/components/select/Select.js +1 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +1 -0
- 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/slider/Slider.d.ts +38 -0
- package/dist/components/slider/Slider.js +1 -0
- package/dist/components/slider/index.d.ts +2 -0
- package/dist/components/slider/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.d.ts +39 -0
- package/dist/components/switch/Switch.js +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/table/Table.d.ts +80 -0
- package/dist/components/table/Table.js +1 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +1 -0
- package/dist/components/tabs/Tabs.d.ts +92 -0
- package/dist/components/tabs/Tabs.js +1 -0
- package/dist/components/tabs/index.d.ts +2 -0
- package/dist/components/tabs/index.js +1 -0
- package/dist/components/text-field/TextField.d.ts +63 -0
- package/dist/components/text-field/TextField.js +1 -0
- package/dist/components/text-field/index.d.ts +2 -0
- package/dist/components/text-field/index.js +1 -0
- 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/toast/Toast.d.ts +116 -0
- package/dist/components/toast/Toast.js +1 -0
- package/dist/components/toast/index.d.ts +2 -0
- package/dist/components/toast/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/components/tooltip/Tooltip.d.ts +81 -0
- package/dist/components/tooltip/Tooltip.js +1 -0
- package/dist/components/tooltip/index.d.ts +2 -0
- package/dist/components/tooltip/index.js +1 -0
- package/dist/components/typography/Typography.d.ts +62 -0
- package/dist/components/typography/Typography.js +1 -0
- package/dist/components/typography/index.d.ts +2 -0
- package/dist/components/typography/index.js +1 -0
- package/dist/index.d.ts +50 -1
- package/dist/index.js +1 -1
- package/dist/internal/button-group.d.ts +25 -0
- package/dist/internal/button-group.js +1 -0
- 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 +79 -0
- package/dist/internal/icons.js +1 -0
- package/dist/internal/menu.d.ts +20 -0
- package/dist/internal/menu.js +1 -0
- package/dist/internal/picker.d.ts +111 -0
- package/dist/internal/picker.js +1 -0
- package/dist/internal/progress.d.ts +122 -0
- package/dist/internal/progress.js +1 -0
- package/dist/internal/sizer.d.ts +33 -0
- package/dist/internal/sizer.js +1 -0
- package/dist/internal/styles.d.ts +257 -0
- package/dist/internal/styles.js +1 -0
- package/dist/styles.css +2 -0
- package/dist/tailwind.css +892 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.js +8 -0
- package/package.json +90 -21
- package/pnpm-workspace.yaml +0 -2
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaAlign, NebaColor, NebaSide, NebaStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* A menu takes `size`, `color` and `density` and stops there.
|
|
5
|
+
*
|
|
6
|
+
* There is no `variant`, for the reason Dialog has none: the three weights
|
|
7
|
+
* answer "how much does this surface assert itself against the page", and a
|
|
8
|
+
* popup that has taken the pointer has already answered it. There is no
|
|
9
|
+
* `elevation` either — a menu genuinely floats, which is the one case elevation
|
|
10
|
+
* exists for, so it is fixed at 3.
|
|
11
|
+
*/
|
|
12
|
+
interface MenuSurfaceProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'> {
|
|
13
|
+
className?: string;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
}
|
|
16
|
+
export interface MenuProps extends MenuSurfaceProps {
|
|
17
|
+
/**
|
|
18
|
+
* The element that opens the menu, wired up by Base UI. Optional — a
|
|
19
|
+
* controlled menu opened from elsewhere needs no trigger of its own.
|
|
20
|
+
*/
|
|
21
|
+
trigger?: React.ReactElement;
|
|
22
|
+
/** Whether the menu is open. Use with `onOpenChange` for a controlled menu. */
|
|
23
|
+
open?: boolean;
|
|
24
|
+
/** Whether it starts open, for an uncontrolled one. */
|
|
25
|
+
defaultOpen?: boolean;
|
|
26
|
+
onOpenChange?: (open: boolean) => void;
|
|
27
|
+
/** Which edge of the trigger it hangs off. @default 'bottom' */
|
|
28
|
+
side?: NebaSide;
|
|
29
|
+
/** Where it sits along that edge. @default 'start' */
|
|
30
|
+
align?: NebaAlign;
|
|
31
|
+
/** Distance from the trigger, in pixels. @default 6 */
|
|
32
|
+
sideOffset?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the page behind is taken away while the menu is open.
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
modal?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Opens on hover as well as on click. For a menu bar, where crossing the row
|
|
40
|
+
* with an open menu should walk through the others rather than close them.
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
openOnHover?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the arrow keys wrap from the last item back to the first.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
loopFocus?: boolean;
|
|
49
|
+
/** Unavailable. The trigger stops opening anything. */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
/** The rows. */
|
|
52
|
+
children?: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
export interface ContextMenuProps extends MenuSurfaceProps {
|
|
55
|
+
/** The rows, exactly as they are written inside a `Menu`. */
|
|
56
|
+
content: React.ReactNode;
|
|
57
|
+
/**
|
|
58
|
+
* The area that answers a right-click or a long press. Rendered inside a
|
|
59
|
+
* `<div>` of Base UI's, which is what listens for the gesture.
|
|
60
|
+
*/
|
|
61
|
+
children: React.ReactNode;
|
|
62
|
+
open?: boolean;
|
|
63
|
+
defaultOpen?: boolean;
|
|
64
|
+
onOpenChange?: (open: boolean) => void;
|
|
65
|
+
/** @default true */
|
|
66
|
+
loopFocus?: boolean;
|
|
67
|
+
disabled?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface MenuItemProps {
|
|
70
|
+
/** What the row does. Not given, and not a link, the row is a label. */
|
|
71
|
+
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
72
|
+
/** Renders the row as a real `<a>`. A menu of links has to be links. */
|
|
73
|
+
href?: string;
|
|
74
|
+
/** Where the link opens — `_blank` and the rest. Ignored without `href`. */
|
|
75
|
+
target?: string;
|
|
76
|
+
/** Content before the label — an icon, a swatch, a check. */
|
|
77
|
+
startIcon?: React.ReactNode;
|
|
78
|
+
/** Content after the label, before any `shortcut`. */
|
|
79
|
+
endIcon?: React.ReactNode;
|
|
80
|
+
/**
|
|
81
|
+
* The keystroke that does the same thing, set at the end of the row and
|
|
82
|
+
* muted. Text only — the row does not bind it, the application does.
|
|
83
|
+
*/
|
|
84
|
+
shortcut?: React.ReactNode;
|
|
85
|
+
/** A second line under the label, one step down the type scale and muted. */
|
|
86
|
+
description?: React.ReactNode;
|
|
87
|
+
/**
|
|
88
|
+
* Re-points the row's colour family — `danger` for the one that deletes.
|
|
89
|
+
* Defaults to the menu's own.
|
|
90
|
+
*/
|
|
91
|
+
color?: NebaColor;
|
|
92
|
+
/**
|
|
93
|
+
* Whether picking the row closes the menu.
|
|
94
|
+
* @default true
|
|
95
|
+
*/
|
|
96
|
+
closeOnClick?: boolean;
|
|
97
|
+
/** Unavailable. Still listed, and still found by typeahead. */
|
|
98
|
+
disabled?: boolean;
|
|
99
|
+
/** What typeahead matches against, when the label is not a plain string. */
|
|
100
|
+
label?: string;
|
|
101
|
+
/** The label. */
|
|
102
|
+
children?: React.ReactNode;
|
|
103
|
+
className?: string;
|
|
104
|
+
style?: React.CSSProperties;
|
|
105
|
+
}
|
|
106
|
+
export interface MenuSubmenuProps {
|
|
107
|
+
/** The label on the row that opens it. */
|
|
108
|
+
label?: React.ReactNode;
|
|
109
|
+
startIcon?: React.ReactNode;
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
/** Which edge of the parent row it opens against. @default 'right' */
|
|
112
|
+
side?: NebaSide;
|
|
113
|
+
/** Distance from the parent menu, in pixels. @default 4 */
|
|
114
|
+
sideOffset?: number;
|
|
115
|
+
/** The nested rows. */
|
|
116
|
+
children?: React.ReactNode;
|
|
117
|
+
className?: string;
|
|
118
|
+
style?: React.CSSProperties;
|
|
119
|
+
}
|
|
120
|
+
export interface MenuGroupProps {
|
|
121
|
+
/** The heading over the group. Wired to it by Base UI. */
|
|
122
|
+
label?: React.ReactNode;
|
|
123
|
+
children?: React.ReactNode;
|
|
124
|
+
className?: string;
|
|
125
|
+
}
|
|
126
|
+
export interface MenuCheckboxItemProps extends Omit<MenuItemProps, 'href' | 'target' | 'startIcon' | 'onClick'> {
|
|
127
|
+
checked?: boolean;
|
|
128
|
+
defaultChecked?: boolean;
|
|
129
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
130
|
+
/**
|
|
131
|
+
* Whether ticking the row closes the menu. `false` here rather than the `true`
|
|
132
|
+
* a plain item takes: a list of things to tick is a list you tick more than
|
|
133
|
+
* one of.
|
|
134
|
+
* @default false
|
|
135
|
+
*/
|
|
136
|
+
closeOnClick?: boolean;
|
|
137
|
+
}
|
|
138
|
+
export interface MenuRadioGroupProps {
|
|
139
|
+
value?: string | number;
|
|
140
|
+
defaultValue?: string | number;
|
|
141
|
+
onValueChange?: (value: string | number) => void;
|
|
142
|
+
disabled?: boolean;
|
|
143
|
+
children?: React.ReactNode;
|
|
144
|
+
className?: string;
|
|
145
|
+
}
|
|
146
|
+
export interface MenuRadioItemProps extends Omit<MenuItemProps, 'href' | 'target' | 'startIcon' | 'onClick'> {
|
|
147
|
+
/** What this row sets the group to. */
|
|
148
|
+
value: string | number;
|
|
149
|
+
/** @default false */
|
|
150
|
+
closeOnClick?: boolean;
|
|
151
|
+
}
|
|
152
|
+
export type MenuSeparatorProps = React.ComponentPropsWithoutRef<'div'>;
|
|
153
|
+
/**
|
|
154
|
+
* One row of a menu.
|
|
155
|
+
*
|
|
156
|
+
* Renders a real `<a>` when it is given an `href` and Base UI's own item
|
|
157
|
+
* otherwise — the same split ListItem makes, for the same reason. A menu of
|
|
158
|
+
* links that are not links cannot be opened in a new tab, cannot be copied, and
|
|
159
|
+
* tells a screen reader the wrong thing about every one of them.
|
|
160
|
+
*/
|
|
161
|
+
export declare function MenuItem({ onClick, href, target, startIcon, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MenuItemProps): React.JSX.Element;
|
|
162
|
+
/** A row that ticks. The tick lands in the same slot a `startIcon` would. */
|
|
163
|
+
export declare function MenuCheckboxItem({ checked, defaultChecked, onCheckedChange, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MenuCheckboxItemProps): React.JSX.Element;
|
|
164
|
+
/** One choice out of a set. Wraps the rows that make up the set. */
|
|
165
|
+
export declare function MenuRadioGroup({ value, defaultValue, onValueChange, disabled, children, className }: MenuRadioGroupProps): React.JSX.Element;
|
|
166
|
+
/**
|
|
167
|
+
* A row inside a `MenuRadioGroup`.
|
|
168
|
+
*
|
|
169
|
+
* Marked with a dot rather than a tick, which is the same distinction Checkbox
|
|
170
|
+
* and Radio make everywhere else: a tick says "and", a dot says "instead of".
|
|
171
|
+
*/
|
|
172
|
+
export declare function MenuRadioItem({ value, endIcon, shortcut, description, color, closeOnClick, disabled, label, children, className, style }: MenuRadioItemProps): React.JSX.Element;
|
|
173
|
+
/** A named run of rows. The label is a heading, not a row — it cannot be picked. */
|
|
174
|
+
export declare function MenuGroup({ label, children, className }: MenuGroupProps): React.JSX.Element;
|
|
175
|
+
/** The hairline between two runs of rows. */
|
|
176
|
+
export declare function MenuSeparator({ className, ...props }: MenuSeparatorProps): React.JSX.Element;
|
|
177
|
+
/**
|
|
178
|
+
* A menu inside a menu.
|
|
179
|
+
*
|
|
180
|
+
* The row that opens it is the same row every other item is, wearing a chevron
|
|
181
|
+
* — and it opens on hover, on Enter and on the arrow key that points at it,
|
|
182
|
+
* all of which is Base UI's. What is here is the surface and the glyph.
|
|
183
|
+
*
|
|
184
|
+
* Nesting is unlimited: a `MenuSubmenu` renders its children inside a popup
|
|
185
|
+
* that is itself a menu, so a submenu of a submenu needs no different component.
|
|
186
|
+
*/
|
|
187
|
+
export declare function MenuSubmenu({ label, startIcon, disabled, side, sideOffset, children, className, style }: MenuSubmenuProps): React.JSX.Element;
|
|
188
|
+
/**
|
|
189
|
+
* A list of actions that appears when something is pressed.
|
|
190
|
+
*
|
|
191
|
+
* Everything that makes a menu a menu rather than a floating list of divs is
|
|
192
|
+
* Base UI's: roving focus with the arrow keys, Home and End, typeahead, Escape,
|
|
193
|
+
* closing on an outside click, restoring focus to the trigger, submenus opening
|
|
194
|
+
* on hover with the safe-triangle so a diagonal reach does not close them, and
|
|
195
|
+
* the `menu` / `menuitem` roles that make any of it mean something to a screen
|
|
196
|
+
* reader. What is here is the surface, the ladders and the row layout.
|
|
197
|
+
*
|
|
198
|
+
* The rows are composed rather than passed as data — the opposite of Select,
|
|
199
|
+
* and deliberately. A select's options are values from a list a caller already
|
|
200
|
+
* has; a menu's rows are *code*, each one a different handler, a different icon,
|
|
201
|
+
* sometimes a submenu. Data would mean an `items` type with a variant for every
|
|
202
|
+
* shape a row can take, which is a component tree spelled as a discriminated
|
|
203
|
+
* union.
|
|
204
|
+
*/
|
|
205
|
+
export declare function Menu({ size, color, density, trigger, open, defaultOpen, onOpenChange, side, align, sideOffset, modal, openOnHover, loopFocus, disabled, className, style, children }: MenuProps): React.JSX.Element;
|
|
206
|
+
/**
|
|
207
|
+
* The same menu, opened by a right-click or a long press instead of by a button.
|
|
208
|
+
*
|
|
209
|
+
* It takes the rows as `content` and the area as `children`, which is Tooltip's
|
|
210
|
+
* shape rather than Menu's — because here the trigger is not one element you
|
|
211
|
+
* hand over, it is a region of the page, and the region is the thing being
|
|
212
|
+
* wrapped. Base UI positions the popup at the pointer rather than against an
|
|
213
|
+
* anchor, and the long press is what makes it reachable on a touch screen at all.
|
|
214
|
+
*/
|
|
215
|
+
export declare function ContextMenu({ size, color, density, content, children, open, defaultOpen, onOpenChange, loopFocus, disabled, className, style }: ContextMenuProps): React.JSX.Element;
|
|
216
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n,Fragment as l}from"react/jsx-runtime";import*as t from"react";import{Menu as a}from"@base-ui/react/menu";import{ContextMenu as s}from"@base-ui/react/context-menu";import{MenuContext as o}from"../../internal/menu";import{CheckIcon as i,ChevronIcon as r,DotIcon as c}from"../../internal/icons";import{controlTextLeadingClasses as d,gapClasses as u,hasContent as m,iconClasses as p,metaTextClasses as h,radiusClasses as f,surfaceClasses as x,surfaceSlots as b,transitionClasses as g}from"../../internal/styles";const y=[x,"max-h-[min(24rem,var(--available-height))] min-w-40 overflow-y-auto overscroll-contain","border bg-(--n-panel-press) p-1","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),N={default:{xs:"px-1.5 py-0.5",sm:"px-2 py-1",md:"px-2.5 py-1.5",lg:"px-3 py-2",xl:"px-3.5 py-2.5"},compact:{xs:"px-1 py-0.5",sm:"px-1.5 py-0.5",md:"px-2 py-1",lg:"px-2.5 py-1",xl:"px-3 py-1.5"}},C={xs:f.xs,sm:f.xs,md:f.sm,lg:f.sm,xl:f.md};function v(e,n,l,t){return["relative flex w-full cursor-pointer items-center select-none",l?"text-(--n-accent)":"text-(--neba-fg)",N[n][e],C[e],u[e],d[e],g,p,"data-[highlighted]:bg-(--n-soft-hover)","data-[popup-open]:bg-(--n-soft)","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)","[outline:none]",t??""].filter(Boolean).join(" ")}const k="flex h-[1lh] w-[1.2em] shrink-0 items-center justify-center";function O({children:l,description:t,size:a}){return m(t)?n("span",{className:"flex min-w-0 flex-1 flex-col text-start",children:[e("span",{className:"truncate",children:l}),e("span",{className:`truncate text-(--neba-muted-fg) ${h[a]}`,children:t})]}):e("span",{className:"min-w-0 flex-1 truncate text-start",children:l})}export function MenuItem({onClick:s,href:i,target:r,startIcon:c,endIcon:d,shortcut:u,description:p,color:f,closeOnClick:x=!0,disabled:g=!1,label:y,children:N,className:C,style:z}){const I=t.useContext(o),{size:j,density:M}=I,$=n(l,{children:[m(c)?e("span",{className:`${k} text-(--neba-muted-fg)`,children:c}):null,e(O,{description:p,size:j,children:N}),m(d)?e("span",{className:`${k} text-(--neba-muted-fg)`,children:d}):null,m(u)?e("span",{className:`ms-2 shrink-0 text-(--neba-muted-fg) tabular-nums ${h[j]}`,children:u}):null]}),w=f?b(f,0):void 0,P=w||z?{...w,...z}:void 0;return void 0!==i?e(a.LinkItem,{href:i,target:r,label:y,closeOnClick:x,onClick:s,className:v(j,M,Boolean(f),C),style:P,children:$}):e(a.Item,{disabled:g,label:y,closeOnClick:x,onClick:s,className:v(j,M,Boolean(f),C),style:P,children:$})}export function MenuCheckboxItem({checked:l,defaultChecked:s,onCheckedChange:r,endIcon:c,shortcut:d,description:u,color:p,closeOnClick:f=!1,disabled:x=!1,label:g,children:y,className:N,style:C}){const{size:z,density:I}=t.useContext(o),j=p?b(p,0):void 0;return n(a.CheckboxItem,{checked:l,defaultChecked:s,onCheckedChange:e=>r?.(e),disabled:x,label:g,closeOnClick:f,className:v(z,I,Boolean(p),N),style:j||C?{...j,...C}:void 0,children:[e("span",{className:`${k} text-(--n-accent)`,children:e(a.CheckboxItemIndicator,{className:"flex items-center justify-center",children:e(i,{})})}),e(O,{description:u,size:z,children:y}),m(c)?e("span",{className:`${k} text-(--neba-muted-fg)`,children:c}):null,m(d)?e("span",{className:`ms-2 shrink-0 text-(--neba-muted-fg) tabular-nums ${h[z]}`,children:d}):null]})}export function MenuRadioGroup({value:n,defaultValue:l,onValueChange:t,disabled:s=!1,children:o,className:i}){return e(a.RadioGroup,{value:n,defaultValue:l,onValueChange:e=>t?.(e),disabled:s,className:i,children:o})}export function MenuRadioItem({value:l,endIcon:s,shortcut:i,description:r,color:d,closeOnClick:u=!1,disabled:p=!1,label:f,children:x,className:g,style:y}){const{size:N,density:C}=t.useContext(o),z=d?b(d,0):void 0;return n(a.RadioItem,{value:l,disabled:p,label:f,closeOnClick:u,className:v(N,C,Boolean(d),g),style:z||y?{...z,...y}:void 0,children:[e("span",{className:`${k} text-(--n-accent)`,children:e(a.RadioItemIndicator,{className:"flex items-center justify-center",children:e(c,{})})}),e(O,{description:r,size:N,children:x}),m(s)?e("span",{className:`${k} text-(--neba-muted-fg)`,children:s}):null,m(i)?e("span",{className:`ms-2 shrink-0 text-(--neba-muted-fg) tabular-nums ${h[N]}`,children:i}):null]})}export function MenuGroup({label:l,children:s,className:i}){const{size:r,density:c}=t.useContext(o);return n(a.Group,{className:i,children:[m(l)?e(a.GroupLabel,{className:[N[c][r],h[r],"font-semibold tracking-wide text-(--neba-muted-fg) uppercase"].join(" "),children:l}):null,s]})}export function MenuSeparator({className:n,...l}){return e(a.Separator,{className:["-mx-1 my-1 h-px bg-(--n-line)",n??""].filter(Boolean).join(" "),...l})}export function MenuSubmenu({label:l,startIcon:s,disabled:i=!1,side:c="right",sideOffset:u=4,children:p,className:h,style:x}){const g=t.useContext(o),{size:N,density:C,color:O}=g;return n(a.SubmenuRoot,{children:[n(a.SubmenuTrigger,{disabled:i,className:v(N,C,!1),children:[m(s)?e("span",{className:`${k} text-(--neba-muted-fg)`,children:s}):null,e("span",{className:"min-w-0 flex-1 truncate text-start",children:l}),e("span",{className:`${k} text-(--neba-muted-fg) -rotate-90`,children:e(r,{})})]}),e(a.Portal,{children:e(a.Positioner,{className:"neba-portal z-50 [outline:none]",side:c,sideOffset:u,align:"start",children:e(a.Popup,{className:[y,f[N],d[N],h??""].filter(Boolean).join(" "),style:{...b(O,3),...x},children:p})})})]})}export function Menu({size:l="md",color:s="primary",density:i="default",trigger:r,open:c,defaultOpen:u,onOpenChange:m,side:p="bottom",align:h="start",sideOffset:x=6,modal:g=!0,openOnHover:N=!1,loopFocus:C=!0,disabled:v=!1,className:k,style:O,children:z}){const I=t.useMemo(()=>({size:l,color:s,density:i}),[l,s,i]);return e(o.Provider,{value:I,children:n(a.Root,{open:c,defaultOpen:u,onOpenChange:e=>m?.(e),modal:g,loopFocus:C,disabled:v,children:[r?e(a.Trigger,{render:r,openOnHover:N,disabled:v}):null,e(a.Portal,{children:e(a.Positioner,{className:"neba-portal z-50 [outline:none]",side:p,align:h,sideOffset:x,children:e(a.Popup,{className:[y,f[l],d[l],k??""].filter(Boolean).join(" "),style:{...b(s,3),...O},children:z})})})]})})}export function ContextMenu({size:l="md",color:a="primary",density:i="default",content:r,children:c,open:u,defaultOpen:m,onOpenChange:p,loopFocus:h=!0,disabled:x=!1,className:g,style:N}){const C=t.useMemo(()=>({size:l,color:a,density:i}),[l,a,i]);return e(o.Provider,{value:C,children:n(s.Root,{open:u,defaultOpen:m,onOpenChange:e=>p?.(e),loopFocus:h,disabled:x,children:[e(s.Trigger,{children:c}),e(s.Portal,{children:e(s.Positioner,{className:"neba-portal z-50 [outline:none]",children:e(s.Popup,{className:[y,f[l],d[l],g??""].filter(Boolean).join(" "),style:{...b(a,3),...N},children:r})})})]})})}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { ContextMenu, Menu, MenuCheckboxItem, MenuGroup, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubmenu } from './Menu';
|
|
2
|
+
export type { ContextMenuProps, MenuCheckboxItemProps, MenuGroupProps, MenuItemProps, MenuProps, MenuRadioGroupProps, MenuRadioItemProps, MenuSeparatorProps, MenuSubmenuProps } from './Menu';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{ContextMenu,Menu,MenuCheckboxItem,MenuGroup,MenuItem,MenuRadioGroup,MenuRadioItem,MenuSeparator,MenuSubmenu}from"./Menu";
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Where the two steppers sit.
|
|
5
|
+
*
|
|
6
|
+
* - `end` — both at the trailing edge, the way a spinner has always looked.
|
|
7
|
+
* - `split` — minus at the start, plus at the end, with the number between
|
|
8
|
+
* them. For a quantity that is nudged rather than typed.
|
|
9
|
+
* - `none` — no buttons. The field is still a number field: the arrow keys,
|
|
10
|
+
* the clamping and the formatting all stay.
|
|
11
|
+
*
|
|
12
|
+
* There is deliberately no stacked pair of half-height chevrons. At `xs` each
|
|
13
|
+
* arrow would be under three pixels tall, and a target that small is a target
|
|
14
|
+
* nobody hits.
|
|
15
|
+
*/
|
|
16
|
+
export type NumberFieldSteppers = 'end' | 'split' | 'none';
|
|
17
|
+
export interface NumberFieldProps extends NebaStyleProps {
|
|
18
|
+
/**
|
|
19
|
+
* Drop shadow depth. `0` (the default) is flat — a field is a well, not a
|
|
20
|
+
* surface that floats.
|
|
21
|
+
* @default 0
|
|
22
|
+
*/
|
|
23
|
+
elevation?: NebaElevation;
|
|
24
|
+
/** The number. Use with `onValueChange` for a controlled field. */
|
|
25
|
+
value?: number | null;
|
|
26
|
+
/** The initial number, for an uncontrolled field. */
|
|
27
|
+
defaultValue?: number;
|
|
28
|
+
/** Called on every change — typing, stepping, the wheel. */
|
|
29
|
+
onValueChange?: (value: number | null) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Called when the value settles: on blur after typing, on pointer release
|
|
32
|
+
* after a press, and together with `onValueChange` for the keyboard.
|
|
33
|
+
*/
|
|
34
|
+
onValueCommitted?: (value: number | null) => void;
|
|
35
|
+
/** The bottom of the range. Stepping stops here. */
|
|
36
|
+
min?: number;
|
|
37
|
+
/** The top of the range. */
|
|
38
|
+
max?: number;
|
|
39
|
+
/** How far one step goes. `'any'` turns step validation off. @default 1 */
|
|
40
|
+
step?: number | 'any';
|
|
41
|
+
/** The step taken while Shift is held. @default 10 */
|
|
42
|
+
largeStep?: number;
|
|
43
|
+
/** The step taken while Alt is held. @default 0.1 */
|
|
44
|
+
smallStep?: number;
|
|
45
|
+
/** Whether stepping snaps to multiples of the step. @default false */
|
|
46
|
+
snapOnStep?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the wheel changes the value while the field is focused and hovered.
|
|
49
|
+
* Off by default: a page that scrolls under the pointer and a field that
|
|
50
|
+
* changes under it are the same gesture, and only one of them was meant.
|
|
51
|
+
* @default false
|
|
52
|
+
*/
|
|
53
|
+
allowWheelScrub?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* How the number is written — currency, percent, decimal places. Passed
|
|
56
|
+
* straight to `Intl.NumberFormat`, so the field shows `$1,240.00` and still
|
|
57
|
+
* reports `1240`.
|
|
58
|
+
*/
|
|
59
|
+
format?: Intl.NumberFormatOptions;
|
|
60
|
+
/** Which locale the number is written and parsed in. Defaults to the runtime's. */
|
|
61
|
+
locale?: Intl.LocalesArgument;
|
|
62
|
+
/** Where the steppers sit, or `none` for a field without them. @default 'end' */
|
|
63
|
+
steppers?: NumberFieldSteppers;
|
|
64
|
+
/** Accessible name of the increment button. */
|
|
65
|
+
incrementLabel?: string;
|
|
66
|
+
/** Accessible name of the decrement button. */
|
|
67
|
+
decrementLabel?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Label above the control, wired to it by Base UI's Field. There is no
|
|
70
|
+
* floating variant on purpose: floating labels need a `transform`.
|
|
71
|
+
*/
|
|
72
|
+
label?: React.ReactNode;
|
|
73
|
+
/** Helper text below the control. */
|
|
74
|
+
description?: React.ReactNode;
|
|
75
|
+
/** Error message below the control. Its presence also turns the field invalid. */
|
|
76
|
+
error?: React.ReactNode;
|
|
77
|
+
/** Forces the invalid state without a message. Defaults to `!!error`. */
|
|
78
|
+
invalid?: boolean;
|
|
79
|
+
/** Content placed before the number — a currency mark, a unit, an icon. */
|
|
80
|
+
startIcon?: React.ReactNode;
|
|
81
|
+
/** Content placed after the number, before the steppers. */
|
|
82
|
+
endIcon?: React.ReactNode;
|
|
83
|
+
/** Stretches to the width of the container. */
|
|
84
|
+
fullWidth?: boolean;
|
|
85
|
+
/** Unavailable. */
|
|
86
|
+
disabled?: boolean;
|
|
87
|
+
/** The number is shown but cannot be changed. */
|
|
88
|
+
readOnly?: boolean;
|
|
89
|
+
/** Whether a value must be entered before the form is submitted. */
|
|
90
|
+
required?: boolean;
|
|
91
|
+
/** Identifies the field when a form is submitted. */
|
|
92
|
+
name?: string;
|
|
93
|
+
/** Placeholder shown while the field is empty. */
|
|
94
|
+
placeholder?: string;
|
|
95
|
+
id?: string;
|
|
96
|
+
className?: string;
|
|
97
|
+
style?: React.CSSProperties;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A field that only holds a number.
|
|
101
|
+
*
|
|
102
|
+
* The shell is a TextField's, to the pixel, because a form where the quantity
|
|
103
|
+
* box is a different height or radius from the boxes around it is a form that
|
|
104
|
+
* looks assembled rather than designed. What is added on top is a real numeric
|
|
105
|
+
* control: arrow keys and the steppers move by `step` (Shift for `largeStep`,
|
|
106
|
+
* Alt for `smallStep`), the value clamps to `min`/`max`, and `format` writes it
|
|
107
|
+
* as currency or a percentage while `value` stays a plain number.
|
|
108
|
+
*
|
|
109
|
+
* Base UI owns the hard parts — parsing what was typed against the locale,
|
|
110
|
+
* clamping, the press-and-hold repeat on the steppers, and the hidden input
|
|
111
|
+
* that submits with a form.
|
|
112
|
+
*/
|
|
113
|
+
export declare function NumberField({ variant, size, color, density, elevation, value, defaultValue, onValueChange, onValueCommitted, min, max, step, largeStep, smallStep, snapOnStep, allowWheelScrub, format, locale, steppers, incrementLabel, decrementLabel, label, description, error, invalid, startIcon, endIcon, fullWidth, disabled, readOnly, required, name, placeholder, id, className, style }: NumberFieldProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import{NumberField as t}from"@base-ui/react/number-field";import{Field as a}from"@base-ui/react/field";import{MinusIcon as l,PlusIcon as i}from"../../internal/icons";import{controlHeightClasses as r,controlTextLeadingClasses as s,disabledClasses as o,fieldReadOnlyClasses as c,fieldRestClasses as d,focusWithinRingClasses as m,gapClasses as u,hasContent as p,iconClasses as f,metaTextClasses as b,paddingXClasses as h,radiusClasses as x,stackGapClasses as g,surfaceSlots as v,transitionClasses as N}from"../../internal/styles";const j=["group relative flex w-full cursor-text items-center","[-webkit-tap-highlight-color:transparent]",N,"focus-within:[transition-duration:0ms]",m,f].join(" "),w=["inline-flex size-[1.7em] shrink-0 cursor-pointer items-center justify-center","rounded-(--neba-radius-xs) text-(--neba-muted-fg) select-none","[&_svg]:size-[0.9em] [&_svg]:shrink-0","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","[transition:background-color_var(--neba-duration)_var(--neba-ease),color_var(--neba-duration)_var(--neba-ease)]","active:[transition-duration:0ms]","hover:bg-(--n-soft) hover:text-(--n-accent)","active:bg-(--n-soft-press)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1","disabled:cursor-not-allowed disabled:bg-transparent disabled:text-(--neba-disabled-fg)"].join(" ");export function NumberField({variant:m="outline",size:f="md",color:N="primary",density:k="default",elevation:y=0,value:S,defaultValue:_,onValueChange:V,onValueCommitted:I,min:C,max:O,step:z,largeStep:D,smallStep:L,snapOnStep:W,allowWheelScrub:$=!1,format:q,locale:B,steppers:F="end",incrementLabel:R="Increase",decrementLabel:E="Decrease",label:G,description:A,error:H,invalid:J,startIcon:K,endIcon:M,fullWidth:P=!1,disabled:Q=!1,readOnly:T=!1,required:U=!1,name:X,placeholder:Y,id:Z,className:ee,style:ne}){const te=p(H),ae=J??te,le=ae?"danger":N,ie=h[k][f],re={end:`${ie} pe-1`,split:"px-1",none:ie},se=e(t.Decrement,{"aria-label":E,className:w,children:e(l,{})}),oe=e(t.Increment,{"aria-label":R,className:w,children:e(i,{})}),ce="none"!==F&&!T;return n(a.Root,{disabled:Q,invalid:ae,className:["flex-col align-top",g[f],P?"flex w-full":"inline-flex",ee??""].filter(Boolean).join(" "),style:{...v(le,y),...ne},children:[G?e(a.Label,{className:[b[f],"font-medium",Q?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:G}):null,e(t.Root,{id:Z,name:X,className:"contents",value:S,defaultValue:_,onValueChange:e=>V?.(e),onValueCommitted:e=>I?.(e),min:C,max:O,step:z,largeStep:D,smallStep:L,snapOnStep:W,allowWheelScrub:$,format:q,locale:B,disabled:Q,readOnly:T,required:U,children:n(t.Group,{className:[j,r[f],s[f],x[f],u[f],ce?re[F]:ie,Q?o[m]:T?c[m]:d[m]].join(" "),children:[ce&&"split"===F?se:null,K?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:K}):null,e(t.Input,{placeholder:Y,className:["min-w-0 flex-1 self-stretch bg-transparent [font:inherit] text-inherit","[outline:none]","tabular-nums","split"===F&&ce?"text-center":"","placeholder:text-(--neba-muted-fg)","caret-(--n-accent) selection:bg-(--n-soft-press)","disabled:cursor-not-allowed"].filter(Boolean).join(" ")}),M?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:M}):null,ce&&"end"===F?n("span",{className:"flex shrink-0 items-center gap-0.5",children:[se,oe]}):null,ce&&"split"===F?oe:null]})}),A?e(a.Description,{className:`${b[f]} text-(--neba-muted-fg)`,children:A}):null,te?e(a.Error,{match:!0,className:`${b[f]} text-(--n-accent)`,children:H}):null]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{NumberField}from"./NumberField";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaAlign, NebaColor, NebaSize } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* How much of the page the overlay takes away.
|
|
5
|
+
*
|
|
6
|
+
* The four steps are one axis — how legible is what is behind — and they are
|
|
7
|
+
* tuned with the blur radius as much as with the alpha, because past about
|
|
8
|
+
* 16px a backdrop smears into flat colour and the scrim reads opaque no matter
|
|
9
|
+
* how low its alpha goes.
|
|
10
|
+
*
|
|
11
|
+
* - `scrim` — the neutral dim a Dialog puts behind itself. The page is still
|
|
12
|
+
* there and still readable; it has only stopped being reachable.
|
|
13
|
+
* - `blur` — frosted. A lighter dim over a real blur, so the page is present as
|
|
14
|
+
* shape and colour but not as words. For "this is being replaced".
|
|
15
|
+
* - `solid` — the page surface, opaque. For a screen that is genuinely gone.
|
|
16
|
+
* - `clear` — nothing drawn at all. Still blocks the pointer, which is the
|
|
17
|
+
* whole reason to reach for it: an invisible sheet that catches a click.
|
|
18
|
+
*/
|
|
19
|
+
export type OverlayTone = 'scrim' | 'blur' | 'solid' | 'clear';
|
|
20
|
+
/**
|
|
21
|
+
* An overlay takes `size`, `color` and `align` and stops there.
|
|
22
|
+
*
|
|
23
|
+
* There is no `variant` — the three weights answer "how much does this surface
|
|
24
|
+
* assert itself against the page", and an overlay has taken the page. There is
|
|
25
|
+
* no `elevation` either: the overlay *is* the plane everything else floats
|
|
26
|
+
* above, and a scrim with a drop shadow is a scrim with an edge.
|
|
27
|
+
*/
|
|
28
|
+
export interface OverlayProps {
|
|
29
|
+
/** The overlay is shown. Use with `onOpenChange` for a controlled overlay. */
|
|
30
|
+
open?: boolean;
|
|
31
|
+
/** Whether the overlay starts shown, for an uncontrolled one. */
|
|
32
|
+
defaultOpen?: boolean;
|
|
33
|
+
onOpenChange?: (open: boolean) => void;
|
|
34
|
+
/** How much of the page is taken away. @default 'scrim' */
|
|
35
|
+
tone?: OverlayTone;
|
|
36
|
+
/**
|
|
37
|
+
* Whether clicking the overlay or pressing Escape closes it.
|
|
38
|
+
*
|
|
39
|
+
* Off by default, which is the other way round from [Dialog](./dialog). A
|
|
40
|
+
* dialog asks a question and Escape is the universal "no"; an overlay is not
|
|
41
|
+
* asking anything — it is saying *wait* — and a save that can be dismissed
|
|
42
|
+
* by a stray click is a save the user will think finished. Turn it on for the
|
|
43
|
+
* overlay whose job is to catch a click outside something.
|
|
44
|
+
* @default false
|
|
45
|
+
*/
|
|
46
|
+
dismissible?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the page behind is taken away for the keyboard too. `'trap-focus'`
|
|
49
|
+
* leaves the page scrollable and clickable while still holding focus inside,
|
|
50
|
+
* which is what a `clear` overlay usually wants.
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
53
|
+
modal?: boolean | 'trap-focus';
|
|
54
|
+
/** Where the content sits down the viewport. @default 'center' */
|
|
55
|
+
align?: NebaAlign;
|
|
56
|
+
/** Scale of the padding around the content. @default 'md' */
|
|
57
|
+
size?: NebaSize;
|
|
58
|
+
/** Semantic colour role. Reaches the focus ring and whatever the content reads. */
|
|
59
|
+
color?: NebaColor;
|
|
60
|
+
/**
|
|
61
|
+
* The accessible name of the overlay. An overlay that holds nothing readable
|
|
62
|
+
* — a bare spinner, a `clear` sheet — still has to say what it is, so this
|
|
63
|
+
* has a default rather than being optional.
|
|
64
|
+
* @default 'Overlay'
|
|
65
|
+
*/
|
|
66
|
+
label?: string;
|
|
67
|
+
/** What sits on top of the scrim — a spinner, a line of text, a small card. */
|
|
68
|
+
children?: React.ReactNode;
|
|
69
|
+
className?: string;
|
|
70
|
+
style?: React.CSSProperties;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A sheet over the whole page that stops it being used.
|
|
74
|
+
*
|
|
75
|
+
* The difference from [Dialog](../surfaces/dialog) is what is *not* here: no
|
|
76
|
+
* surface, no border, no title, no actions. An overlay is the scrim on its own,
|
|
77
|
+
* with whatever the caller puts on top of it — most often a spinner and a line
|
|
78
|
+
* saying what is being waited for.
|
|
79
|
+
*
|
|
80
|
+
* It is not dismissible by default, and that is the one prop worth reading
|
|
81
|
+
* twice. Everything else Base UI owns: the portal, the scroll lock, the focus
|
|
82
|
+
* held inside, the page behind going inert, and focus returning to wherever it
|
|
83
|
+
* came from when the overlay closes.
|
|
84
|
+
*/
|
|
85
|
+
export declare function Overlay({ open, defaultOpen, onOpenChange, tone, dismissible, modal, align, size, color, label, className, style, children }: OverlayProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Dialog as r}from"@base-ui/react/dialog";import{surfaceSlots as n}from"../../internal/styles";const t={scrim:"bg-(--neba-scrim) [backdrop-filter:blur(2px)]",blur:"[background-color:color-mix(in_oklab,var(--neba-scrim)_55%,transparent)] [backdrop-filter:blur(14px)_saturate(1.4)]",solid:"bg-(--neba-surface)",clear:""},l={start:"items-start",center:"items-center",end:"items-end"},i={xs:"p-3",sm:"p-4",md:"p-6",lg:"p-8",xl:"p-10"},s=["[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" ");export function Overlay({open:o,defaultOpen:c,onOpenChange:p,tone:m="scrim",dismissible:d=!1,modal:b=!0,align:f="center",size:u="md",color:x="primary",label:y="Overlay",className:g,style:h,children:j}){return e(r.Root,{open:o,defaultOpen:c,modal:b,disablePointerDismissal:!d,onOpenChange:(e,a)=>{d||e||"escape-key"!==a.reason?p?.(e):a.cancel()},children:a(r.Portal,{children:[e(r.Backdrop,{className:`neba-portal fixed inset-0 z-50 ${s} ${t[m]}`}),e(r.Viewport,{className:["neba-portal fixed inset-0 z-50 flex justify-center",l[f],i[u]].join(" "),children:e(r.Popup,{"aria-label":y,className:["flex max-h-full max-w-full flex-col items-center justify-center","[outline:none]",s,g??""].filter(Boolean).join(" "),style:{...n(x,0),...h},children:j})})]})})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Overlay}from"./Overlay";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
export interface PaginationProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'nav'>, 'color' | 'onChange'> {
|
|
4
|
+
/** How many pages there are. Fewer than two and the whole control renders nothing. */
|
|
5
|
+
count: number;
|
|
6
|
+
/** The current page, 1-based. Use with `onPageChange` for a controlled set. */
|
|
7
|
+
page?: number;
|
|
8
|
+
/** Which page starts current, for an uncontrolled one. @default 1 */
|
|
9
|
+
defaultPage?: number;
|
|
10
|
+
onPageChange?: (page: number) => void;
|
|
11
|
+
/**
|
|
12
|
+
* How many pages are always shown on either side of the current one.
|
|
13
|
+
* @default 1
|
|
14
|
+
*/
|
|
15
|
+
siblingCount?: number;
|
|
16
|
+
/**
|
|
17
|
+
* How many pages are always shown at each end, whatever the current page is.
|
|
18
|
+
* `0` drops the first and last page from the row, leaving only the window.
|
|
19
|
+
* @default 1
|
|
20
|
+
*/
|
|
21
|
+
boundaryCount?: number;
|
|
22
|
+
/** Shows the jump-to-first and jump-to-last steppers. @default false */
|
|
23
|
+
showEdges?: boolean;
|
|
24
|
+
/** Shows the previous and next steppers. @default true */
|
|
25
|
+
showArrows?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Drop shadow depth of the page buttons. `0` (the default) is flat.
|
|
28
|
+
* @default 0
|
|
29
|
+
*/
|
|
30
|
+
elevation?: NebaElevation;
|
|
31
|
+
/** Unavailable. Every button in the row stops answering. */
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/** Accessible name of the `<nav>`. @default 'Pagination' */
|
|
34
|
+
label?: string;
|
|
35
|
+
/** Accessible name of a page button. @default `Page ${page}` */
|
|
36
|
+
pageLabel?: (page: number) => string;
|
|
37
|
+
/** @default 'Previous page' */
|
|
38
|
+
previousLabel?: string;
|
|
39
|
+
/** @default 'Next page' */
|
|
40
|
+
nextLabel?: string;
|
|
41
|
+
/** @default 'First page' */
|
|
42
|
+
firstLabel?: string;
|
|
43
|
+
/** @default 'Last page' */
|
|
44
|
+
lastLabel?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A row of page numbers.
|
|
48
|
+
*
|
|
49
|
+
* Every button in it is a real `Button`, which is the point: a pagination is not
|
|
50
|
+
* a new kind of control, it is buttons in a row that happen to know about each
|
|
51
|
+
* other. Reusing the component means the row inherits the acrylic surface, the
|
|
52
|
+
* press-instant/release-slow signature, the focus ring and every future change
|
|
53
|
+
* to any of them for free — and it means a `lg` pagination lines up with a `lg`
|
|
54
|
+
* button beside it, because it *is* one.
|
|
55
|
+
*
|
|
56
|
+
* `variant` sets how the pages at rest look; the current page is always `solid`,
|
|
57
|
+
* which is the one thing the row has to say without being read. That is why the
|
|
58
|
+
* default here is `text` rather than the `solid` a lone Button takes — nine
|
|
59
|
+
* filled buttons in a row say that all nine are the primary action.
|
|
60
|
+
*
|
|
61
|
+
* The markup is a `<nav>` around a `<ul>` because that is what a screen reader
|
|
62
|
+
* needs to hear: a named landmark it can skip, holding a list whose length says
|
|
63
|
+
* how far the pages go, with `aria-current="page"` marking where it is.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Pagination: React.ForwardRefExoticComponent<PaginationProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as a from"react";import{Button as n}from"../button/Button";import{ChevronIcon as r}from"../../internal/icons";import{controlTextClasses as i,gapClasses as l,srOnlyClasses as o}from"../../internal/styles";function s(e,t){return Array.from({length:Math.max(0,t-e+1)},(t,a)=>e+a)}function m(){return e("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:e("path",{d:"m7.5 4.5 3.5 3.5-3.5 3.5M3.5 4.5 7 8l-3.5 3.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}const c={xs:"h-5.5 min-w-5.5",sm:"h-6.5 min-w-6.5",md:"h-8 min-w-8",lg:"h-10 min-w-10",xl:"h-12 min-w-12"};export const Pagination=a.forwardRef(function({variant:d="text",size:u="md",color:h="primary",density:f="compact",elevation:p=0,count:x,page:g,defaultPage:b=1,onPageChange:v,siblingCount:M=1,boundaryCount:w=1,showEdges:N=!1,showArrows:y=!0,disabled:L=!1,label:j="Pagination",pageLabel:k=e=>`Page ${e}`,previousLabel:C="Previous page",nextLabel:P="Next page",firstLabel:$="First page",lastLabel:z="Last page",className:B,children:A,...E},F){const[I,R]=a.useState(b),S=Math.min(Math.max(g??I,1),Math.max(x,1)),W=e=>{const t=Math.min(Math.max(e,1),x);t!==S&&(void 0===g&&R(t),v?.(t))};if(x<2)return null;const q=function(e,t,a,n){const r=s(1,Math.min(n,e)),i=s(Math.max(e-n+1,n+1),e),l=Math.max(Math.min(t-a,e-n-2*a-1),n+2),o=Math.min(Math.max(t+a,n+2*a+2),i.length>0?i[0]-2:e-1);return[...r,...l>n+2?["start-ellipsis"]:n+1<e-n?[n+1]:[],...s(l,o),...o<e-n-1?["end-ellipsis"]:e-n>n?[e-n]:[],...i]}(x,S,M,w),D=S<=1,G=S>=x,H=(t,a,r,i,l,o)=>e("li",{className:"flex",children:e(n,{variant:d,size:u,color:h,density:f,elevation:p,disabled:L||i,"aria-label":a,startIcon:e("span",{className:`flex items-center ${l}`,children:o}),onClick:()=>W(r)})},t);return t("nav",{ref:F,"aria-label":j,className:["flex items-center",B??""].filter(Boolean).join(" "),...E,children:[t("ul",{role:"list",className:`m-0 flex list-none items-center p-0 ${l[u]}`,children:[N?H("first",$,1,D,"rotate-180 rtl:rotate-0",e(m,{})):null,y?H("previous",C,S-1,D,"rotate-90 rtl:-rotate-90",e(r,{})):null,q.map((t,a)=>e("li","number"==typeof t?{className:"flex",children:e(n,{variant:t===S?"solid":d,size:u,color:h,density:f,elevation:p,disabled:L,"aria-label":k(t),"aria-current":t===S?"page":void 0,className:"tabular-nums",onClick:()=>W(t),children:t})}:{"aria-hidden":"true",className:["flex select-none items-center justify-center","text-(--neba-muted-fg)",i[u],c[u]].join(" "),children:"…"},`slot-${a}`)),y?H("next",P,S+1,G,"-rotate-90 rtl:rotate-90",e(r,{})):null,N?H("last",z,x,G,"rtl:rotate-180",e(m,{})):null]}),e("span",{className:o,"aria-live":"polite",children:`${k(S)} of ${x}`}),A]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Pagination}from"./Pagination";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaElevation, NebaPosition, NebaStyleProps } from '../../types';
|
|
3
|
+
export interface PillProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'onClick' | 'title'> {
|
|
4
|
+
/**
|
|
5
|
+
* Drop shadow depth. `2` here, against the `0` everything else defaults to.
|
|
6
|
+
*
|
|
7
|
+
* That is not an inconsistency: a Pill is defined by not being part of the
|
|
8
|
+
* page. Every other surface in the library rests on the page and earns its
|
|
9
|
+
* separation from the acrylic edge, so a shadow is opt-in. This one hovers
|
|
10
|
+
* over whatever is underneath it, and a lozenge floating flat on the content
|
|
11
|
+
* it is floating over reads as a mistake.
|
|
12
|
+
* @default 2
|
|
13
|
+
*/
|
|
14
|
+
elevation?: NebaElevation;
|
|
15
|
+
/**
|
|
16
|
+
* The leading slot — a glyph, an avatar, a status dot, a photo.
|
|
17
|
+
*
|
|
18
|
+
* It is given a square box of its own and clipped to a circle, so an `<img>`
|
|
19
|
+
* lands in it as readily as an icon does: the image fills the box and is
|
|
20
|
+
* cropped rather than letterboxed, which is what a 20px avatar wants.
|
|
21
|
+
*/
|
|
22
|
+
startIcon?: React.ReactNode;
|
|
23
|
+
/** The trailing slot. Outside the pressable area, so it can be a control. */
|
|
24
|
+
endIcon?: React.ReactNode;
|
|
25
|
+
/**
|
|
26
|
+
* The headline in the middle — what the pill is currently about.
|
|
27
|
+
*
|
|
28
|
+
* A prop rather than something to compose, for the reason Card's title is one:
|
|
29
|
+
* the arrangement is fixed and what a caller wants to decide is what goes in
|
|
30
|
+
* each slot. Almost every pill is a line of text and an optional second line
|
|
31
|
+
* under it, and spelling that as children means every caller inventing their
|
|
32
|
+
* own centring and type scale.
|
|
33
|
+
*/
|
|
34
|
+
title?: React.ReactNode;
|
|
35
|
+
/** The second line, under the title. One step down and lighter. */
|
|
36
|
+
description?: React.ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* The second half, revealed when `expanded`.
|
|
39
|
+
*
|
|
40
|
+
* The pill grows downward into it rather than swapping to a different shape:
|
|
41
|
+
* one object saying more, which is the whole idea being borrowed here.
|
|
42
|
+
*/
|
|
43
|
+
details?: React.ReactNode;
|
|
44
|
+
/** Whether `details` is showing. @default false */
|
|
45
|
+
expanded?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* How it sits in the page's scroll. `fixed` pins it against the viewport and
|
|
48
|
+
* centres it horizontally, which is the arrangement this shape exists for.
|
|
49
|
+
* @default 'static'
|
|
50
|
+
*/
|
|
51
|
+
position?: NebaPosition;
|
|
52
|
+
/** Which edge it is held against when `position` is not `static`. @default 'top' */
|
|
53
|
+
side?: 'top' | 'bottom';
|
|
54
|
+
/** Passing it makes the row a real button. */
|
|
55
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
56
|
+
/**
|
|
57
|
+
* Anything the middle needs that `title` and `description` cannot say — a
|
|
58
|
+
* marquee, a pair of small readouts, a live counter. Rendered under them, in
|
|
59
|
+
* the same centred column.
|
|
60
|
+
*/
|
|
61
|
+
children?: React.ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A floating lozenge holding a small amount of live information.
|
|
65
|
+
*
|
|
66
|
+
* The shape is a stadium, which the house radius rule otherwise forbids: every
|
|
67
|
+
* control is held just short of the 50% that would make it a pill, because the
|
|
68
|
+
* flat run along its top and bottom edge is what still reads as a sheet with the
|
|
69
|
+
* corners cut off it. A Pill is the exception the rule is drawn against, and the
|
|
70
|
+
* exception works for the same reason the rule does — this is not a sheet lying
|
|
71
|
+
* on the page. It is an object hovering over it, and an object hovering over the
|
|
72
|
+
* page should not look like it was cut from the same material.
|
|
73
|
+
*
|
|
74
|
+
* `details` is revealed by animating a measured height, exactly as an Accordion
|
|
75
|
+
* panel is: nothing is transformed and no text is resampled, the pill is simply
|
|
76
|
+
* a window that opens. The measurement is a `ResizeObserver` rather than a
|
|
77
|
+
* hardcoded height, so a details area whose content changes — which is what live
|
|
78
|
+
* information does — grows with it.
|
|
79
|
+
*/
|
|
80
|
+
export declare const Pill: React.ForwardRefExoticComponent<PillProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n,Fragment as t}from"react/jsx-runtime";import*as o from"react";import{controlSlots as l,controlTextClasses as r,focusRingClasses as i,gapClasses as s,hasContent as a,iconClasses as c,iconSizeClasses as d,metaTextClasses as m,paddingXClasses as x,pressTransitionClasses as f,sheetBodyClasses as p,surfaceClasses as u,transitionClasses as h}from"../../internal/styles";const v={solid:[u,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[u,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:`${u} text-(--n-accent) bg-(--n-soft)`},b={solid:"hover:bg-(--n-fill-hover) active:bg-(--n-fill-active)",outline:"hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)] active:bg-(--n-panel-press)",text:"hover:bg-(--n-soft-hover) active:bg-(--n-soft-press)"},g={xs:"min-h-5.5",sm:"min-h-6.5",md:"min-h-8",lg:"min-h-10",xl:"min-h-12"},w={xs:"rounded-[0.6875rem]",sm:"rounded-[0.8125rem]",md:"rounded-[1rem]",lg:"rounded-[1.25rem]",xl:"rounded-[1.5rem]"},j={default:{xs:"px-3",sm:"px-4",md:"px-5",lg:"px-6",xl:"px-8"},compact:{xs:"px-1.5",sm:"px-2",md:"px-2.5",lg:"px-3",xl:"px-4"}},y={static:{top:"",bottom:""},sticky:{top:"sticky top-3 z-20",bottom:"sticky bottom-3 z-20"},fixed:{top:"fixed inset-x-0 top-3 z-30 mx-auto w-fit",bottom:"fixed inset-x-0 bottom-3 z-30 mx-auto w-fit"}};export const Pill=o.forwardRef(function({variant:u="solid",size:N="md",color:k="secondary",density:z="default",elevation:$=2,startIcon:_,endIcon:C,title:R,description:B,details:H,expanded:I=!1,position:E="static",side:F="top",className:O,style:P,children:S,onClick:q,...A},D){const G=o.useRef(null),[J,K]=o.useState(0);o.useEffect(()=>{const e=G.current;if(!e)return;const n=new ResizeObserver(()=>{K(e.scrollHeight)});return n.observe(e),K(e.scrollHeight),()=>n.disconnect()},[H]);const L=Boolean(q),M=x[z][N],Q=n(t,{children:[a(_)?e("span",{className:`flex shrink-0 items-center justify-center overflow-hidden rounded-full [&_img]:size-full [&_img]:object-cover ${d[N]}`,children:_}):null,a(R)||a(B)||a(S)?n("span",{className:["flex min-w-0 flex-1 flex-col items-center justify-center text-center",j[z][N]].join(" "),children:[a(R)?e("span",{className:"max-w-full truncate",children:R}):null,a(B)?e("span",{className:`max-w-full truncate font-normal ${m[N]} [color:color-mix(in_oklab,currentColor_72%,transparent)]`,children:B}):null,S]}):null]});return n("div",{ref:D,className:["inline-flex max-w-full flex-col overflow-hidden align-middle",w[N],"font-medium whitespace-nowrap select-none",r[N],v[u],h,f,c,L?`neba-glow ${b[u]}`:"",y[E][F],O??""].filter(Boolean).join(" "),style:{...l(k,$,u),...P},...A,children:[n("div",{className:["flex shrink-0 items-center py-1",g[N],s[N],L?"ps-0":M,a(C)?"pe-1":L?"pe-0":""].join(" "),children:[L?e("button",{type:"button",className:["flex min-w-0 flex-1 cursor-pointer items-center justify-center self-stretch","rounded-[inherit]",s[N],M,i].join(" "),onClick:q,children:Q}):Q,a(C)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:C}):null]}),a(H)?e("div",{className:["overflow-hidden","[transition:height_var(--neba-duration)_var(--neba-ease)]","motion-reduce:[transition-duration:0ms]"].join(" "),style:{height:I?J:0},inert:!I,children:e("div",{ref:G,className:`whitespace-normal ${M} pb-2 ${p[N]}`,children:H})}):null]})});
|