neba 1.1.0 β†’ 1.2.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 (42) hide show
  1. package/README.md +9 -6
  2. package/dist/components/avatar/Avatar.d.ts +100 -0
  3. package/dist/components/avatar/Avatar.js +1 -0
  4. package/dist/components/avatar/index.d.ts +2 -0
  5. package/dist/components/avatar/index.js +1 -0
  6. package/dist/components/breadcrumb/Breadcrumb.d.ts +92 -0
  7. package/dist/components/breadcrumb/Breadcrumb.js +1 -0
  8. package/dist/components/breadcrumb/index.d.ts +2 -0
  9. package/dist/components/breadcrumb/index.js +1 -0
  10. package/dist/components/chat-bubble/ChatBubble.d.ts +114 -0
  11. package/dist/components/chat-bubble/ChatBubble.js +1 -0
  12. package/dist/components/chat-bubble/index.d.ts +2 -0
  13. package/dist/components/chat-bubble/index.js +1 -0
  14. package/dist/components/otp-field/OtpField.d.ts +85 -0
  15. package/dist/components/otp-field/OtpField.js +1 -0
  16. package/dist/components/otp-field/index.d.ts +2 -0
  17. package/dist/components/otp-field/index.js +1 -0
  18. package/dist/components/panes/Panes.d.ts +78 -0
  19. package/dist/components/panes/Panes.js +1 -0
  20. package/dist/components/panes/index.d.ts +2 -0
  21. package/dist/components/panes/index.js +1 -0
  22. package/dist/components/spoiler/Spoiler.d.ts +95 -0
  23. package/dist/components/spoiler/Spoiler.js +1 -0
  24. package/dist/components/spoiler/index.d.ts +2 -0
  25. package/dist/components/spoiler/index.js +1 -0
  26. package/dist/components/text-link/TextLink.d.ts +82 -0
  27. package/dist/components/text-link/TextLink.js +1 -0
  28. package/dist/components/text-link/index.d.ts +2 -0
  29. package/dist/components/text-link/index.js +1 -0
  30. package/dist/components/tree-view/TreeView.d.ts +115 -0
  31. package/dist/components/tree-view/TreeView.js +1 -0
  32. package/dist/components/tree-view/index.d.ts +2 -0
  33. package/dist/components/tree-view/index.js +1 -0
  34. package/dist/index.d.ts +8 -0
  35. package/dist/index.js +1 -1
  36. package/dist/internal/i18n.d.ts +78 -0
  37. package/dist/internal/i18n.js +1 -0
  38. package/dist/internal/icons.d.ts +23 -0
  39. package/dist/internal/icons.js +1 -1
  40. package/dist/styles.css +1 -1
  41. package/dist/tailwind.css +125 -0
  42. package/package.json +9 -9
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### πŸ“˜ [**neba.cdget.com**](https://neba.cdget.com)
8
8
 
9
- [![Components](https://img.shields.io/badge/All_components-live_previews-444?style=for-the-badge)](https://neba.cdget.com/examples/)
9
+ [![Components](https://img.shields.io/badge/All_components-live_previews-444?style=for-the-badge)](https://neba.cdget.com/examples/overview)
10
10
 
11
11
  Live previews and full props for every component. This README is just the quick start.
12
12
 
@@ -32,10 +32,11 @@ Everything is documented at **[neba.cdget.com](https://neba.cdget.com)**, where
32
32
  | --- | --- |
33
33
  | [**Getting started**](https://neba.cdget.com/guide/getting-started) | Install and setup, end to end. |
34
34
  | [**All components**](https://neba.cdget.com/components/) | Every component, one page each: live previews and the full props table. |
35
- | [**Examples**](https://neba.cdget.com/examples/) | A whole sample screen, explained block by block. |
35
+ | [**Examples**](https://neba.cdget.com/examples/overview) | A whole sample screen explained block by block, plus three concept screens β€” a landing page, an admin dashboard and a sign-up flow. |
36
36
  | [**Design language**](https://neba.cdget.com/design/design-language) | Why a Neba surface looks and behaves the way it does. |
37
37
  | [**Prop conventions**](https://neba.cdget.com/design/prop-conventions) | The shared vocabulary every component draws from. |
38
38
  | [**Color**](https://neba.cdget.com/design/color) | The token families, and how to theme them. |
39
+ | [**Changelog**](https://neba.cdget.com/changelog) | What changed in each release, and the setup changes worth acting on. |
39
40
 
40
41
  Also available in Korean / ν•œκ΅­μ–΄ λ¬Έμ„œ: **[neba.cdget.com/ko/](https://neba.cdget.com/ko/)**
41
42
 
@@ -110,15 +111,17 @@ Placement props are logical, not physical β€” `start`/`end` rather than `left`/`
110
111
 
111
112
  ### Components
112
113
 
113
- **Inputs** β€” Button, IconButton, ButtonGroup, SegmentedButton, TextField, NumberField, Select, Combobox, Checkbox, RadioGroup, Switch, Slider, Menu (with submenus, checkbox and radio items), ContextMenu, FilePicker, Pagination, DatePicker, TimePicker, DateTimePicker, DateRangePicker
114
+ **Inputs** β€” Button, IconButton, ButtonGroup, SegmentedButton, TextField, NumberField, OtpField, Select, Combobox, Checkbox, RadioGroup, Switch, Slider, Menu (with submenus, checkbox and radio items), ContextMenu, FilePicker, Pagination, DatePicker, TimePicker, DateTimePicker, DateRangePicker
114
115
 
115
- **Surfaces** β€” Box, Card, Accordion, Tabs, Carousel, Toolbar, Pill
116
+ **Surfaces** β€” Box, Card, Accordion, Tabs, Carousel, Toolbar, Pill, Spoiler, ChatBubble
116
117
 
117
- **Display** β€” Typography, Blockquote, Highlight, Divider, Chip, Badge, Icon, Shortcut, Statistic, List, Table, Timeline
118
+ **Display** β€” Typography, TextLink, Blockquote, Highlight, Divider, Chip, Badge, Avatar, Icon, Shortcut, Statistic, List, Table, Timeline, Breadcrumb, TreeView
118
119
 
119
120
  **Feedback** β€” Alert, Dialog, Toast, Tooltip, Overlay, ProgressLinear, ProgressCircular, ProgressBox
120
121
 
121
- Recent additions: **Blockquote** (somebody else's words, with the `figure`/`figcaption` markup the spec actually asks for), **Shortcut** (a keyboard key or combination, where `Mod` resolves to Command on a Mac and Control everywhere else, and every glyph carries its name for a screen reader), **Highlight** (marks the words a reader searched for, walking into elements rather than demanding a plain string), **SegmentedButton** (exactly one of a set, in one pill, with a tile that slides between the choices and transforms nothing), and **Timeline** (a sequence of steps in the order they happen, vertical or as a horizontal stepper); before those, the four pickers β€” **DatePicker**, **TimePicker**, **DateTimePicker** and **DateRangePicker** β€” which take and return a plain `Date` and add no date library to your bundle.
122
+ **Layout** β€” Container, Grid (with GridContainer), Panes
123
+
124
+ Recent additions: **ChatBubble** (one message in a conversation, where the avatar, the time, the delivery mark, the media and the link card are each drawn only when given something), **Spoiler** (content covered by a blur rather than hidden, so a reader can see there is something there without reading it by accident), **TextLink** (a link with no surface of its own, and a mark for the ones that take over the window), **Avatar** (falls back to initials, a glyph or a silhouette, so it is never an empty box), **TreeView**, **Breadcrumb**, **Panes** (regions with a draggable bar between each pair) and **OtpField**; before those, **Blockquote**, **Shortcut**, **Highlight**, **SegmentedButton** and **Timeline**, and the four pickers β€” **DatePicker**, **TimePicker**, **DateTimePicker** and **DateRangePicker** β€” which take and return a plain `Date` and add no date library to your bundle.
122
125
 
123
126
  Each one has its own page β€” live previews, every prop, and the variations worth seeing β€” under [**All components**](https://neba.cdget.com/components/).
124
127
 
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaElevation, NebaSize, NebaVariant } from '../../types';
3
+ /** What Base UI reports about the picture as it loads. */
4
+ export type AvatarLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error';
5
+ /**
6
+ * The crop, not the sheet.
7
+ *
8
+ * `circle` is the default, and it is the one place besides Badge where the
9
+ * library draws something without a flat run along its edge. The reasoning is
10
+ * Badge's: the cut acrylic edge is what says "this is a surface", and an avatar
11
+ * is not a surface β€” it is a portrait laid on one. A round crop is what a
12
+ * portrait has been for as long as there have been portraits.
13
+ *
14
+ * `square` cuts the corners off instead, which is what a logo or a repository
15
+ * icon wants: those are drawn to the edges of a rectangle and a round crop eats
16
+ * them.
17
+ */
18
+ export type AvatarShape = 'circle' | 'square';
19
+ export interface AvatarProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
20
+ /**
21
+ * The picture. Until it loads β€” and forever, if it fails β€” the fallback is
22
+ * what is drawn, so an avatar is never an empty box.
23
+ */
24
+ src?: string;
25
+ /** Candidate images at other resolutions, as on any `<img>`. */
26
+ srcSet?: string;
27
+ /**
28
+ * What the picture says, for a reader who cannot see it. Defaults to `name`,
29
+ * and to nothing at all when there is no name β€” an avatar next to the person's
30
+ * own name in the row is decoration, and reading it out says the name twice.
31
+ */
32
+ alt?: string;
33
+ /**
34
+ * Who or what this is. One prop doing three jobs: it names the picture, the
35
+ * initials are derived from it, and it is the sentence a screen reader hears
36
+ * instead of those initials.
37
+ *
38
+ * The initials are the first character of the first word plus the first
39
+ * character of the last β€” "Jane Doe" is `JD`, "홍길동" is `홍`. That rule is
40
+ * wrong for some names, which is what `initials` is for.
41
+ */
42
+ name?: string;
43
+ /** The initials, written out, for when the rule derived the wrong ones. */
44
+ initials?: string;
45
+ /**
46
+ * The crop.
47
+ * @default 'circle'
48
+ */
49
+ shape?: AvatarShape;
50
+ /**
51
+ * Weight of the surface behind the fallback. Invisible once a picture has
52
+ * loaded, apart from the edge it keeps.
53
+ * @default 'text'
54
+ */
55
+ variant?: NebaVariant;
56
+ /**
57
+ * The box the picture is drawn in β€” the control heights, so an avatar and the
58
+ * button beside it in a toolbar are the same height.
59
+ * @default 'md'
60
+ */
61
+ size?: NebaSize;
62
+ /** @default 'primary' */
63
+ color?: NebaColor;
64
+ /**
65
+ * Drop shadow depth. `0` (the default) is flat.
66
+ * @default 0
67
+ */
68
+ elevation?: NebaElevation;
69
+ /**
70
+ * How long to wait before drawing the fallback, in milliseconds. Set it to
71
+ * roughly the time a cached image takes and the initials stop flashing up in
72
+ * front of a picture that was about to arrive anyway.
73
+ */
74
+ delay?: number;
75
+ /** Anything else the `<img>` needs β€” `loading`, `crossOrigin`, `referrerPolicy`. */
76
+ imageProps?: Omit<React.ComponentPropsWithoutRef<'img'>, 'src' | 'srcSet' | 'alt'>;
77
+ /** Called as the picture moves between `idle`, `loading`, `loaded` and `error`. */
78
+ onLoadingStatusChange?: (status: AvatarLoadingStatus) => void;
79
+ /**
80
+ * The fallback, drawn instead of the initials. An icon, a logo, a single
81
+ * emoji β€” whatever stands in for this particular thing when there is no
82
+ * picture of it.
83
+ */
84
+ children?: React.ReactNode;
85
+ }
86
+ /**
87
+ * A picture of a person or a thing, at a known size, that is never an empty box.
88
+ *
89
+ * Three things can be drawn in it and exactly one of them is at a time: the
90
+ * picture, if `src` is given and loads; otherwise whatever stands in for it β€”
91
+ * `children`, or `initials`, or the initials derived from `name`; and failing
92
+ * all of those, a silhouette. Which one is showing is Base UI's `Avatar` to
93
+ * decide, because "has the image loaded" is a question with four answers and a
94
+ * race in the middle of it.
95
+ *
96
+ * It carries no status dot of its own. An avatar with a green mark on it is a
97
+ * [Badge](./badge) with an avatar in it, and inventing a second spelling for
98
+ * that would give the library two of them.
99
+ */
100
+ export declare const Avatar: React.ForwardRefExoticComponent<AvatarProps & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{Avatar as n}from"@base-ui/react/avatar";import{controlHeightClasses as a,controlSlots as o,controlSquareClasses as l,hasContent as s,srOnlyClasses as i,surfaceClasses as d,transitionClasses as c}from"../../internal/styles";const m={xs:"text-[0.5625rem]",sm:"text-[0.6875rem]",md:"text-[0.8125rem]",lg:"text-[1rem]",xl:"text-[1.1875rem]"},f={xs:"rounded-[0.375rem]",sm:"rounded-[0.4375rem]",md:"rounded-[0.5625rem]",lg:"rounded-[0.6875rem]",xl:"rounded-[0.875rem]"},u={solid:[d,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev)]"].join(" "),outline:[d,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev)]"].join(" "),text:"text-(--n-accent) bg-(--n-soft-press) [box-shadow:var(--n-elev)]"},x="after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit]",h={solid:`${x} after:[box-shadow:var(--neba-plate-solid)]`,outline:`${x} after:[box-shadow:var(--neba-plate-glass)]`,text:""},v=["relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden","align-middle font-semibold tracking-wide whitespace-nowrap leading-none","[&_svg]:pointer-events-none [&_svg]:size-[55%]",c].join(" ");function p(){return r("svg",{viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",children:[e("path",{d:"M12 12a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9Z"}),e("path",{d:"M12 14.25c-4.28 0-7.75 2.42-7.75 5.4 0 .75.6 1.35 1.35 1.35h12.8c.75 0 1.35-.6 1.35-1.35 0-2.98-3.47-5.4-7.75-5.4Z"})]})}export const Avatar=t.forwardRef(function({src:t,srcSet:d,alt:c,name:x,initials:g,shape:b="circle",variant:w="text",size:j="md",color:y="primary",elevation:N=0,delay:z,imageProps:C,onLoadingStatusChange:A,className:B,style:S,children:k,...L},F){const M=x?function(e){const r=e.normalize("NFC").trim().split(/\s+/).filter(Boolean);return 0===r.length?"":((Array.from(r[0])[0]??"")+(r.length>1?Array.from(r[r.length-1])[0]??"":"")).toLocaleUpperCase()}(x):"",R=c??x,Z=s(k)?k:(g??M)||e(p,{}),$=s(k)||Boolean(g??M),_=[v,a[j],l[j],m[j],"circle"===b?"rounded-full":f[j],u[w],h[w],B??""].filter(Boolean).join(" ");return r(n.Root,{ref:F,className:_,style:{...o(y,N,w),...S},...L,children:[t?e(n.Image,{src:t,srcSet:d,alt:R??"",className:"size-full object-cover",onLoadingStatusChange:A,...C}):null,r(n.Fallback,{delay:t?z:void 0,className:"flex size-full items-center justify-center",children:[R&&$?e("span",{className:i,children:R}):null,e("span",{"aria-hidden":!(!R||!$)||void 0,className:"contents",children:Z})]})]})});
@@ -0,0 +1,2 @@
1
+ export { Avatar } from './Avatar';
2
+ export type { AvatarLoadingStatus, AvatarProps, AvatarShape } from './Avatar';
@@ -0,0 +1 @@
1
+ export{Avatar}from"./Avatar";
@@ -0,0 +1,92 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaDensity, NebaSize } from '../../types';
3
+ /**
4
+ * What is drawn between two steps of the trail.
5
+ *
6
+ * Four named marks rather than a free-for-all, because a separator is read
7
+ * hundreds of times a day and the difference between them is meaning, not
8
+ * decoration: a `chevron` and an `arrow` say "and then", a `slash` says "path",
9
+ * a `dot` says "these are peers of one thing". Anything else can still be passed
10
+ * as a node.
11
+ */
12
+ export type BreadcrumbSeparator = 'chevron' | 'arrow' | 'slash' | 'dot';
13
+ export interface BreadcrumbProps extends Omit<React.ComponentPropsWithoutRef<'nav'>, 'color'> {
14
+ /** @default 'md' */
15
+ size?: NebaSize;
16
+ /** The colour family a link picks up when it is hovered. @default 'primary' */
17
+ color?: NebaColor;
18
+ /** How tightly the steps pack. Spacing only. @default 'default' */
19
+ density?: NebaDensity;
20
+ /**
21
+ * The mark between two steps. One of the four names, or any node.
22
+ * @default 'chevron'
23
+ */
24
+ separator?: BreadcrumbSeparator | React.ReactNode;
25
+ /**
26
+ * How many steps to show before the middle is folded away behind a `…`.
27
+ * Left out, the whole trail is shown however long it gets.
28
+ */
29
+ maxItems?: number;
30
+ /** How many steps stay at the front of a folded trail. @default 1 */
31
+ itemsBeforeCollapse?: number;
32
+ /** How many stay at the end. @default 1 */
33
+ itemsAfterCollapse?: number;
34
+ /**
35
+ * Whether pressing the `…` unfolds the trail in place. Turn it off to leave
36
+ * the fold as a plain mark.
37
+ * @default true
38
+ */
39
+ expandable?: boolean;
40
+ /** The name the trail is announced by. @default 'Breadcrumb' */
41
+ label?: string;
42
+ /** What the `…` is announced as. @default 'Show hidden steps' */
43
+ expandLabel?: string;
44
+ /** The BreadcrumbItems. */
45
+ children?: React.ReactNode;
46
+ }
47
+ export interface BreadcrumbItemProps extends Omit<React.ComponentPropsWithoutRef<'li'>, 'color' | 'onClick'> {
48
+ /** Renders the step as a link. */
49
+ href?: string;
50
+ /** Fires when the step is pressed. Renders it as a button when there is no `href`. */
51
+ onClick?: React.MouseEventHandler<HTMLElement>;
52
+ /** Content before the label β€” a home glyph, a repository avatar. */
53
+ startIcon?: React.ReactNode;
54
+ /** Content after the label. */
55
+ endIcon?: React.ReactNode;
56
+ /**
57
+ * Marks this step as the page you are on, which stops it being a link.
58
+ *
59
+ * The last step is the current one on its own, so this is only needed for a
60
+ * trail that ends somewhere the reader is not β€” and setting it anywhere takes
61
+ * the mark off the last step, because only one step in a trail can be it.
62
+ */
63
+ current?: boolean;
64
+ /** Unavailable. Stops answering, keeps its place in the trail. */
65
+ disabled?: boolean;
66
+ /** The step's label. */
67
+ children?: React.ReactNode;
68
+ }
69
+ /**
70
+ * The trail of pages above the one being read.
71
+ *
72
+ * Two things make this more than a row of links. The first is that the last step
73
+ * is where the reader already is, so it is not a link at all β€” it carries
74
+ * `aria-current="page"` and stops being pressable, and the component works that
75
+ * out rather than asking every caller to remember it. The second is the fold: a
76
+ * trail seven levels deep is a trail nobody reads, so the middle collapses to a
77
+ * `…` that puts it back when pressed.
78
+ *
79
+ * The separators are drawn by the trail rather than by the steps. A step does
80
+ * not know whether anything follows it, and a mark that belonged to a step would
81
+ * have to be taken off the last one by hand.
82
+ */
83
+ export declare const Breadcrumb: React.ForwardRefExoticComponent<BreadcrumbProps & React.RefAttributes<HTMLElement>>;
84
+ /**
85
+ * One step of the trail.
86
+ *
87
+ * It renders three different things and the caller picks by what they pass: an
88
+ * `<a>` with an `href`, a `<button>` with an `onClick`, and a plain `<span>` with
89
+ * neither β€” which is what the last step is, because the page you are already on
90
+ * is not somewhere to go.
91
+ */
92
+ export declare const BreadcrumbItem: React.ForwardRefExoticComponent<BreadcrumbItemProps & React.RefAttributes<HTMLLIElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as a,Fragment as n}from"react/jsx-runtime";import*as t from"react";import{ArrowRightIcon as s,ChevronIcon as r,EllipsisIcon as l}from"../../internal/icons";import{controlTextClasses as i,cx as c,gapClasses as o,hasContent as m,iconClasses as d,radiusClasses as f,transitionClasses as u}from"../../internal/styles";const h=t.createContext({size:"md",last:!1}),p={default:{xs:"gap-1",sm:"gap-1.5",md:"gap-2",lg:"gap-2.5",xl:"gap-3"},compact:{xs:"gap-0.5",sm:"gap-1",md:"gap-1",lg:"gap-1.5",xl:"gap-2"}},x={xs:f.xs,sm:f.xs,md:f.xs,lg:f.sm,xl:f.sm};const b=["chevron","arrow","slash","dot"];export const Breadcrumb=t.forwardRef(function({size:n="md",color:o="primary",density:m="default",separator:f="chevron",maxItems:x,itemsBeforeCollapse:g=1,itemsAfterCollapse:v=1,expandable:N=!0,label:y="Breadcrumb",expandLabel:w="Show hidden steps",className:k,style:C,children:B,...z},I){const[_,j]=t.useState(!1),M=t.Children.toArray(B).filter(t.isValidElement),$=M.length,A=M.some(e=>!0===e.props.current),F=!_&&void 0!==x&&$>Math.max(x,1)&&$-g-v>1?[...M.slice(0,Math.max(0,g)),null,...M.slice($-Math.max(0,v))]:M,R="string"==typeof(S=f)&&b.includes(S)?function(a){switch(a){case"chevron":return e("span",{className:"flex -rotate-90 items-center rtl:rotate-90",children:e(r,{})});case"arrow":return e("span",{className:"flex items-center rtl:rotate-180",children:e(s,{})});case"slash":return e("span",{className:"opacity-70",children:"/"});case"dot":return e("span",{className:"opacity-70",children:"Β·"});default:return null}}(f):f;var S;const E=c("inline-flex items-center rounded-(--neba-radius-xs) px-0.5","text-(--neba-muted-fg)",u,d,N?c("cursor-pointer hover:bg-(--n-soft) hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1"):"");return e("nav",{ref:I,"aria-label":y,className:c("flex",i[n],d,k),style:{"--n-accent":`var(--neba-${o}-accent)`,"--n-soft":`var(--neba-${o}-soft)`,"--n-ring":`var(--neba-${o}-ring)`,...C},...z,children:e("ol",{role:"list",className:c("flex list-none flex-wrap items-center p-0",p[m][n]),children:F.map((s,r)=>a(t.Fragment,{children:[r>0?e("li",{"aria-hidden":"true",className:"flex shrink-0 items-center text-(--neba-muted-fg) select-none",children:R}):null,s?e(h.Provider,{value:{size:n,last:!A&&r===F.length-1},children:s}):e("li",{className:"flex shrink-0 items-center",children:N?e("button",{type:"button",className:E,"aria-label":w,onClick:()=>j(!0),children:e(l,{})}):e("span",{className:E,"aria-hidden":"true",children:e(l,{})})})]},s?s.key??r:"fold"))})})});export const BreadcrumbItem=t.forwardRef(function({href:s,onClick:r,startIcon:l,endIcon:i,current:d,disabled:f=!1,className:p,children:b,...g},v){const{size:N,last:y}=t.useContext(h),w=d??y,k=Boolean(s||r)&&!w&&!f,C=c("inline-flex min-w-0 items-center px-1",o[N],x[N],u,f?"cursor-not-allowed text-(--neba-disabled-fg)":w?"font-medium text-(--neba-fg)":k?c("cursor-pointer text-(--neba-muted-fg)","hover:bg-(--n-soft) hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1"):"text-(--neba-muted-fg)"),B=a(n,{children:[m(l)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:l}):null,e("span",{className:"truncate",children:b}),m(i)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:i}):null]});return e("li",{ref:v,className:c("flex min-w-0 items-center",p),...g,children:k&&s?e("a",{href:s,className:C,onClick:r,children:B}):k?e("button",{type:"button",className:C,onClick:r,children:B}):e("span",{className:C,"aria-current":w?"page":void 0,"aria-disabled":f||void 0,children:B})})});
@@ -0,0 +1,2 @@
1
+ export { Breadcrumb, BreadcrumbItem } from './Breadcrumb';
2
+ export type { BreadcrumbItemProps, BreadcrumbProps, BreadcrumbSeparator } from './Breadcrumb';
@@ -0,0 +1 @@
1
+ export{Breadcrumb,BreadcrumbItem}from"./Breadcrumb";
@@ -0,0 +1,114 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaDensity, NebaElevation, NebaSize, NebaVariant } from '../../types';
3
+ /**
4
+ * Whose message this is.
5
+ *
6
+ * `start` and `end` rather than `them`/`me` or `left`/`right`: a thread runs the
7
+ * way the language does, and the same two words already mean this everywhere
8
+ * else in the library. `start` is the default because a message from someone
9
+ * else is the one you have no other way of knowing about.
10
+ */
11
+ export type ChatBubbleSide = 'start' | 'end';
12
+ /**
13
+ * How far a message has got.
14
+ *
15
+ * The four steps are a ladder and the fifth is not on it: `failed` is the
16
+ * message that did not go, which is why it is the only one drawn in another
17
+ * colour family.
18
+ */
19
+ export type ChatBubbleStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
20
+ /** What a link inside a message unfurls to. */
21
+ export interface ChatBubbleLinkPreview {
22
+ /** Where the card goes. */
23
+ url: string;
24
+ /** The page's title. */
25
+ title?: React.ReactNode;
26
+ /** Its summary, clamped to two lines. */
27
+ description?: React.ReactNode;
28
+ /** The share image, drawn across the top of the card. */
29
+ image?: string;
30
+ /** Who published it β€” a domain, a site name. */
31
+ site?: React.ReactNode;
32
+ /** Opens the card in a new tab. @default false */
33
+ newTab?: boolean;
34
+ }
35
+ export interface ChatBubbleProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title'> {
36
+ /**
37
+ * Whose message this is.
38
+ * @default 'start'
39
+ */
40
+ side?: ChatBubbleSide;
41
+ /** Who sent it, above the bubble. */
42
+ name?: React.ReactNode;
43
+ /** When it was sent, beside the name. */
44
+ time?: React.ReactNode;
45
+ /**
46
+ * The sender's picture β€” an [Avatar](../display/avatar), at the size the
47
+ * thread uses. Left out, the bubble takes the whole row.
48
+ */
49
+ avatar?: React.ReactNode;
50
+ /**
51
+ * How far the message has got, drawn as a mark under the bubble. Left out,
52
+ * nothing is drawn β€” a received message has no delivery state worth showing.
53
+ */
54
+ status?: ChatBubbleStatus;
55
+ /** Overrides the word the mark is read out as. */
56
+ statusLabel?: string;
57
+ /**
58
+ * Draws the three dots instead of the message. What `children` holds is left
59
+ * alone, so the same bubble can go back to it when the message arrives.
60
+ * @default false
61
+ */
62
+ typing?: boolean;
63
+ /**
64
+ * A picture, a video, a map β€” drawn edge to edge above the text, so the
65
+ * bubble's corners crop it.
66
+ */
67
+ media?: React.ReactNode;
68
+ /** A link in the message, unfurled into a card under the text. */
69
+ preview?: ChatBubbleLinkPreview;
70
+ /**
71
+ * The message's own actions β€” a [Menu](../inputs/menu) trigger, most of the
72
+ * time. Sits beside the bubble and stays out of the way until the row is
73
+ * hovered or something in it takes focus.
74
+ */
75
+ actions?: React.ReactNode;
76
+ /**
77
+ * Which language the marks are read out in β€” a BCP 47 tag such as `ko`,
78
+ * `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
79
+ */
80
+ locale?: string;
81
+ /**
82
+ * Weight of the bubble's surface. `solid` is the usual way to tell your own
83
+ * messages from everyone else's; `side` deliberately does not decide this,
84
+ * because which end is filled is a decision about the product, not about the
85
+ * component.
86
+ * @default 'outline'
87
+ */
88
+ variant?: NebaVariant;
89
+ /** @default 'md' */
90
+ size?: NebaSize;
91
+ /** @default 'primary' */
92
+ color?: NebaColor;
93
+ /** Padding inside the bubble, and nothing else. @default 'default' */
94
+ density?: NebaDensity;
95
+ /** Drop shadow depth. `0` (the default) is flat. @default 0 */
96
+ elevation?: NebaElevation;
97
+ /** The message. */
98
+ children?: React.ReactNode;
99
+ }
100
+ /**
101
+ * One message in a conversation.
102
+ *
103
+ * Everything around the bubble is optional and nothing about it is fixed by
104
+ * `side`: the avatar, the sender's name, the time, the delivery mark, the media
105
+ * above the text and the link card below it are each drawn only when they are
106
+ * given something. What `side` decides is which way the row runs and which
107
+ * corner of the sheet is cut short.
108
+ *
109
+ * `variant` is what tells your own messages from everyone else's, and it is
110
+ * deliberately not tied to `side` β€” filling the right-hand column is a
111
+ * convention, not a law, and a thread that fills neither is a perfectly good
112
+ * thread.
113
+ */
114
+ export declare const ChatBubble: React.ForwardRefExoticComponent<ChatBubbleProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as r from"react";import{useMessages as a}from"../../internal/i18n";import{CheckIcon as l,ClockIcon as i,LinkIcon as t,severityIcons as o}from"../../internal/icons";import{controlSlots as s,hasContent as c,metaTextClasses as d,radiusClasses as m,sheetBodyClasses as p,sheetHeaderGapClasses as u,srOnlyClasses as b,surfaceClasses as f,transitionClasses as v}from"../../internal/styles";const x={default:{xs:"px-2 py-1",sm:"px-2.5 py-1.5",md:"px-3 py-2",lg:"px-3.5 py-2.5",xl:"px-4 py-3"},compact:{xs:"px-1.5 py-0.5",sm:"px-2 py-1",md:"px-2.5 py-1.5",lg:"px-3 py-1.5",xl:"px-3.5 py-2"}},h={start:"[border-start-start-radius:0.25rem]",end:"[border-start-end-radius:0.25rem]"},g={solid:[f,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[f,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-(--n-soft) [box-shadow:var(--n-elev)]"};function y(){return n("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[e("path",{d:"m1.5 8.5 2.75 2.75L9.5 6",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round"}),e("path",{d:"M7 10.75 8.25 12l5.25-5.25",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round"})]})}const w={sending:e(i,{}),sent:e(l,{}),delivered:e(y,{}),read:e(y,{}),failed:o.danger},N={sending:"text-(--neba-muted-fg)",sent:"text-(--neba-muted-fg)",delivered:"text-(--neba-muted-fg)",read:"text-(--n-accent)",failed:"text-(--neba-danger-accent)"},k=["block overflow-hidden rounded-(--neba-radius-sm) border no-underline","[border-color:color-mix(in_oklab,currentColor_18%,transparent)]","[background-color:color-mix(in_oklab,currentColor_7%,transparent)]","hover:[background-color:color-mix(in_oklab,currentColor_12%,transparent)]","[transition-property:background-color] [transition-duration:var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),_=["shrink-0 opacity-0","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","group-hover/bubble:opacity-100 group-focus-within/bubble:opacity-100","[@media(hover:none)]:opacity-100"].join(" ");export const ChatBubble=r.forwardRef(function({side:r="start",name:l,time:i,avatar:t,status:o,statusLabel:f,typing:y=!1,media:k,preview:L,actions:z,locale:B,variant:W="outline",size:M="md",color:R="primary",density:T="default",elevation:$=0,className:q,style:A,children:D,...E},F){const G=a(B),H="end"===r,I=c(l)||c(i),J=y||c(D)||Boolean(L),K=["flex min-w-0 flex-col overflow-hidden",m[M],h[r],g[W],v].join(" "),O=o?f??G.chat[o]:"";return n("div",{ref:F,className:["group/bubble flex w-full items-start gap-2",H?"flex-row-reverse":"",q??""].filter(Boolean).join(" "),style:{...s(R,$,W),...A},...E,children:[c(t)?e("div",{className:"shrink-0",children:t}):null,n("div",{className:["flex min-w-0 max-w-[min(100%,32rem)] flex-col",u[M],H?"items-end":"items-start"].join(" "),children:[I?n("div",{className:`flex items-baseline gap-2 ${d[M]}`,children:[c(l)?e("span",{className:"font-semibold",children:l}):null,c(i)?e("span",{className:"text-(--neba-muted-fg)",children:i}):null]}):null,n("div",{className:"flex min-w-0 items-center gap-1 "+(H?"flex-row-reverse":""),children:[n("div",{className:K,children:[c(k)?e("div",{className:"[&_img]:block [&_img]:w-full [&_video]:block [&_video]:w-full",children:k}):null,J?n("div",{className:[x[T][M],"flex min-w-0 flex-col gap-2",p[M]].join(" "),children:[y?e(j,{label:G.chat.typing}):c(D)?e("div",{className:"min-w-0 break-words whitespace-pre-line",children:D}):null,L?e(C,{preview:L}):null]}):null]}),c(z)?e("div",{className:_,children:z}):null]}),o?n("div",{className:["flex items-center gap-1",d[M],N[o],"[&_svg]:size-[1.15em] [&_svg]:shrink-0"].join(" "),children:[w[o],e("span",{className:b,children:O})]}):null]})]})});function j({label:r}){return n("div",{className:"flex items-center gap-1 py-[0.35em]",role:"status",children:[[0,1,2].map(n=>e("span",{"aria-hidden":"true",className:"neba-typing-dot size-[0.45em] rounded-full",style:{"--n-i":n}},n)),e("span",{className:b,children:r})]})}function C({preview:r}){const{url:a,title:l,description:i,image:o,site:s,newTab:d=!1}=r;return n("a",{href:a,target:d?"_blank":void 0,rel:d?"noopener noreferrer":void 0,className:k,children:[o?e("img",{src:o,alt:"",className:"block h-28 w-full object-cover"}):null,n("div",{className:"flex flex-col gap-0.5 p-2",children:[c(s)?n("span",{className:"flex items-center gap-1 text-[0.85em] opacity-70 [&_svg]:size-[1em] [&_svg]:shrink-0",children:[e(t,{}),e("span",{className:"truncate",children:s})]}):null,c(l)?e("span",{className:"font-semibold",children:l}):null,c(i)?e("span",{className:"line-clamp-2 text-[0.9em] opacity-80",children:i}):null]})]})}
@@ -0,0 +1,2 @@
1
+ export { ChatBubble } from './ChatBubble';
2
+ export type { ChatBubbleLinkPreview, ChatBubbleProps, ChatBubbleSide, ChatBubbleStatus } from './ChatBubble';
@@ -0,0 +1 @@
1
+ export{ChatBubble}from"./ChatBubble";
@@ -0,0 +1,85 @@
1
+ import * as React from 'react';
2
+ import type { NebaElevation, NebaStyleProps } from '../../types';
3
+ /**
4
+ * What may be typed into a slot.
5
+ *
6
+ * `numeric` is the default because that is what a texted code is, and it is also
7
+ * what puts a number pad in front of a phone. `any` accepts whatever the
8
+ * keyboard produces β€” for a licence key with punctuation in it.
9
+ */
10
+ export type OtpFieldCharset = 'numeric' | 'alpha' | 'alphanumeric' | 'any';
11
+ export interface OtpFieldProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange' | 'children'> {
12
+ /**
13
+ * Drop shadow depth. `0` (the default) is flat.
14
+ * @default 0
15
+ */
16
+ elevation?: NebaElevation;
17
+ /**
18
+ * How many characters the code has. Clamped to 2–12: a single box is a
19
+ * TextField, and past twelve the row stops fitting a phone.
20
+ * @default 6
21
+ */
22
+ length?: number;
23
+ /**
24
+ * What may be typed. Anything rejected is dropped rather than shown, and
25
+ * `onValueInvalid` reports it.
26
+ * @default 'numeric'
27
+ */
28
+ charset?: OtpFieldCharset;
29
+ /** Hides the characters, the way a password field does. @default false */
30
+ mask?: boolean;
31
+ /**
32
+ * Splits the row every `groupSize` slots with a separator. `3` on a six digit
33
+ * code gives the familiar two blocks of three.
34
+ */
35
+ groupSize?: number;
36
+ /** What is drawn between two groups. @default '–' */
37
+ separator?: React.ReactNode;
38
+ /** The code. Use with `onValueChange` for a controlled field. */
39
+ value?: string;
40
+ /** What it starts as, for an uncontrolled one. */
41
+ defaultValue?: string;
42
+ onValueChange?: (value: string) => void;
43
+ /** Fires once every slot is filled β€” the moment to verify the code. */
44
+ onComplete?: (value: string) => void;
45
+ /** Fires when typed or pasted text held characters the charset rejects. */
46
+ onValueInvalid?: (value: string) => void;
47
+ /** Submits the owning form as soon as the code is complete. @default false */
48
+ autoSubmit?: boolean;
49
+ /** Label above the row, wired to the slots by Base UI's Field. */
50
+ label?: React.ReactNode;
51
+ /** Helper text below the row. */
52
+ description?: React.ReactNode;
53
+ /** Error message below the row. Its presence also turns the field invalid. */
54
+ error?: React.ReactNode;
55
+ /**
56
+ * Forces the invalid state without a message β€” for when a form library owns
57
+ * the validity. Defaults to whether `error` has content.
58
+ */
59
+ invalid?: boolean;
60
+ /** Identifies the field when a form is submitted. */
61
+ name?: string;
62
+ /** The form must have a complete code before it submits. @default false */
63
+ required?: boolean;
64
+ /** Unavailable. Every slot stops answering. */
65
+ disabled?: boolean;
66
+ /** Readable and copyable, but not typeable. @default false */
67
+ readOnly?: boolean;
68
+ /** Puts the caret in the first slot on mount. @default false */
69
+ autoFocus?: boolean;
70
+ }
71
+ /**
72
+ * A row of one-character slots: a PIN, a texted verification code, an invite
73
+ * key.
74
+ *
75
+ * Base UI owns everything that makes this harder than it looks β€” one hidden
76
+ * value behind however many inputs, paste spread across the slots from wherever
77
+ * the caret was, backspace stepping back a box, a click landing on the first
78
+ * empty slot rather than the one under the pointer, and the autofill hook that
79
+ * lets a phone offer the code straight from the message.
80
+ *
81
+ * What is here is the ladder a slot is drawn on and the field shell it shares
82
+ * with TextField and Select β€” a slot is a field-shaped box, and a form holding
83
+ * both should not look like two form kits stacked on each other.
84
+ */
85
+ export declare const OtpField: React.ForwardRefExoticComponent<OtpFieldProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Field as n}from"@base-ui/react/field";import{OTPField as l}from"@base-ui/react/otp-field";import{cx as r,disabledClasses as o,fieldReadOnlyClasses as i,fieldRestClasses as s,metaTextClasses as m,stackGapClasses as d,surfaceSlots as u,transitionClasses as c}from"../../internal/styles";const p={xs:"h-7 w-6",sm:"h-8 w-7",md:"h-10 w-8",lg:"h-12 w-10",xl:"h-14 w-12"},f={xs:"rounded-[0.3125rem]",sm:"rounded-[0.375rem]",md:"rounded-[0.4375rem]",lg:"rounded-[0.5625rem]",xl:"rounded-[0.6875rem]"},x={xs:"text-[0.8125rem]",sm:"text-[0.9375rem]",md:"text-[1.0625rem]",lg:"text-[1.25rem]",xl:"text-[1.5rem]"},g={default:{xs:"gap-1",sm:"gap-1",md:"gap-1.5",lg:"gap-2",xl:"gap-2.5"},compact:{xs:"gap-0.5",sm:"gap-0.5",md:"gap-1",lg:"gap-1",xl:"gap-1.5"}},h={numeric:"numeric",alpha:"alpha",alphanumeric:"alphanumeric",any:"none"};export const OtpField=t.forwardRef(function({variant:b="outline",size:y="md",color:v="primary",density:N="default",elevation:V=0,length:w=6,charset:C="numeric",mask:F=!1,groupSize:M,separator:j="–",value:I,defaultValue:O,onValueChange:R,onComplete:S,onValueInvalid:k,autoSubmit:q=!1,label:z,description:_,error:A,invalid:D,name:E,required:L=!1,disabled:T=!1,readOnly:B=!1,autoFocus:G=!1,className:H,style:J,...K},P){const Q=Math.min(12,Math.max(2,Math.round(w))),U=null!=A&&!1!==A&&""!==A,W=D??U,X=W?"danger":v,Y=r("text-center font-medium [font-family:inherit]",p[y],x[y],f[y],c,"caret-(--n-accent) selection:bg-(--n-soft-press)","focus:[outline:2px_solid_var(--n-ring)] focus:outline-offset-1","focus:[transition-duration:0ms]",T?o[b]:B?i[b]:s[b]),Z=M&&M>0?Math.round(M):0;return a(n.Root,{disabled:T,invalid:W,className:r("inline-flex flex-col align-top",d[y],H),style:{...u(X,V),...J},children:[z?e(n.Label,{className:r(m[y],"font-medium",T?"text-(--neba-disabled-fg)":"text-(--neba-fg)"),children:z}):null,e(l.Root,{ref:P,length:Q,validationType:h[C],mask:F,name:E,required:L,disabled:T,readOnly:B,autoSubmit:q,value:I,defaultValue:O,onValueChange:e=>R?.(e),onValueComplete:e=>S?.(e),onValueInvalid:e=>k?.(e),className:r("flex items-center",g[N][y]),...K,children:Array.from({length:Q},(n,o)=>a(t.Fragment,{children:[Z>0&&o>0&&o%Z===0?e("span",{"aria-hidden":"true",className:r("select-none px-0.5 text-(--neba-muted-fg)",x[y]),children:j}):null,e(l.Input,{className:Y,autoFocus:G&&0===o})]},o))}),_?e(n.Description,{className:r(m[y],"text-(--neba-muted-fg)"),children:_}):null,U?e(n.Error,{match:!0,className:r(m[y],"text-(--n-accent)"),children:A}):null]})});
@@ -0,0 +1,2 @@
1
+ export { OtpField } from './OtpField';
2
+ export type { OtpFieldCharset, OtpFieldProps } from './OtpField';
@@ -0,0 +1 @@
1
+ export{OtpField}from"./OtpField";
@@ -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";