panelui-web 0.10.0 → 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 +84 -25
  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
@@ -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
  * LaneBoard — lanes side by side, each holding cards that can be dragged
5
5
  * within a lane and from one lane to another.
@@ -46,6 +46,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
46
46
  import { ScrollArea } from '@base-ui/react/scroll-area';
47
47
  import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react';
48
48
  import { tv } from 'tailwind-variants';
49
+ import { mergeProps } from '@base-ui/react/merge-props';
50
+ import { useRender } from '@base-ui/react/use-render';
49
51
  const laneBoardVariants = tv({
50
52
  slots: {
51
53
  root: 'relative w-full',
@@ -186,7 +188,7 @@ function whereIs(lanes, id) {
186
188
  }
187
189
  return null;
188
190
  }
189
- function LaneBoardRoot({ lanes: controlled, defaultLanes, onLanesChange, onMove, renderCard, renderLaneFooter, cardName = (card) => card.id, label = 'Board', height = '28rem', className, style, ...props }) {
191
+ function LaneBoardRoot({ lanes: controlled, defaultLanes, onLanesChange, onMove, renderCard, renderLaneFooter, cardName = (card) => card.id, label = 'Board', height = '28rem', className, style, render, ...props }) {
190
192
  const slots = laneBoardVariants();
191
193
  const [internal, setInternal] = useState(defaultLanes ?? []);
192
194
  const settled = controlled ?? internal;
@@ -605,83 +607,121 @@ function LaneBoardRoot({ lanes: controlled, defaultLanes, onLanesChange, onMove,
605
607
  });
606
608
  const carried = carry ? whereIs(shown, carry.id) : null;
607
609
  const carriedLane = carried ? shown.find((lane) => lane.id === carried.lane) : undefined;
608
- return (_jsxs("div", { ref: root, role: "group", "aria-label": label, className: slots.root({ className }), style: { height: height === 'auto' ? undefined : height, ...style }, ...props, children: [_jsxs(ScrollArea.Root, { className: slots.board(), children: [_jsx(ScrollArea.Viewport, { ref: scroller, className: slots.boardViewport(), children: _jsx("div", { className: slots.lanes(), children: shown.map((lane) => (_jsxs("section", { ref: (node) => {
609
- if (node)
610
- sections.current.set(lane.id, node);
611
- else
612
- sections.current.delete(lane.id);
613
- }, "aria-label": typeof lane.title === 'string' ? lane.title : undefined, "data-over": carried?.lane === lane.id ? '' : undefined, className: laneBoardVariants({ over: carried?.lane === lane.id }).lane(), children: [_jsxs("header", { className: slots.laneHeader(), children: [_jsxs("div", { className: slots.laneHeading(), children: [lane.color ? (_jsx("span", { "aria-hidden": "true", className: laneBoardVariants({ color: lane.color }).laneDot() })) : null, _jsx("h3", { className: slots.laneTitle(), children: lane.title })] }), _jsx("span", { className: laneBoardVariants({
614
- full: lane.limit !== undefined && lane.cards.length > lane.limit,
615
- }).laneCount(), children: lane.limit === undefined
616
- ? lane.cards.length
617
- : `${lane.cards.length}/${lane.limit}` })] }), _jsxs(ScrollArea.Root, { className: slots.laneScroller(), children: [_jsx(ScrollArea.Viewport, { ref: (node) => {
618
- if (node)
619
- viewports.current.set(lane.id, node);
620
- else
621
- viewports.current.delete(lane.id);
622
- }, className: slots.laneViewport(), children: _jsx("ol", { className: slots.list(), children: lane.cards.map((card) => {
623
- const isCarried = carry?.id === card.id;
624
- const state = !isCarried
625
- ? 'rest'
626
- : carry.by === 'pointer'
627
- ? 'placeholder'
628
- : 'held';
629
- return (_jsx("li", { ref: (node) => {
630
- if (node)
631
- cards.current.set(card.id, node);
632
- else
633
- cards.current.delete(card.id);
634
- }, tabIndex: 0, "aria-roledescription": "Card that can be moved", "aria-label": cardName(card), "data-card": card.id, "data-carried": isCarried ? carry.by : undefined, className: laneBoardVariants({ state }).card(), onPointerDown: (event) => onPointerDown(event, card.id), onKeyDown: (event) => onKeyDown(event, card), onBlur: () => {
635
- // Focus leaving a card held with the keyboard puts it
636
- // back: nothing is steering it any more.
637
- if (carry?.by === 'keys' &&
638
- carry.id === card.id &&
639
- !cards.current.get(card.id)?.matches(':focus')) {
640
- requestAnimationFrame(() => {
641
- if (document.activeElement !== cards.current.get(card.id)) {
642
- setDraft(null);
643
- setCarry(null);
610
+ return useRender({
611
+ defaultTagName: 'div',
612
+ render,
613
+ props: mergeProps({
614
+ ref: root,
615
+ role: 'group',
616
+ 'aria-label': label,
617
+ className: slots.root({ className }),
618
+ style: { height: height === 'auto' ? undefined : height, ...style },
619
+ children: (_jsxs(_Fragment, { children: [_jsxs(ScrollArea.Root, { className: slots.board(), children: [_jsx(ScrollArea.Viewport, { ref: scroller, className: slots.boardViewport(), children: _jsx("div", { className: slots.lanes(), children: shown.map((lane) => (_jsxs("section", { ref: (node) => {
620
+ if (node)
621
+ sections.current.set(lane.id, node);
622
+ else
623
+ sections.current.delete(lane.id);
624
+ }, "aria-label": typeof lane.title === 'string' ? lane.title : undefined, "data-over": carried?.lane === lane.id ? '' : undefined, className: laneBoardVariants({ over: carried?.lane === lane.id }).lane(), children: [_jsxs("header", { className: slots.laneHeader(), children: [_jsxs("div", { className: slots.laneHeading(), children: [lane.color ? (_jsx("span", { "aria-hidden": "true", className: laneBoardVariants({ color: lane.color }).laneDot() })) : null, _jsx("h3", { className: slots.laneTitle(), children: lane.title })] }), _jsx("span", { className: laneBoardVariants({
625
+ full: lane.limit !== undefined && lane.cards.length > lane.limit,
626
+ }).laneCount(), children: lane.limit === undefined ? lane.cards.length : `${lane.cards.length}/${lane.limit}` })] }), _jsxs(ScrollArea.Root, { className: slots.laneScroller(), children: [_jsx(ScrollArea.Viewport, { ref: (node) => {
627
+ if (node)
628
+ viewports.current.set(lane.id, node);
629
+ else
630
+ viewports.current.delete(lane.id);
631
+ }, className: slots.laneViewport(), children: _jsx("ol", { className: slots.list(), children: lane.cards.map((card) => {
632
+ const isCarried = carry?.id === card.id;
633
+ const state = !isCarried ? 'rest' : carry.by === 'pointer' ? 'placeholder' : 'held';
634
+ return (_jsx("li", { ref: (node) => {
635
+ if (node)
636
+ cards.current.set(card.id, node);
637
+ else
638
+ cards.current.delete(card.id);
639
+ }, tabIndex: 0, "aria-roledescription": "Card that can be moved", "aria-label": cardName(card), "data-card": card.id, "data-carried": isCarried ? carry.by : undefined, className: laneBoardVariants({ state }).card(), onPointerDown: (event) => onPointerDown(event, card.id), onKeyDown: (event) => onKeyDown(event, card), onBlur: () => {
640
+ // Focus leaving a card held with the keyboard puts it
641
+ // back: nothing is steering it any more.
642
+ if (carry?.by === 'keys' &&
643
+ carry.id === card.id &&
644
+ !cards.current.get(card.id)?.matches(':focus')) {
645
+ requestAnimationFrame(() => {
646
+ if (document.activeElement !== cards.current.get(card.id)) {
647
+ setDraft(null);
648
+ setCarry(null);
649
+ }
650
+ });
644
651
  }
645
- });
646
- }
647
- }, children: renderCard(card, { lane, carried: isCarried }) }, card.id));
648
- }) }) }), _jsx(ScrollArea.Scrollbar, { orientation: "vertical", className: slots.scrollbar(), children: _jsx(ScrollArea.Thumb, { className: slots.thumb() }) })] }), _jsx("div", { className: slots.laneFooter(), children: renderLaneFooter?.(lane) })] }, lane.id))) }) }), _jsx(ScrollArea.Scrollbar, { orientation: "horizontal", className: slots.scrollbar(), children: _jsx(ScrollArea.Thumb, { className: slots.thumb() }) })] }), carry?.by === 'pointer' && carried && carriedLane ? (_jsx("div", { ref: overlay, "aria-hidden": "true", className: slots.overlay(), style: { width: drag.current?.width }, children: renderCard(carried.card, { lane: carriedLane, carried: true }) })) : null, _jsx("span", { "aria-live": "assertive", className: "sr-only", children: said })] }));
652
+ }, children: renderCard(card, { lane, carried: isCarried }) }, card.id));
653
+ }) }) }), _jsx(ScrollArea.Scrollbar, { orientation: "vertical", className: slots.scrollbar(), children: _jsx(ScrollArea.Thumb, { className: slots.thumb() }) })] }), _jsx("div", { className: slots.laneFooter(), children: renderLaneFooter?.(lane) })] }, lane.id))) }) }), _jsx(ScrollArea.Scrollbar, { orientation: "horizontal", className: slots.scrollbar(), children: _jsx(ScrollArea.Thumb, { className: slots.thumb() }) })] }), carry?.by === 'pointer' && carried && carriedLane ? (_jsx("div", { ref: overlay, "aria-hidden": "true", className: slots.overlay(), style: { width: drag.current?.width }, children: renderCard(carried.card, { lane: carriedLane, carried: true }) })) : null, _jsx("span", { "aria-live": "assertive", className: "sr-only", children: said })] })),
654
+ }, props),
655
+ });
649
656
  }
650
657
  LaneBoardRoot.displayName = 'LaneBoard';
651
658
  /** A card's name. */
652
- function LaneBoardTitle({ className, ...props }) {
653
- return _jsx("div", { className: laneBoardVariants().title({ className }), ...props });
659
+ function LaneBoardTitle({ className, render, ...props }) {
660
+ return useRender({
661
+ defaultTagName: 'div',
662
+ render,
663
+ props: mergeProps({ className: laneBoardVariants().title({ className }) }, props),
664
+ });
654
665
  }
655
666
  LaneBoardTitle.displayName = 'LaneBoard.Title';
656
667
  /** A card's reference, in a fixed-width face so a column of them lines up. */
657
- function LaneBoardCode({ className, ...props }) {
658
- return _jsx("div", { className: laneBoardVariants().code({ className }), ...props });
668
+ function LaneBoardCode({ className, render, ...props }) {
669
+ return useRender({
670
+ defaultTagName: 'div',
671
+ render,
672
+ props: mergeProps({ className: laneBoardVariants().code({ className }) }, props),
673
+ });
659
674
  }
660
675
  LaneBoardCode.displayName = 'LaneBoard.Code';
661
676
  /** The last line of a card: something at each end. */
662
- function LaneBoardRow({ className, ...props }) {
663
- return _jsx("div", { className: laneBoardVariants().row({ className }), ...props });
677
+ function LaneBoardRow({ className, render, ...props }) {
678
+ return useRender({
679
+ defaultTagName: 'div',
680
+ render,
681
+ props: mergeProps({ className: laneBoardVariants().row({ className }) }, props),
682
+ });
664
683
  }
665
684
  LaneBoardRow.displayName = 'LaneBoard.Row';
666
685
  /** How far along a card is, as a row of dashes with the done ones lit. */
667
- function LaneBoardSteps({ value, max = 5, color = 'primary', label = 'Progress', className, ...props }) {
686
+ function LaneBoardSteps({ value, max = 5, color = 'primary', label = 'Progress', className, render, ...props }) {
668
687
  const slots = laneBoardVariants({ color });
669
- return (_jsx("div", { role: "img", "aria-label": `${label}: ${value} of ${max}`, className: slots.steps({ className }), ...props, children: Array.from({ length: max }, (_, index) => (_jsx("span", { className: laneBoardVariants({ lit: index < value }).step() }, index))) }));
688
+ return useRender({
689
+ defaultTagName: 'div',
690
+ render,
691
+ props: mergeProps({
692
+ role: 'img',
693
+ 'aria-label': `${label}: ${value} of ${max}`,
694
+ className: slots.steps({ className }),
695
+ children: (_jsx(_Fragment, { children: Array.from({ length: max }, (_, index) => (_jsx("span", { className: laneBoardVariants({ lit: index < value }).step() }, index))) })),
696
+ }, props),
697
+ });
670
698
  }
671
699
  LaneBoardSteps.displayName = 'LaneBoard.Steps';
672
700
  /** A word in a pill, for a card's state. */
673
- function LaneBoardTag({ color = 'primary', className, ...props }) {
674
- return _jsx("span", { className: laneBoardVariants({ color }).tag({ className }), ...props });
701
+ function LaneBoardTag({ color = 'primary', className, render, ...props }) {
702
+ return useRender({
703
+ defaultTagName: 'span',
704
+ render,
705
+ props: mergeProps({ className: laneBoardVariants({ color }).tag({ className }) }, props),
706
+ });
675
707
  }
676
708
  LaneBoardTag.displayName = 'LaneBoard.Tag';
677
709
  /** A short figure at the end of a card's last line: a time, a count. */
678
- function LaneBoardMeta({ className, ...props }) {
679
- return _jsx("span", { className: laneBoardVariants().meta({ className }), ...props });
710
+ function LaneBoardMeta({ className, render, ...props }) {
711
+ return useRender({
712
+ defaultTagName: 'span',
713
+ render,
714
+ props: mergeProps({ className: laneBoardVariants().meta({ className }) }, props),
715
+ });
680
716
  }
681
717
  LaneBoardMeta.displayName = 'LaneBoard.Meta';
682
718
  /** Who a card belongs to, as initials in a small circle. */
683
- function LaneBoardAvatar({ className, ...props }) {
684
- return _jsx("span", { "data-slot": "lane-board-avatar", className: laneBoardVariants().avatar({ className }), ...props });
719
+ function LaneBoardAvatar({ className, render, ...props }) {
720
+ return useRender({
721
+ defaultTagName: 'span',
722
+ render,
723
+ props: mergeProps({ 'data-slot': 'lane-board-avatar', className: laneBoardVariants().avatar({ className }) }, props),
724
+ });
685
725
  }
686
726
  LaneBoardAvatar.displayName = 'LaneBoard.Avatar';
687
727
  export const LaneBoard = Object.assign(LaneBoardRoot, {
@@ -695,4 +735,4 @@ export const LaneBoard = Object.assign(LaneBoardRoot, {
695
735
  });
696
736
  /* By name as well, for a Server Component, which cannot dot into a client
697
737
  module. */
698
- export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar, };
738
+ export { LaneBoardTitle, LaneBoardCode, LaneBoardRow, LaneBoardSteps, LaneBoardTag, LaneBoardMeta, LaneBoardAvatar };
@@ -42,6 +42,12 @@
42
42
  */
43
43
  import { Menu as BaseMenu } from '@base-ui/react/menu';
44
44
  import type { ComponentProps, ReactNode } 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
+ };
45
51
  export interface MenuProps extends BaseMenu.Root.Props {
46
52
  }
47
53
  /** Holds whether the menu is open. Takes `open`/`onOpenChange`, `defaultOpen` and `modal`. */
@@ -157,28 +163,28 @@ declare namespace MenuGroupLabel {
157
163
  export interface MenuSeparatorProps extends ComponentProps<'div'> {
158
164
  }
159
165
  /** A rule between groups of items. */
160
- declare function MenuSeparator({ className, ...props }: MenuSeparatorProps): import("react").JSX.Element;
166
+ declare function MenuSeparator({ className, render, ...props }: MenuSeparatorProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
161
167
  declare namespace MenuSeparator {
162
168
  var displayName: string;
163
169
  }
164
170
  export interface MenuDescriptionProps extends ComponentProps<'span'> {
165
171
  }
166
172
  /** What an item does, in quieter words after its label. */
167
- declare function MenuDescription({ className, ...props }: MenuDescriptionProps): import("react").JSX.Element;
173
+ declare function MenuDescription({ className, render, ...props }: MenuDescriptionProps & RenderProp<'span'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
168
174
  declare namespace MenuDescription {
169
175
  var displayName: string;
170
176
  }
171
177
  export interface MenuShortcutProps extends ComponentProps<'kbd'> {
172
178
  }
173
179
  /** The keys for an item, at its end. It only shows them: wire the keys up where the action lives. */
174
- declare function MenuShortcut({ className, ...props }: MenuShortcutProps): import("react").JSX.Element;
180
+ declare function MenuShortcut({ className, render, ...props }: MenuShortcutProps & RenderProp<'kbd'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
175
181
  declare namespace MenuShortcut {
176
182
  var displayName: string;
177
183
  }
178
184
  export interface MenuBadgeProps extends ComponentProps<'span'> {
179
185
  }
180
186
  /** A small count or flag at an item's end: how many need attention, or that something is new. */
181
- declare function MenuBadge({ className, ...props }: MenuBadgeProps): import("react").JSX.Element;
187
+ declare function MenuBadge({ className, render, ...props }: MenuBadgeProps & RenderProp<'span'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
182
188
  declare namespace MenuBadge {
183
189
  var displayName: string;
184
190
  }
@@ -44,6 +44,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
44
44
  */
45
45
  import { Menu as BaseMenu } from '@base-ui/react/menu';
46
46
  import { tv } from 'tailwind-variants';
47
+ import { mergeProps } from '@base-ui/react/merge-props';
48
+ import { useRender } from '@base-ui/react/use-render';
47
49
  const menuVariants = tv({
48
50
  slots: {
49
51
  positioner: 'z-50 outline-none',
@@ -113,7 +115,7 @@ function MenuCheckboxItem({ className, children, ...props }) {
113
115
  MenuCheckboxItem.displayName = 'Menu.CheckboxItem';
114
116
  /** Radio items of which one is chosen. Takes `value` and `onValueChange`. */
115
117
  function MenuRadioGroup({ className, ...props }) {
116
- return _jsx(BaseMenu.RadioGroup, { "data-slot": "menu-radio-group", className: menuVariants().group({ className }), ...props });
118
+ return (_jsx(BaseMenu.RadioGroup, { "data-slot": "menu-radio-group", className: menuVariants().group({ className }), ...props }));
117
119
  }
118
120
  MenuRadioGroup.displayName = 'Menu.RadioGroup';
119
121
  /** One choice in a radio group, with a check at its end while chosen. */
@@ -145,27 +147,43 @@ function MenuGroup({ className, ...props }) {
145
147
  MenuGroup.displayName = 'Menu.Group';
146
148
  /** The heading of a group. Screen readers announce the group by it. */
147
149
  function MenuGroupLabel({ className, ...props }) {
148
- return _jsx(BaseMenu.GroupLabel, { "data-slot": "menu-group-label", className: menuVariants().groupLabel({ className }), ...props });
150
+ return (_jsx(BaseMenu.GroupLabel, { "data-slot": "menu-group-label", className: menuVariants().groupLabel({ className }), ...props }));
149
151
  }
150
152
  MenuGroupLabel.displayName = 'Menu.GroupLabel';
151
153
  /** A rule between groups of items. */
152
- function MenuSeparator({ className, ...props }) {
153
- return _jsx("div", { role: "separator", "data-slot": "menu-separator", className: menuVariants().separator({ className }), ...props });
154
+ function MenuSeparator({ className, render, ...props }) {
155
+ return useRender({
156
+ defaultTagName: 'div',
157
+ render,
158
+ props: mergeProps({ role: 'separator', 'data-slot': 'menu-separator', className: menuVariants().separator({ className }) }, props),
159
+ });
154
160
  }
155
161
  MenuSeparator.displayName = 'Menu.Separator';
156
162
  /** What an item does, in quieter words after its label. */
157
- function MenuDescription({ className, ...props }) {
158
- return _jsx("span", { "data-slot": "menu-description", className: menuVariants().description({ className }), ...props });
163
+ function MenuDescription({ className, render, ...props }) {
164
+ return useRender({
165
+ defaultTagName: 'span',
166
+ render,
167
+ props: mergeProps({ 'data-slot': 'menu-description', className: menuVariants().description({ className }) }, props),
168
+ });
159
169
  }
160
170
  MenuDescription.displayName = 'Menu.Description';
161
171
  /** The keys for an item, at its end. It only shows them: wire the keys up where the action lives. */
162
- function MenuShortcut({ className, ...props }) {
163
- return _jsx("kbd", { "data-slot": "menu-shortcut", className: menuVariants().shortcut({ className }), ...props });
172
+ function MenuShortcut({ className, render, ...props }) {
173
+ return useRender({
174
+ defaultTagName: 'kbd',
175
+ render,
176
+ props: mergeProps({ 'data-slot': 'menu-shortcut', className: menuVariants().shortcut({ className }) }, props),
177
+ });
164
178
  }
165
179
  MenuShortcut.displayName = 'Menu.Shortcut';
166
180
  /** A small count or flag at an item's end: how many need attention, or that something is new. */
167
- function MenuBadge({ className, ...props }) {
168
- return _jsx("span", { "data-slot": "menu-badge", className: menuVariants().badge({ className }), ...props });
181
+ function MenuBadge({ className, render, ...props }) {
182
+ return useRender({
183
+ defaultTagName: 'span',
184
+ render,
185
+ props: mergeProps({ 'data-slot': 'menu-badge', className: menuVariants().badge({ className }) }, props),
186
+ });
169
187
  }
170
188
  MenuBadge.displayName = 'Menu.Badge';
171
189
  export const Menu = Object.assign(MenuRoot, {
@@ -1,4 +1,10 @@
1
1
  import { type ComponentProps, 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 MessageFrom = 'user' | 'assistant';
3
9
  export interface MessageProps extends ComponentProps<'div'> {
4
10
  /** Who wrote it. A person's turn is a bubble on the trailing side; the assistant's is prose. */
@@ -26,28 +32,28 @@ declare namespace MessageGroup {
26
32
  export interface MessageAvatarProps extends ComponentProps<'div'> {
27
33
  }
28
34
  /** Who it is from, beside the turn's first line. Leave it empty to keep the space. */
29
- declare function MessageAvatar({ className, ...props }: MessageAvatarProps): import("react").JSX.Element;
35
+ declare function MessageAvatar({ className, render, ...props }: MessageAvatarProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
30
36
  declare namespace MessageAvatar {
31
37
  var displayName: string;
32
38
  }
33
39
  export interface MessageContentProps extends ComponentProps<'div'> {
34
40
  }
35
41
  /** The column with the header, the bubble, the attachments and the actions. */
36
- declare function MessageContent({ className, ...props }: MessageContentProps): import("react").JSX.Element;
42
+ declare function MessageContent({ className, render, ...props }: MessageContentProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
37
43
  declare namespace MessageContent {
38
44
  var displayName: string;
39
45
  }
40
46
  export interface MessageHeaderProps extends ComponentProps<'div'> {
41
47
  }
42
48
  /** A line above the turn: a name in `<strong>`, a time, a model. */
43
- declare function MessageHeader({ className, ...props }: MessageHeaderProps): import("react").JSX.Element;
49
+ declare function MessageHeader({ className, render, ...props }: MessageHeaderProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
44
50
  declare namespace MessageHeader {
45
51
  var displayName: string;
46
52
  }
47
53
  export interface MessageBubbleProps extends ComponentProps<'div'> {
48
54
  }
49
55
  /** The surface of a person's turn. On the assistant's it draws nothing, and the text is the page's. */
50
- declare function MessageBubble({ className, ...props }: MessageBubbleProps): import("react").JSX.Element;
56
+ declare function MessageBubble({ className, render, ...props }: MessageBubbleProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
51
57
  declare namespace MessageBubble {
52
58
  var displayName: string;
53
59
  }
@@ -57,14 +63,14 @@ export interface MessageBubbleContentProps extends ComponentProps<'div'> {
57
63
  * The text. Paragraphs, lists, inline code, code blocks and headings inside
58
64
  * it are set as prose, so rendered Markdown can go straight in.
59
65
  */
60
- declare function MessageBubbleContent({ className, children, ...props }: MessageBubbleContentProps): import("react").JSX.Element;
66
+ declare function MessageBubbleContent({ className, children, render, ...props }: MessageBubbleContentProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
61
67
  declare namespace MessageBubbleContent {
62
68
  var displayName: string;
63
69
  }
64
70
  export interface MessageFooterProps extends ComponentProps<'div'> {
65
71
  }
66
72
  /** A line under the turn: sent, read, a model and how long it took. */
67
- declare function MessageFooter({ className, ...props }: MessageFooterProps): import("react").JSX.Element;
73
+ declare function MessageFooter({ className, render, ...props }: MessageFooterProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
68
74
  declare namespace MessageFooter {
69
75
  var displayName: string;
70
76
  }
@@ -107,7 +113,7 @@ export interface MessageBranchProps extends Omit<ComponentProps<'div'>, 'onChang
107
113
  onIndexChange: (index: number) => void;
108
114
  }
109
115
  /** "‹ 2 / 3 ›": steps between the versions of an answer that was retried or edited. */
110
- declare function MessageBranch({ count, index, onIndexChange, className, ...props }: MessageBranchProps): import("react").JSX.Element;
116
+ declare function MessageBranch({ count, index, onIndexChange, className, render, ...props }: MessageBranchProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
111
117
  declare namespace MessageBranch {
112
118
  var displayName: string;
113
119
  }
@@ -124,7 +130,7 @@ declare namespace MessageStatus {
124
130
  export interface MessageAttachmentsProps extends ComponentProps<'div'> {
125
131
  }
126
132
  /** The files sent with a turn, above its bubble. */
127
- declare function MessageAttachments({ className, ...props }: MessageAttachmentsProps): import("react").JSX.Element;
133
+ declare function MessageAttachments({ className, render, ...props }: MessageAttachmentsProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
128
134
  declare namespace MessageAttachments {
129
135
  var displayName: string;
130
136
  }
@@ -139,7 +145,7 @@ export interface MessageAttachmentProps extends Omit<ComponentProps<'div'>, 'chi
139
145
  icon?: ReactNode;
140
146
  }
141
147
  /** One sent file: a picture, or a card with a glyph, the name and its size. */
142
- declare function MessageAttachment({ name, src, meta, icon, className, ...props }: MessageAttachmentProps): import("react").JSX.Element;
148
+ declare function MessageAttachment({ name, src, meta, icon, className, render, ...props }: MessageAttachmentProps & RenderProp<'div'>): import("react").JSX.Element;
143
149
  declare namespace MessageAttachment {
144
150
  var displayName: string;
145
151
  }
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  /**
4
4
  * Message — one turn of a conversation with an assistant.
5
5
  *
@@ -49,6 +49,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
49
49
  import { Tooltip } from '@base-ui/react/tooltip';
50
50
  import { createContext, useContext, useEffect, useRef, useState, } from 'react';
51
51
  import { tv } from 'tailwind-variants';
52
+ import { mergeProps } from '@base-ui/react/merge-props';
53
+ import { useRender } from '@base-ui/react/use-render';
52
54
  const messageVariants = tv({
53
55
  slots: {
54
56
  root: 'group/message flex w-full gap-3',
@@ -156,45 +158,73 @@ function MessageGroup({ from = 'assistant', className, ...props }) {
156
158
  }
157
159
  MessageGroup.displayName = 'Message.Group';
158
160
  /** Who it is from, beside the turn's first line. Leave it empty to keep the space. */
159
- function MessageAvatar({ className, ...props }) {
160
- return _jsx("div", { "data-slot": "message-avatar", className: messageVariants().avatar({ className }), ...props });
161
+ function MessageAvatar({ className, render, ...props }) {
162
+ return useRender({
163
+ defaultTagName: 'div',
164
+ render,
165
+ props: mergeProps({ 'data-slot': 'message-avatar', className: messageVariants().avatar({ className }) }, props),
166
+ });
161
167
  }
162
168
  MessageAvatar.displayName = 'Message.Avatar';
163
169
  /** The column with the header, the bubble, the attachments and the actions. */
164
- function MessageContent({ className, ...props }) {
170
+ function MessageContent({ className, render, ...props }) {
165
171
  const { from } = useContext(MessageContext);
166
- return _jsx("div", { "data-slot": "message-content", className: messageVariants({ from }).content({ className }), ...props });
172
+ return useRender({
173
+ defaultTagName: 'div',
174
+ render,
175
+ props: mergeProps({ 'data-slot': 'message-content', className: messageVariants({ from }).content({ className }) }, props),
176
+ });
167
177
  }
168
178
  MessageContent.displayName = 'Message.Content';
169
179
  /** A line above the turn: a name in `<strong>`, a time, a model. */
170
- function MessageHeader({ className, ...props }) {
180
+ function MessageHeader({ className, render, ...props }) {
171
181
  const { from } = useContext(MessageContext);
172
- return _jsx("div", { "data-slot": "message-header", className: messageVariants({ from }).header({ className }), ...props });
182
+ return useRender({
183
+ defaultTagName: 'div',
184
+ render,
185
+ props: mergeProps({ 'data-slot': 'message-header', className: messageVariants({ from }).header({ className }) }, props),
186
+ });
173
187
  }
174
188
  MessageHeader.displayName = 'Message.Header';
175
189
  /** The surface of a person's turn. On the assistant's it draws nothing, and the text is the page's. */
176
- function MessageBubble({ className, ...props }) {
190
+ function MessageBubble({ className, render, ...props }) {
177
191
  const { from } = useContext(MessageContext);
178
- return _jsx("div", { "data-slot": "message-bubble", className: messageVariants({ from }).bubble({ className }), ...props });
192
+ return useRender({
193
+ defaultTagName: 'div',
194
+ render,
195
+ props: mergeProps({ 'data-slot': 'message-bubble', className: messageVariants({ from }).bubble({ className }) }, props),
196
+ });
179
197
  }
180
198
  MessageBubble.displayName = 'Message.Bubble';
181
199
  /**
182
200
  * The text. Paragraphs, lists, inline code, code blocks and headings inside
183
201
  * it are set as prose, so rendered Markdown can go straight in.
184
202
  */
185
- function MessageBubbleContent({ className, children, ...props }) {
203
+ function MessageBubbleContent({ className, children, render, ...props }) {
186
204
  const { from, streaming } = useContext(MessageContext);
187
205
  const slots = messageVariants({ from });
188
206
  // The caret follows the last word: after the text itself, or inside the last block.
189
207
  const plain = typeof children === 'string' || typeof children === 'number';
190
208
  const caret = streaming ? (plain ? slots.caret() : slots.caretLast()) : undefined;
191
- return (_jsx("div", { "data-slot": "message-bubble-content", className: slots.bubbleContent({ className: [caret, className] }), ...props, children: children }));
209
+ return useRender({
210
+ defaultTagName: 'div',
211
+ render,
212
+ props: mergeProps({
213
+ 'data-slot': 'message-bubble-content',
214
+ className: slots.bubbleContent({ className: [caret, className] }),
215
+ children: _jsx(_Fragment, { children: children }),
216
+ }, props),
217
+ });
192
218
  }
193
219
  MessageBubbleContent.displayName = 'Message.BubbleContent';
194
220
  /** A line under the turn: sent, read, a model and how long it took. */
195
- function MessageFooter({ className, ...props }) {
221
+ function MessageFooter({ className, render, ...props }) {
196
222
  const { from } = useContext(MessageContext);
197
- return _jsx("div", { "data-slot": "message-footer", className: messageVariants({ from }).footer({ className }), ...props });
223
+ return useRender({
224
+ defaultTagName: 'div',
225
+ render,
226
+ props: mergeProps({ 'data-slot': 'message-footer', className: messageVariants({ from }).footer({ className }) }, props),
227
+ });
198
228
  }
199
229
  MessageFooter.displayName = 'Message.Footer';
200
230
  /** The row of actions under a turn. */
@@ -227,9 +257,19 @@ function MessageAction({ label, children, copy, pressed, onClick, className, ...
227
257
  }
228
258
  MessageAction.displayName = 'Message.Action';
229
259
  /** "‹ 2 / 3 ›": steps between the versions of an answer that was retried or edited. */
230
- function MessageBranch({ count, index, onIndexChange, className, ...props }) {
260
+ function MessageBranch({ count, index, onIndexChange, className, render, ...props }) {
231
261
  const slots = messageVariants();
232
- return (_jsxs("div", { role: "group", "aria-label": "Versions", "data-slot": "message-branch", className: slots.branch({ className }), ...props, children: [_jsx("button", { type: "button", "aria-label": "Previous version", className: slots.branchButton(), disabled: index <= 0, onClick: () => onIndexChange(index - 1), children: _jsx(ChevronGlyph, { flip: true }) }), _jsxs("span", { "aria-live": "polite", className: "min-w-9 text-center", children: [index + 1, " / ", count] }), _jsx("button", { type: "button", "aria-label": "Next version", className: slots.branchButton(), disabled: index >= count - 1, onClick: () => onIndexChange(index + 1), children: _jsx(ChevronGlyph, {}) })] }));
262
+ return useRender({
263
+ defaultTagName: 'div',
264
+ render,
265
+ props: mergeProps({
266
+ role: 'group',
267
+ 'aria-label': 'Versions',
268
+ 'data-slot': 'message-branch',
269
+ className: slots.branch({ className }),
270
+ children: (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Previous version", className: slots.branchButton(), disabled: index <= 0, onClick: () => onIndexChange(index - 1), children: _jsx(ChevronGlyph, { flip: true }) }), _jsxs("span", { "aria-live": "polite", className: "min-w-9 text-center", children: [index + 1, " / ", count] }), _jsx("button", { type: "button", "aria-label": "Next version", className: slots.branchButton(), disabled: index >= count - 1, onClick: () => onIndexChange(index + 1), children: _jsx(ChevronGlyph, {}) })] })),
271
+ }, props),
272
+ });
233
273
  }
234
274
  MessageBranch.displayName = 'Message.Branch';
235
275
  /**
@@ -241,18 +281,30 @@ function MessageStatus({ className, ...props }) {
241
281
  }
242
282
  MessageStatus.displayName = 'Message.Status';
243
283
  /** The files sent with a turn, above its bubble. */
244
- function MessageAttachments({ className, ...props }) {
284
+ function MessageAttachments({ className, render, ...props }) {
245
285
  const { from } = useContext(MessageContext);
246
- return (_jsx("div", { "data-slot": "message-attachments", className: messageVariants({ from }).attachments({ className }), ...props }));
286
+ return useRender({
287
+ defaultTagName: 'div',
288
+ render,
289
+ props: mergeProps({ 'data-slot': 'message-attachments', className: messageVariants({ from }).attachments({ className }) }, props),
290
+ });
247
291
  }
248
292
  MessageAttachments.displayName = 'Message.Attachments';
249
293
  /** One sent file: a picture, or a card with a glyph, the name and its size. */
250
- function MessageAttachment({ name, src, meta, icon, className, ...props }) {
294
+ function MessageAttachment({ name, src, meta, icon, className, render, ...props }) {
251
295
  const slots = messageVariants();
252
296
  if (src) {
253
297
  return (_jsx("div", { "data-slot": "message-attachment", className: slots.attachment({ className }), ...props, children: _jsx("img", { src: src, alt: name, className: slots.attachmentImage() }) }));
254
298
  }
255
- return (_jsxs("div", { "data-slot": "message-attachment", className: slots.attachment({ className: [slots.attachmentFile(), className] }), ...props, children: [_jsx("span", { className: slots.attachmentGlyph(), children: icon ?? _jsx(FileGlyph, {}) }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: slots.attachmentName(), children: name }), meta ? _jsx("span", { className: slots.attachmentMeta(), children: meta }) : null] })] }));
299
+ return useRender({
300
+ defaultTagName: 'div',
301
+ render,
302
+ props: mergeProps({
303
+ 'data-slot': 'message-attachment',
304
+ className: slots.attachment({ className: [slots.attachmentFile(), className] }),
305
+ children: (_jsxs(_Fragment, { children: [_jsx("span", { className: slots.attachmentGlyph(), children: icon ?? _jsx(FileGlyph, {}) }), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: slots.attachmentName(), children: name }), meta ? _jsx("span", { className: slots.attachmentMeta(), children: meta }) : null] })] })),
306
+ }, props),
307
+ });
256
308
  }
257
309
  MessageAttachment.displayName = 'Message.Attachment';
258
310
  /* -------------------------------------------------------------------------- */