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.
Files changed (99) hide show
  1. package/dist/components/alert/index.d.ts +15 -8
  2. package/dist/components/alert/index.js +65 -18
  3. package/dist/components/alert-dialog/index.d.ts +9 -3
  4. package/dist/components/alert-dialog/index.js +23 -7
  5. package/dist/components/avatar/index.d.ts +9 -3
  6. package/dist/components/avatar/index.js +34 -10
  7. package/dist/components/badge/index.d.ts +57 -0
  8. package/dist/components/badge/index.js +61 -0
  9. package/dist/components/bar-picker/index.d.ts +8 -1
  10. package/dist/components/bar-picker/index.js +35 -26
  11. package/dist/components/button/index.d.ts +68 -46
  12. package/dist/components/button/index.js +38 -2
  13. package/dist/components/button-group/index.d.ts +11 -5
  14. package/dist/components/button-group/index.js +31 -7
  15. package/dist/components/canvas/index.d.ts +9 -3
  16. package/dist/components/canvas/index.js +53 -25
  17. package/dist/components/card/index.d.ts +13 -7
  18. package/dist/components/card/index.js +45 -17
  19. package/dist/components/checkbox/index.d.ts +73 -0
  20. package/dist/components/checkbox/index.js +100 -0
  21. package/dist/components/chip/index.d.ts +79 -0
  22. package/dist/components/chip/index.js +112 -0
  23. package/dist/components/choice-cards/index.d.ts +11 -5
  24. package/dist/components/choice-cards/index.js +25 -6
  25. package/dist/components/command-dock/index.d.ts +16 -9
  26. package/dist/components/command-dock/index.js +76 -19
  27. package/dist/components/day-grid/index.d.ts +12 -6
  28. package/dist/components/day-grid/index.js +71 -27
  29. package/dist/components/dialog/index.d.ts +19 -12
  30. package/dist/components/dialog/index.js +76 -24
  31. package/dist/components/feedback/index.d.ts +20 -13
  32. package/dist/components/feedback/index.js +83 -27
  33. package/dist/components/field/index.d.ts +85 -0
  34. package/dist/components/field/index.js +90 -0
  35. package/dist/components/flow/index.d.ts +21 -14
  36. package/dist/components/flow/index.js +56 -20
  37. package/dist/components/frame/index.d.ts +17 -11
  38. package/dist/components/frame/index.js +73 -22
  39. package/dist/components/input/index.d.ts +9 -24
  40. package/dist/components/input/index.js +53 -6
  41. package/dist/components/inspector/index.d.ts +69 -63
  42. package/dist/components/inspector/index.js +31 -9
  43. package/dist/components/kpi/index.d.ts +20 -14
  44. package/dist/components/kpi/index.js +111 -36
  45. package/dist/components/label/index.d.ts +10 -4
  46. package/dist/components/label/index.js +39 -9
  47. package/dist/components/lane-board/index.d.ts +15 -9
  48. package/dist/components/lane-board/index.js +97 -57
  49. package/dist/components/menu/index.d.ts +10 -4
  50. package/dist/components/menu/index.js +28 -10
  51. package/dist/components/message/index.d.ts +15 -9
  52. package/dist/components/message/index.js +71 -19
  53. package/dist/components/not-found/index.d.ts +10 -4
  54. package/dist/components/not-found/index.js +48 -12
  55. package/dist/components/planet/index.d.ts +11 -5
  56. package/dist/components/planet/index.js +73 -20
  57. package/dist/components/prompt/index.d.ts +30 -23
  58. package/dist/components/prompt/index.js +148 -52
  59. package/dist/components/radio-group/index.d.ts +124 -0
  60. package/dist/components/radio-group/index.js +216 -0
  61. package/dist/components/range-meter/index.d.ts +9 -3
  62. package/dist/components/range-meter/index.js +61 -27
  63. package/dist/components/rolling-number/index.d.ts +8 -1
  64. package/dist/components/rolling-number/index.js +15 -6
  65. package/dist/components/select/index.d.ts +7 -1
  66. package/dist/components/select/index.js +13 -4
  67. package/dist/components/sheet/index.d.ts +8 -2
  68. package/dist/components/sheet/index.js +27 -15
  69. package/dist/components/slider/index.d.ts +11 -4
  70. package/dist/components/slider/index.js +30 -10
  71. package/dist/components/soundwave/index.d.ts +8 -2
  72. package/dist/components/soundwave/index.js +26 -6
  73. package/dist/components/stat/index.d.ts +13 -7
  74. package/dist/components/stat/index.js +45 -15
  75. package/dist/components/table/index.d.ts +128 -0
  76. package/dist/components/table/index.js +145 -0
  77. package/dist/components/tabs/index.d.ts +7 -1
  78. package/dist/components/tabs/index.js +8 -2
  79. package/dist/components/textarea/index.d.ts +0 -23
  80. package/dist/components/textarea/index.js +22 -5
  81. package/dist/components/tilt-card/index.d.ts +9 -3
  82. package/dist/components/tilt-card/index.js +28 -8
  83. package/dist/components/timeline/index.d.ts +20 -13
  84. package/dist/components/timeline/index.js +166 -59
  85. package/dist/components/toast/dither-text.d.ts +13 -0
  86. package/dist/components/toast/dither-text.js +143 -0
  87. package/dist/components/toast/dither.d.ts +29 -0
  88. package/dist/components/toast/dither.js +153 -0
  89. package/dist/components/toast/index.d.ts +108 -0
  90. package/dist/components/toast/index.js +225 -0
  91. package/dist/components/toolbar/index.d.ts +9 -3
  92. package/dist/components/toolbar/index.js +23 -6
  93. package/dist/components/workbench/index.d.ts +50 -43
  94. package/dist/components/workbench/index.js +77 -20
  95. package/dist/components/xy-pad/index.d.ts +9 -3
  96. package/dist/components/xy-pad/index.js +13 -2
  97. package/dist/index.d.ts +7 -0
  98. package/dist/index.js +7 -0
  99. package/package.json +1 -1
@@ -72,6 +72,8 @@ import { Drawer } from '@base-ui/react/drawer';
72
72
  import { ScrollArea } from '@base-ui/react/scroll-area';
73
73
  import { Children, createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
74
74
  import { tv } from 'tailwind-variants';
75
+ import { mergeProps } from '@base-ui/react/merge-props';
76
+ import { useRender } from '@base-ui/react/use-render';
75
77
  /*
76
78
  * One curve for every movement: the sheet arriving, the one behind it stepping
77
79
  * back, the page receding. A fast start that eases into place reads as weight,
@@ -356,16 +358,11 @@ function SheetFrame({ children, open, onOpenChange, defaultOpen = false, side =
356
358
  return (_jsx(SheetContext.Provider, { value: context, children: _jsx(Drawer.Root, { open: isOpen, handle: drawerHandle, swipeDirection: SWIPE[side], disablePointerDismissal: !dismissible, onOpenChange: (next, details) => {
357
359
  // The primitive has a switch for a press outside and none for
358
360
  // Escape or a swipe, so those are refused here.
359
- if (!next &&
360
- !dismissible &&
361
- details.reason !== 'close-press' &&
362
- details.reason !== 'imperative-action') {
361
+ if (!next && !dismissible && details.reason !== 'close-press' && details.reason !== 'imperative-action') {
363
362
  return;
364
363
  }
365
364
  setOpen(next);
366
- }, children: typeof children === 'function'
367
- ? ({ payload }) => children(payload)
368
- : children }) }));
365
+ }, children: typeof children === 'function' ? ({ payload }) => children(payload) : children }) }));
369
366
  }
370
367
  /**
371
368
  * What opens a sheet: its own, or with `to`, the `Sheet.Next` of that name.
@@ -435,10 +432,17 @@ SheetContent.displayName = 'Sheet.Content';
435
432
  * The heading block. It leaves room for the close button beside the title,
436
433
  * so the two share the top line instead of stacking.
437
434
  */
438
- function SheetHeader({ title, description, className, children, ...props }) {
435
+ function SheetHeader({ title, description, className, children, render, ...props }) {
439
436
  const { showClose } = useSheet('Sheet.Header');
440
437
  const slots = sheetVariants();
441
- return (_jsxs("div", { className: slots.header({ className: [showClose && 'pe-14', className] }), ...props, children: [title !== undefined ? _jsx(SheetTitle, { children: title }) : null, description !== undefined ? _jsx(SheetDescription, { children: description }) : null, children] }));
438
+ return useRender({
439
+ defaultTagName: 'div',
440
+ render,
441
+ props: mergeProps({
442
+ className: slots.header({ className: [showClose && 'pe-14', className] }),
443
+ children: (_jsxs(_Fragment, { children: [title !== undefined ? _jsx(SheetTitle, { children: title }) : null, description !== undefined ? _jsx(SheetDescription, { children: description }) : null, children] })),
444
+ }, props),
445
+ });
442
446
  }
443
447
  SheetHeader.displayName = 'Sheet.Header';
444
448
  /** The sheet's name, announced when it opens. */
@@ -456,7 +460,7 @@ function SheetDescription({ className, ...props }) {
456
460
  const slots = sheetVariants();
457
461
  if (inline)
458
462
  return _jsx("p", { className: slots.description({ className }), ...props });
459
- return (_jsx(Drawer.Content, { render: _jsx(Drawer.Description, { className: slots.description({ className }), ...props }) }));
463
+ return _jsx(Drawer.Content, { render: _jsx(Drawer.Description, { className: slots.description({ className }), ...props }) });
460
464
  }
461
465
  SheetDescription.displayName = 'Sheet.Description';
462
466
  /**
@@ -678,14 +682,12 @@ function SheetSlides({ snap = true, index, defaultIndex = 0, onIndexChange, coun
678
682
  };
679
683
  const context = useMemo(() => ({ snap, count, current, choose: settle, pressable: !snap && onIndexChange !== undefined }), [snap, count, current, settle, onIndexChange]);
680
684
  return (_jsx(SlidesContext.Provider, { value: context, children: _jsxs(ScrollArea.Root, { "data-slot": "sheet-slides", "data-snap": snap ? '' : undefined, className: slots.slides({ className }), style: { ...style, ['--slide-aspect']: aspect }, ...props, children: [_jsx(ScrollArea.Viewport, { ref: viewport, tabIndex: 0, "aria-roledescription": "carousel", "aria-label": label, onKeyDown: keys, className: slots.slidesViewport({
681
- className: snap
682
- ? 'min-h-[min(60dvh,32rem)] snap-y snap-mandatory [container-type:size]'
683
- : undefined,
685
+ className: snap ? 'min-h-[min(60dvh,32rem)] snap-y snap-mandatory [container-type:size]' : undefined,
684
686
  }), children: _jsx(ScrollArea.Content, { className: slots.slidesContent({ className: snap ? 'py-1.5' : 'gap-2 pb-3 pt-1' }), children: slides.map((slide, at) => (_jsx(SlideIndexContext.Provider, { value: at, children: slide }, at))) }) }), _jsx(ScrollArea.Scrollbar, { orientation: "vertical", className: slots.scrollbar(), children: _jsx(ScrollArea.Thumb, { className: slots.thumb() }) }), (counter ?? snap) && count > 1 ? (_jsxs("div", { "data-slot": "sheet-slides-counter", "aria-hidden": "true", className: slots.counter(), children: [current + 1, " / ", count] })) : null] }) }));
685
687
  }
686
688
  SheetSlides.displayName = 'Sheet.Slides';
687
689
  /** One slide: a rounded frame that fills with an image, a video or anything drawn. */
688
- function SheetSlide({ label, aspect, className, style, children, ...props }) {
690
+ function SheetSlide({ label, aspect, className, style, children, render, ...props }) {
689
691
  const slides = useContext(SlidesContext);
690
692
  if (!slides)
691
693
  throw new Error('Sheet.Slide must be used inside <Sheet.Slides>.');
@@ -715,7 +717,17 @@ function SheetSlide({ label, aspect, className, style, children, ...props }) {
715
717
  return (_jsx("div", { "data-slot": "sheet-slide", "data-slide-frame": "", "data-index": at, "data-current": selected ? '' : undefined, role: "group", "aria-roledescription": "slide", "aria-label": name, className: frameClass, style: frameStyle, ...props, children: children }));
716
718
  }
717
719
  const frame = (_jsx("div", { "data-slide-frame": "", "data-current": selected ? '' : undefined, className: frameClass, style: frameStyle, children: children }));
718
- return (_jsxs("div", { "data-slot": "sheet-slide", "data-index": at, "data-selected": selected ? '' : undefined, className: slots.slideRow(), ...props, children: [_jsx("span", { "aria-hidden": "true", className: slots.slideNumber({ className: selected ? 'text-[var(--info)]' : undefined }), children: at + 1 }), slides.pressable ? (_jsx("button", { type: "button", "aria-label": label ? name : `Slide ${place}`, "aria-current": selected ? 'true' : undefined, className: slots.slideButton(), onClick: () => slides.choose(at), children: frame })) : (_jsx("div", { role: "group", "aria-roledescription": "slide", "aria-label": name, children: frame }))] }));
720
+ return useRender({
721
+ defaultTagName: 'div',
722
+ render,
723
+ props: mergeProps({
724
+ 'data-slot': 'sheet-slide',
725
+ 'data-index': at,
726
+ 'data-selected': selected ? '' : undefined,
727
+ className: slots.slideRow(),
728
+ children: (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: slots.slideNumber({ className: selected ? 'text-[var(--info)]' : undefined }), children: at + 1 }), slides.pressable ? (_jsx("button", { type: "button", "aria-label": label ? name : `Slide ${place}`, "aria-current": selected ? 'true' : undefined, className: slots.slideButton(), onClick: () => slides.choose(at), children: frame })) : (_jsx("div", { role: "group", "aria-roledescription": "slide", "aria-label": name, children: frame }))] })),
729
+ }, props),
730
+ });
719
731
  }
720
732
  SheetSlide.displayName = 'Sheet.Slide';
721
733
  /**
@@ -37,6 +37,13 @@
37
37
  */
38
38
  import { Slider as BaseSlider } from '@base-ui/react/slider';
39
39
  import { type ComponentProps, type CSSProperties, 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
  export type SliderVariant = 'fill' | 'line';
41
48
  export type SliderSize = 'sm' | 'md' | 'lg';
42
49
  export type SliderColor = 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'destructive';
@@ -164,7 +171,7 @@ declare const sliderVariants: import("tailwind-variants").TVReturnType<{
164
171
  label: string;
165
172
  value: string;
166
173
  step: string[];
167
- }, import("tailwind-variants").TVReturnType<{
174
+ }, import("tailwind-variants").TVReturnTypeLike<{
168
175
  variant: {
169
176
  fill: {
170
177
  control: string;
@@ -226,7 +233,7 @@ declare const sliderVariants: import("tailwind-variants").TVReturnType<{
226
233
  label: string;
227
234
  value: string;
228
235
  step: string[];
229
- }, undefined, unknown, unknown, undefined>>;
236
+ }>>;
230
237
  type SliderValue = number | number[];
231
238
  export interface SliderProps<Value extends SliderValue = number> extends Omit<BaseSlider.Root.Props<Value>, 'className' | 'style' | 'format' | 'orientation' | 'children' | 'render' | 'onValueChange' | 'value' | 'defaultValue'> {
232
239
  /** The value, when the caller holds it. Two numbers make a range with two handles. */
@@ -268,7 +275,7 @@ export interface SliderProps<Value extends SliderValue = number> extends Omit<Ba
268
275
  * A slider. `defaultValue`, or `value` with `onValueChange`; `min`, `max`
269
276
  * and `step` as for any range.
270
277
  */
271
- declare function SliderRoot<Value extends SliderValue = number>({ value: valueProp, defaultValue, onValueChange, variant, label, format, origin, color, size, showValue, ticks, min, max, step, disabled, locale, children, className, style, ...props }: SliderProps<Value>): import("react").JSX.Element;
278
+ declare function SliderRoot<Value extends SliderValue = number>({ value: valueProp, defaultValue, onValueChange, variant, label, format, origin, color, size, showValue, ticks, min, max, step, disabled, locale, children, className, style, ...props }: SliderProps<Value>): ReactTypes.JSX.Element;
272
279
  declare namespace SliderRoot {
273
280
  var displayName: string;
274
281
  }
@@ -283,7 +290,7 @@ export interface SliderStepProps extends Omit<ComponentProps<'button'>, 'childre
283
290
  * in on either side of a zoom slider. It is disabled at the end it moves
284
291
  * towards.
285
292
  */
286
- declare function SliderStep({ by, className, disabled, onClick, ...props }: SliderStepProps): import("react").JSX.Element;
293
+ declare function SliderStep({ by, className, disabled, onClick, render, ...props }: SliderStepProps & RenderProp<'button'>): ReactTypes.ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
287
294
  declare namespace SliderStep {
288
295
  var displayName: string;
289
296
  }
@@ -40,6 +40,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
40
40
  import { Slider as BaseSlider } from '@base-ui/react/slider';
41
41
  import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, } 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
  /** A glide with a little overshoot, for a press. A drag turns it off. */
44
46
  const GLIDE = 'duration-[420ms] ease-[cubic-bezier(0.3,1.3,0.45,1)]';
45
47
  /** How far the track gives past an end, at most, in pixels. */
@@ -119,11 +121,19 @@ const sliderVariants = tv({
119
121
  },
120
122
  },
121
123
  color: {
122
- neutral: { root: '[--slider-fill:color-mix(in_oklab,var(--foreground)_11%,transparent)] [--slider-mark:var(--foreground)]' },
123
- primary: { root: '[--slider-fill:color-mix(in_oklab,var(--primary)_24%,transparent)] [--slider-mark:var(--primary)]' },
124
+ neutral: {
125
+ root: '[--slider-fill:color-mix(in_oklab,var(--foreground)_11%,transparent)] [--slider-mark:var(--foreground)]',
126
+ },
127
+ primary: {
128
+ root: '[--slider-fill:color-mix(in_oklab,var(--primary)_24%,transparent)] [--slider-mark:var(--primary)]',
129
+ },
124
130
  info: { root: '[--slider-fill:color-mix(in_oklab,var(--info)_26%,transparent)] [--slider-mark:var(--info)]' },
125
- success: { root: '[--slider-fill:color-mix(in_oklab,var(--success)_26%,transparent)] [--slider-mark:var(--success)]' },
126
- warning: { root: '[--slider-fill:color-mix(in_oklab,var(--warning)_28%,transparent)] [--slider-mark:var(--warning)]' },
131
+ success: {
132
+ root: '[--slider-fill:color-mix(in_oklab,var(--success)_26%,transparent)] [--slider-mark:var(--success)]',
133
+ },
134
+ warning: {
135
+ root: '[--slider-fill:color-mix(in_oklab,var(--warning)_28%,transparent)] [--slider-mark:var(--warning)]',
136
+ },
127
137
  destructive: {
128
138
  root: '[--slider-fill:color-mix(in_oklab,var(--destructive)_24%,transparent)] [--slider-mark:var(--destructive)]',
129
139
  },
@@ -323,17 +333,27 @@ function SliderSteps({ children }) {
323
333
  * in on either side of a zoom slider. It is disabled at the end it moves
324
334
  * towards.
325
335
  */
326
- function SliderStep({ by, className, disabled, onClick, ...props }) {
336
+ function SliderStep({ by, className, disabled, onClick, render, ...props }) {
327
337
  const slider = useContext(SliderContext);
328
338
  if (!slider)
329
339
  throw new Error('Slider.Step must be used inside a <Slider>.');
330
340
  const slots = sliderVariants();
331
341
  const stuck = by < 0 ? slider.atMin : slider.atMax;
332
- return (_jsx("button", { type: "button", "data-slot": "slider-step", disabled: disabled || slider.disabled || stuck, className: slots.step({ className }), onClick: (event) => {
333
- onClick?.(event);
334
- if (!event.defaultPrevented)
335
- slider.nudge(by);
336
- }, ...props }));
342
+ return useRender({
343
+ defaultTagName: 'button',
344
+ render,
345
+ props: mergeProps({
346
+ type: 'button',
347
+ 'data-slot': 'slider-step',
348
+ disabled: disabled || slider.disabled || stuck,
349
+ className: slots.step({ className }),
350
+ onClick: (event) => {
351
+ onClick?.(event);
352
+ if (!event.defaultPrevented)
353
+ slider.nudge(by);
354
+ },
355
+ }, props),
356
+ });
337
357
  }
338
358
  SliderStep.displayName = 'Slider.Step';
339
359
  export const Slider = Object.assign(SliderRoot, {
@@ -38,6 +38,12 @@
38
38
  * back gently instead of chattering on every sample.
39
39
  */
40
40
  import { type ComponentProps, type ReactNode, type RefObject } from 'react';
41
+ import { useRender } from '@base-ui/react/use-render';
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
+ };
41
47
  export type SoundwaveVariant = 'pills' | 'bars' | 'line' | 'ambient' | 'dots' | 'radial' | 'ring';
42
48
  export type SoundwaveState = 'idle' | 'listening' | 'thinking' | 'speaking';
43
49
  /** A role from the theme. The wave never carries a colour of its own. */
@@ -126,7 +132,7 @@ export interface SoundwaveProps extends Omit<ComponentProps<'div'>, 'color' | 'c
126
132
  children?: ReactNode;
127
133
  }
128
134
  /** A voice as a wave. Draws a `level` it is handed, or runs its own motion for `state`. */
129
- declare function SoundwaveRoot({ variant, state, level: levelProp, source, levels, progress, bars, barWidth, barGap, height, mode, centered, fadeEdges, sensitivity, speed, color, gradient, trackColor, paused, label, className, style, children, ...props }: SoundwaveProps): import("react").JSX.Element;
135
+ declare function SoundwaveRoot({ variant, state, level: levelProp, source, levels, progress, bars, barWidth, barGap, height, mode, centered, fadeEdges, sensitivity, speed, color, gradient, trackColor, paused, label, className, style, children, render, ...props }: SoundwaveProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
130
136
  declare namespace SoundwaveRoot {
131
137
  var displayName: string;
132
138
  }
@@ -136,7 +142,7 @@ export interface SoundwaveCenterProps extends ComponentProps<'div'> {
136
142
  * What sits in the hole of a `radial` or `ring` wave: a person's avatar, a
137
143
  * figure, a button. It is sized to the hole and centred in it.
138
144
  */
139
- declare function SoundwaveCenter({ className, ...props }: SoundwaveCenterProps): import("react").JSX.Element;
145
+ declare function SoundwaveCenter({ className, render, ...props }: SoundwaveCenterProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
140
146
  declare namespace SoundwaveCenter {
141
147
  var displayName: string;
142
148
  }
@@ -41,6 +41,8 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
41
41
  */
42
42
  import { useEffect, useId, useLayoutEffect, useRef, useState, useSyncExternalStore, } 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
  /** What each state is doing, for anyone who cannot see it. */
45
47
  const STATE_LABEL = {
46
48
  idle: 'Idle',
@@ -402,7 +404,7 @@ const soundwaveVariants = tv({
402
404
  },
403
405
  });
404
406
  /** A voice as a wave. Draws a `level` it is handed, or runs its own motion for `state`. */
405
- function SoundwaveRoot({ variant = 'pills', state = 'listening', level: levelProp, source, levels, progress, bars, barWidth, barGap, height, mode = 'static', centered = true, fadeEdges = false, sensitivity = 1, speed = 1, color, gradient, trackColor, paused = false, label, className, style, children, ...props }) {
407
+ function SoundwaveRoot({ variant = 'pills', state = 'listening', level: levelProp, source, levels, progress, bars, barWidth, barGap, height, mode = 'static', centered = true, fadeEdges = false, sensitivity = 1, speed = 1, color, gradient, trackColor, paused = false, label, className, style, children, render, ...props }) {
406
408
  const sourceLevel = useAudioLevel(source);
407
409
  const level = source ? sourceLevel : levelProp;
408
410
  const defaults = DEFAULTS[variant];
@@ -571,17 +573,35 @@ function SoundwaveRoot({ variant = 'pills', state = 'listening', level: levelPro
571
573
  const layer = (key, extra = {}) => (_jsx("path", { ref: (node) => {
572
574
  layers.current[key] = node;
573
575
  }, d: painted[key] ?? '', fill: "none", stroke: extra.stroke ?? stroke, strokeOpacity: extra.opacity, strokeWidth: extra.strokeWidth ?? w, strokeLinecap: "round", strokeLinejoin: "round" }));
574
- return (_jsx("div", { ref: root, role: "img", "aria-label": label ?? STATE_LABEL[state], "data-slot": "soundwave", "data-variant": variant, "data-state": state, className: slots.root({ className }), style: rootStyle, ...props, children: variant === 'ambient' ? (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", className: slots.bloom() }), _jsx("div", { "aria-hidden": "true", className: slots.rim() })] })) : (_jsxs(_Fragment, { children: [variant === 'radial' ? (_jsx("div", { ref: glow, "aria-hidden": "true", className: slots.glow(), style: { opacity: 0.25 + (painted.glow ?? 0) * 0.75 } })) : null, width > 0 ? (_jsxs("svg", { "aria-hidden": "true", width: width, height: h, viewBox: `0 0 ${width} ${h}`, className: slots.svg(), children: [gradient?.length ? (_jsx("defs", { children: _jsx("linearGradient", { id: gradientId, x1: "0", x2: "1", y1: "0", y2: "0", children: gradient.map((role, index) => (_jsx("stop", { offset: gradient.length === 1 ? 0 : index / (gradient.length - 1), style: { stopColor: COLOR_VAR[role] } }, `${role}-${index}`))) }) })) : null, variant === 'dots' || variant === 'ring' ? layer('track', { stroke: track }) : null, variant === 'radial' ? (_jsx("circle", { cx: h / 2, cy: h / 2, r: h * HOLE, fill: "none", stroke: "currentColor", strokeOpacity: 0.22, strokeWidth: 1.5 })) : null, variant === 'radial' ? layer('tip', { opacity: 0.42 }) : null, variant === 'dots' || variant === 'ring' ? layer('edge', { opacity: 0.45 }) : null, variant === 'bars' || variant === 'dots'
575
- ? layer('rest', trackColor && variant === 'bars' ? { stroke: track } : { opacity: UNPLAYED })
576
- : null, layer('ink')] })) : null, children] })) }));
576
+ return useRender({
577
+ defaultTagName: 'div',
578
+ render,
579
+ props: mergeProps({
580
+ ref: root,
581
+ role: 'img',
582
+ 'aria-label': label ?? STATE_LABEL[state],
583
+ 'data-slot': 'soundwave',
584
+ 'data-variant': variant,
585
+ 'data-state': state,
586
+ className: slots.root({ className }),
587
+ style: rootStyle,
588
+ children: (_jsx(_Fragment, { children: variant === 'ambient' ? (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", className: slots.bloom() }), _jsx("div", { "aria-hidden": "true", className: slots.rim() })] })) : (_jsxs(_Fragment, { children: [variant === 'radial' ? (_jsx("div", { ref: glow, "aria-hidden": "true", className: slots.glow(), style: { opacity: 0.25 + (painted.glow ?? 0) * 0.75 } })) : null, width > 0 ? (_jsxs("svg", { "aria-hidden": "true", width: width, height: h, viewBox: `0 0 ${width} ${h}`, className: slots.svg(), children: [gradient?.length ? (_jsx("defs", { children: _jsx("linearGradient", { id: gradientId, x1: "0", x2: "1", y1: "0", y2: "0", children: gradient.map((role, index) => (_jsx("stop", { offset: gradient.length === 1 ? 0 : index / (gradient.length - 1), style: { stopColor: COLOR_VAR[role] } }, `${role}-${index}`))) }) })) : null, variant === 'dots' || variant === 'ring' ? layer('track', { stroke: track }) : null, variant === 'radial' ? (_jsx("circle", { cx: h / 2, cy: h / 2, r: h * HOLE, fill: "none", stroke: "currentColor", strokeOpacity: 0.22, strokeWidth: 1.5 })) : null, variant === 'radial' ? layer('tip', { opacity: 0.42 }) : null, variant === 'dots' || variant === 'ring' ? layer('edge', { opacity: 0.45 }) : null, variant === 'bars' || variant === 'dots'
589
+ ? layer('rest', trackColor && variant === 'bars' ? { stroke: track } : { opacity: UNPLAYED })
590
+ : null, layer('ink')] })) : null, children] })) })),
591
+ }, props),
592
+ });
577
593
  }
578
594
  SoundwaveRoot.displayName = 'Soundwave';
579
595
  /**
580
596
  * What sits in the hole of a `radial` or `ring` wave: a person's avatar, a
581
597
  * figure, a button. It is sized to the hole and centred in it.
582
598
  */
583
- function SoundwaveCenter({ className, ...props }) {
584
- return _jsx("div", { "data-slot": "soundwave-center", className: soundwaveVariants().center({ className }), ...props });
599
+ function SoundwaveCenter({ className, render, ...props }) {
600
+ return useRender({
601
+ defaultTagName: 'div',
602
+ render,
603
+ props: mergeProps({ 'data-slot': 'soundwave-center', className: soundwaveVariants().center({ className }) }, props),
604
+ });
585
605
  }
586
606
  SoundwaveCenter.displayName = 'Soundwave.Center';
587
607
  export const Soundwave = Object.assign(SoundwaveRoot, { Center: SoundwaveCenter });
@@ -38,17 +38,23 @@
38
38
  * done in CSS from data attributes, so a Server Component can render it.
39
39
  */
40
40
  import type { ComponentProps } from 'react';
41
+ import { useRender } from '@base-ui/react/use-render';
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
+ };
41
47
  export interface StatProps extends ComponentProps<'div'> {
42
48
  }
43
49
  /** A row: the label and value on the leading side, a badge on the trailing one. */
44
- declare function StatRoot({ className, ...props }: StatProps): import("react").JSX.Element;
50
+ declare function StatRoot({ className, render, ...props }: StatProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
45
51
  declare namespace StatRoot {
46
52
  var displayName: string;
47
53
  }
48
54
  export interface StatContentProps extends ComponentProps<'div'> {
49
55
  }
50
56
  /** The label and the value, stacked. Used on its own when there is no badge. */
51
- declare function StatContent({ className, ...props }: StatContentProps): import("react").JSX.Element;
57
+ declare function StatContent({ className, render, ...props }: StatContentProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
52
58
  declare namespace StatContent {
53
59
  var displayName: string;
54
60
  }
@@ -61,14 +67,14 @@ export interface StatLabelProps extends ComponentProps<'p'> {
61
67
  weight?: 'normal' | 'medium';
62
68
  }
63
69
  /** What is measured, in a quiet line over the value. */
64
- declare function StatLabel({ weight, className, ...props }: StatLabelProps): import("react").JSX.Element;
70
+ declare function StatLabel({ weight, className, render, ...props }: StatLabelProps & RenderProp<'p'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
65
71
  declare namespace StatLabel {
66
72
  var displayName: string;
67
73
  }
68
74
  export interface StatDescriptionProps extends ComponentProps<'p'> {
69
75
  }
70
76
  /** What the reading means, in words: "Answering slowly". Written under the label. */
71
- declare function StatDescription({ className, ...props }: StatDescriptionProps): import("react").JSX.Element;
77
+ declare function StatDescription({ className, render, ...props }: StatDescriptionProps & RenderProp<'p'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
72
78
  declare namespace StatDescription {
73
79
  var displayName: string;
74
80
  }
@@ -77,21 +83,21 @@ export interface StatValueProps extends ComponentProps<'p'> {
77
83
  size?: 'sm' | 'md' | 'lg';
78
84
  }
79
85
  /** The figure. Put a `Stat.Unit` inside it, after the number. */
80
- declare function StatValue({ size, className, ...props }: StatValueProps): import("react").JSX.Element;
86
+ declare function StatValue({ size, className, render, ...props }: StatValueProps & RenderProp<'p'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
81
87
  declare namespace StatValue {
82
88
  var displayName: string;
83
89
  }
84
90
  export interface StatUnitProps extends ComponentProps<'span'> {
85
91
  }
86
92
  /** The unit after the number, smaller and quieter, sized from the value it is in. */
87
- declare function StatUnit({ className, ...props }: StatUnitProps): import("react").JSX.Element;
93
+ declare function StatUnit({ className, render, ...props }: StatUnitProps & RenderProp<'span'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
88
94
  declare namespace StatUnit {
89
95
  var displayName: string;
90
96
  }
91
97
  export interface StatBadgeProps extends ComponentProps<'span'> {
92
98
  }
93
99
  /** How the reading stands, in a pill on the row's trailing side. */
94
- declare function StatBadge({ className, ...props }: StatBadgeProps): import("react").JSX.Element;
100
+ declare function StatBadge({ className, render, ...props }: StatBadgeProps & RenderProp<'span'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
95
101
  declare namespace StatBadge {
96
102
  var displayName: string;
97
103
  }
@@ -1,5 +1,7 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ 'use client';
2
2
  import { tv } from 'tailwind-variants';
3
+ import { mergeProps } from '@base-ui/react/merge-props';
4
+ import { useRender } from '@base-ui/react/use-render';
3
5
  const statVariants = tv({
4
6
  slots: {
5
7
  root: 'flex items-end justify-between gap-4',
@@ -27,38 +29,66 @@ const statVariants = tv({
27
29
  },
28
30
  });
29
31
  /** A row: the label and value on the leading side, a badge on the trailing one. */
30
- function StatRoot({ className, ...props }) {
31
- return _jsx("div", { "data-slot": "stat", className: statVariants().root({ className }), ...props });
32
+ function StatRoot({ className, render, ...props }) {
33
+ return useRender({
34
+ defaultTagName: 'div',
35
+ render,
36
+ props: mergeProps({ 'data-slot': 'stat', className: statVariants().root({ className }) }, props),
37
+ });
32
38
  }
33
39
  StatRoot.displayName = 'Stat';
34
40
  /** The label and the value, stacked. Used on its own when there is no badge. */
35
- function StatContent({ className, ...props }) {
36
- return _jsx("div", { "data-slot": "stat-content", className: statVariants().content({ className }), ...props });
41
+ function StatContent({ className, render, ...props }) {
42
+ return useRender({
43
+ defaultTagName: 'div',
44
+ render,
45
+ props: mergeProps({ 'data-slot': 'stat-content', className: statVariants().content({ className }) }, props),
46
+ });
37
47
  }
38
48
  StatContent.displayName = 'Stat.Content';
39
49
  /** What is measured, in a quiet line over the value. */
40
- function StatLabel({ weight = 'normal', className, ...props }) {
41
- return _jsx("p", { "data-slot": "stat-label", className: statVariants({ weight }).label({ className }), ...props });
50
+ function StatLabel({ weight = 'normal', className, render, ...props }) {
51
+ return useRender({
52
+ defaultTagName: 'p',
53
+ render,
54
+ props: mergeProps({ 'data-slot': 'stat-label', className: statVariants({ weight }).label({ className }) }, props),
55
+ });
42
56
  }
43
57
  StatLabel.displayName = 'Stat.Label';
44
58
  /** What the reading means, in words: "Answering slowly". Written under the label. */
45
- function StatDescription({ className, ...props }) {
46
- return (_jsx("p", { "data-slot": "stat-description", className: statVariants().description({ className }), ...props }));
59
+ function StatDescription({ className, render, ...props }) {
60
+ return useRender({
61
+ defaultTagName: 'p',
62
+ render,
63
+ props: mergeProps({ 'data-slot': 'stat-description', className: statVariants().description({ className }) }, props),
64
+ });
47
65
  }
48
66
  StatDescription.displayName = 'Stat.Description';
49
67
  /** The figure. Put a `Stat.Unit` inside it, after the number. */
50
- function StatValue({ size = 'lg', className, ...props }) {
51
- return (_jsx("p", { "data-slot": "stat-value", "data-size": size, className: statVariants({ size }).value({ className }), ...props }));
68
+ function StatValue({ size = 'lg', className, render, ...props }) {
69
+ return useRender({
70
+ defaultTagName: 'p',
71
+ render,
72
+ props: mergeProps({ 'data-slot': 'stat-value', 'data-size': size, className: statVariants({ size }).value({ className }) }, props),
73
+ });
52
74
  }
53
75
  StatValue.displayName = 'Stat.Value';
54
76
  /** The unit after the number, smaller and quieter, sized from the value it is in. */
55
- function StatUnit({ className, ...props }) {
56
- return _jsx("span", { "data-slot": "stat-unit", className: statVariants().unit({ className }), ...props });
77
+ function StatUnit({ className, render, ...props }) {
78
+ return useRender({
79
+ defaultTagName: 'span',
80
+ render,
81
+ props: mergeProps({ 'data-slot': 'stat-unit', className: statVariants().unit({ className }) }, props),
82
+ });
57
83
  }
58
84
  StatUnit.displayName = 'Stat.Unit';
59
85
  /** How the reading stands, in a pill on the row's trailing side. */
60
- function StatBadge({ className, ...props }) {
61
- return _jsx("span", { "data-slot": "stat-badge", className: statVariants().badge({ className }), ...props });
86
+ function StatBadge({ className, render, ...props }) {
87
+ return useRender({
88
+ defaultTagName: 'span',
89
+ render,
90
+ props: mergeProps({ 'data-slot': 'stat-badge', className: statVariants().badge({ className }) }, props),
91
+ });
62
92
  }
63
93
  StatBadge.displayName = 'Stat.Badge';
64
94
  export const Stat = Object.assign(StatRoot, {
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Table — rows of records with the same columns, to be read across and compared down.
3
+ *
4
+ * ```tsx
5
+ * <Table>
6
+ * <Table.Header>
7
+ * <Table.Row>
8
+ * <Table.Head>Invoice</Table.Head>
9
+ * <Table.Head align="end">Amount</Table.Head>
10
+ * </Table.Row>
11
+ * </Table.Header>
12
+ * <Table.Body>
13
+ * <Table.Row>
14
+ * <Table.Cell>INV-2041</Table.Cell>
15
+ * <Table.Cell align="end">£1,280.00</Table.Cell>
16
+ * </Table.Row>
17
+ * </Table.Body>
18
+ * </Table>
19
+ * ```
20
+ *
21
+ * ## Numbers line up
22
+ *
23
+ * `align="end"` on a column's head and cells right-aligns it and switches the
24
+ * digits to equal widths, so a column of amounts lines up on its last digit
25
+ * and can be compared at a glance. Text columns stay at the start.
26
+ *
27
+ * ## It scrolls inside itself
28
+ *
29
+ * A table wider than the page scrolls sideways inside its own box, so the
30
+ * page around it does not. Give the table a `maxHeight` and the body scrolls
31
+ * too, with the header row pinned above it.
32
+ *
33
+ * ## Density
34
+ *
35
+ * `density="compact"` tightens the rows for a dense admin screen; the
36
+ * default leaves room for a second line of muted text in a cell.
37
+ * `striped` shades every other row, which helps a reader keep their place
38
+ * across a wide row with nothing in the middle of it.
39
+ *
40
+ * Every part is the native table element, so a screen reader announces the
41
+ * row and column of each cell. For data that is a list of things rather than
42
+ * a grid of values, Frame's rows read better.
43
+ */
44
+ import type { ComponentProps, CSSProperties } from 'react';
45
+ import { useRender } from '@base-ui/react/use-render';
46
+ import type { ElementType as RenderElementType } from 'react';
47
+ /** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
48
+ type RenderProp<Tag extends RenderElementType> = {
49
+ render?: useRender.ComponentProps<Tag>['render'];
50
+ };
51
+ export type TableDensity = 'comfortable' | 'compact';
52
+ export type TableAlign = 'start' | 'center' | 'end';
53
+ export interface TableProps extends ComponentProps<'table'> {
54
+ /** Row height. `compact` for a dense screen. Default `comfortable`. */
55
+ density?: TableDensity;
56
+ /** Shades every other body row. */
57
+ striped?: boolean;
58
+ /**
59
+ * Draws the cells clear of the edges, for a table set inside a Card or
60
+ * Frame panel, whose edge the first and last columns would otherwise touch.
61
+ */
62
+ framed?: boolean;
63
+ /**
64
+ * The tallest the table gets before its body scrolls, with the header
65
+ * pinned above. Any CSS length.
66
+ */
67
+ maxHeight?: CSSProperties['maxHeight'];
68
+ /** Classes for the scrolling box around the table, rather than the table. */
69
+ containerClassName?: string;
70
+ }
71
+ /** The table, in a box that scrolls when the table is wider or taller than it. */
72
+ declare function TableRoot({ density, striped, framed, maxHeight, containerClassName, className, render, ...props }: TableProps & RenderProp<'table'>): import("react").JSX.Element;
73
+ declare namespace TableRoot {
74
+ var displayName: string;
75
+ }
76
+ /** The header row group. Pinned while the body scrolls, when the table has a `maxHeight`. */
77
+ declare function TableHeader({ className, render, ...props }: ComponentProps<'thead'> & RenderProp<'thead'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
78
+ declare namespace TableHeader {
79
+ var displayName: string;
80
+ }
81
+ /** The rows of data. */
82
+ declare function TableBody({ className, render, ...props }: ComponentProps<'tbody'> & RenderProp<'tbody'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
83
+ declare namespace TableBody {
84
+ var displayName: string;
85
+ }
86
+ /** Totals under the body. */
87
+ declare function TableFooter({ className, render, ...props }: ComponentProps<'tfoot'> & RenderProp<'tfoot'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
88
+ declare namespace TableFooter {
89
+ var displayName: string;
90
+ }
91
+ /** One row. `aria-selected` shades it as chosen. */
92
+ declare function TableRow({ className, render, ...props }: ComponentProps<'tr'> & RenderProp<'tr'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
93
+ declare namespace TableRow {
94
+ var displayName: string;
95
+ }
96
+ export interface TableHeadProps extends Omit<ComponentProps<'th'>, 'align'> {
97
+ /** Where the column's content sits. `end` for numbers. Default `start`. */
98
+ align?: TableAlign;
99
+ }
100
+ /** A column's heading. */
101
+ declare function TableHead({ align, className, render, ...props }: TableHeadProps & RenderProp<'th'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
102
+ declare namespace TableHead {
103
+ var displayName: string;
104
+ }
105
+ export interface TableCellProps extends Omit<ComponentProps<'td'>, 'align'> {
106
+ /** Where the content sits. Match the column's head. `end` also gives the digits equal widths. Default `start`. */
107
+ align?: TableAlign;
108
+ }
109
+ /** One cell. */
110
+ declare function TableCell({ align, className, render, ...props }: TableCellProps & RenderProp<'td'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
111
+ declare namespace TableCell {
112
+ var displayName: string;
113
+ }
114
+ /** What the table is, under it. Read first by a screen reader. */
115
+ declare function TableCaption({ className, render, ...props }: ComponentProps<'caption'> & RenderProp<'caption'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
116
+ declare namespace TableCaption {
117
+ var displayName: string;
118
+ }
119
+ export declare const Table: typeof TableRoot & {
120
+ Header: typeof TableHeader;
121
+ Body: typeof TableBody;
122
+ Footer: typeof TableFooter;
123
+ Row: typeof TableRow;
124
+ Head: typeof TableHead;
125
+ Cell: typeof TableCell;
126
+ Caption: typeof TableCaption;
127
+ };
128
+ export { TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption };