neba 1.1.0 → 1.3.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 (123) hide show
  1. package/README.md +12 -7
  2. package/dist/components/alert/Alert.d.ts +7 -1
  3. package/dist/components/alert/Alert.js +1 -1
  4. package/dist/components/animate-appear/AnimateAppear.d.ts +55 -0
  5. package/dist/components/animate-appear/AnimateAppear.js +1 -0
  6. package/dist/components/animate-appear/index.d.ts +2 -0
  7. package/dist/components/animate-appear/index.js +1 -0
  8. package/dist/components/animate-blink/AnimateBlink.d.ts +31 -0
  9. package/dist/components/animate-blink/AnimateBlink.js +1 -0
  10. package/dist/components/animate-blink/index.d.ts +2 -0
  11. package/dist/components/animate-blink/index.js +1 -0
  12. package/dist/components/animate-fade/AnimateFade.d.ts +31 -0
  13. package/dist/components/animate-fade/AnimateFade.js +1 -0
  14. package/dist/components/animate-fade/index.d.ts +2 -0
  15. package/dist/components/animate-fade/index.js +1 -0
  16. package/dist/components/animate-grow/AnimateGrow.d.ts +41 -0
  17. package/dist/components/animate-grow/AnimateGrow.js +1 -0
  18. package/dist/components/animate-grow/index.d.ts +2 -0
  19. package/dist/components/animate-grow/index.js +1 -0
  20. package/dist/components/animate-headline/AnimateHeadline.d.ts +55 -0
  21. package/dist/components/animate-headline/AnimateHeadline.js +1 -0
  22. package/dist/components/animate-headline/index.d.ts +2 -0
  23. package/dist/components/animate-headline/index.js +1 -0
  24. package/dist/components/animate-lighting/AnimateLighting.d.ts +62 -0
  25. package/dist/components/animate-lighting/AnimateLighting.js +1 -0
  26. package/dist/components/animate-lighting/index.d.ts +2 -0
  27. package/dist/components/animate-lighting/index.js +1 -0
  28. package/dist/components/animate-marquee/AnimateMarquee.d.ts +65 -0
  29. package/dist/components/animate-marquee/AnimateMarquee.js +1 -0
  30. package/dist/components/animate-marquee/index.d.ts +2 -0
  31. package/dist/components/animate-marquee/index.js +1 -0
  32. package/dist/components/animate-rotate/AnimateRotate.d.ts +48 -0
  33. package/dist/components/animate-rotate/AnimateRotate.js +1 -0
  34. package/dist/components/animate-rotate/index.d.ts +2 -0
  35. package/dist/components/animate-rotate/index.js +1 -0
  36. package/dist/components/animate-slide/AnimateSlide.d.ts +46 -0
  37. package/dist/components/animate-slide/AnimateSlide.js +1 -0
  38. package/dist/components/animate-slide/index.d.ts +2 -0
  39. package/dist/components/animate-slide/index.js +1 -0
  40. package/dist/components/animate-typing/AnimateTyping.d.ts +58 -0
  41. package/dist/components/animate-typing/AnimateTyping.js +1 -0
  42. package/dist/components/animate-typing/index.d.ts +2 -0
  43. package/dist/components/animate-typing/index.js +1 -0
  44. package/dist/components/animate-zoom/AnimateZoom.d.ts +37 -0
  45. package/dist/components/animate-zoom/AnimateZoom.js +1 -0
  46. package/dist/components/animate-zoom/index.d.ts +2 -0
  47. package/dist/components/animate-zoom/index.js +1 -0
  48. package/dist/components/aspect-ratio/AspectRatio.d.ts +63 -0
  49. package/dist/components/aspect-ratio/AspectRatio.js +1 -0
  50. package/dist/components/aspect-ratio/index.d.ts +2 -0
  51. package/dist/components/aspect-ratio/index.js +1 -0
  52. package/dist/components/avatar/Avatar.d.ts +106 -0
  53. package/dist/components/avatar/Avatar.js +1 -0
  54. package/dist/components/avatar/index.d.ts +2 -0
  55. package/dist/components/avatar/index.js +1 -0
  56. package/dist/components/blockquote/Blockquote.d.ts +7 -1
  57. package/dist/components/blockquote/Blockquote.js +1 -1
  58. package/dist/components/box/Box.d.ts +7 -1
  59. package/dist/components/box/Box.js +1 -1
  60. package/dist/components/breadcrumb/Breadcrumb.d.ts +92 -0
  61. package/dist/components/breadcrumb/Breadcrumb.js +1 -0
  62. package/dist/components/breadcrumb/index.d.ts +2 -0
  63. package/dist/components/breadcrumb/index.js +1 -0
  64. package/dist/components/chat-bubble/ChatBubble.d.ts +114 -0
  65. package/dist/components/chat-bubble/ChatBubble.js +1 -0
  66. package/dist/components/chat-bubble/index.d.ts +2 -0
  67. package/dist/components/chat-bubble/index.js +1 -0
  68. package/dist/components/chip/Chip.d.ts +7 -1
  69. package/dist/components/chip/Chip.js +1 -1
  70. package/dist/components/color-picker/ColorPicker.d.ts +102 -0
  71. package/dist/components/color-picker/ColorPicker.js +1 -0
  72. package/dist/components/color-picker/index.d.ts +2 -0
  73. package/dist/components/color-picker/index.js +1 -0
  74. package/dist/components/drawer/Drawer.d.ts +145 -0
  75. package/dist/components/drawer/Drawer.js +1 -0
  76. package/dist/components/drawer/index.d.ts +2 -0
  77. package/dist/components/drawer/index.js +1 -0
  78. package/dist/components/icon/Icon.d.ts +8 -1
  79. package/dist/components/icon/Icon.js +1 -1
  80. package/dist/components/otp-field/OtpField.d.ts +85 -0
  81. package/dist/components/otp-field/OtpField.js +1 -0
  82. package/dist/components/otp-field/index.d.ts +2 -0
  83. package/dist/components/otp-field/index.js +1 -0
  84. package/dist/components/panes/Panes.d.ts +78 -0
  85. package/dist/components/panes/Panes.js +1 -0
  86. package/dist/components/panes/index.d.ts +2 -0
  87. package/dist/components/panes/index.js +1 -0
  88. package/dist/components/popover/Popover.d.ts +109 -0
  89. package/dist/components/popover/Popover.js +1 -0
  90. package/dist/components/popover/index.d.ts +2 -0
  91. package/dist/components/popover/index.js +1 -0
  92. package/dist/components/skeleton/Skeleton.d.ts +76 -0
  93. package/dist/components/skeleton/Skeleton.js +1 -0
  94. package/dist/components/skeleton/index.d.ts +2 -0
  95. package/dist/components/skeleton/index.js +1 -0
  96. package/dist/components/spoiler/Spoiler.d.ts +95 -0
  97. package/dist/components/spoiler/Spoiler.js +1 -0
  98. package/dist/components/spoiler/index.d.ts +2 -0
  99. package/dist/components/spoiler/index.js +1 -0
  100. package/dist/components/text-link/TextLink.d.ts +82 -0
  101. package/dist/components/text-link/TextLink.js +1 -0
  102. package/dist/components/text-link/index.d.ts +2 -0
  103. package/dist/components/text-link/index.js +1 -0
  104. package/dist/components/tree-view/TreeView.d.ts +115 -0
  105. package/dist/components/tree-view/TreeView.js +1 -0
  106. package/dist/components/tree-view/index.d.ts +2 -0
  107. package/dist/components/tree-view/index.js +1 -0
  108. package/dist/components/typography/Typography.d.ts +7 -1
  109. package/dist/components/typography/Typography.js +1 -1
  110. package/dist/index.d.ts +24 -0
  111. package/dist/index.js +1 -1
  112. package/dist/internal/animate.d.ts +175 -0
  113. package/dist/internal/animate.js +1 -0
  114. package/dist/internal/color.d.ts +108 -0
  115. package/dist/internal/color.js +1 -0
  116. package/dist/internal/i18n.d.ts +103 -0
  117. package/dist/internal/i18n.js +1 -0
  118. package/dist/internal/icons.d.ts +23 -0
  119. package/dist/internal/icons.js +1 -1
  120. package/dist/styles.css +1 -1
  121. package/dist/tailwind.css +504 -0
  122. package/dist/types.d.ts +112 -0
  123. package/package.json +14 -14
@@ -0,0 +1,78 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaOrientation, NebaSize } from '../../types';
3
+ /**
4
+ * A pane's share of the split, as a percentage of the container or as a CSS
5
+ * length.
6
+ *
7
+ * A bare number is a percentage — that is what a split is usually described in,
8
+ * and a percentage keeps its meaning when the window changes size. A string is
9
+ * an absolute length (`'240px'`, `'15rem'`, `'20%'`), which is what a sidebar
10
+ * with a minimum actually needs: "at least 200 pixels" does not survive being
11
+ * written down as a percentage of a width nobody knows yet.
12
+ */
13
+ export type PaneSize = number | string;
14
+ export interface PanesProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
15
+ /**
16
+ * Which way the panes run. `horizontal` puts them side by side with upright
17
+ * handles between them; `vertical` stacks them.
18
+ * @default 'horizontal'
19
+ */
20
+ orientation?: NebaOrientation;
21
+ /**
22
+ * Whether the handles between the panes can be dragged. Turn it off for a
23
+ * split that is a layout rather than a control.
24
+ * @default true
25
+ */
26
+ resizable?: boolean;
27
+ /** The colour family the handles light up in. @default 'primary' */
28
+ color?: NebaColor;
29
+ /** How thick a handle is, and how far it reaches. @default 'md' */
30
+ size?: NebaSize;
31
+ /** Fires with every pane's share, in percent, while a handle is dragged. */
32
+ onResize?: (sizes: number[]) => void;
33
+ /** Fires once, with the same shape, when the handle is let go. */
34
+ onResizeEnd?: (sizes: number[]) => void;
35
+ /** The Panes. Anything that is not a Pane is still laid out, but has no size. */
36
+ children?: React.ReactNode;
37
+ }
38
+ export interface PaneProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
39
+ /**
40
+ * The share this pane starts with. Panes with no `defaultSize` split whatever
41
+ * is left over equally.
42
+ */
43
+ defaultSize?: PaneSize;
44
+ /** How small it may be dragged. @default 0 */
45
+ minSize?: PaneSize;
46
+ /** How large it may be dragged. Unbounded when left out. */
47
+ maxSize?: PaneSize;
48
+ /** What is inside the pane. */
49
+ children?: React.ReactNode;
50
+ }
51
+ /**
52
+ * A set of panes with draggable handles between them.
53
+ *
54
+ * The panes are sized in **fractions**, written out as
55
+ * `flex-basis: calc((100% - gutters) * fraction)`. That is the one decision the
56
+ * rest of this file follows from: a split described in percentages survives the
57
+ * window being resized without a single line of JavaScript running, so the
58
+ * component measures itself only twice — once on mount, to turn a `'240px'`
59
+ * default into a fraction, and once at the start of each drag, to know what a
60
+ * pixel of pointer movement is worth.
61
+ *
62
+ * The handles are interleaved here rather than written by the caller, so the
63
+ * children of a Panes are just panes. That does mean the direct children have to
64
+ * *be* Panes: the constraints are read off their props, and a Pane wrapped in
65
+ * something else is a pane with no minimum.
66
+ */
67
+ export declare const Panes: React.ForwardRefExoticComponent<PanesProps & React.RefAttributes<HTMLDivElement>>;
68
+ /**
69
+ * One region of a split.
70
+ *
71
+ * It carries no surface of its own on purpose: a Panes is layout, and the moment
72
+ * a pane drew a sheet it would stop being usable as the thing a Card, a Table or
73
+ * an editor is put inside. Put a Box or a Card in it when a surface is wanted.
74
+ *
75
+ * `defaultSize`, `minSize` and `maxSize` are read by the Panes around it rather
76
+ * than used here — a pane cannot know what "half" is, only the split can.
77
+ */
78
+ export declare const Pane: React.ForwardRefExoticComponent<PaneProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{cx as r,transitionClasses as o}from"../../internal/styles";const i=n.createContext({basis:null}),a={xs:"basis-1",sm:"basis-1.5",md:"basis-2",lg:"basis-2.5",xl:"basis-3"},s={xs:4,sm:6,md:8,lg:10,xl:12};function l(e,t,n){if(null==e)return;if("number"==typeof e)return t*e/100;const r=/^\s*(-?[\d.]+)\s*(px|rem|em|%)\s*$/.exec(e);if(!r)return;const o=Number(r[1]);if(!Number.isNaN(o))switch(r[2]){case"px":return o;case"%":return t*o/100;case"rem":return o*parseFloat(getComputedStyle(document.documentElement).fontSize||"16");case"em":return o*parseFloat(n&&getComputedStyle(n).fontSize||"16");default:return}}export const Panes=n.forwardRef(function({orientation:c="horizontal",resizable:u=!0,color:d="primary",size:m="md",onResize:f,onResizeEnd:p,className:h,style:g,children:v,...x},b){const y=n.Children.toArray(v).filter(n.isValidElement),z=y.length,w=n.useRef(null),S=n.useCallback(e=>{w.current=e,"function"==typeof b?b(e):b&&(b.current=e)},[b]),R=n.useRef([]);R.current=y.map(e=>e.props);const[C,E]=n.useState(null),N=C&&C.length===z?C:null,M=n.useRef(null);M.current=N;const L="horizontal"===c,$=s[m]*Math.max(0,z-1);function k(e){const t=w.current,n=M.current;if(!u||!t||!n||void 0===n[e+1])return null;const r=t.getBoundingClientRect(),o=(L?r.width:r.height)-$;if(o<=0)return null;const i=R.current[e],a=R.current[e+1],s=n[e]*o,c=s+n[e+1]*o,d=Math.max(l(i?.minSize,o,t)??0,c-(l(a?.maxSize,o,t)??c)),m=Math.min(l(i?.maxSize,o,t)??c,c-(l(a?.minSize,o,t)??0));return m<d?null:{root:t,current:n,extent:o,start:s,pair:c,resize(t){const r=Math.min(m,Math.max(d,s+t)),i=[...n];return i[e]=r/o,i[e+1]=(c-r)/o,E(i),f?.(i.map(e=>100*e)),i}}}n.useEffect(()=>{const e=w.current;if(!e)return;const t=()=>{const t=e.getBoundingClientRect(),n=(L?t.width:t.height)-$;n<=0||E(t=>t&&t.length===z?t:function(e,t,n){const r=e.map(e=>l(e.defaultSize,t,n)),o=r.reduce((e,t)=>e+(t??0),0),i=r.filter(e=>void 0===e).length,a=i>0?Math.max(0,t-o)/i:0,s=r.map(e=>Math.max(0,e??a)),c=s.reduce((e,t)=>e+t,0);return c<=0?s.map(()=>1/Math.max(1,s.length)):s.map(e=>e/c)}(R.current,n,e))};t();const n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[z,L,$]);const A=r("group/handle relative z-1 flex shrink-0 grow-0 items-center justify-center",a[m],o,"[outline:none] focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-0",u?r(L?"cursor-col-resize":"cursor-row-resize","hover:bg-(--n-soft) data-[dragging]:bg-(--n-soft)"):"");return e("div",{ref:S,className:r("flex h-full w-full",L?"flex-row":"flex-col","min-h-0 min-w-0",h),style:{"--n-accent":`var(--neba-${d}-accent)`,"--n-soft":`var(--neba-${d}-soft)`,"--n-ring":`var(--neba-${d}-ring)`,...g},...x,children:y.map((a,s)=>t(n.Fragment,{children:[s>0?e("div",{role:"separator","aria-orientation":L?"vertical":"horizontal","aria-valuenow":N?Math.round(100*N[s-1]):void 0,"aria-valuemin":0,"aria-valuemax":100,"aria-disabled":!u||void 0,tabIndex:u?0:-1,className:A,onPointerDown:e=>{0===e.button&&function(e,t){const n=k(e);if(!n)return;const r=t.currentTarget;r.setPointerCapture(t.pointerId),r.dataset.dragging="true";const o=document.body.style.userSelect;document.body.style.userSelect="none";const i=L?t.clientX:t.clientY,a=L&&"rtl"===getComputedStyle(n.root).direction?-1:1;let s=n.current;const l=e=>{const t=L?e.clientX:e.clientY;s=n.resize((t-i)*a)},c=()=>{r.removeEventListener("pointermove",l),r.removeEventListener("pointerup",c),r.removeEventListener("pointercancel",c),delete r.dataset.dragging,document.body.style.userSelect=o,p?.(s.map(e=>100*e))};r.addEventListener("pointermove",l),r.addEventListener("pointerup",c),r.addEventListener("pointercancel",c)}(s-1,e)},onKeyDown:e=>{const t=L?"ArrowLeft":"ArrowUp",n=L?"ArrowRight":"ArrowDown";e.key!==t&&e.key!==n||(e.preventDefault(),function(e,t){const n=k(e);if(!n)return;const r=n.resize(t);p?.(r.map(e=>100*e))}(s-1,e.key===n?16:-16))},children:e("span",{"aria-hidden":"true",className:r("pointer-events-none bg-(--neba-border)",o,L?"h-full w-px":"h-px w-full",u?"group-hover/handle:bg-(--n-accent) group-focus-visible/handle:bg-(--n-accent) group-data-[dragging]/handle:bg-(--n-accent)":"")})}):null,e(i.Provider,{value:{basis:N?`calc((100% - ${$}px) * ${N[s].toFixed(6)})`:null},children:a})]},a.key??s))})});export const Pane=n.forwardRef(function({defaultSize:t,minSize:o,maxSize:a,className:s,style:l,children:c,...u},d){const{basis:m}=n.useContext(i);return e("div",{ref:d,className:r("relative min-h-0 min-w-0 overflow-auto",s),style:{flex:m?`0 0 ${m}`:"1 1 0%",...l},...u,children:c})});
@@ -0,0 +1,2 @@
1
+ export { Pane, Panes } from './Panes';
2
+ export type { PaneProps, PaneSize, PanesProps } from './Panes';
@@ -0,0 +1 @@
1
+ export{Pane,Panes}from"./Panes";
@@ -0,0 +1,109 @@
1
+ import * as React from 'react';
2
+ import { Popover as BaseUIPopover } from '@base-ui/react/popover';
3
+ import type { NebaAlign, NebaSide, NebaStyleProps } from '../../types';
4
+ /**
5
+ * A popover takes `size`, `color` and `density` and stops there.
6
+ *
7
+ * There is no `variant` — the three weights answer "how much does this surface
8
+ * assert itself against the page", and a popup that had to be asked for has
9
+ * already been asserted. There is no `elevation` either: a popover floats over
10
+ * the page by definition, so it carries a shadow at level 3 and a prop that
11
+ * could sit it flat would be a prop that could stop it being a popover.
12
+ */
13
+ export interface PopoverProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'> {
14
+ /**
15
+ * The element the popup hangs off and that opens it. Exactly one element,
16
+ * which must accept a ref and spread props — every Neba component does.
17
+ *
18
+ * Optional: a controlled popover anchored from elsewhere needs none, though it
19
+ * then has nothing to position against and will sit against the viewport.
20
+ */
21
+ trigger?: React.ReactElement;
22
+ /** The heading, rendered as the element that names the popup. */
23
+ title?: React.ReactNode;
24
+ /** A line under the title, and the popup's accessible description. */
25
+ description?: React.ReactNode;
26
+ /** The body. */
27
+ children?: React.ReactNode;
28
+ /**
29
+ * Which edge of the trigger it appears on. Flips to the opposite side when
30
+ * there is no room, which is Base UI's doing and is the right behaviour.
31
+ * @default 'bottom'
32
+ */
33
+ side?: NebaSide;
34
+ /** Where it sits along that edge. @default 'center' */
35
+ align?: NebaAlign;
36
+ /** Distance from the trigger, in pixels. @default 6 */
37
+ sideOffset?: number;
38
+ /** Shift along that edge, in pixels. @default 0 */
39
+ alignOffset?: number;
40
+ /**
41
+ * Draws the little wedge pointing at the trigger.
42
+ *
43
+ * Off by default, unlike on [Tooltip](../feedback/tooltip). A tooltip is a
44
+ * filled plate and its wedge is the same solid colour; this surface is
45
+ * translucent over a blurred backdrop, and a wedge sticking out past the
46
+ * popup's own box cannot carry that backdrop with it. Turn it on where the
47
+ * trigger is far enough away that the popup needs to say what it belongs to.
48
+ * @default false
49
+ */
50
+ arrow?: boolean;
51
+ /** Whether the popover is open. Use with `onOpenChange` for a controlled one. */
52
+ open?: boolean;
53
+ /** Whether it starts open, for an uncontrolled one. */
54
+ defaultOpen?: boolean;
55
+ onOpenChange?: (open: boolean) => void;
56
+ /**
57
+ * Whether the page behind is taken away. `false` — the default — leaves the
58
+ * page scrollable and clickable, which is what separates a popover from a
59
+ * [Dialog](../feedback/dialog): it is a detail beside the page, not instead of
60
+ * it. `'trap-focus'` holds focus inside without locking the scroll.
61
+ * @default false
62
+ */
63
+ modal?: boolean | 'trap-focus';
64
+ /**
65
+ * Whether pressing Escape or clicking outside closes the popup. Turn it off
66
+ * only for a popup with its own way out, because there will be no other.
67
+ * @default true
68
+ */
69
+ dismissible?: boolean;
70
+ /** Shows the × in the corner. @default false */
71
+ showClose?: boolean;
72
+ /** Accessible name of the × button. */
73
+ closeLabel?: string;
74
+ /**
75
+ * A hard cap on the popup's width, overriding the one `size` implies. Numbers
76
+ * are pixels. For the popover whose content decides its width — a form, a
77
+ * single line of help — rather than for tuning the scale, which is `size`.
78
+ */
79
+ width?: number | string;
80
+ className?: string;
81
+ style?: React.CSSProperties;
82
+ }
83
+ export type PopoverCloseProps = React.ComponentPropsWithoutRef<typeof BaseUIPopover.Close>;
84
+ /**
85
+ * Closes the popover it is inside.
86
+ *
87
+ * Exported for the reason `DialogClose` is: an uncontrolled popover has no
88
+ * `setOpen` for its Cancel button to call, and making every popover controlled
89
+ * is a piece of state per popover that exists only to answer a button.
90
+ *
91
+ * `render` is Base UI's own escape hatch, so a real Neba button dismisses:
92
+ * `<PopoverClose render={<Button variant="text">Cancel</Button>} />`.
93
+ */
94
+ export declare const PopoverClose: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").PopoverCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
95
+ /**
96
+ * A sheet that opens beside the thing that opened it.
97
+ *
98
+ * The difference from a [Tooltip](../feedback/tooltip) is that this one can be
99
+ * reached: it stays up until it is dismissed, it can be entered with the
100
+ * pointer or the keyboard, and what is inside it can be clicked and typed into.
101
+ * The difference from a [Dialog](../feedback/dialog) is that it does not take
102
+ * the page — it is anchored to a control, and the page behind goes on working.
103
+ *
104
+ * Base UI owns everything hard about it: the anchoring and the flip at the
105
+ * window edge, the click-outside and Escape, returning focus to the trigger, and
106
+ * the `aria-labelledby` / `aria-describedby` wiring. What is left here is the
107
+ * surface, the width ladder and the header.
108
+ */
109
+ export declare function Popover({ size, color, density, trigger, title, description, children, side, align, sideOffset, alignOffset, arrow, open, defaultOpen, onOpenChange, modal, dismissible, showClose, closeLabel, width, className, style }: PopoverProps): React.JSX.Element;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Popover as o}from"@base-ui/react/popover";import{boxPaddingXClasses as t,boxPaddingYClasses as n}from"../box/Box";import{CloseIcon as s}from"../../internal/icons";import{hasContent as i,metaTextClasses as l,radiusClasses as r,sheetBodyClasses as d,sheetHeaderGapClasses as c,sheetSectionGapClasses as m,sheetTitleClasses as p,surfaceClasses as f,surfaceSlots as u}from"../../internal/styles";const h={xs:"max-w-56",sm:"max-w-64",md:"max-w-80",lg:"max-w-96",xl:"max-w-lg"},x=[f,"relative flex flex-col","border text-(--neba-fg) bg-(--n-panel-press)","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),b={xs:8,sm:9,md:10,lg:11,xl:12};export const PopoverClose=o.Close;export function Popover({size:f="md",color:g="primary",density:v="default",trigger:w,title:y,description:N,children:_,side:k="bottom",align:j="center",sideOffset:O=6,alignOffset:C=0,arrow:P=!1,open:z,defaultOpen:$,onOpenChange:B,modal:L=!1,dismissible:M=!0,showClose:T=!1,closeLabel:W="Close",width:A,className:D,style:E}){const R=t[v][f],q=n[v][f],F=b[f],G=i(y)||i(N);return a(o.Root,{open:z,defaultOpen:$,modal:L,onOpenChange:(e,a)=>{M||e||"escape-key"!==a.reason&&"outside-press"!==a.reason&&"focus-out"!==a.reason?B?.(e):a.cancel()},children:[w?e(o.Trigger,{render:w}):null,e(o.Portal,{children:e(o.Positioner,{className:"neba-portal z-50 [outline:none]",side:k,align:j,sideOffset:O,alignOffset:C,children:a(o.Popup,{className:[x,r[f],d[f],m[f],R,q,void 0===A?h[f]:"",D??""].filter(Boolean).join(" "),style:{...u(g,3),...void 0===A?null:{maxWidth:"number"==typeof A?`${A}px`:A},...E},children:[P?e(o.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:a("svg",{width:F,height:F/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:[e("path",{d:"M0 0h10L5 5z",fill:"var(--n-panel-press)"}),e("path",{d:"M0 0 5 5 10 0",fill:"none",stroke:"var(--n-line)",strokeWidth:"1",vectorEffect:"non-scaling-stroke"})]})}):null,G||T?a("div",{className:"flex shrink-0 items-start gap-3",children:[a("div",{className:`flex min-w-0 flex-1 flex-col ${c[f]}`,children:[i(y)?e(o.Title,{className:`m-0 font-semibold ${p[f]}`,children:y}):null,i(N)?e(o.Description,{className:`m-0 text-(--neba-muted-fg) ${l[f]}`,children:N}):null]}),T?e(o.Close,{"aria-label":W,className:["flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center","rounded-full text-(--neba-muted-fg)","[&_svg]:size-[1.1em] [&_svg]:shrink-0","[transition:background-color_var(--neba-duration)_var(--neba-ease),color_var(--neba-duration)_var(--neba-ease)]","hover:bg-(--n-soft) hover:text-(--neba-fg)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),children:e(s,{})}):null]}):null,i(_)?e("div",{className:"min-w-0",children:_}):null]})})})]})}
@@ -0,0 +1,2 @@
1
+ export { Popover, PopoverClose } from './Popover';
2
+ export type { PopoverCloseProps, PopoverProps } from './Popover';
@@ -0,0 +1 @@
1
+ export{Popover,PopoverClose}from"./Popover";
@@ -0,0 +1,76 @@
1
+ import * as React from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import type { NebaColor, NebaSize } from '../../types';
4
+ /**
5
+ * What the placeholder is standing in for.
6
+ *
7
+ * - `line` — a run of text. Sized off the type scale, so a `md` line is exactly
8
+ * as tall as the `md` type it will be replaced by.
9
+ * - `rect` — a block: an image, a chart, a card, a map.
10
+ * - `circle` — an avatar, or anything else round.
11
+ */
12
+ export type NebaSkeletonShape = 'line' | 'rect' | 'circle';
13
+ export interface SkeletonProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
14
+ /** @default 'line' */
15
+ shape?: NebaSkeletonShape;
16
+ /**
17
+ * How many lines to draw, for `shape="line"`. The last one is drawn short, the
18
+ * way the last line of a paragraph is, so a block of them reads as prose
19
+ * rather than as a barcode. Ignored by the other two shapes.
20
+ * @default 1
21
+ */
22
+ lines?: number;
23
+ /**
24
+ * The scale of the thing being stood in for: the type scale for a `line`, the
25
+ * diameter for a `circle`, the default block height for a `rect`.
26
+ * @default 'md'
27
+ */
28
+ size?: NebaSize;
29
+ /**
30
+ * Colour family. `secondary` by default, and it is worth leaving there: a
31
+ * placeholder that carries a semantic colour is saying something about content
32
+ * that has not arrived yet.
33
+ * @default 'secondary'
34
+ */
35
+ color?: NebaColor;
36
+ /** An explicit width. Numbers are pixels. */
37
+ width?: number | string;
38
+ /** An explicit height. Numbers are pixels. */
39
+ height?: number | string;
40
+ /**
41
+ * The travelling highlight. Turn it off for a page holding dozens of them, or
42
+ * where the wait is expected to be long enough that motion becomes noise.
43
+ *
44
+ * A reduced-motion preference already replaces the sweep with a colour pulse
45
+ * without being asked, so this is not the accessibility switch.
46
+ * @default true
47
+ */
48
+ animated?: boolean;
49
+ /**
50
+ * What a screen reader is told, if anything.
51
+ *
52
+ * Unset — the default — the placeholder is `aria-hidden`, because a dozen
53
+ * boxes each announcing themselves is worse than silence. Give the *one*
54
+ * skeleton that stands for the whole region a label and it becomes a live
55
+ * `status` instead.
56
+ */
57
+ label?: string;
58
+ /**
59
+ * Renders something other than a `<div>`. Base UI's own escape hatch.
60
+ */
61
+ render?: useRender.RenderProp;
62
+ }
63
+ /**
64
+ * The shape of something that has not loaded yet.
65
+ *
66
+ * It reserves the space the real thing will take, which is the whole job: a card
67
+ * that grows by 200px when its image arrives has moved everything below it while
68
+ * somebody was reading. A spinner cannot do that, which is why this is not a
69
+ * [ProgressCircular](../feedback/progress-circular) in a box.
70
+ *
71
+ * The three shapes are the three things a layout is made of — a run of text, a
72
+ * block and a circle — and each is sized off the ladder the real component uses,
73
+ * so a `md` line is as tall as `md` type and a `md` circle is exactly an
74
+ * [Avatar](../display/avatar) at `md`.
75
+ */
76
+ export declare const Skeleton: React.ForwardRefExoticComponent<SkeletonProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e}from"react/jsx-runtime";import*as r from"react";import{useRender as l}from"@base-ui/react/use-render";import{controlHeightClasses as n,controlSquareClasses as d,surfaceSlots as o}from"../../internal/styles";const a={xs:"h-[0.6875rem]",sm:"h-[0.75rem]",md:"h-[0.8125rem]",lg:"h-[0.9375rem]",xl:"h-[1.0625rem]"},s={xs:"gap-[0.3125rem]",sm:"gap-[0.375rem]",md:"gap-[0.5625rem]",lg:"gap-[0.5625rem]",xl:"gap-[0.6875rem]"},m={xs:"rounded-[0.3125rem]",sm:"rounded-[0.3125rem]",md:"rounded-[0.375rem]",lg:"rounded-[0.4375rem]",xl:"rounded-[0.5rem]"},i={xs:"h-12",sm:"h-16",md:"h-20",lg:"h-28",xl:"h-36"},t={xs:"rounded-(--neba-radius-xs)",sm:"rounded-(--neba-radius-sm)",md:"rounded-(--neba-radius-md)",lg:"rounded-(--neba-radius-lg)",xl:"rounded-(--neba-radius-xl)"},u="relative overflow-hidden bg-(--n-soft-hover)";function f(e){if(void 0!==e)return"number"==typeof e?`${e}px`:e}export const Skeleton=r.forwardRef(function({shape:r="line",lines:h=1,size:c="md",color:x="secondary",width:g,height:p,animated:b=!0,label:w,render:y,className:$,style:v,...j},k){const N=b?"neba-skeleton":"",B="circle"===r?`rounded-full ${n[c]} ${d[c]} shrink-0`:"rect"===r?`w-full ${t[c]} ${void 0===p?i[c]:""}`:`w-full ${m[c]} ${a[c]}`,z=w?{role:"status","aria-busy":!0,"aria-label":w}:{"aria-hidden":!0},A="line"===r&&h>1;return l({render:y,ref:k,props:{className:(A?["flex w-full flex-col",s[c],$??""]:[u,N,B,$??""]).filter(Boolean).join(" "),style:{...o(x,0),width:f(g),height:f(p),...v},...z,...A?{children:Array.from({length:h},(r,l)=>e("div",{className:[u,N,m[c],a[c],l===h-1?"w-3/5":"w-full"].filter(Boolean).join(" ")},l))}:null,...j}})});
@@ -0,0 +1,2 @@
1
+ export { Skeleton } from './Skeleton';
2
+ export type { NebaSkeletonShape, SkeletonProps } from './Skeleton';
@@ -0,0 +1 @@
1
+ export{Skeleton}from"./Skeleton";
@@ -0,0 +1,95 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaDensity, NebaElevation, NebaSize, NebaVariant } from '../../types';
3
+ export interface SpoilerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'onChange'> {
4
+ /** Whether the content is uncovered. Pass it to drive the Spoiler yourself. */
5
+ revealed?: boolean;
6
+ /**
7
+ * Where an uncontrolled Spoiler starts.
8
+ * @default false
9
+ */
10
+ defaultRevealed?: boolean;
11
+ /** Called when the reveal or hide button is pressed. */
12
+ onRevealedChange?: (revealed: boolean) => void;
13
+ /**
14
+ * Which language the default label and notice are written in — a BCP 47 tag
15
+ * such as `ko`, `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
16
+ *
17
+ * Both strings can be written out instead, in `label` and `description`; this
18
+ * is for the far more common case where the page already knows its language
19
+ * and nobody should have to translate a button that says "Reveal".
20
+ */
21
+ locale?: string;
22
+ /** The reveal button's label. Defaults to the `locale`'s word for it. */
23
+ label?: React.ReactNode;
24
+ /** The hide button's label, when `reversible` is on. */
25
+ hideLabel?: React.ReactNode;
26
+ /**
27
+ * The line above the button, saying why the content is covered. Defaults to
28
+ * the `locale`'s wording; pass `false` for a cover with nothing written on it.
29
+ */
30
+ description?: React.ReactNode | false;
31
+ /**
32
+ * Replaces the default reveal button entirely.
33
+ *
34
+ * The replacement is yours to wire up: pass `revealed` and
35
+ * `onRevealedChange` and drive it from your own control. `label` is the prop
36
+ * for the far commoner case of wanting different words on the button that is
37
+ * already there.
38
+ */
39
+ action?: React.ReactNode;
40
+ /**
41
+ * Keeps the content coverable: once revealed, a hide button appears under it.
42
+ * @default false
43
+ */
44
+ reversible?: boolean;
45
+ /**
46
+ * Clamps the covered box to this height — a CSS length, or a number in
47
+ * pixels. Revealing releases it and the content takes whatever height it
48
+ * needs.
49
+ *
50
+ * Left out, the box is exactly as tall as what it holds, which is the right
51
+ * default for a paragraph or a picture. Set it for something long enough that
52
+ * a page of blurred content would be a page of nothing.
53
+ */
54
+ maxHeight?: number | string;
55
+ /**
56
+ * How hard the content is blurred, in pixels.
57
+ * @default 10
58
+ */
59
+ blur?: number;
60
+ /**
61
+ * Inner padding around the content, on Box's own `size`/`density` scale. Turn
62
+ * it off for something that should reach the edges — a picture, a video.
63
+ * @default true
64
+ */
65
+ padded?: boolean;
66
+ /**
67
+ * Weight of the box's surface. `text` draws no box at all, which is what a
68
+ * spoiler sitting inside running prose usually wants.
69
+ * @default 'outline'
70
+ */
71
+ variant?: NebaVariant;
72
+ /** The sheet's radius, and the size of the button on it. @default 'md' */
73
+ size?: NebaSize;
74
+ /** @default 'primary' */
75
+ color?: NebaColor;
76
+ /** Padding around the cover's own text and button. @default 'default' */
77
+ density?: NebaDensity;
78
+ /** Drop shadow depth. `0` (the default) is flat. @default 0 */
79
+ elevation?: NebaElevation;
80
+ /** What is being covered. */
81
+ children?: React.ReactNode;
82
+ }
83
+ /**
84
+ * Content that is covered until somebody asks for it.
85
+ *
86
+ * The cover is a blur rather than a `display: none`, which is the whole point:
87
+ * a reader can see that there is something there, roughly how much of it there
88
+ * is, and — with `maxHeight` — that it has been clamped. What they cannot do is
89
+ * read it by accident, which is the one thing a spoiler is for.
90
+ *
91
+ * While it is covered the content is `inert`, so it is not tabbable, not
92
+ * readable by a screen reader and not selectable by a drag across the page. A
93
+ * spoiler that could be defeated by Ctrl-A is not a spoiler.
94
+ */
95
+ export declare const Spoiler: React.ForwardRefExoticComponent<SpoilerProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as i from"react";import{Button as n}from"../button/Button";import{useMessages as o}from"../../internal/i18n";import{boxPaddingClasses as a,boxPaddingXClasses as l,boxPaddingYClasses as t}from"../box/Box";import{hasContent as s,metaTextClasses as d,radiusClasses as c,surfaceClasses as m,surfaceSlots as v,transitionClasses as f}from"../../internal/styles";const p={solid:[m,"bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[m,"border bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"bg-transparent"},u="[background-color:color-mix(in_oklab,var(--neba-surface)_55%,transparent)]";export const Spoiler=i.forwardRef(function({revealed:m,defaultRevealed:b=!1,onRevealedChange:x,locale:h,label:j,hideLabel:g,description:y,action:w,reversible:N=!1,maxHeight:k,blur:z=10,padded:B=!0,variant:_="outline",size:C="md",color:R="primary",density:H="default",elevation:S=0,className:$,style:I,children:L,...q},A){const D=o(h),E=i.useId(),[F,G]=i.useState(b),J=m??F,K=e=>{void 0===m&&G(e),x?.(e)},M=!1===y?null:y??D.spoiler.notice;return r("div",{ref:A,className:["relative isolate overflow-hidden",c[C],p[_],f,$??""].filter(Boolean).join(" "),style:{...v(R,S),...I},...q,children:[e("div",{id:E,className:["min-w-0",B?a[H][C]:"","[transition:filter_var(--neba-duration-fill)_var(--neba-ease)]","motion-reduce:[transition-duration:0ms]",J?"":"select-none"].filter(Boolean).join(" "),style:{filter:J?void 0:`blur(${z}px)`,maxHeight:J?void 0:k,overflow:J?void 0:"hidden"},inert:!J,children:L}),J?null:r("div",{className:["absolute inset-0 z-10 flex flex-col items-center justify-center gap-2 text-center",a[H][C],u].join(" "),children:[s(M)?e("p",{className:`m-0 text-(--neba-muted-fg) ${d[C]}`,children:M}):null,w??e(n,{size:C,color:R,density:H,onClick:()=>K(!0),"aria-expanded":!1,"aria-controls":E,children:j??D.spoiler.reveal})]}),J&&N?e("div",{className:["flex justify-end",l[H][C],t[H][C],"pt-0"].join(" "),children:e(n,{variant:"text",size:C,color:R,density:H,onClick:()=>K(!1),"aria-expanded":!0,"aria-controls":E,children:g??D.spoiler.hide})}):null]})});
@@ -0,0 +1,2 @@
1
+ export { Spoiler } from './Spoiler';
2
+ export type { SpoilerProps } from './Spoiler';
@@ -0,0 +1 @@
1
+ export{Spoiler}from"./Spoiler";
@@ -0,0 +1,82 @@
1
+ import * as React from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import type { NebaColor, NebaSize } from '../../types';
4
+ /**
5
+ * When the line under a link is drawn.
6
+ *
7
+ * `always` is the default, and the reason is `color`: a TextLink takes no
8
+ * colour family unless one is asked for, so with the line off there would be
9
+ * nothing at all distinguishing a link from the sentence it sits in. That is
10
+ * also why this is not a boolean — "no underline" is a real choice for a link
11
+ * in a nav bar or a footer, where position already says what it is, and it
12
+ * should have to be spelled out rather than fallen into.
13
+ */
14
+ export type TextLinkUnderline = 'always' | 'hover' | 'none';
15
+ export interface TextLinkProps extends Omit<React.ComponentPropsWithoutRef<'a'>, 'color'> {
16
+ /** Where the link goes. */
17
+ href: string;
18
+ /**
19
+ * When the underline is drawn.
20
+ * @default 'always'
21
+ */
22
+ underline?: TextLinkUnderline;
23
+ /**
24
+ * Semantic colour role. Like [Typography](../display/typography) and unlike
25
+ * every control in the library this has **no default** — a link in a
26
+ * paragraph is usually the paragraph's own colour with a line under it, and a
27
+ * component that arrived pre-dyed is one a page has to undo.
28
+ */
29
+ color?: NebaColor;
30
+ /**
31
+ * The type scale. Also no default: a link inside a sentence is the size of
32
+ * the sentence. Set it for a link that stands on its own.
33
+ */
34
+ size?: NebaSize;
35
+ /**
36
+ * Opens the link in a new tab, with the `rel` that keeps the new page from
37
+ * reaching back into this one.
38
+ *
39
+ * A window changing under the reader is the one thing about a link that
40
+ * cannot be seen before it happens, so this also turns `icon` on by default
41
+ * and adds a line for a screen reader — see `locale`.
42
+ * @default false
43
+ */
44
+ newTab?: boolean;
45
+ /**
46
+ * The mark after the label. `true` draws the arrow leaving its box when
47
+ * `newTab` is on and the chain otherwise, `false` draws nothing, and a node
48
+ * of your own replaces the glyph.
49
+ *
50
+ * Left out, it follows `newTab`.
51
+ */
52
+ icon?: React.ReactNode | boolean;
53
+ /**
54
+ * Which language the line for a screen reader is written in — a BCP 47 tag
55
+ * such as `ko`, `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
56
+ *
57
+ * Only `newTab` produces that line; a link without it says nothing of its
58
+ * own, so this changes nothing.
59
+ */
60
+ locale?: string;
61
+ /**
62
+ * Renders something other than an `<a>` — the `Link` a router brings, most
63
+ * of the time. `href` still goes through, so `render={<NextLink href="…" />}`
64
+ * needs it written once, on the TextLink.
65
+ */
66
+ render?: useRender.RenderProp;
67
+ /** The label. */
68
+ children?: React.ReactNode;
69
+ }
70
+ /**
71
+ * A link, in a sentence or on its own.
72
+ *
73
+ * Everything about it is deliberately smaller than a Button. It has no surface,
74
+ * no height of its own and no colour unless asked — what it has is a line under
75
+ * it, which is the one mark a reader already knows means "this goes somewhere".
76
+ *
77
+ * The three things it does that a bare `<a>` does not: it draws that line on a
78
+ * schedule (`always`, or only under the pointer), it marks a link that opens a
79
+ * new tab both visibly and for a screen reader, and it takes `render`, so the
80
+ * `Link` a router brings can wear all of it.
81
+ */
82
+ export declare const TextLink: React.ForwardRefExoticComponent<TextLinkProps & React.RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as n,Fragment as e,jsxs as r}from"react/jsx-runtime";import*as i from"react";import{useRender as o}from"@base-ui/react/use-render";import{useMessages as a}from"../../internal/i18n";import{ExternalLinkIcon as t,LinkIcon as l}from"../../internal/icons";import{controlTextLeadingClasses as s,focusRingClasses as c,srOnlyClasses as m}from"../../internal/styles";const d={always:"[&.neba-link]:underline",hover:"[&.neba-link]:no-underline [&.neba-link]:hover:underline",none:"[&.neba-link]:no-underline"},u=["neba-link","cursor-pointer","[&_svg]:pointer-events-none [&_svg]:inline [&_svg]:size-[0.95em] [&_svg]:shrink-0",["[transition-property:color,text-decoration-color]","[transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]"].join(" "),c,"focus-visible:rounded-[0.25rem]"].join(" ");export const TextLink=i.forwardRef(function({href:i,underline:c="always",color:p,size:b,newTab:f=!1,icon:v,locale:h,render:k,className:g,style:x,children:y,...j},w){const _=a(h),N=v??f,T=!0===N?n(f?t:l,{}):N,z=[u,b?s[b]:"",d[c],p?"[&.neba-link]:text-(--n-accent)":"[&.neba-link]:text-inherit",g??""].filter(Boolean).join(" "),C={"--n-underline":"color-mix(in oklab, currentColor 45%, transparent)","--n-underline-hover":"currentColor","--n-ring":`var(--neba-${p??"primary"}-ring)`,...p?{"--n-accent":`var(--neba-${p}-accent)`}:null};return o({render:k??n("a",{}),ref:w,props:{href:i,target:f?"_blank":void 0,rel:f?"noopener noreferrer":void 0,className:z,style:{...C,...x},children:r(e,{children:[y,T?n("span",{className:"ms-[0.25em]",children:T}):null,f?r(e,{children:[" ",n("span",{className:m,children:_.link.newTab})]}):null]}),...j}})});
@@ -0,0 +1,2 @@
1
+ export { TextLink } from './TextLink';
2
+ export type { TextLinkProps, TextLinkUnderline } from './TextLink';
@@ -0,0 +1 @@
1
+ export{TextLink}from"./TextLink";
@@ -0,0 +1,115 @@
1
+ import * as React from 'react';
2
+ import type { NebaElevation, NebaStyleProps } from '../../types';
3
+ /**
4
+ * How the hierarchy is drawn.
5
+ *
6
+ * - `none` — indentation only. The quietest, and usually right for a navigation
7
+ * sidebar, where the tree is two levels deep and the labels say what the
8
+ * structure is.
9
+ * - `simple` — one hairline rail per level, running the full height of the
10
+ * group. Enough to follow a column of rows back to the branch it belongs to.
11
+ * - `folder` — the rail plus an elbow into every row, and the rail under a last
12
+ * child stops at that row. The file-manager drawing, and the one to reach for
13
+ * when the tree is deep.
14
+ */
15
+ export type TreeViewLines = 'none' | 'simple' | 'folder';
16
+ /** A row's identity, and what `expanded` and `selected` are lists of. */
17
+ export type TreeViewValue = string | number;
18
+ export interface TreeViewProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'ul'>, 'color' | 'defaultValue' | 'onSelect'> {
19
+ /**
20
+ * Drop shadow depth. `0` (the default) is flat.
21
+ * @default 0
22
+ */
23
+ elevation?: NebaElevation;
24
+ /**
25
+ * How the hierarchy is drawn between the rows.
26
+ * @default 'simple'
27
+ */
28
+ lines?: TreeViewLines;
29
+ /** Which branches are open. Use with `onExpandedChange` for a controlled tree. */
30
+ expanded?: TreeViewValue[];
31
+ /** Which start open, for an uncontrolled one. */
32
+ defaultExpanded?: TreeViewValue[];
33
+ onExpandedChange?: (expanded: TreeViewValue[]) => void;
34
+ /**
35
+ * Which rows are chosen. An array even when only one row may be chosen at a
36
+ * time — the same shape Accordion's `value` takes, so turning `multiple` on
37
+ * does not also change the type of the value.
38
+ */
39
+ selected?: TreeViewValue[];
40
+ /** Which start chosen, for an uncontrolled one. */
41
+ defaultSelected?: TreeViewValue[];
42
+ onSelectedChange?: (selected: TreeViewValue[]) => void;
43
+ /**
44
+ * Whether more than one row may be chosen at a time.
45
+ * @default false
46
+ */
47
+ multiple?: boolean;
48
+ /** Unavailable. Every row stops answering. */
49
+ disabled?: boolean;
50
+ /** The name the tree is announced by. */
51
+ label?: string;
52
+ /** The top-level TreeItems. */
53
+ children?: React.ReactNode;
54
+ }
55
+ export interface TreeItemProps extends Omit<React.ComponentPropsWithoutRef<'li'>, 'color' | 'onClick'> {
56
+ /**
57
+ * Identifies the row to `expanded` and `selected`. One is generated when it is
58
+ * left out, which is fine for a tree nobody drives from code.
59
+ */
60
+ value?: TreeViewValue;
61
+ /**
62
+ * The row's text. Its own prop rather than `children`, because in a tree the
63
+ * children are the rows underneath it.
64
+ */
65
+ label?: React.ReactNode;
66
+ /** Content before the label — a folder glyph, a file type, a status dot. */
67
+ startIcon?: React.ReactNode;
68
+ /** Content after the label, inside the pressable area — a count, a badge. */
69
+ endIcon?: React.ReactNode;
70
+ /**
71
+ * A control pinned to the end of the row.
72
+ *
73
+ * Deliberately outside the pressable area, the same shape ListItem uses: a
74
+ * row that both opens and holds a menu button has two things to press.
75
+ */
76
+ action?: React.ReactNode;
77
+ /** Renders the row as a link, for a tree that is navigation. */
78
+ href?: string;
79
+ /** Fires when the row is pressed, before it opens or is chosen. */
80
+ onClick?: React.MouseEventHandler<HTMLElement>;
81
+ /**
82
+ * Forces the disclosure arrow onto a row with no children yet — the branch
83
+ * that is fetched the first time it is opened.
84
+ */
85
+ expandable?: boolean;
86
+ /** Unavailable. Its branch, if it is open, keeps working. */
87
+ disabled?: boolean;
88
+ /** The rows underneath this one. */
89
+ children?: React.ReactNode;
90
+ }
91
+ /**
92
+ * A tree of rows that open and shut.
93
+ *
94
+ * There is no Base UI primitive under this: the library has no tree, and the
95
+ * three things a tree owes — the `tree`/`treeitem`/`group` roles, one tab stop
96
+ * for the whole widget, and the arrow keys that walk it — are most of the
97
+ * component.
98
+ *
99
+ * The keyboard is handled once, here, rather than on every row. A tree's arrow
100
+ * keys are questions about the *tree* ("what is the next visible row", "where is
101
+ * my parent"), and the only element that can answer them is the one holding all
102
+ * of them. The rows the query returns are in document order, which is reading
103
+ * order, because a shut branch is unmounted rather than hidden.
104
+ */
105
+ export declare const TreeView: React.ForwardRefExoticComponent<TreeViewProps & React.RefAttributes<HTMLUListElement>>;
106
+ /**
107
+ * One row, and everything under it.
108
+ *
109
+ * The `<li>` is the `treeitem` and it is what takes focus — not the row drawn
110
+ * inside it. That is the ARIA pattern, and it is also why the disclosure arrow
111
+ * is a plain span with a click handler rather than a button: a button inside the
112
+ * focusable row would be a second tab stop in a widget that is supposed to have
113
+ * exactly one, and the keyboard already opens a branch with ArrowRight.
114
+ */
115
+ export declare const TreeItem: React.ForwardRefExoticComponent<TreeItemProps & React.RefAttributes<HTMLLIElement>>;