panelui-web 0.10.1 → 0.11.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/dist/components/alert/index.d.ts +15 -8
- package/dist/components/alert/index.js +65 -18
- package/dist/components/alert-dialog/index.d.ts +9 -3
- package/dist/components/alert-dialog/index.js +23 -7
- package/dist/components/avatar/index.d.ts +9 -3
- package/dist/components/avatar/index.js +34 -10
- package/dist/components/badge/index.d.ts +57 -0
- package/dist/components/badge/index.js +61 -0
- package/dist/components/bar-picker/index.d.ts +8 -1
- package/dist/components/bar-picker/index.js +35 -26
- package/dist/components/button/index.d.ts +68 -46
- package/dist/components/button/index.js +38 -2
- package/dist/components/button-group/index.d.ts +11 -5
- package/dist/components/button-group/index.js +31 -7
- package/dist/components/canvas/index.d.ts +9 -3
- package/dist/components/canvas/index.js +53 -25
- package/dist/components/card/index.d.ts +13 -7
- package/dist/components/card/index.js +45 -17
- package/dist/components/checkbox/index.d.ts +73 -0
- package/dist/components/checkbox/index.js +100 -0
- package/dist/components/chip/index.d.ts +79 -0
- package/dist/components/chip/index.js +112 -0
- package/dist/components/choice-cards/index.d.ts +11 -5
- package/dist/components/choice-cards/index.js +25 -6
- package/dist/components/command-dock/index.d.ts +16 -9
- package/dist/components/command-dock/index.js +76 -19
- package/dist/components/day-grid/index.d.ts +12 -6
- package/dist/components/day-grid/index.js +71 -27
- package/dist/components/dialog/index.d.ts +19 -12
- package/dist/components/dialog/index.js +76 -24
- package/dist/components/feedback/index.d.ts +20 -13
- package/dist/components/feedback/index.js +83 -27
- package/dist/components/field/index.d.ts +85 -0
- package/dist/components/field/index.js +90 -0
- package/dist/components/flow/index.d.ts +21 -14
- package/dist/components/flow/index.js +56 -20
- package/dist/components/frame/index.d.ts +17 -11
- package/dist/components/frame/index.js +73 -22
- package/dist/components/input/index.d.ts +9 -24
- package/dist/components/input/index.js +53 -6
- package/dist/components/inspector/index.d.ts +69 -63
- package/dist/components/inspector/index.js +31 -9
- package/dist/components/kpi/index.d.ts +20 -14
- package/dist/components/kpi/index.js +111 -36
- package/dist/components/label/index.d.ts +10 -4
- package/dist/components/label/index.js +39 -9
- package/dist/components/lane-board/index.d.ts +15 -9
- package/dist/components/lane-board/index.js +97 -57
- package/dist/components/menu/index.d.ts +10 -4
- package/dist/components/menu/index.js +28 -10
- package/dist/components/message/index.d.ts +15 -9
- package/dist/components/message/index.js +71 -19
- package/dist/components/not-found/index.d.ts +10 -4
- package/dist/components/not-found/index.js +48 -12
- package/dist/components/planet/index.d.ts +11 -5
- package/dist/components/planet/index.js +73 -20
- package/dist/components/prompt/index.d.ts +30 -23
- package/dist/components/prompt/index.js +148 -52
- package/dist/components/radio-group/index.d.ts +124 -0
- package/dist/components/radio-group/index.js +216 -0
- package/dist/components/range-meter/index.d.ts +9 -3
- package/dist/components/range-meter/index.js +61 -27
- package/dist/components/rolling-number/index.d.ts +8 -1
- package/dist/components/rolling-number/index.js +15 -6
- package/dist/components/select/index.d.ts +7 -1
- package/dist/components/select/index.js +13 -4
- package/dist/components/sheet/index.d.ts +8 -2
- package/dist/components/sheet/index.js +27 -15
- package/dist/components/slider/index.d.ts +11 -4
- package/dist/components/slider/index.js +30 -10
- package/dist/components/soundwave/index.d.ts +8 -2
- package/dist/components/soundwave/index.js +26 -6
- package/dist/components/stat/index.d.ts +13 -7
- package/dist/components/stat/index.js +45 -15
- package/dist/components/table/index.d.ts +128 -0
- package/dist/components/table/index.js +145 -0
- package/dist/components/tabs/index.d.ts +7 -1
- package/dist/components/tabs/index.js +8 -2
- package/dist/components/textarea/index.d.ts +0 -23
- package/dist/components/textarea/index.js +22 -5
- package/dist/components/tilt-card/index.d.ts +9 -3
- package/dist/components/tilt-card/index.js +28 -8
- package/dist/components/timeline/index.d.ts +20 -13
- package/dist/components/timeline/index.js +166 -59
- package/dist/components/toast/dither-text.d.ts +13 -0
- package/dist/components/toast/dither-text.js +143 -0
- package/dist/components/toast/dither.d.ts +29 -0
- package/dist/components/toast/dither.js +153 -0
- package/dist/components/toast/index.d.ts +108 -0
- package/dist/components/toast/index.js +225 -0
- package/dist/components/toolbar/index.d.ts +9 -3
- package/dist/components/toolbar/index.js +23 -6
- package/dist/components/workbench/index.d.ts +50 -43
- package/dist/components/workbench/index.js +77 -20
- package/dist/components/xy-pad/index.d.ts +9 -3
- package/dist/components/xy-pad/index.js +13 -2
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/package.json +1 -1
|
@@ -37,6 +37,13 @@
|
|
|
37
37
|
* should not cut across what a screen reader is in the middle of saying.
|
|
38
38
|
*/
|
|
39
39
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
40
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
41
|
+
import type * as ReactTypes from 'react';
|
|
42
|
+
import type { ElementType as RenderElementType } from 'react';
|
|
43
|
+
/** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
|
|
44
|
+
type RenderProp<Tag extends RenderElementType> = {
|
|
45
|
+
render?: useRender.ComponentProps<Tag>['render'];
|
|
46
|
+
};
|
|
40
47
|
/** The theme role an alert is drawn in. */
|
|
41
48
|
export type AlertTone = 'neutral' | 'info' | 'success' | 'warning' | 'destructive';
|
|
42
49
|
/** `default` is the card in a tray, `plain` one tinted box, `banner` a strip across a page. */
|
|
@@ -57,28 +64,28 @@ export interface AlertProps extends ComponentProps<'div'> {
|
|
|
57
64
|
/** Called when `Alert.Close` asks for it to close. */
|
|
58
65
|
onOpenChange?: (open: boolean) => void;
|
|
59
66
|
}
|
|
60
|
-
declare function AlertRoot({ tone, variant, open, defaultOpen, onOpenChange, role, className, children, ...props }: AlertProps):
|
|
67
|
+
declare function AlertRoot({ tone, variant, open, defaultOpen, onOpenChange, role, className, children, ...props }: AlertProps): ReactTypes.JSX.Element;
|
|
61
68
|
declare namespace AlertRoot {
|
|
62
69
|
var displayName: string;
|
|
63
70
|
}
|
|
64
71
|
export interface AlertIconProps extends ComponentProps<'span'> {
|
|
65
72
|
}
|
|
66
73
|
/** The glyph at the start, in the tone's colour. Without children it draws the tone's own. */
|
|
67
|
-
declare function AlertIcon({ className, children, ...props }: AlertIconProps):
|
|
74
|
+
declare function AlertIcon({ className, children, render, ...props }: AlertIconProps & RenderProp<'span'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
68
75
|
declare namespace AlertIcon {
|
|
69
76
|
var displayName: string;
|
|
70
77
|
}
|
|
71
78
|
export interface AlertTitleProps extends ComponentProps<'div'> {
|
|
72
79
|
}
|
|
73
80
|
/** What happened, in a few words. */
|
|
74
|
-
declare function AlertTitle({ className, ...props }: AlertTitleProps):
|
|
81
|
+
declare function AlertTitle({ className, render, ...props }: AlertTitleProps & RenderProp<'div'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
75
82
|
declare namespace AlertTitle {
|
|
76
83
|
var displayName: string;
|
|
77
84
|
}
|
|
78
85
|
export interface AlertDescriptionProps extends ComponentProps<'div'> {
|
|
79
86
|
}
|
|
80
87
|
/** The sentence under the title: why, and what follows from it. A link in it is underlined. */
|
|
81
|
-
declare function AlertDescription({ className, ...props }: AlertDescriptionProps):
|
|
88
|
+
declare function AlertDescription({ className, render, ...props }: AlertDescriptionProps & RenderProp<'div'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
82
89
|
declare namespace AlertDescription {
|
|
83
90
|
var displayName: string;
|
|
84
91
|
}
|
|
@@ -89,14 +96,14 @@ export interface AlertActionsProps extends ComponentProps<'div'> {
|
|
|
89
96
|
* its end; in `plain` under the words; in `banner` at the end of the line.
|
|
90
97
|
* Keep it a direct child of `Alert`, so the tray can find it.
|
|
91
98
|
*/
|
|
92
|
-
declare function AlertActions({ className, ...props }: AlertActionsProps):
|
|
99
|
+
declare function AlertActions({ className, render, ...props }: AlertActionsProps & RenderProp<'div'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
93
100
|
declare namespace AlertActions {
|
|
94
101
|
var displayName: string;
|
|
95
102
|
}
|
|
96
103
|
export interface AlertCloseProps extends ComponentProps<'button'> {
|
|
97
104
|
}
|
|
98
105
|
/** A round cross at the end that folds the alert away. */
|
|
99
|
-
declare function AlertClose({ className, onClick, 'aria-label': label, ...props }: AlertCloseProps):
|
|
106
|
+
declare function AlertClose({ className, onClick, 'aria-label': label, render, ...props }: AlertCloseProps & RenderProp<'button'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
100
107
|
declare namespace AlertClose {
|
|
101
108
|
var displayName: string;
|
|
102
109
|
}
|
|
@@ -115,14 +122,14 @@ export interface AlertDetailsProps extends Omit<ComponentProps<'div'>, 'title'>
|
|
|
115
122
|
* an alert that sums up several things: the fields a form still needs, the
|
|
116
123
|
* files an upload skipped.
|
|
117
124
|
*/
|
|
118
|
-
declare function AlertDetails({ label, open, defaultOpen, onOpenChange, className, children, ...props }: AlertDetailsProps):
|
|
125
|
+
declare function AlertDetails({ label, open, defaultOpen, onOpenChange, className, children, render, ...props }: AlertDetailsProps & RenderProp<'div'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
119
126
|
declare namespace AlertDetails {
|
|
120
127
|
var displayName: string;
|
|
121
128
|
}
|
|
122
129
|
export interface AlertItemProps extends ComponentProps<'li'> {
|
|
123
130
|
}
|
|
124
131
|
/** One entry in `Alert.Details`, marked with a dot in the alert's tone. */
|
|
125
|
-
declare function AlertItem({ className, ...props }: AlertItemProps):
|
|
132
|
+
declare function AlertItem({ className, render, ...props }: AlertItemProps & RenderProp<'li'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
|
|
126
133
|
declare namespace AlertItem {
|
|
127
134
|
var displayName: string;
|
|
128
135
|
}
|
|
@@ -40,6 +40,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
40
40
|
*/
|
|
41
41
|
import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
42
42
|
import { tv } from 'tailwind-variants';
|
|
43
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
44
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
43
45
|
/** The fold every opening and closing here uses, the one the Prompt's bands use. */
|
|
44
46
|
const FOLD = 'grid transition-[grid-template-rows,opacity] duration-300 ease-[cubic-bezier(0.2,0,0,1)] motion-reduce:transition-none';
|
|
45
47
|
const alertVariants = tv({
|
|
@@ -205,19 +207,36 @@ const GLYPHS = {
|
|
|
205
207
|
destructive: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: "12", cy: "12", r: "9" }), _jsx("path", { d: "M12 7.5v5M12 16h.01" })] })),
|
|
206
208
|
};
|
|
207
209
|
/** The glyph at the start, in the tone's colour. Without children it draws the tone's own. */
|
|
208
|
-
function AlertIcon({ className, children, ...props }) {
|
|
210
|
+
function AlertIcon({ className, children, render, ...props }) {
|
|
209
211
|
const { tone } = useAlert('Alert.Icon');
|
|
210
|
-
return (
|
|
212
|
+
return useRender({
|
|
213
|
+
defaultTagName: 'span',
|
|
214
|
+
render,
|
|
215
|
+
props: mergeProps({
|
|
216
|
+
'data-slot': 'alert-icon',
|
|
217
|
+
'aria-hidden': 'true',
|
|
218
|
+
className: alertVariants().icon({ className }),
|
|
219
|
+
children: (_jsx(_Fragment, { children: children ?? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: GLYPHS[tone] })) })),
|
|
220
|
+
}, props),
|
|
221
|
+
});
|
|
211
222
|
}
|
|
212
223
|
AlertIcon.displayName = 'Alert.Icon';
|
|
213
224
|
/** What happened, in a few words. */
|
|
214
|
-
function AlertTitle({ className, ...props }) {
|
|
215
|
-
return
|
|
225
|
+
function AlertTitle({ className, render, ...props }) {
|
|
226
|
+
return useRender({
|
|
227
|
+
defaultTagName: 'div',
|
|
228
|
+
render,
|
|
229
|
+
props: mergeProps({ 'data-slot': 'alert-title', className: alertVariants().title({ className }) }, props),
|
|
230
|
+
});
|
|
216
231
|
}
|
|
217
232
|
AlertTitle.displayName = 'Alert.Title';
|
|
218
233
|
/** The sentence under the title: why, and what follows from it. A link in it is underlined. */
|
|
219
|
-
function AlertDescription({ className, ...props }) {
|
|
220
|
-
return
|
|
234
|
+
function AlertDescription({ className, render, ...props }) {
|
|
235
|
+
return useRender({
|
|
236
|
+
defaultTagName: 'div',
|
|
237
|
+
render,
|
|
238
|
+
props: mergeProps({ 'data-slot': 'alert-description', className: alertVariants().description({ className }) }, props),
|
|
239
|
+
});
|
|
221
240
|
}
|
|
222
241
|
AlertDescription.displayName = 'Alert.Description';
|
|
223
242
|
/**
|
|
@@ -225,18 +244,33 @@ AlertDescription.displayName = 'Alert.Description';
|
|
|
225
244
|
* its end; in `plain` under the words; in `banner` at the end of the line.
|
|
226
245
|
* Keep it a direct child of `Alert`, so the tray can find it.
|
|
227
246
|
*/
|
|
228
|
-
function AlertActions({ className, ...props }) {
|
|
229
|
-
return
|
|
247
|
+
function AlertActions({ className, render, ...props }) {
|
|
248
|
+
return useRender({
|
|
249
|
+
defaultTagName: 'div',
|
|
250
|
+
render,
|
|
251
|
+
props: mergeProps({ 'data-slot': 'alert-actions', className: alertVariants().actions({ className }) }, props),
|
|
252
|
+
});
|
|
230
253
|
}
|
|
231
254
|
AlertActions.displayName = 'Alert.Actions';
|
|
232
255
|
/** A round cross at the end that folds the alert away. */
|
|
233
|
-
function AlertClose({ className, onClick, 'aria-label': label = 'Dismiss', ...props }) {
|
|
256
|
+
function AlertClose({ className, onClick, 'aria-label': label = 'Dismiss', render, ...props }) {
|
|
234
257
|
const { setOpen } = useAlert('Alert.Close');
|
|
235
|
-
return (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
258
|
+
return useRender({
|
|
259
|
+
defaultTagName: 'button',
|
|
260
|
+
render,
|
|
261
|
+
props: mergeProps({
|
|
262
|
+
type: 'button',
|
|
263
|
+
'data-slot': 'alert-close',
|
|
264
|
+
'aria-label': label,
|
|
265
|
+
className: alertVariants().close({ className }),
|
|
266
|
+
onClick: (event) => {
|
|
267
|
+
onClick?.(event);
|
|
268
|
+
if (!event.defaultPrevented)
|
|
269
|
+
setOpen(false);
|
|
270
|
+
},
|
|
271
|
+
children: (_jsx(_Fragment, { children: _jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", children: _jsx("path", { d: "M6 6l12 12M18 6L6 18" }) }) })),
|
|
272
|
+
}, props),
|
|
273
|
+
});
|
|
240
274
|
}
|
|
241
275
|
AlertClose.displayName = 'Alert.Close';
|
|
242
276
|
/**
|
|
@@ -244,7 +278,7 @@ AlertClose.displayName = 'Alert.Close';
|
|
|
244
278
|
* an alert that sums up several things: the fields a form still needs, the
|
|
245
279
|
* files an upload skipped.
|
|
246
280
|
*/
|
|
247
|
-
function AlertDetails({ label, open, defaultOpen = false, onOpenChange, className, children, ...props }) {
|
|
281
|
+
function AlertDetails({ label, open, defaultOpen = false, onOpenChange, className, children, render, ...props }) {
|
|
248
282
|
useAlert('Alert.Details');
|
|
249
283
|
const slots = alertVariants();
|
|
250
284
|
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
@@ -259,12 +293,25 @@ function AlertDetails({ label, open, defaultOpen = false, onOpenChange, classNam
|
|
|
259
293
|
setInternalOpen(!expanded);
|
|
260
294
|
onOpenChange?.(!expanded);
|
|
261
295
|
};
|
|
262
|
-
return (
|
|
296
|
+
return useRender({
|
|
297
|
+
defaultTagName: 'div',
|
|
298
|
+
render,
|
|
299
|
+
props: mergeProps({
|
|
300
|
+
'data-slot': 'alert-details',
|
|
301
|
+
'data-open': expanded ? '' : undefined,
|
|
302
|
+
className: slots.details({ className }),
|
|
303
|
+
children: (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", "aria-expanded": expanded, "aria-controls": listId, onClick: toggle, className: slots.detailsToggle(), children: [label, _jsx("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: slots.detailsChevron({ className: expanded ? 'rotate-180' : undefined }), children: _jsx("path", { d: "m6 9 6 6 6-6" }) })] }), _jsx("div", { className: [FOLD, expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr] opacity-0'].join(' '), children: _jsx("div", { ref: clip, className: "min-h-0 overflow-hidden", children: _jsx("ul", { id: listId, className: slots.detailsList(), children: children }) }) })] })),
|
|
304
|
+
}, props),
|
|
305
|
+
});
|
|
263
306
|
}
|
|
264
307
|
AlertDetails.displayName = 'Alert.Details';
|
|
265
308
|
/** One entry in `Alert.Details`, marked with a dot in the alert's tone. */
|
|
266
|
-
function AlertItem({ className, ...props }) {
|
|
267
|
-
return
|
|
309
|
+
function AlertItem({ className, render, ...props }) {
|
|
310
|
+
return useRender({
|
|
311
|
+
defaultTagName: 'li',
|
|
312
|
+
render,
|
|
313
|
+
props: mergeProps({ 'data-slot': 'alert-item', className: alertVariants().item({ className }) }, props),
|
|
314
|
+
});
|
|
268
315
|
}
|
|
269
316
|
AlertItem.displayName = 'Alert.Item';
|
|
270
317
|
export const Alert = Object.assign(AlertRoot, {
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { type ComponentProps, type MouseEvent, type ReactElement, type ReactNode } from 'react';
|
|
2
2
|
import { type ButtonProps } from '../button/index.js';
|
|
3
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
4
|
+
import type { ElementType as RenderElementType } from 'react';
|
|
5
|
+
/** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
|
|
6
|
+
type RenderProp<Tag extends RenderElementType> = {
|
|
7
|
+
render?: useRender.ComponentProps<Tag>['render'];
|
|
8
|
+
};
|
|
3
9
|
/** The theme role the dialog's media is drawn in, which also sets its action's default colour. */
|
|
4
10
|
export type AlertDialogTone = 'neutral' | 'info' | 'success' | 'warning' | 'destructive';
|
|
5
11
|
export interface AlertDialogProps {
|
|
@@ -13,7 +19,7 @@ export interface AlertDialogProps {
|
|
|
13
19
|
/** Whether a press outside it closes it, as Cancel would. Escape always does. Default `true`. */
|
|
14
20
|
dismissible?: boolean;
|
|
15
21
|
}
|
|
16
|
-
declare function AlertDialogRoot({ children, open, defaultOpen, onOpenChange, dismissible
|
|
22
|
+
declare function AlertDialogRoot({ children, open, defaultOpen, onOpenChange, dismissible }: AlertDialogProps): import("react").JSX.Element;
|
|
17
23
|
declare namespace AlertDialogRoot {
|
|
18
24
|
var displayName: string;
|
|
19
25
|
}
|
|
@@ -56,7 +62,7 @@ declare namespace AlertDialogContent {
|
|
|
56
62
|
export interface AlertDialogMediaProps extends ComponentProps<'div'> {
|
|
57
63
|
}
|
|
58
64
|
/** A glyph in a disc of the dialog's tone, above the title. */
|
|
59
|
-
declare function AlertDialogMedia({ className, ...props }: AlertDialogMediaProps): import("react").
|
|
65
|
+
declare function AlertDialogMedia({ className, render, ...props }: AlertDialogMediaProps & RenderProp<'div'>): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
60
66
|
declare namespace AlertDialogMedia {
|
|
61
67
|
var displayName: string;
|
|
62
68
|
}
|
|
@@ -80,7 +86,7 @@ export interface AlertDialogFooterProps extends ComponentProps<'div'> {
|
|
|
80
86
|
* The answers, side by side at equal widths in the band under the panel.
|
|
81
87
|
* Keep it a direct child of `AlertDialog.Content`, so the band can find it.
|
|
82
88
|
*/
|
|
83
|
-
declare function AlertDialogFooter({ className, ...props }: AlertDialogFooterProps): import("react").
|
|
89
|
+
declare function AlertDialogFooter({ className, render, ...props }: AlertDialogFooterProps & RenderProp<'div'>): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
84
90
|
declare namespace AlertDialogFooter {
|
|
85
91
|
var displayName: string;
|
|
86
92
|
}
|
|
@@ -47,6 +47,8 @@ import { Dialog as Primitive } from '@base-ui/react/dialog';
|
|
|
47
47
|
import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
|
|
48
48
|
import { tv } from 'tailwind-variants';
|
|
49
49
|
import { Button } from '../button/index.js';
|
|
50
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
51
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
50
52
|
const alertDialogVariants = tv({
|
|
51
53
|
slots: {
|
|
52
54
|
backdrop: 'fixed inset-0 z-50 bg-black/40 transition-opacity duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none',
|
|
@@ -103,7 +105,9 @@ const alertDialogVariants = tv({
|
|
|
103
105
|
{
|
|
104
106
|
weight: 'soft',
|
|
105
107
|
actionTone: 'primary',
|
|
106
|
-
className: {
|
|
108
|
+
className: {
|
|
109
|
+
action: 'bg-foreground/10 text-foreground hover:not-disabled:bg-foreground/15 hover:not-disabled:text-foreground',
|
|
110
|
+
},
|
|
107
111
|
},
|
|
108
112
|
{
|
|
109
113
|
weight: 'soft',
|
|
@@ -129,7 +133,7 @@ function useAlertDialog(part) {
|
|
|
129
133
|
throw new Error(`${part} must be used inside an <AlertDialog>.`);
|
|
130
134
|
return context;
|
|
131
135
|
}
|
|
132
|
-
function AlertDialogRoot({ children, open, defaultOpen = false, onOpenChange, dismissible = true
|
|
136
|
+
function AlertDialogRoot({ children, open, defaultOpen = false, onOpenChange, dismissible = true }) {
|
|
133
137
|
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
134
138
|
const resolvedOpen = open ?? internalOpen;
|
|
135
139
|
const [busy, setBusy] = useState(false);
|
|
@@ -169,8 +173,16 @@ function AlertDialogContent({ tone = 'neutral', size = 'default', blur = false,
|
|
|
169
173
|
}
|
|
170
174
|
AlertDialogContent.displayName = 'AlertDialog.Content';
|
|
171
175
|
/** A glyph in a disc of the dialog's tone, above the title. */
|
|
172
|
-
function AlertDialogMedia({ className, ...props }) {
|
|
173
|
-
return
|
|
176
|
+
function AlertDialogMedia({ className, render, ...props }) {
|
|
177
|
+
return useRender({
|
|
178
|
+
defaultTagName: 'div',
|
|
179
|
+
render,
|
|
180
|
+
props: mergeProps({
|
|
181
|
+
'data-slot': 'alert-dialog-media',
|
|
182
|
+
'aria-hidden': 'true',
|
|
183
|
+
className: alertDialogVariants().media({ className }),
|
|
184
|
+
}, props),
|
|
185
|
+
});
|
|
174
186
|
}
|
|
175
187
|
AlertDialogMedia.displayName = 'AlertDialog.Media';
|
|
176
188
|
/** The question. It is what the dialog is announced as. */
|
|
@@ -188,15 +200,19 @@ function AlertDialogDescription({ className, ...props }) {
|
|
|
188
200
|
const slots = alertDialogVariants();
|
|
189
201
|
if (inline)
|
|
190
202
|
return _jsx("p", { "data-slot": "alert-dialog-description", className: slots.description({ className }), ...props });
|
|
191
|
-
return _jsx(Primitive.Description, { "data-slot": "alert-dialog-description", className: slots.description({ className }), ...props });
|
|
203
|
+
return (_jsx(Primitive.Description, { "data-slot": "alert-dialog-description", className: slots.description({ className }), ...props }));
|
|
192
204
|
}
|
|
193
205
|
AlertDialogDescription.displayName = 'AlertDialog.Description';
|
|
194
206
|
/**
|
|
195
207
|
* The answers, side by side at equal widths in the band under the panel.
|
|
196
208
|
* Keep it a direct child of `AlertDialog.Content`, so the band can find it.
|
|
197
209
|
*/
|
|
198
|
-
function AlertDialogFooter({ className, ...props }) {
|
|
199
|
-
return
|
|
210
|
+
function AlertDialogFooter({ className, render, ...props }) {
|
|
211
|
+
return useRender({
|
|
212
|
+
defaultTagName: 'div',
|
|
213
|
+
render,
|
|
214
|
+
props: mergeProps({ 'data-slot': 'alert-dialog-footer', className: alertDialogVariants().footer({ className }) }, props),
|
|
215
|
+
});
|
|
200
216
|
}
|
|
201
217
|
AlertDialogFooter.displayName = 'AlertDialog.Footer';
|
|
202
218
|
/** Closes the dialog without doing anything. It reads "Cancel" unless given children. */
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import { type ComponentProps, type ReactNode } from 'react';
|
|
1
|
+
import { type ComponentProps, type ReactElement, type ReactNode } from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { ElementType as RenderElementType } from 'react';
|
|
4
|
+
/** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
|
|
5
|
+
type RenderProp<Tag extends RenderElementType> = {
|
|
6
|
+
render?: useRender.ComponentProps<Tag>['render'];
|
|
7
|
+
};
|
|
2
8
|
export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
3
9
|
export type AvatarShape = 'circle' | 'square';
|
|
4
10
|
export type AvatarColor = 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5' | 'muted';
|
|
@@ -22,7 +28,7 @@ export interface AvatarProps extends Omit<ComponentProps<'span'>, 'color'> {
|
|
|
22
28
|
children?: ReactNode;
|
|
23
29
|
}
|
|
24
30
|
/** A picture of someone, or their initials in a colour of their own. */
|
|
25
|
-
declare function AvatarRoot({ src, name, alt, size, shape, color, fallback, className, style, children, ...props }: AvatarProps): import("react").
|
|
31
|
+
declare function AvatarRoot({ src, name, alt, size, shape, color, fallback, className, style, children, render, ...props }: AvatarProps & RenderProp<'span'>): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
26
32
|
declare namespace AvatarRoot {
|
|
27
33
|
var displayName: string;
|
|
28
34
|
}
|
|
@@ -40,7 +46,7 @@ export interface AvatarBadgeProps extends Omit<ComponentProps<'span'>, 'color'>
|
|
|
40
46
|
* A dot or a small icon on the avatar's lower trailing edge. The avatar is
|
|
41
47
|
* cut away round it, so it reads on any background.
|
|
42
48
|
*/
|
|
43
|
-
declare function AvatarBadge({ status, color, label: _label, className, ...props }: AvatarBadgeProps): import("react").
|
|
49
|
+
declare function AvatarBadge({ status, color, label: _label, className, render, ...props }: AvatarBadgeProps & RenderProp<'span'>): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
44
50
|
declare namespace AvatarBadge {
|
|
45
51
|
var displayName: string;
|
|
46
52
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
4
|
* Avatar — a person or a team as a picture, with their initials when there
|
|
5
5
|
* is no picture to show.
|
|
@@ -41,6 +41,8 @@ import { Avatar as BaseAvatar } from '@base-ui/react/avatar';
|
|
|
41
41
|
import { Popover } from '@base-ui/react/popover';
|
|
42
42
|
import { Children, createContext, isValidElement, useContext, useMemo, } from 'react';
|
|
43
43
|
import { tv } from 'tailwind-variants';
|
|
44
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
45
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
44
46
|
const SIZE = {
|
|
45
47
|
xs: '1.5rem',
|
|
46
48
|
sm: '2rem',
|
|
@@ -197,7 +199,7 @@ const GroupContext = createContext(null);
|
|
|
197
199
|
/** Set on every avatar in a group but the last, which nothing overlaps. */
|
|
198
200
|
const OverlappedContext = createContext(false);
|
|
199
201
|
/** A picture of someone, or their initials in a colour of their own. */
|
|
200
|
-
function AvatarRoot({ src, name, alt, size, shape, color, fallback, className, style, children, ...props }) {
|
|
202
|
+
function AvatarRoot({ src, name, alt, size, shape, color, fallback, className, style, children, render, ...props }) {
|
|
201
203
|
const group = useContext(GroupContext);
|
|
202
204
|
const overlapped = useContext(OverlappedContext);
|
|
203
205
|
const resolvedSize = size ?? group?.size ?? 'md';
|
|
@@ -207,12 +209,25 @@ function AvatarRoot({ src, name, alt, size, shape, color, fallback, className, s
|
|
|
207
209
|
const badge = Children.toArray(children).find((child) => isValidElement(child) && child.type === AvatarBadge);
|
|
208
210
|
const status = badge?.props.label ?? (badge?.props.status ? STATUS_LABEL[badge.props.status] : undefined);
|
|
209
211
|
const label = [alt ?? name, status].filter(Boolean).join(', ') || undefined;
|
|
210
|
-
return (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
212
|
+
return useRender({
|
|
213
|
+
defaultTagName: 'span',
|
|
214
|
+
render,
|
|
215
|
+
props: mergeProps({
|
|
216
|
+
'data-slot': 'avatar',
|
|
217
|
+
'data-size': resolvedSize,
|
|
218
|
+
'data-shape': resolvedShape,
|
|
219
|
+
role: label ? 'img' : undefined,
|
|
220
|
+
'aria-label': label,
|
|
221
|
+
className: slots.root({ className }),
|
|
222
|
+
style: {
|
|
223
|
+
['--avatar-size']: SIZE[resolvedSize],
|
|
224
|
+
// Here and not on the badge, so the face's cut and the badge's place can both read it.
|
|
225
|
+
['--badge-size']: 'max(0.5rem, calc(var(--avatar-size) * 0.28))',
|
|
226
|
+
...style,
|
|
227
|
+
},
|
|
228
|
+
children: (_jsxs(_Fragment, { children: [_jsxs(BaseAvatar.Root, { "data-slot": "avatar-face", "aria-hidden": "true", className: slots.face(), style: maskStyle(resolvedShape, badge !== undefined, overlapped), children: [src ? _jsx(BaseAvatar.Image, { src: src, alt: "", className: slots.image() }) : null, _jsx(BaseAvatar.Fallback, { className: slots.fallback(), children: fallback ?? (name ? initialsOf(name) : _jsx(PersonGlyph, {})) })] }), children] })),
|
|
229
|
+
}, props),
|
|
230
|
+
});
|
|
216
231
|
}
|
|
217
232
|
AvatarRoot.displayName = 'Avatar';
|
|
218
233
|
function PersonGlyph() {
|
|
@@ -222,9 +237,18 @@ function PersonGlyph() {
|
|
|
222
237
|
* A dot or a small icon on the avatar's lower trailing edge. The avatar is
|
|
223
238
|
* cut away round it, so it reads on any background.
|
|
224
239
|
*/
|
|
225
|
-
function AvatarBadge({ status, color, label: _label, className, ...props }) {
|
|
240
|
+
function AvatarBadge({ status, color, label: _label, className, render, ...props }) {
|
|
226
241
|
const slots = avatarVariants({ status, color: status ? undefined : (color ?? 'muted') });
|
|
227
|
-
return (
|
|
242
|
+
return useRender({
|
|
243
|
+
defaultTagName: 'span',
|
|
244
|
+
render,
|
|
245
|
+
props: mergeProps({
|
|
246
|
+
'aria-hidden': 'true',
|
|
247
|
+
'data-slot': 'avatar-badge',
|
|
248
|
+
'data-status': status,
|
|
249
|
+
className: slots.badge({ className }),
|
|
250
|
+
}, props),
|
|
251
|
+
});
|
|
228
252
|
}
|
|
229
253
|
AvatarBadge.displayName = 'Avatar.Badge';
|
|
230
254
|
/** A row of overlapping avatars, that opens up when it is hovered or focused. */
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge — a short label that says what state something is in, or what kind of thing it is.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <Badge>New</Badge>
|
|
6
|
+
* <Badge variant="success" dot>Operational</Badge>
|
|
7
|
+
* <Badge variant="info" dot="pulse">Building</Badge>
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* ## Status colours are tinted, not filled
|
|
11
|
+
*
|
|
12
|
+
* A status badge sits inside a row of other text, and a solid green or red
|
|
13
|
+
* block pulls the eye away from the row it belongs to. `success`, `info`,
|
|
14
|
+
* `warning` and `destructive` draw their colour as a light tint with text in
|
|
15
|
+
* the same hue, so a column of them reads as a column of states rather than a
|
|
16
|
+
* column of buttons. `default` is the one solid badge, for the single thing on
|
|
17
|
+
* a screen that should be seen first.
|
|
18
|
+
*
|
|
19
|
+
* ## The dot says it is live
|
|
20
|
+
*
|
|
21
|
+
* `dot` puts a small mark before the text in the badge's colour. `dot="pulse"`
|
|
22
|
+
* makes it breathe, for a state that is still changing — a build running, a
|
|
23
|
+
* call connected — and stops once the state settles. The pulse is off for
|
|
24
|
+
* readers who ask for reduced motion.
|
|
25
|
+
*
|
|
26
|
+
* A badge is not a control. For a label that can be pressed, removed or
|
|
27
|
+
* toggled, use Chip.
|
|
28
|
+
*/
|
|
29
|
+
import type { ComponentProps } from 'react';
|
|
30
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
31
|
+
import type { ElementType as RenderElementType } from 'react';
|
|
32
|
+
/** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
|
|
33
|
+
type RenderProp<Tag extends RenderElementType> = {
|
|
34
|
+
render?: useRender.ComponentProps<Tag>['render'];
|
|
35
|
+
};
|
|
36
|
+
export type BadgeVariant = 'default' | 'secondary' | 'outline' | 'success' | 'info' | 'warning' | 'destructive';
|
|
37
|
+
export type BadgeSize = 'sm' | 'md' | 'lg';
|
|
38
|
+
export interface BadgeProps extends ComponentProps<'span'> {
|
|
39
|
+
/**
|
|
40
|
+
* What it means. `default` is solid, for the one thing that should be seen
|
|
41
|
+
* first; the four states are tinted in their theme colour. Default `default`.
|
|
42
|
+
*/
|
|
43
|
+
variant?: BadgeVariant;
|
|
44
|
+
/** Its height and text size. Default `md`. */
|
|
45
|
+
size?: BadgeSize;
|
|
46
|
+
/**
|
|
47
|
+
* A dot before the text in the badge's colour. `'pulse'` makes it breathe,
|
|
48
|
+
* for a state that is still changing.
|
|
49
|
+
*/
|
|
50
|
+
dot?: boolean | 'pulse';
|
|
51
|
+
}
|
|
52
|
+
/** A short label for a state or a kind. Renders a `<span>`. */
|
|
53
|
+
declare function Badge({ variant, size, dot, className, children, render, ...props }: BadgeProps & RenderProp<'span'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
54
|
+
declare namespace Badge {
|
|
55
|
+
var displayName: string;
|
|
56
|
+
}
|
|
57
|
+
export { Badge };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { tv } from 'tailwind-variants';
|
|
4
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
5
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
6
|
+
const badgeVariants = tv({
|
|
7
|
+
slots: {
|
|
8
|
+
root: [
|
|
9
|
+
'inline-flex w-fit shrink-0 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border font-medium',
|
|
10
|
+
'tabular-nums [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-3.5',
|
|
11
|
+
],
|
|
12
|
+
dot: 'relative inline-flex size-1.5 shrink-0 rounded-full bg-current',
|
|
13
|
+
halo: 'absolute inset-0 rounded-full bg-current opacity-60 animate-ping motion-reduce:hidden',
|
|
14
|
+
},
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: { root: 'border-transparent bg-primary text-primary-foreground' },
|
|
18
|
+
secondary: { root: 'border-transparent bg-secondary text-secondary-foreground' },
|
|
19
|
+
outline: { root: 'border-border bg-transparent text-foreground', dot: 'text-muted-foreground' },
|
|
20
|
+
// The four states share one recipe, read from --badge-color.
|
|
21
|
+
success: { root: '[--badge-color:var(--success)]' },
|
|
22
|
+
info: { root: '[--badge-color:var(--info)]' },
|
|
23
|
+
warning: { root: '[--badge-color:var(--warning)]' },
|
|
24
|
+
destructive: { root: '[--badge-color:var(--destructive)]' },
|
|
25
|
+
},
|
|
26
|
+
tinted: {
|
|
27
|
+
true: {
|
|
28
|
+
root: [
|
|
29
|
+
'border-[color-mix(in_oklab,var(--badge-color)_22%,var(--background))]',
|
|
30
|
+
'bg-[color-mix(in_oklab,var(--badge-color)_10%,var(--background))] dark:bg-[color-mix(in_oklab,var(--badge-color)_16%,var(--background))]',
|
|
31
|
+
// Text in the badge's own hue, pulled towards the foreground so it stays legible on the tint.
|
|
32
|
+
'text-[color-mix(in_oklab,var(--badge-color),var(--foreground)_30%)]',
|
|
33
|
+
],
|
|
34
|
+
dot: 'text-(--badge-color)',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
size: {
|
|
38
|
+
sm: { root: 'h-5 px-1.5 text-[0.6875rem] leading-none' },
|
|
39
|
+
md: { root: 'h-6 px-2 text-xs leading-none' },
|
|
40
|
+
lg: { root: 'h-7 px-2.5 text-[0.8125rem] leading-none' },
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
defaultVariants: { variant: 'default', size: 'md', tinted: false },
|
|
44
|
+
});
|
|
45
|
+
const TINTED = new Set(['success', 'info', 'warning', 'destructive']);
|
|
46
|
+
/** A short label for a state or a kind. Renders a `<span>`. */
|
|
47
|
+
function Badge({ variant = 'default', size = 'md', dot = false, className, children, render, ...props }) {
|
|
48
|
+
const slots = badgeVariants({ variant, size, tinted: TINTED.has(variant) });
|
|
49
|
+
return useRender({
|
|
50
|
+
defaultTagName: 'span',
|
|
51
|
+
render,
|
|
52
|
+
props: mergeProps({
|
|
53
|
+
'data-slot': 'badge',
|
|
54
|
+
'data-variant': variant,
|
|
55
|
+
className: slots.root({ className }),
|
|
56
|
+
children: (_jsxs(_Fragment, { children: [dot ? (_jsx("span", { "data-slot": "badge-dot", "aria-hidden": "true", className: slots.dot(), children: dot === 'pulse' ? _jsx("span", { className: slots.halo() }) : null })) : null, children] })),
|
|
57
|
+
}, props),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
Badge.displayName = 'Badge';
|
|
61
|
+
export { Badge };
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
* the unit, but one number can.
|
|
27
27
|
*/
|
|
28
28
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
29
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
30
|
+
import type { ElementType as RenderElementType } from 'react';
|
|
31
|
+
/** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
|
|
32
|
+
type RenderProp<Tag extends RenderElementType> = {
|
|
33
|
+
render?: useRender.ComponentProps<Tag>['render'];
|
|
34
|
+
};
|
|
29
35
|
export interface BarPickerBar {
|
|
30
36
|
/** Written under the column: "Mon", "W3". Keep it to a few characters. */
|
|
31
37
|
label: ReactNode;
|
|
@@ -55,7 +61,8 @@ export interface BarPickerProps extends Omit<ComponentProps<'div'>, 'children' |
|
|
|
55
61
|
/** What a screen reader calls the row. */
|
|
56
62
|
label?: string;
|
|
57
63
|
}
|
|
58
|
-
export declare function BarPicker({ data, max, value, defaultValue, onValueChange, segments, color, formatValue, label, className, ...props }: BarPickerProps): import("react").
|
|
64
|
+
export declare function BarPicker({ data, max, value, defaultValue, onValueChange, segments, color, formatValue, label, className, render, ...props }: BarPickerProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
59
65
|
export declare namespace BarPicker {
|
|
60
66
|
var displayName: string;
|
|
61
67
|
}
|
|
68
|
+
export {};
|