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
@@ -45,6 +45,12 @@
45
45
  * time it draws, so a change of theme needs nothing from the page.
46
46
  */
47
47
  import { type ComponentProps } from 'react';
48
+ import { useRender } from '@base-ui/react/use-render';
49
+ import type { ElementType as RenderElementType } from 'react';
50
+ /** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
51
+ type RenderProp<Tag extends RenderElementType> = {
52
+ render?: useRender.ComponentProps<Tag>['render'];
53
+ };
48
54
  /** How the digit near the pointer reacts. */
49
55
  export type NotFoundEffect = 'scatter' | 'dissolve' | 'scramble';
50
56
  /** Which of the theme's roles the highlighted digit is drawn in. */
@@ -54,7 +60,7 @@ export interface NotFoundProps extends ComponentProps<'div'> {
54
60
  backdrop?: boolean;
55
61
  }
56
62
  /** The column the code, the title, the description and the actions stand in, centred. */
57
- declare function NotFoundRoot({ backdrop, className, children, ...props }: NotFoundProps): import("react").JSX.Element;
63
+ declare function NotFoundRoot({ backdrop, className, children, render, ...props }: NotFoundProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
58
64
  declare namespace NotFoundRoot {
59
65
  var displayName: string;
60
66
  }
@@ -82,7 +88,7 @@ export interface NotFoundCodeProps extends Omit<ComponentProps<'div'>, 'children
82
88
  label?: string;
83
89
  }
84
90
  /** The code, drawn in cells on a canvas. Its box keeps the code's shape before anything is drawn. */
85
- declare function NotFoundCode({ code, effect, fill, color, ambient, highlight, label, className, style, ...props }: NotFoundCodeProps): import("react").JSX.Element;
91
+ declare function NotFoundCode({ code, effect, fill, color, ambient, highlight, label, className, style, render, ...props }: NotFoundCodeProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
86
92
  declare namespace NotFoundCode {
87
93
  var displayName: string;
88
94
  }
@@ -98,14 +104,14 @@ declare namespace NotFoundTitle {
98
104
  export interface NotFoundDescriptionProps extends ComponentProps<'p'> {
99
105
  }
100
106
  /** A line on what to do next. */
101
- declare function NotFoundDescription({ className, ...props }: NotFoundDescriptionProps): import("react").JSX.Element;
107
+ declare function NotFoundDescription({ className, render, ...props }: NotFoundDescriptionProps & RenderProp<'p'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
102
108
  declare namespace NotFoundDescription {
103
109
  var displayName: string;
104
110
  }
105
111
  export interface NotFoundActionsProps extends ComponentProps<'div'> {
106
112
  }
107
113
  /** The ways out: links or buttons in a row that wraps on a narrow screen. */
108
- declare function NotFoundActions({ className, ...props }: NotFoundActionsProps): import("react").JSX.Element;
114
+ declare function NotFoundActions({ className, render, ...props }: NotFoundActionsProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
109
115
  declare namespace NotFoundActions {
110
116
  var displayName: string;
111
117
  }
@@ -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, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  /**
4
4
  * NotFound — an error code drawn in pixels that come apart when the pointer
5
5
  * reaches them, with a title, a line of help and a way out underneath.
@@ -46,9 +46,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
46
46
  * while something is moving. The canvas reads its colours from the theme each
47
47
  * time it draws, so a change of theme needs nothing from the page.
48
48
  */
49
- import { useEffect, useRef, } from 'react';
49
+ import { useEffect, useRef } from 'react';
50
50
  import { tv } from 'tailwind-variants';
51
51
  import { GLYPH_COLUMNS, GLYPH_ROWS, ICONS, digitGlyph } from './glyphs.js';
52
+ import { mergeProps } from '@base-ui/react/merge-props';
53
+ import { useRender } from '@base-ui/react/use-render';
52
54
  const notFoundVariants = tv({
53
55
  slots: {
54
56
  // `overflow-x-clip` keeps flying cells from widening the page on a phone.
@@ -352,7 +354,10 @@ function createEngine({ canvas, code, fill, highlight, effect: initialEffect, am
352
354
  cell.x += cell.vx * h;
353
355
  cell.y += cell.vy * h;
354
356
  }
355
- if (!digit.active && Math.abs(cell.x - tx) < 0.004 && Math.abs(cell.y - ty) < 0.004 && Math.abs(cell.vx) + Math.abs(cell.vy) < 0.02) {
357
+ if (!digit.active &&
358
+ Math.abs(cell.x - tx) < 0.004 &&
359
+ Math.abs(cell.y - ty) < 0.004 &&
360
+ Math.abs(cell.vx) + Math.abs(cell.vy) < 0.02) {
356
361
  cell.x = tx;
357
362
  cell.y = ty;
358
363
  cell.vx = 0;
@@ -587,7 +592,11 @@ function createEngine({ canvas, code, fill, highlight, effect: initialEffect, am
587
592
  track(event);
588
593
  // Anywhere over the canvas the pointer lights cells, so a frame is wanted
589
594
  // even when no digit is close enough to react.
590
- if (pointer && pointer.x > -HEAT_RADIUS && pointer.x < columns + HEAT_RADIUS && pointer.y > -HEAT_RADIUS && pointer.y < GLYPH_ROWS + PAD_Y * 2 + HEAT_RADIUS)
595
+ if (pointer &&
596
+ pointer.x > -HEAT_RADIUS &&
597
+ pointer.x < columns + HEAT_RADIUS &&
598
+ pointer.y > -HEAT_RADIUS &&
599
+ pointer.y < GLYPH_ROWS + PAD_Y * 2 + HEAT_RADIUS)
591
600
  invalidate();
592
601
  const { index, distance } = nearest();
593
602
  const current = digits.findIndex((digit) => digit.active);
@@ -722,13 +731,21 @@ const backdropStyle = {
722
731
  WebkitMaskComposite: 'source-in',
723
732
  };
724
733
  /** The column the code, the title, the description and the actions stand in, centred. */
725
- function NotFoundRoot({ backdrop = true, className, children, ...props }) {
734
+ function NotFoundRoot({ backdrop = true, className, children, render, ...props }) {
726
735
  const slots = notFoundVariants({ backdrop });
727
- return (_jsxs("div", { "data-slot": "not-found", className: slots.root({ className }), ...props, children: [backdrop ? _jsx("span", { "aria-hidden": "true", "data-slot": "not-found-backdrop", className: slots.backdrop(), style: backdropStyle }) : null, children] }));
736
+ return useRender({
737
+ defaultTagName: 'div',
738
+ render,
739
+ props: mergeProps({
740
+ 'data-slot': 'not-found',
741
+ className: slots.root({ className }),
742
+ children: (_jsxs(_Fragment, { children: [backdrop ? (_jsx("span", { "aria-hidden": "true", "data-slot": "not-found-backdrop", className: slots.backdrop(), style: backdropStyle })) : null, children] })),
743
+ }, props),
744
+ });
728
745
  }
729
746
  NotFoundRoot.displayName = 'NotFound';
730
747
  /** The code, drawn in cells on a canvas. Its box keeps the code's shape before anything is drawn. */
731
- function NotFoundCode({ code = '404', effect = 'scatter', fill = 'solid', color = 'info', ambient = true, highlight, label, className, style, ...props }) {
748
+ function NotFoundCode({ code = '404', effect = 'scatter', fill = 'solid', color = 'info', ambient = true, highlight, label, className, style, render, ...props }) {
732
749
  const canvasRef = useRef(null);
733
750
  const engineRef = useRef(null);
734
751
  const effectRef = useRef(effect);
@@ -760,7 +777,18 @@ function NotFoundCode({ code = '404', effect = 'scatter', fill = 'solid', color
760
777
  width: `${(1 + (2 * PAD_X) / columns) * 100}%`,
761
778
  height: `${(1 + (2 * PAD_Y) / GLYPH_ROWS) * 100}%`,
762
779
  };
763
- return (_jsx("div", { "data-slot": "not-found-code", role: "img", "aria-label": label ?? `Error ${code}`, className: slots.code({ className }), style: { aspectRatio: `${columns} / ${GLYPH_ROWS}`, ...style }, ...props, children: _jsx("canvas", { ref: canvasRef, "aria-hidden": "true", className: slots.canvas(), style: canvasStyle }) }));
780
+ return useRender({
781
+ defaultTagName: 'div',
782
+ render,
783
+ props: mergeProps({
784
+ 'data-slot': 'not-found-code',
785
+ role: 'img',
786
+ 'aria-label': label ?? `Error ${code}`,
787
+ className: slots.code({ className }),
788
+ style: { aspectRatio: `${columns} / ${GLYPH_ROWS}`, ...style },
789
+ children: (_jsx(_Fragment, { children: _jsx("canvas", { ref: canvasRef, "aria-hidden": "true", className: slots.canvas(), style: canvasStyle }) })),
790
+ }, props),
791
+ });
764
792
  }
765
793
  NotFoundCode.displayName = 'NotFound.Code';
766
794
  /** What happened, in a few words. */
@@ -769,13 +797,21 @@ function NotFoundTitle({ as: Tag = 'h1', className, ...props }) {
769
797
  }
770
798
  NotFoundTitle.displayName = 'NotFound.Title';
771
799
  /** A line on what to do next. */
772
- function NotFoundDescription({ className, ...props }) {
773
- return _jsx("p", { "data-slot": "not-found-description", className: notFoundVariants().description({ className }), ...props });
800
+ function NotFoundDescription({ className, render, ...props }) {
801
+ return useRender({
802
+ defaultTagName: 'p',
803
+ render,
804
+ props: mergeProps({ 'data-slot': 'not-found-description', className: notFoundVariants().description({ className }) }, props),
805
+ });
774
806
  }
775
807
  NotFoundDescription.displayName = 'NotFound.Description';
776
808
  /** The ways out: links or buttons in a row that wraps on a narrow screen. */
777
- function NotFoundActions({ className, ...props }) {
778
- return _jsx("div", { "data-slot": "not-found-actions", className: notFoundVariants().actions({ className }), ...props });
809
+ function NotFoundActions({ className, render, ...props }) {
810
+ return useRender({
811
+ defaultTagName: 'div',
812
+ render,
813
+ props: mergeProps({ 'data-slot': 'not-found-actions', className: notFoundVariants().actions({ className }) }, props),
814
+ });
779
815
  }
780
816
  NotFoundActions.displayName = 'NotFound.Actions';
781
817
  export const NotFound = Object.assign(NotFoundRoot, {
@@ -41,6 +41,12 @@
41
41
  * dark, with no colour passed in and nothing to keep in step with the theme.
42
42
  */
43
43
  import { type ComponentProps, type MouseEvent, type ReactNode } from 'react';
44
+ import { useRender } from '@base-ui/react/use-render';
45
+ import type { ElementType as RenderElementType } from 'react';
46
+ /** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
47
+ type RenderProp<Tag extends RenderElementType> = {
48
+ render?: useRender.ComponentProps<Tag>['render'];
49
+ };
44
50
  /** `[longitude, latitude]` of the point facing the viewer, in degrees. */
45
51
  export type PlanetRotation = [longitude: number, latitude: number];
46
52
  export interface PlanetHandle {
@@ -77,7 +83,7 @@ export interface PlanetGlobeProps extends Omit<ComponentProps<'div'>, 'children'
77
83
  /** What a screen reader calls the globe. */
78
84
  label?: string;
79
85
  }
80
- declare function PlanetGlobe({ children, className, color, label, ...props }: PlanetGlobeProps): import("react").JSX.Element;
86
+ declare function PlanetGlobe({ children, className, color, label, render, ...props }: PlanetGlobeProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
81
87
  declare namespace PlanetGlobe {
82
88
  var displayName: string;
83
89
  }
@@ -110,7 +116,7 @@ export interface PlanetMarkerProps extends Omit<ComponentProps<'div'>, 'children
110
116
  /** What is drawn at the coordinate: an avatar, an icon. A dot when left out. */
111
117
  children?: ReactNode;
112
118
  }
113
- declare function PlanetMarker({ lat, lng, label, count, color, pulse, onClick, selected, name, className, labelClassName, children, ...props }: PlanetMarkerProps): import("react").JSX.Element;
119
+ declare function PlanetMarker({ lat, lng, label, count, color, pulse, onClick, selected, name, className, labelClassName, children, render, ...props }: PlanetMarkerProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
114
120
  declare namespace PlanetMarker {
115
121
  var displayName: string;
116
122
  }
@@ -120,7 +126,7 @@ export interface PlanetControlsProps extends Omit<ComponentProps<'div'>, 'childr
120
126
  /** Words to show between the two arrows. Without them it is the arrows alone. */
121
127
  children?: ReactNode;
122
128
  }
123
- declare function PlanetControls({ step, className, children, ...props }: PlanetControlsProps): import("react").JSX.Element;
129
+ declare function PlanetControls({ step, className, children, render, ...props }: PlanetControlsProps & RenderProp<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
124
130
  declare namespace PlanetControls {
125
131
  var displayName: string;
126
132
  }
@@ -130,7 +136,7 @@ export interface PlanetListProps extends ComponentProps<'ul'> {
130
136
  * The places on the globe as a list, in two columns, for picking one by name.
131
137
  * Put it beside or under the globe and turn the globe to whatever is picked.
132
138
  */
133
- declare function PlanetList({ className, ...props }: PlanetListProps): import("react").JSX.Element;
139
+ declare function PlanetList({ className, render, ...props }: PlanetListProps & RenderProp<'ul'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
134
140
  declare namespace PlanetList {
135
141
  var displayName: string;
136
142
  }
@@ -141,7 +147,7 @@ export interface PlanetListItemProps extends Omit<ComponentProps<'button'>, 'col
141
147
  selected?: boolean;
142
148
  }
143
149
  /** One place in `Planet.List`: a dot in its marker's colour, and its name. A button. */
144
- declare function PlanetListItem({ color, selected, className, children, ...props }: PlanetListItemProps): import("react").JSX.Element;
150
+ declare function PlanetListItem({ color, selected, className, children, render, ...props }: PlanetListItemProps & RenderProp<'button'>): import("react").JSX.Element;
145
151
  declare namespace PlanetListItem {
146
152
  var displayName: string;
147
153
  }
@@ -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
  * Planet — the world as dots on a globe you can turn, with things pinned to it.
5
5
  *
@@ -45,6 +45,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
45
45
  import { createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
46
46
  import { tv } from 'tailwind-variants';
47
47
  import { LAND, LAND_COLUMNS, LAND_ROWS } from './land.js';
48
+ import { mergeProps } from '@base-ui/react/merge-props';
49
+ import { useRender } from '@base-ui/react/use-render';
48
50
  const planetVariants = tv({
49
51
  slots: {
50
52
  // `isolate` keeps the markers' depth ordering inside the planet. Each marker
@@ -509,7 +511,7 @@ const PlanetRoot = forwardRef(function PlanetRoot({ children, className, default
509
511
  PlanetRoot.displayName = 'Planet';
510
512
  /** Degrees one press of an arrow key turns the globe. */
511
513
  const KEY_STEP = 15;
512
- function PlanetGlobe({ children, className, color = 'primary', label = 'Globe', ...props }) {
514
+ function PlanetGlobe({ children, className, color = 'primary', label = 'Globe', render, ...props }) {
513
515
  const slots = planetVariants({ glow: color });
514
516
  const planet = usePlanetContext('Planet.Globe');
515
517
  const canvas = useRef(null);
@@ -536,8 +538,7 @@ function PlanetGlobe({ children, className, color = 'primary', label = 'Globe',
536
538
  autoRotate: 0,
537
539
  listeners,
538
540
  onSettle: (rotation) => {
539
- setSettled((current) => Math.round(current[0]) === Math.round(rotation[0]) &&
540
- Math.round(current[1]) === Math.round(rotation[1])
541
+ setSettled((current) => Math.round(current[0]) === Math.round(rotation[0]) && Math.round(current[1]) === Math.round(rotation[1])
541
542
  ? current
542
543
  : rotation);
543
544
  onRotationChange.current?.(rotation);
@@ -602,16 +603,35 @@ function PlanetGlobe({ children, className, color = 'primary', label = 'Globe',
602
603
  };
603
604
  const longitude = Math.round(settled[0]);
604
605
  const side = longitude === 0 ? '' : longitude > 0 ? ' east' : ' west';
605
- return (_jsxs("div", {
606
- // A slider, because that is what it is to a keyboard: one value, the
607
- // longitude facing you, moved with the arrow keys.
608
- role: planet.interactive ? 'slider' : 'img', "aria-label": label, "aria-orientation": planet.interactive ? 'horizontal' : undefined, "aria-valuemin": planet.interactive ? -180 : undefined, "aria-valuemax": planet.interactive ? 180 : undefined, "aria-valuenow": planet.interactive ? longitude : undefined, "aria-valuetext": planet.interactive ? `Centred on ${Math.abs(longitude)} degrees${side}` : undefined, tabIndex: planet.interactive ? 0 : undefined, className: slots.globe({ className }), onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onPointerEnter: () => engine.current?.setHover(true), onPointerLeave: () => engine.current?.setHover(false), onKeyDown: onKeyDown, ...props, children: [_jsx("canvas", { ref: canvas, "aria-hidden": "true", className: slots.canvas() }), _jsx("div", { className: slots.markers(), children: children })] }));
606
+ return useRender({
607
+ defaultTagName: 'div',
608
+ render,
609
+ props: mergeProps({
610
+ role: planet.interactive ? 'slider' : 'img',
611
+ 'aria-label': label,
612
+ 'aria-orientation': planet.interactive ? 'horizontal' : undefined,
613
+ 'aria-valuemin': planet.interactive ? -180 : undefined,
614
+ 'aria-valuemax': planet.interactive ? 180 : undefined,
615
+ 'aria-valuenow': planet.interactive ? longitude : undefined,
616
+ 'aria-valuetext': planet.interactive ? `Centred on ${Math.abs(longitude)} degrees${side}` : undefined,
617
+ tabIndex: planet.interactive ? 0 : undefined,
618
+ className: slots.globe({ className }),
619
+ onPointerDown: onPointerDown,
620
+ onPointerMove: onPointerMove,
621
+ onPointerUp: endDrag,
622
+ onPointerCancel: endDrag,
623
+ onPointerEnter: () => engine.current?.setHover(true),
624
+ onPointerLeave: () => engine.current?.setHover(false),
625
+ onKeyDown: onKeyDown,
626
+ children: (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvas, "aria-hidden": "true", className: slots.canvas() }), _jsx("div", { className: slots.markers(), children: children })] })),
627
+ }, props),
628
+ });
609
629
  }
610
630
  PlanetGlobe.displayName = 'Planet.Globe';
611
631
  /** How near the edge a marker starts to fade, as depth. */
612
632
  const FADE_FROM = 0.28;
613
633
  const FADE_TO = 0.06;
614
- function PlanetMarker({ lat, lng, label, count, color = 'primary', pulse = false, onClick, selected = false, name, className, labelClassName, children, ...props }) {
634
+ function PlanetMarker({ lat, lng, label, count, color = 'primary', pulse = false, onClick, selected = false, name, className, labelClassName, children, render, ...props }) {
615
635
  const slots = planetVariants({ color, selected });
616
636
  const planet = usePlanetContext('Planet.Marker');
617
637
  const element = useRef(null);
@@ -632,32 +652,65 @@ function PlanetMarker({ lat, lng, label, count, color = 'primary', pulse = false
632
652
  // Nearer the viewer is on top, as it would be on a real globe.
633
653
  node.style.zIndex = String(Math.round(depth * 100));
634
654
  }), [subscribe, lat, lng]);
635
- const body = (_jsxs(_Fragment, { children: [label !== undefined && label !== null ? (_jsxs("span", { className: slots.label({ className: labelClassName }), children: [label, count !== undefined && count !== null ? (_jsx("span", { className: slots.count(), children: count })) : null] })) : null, pulse ? _jsx("span", { "aria-hidden": "true", className: slots.pulse() }) : null, children !== undefined && children !== null ? (_jsx("span", { "data-pin": "", className: slots.pin(), children: children })) : (_jsx("span", { "data-pin": "", className: slots.dot() }))] }));
636
- return (_jsx("div", { ref: element, "data-planet-marker": "", className: slots.marker({ className }), ...props, children: onClick ? (_jsx("button", { type: "button", "aria-label": name ?? (typeof label === 'string' ? label : undefined), "aria-pressed": selected, className: slots.press(), onClick: onClick,
637
- // Kept from the globe, which would otherwise take the press as the
638
- // start of a drag and the click would never arrive.
639
- onPointerDown: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: body })) : (body) }));
655
+ const body = (_jsxs(_Fragment, { children: [label !== undefined && label !== null ? (_jsxs("span", { className: slots.label({ className: labelClassName }), children: [label, count !== undefined && count !== null ? _jsx("span", { className: slots.count(), children: count }) : null] })) : null, pulse ? _jsx("span", { "aria-hidden": "true", className: slots.pulse() }) : null, children !== undefined && children !== null ? (_jsx("span", { "data-pin": "", className: slots.pin(), children: children })) : (_jsx("span", { "data-pin": "", className: slots.dot() }))] }));
656
+ return useRender({
657
+ defaultTagName: 'div',
658
+ render,
659
+ props: mergeProps({
660
+ ref: element,
661
+ 'data-planet-marker': '',
662
+ className: slots.marker({ className }),
663
+ children: (_jsx(_Fragment, { children: onClick ? (_jsx("button", { type: "button", "aria-label": name ?? (typeof label === 'string' ? label : undefined), "aria-pressed": selected, className: slots.press(), onClick: onClick,
664
+ // Kept from the globe, which would otherwise take the press as the
665
+ // start of a drag and the click would never arrive.
666
+ onPointerDown: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: body })) : (body) })),
667
+ }, props),
668
+ });
640
669
  }
641
670
  PlanetMarker.displayName = 'Planet.Marker';
642
671
  const Arrow = ({ flipped }) => (_jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: flipped ? 'size-4 -scale-x-100' : 'size-4', fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M3 8h10M9 4l4 4-4 4" }) }));
643
- function PlanetControls({ step = 60, className, children, ...props }) {
672
+ function PlanetControls({ step = 60, className, children, render, ...props }) {
644
673
  const slots = planetVariants();
645
674
  const planet = usePlanetContext('Planet.Controls');
646
- return (_jsxs("div", { role: "group", "aria-label": "Turn the globe", className: slots.controls({ className }), ...props, children: [_jsx("button", { type: "button", "aria-label": "Turn west", className: slots.control(), onClick: () => planet.rotateBy(-step), children: _jsx(Arrow, { flipped: true }) }), children !== undefined && children !== null ? (_jsx("span", { className: slots.caption(), children: children })) : null, _jsx("button", { type: "button", "aria-label": "Turn east", className: slots.control(), onClick: () => planet.rotateBy(step), children: _jsx(Arrow, {}) })] }));
675
+ return useRender({
676
+ defaultTagName: 'div',
677
+ render,
678
+ props: mergeProps({
679
+ role: 'group',
680
+ 'aria-label': 'Turn the globe',
681
+ className: slots.controls({ className }),
682
+ children: (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Turn west", className: slots.control(), onClick: () => planet.rotateBy(-step), children: _jsx(Arrow, { flipped: true }) }), children !== undefined && children !== null ? _jsx("span", { className: slots.caption(), children: children }) : null, _jsx("button", { type: "button", "aria-label": "Turn east", className: slots.control(), onClick: () => planet.rotateBy(step), children: _jsx(Arrow, {}) })] })),
683
+ }, props),
684
+ });
647
685
  }
648
686
  PlanetControls.displayName = 'Planet.Controls';
649
687
  /**
650
688
  * The places on the globe as a list, in two columns, for picking one by name.
651
689
  * Put it beside or under the globe and turn the globe to whatever is picked.
652
690
  */
653
- function PlanetList({ className, ...props }) {
654
- return _jsx("ul", { "data-slot": "planet-list", className: planetVariants().list({ className }), ...props });
691
+ function PlanetList({ className, render, ...props }) {
692
+ return useRender({
693
+ defaultTagName: 'ul',
694
+ render,
695
+ props: mergeProps({ 'data-slot': 'planet-list', className: planetVariants().list({ className }) }, props),
696
+ });
655
697
  }
656
698
  PlanetList.displayName = 'Planet.List';
657
699
  /** One place in `Planet.List`: a dot in its marker's colour, and its name. A button. */
658
- function PlanetListItem({ color = 'primary', selected = false, className, children, ...props }) {
700
+ function PlanetListItem({ color = 'primary', selected = false, className, children, render, ...props }) {
659
701
  const slots = planetVariants({ color });
660
- return (_jsx("li", { "data-slot": "planet-list-item", children: _jsxs("button", { type: "button", "aria-pressed": selected, className: slots.listItem({ className }), ...props, children: [_jsx("span", { "aria-hidden": "true", className: slots.listDot() }), _jsx("span", { className: slots.listName(), children: children })] }) }));
702
+ // `render` draws the row's button as something else, such as a link to the place.
703
+ const button = useRender({
704
+ defaultTagName: 'button',
705
+ render,
706
+ props: mergeProps({
707
+ type: render ? undefined : 'button',
708
+ 'aria-pressed': selected,
709
+ className: slots.listItem({ className }),
710
+ children: (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", className: slots.listDot() }), _jsx("span", { className: slots.listName(), children: children })] })),
711
+ }, props),
712
+ });
713
+ return _jsx("li", { "data-slot": "planet-list-item", children: button });
661
714
  }
662
715
  PlanetListItem.displayName = 'Planet.ListItem';
663
716
  export const Planet = Object.assign(PlanetRoot, {
@@ -60,10 +60,17 @@
60
60
  * the rest. Images are shown as thumbnails, anything else as a chip with its
61
61
  * name and size.
62
62
  */
63
- import { type ComponentProps, type ReactNode } from 'react';
63
+ import { type ComponentProps, type ReactElement, type ReactNode } from 'react';
64
64
  import { type ButtonProps } from '../button/index.js';
65
65
  import { type MenuContentProps, type MenuItemProps } from '../menu/index.js';
66
66
  import { type TextareaProps } from '../textarea/index.js';
67
+ import { useRender } from '@base-ui/react/use-render';
68
+ import type * as ReactTypes from 'react';
69
+ import type { ElementType as RenderElementType } from 'react';
70
+ /** Draws a part as another element, or composes it with a component: `render={<a href="/" />}`. */
71
+ type RenderProp<Tag extends RenderElementType> = {
72
+ render?: useRender.ComponentProps<Tag>['render'];
73
+ };
67
74
  export type PromptState = 'idle' | 'submitted' | 'streaming' | 'error';
68
75
  export interface PromptMessage {
69
76
  /** What was written, trimmed. */
@@ -112,7 +119,7 @@ export interface PromptProps extends Omit<ComponentProps<'form'>, 'onSubmit' | '
112
119
  */
113
120
  mode?: string;
114
121
  }
115
- declare function PromptRoot({ value: controlledValue, defaultValue, onValueChange, onSubmit, status, onStop, disabled, defaultFiles, accept, maxFiles, onReject, mode, className, children, ...props }: PromptProps): import("react").JSX.Element;
122
+ declare function PromptRoot({ value: controlledValue, defaultValue, onValueChange, onSubmit, status, onStop, disabled, defaultFiles, accept, maxFiles, onReject, mode, className, children, ...props }: PromptProps): ReactTypes.JSX.Element;
116
123
  declare namespace PromptRoot {
117
124
  var displayName: string;
118
125
  }
@@ -125,14 +132,14 @@ export interface PromptBannerProps extends ComponentProps<'div'> {
125
132
  mode?: PromptBandMode;
126
133
  }
127
134
  /** A band above the field, for something to do before or while writing: connect an account, pick a project. */
128
- declare function PromptBanner({ open, mode, ...props }: PromptBannerProps): import("react").JSX.Element;
135
+ declare function PromptBanner({ open, mode, ...props }: PromptBannerProps): ReactTypes.JSX.Element;
129
136
  declare namespace PromptBanner {
130
137
  var displayName: string;
131
138
  }
132
139
  export interface PromptBannerActionProps extends ButtonProps {
133
140
  }
134
141
  /** The banner's button, at its end. */
135
- declare function PromptBannerAction({ className, size, shape, ...props }: PromptBannerActionProps): import("react").JSX.Element;
142
+ declare function PromptBannerAction({ className, size, shape, ...props }: PromptBannerActionProps): ReactTypes.JSX.Element;
136
143
  declare namespace PromptBannerAction {
137
144
  var displayName: string;
138
145
  }
@@ -147,7 +154,7 @@ export interface PromptStatusProps extends ComponentProps<'div'> {
147
154
  spinner?: boolean;
148
155
  }
149
156
  /** A band under the field saying what the answer is doing, with the words lit by a moving sweep. */
150
- declare function PromptStatus({ open, mode, icon, spinner, children, ...props }: PromptStatusProps): import("react").JSX.Element;
157
+ declare function PromptStatus({ open, mode, icon, spinner, children, ...props }: PromptStatusProps): ReactTypes.JSX.Element;
151
158
  declare namespace PromptStatus {
152
159
  var displayName: string;
153
160
  }
@@ -158,7 +165,7 @@ export interface PromptContextProps extends ComponentProps<'div'> {
158
165
  mode?: PromptBandMode;
159
166
  }
160
167
  /** A strip under the field, inset from its edges, for where the message is going: a branch, a folder, a ticket. */
161
- declare function PromptContext({ open, mode, className, ...props }: PromptContextProps): import("react").JSX.Element;
168
+ declare function PromptContext({ open, mode, className, render, ...props }: PromptContextProps & RenderProp<'div'>): ReactTypes.JSX.Element;
162
169
  declare namespace PromptContext {
163
170
  var displayName: string;
164
171
  }
@@ -167,14 +174,14 @@ export interface PromptContextItemProps extends ComponentProps<'span'> {
167
174
  onSelect?: () => void;
168
175
  }
169
176
  /** One fact in the context strip, with an icon before it. */
170
- declare function PromptContextItem({ onSelect, className, children, ...props }: PromptContextItemProps): import("react").JSX.Element;
177
+ declare function PromptContextItem({ onSelect, className, children, render, ...props }: PromptContextItemProps & RenderProp<'span'>): ReactTypes.JSX.Element;
171
178
  declare namespace PromptContextItem {
172
179
  var displayName: string;
173
180
  }
174
181
  export interface PromptHintProps extends ComponentProps<'p'> {
175
182
  }
176
183
  /** A quiet line under the prompt. Keys written in `<kbd>` are drawn as keys. */
177
- declare function PromptHint({ className, children, ...props }: PromptHintProps): import("react").JSX.Element;
184
+ declare function PromptHint({ className, children, render, ...props }: PromptHintProps & RenderProp<'p'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
178
185
  declare namespace PromptHint {
179
186
  var displayName: string;
180
187
  }
@@ -187,35 +194,35 @@ export interface PromptFieldProps extends ComponentProps<'div'> {
187
194
  layout?: 'stacked' | 'inline';
188
195
  }
189
196
  /** The card that holds the text, the files and the footer. Files can be dropped on it. */
190
- declare function PromptField({ layout, className, onDragOver, onDragLeave, onDrop, ...props }: PromptFieldProps): import("react").JSX.Element;
197
+ declare function PromptField({ layout, className, onDragOver, onDragLeave, onDrop, render, ...props }: PromptFieldProps & RenderProp<'div'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
191
198
  declare namespace PromptField {
192
199
  var displayName: string;
193
200
  }
194
201
  export interface PromptTextareaProps extends Omit<TextareaProps, 'value' | 'defaultValue' | 'onChange' | 'variant'> {
195
202
  }
196
203
  /** Where the message is written. Enter sends, Shift+Enter starts a new line, and pasted files are attached. */
197
- declare function PromptTextarea({ className, minRows, maxRows, onKeyDown, onPaste, 'aria-label': ariaLabel, ...props }: PromptTextareaProps): import("react").JSX.Element;
204
+ declare function PromptTextarea({ className, minRows, maxRows, onKeyDown, onPaste, 'aria-label': ariaLabel, ...props }: PromptTextareaProps): ReactTypes.JSX.Element;
198
205
  declare namespace PromptTextarea {
199
206
  var displayName: string;
200
207
  }
201
208
  export interface PromptAttachmentsProps extends ComponentProps<'ul'> {
202
209
  }
203
210
  /** The files attached so far: images as thumbnails, anything else as a chip. Takes no room while there are none. */
204
- declare function PromptAttachments({ className, 'aria-label': ariaLabel, ...props }: PromptAttachmentsProps): import("react").JSX.Element | null;
211
+ declare function PromptAttachments({ className, 'aria-label': ariaLabel, render, ...props }: PromptAttachmentsProps & RenderProp<'ul'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>> | null;
205
212
  declare namespace PromptAttachments {
206
213
  var displayName: string;
207
214
  }
208
215
  export interface PromptFooterProps extends ComponentProps<'div'> {
209
216
  }
210
217
  /** The row under the text: tools at the start, the submit button at the end. */
211
- declare function PromptFooter({ className, ...props }: PromptFooterProps): import("react").JSX.Element;
218
+ declare function PromptFooter({ className, render, ...props }: PromptFooterProps & RenderProp<'div'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
212
219
  declare namespace PromptFooter {
213
220
  var displayName: string;
214
221
  }
215
222
  export interface PromptToolsProps extends ComponentProps<'div'> {
216
223
  }
217
224
  /** The tools at the start of the footer. Wraps onto a second line where it has to. */
218
- declare function PromptTools({ className, ...props }: PromptToolsProps): import("react").JSX.Element;
225
+ declare function PromptTools({ className, render, ...props }: PromptToolsProps & RenderProp<'div'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
219
226
  declare namespace PromptTools {
220
227
  var displayName: string;
221
228
  }
@@ -230,7 +237,7 @@ export interface PromptToolProps extends Omit<ButtonProps, 'aria-pressed'> {
230
237
  showLabel?: boolean;
231
238
  }
232
239
  /** A round button in the footer, holding an icon. With `pressed`, it switches on and off. */
233
- declare function PromptTool({ label, pressed, onPressedChange, showLabel, onClick, className, children, variant, ...props }: PromptToolProps): import("react").JSX.Element;
240
+ declare function PromptTool({ label, pressed, onPressedChange, showLabel, onClick, className, children, variant, ...props }: PromptToolProps): ReactTypes.JSX.Element;
234
241
  declare namespace PromptTool {
235
242
  var displayName: string;
236
243
  }
@@ -239,7 +246,7 @@ export interface PromptAttachProps extends Omit<PromptToolProps, 'label' | 'pres
239
246
  label?: string;
240
247
  }
241
248
  /** A tool that opens the file picker. Files can also be pasted, or dropped on the field. */
242
- declare function PromptAttach({ label, onClick, children, ...props }: PromptAttachProps): import("react").JSX.Element;
249
+ declare function PromptAttach({ label, onClick, children, ...props }: PromptAttachProps): ReactTypes.JSX.Element;
243
250
  declare namespace PromptAttach {
244
251
  var displayName: string;
245
252
  }
@@ -267,7 +274,7 @@ export interface PromptModelProps {
267
274
  className?: string;
268
275
  }
269
276
  /** Chooses the model the message goes to. The button shows the chosen one's icon and name. */
270
- declare function PromptModel({ items, value, defaultValue, onValueChange, variant, label, className, }: PromptModelProps): import("react").JSX.Element;
277
+ declare function PromptModel({ items, value, defaultValue, onValueChange, variant, label, className, }: PromptModelProps): ReactTypes.JSX.Element;
271
278
  declare namespace PromptModel {
272
279
  var displayName: string;
273
280
  }
@@ -286,7 +293,7 @@ export interface PromptMenuProps extends Omit<MenuContentProps, 'children'> {
286
293
  * message: files, tools, modes. It keeps the footer to one button however
287
294
  * many there are.
288
295
  */
289
- declare function PromptMenu({ label, icon, children, side, align, width, className, ...props }: PromptMenuProps): import("react").JSX.Element;
296
+ declare function PromptMenu({ label, icon, children, side, align, width, className, ...props }: PromptMenuProps): ReactTypes.JSX.Element;
290
297
  declare namespace PromptMenu {
291
298
  var displayName: string;
292
299
  }
@@ -297,7 +304,7 @@ export interface PromptAttachItemProps extends Omit<MenuItemProps, 'children'> {
297
304
  shortcut?: ReactNode;
298
305
  }
299
306
  /** The menu item that opens the file picker. */
300
- declare function PromptAttachItem({ children, shortcut, onClick, ...props }: PromptAttachItemProps): import("react").JSX.Element;
307
+ declare function PromptAttachItem({ children, shortcut, onClick, ...props }: PromptAttachItemProps): ReactTypes.JSX.Element;
301
308
  declare namespace PromptAttachItem {
302
309
  var displayName: string;
303
310
  }
@@ -314,7 +321,7 @@ export interface PromptSubmitProps extends Omit<ButtonProps, 'type' | 'children'
314
321
  voiceLabel?: string;
315
322
  }
316
323
  /** Sends the message. While busy it stops the answer, and with `onVoice` it starts voice while the field is empty. */
317
- declare function PromptSubmit({ onVoice, listening, sendLabel, stopLabel, voiceLabel, onClick, className, disabled, ...props }: PromptSubmitProps): import("react").JSX.Element;
324
+ declare function PromptSubmit({ onVoice, listening, sendLabel, stopLabel, voiceLabel, onClick, className, disabled, ...props }: PromptSubmitProps): ReactTypes.JSX.Element;
318
325
  declare namespace PromptSubmit {
319
326
  var displayName: string;
320
327
  }
@@ -340,7 +347,7 @@ export interface PromptTasksProps extends Omit<ComponentProps<'div'>, 'title'> {
340
347
  * fills as they are done, opening into the list. The list scrolls past
341
348
  * `maxHeight`, and keeps the task in progress in view.
342
349
  */
343
- declare function PromptTasks({ open, mode, title, expanded, defaultExpanded, onExpandedChange, maxHeight, className, children, ...props }: PromptTasksProps): import("react").JSX.Element;
350
+ declare function PromptTasks({ open, mode, title, expanded, defaultExpanded, onExpandedChange, maxHeight, className, children, ...props }: PromptTasksProps): ReactTypes.JSX.Element;
344
351
  declare namespace PromptTasks {
345
352
  var displayName: string;
346
353
  }
@@ -349,7 +356,7 @@ export interface PromptTaskProps extends ComponentProps<'li'> {
349
356
  status?: PromptTaskStatus;
350
357
  }
351
358
  /** One task in `Prompt.Tasks`. */
352
- declare function PromptTask({ status, className, children, ...props }: PromptTaskProps): import("react").JSX.Element;
359
+ declare function PromptTask({ status, className, children, render, ...props }: PromptTaskProps & RenderProp<'li'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
353
360
  declare namespace PromptTask {
354
361
  var displayName: string;
355
362
  }
@@ -382,7 +389,7 @@ export interface PromptCommandsProps {
382
389
  * word, `/sum`. The arrow keys move through it, Enter or Tab chooses, Escape
383
390
  * puts it away.
384
391
  */
385
- declare function PromptCommands({ items, trigger, onSelect, label, maxHeight }: PromptCommandsProps): import("react").JSX.Element;
392
+ declare function PromptCommands({ items, trigger, onSelect, label, maxHeight, }: PromptCommandsProps): ReactTypes.JSX.Element;
386
393
  declare namespace PromptCommands {
387
394
  var displayName: string;
388
395
  }
@@ -410,7 +417,7 @@ export interface PromptRecorderProps extends ComponentProps<'div'> {
410
417
  * has been heard so far, the sound as a wave scrolling to the left, how long
411
418
  * it has been, and buttons to throw it away or keep it.
412
419
  */
413
- declare function PromptRecorder({ transcript, placeholder, onCancel, onDone, level, cancelLabel, doneLabel, className, ...props }: PromptRecorderProps): import("react").JSX.Element;
420
+ declare function PromptRecorder({ transcript, placeholder, onCancel, onDone, level, cancelLabel, doneLabel, className, render, ...props }: PromptRecorderProps & RenderProp<'div'>): ReactElement<unknown, string | ReactTypes.JSXElementConstructor<any>>;
414
421
  declare namespace PromptRecorder {
415
422
  var displayName: string;
416
423
  }