neba 1.0.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 (136) hide show
  1. package/README.md +27 -16
  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/blockquote/Blockquote.d.ts +65 -0
  7. package/dist/components/blockquote/Blockquote.js +1 -0
  8. package/dist/components/blockquote/index.d.ts +2 -0
  9. package/dist/components/blockquote/index.js +1 -0
  10. package/dist/components/breadcrumb/Breadcrumb.d.ts +92 -0
  11. package/dist/components/breadcrumb/Breadcrumb.js +1 -0
  12. package/dist/components/breadcrumb/index.d.ts +2 -0
  13. package/dist/components/breadcrumb/index.js +1 -0
  14. package/dist/components/carousel/Carousel.d.ts +74 -0
  15. package/dist/components/carousel/Carousel.js +1 -0
  16. package/dist/components/carousel/index.d.ts +2 -0
  17. package/dist/components/carousel/index.js +1 -0
  18. package/dist/components/chat-bubble/ChatBubble.d.ts +114 -0
  19. package/dist/components/chat-bubble/ChatBubble.js +1 -0
  20. package/dist/components/chat-bubble/index.d.ts +2 -0
  21. package/dist/components/chat-bubble/index.js +1 -0
  22. package/dist/components/checkbox/Checkbox.js +1 -1
  23. package/dist/components/combobox/Combobox.js +1 -1
  24. package/dist/components/container/Container.d.ts +55 -0
  25. package/dist/components/container/Container.js +1 -0
  26. package/dist/components/container/index.d.ts +2 -0
  27. package/dist/components/container/index.js +1 -0
  28. package/dist/components/date-picker/DatePicker.d.ts +75 -0
  29. package/dist/components/date-picker/DatePicker.js +1 -0
  30. package/dist/components/date-picker/index.d.ts +2 -0
  31. package/dist/components/date-picker/index.js +1 -0
  32. package/dist/components/date-range-picker/DateRangePicker.d.ts +81 -0
  33. package/dist/components/date-range-picker/DateRangePicker.js +1 -0
  34. package/dist/components/date-range-picker/index.d.ts +2 -0
  35. package/dist/components/date-range-picker/index.js +1 -0
  36. package/dist/components/date-time-picker/DateTimePicker.d.ts +68 -0
  37. package/dist/components/date-time-picker/DateTimePicker.js +1 -0
  38. package/dist/components/date-time-picker/index.d.ts +2 -0
  39. package/dist/components/date-time-picker/index.js +1 -0
  40. package/dist/components/dialog/Dialog.js +1 -1
  41. package/dist/components/divider/Divider.d.ts +19 -0
  42. package/dist/components/divider/Divider.js +1 -1
  43. package/dist/components/grid/Grid.d.ts +50 -0
  44. package/dist/components/grid/Grid.js +1 -0
  45. package/dist/components/grid/index.d.ts +2 -0
  46. package/dist/components/grid/index.js +1 -0
  47. package/dist/components/grid-container/GridContainer.d.ts +79 -0
  48. package/dist/components/grid-container/GridContainer.js +1 -0
  49. package/dist/components/grid-container/index.d.ts +2 -0
  50. package/dist/components/grid-container/index.js +1 -0
  51. package/dist/components/highlight/Highlight.d.ts +84 -0
  52. package/dist/components/highlight/Highlight.js +1 -0
  53. package/dist/components/highlight/index.d.ts +2 -0
  54. package/dist/components/highlight/index.js +1 -0
  55. package/dist/components/icon/Icon.d.ts +58 -0
  56. package/dist/components/icon/Icon.js +1 -0
  57. package/dist/components/icon/index.d.ts +2 -0
  58. package/dist/components/icon/index.js +1 -0
  59. package/dist/components/icon-button/IconButton.d.ts +39 -0
  60. package/dist/components/icon-button/IconButton.js +1 -0
  61. package/dist/components/icon-button/index.d.ts +2 -0
  62. package/dist/components/icon-button/index.js +1 -0
  63. package/dist/components/otp-field/OtpField.d.ts +85 -0
  64. package/dist/components/otp-field/OtpField.js +1 -0
  65. package/dist/components/otp-field/index.d.ts +2 -0
  66. package/dist/components/otp-field/index.js +1 -0
  67. package/dist/components/pagination/Pagination.js +1 -1
  68. package/dist/components/panes/Panes.d.ts +78 -0
  69. package/dist/components/panes/Panes.js +1 -0
  70. package/dist/components/panes/index.d.ts +2 -0
  71. package/dist/components/panes/index.js +1 -0
  72. package/dist/components/pill/Pill.d.ts +80 -0
  73. package/dist/components/pill/Pill.js +1 -0
  74. package/dist/components/pill/index.d.ts +2 -0
  75. package/dist/components/pill/index.js +1 -0
  76. package/dist/components/radio-group/RadioGroup.js +1 -1
  77. package/dist/components/segmented-button/SegmentedButton.d.ts +77 -0
  78. package/dist/components/segmented-button/SegmentedButton.js +1 -0
  79. package/dist/components/segmented-button/index.d.ts +2 -0
  80. package/dist/components/segmented-button/index.js +1 -0
  81. package/dist/components/select/Select.js +1 -1
  82. package/dist/components/shortcut/Shortcut.d.ts +60 -0
  83. package/dist/components/shortcut/Shortcut.js +1 -0
  84. package/dist/components/shortcut/index.d.ts +2 -0
  85. package/dist/components/shortcut/index.js +1 -0
  86. package/dist/components/spoiler/Spoiler.d.ts +95 -0
  87. package/dist/components/spoiler/Spoiler.js +1 -0
  88. package/dist/components/spoiler/index.d.ts +2 -0
  89. package/dist/components/spoiler/index.js +1 -0
  90. package/dist/components/statistic/Statistic.d.ts +91 -0
  91. package/dist/components/statistic/Statistic.js +1 -0
  92. package/dist/components/statistic/index.d.ts +2 -0
  93. package/dist/components/statistic/index.js +1 -0
  94. package/dist/components/switch/Switch.js +1 -1
  95. package/dist/components/text-link/TextLink.d.ts +82 -0
  96. package/dist/components/text-link/TextLink.js +1 -0
  97. package/dist/components/text-link/index.d.ts +2 -0
  98. package/dist/components/text-link/index.js +1 -0
  99. package/dist/components/time-picker/TimePicker.d.ts +76 -0
  100. package/dist/components/time-picker/TimePicker.js +1 -0
  101. package/dist/components/time-picker/index.d.ts +2 -0
  102. package/dist/components/time-picker/index.js +1 -0
  103. package/dist/components/timeline/Timeline.d.ts +98 -0
  104. package/dist/components/timeline/Timeline.js +1 -0
  105. package/dist/components/timeline/index.d.ts +2 -0
  106. package/dist/components/timeline/index.js +1 -0
  107. package/dist/components/toolbar/Toolbar.d.ts +67 -0
  108. package/dist/components/toolbar/Toolbar.js +1 -0
  109. package/dist/components/toolbar/index.d.ts +2 -0
  110. package/dist/components/toolbar/index.js +1 -0
  111. package/dist/components/tree-view/TreeView.d.ts +115 -0
  112. package/dist/components/tree-view/TreeView.js +1 -0
  113. package/dist/components/tree-view/index.d.ts +2 -0
  114. package/dist/components/tree-view/index.js +1 -0
  115. package/dist/index.d.ts +26 -0
  116. package/dist/index.js +1 -1
  117. package/dist/internal/calendar.d.ts +149 -0
  118. package/dist/internal/calendar.js +1 -0
  119. package/dist/internal/date.d.ts +170 -0
  120. package/dist/internal/date.js +1 -0
  121. package/dist/internal/grid.d.ts +69 -0
  122. package/dist/internal/grid.js +1 -0
  123. package/dist/internal/i18n.d.ts +78 -0
  124. package/dist/internal/i18n.js +1 -0
  125. package/dist/internal/icons.d.ts +54 -0
  126. package/dist/internal/icons.js +1 -1
  127. package/dist/internal/picker.d.ts +111 -0
  128. package/dist/internal/picker.js +1 -0
  129. package/dist/internal/sizer.d.ts +33 -0
  130. package/dist/internal/sizer.js +1 -0
  131. package/dist/internal/styles.d.ts +33 -0
  132. package/dist/internal/styles.js +1 -1
  133. package/dist/styles.css +2 -758
  134. package/dist/tailwind.css +1017 -0
  135. package/dist/types.d.ts +65 -0
  136. package/package.json +25 -12
@@ -1 +1 @@
1
- import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Radio as n}from"@base-ui/react/radio";import{RadioGroup as l}from"@base-ui/react/radio-group";import{Field as o}from"@base-ui/react/field";import{controlTextClasses as i,metaTextClasses as t,surfaceClasses as s,tickSizeClasses as d,transitionClasses as c}from"../../internal/styles";const b=r.createContext({size:"md",color:"primary",readOnly:!1}),f=["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",c,"active:[transition-duration:0ms]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),h=[s,"cursor-pointer bg-(--n-panel) [border-color:var(--n-line)]","[box-shadow:var(--neba-plate-glass)]","hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]","data-[checked]:[box-shadow:var(--neba-plate-solid)]","data-[checked]:hover:bg-(--n-fill-hover)"].join(" "),p=[s,"cursor-default bg-(--n-panel) [border-color:var(--n-line)]","[box-shadow:var(--neba-plate-glass)] [filter:saturate(0.55)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]"].join(" "),m=["cursor-not-allowed bg-transparent [border-color:var(--neba-disabled-border)] shadow-none","data-[checked]:bg-(--neba-disabled-bg)"].join(" ");export const Radio=r.forwardRef(function({label:l,description:s,disabled:c=!1,className:u,style:v,...x},g){const y=r.useContext(b),N=x.readOnly??y.readOnly;return e(o.Root,{disabled:c,className:["flex flex-col",u??""].filter(Boolean).join(" "),style:v,children:a("div",{className:`flex items-start gap-2 ${i[y.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(n.Root,{ref:g,className:[f,d[y.size],c?m:N?p:h].join(" "),disabled:c,...x,children:e(n.Indicator,{className:"size-[38%] rounded-full bg-current"})})}),l||s?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[l?e(o.Label,{className:["leading-[1.4]",c?"text-(--neba-disabled-fg)":"cursor-pointer text-(--neba-fg)"].join(" "),children:l}):null,s?e(o.Description,{className:`${t[y.size]} text-(--neba-muted-fg)`,children:s}):null]}):null]})})});export const RadioGroup=r.forwardRef(function({size:n="md",color:i="primary",orientation:s="vertical",label:d,description:c,error:f,invalid:h,disabled:p=!1,readOnly:m=!1,className:u,style:v,children:x,...g},y){const N=null!=f&&!1!==f&&""!==f,j=h??N,k=j?"danger":i,w={"--n-fill":`var(--neba-${k}-fill)`,"--n-fill-hover":`var(--neba-${k}-fill-hover)`,"--n-on-solid":`var(--neba-${k}-on-solid)`,"--n-accent":`var(--neba-${k}-accent)`,"--n-panel":"var(--neba-panel)","--n-panel-hover":"var(--neba-panel-hover)","--n-line":`var(--neba-${k}-line)`,"--n-line-hover":`var(--neba-${k}-line-hover)`,"--n-ring":`var(--neba-${k}-ring)`},$=r.useMemo(()=>({size:n,color:k,readOnly:m}),[n,k,m]);return e(b.Provider,{value:$,children:a(o.Root,{disabled:p,invalid:j,className:["flex flex-col gap-1.5",u??""].filter(Boolean).join(" "),style:{...w,...v},children:[d?e(o.Label,{className:[t[n],"font-medium",p?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:d}):null,c?e(o.Description,{className:`${t[n]} text-(--neba-muted-fg)`,children:c}):null,e(l,{ref:y,disabled:p,readOnly:m,className:["flex","horizontal"===s?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2"].join(" "),...g,children:x}),N?e(o.Error,{match:!0,className:`${t[n]} text-(--n-accent)`,children:f}):null]})})});
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Radio as n}from"@base-ui/react/radio";import{RadioGroup as l}from"@base-ui/react/radio-group";import{Field as o}from"@base-ui/react/field";import{controlTextClasses as i,metaTextClasses as t,surfaceClasses as s,tickDotClasses as d,tickRowLeadingClasses as c,tickSizeClasses as b,transitionClasses as f}from"../../internal/styles";const h=r.createContext({size:"md",color:"primary",readOnly:!1}),m=["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",f,"active:[transition-duration:0ms]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),u=[s,"cursor-pointer bg-(--n-panel) [border-color:var(--n-line)]","hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]","data-[checked]:hover:bg-(--n-fill-hover)"].join(" "),p=[s,"cursor-default bg-(--n-panel) [border-color:var(--n-line)]","[filter:saturate(0.55)]","data-[checked]:bg-(--n-fill) data-[checked]:text-(--n-on-solid)","data-[checked]:[border-color:transparent]"].join(" "),v=["cursor-not-allowed bg-transparent [border-color:var(--neba-disabled-border)] shadow-none","data-[checked]:bg-(--neba-disabled-bg)"].join(" ");export const Radio=r.forwardRef(function({label:l,description:s,disabled:f=!1,className:x,style:g,...y},N){const j=r.useContext(h),$=y.readOnly??j.readOnly;return e(o.Root,{disabled:f,className:["flex flex-col",x??""].filter(Boolean).join(" "),style:g,children:a("div",{className:`flex items-start gap-2 ${i[j.size]} ${c}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(n.Root,{ref:N,className:[m,b[j.size],f?v:$?p:u].join(" "),disabled:f,...y,children:e(n.Indicator,{className:`rounded-full bg-current ${d[j.size]}`})})}),l||s?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[l?e(o.Label,{className:["leading-[1.4]",f?"text-(--neba-disabled-fg)":"cursor-pointer text-(--neba-fg)"].join(" "),children:l}):null,s?e(o.Description,{className:`${t[j.size]} text-(--neba-muted-fg)`,children:s}):null]}):null]})})});export const RadioGroup=r.forwardRef(function({size:n="md",color:i="primary",orientation:s="vertical",label:d,description:c,error:b,invalid:f,disabled:m=!1,readOnly:u=!1,className:p,style:v,children:x,...g},y){const N=null!=b&&!1!==b&&""!==b,j=f??N,$=j?"danger":i,k={"--n-fill":`var(--neba-${$}-fill)`,"--n-fill-hover":`var(--neba-${$}-fill-hover)`,"--n-on-solid":`var(--neba-${$}-on-solid)`,"--n-accent":`var(--neba-${$}-accent)`,"--n-panel":"var(--neba-panel)","--n-panel-hover":"var(--neba-panel-hover)","--n-line":`var(--neba-${$}-line)`,"--n-line-hover":`var(--neba-${$}-line-hover)`,"--n-ring":`var(--neba-${$}-ring)`},R=r.useMemo(()=>({size:n,color:$,readOnly:u}),[n,$,u]);return e(h.Provider,{value:R,children:a(o.Root,{disabled:m,invalid:j,className:["flex flex-col gap-1.5",p??""].filter(Boolean).join(" "),style:{...k,...v},children:[d?e(o.Label,{className:[t[n],"font-medium",m?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:d}):null,c?e(o.Description,{className:`${t[n]} text-(--neba-muted-fg)`,children:c}):null,e(l,{ref:y,disabled:m,readOnly:u,className:["flex","horizontal"===s?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2"].join(" "),...g,children:x}),N?e(o.Error,{match:!0,className:`${t[n]} text-(--n-accent)`,children:b}):null]})})});
@@ -0,0 +1,77 @@
1
+ import * as React from 'react';
2
+ import type { NebaElevation, NebaStyleProps, NebaVariant } from '../../types';
3
+ /** A segment's value. The same restraint Tabs and Select put on theirs. */
4
+ export type SegmentValue = string | number;
5
+ export interface SegmentedButtonProps extends Omit<NebaStyleProps, 'variant'>, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
6
+ /**
7
+ * Weight of the trough the segments sit in.
8
+ *
9
+ * - `solid` — a frosted trough with a filled tile riding in it. The loudest,
10
+ * and the one for a control a screen is about to be steered by.
11
+ * - `outline` — the same trough with a hairline around it and a lit tile
12
+ * rather than a filled one. The default.
13
+ * - `text` — no trough at all: the segments sit straight on the page and only
14
+ * the chosen one has a surface.
15
+ * @default 'outline'
16
+ */
17
+ variant?: NebaVariant;
18
+ /** The chosen segment. Use with `onValueChange` for a controlled set. */
19
+ value?: SegmentValue | null;
20
+ /** Which starts chosen, for an uncontrolled set. */
21
+ defaultValue?: SegmentValue | null;
22
+ onValueChange?: (value: SegmentValue | null) => void;
23
+ /**
24
+ * Drop shadow depth of the trough. `0` (the default) is flat.
25
+ * @default 0
26
+ */
27
+ elevation?: NebaElevation;
28
+ /** Disables every segment at once. */
29
+ disabled?: boolean;
30
+ /** Shows which one is chosen but does not let it be changed. */
31
+ readOnly?: boolean;
32
+ /** Identifies the value when a form is submitted. */
33
+ name?: string;
34
+ /** The segments share the full width, each taking an equal part of it. */
35
+ fullWidth?: boolean;
36
+ children?: React.ReactNode;
37
+ }
38
+ export interface SegmentProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'value' | 'color'> {
39
+ /** Identifies the segment. What `onValueChange` reports. */
40
+ value: SegmentValue;
41
+ /** Content before the label. Sized in `em`, so it tracks the label. */
42
+ startIcon?: React.ReactNode;
43
+ /** Content after the label — a count, a status dot. */
44
+ endIcon?: React.ReactNode;
45
+ /** Unavailable, but still part of the set. */
46
+ disabled?: boolean;
47
+ children?: React.ReactNode;
48
+ }
49
+ /**
50
+ * One choice in a segmented button.
51
+ *
52
+ * It has no `size`, no `color` and no `variant` of its own: all three belong to
53
+ * the set, which is the only place they can be set once and mean the same thing
54
+ * for every segment.
55
+ */
56
+ export declare const Segment: React.ForwardRefExoticComponent<SegmentProps & React.RefAttributes<HTMLElement>>;
57
+ /**
58
+ * Two or more choices in one pill, exactly one of them taken.
59
+ *
60
+ * Underneath it is a radio group, and that is the whole accessibility argument:
61
+ * a segmented button *is* "exactly one of these", so it gets `role="radiogroup"`,
62
+ * one tab stop for the set, arrow keys within it, and `aria-checked` on the one
63
+ * that is taken. Building it out of `aria-pressed` toggles — which is what a row
64
+ * of buttons would give — would announce four independent switches, three of
65
+ * which happen to be off.
66
+ *
67
+ * The tile slides because its `left`, `top`, `width` and `height` are measured
68
+ * off the chosen segment and animated. Nothing is transformed: the tile is an
69
+ * empty box, and no label is resampled while it travels. That is the same
70
+ * distinction Tabs' indicator draws, and the reason the house no-transform rule
71
+ * survives a component whose entire point is that something moves.
72
+ *
73
+ * `left`, not `inset-inline-start`, for the reason Tabs gives: `offsetLeft` is a
74
+ * distance from the left edge and stays one under RTL. Pairing a physical
75
+ * measurement with a logical property is what would break the direction.
76
+ */
77
+ export declare const SegmentedButton: React.ForwardRefExoticComponent<SegmentedButtonProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as a from"react";import{Radio as n}from"@base-ui/react/radio";import{RadioGroup as r}from"@base-ui/react/radio-group";import{controlHeightClasses as s,controlSlots as l,controlTextClasses as o,gapClasses as i,hasContent as d,iconClasses as u,paddingXClasses as c,surfaceClasses as f,transitionClasses as h}from"../../internal/styles";const p=a.createContext({variant:"outline",size:"md",density:"default",fullWidth:!1}),b={solid:`${f} bg-(--n-panel) p-1 [box-shadow:var(--n-elev),var(--neba-plate-glass)]`,outline:`${f} border bg-(--n-panel) p-1 [border-color:var(--n-line)] [box-shadow:var(--n-elev),var(--neba-plate-glass)]`,text:""},m={solid:`${f} bg-(--n-fill) [box-shadow:var(--neba-shadow-1),var(--neba-plate-solid)]`,outline:`${f} bg-(--n-panel-press) [box-shadow:var(--neba-shadow-1),var(--neba-plate-glass)]`,text:`${f} bg-(--n-panel-press) [box-shadow:var(--neba-shadow-1),var(--neba-plate-glass)]`},v={solid:"data-[checked]:text-(--n-on-solid)",outline:"data-[checked]:text-(--n-accent)",text:"data-[checked]:text-(--n-accent)"};export const Segment=a.forwardRef(function({value:r,startIcon:l,endIcon:f,disabled:b=!1,className:m,children:x,...g},y){const{variant:w,size:k,density:$,fullWidth:R}=a.useContext(p);return t(n.Root,{ref:y,value:r,disabled:b,"data-segment":"",className:["relative z-10 inline-flex shrink-0 cursor-pointer items-center justify-center select-none","whitespace-nowrap font-medium","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",s[k],o[k],i[k],c[$][k],"rounded-full",h,u,"text-(--neba-muted-fg) hover:text-(--neba-fg)",v[w],"focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)","data-[readonly]:cursor-default",R?"flex-1":"",m??""].filter(Boolean).join(" "),...g,children:[d(l)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:l}):null,x,d(f)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:f}):null]})});export const SegmentedButton=a.forwardRef(function({variant:n="outline",size:s="md",color:o="primary",density:i="default",elevation:d=0,value:u,defaultValue:c=null,onValueChange:f,disabled:v=!1,readOnly:x=!1,name:g,fullWidth:y=!1,className:w,style:k,children:$,...R},j){const[N,z]=a.useState(c),W=void 0!==u,C=W?u:N,P=a.useRef(null),S=a.useRef(null),A=a.useCallback(e=>{const t=P.current,a=S.current;if(!t||!a)return;const n=t.querySelector("[data-segment][data-checked]");if(!n)return;const r=!e||!a.hasAttribute("data-ready");r&&a.removeAttribute("data-ready"),a.style.setProperty("--n-seg-x",`${n.offsetLeft}px`),a.style.setProperty("--n-seg-y",`${n.offsetTop}px`),a.style.setProperty("--n-seg-w",`${n.offsetWidth}px`),a.style.setProperty("--n-seg-h",`${n.offsetHeight}px`),r&&a.offsetWidth,a.setAttribute("data-ready","")},[]);a.useLayoutEffect(()=>{A(!0)},[A,C,n,s,i,y,$]),a.useEffect(()=>{const e=P.current;if(!e)return;const t=new ResizeObserver(()=>A(!1));return t.observe(e),()=>t.disconnect()},[A]);const B=a.useMemo(()=>({variant:n,size:s,density:i,fullWidth:y}),[n,s,i,y]);return e(p.Provider,{value:B,children:t(r,{ref:e=>{P.current=e,"function"==typeof j?j(e):j&&(j.current=e)},value:C,onValueChange:e=>{const t=e??null;W||z(t),f?.(t)},disabled:v,readOnly:x,name:g,className:["relative inline-flex items-center rounded-full",b[n],h,x?"[filter:saturate(0.55)]":"",y?"flex w-full":"",w??""].filter(Boolean).join(" "),style:{...l(o,d,n),...k},...R,children:[null!=C?e("span",{ref:S,"aria-hidden":"true",className:["pointer-events-none absolute rounded-full","left-(--n-seg-x) top-(--n-seg-y) h-(--n-seg-h) w-(--n-seg-w)",m[n],"[transition-property:left,top,width,height]","[transition-timing-function:var(--neba-ease)]","[transition-duration:0ms] data-[ready]:[transition-duration:var(--neba-duration)]"].join(" ")}):null,$]})})});
@@ -0,0 +1,2 @@
1
+ export { Segment, SegmentedButton } from './SegmentedButton';
2
+ export type { SegmentedButtonProps, SegmentProps, SegmentValue } from './SegmentedButton';
@@ -0,0 +1 @@
1
+ export{Segment,SegmentedButton}from"./SegmentedButton";
@@ -1 +1 @@
1
- import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Select as l}from"@base-ui/react/select";import{Field as n}from"@base-ui/react/field";import{CheckIcon as r,ChevronIcon as i}from"../../internal/icons";import{controlHeightClasses as o,controlTextLeadingClasses as s,disabledClasses as d,fieldReadOnlyClasses as c,fieldRestClasses as u,focusWithinRingClasses as m,gapClasses as h,iconClasses as f,metaTextClasses as p,paddingXClasses as b,radiusClasses as g,stackGapClasses as x,surfaceClasses as v,surfaceSlots as N,transitionClasses as j}from"../../internal/styles";const w=["group relative flex w-full cursor-pointer items-center select-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",j,"focus-within:[transition-duration:0ms]",m,f].join(" "),y=[v,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","min-w-[var(--anchor-width)] border bg-(--n-panel-press) p-1","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]"].join(" "),I=["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--neba-radius-xs) py-1.5 pe-2 ps-7",j,"data-[highlighted]:bg-(--n-soft-hover)","data-[selected]:text-(--n-accent) data-[selected]:font-medium","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)","[outline:none]"].join(" ");export const Select=t.forwardRef(function({variant:m="outline",size:f="md",color:v="primary",density:j="default",elevation:$=0,items:S,value:V,defaultValue:k,onValueChange:z,placeholder:O,label:P,description:R,error:T,invalid:q,startIcon:C,fullWidth:W=!1,disabled:_=!1,readOnly:B=!1,required:D=!1,name:E,id:L,className:M,style:A},F){const G=null!=T&&!1!==T&&""!==T,H=q??G,J=H?"danger":v,K=t.useMemo(()=>S.map(e=>({label:e.label??String(e.value),value:e.value})),[S]);return a(n.Root,{disabled:_,invalid:H,className:["flex-col align-top",x[f],W?"flex w-full":"inline-flex",M??""].filter(Boolean).join(" "),style:{...N(J,$),...A},children:[P?e(n.Label,{className:[p[f],"font-medium",_?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:P}):null,a(l.Root,{id:L,name:E,items:K,value:V,defaultValue:k,onValueChange:e=>z?.(e),disabled:_,readOnly:B,required:D,children:[a(l.Trigger,{ref:F,className:[w,o[f],s[f],g[f],h[f],b[j][f],_?d[m]:B?`${c[m]} cursor-default`:u[m]].join(" "),children:[C?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:C}):null,e(l.Value,{className:["min-w-0 flex-1 truncate text-start","data-[placeholder]:text-(--neba-muted-fg)"].join(" "),placeholder:O}),e(l.Icon,{className:["flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)","[transition:rotate_var(--neba-duration)_var(--neba-ease)]","data-[popup-open]:rotate-180"].join(" "),children:e(i,{})})]}),e(l.Portal,{children:e(l.Positioner,{className:"neba-portal z-50 [outline:none]",sideOffset:6,alignItemWithTrigger:!1,children:e(l.Popup,{className:`${y} ${g[f]} ${s[f]}`,children:S.map(t=>a(l.Item,{value:t.value,disabled:t.disabled,className:I,children:[e(l.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(r,{})}),e(l.ItemText,{className:"truncate",children:t.label??String(t.value)})]},String(t.value)))})})})]}),R?e(n.Description,{className:`${p[f]} text-(--neba-muted-fg)`,children:R}):null,G?e(n.Error,{match:!0,className:`${p[f]} text-(--n-accent)`,children:T}):null]})});
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Select as l}from"@base-ui/react/select";import{Field as n}from"@base-ui/react/field";import{CheckIcon as r,ChevronIcon as i}from"../../internal/icons";import{WidthSizer as s}from"../../internal/sizer";import{controlHeightClasses as o,controlTextLeadingClasses as d,disabledClasses as c,fieldReadOnlyClasses as m,fieldRestClasses as u,focusWithinRingClasses as h,gapClasses as f,hasContent as p,iconClasses as b,metaTextClasses as g,paddingXClasses as x,radiusClasses as v,stackGapClasses as N,surfaceClasses as w,surfaceSlots as j,transitionClasses as y}from"../../internal/styles";const I=["group relative flex w-full cursor-pointer items-center select-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",y,"focus-within:[transition-duration:0ms]",h,b].join(" "),S=[w,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","min-w-[var(--anchor-width)] border bg-(--n-panel-press) p-1","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]"].join(" "),$=["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--neba-radius-xs) py-1.5 pe-2 ps-7",y,"data-[highlighted]:bg-(--n-soft-hover) data-[highlighted]:text-(--n-accent)","data-[selected]:text-(--n-accent) data-[selected]:font-medium","data-[disabled]:cursor-not-allowed data-[disabled]:text-(--neba-disabled-fg)","[outline:none]"].join(" ");export const Select=t.forwardRef(function({variant:h="outline",size:b="md",color:w="primary",density:y="default",elevation:V=0,items:z,value:k,defaultValue:O,onValueChange:P,placeholder:R,label:T,description:q,error:C,invalid:M,startIcon:W,fullWidth:_=!1,disabled:B=!1,readOnly:D=!1,required:E=!1,name:L,id:A,className:F,style:G},H){const J=null!=C&&!1!==C&&""!==C,K=M??J,Q=K?"danger":w,U=t.useMemo(()=>z.map(e=>({label:e.label??String(e.value),value:e.value})),[z]),X=t.useMemo(()=>[...z.map(e=>e.label??String(e.value)),...p(R)?[R]:[]],[z,R]);return a(n.Root,{disabled:B,invalid:K,className:["flex-col align-top",N[b],_?"flex w-full":"inline-flex",F??""].filter(Boolean).join(" "),style:{...j(Q,V),...G},children:[T?e(n.Label,{className:[g[b],"font-medium",B?"text-(--neba-disabled-fg)":"text-(--neba-fg)"].join(" "),children:T}):null,a(l.Root,{id:A,name:L,items:U,value:k,defaultValue:O,onValueChange:e=>P?.(e),disabled:B,readOnly:D,required:E,children:[a(l.Trigger,{ref:H,className:[I,o[b],d[b],v[b],f[b],x[y][b],B?c[h]:D?`${m[h]} cursor-default`:u[h]].join(" "),children:[W?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)",children:W}):null,a("span",{className:"flex min-w-0 flex-1 flex-col",children:[e(l.Value,{className:["w-full truncate text-start","data-[placeholder]:text-(--neba-muted-fg)"].join(" "),placeholder:R}),e(s,{samples:X})]}),e(l.Icon,{className:["flex h-[1lh] shrink-0 items-center text-(--neba-muted-fg)","[transition:rotate_var(--neba-duration)_var(--neba-ease)]","data-[popup-open]:rotate-180"].join(" "),children:e(i,{})})]}),e(l.Portal,{children:e(l.Positioner,{className:"neba-portal z-50 [outline:none]",sideOffset:6,alignItemWithTrigger:!1,children:e(l.Popup,{className:`${S} ${v[b]} ${d[b]}`,style:j(Q,3),children:z.map(t=>a(l.Item,{value:t.value,disabled:t.disabled,className:$,children:[e(l.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(r,{})}),e(l.ItemText,{className:"truncate",children:t.label??String(t.value)})]},String(t.value)))})})})]}),q?e(n.Description,{className:`${g[b]} text-(--neba-muted-fg)`,children:q}):null,J?e(n.Error,{match:!0,className:`${g[b]} text-(--n-accent)`,children:C}):null]})});
@@ -0,0 +1,60 @@
1
+ import * as React from 'react';
2
+ import type { NebaElevation, NebaStyleProps } from '../../types';
3
+ /**
4
+ * Which keyboard the shortcut is being read on.
5
+ *
6
+ * `auto` asks the browser, which is right for a shortcut a reader is about to
7
+ * press. The three explicit values are for documentation that has to name a
8
+ * platform rather than the reader's own — a support page describing the Windows
9
+ * build, a table comparing the two.
10
+ */
11
+ export type ShortcutOS = 'auto' | 'mac' | 'windows' | 'linux';
12
+ export interface ShortcutProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'span'>, 'color' | 'children'> {
13
+ /**
14
+ * The keys, innermost punctuation and all.
15
+ *
16
+ * A string is split on `+` — `'Mod+Shift+P'` — which covers everything except
17
+ * a shortcut whose key *is* a plus. For that one, pass the array form:
18
+ * `keys={['Ctrl', '+']}`.
19
+ */
20
+ keys: string | string[];
21
+ /**
22
+ * Which keyboard to name the modifiers for.
23
+ * @default 'auto'
24
+ */
25
+ os?: ShortcutOS;
26
+ /**
27
+ * What goes between two keys. Omit it for the platform's own convention: a `+`
28
+ * on Windows and Linux, and nothing at all on macOS, where a shortcut is
29
+ * written as a run of symbols — `⇧⌘P`, never `⇧+⌘+P`.
30
+ */
31
+ separator?: React.ReactNode;
32
+ /**
33
+ * Drop shadow depth. `0` (the default) is flat. A key cap is the one place a
34
+ * raised surface is tempting and wrong: this is a picture of a key, not a key.
35
+ * @default 0
36
+ */
37
+ elevation?: NebaElevation;
38
+ }
39
+ /**
40
+ * A keyboard key, or a combination of them.
41
+ *
42
+ * Two things make this more than a styled `<kbd>`, and both are about the label
43
+ * rather than the box around it.
44
+ *
45
+ * The first is `Mod`. A shortcut written as `Ctrl+K` is wrong for every Mac
46
+ * reader and one written as `⌘K` is wrong for everybody else, so the token that
47
+ * means "the modifier shortcuts are built on" resolves per platform — and `os`
48
+ * is there for the pages that have to name a platform rather than the reader's.
49
+ *
50
+ * The second is that `⌘` is not a word. A screen reader reads it as "place of
51
+ * interest sign", so every key drawn as a glyph carries its name beside it, in
52
+ * the clipped box `srOnlyClasses` describes. What is announced is "Command K",
53
+ * which is what the shortcut is called.
54
+ *
55
+ * The keys are real `<kbd>` elements; the wrapper around them is a `<span>`.
56
+ * Nesting `<kbd>` inside `<kbd>` is allowed and would also be defensible, but a
57
+ * `kbd` wrapper is a second box for a host stylesheet to reach into for no gain
58
+ * — the semantics are carried by the keys themselves either way.
59
+ */
60
+ export declare const Shortcut: React.ForwardRefExoticComponent<ShortcutProps & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as n,Fragment as e,jsxs as a}from"react/jsx-runtime";import*as o from"react";import{controlHeightClasses as t,controlSlots as r,controlTextClasses as l,paddingXClasses as s,radiusClasses as m,srOnlyClasses as i,surfaceClasses as c,transitionClasses as d}from"../../internal/styles";const w=n=>({symbol:n,name:n}),u={mod:{mac:{symbol:"⌘",name:"Command"},windows:w("Ctrl"),linux:w("Ctrl")},meta:{mac:{symbol:"⌘",name:"Command"},windows:w("Win"),linux:w("Super")},ctrl:{mac:{symbol:"⌃",name:"Control"},windows:w("Ctrl"),linux:w("Ctrl")},alt:{mac:{symbol:"⌥",name:"Option"},windows:w("Alt"),linux:w("Alt")},shift:{mac:{symbol:"⇧",name:"Shift"},windows:w("Shift"),linux:w("Shift")},enter:{mac:{symbol:"↩",name:"Enter"},windows:w("Enter"),linux:w("Enter")},tab:{mac:{symbol:"⇥",name:"Tab"},windows:w("Tab"),linux:w("Tab")},escape:{mac:{symbol:"⎋",name:"Escape"},windows:w("Esc"),linux:w("Esc")},backspace:{mac:{symbol:"⌫",name:"Backspace"},windows:w("Backspace"),linux:w("Backspace")},delete:{mac:{symbol:"⌦",name:"Delete"},windows:w("Del"),linux:w("Del")},capslock:{mac:{symbol:"⇪",name:"Caps Lock"},windows:w("Caps Lock"),linux:w("Caps Lock")}},p={cmdorctrl:"mod",commandorcontrol:"mod",cmd:"meta",command:"meta",super:"meta",win:"meta",windows:"meta",control:"ctrl",option:"alt",opt:"alt",return:"enter",esc:"escape",del:"delete",caps:"capslock"},b={up:{symbol:"↑",name:"Arrow up"},down:{symbol:"↓",name:"Arrow down"},left:{symbol:"←",name:"Arrow left"},right:{symbol:"→",name:"Arrow right"},arrowup:{symbol:"↑",name:"Arrow up"},arrowdown:{symbol:"↓",name:"Arrow down"},arrowleft:{symbol:"←",name:"Arrow left"},arrowright:{symbol:"→",name:"Arrow right"}};function f(){if("undefined"==typeof navigator)return"windows";const n=navigator.userAgentData,e=`${n?.platform??""} ${navigator.platform??""} ${navigator.userAgent??""}`;return/mac|iphone|ipad|ipod/i.test(e)?"mac":/win/i.test(e)?"windows":"linux"}function y(){return()=>{}}function x(){return"windows"}const g={xs:"xs",sm:"xs",md:"sm",lg:"md",xl:"lg"},h={solid:[c,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[c,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--n-accent) bg-(--n-soft)"},v={xs:"min-w-5.5",sm:"min-w-6.5",md:"min-w-8",lg:"min-w-10",xl:"min-w-12"};export const Shortcut=o.forwardRef(function({variant:c="outline",size:A="md",color:k="secondary",density:C="compact",elevation:j=0,keys:E,os:S="auto",separator:B,className:N,style:D,...L},T){const $=o.useSyncExternalStore(y,f,x),F="auto"===S?$:S,z=g[A],O=function(n){return Array.isArray(n)?n.map(n=>n.trim()).filter(Boolean):n.split("+").map(n=>n.trim()).filter(Boolean)}(E),R=O.map(n=>function(n,e){const a=n.toLowerCase().replace(/[\s_-]/g,""),o=p[a]??a,t=b[o];if(t)return t;const r=u[o];return r?r[e]:w(1===n.length?n.toUpperCase():n)}(n,F)),U=void 0===B?"mac"===F?null:"+":B,W=["inline-flex shrink-0 items-center justify-center","font-mono font-medium leading-none whitespace-nowrap tabular-nums",t[z],l[z],v[z],s[C][z],m[z],h[c],d].join(" ");return n("span",{ref:T,className:["inline-flex max-w-full items-center gap-1 align-middle",N??""].filter(Boolean).join(" "),style:{...r(k,j,c),...D},...L,children:R.map((t,r)=>a(o.Fragment,{children:[r>0&&null!==U?n("span",{"aria-hidden":"true",className:"text-(--neba-muted-fg)",children:U}):null,n("kbd",{className:W,children:t.symbol===t.name?t.symbol:a(e,{children:[n("span",{"aria-hidden":"true",children:t.symbol}),n("span",{className:i,children:t.name})]})})]},r))})});
@@ -0,0 +1,2 @@
1
+ export { Shortcut } from './Shortcut';
2
+ export type { ShortcutOS, ShortcutProps } from './Shortcut';
@@ -0,0 +1 @@
1
+ export{Shortcut}from"./Shortcut";
@@ -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,91 @@
1
+ import * as React from 'react';
2
+ import { type BoxProps } from '../box/Box';
3
+ import type { NebaAlign } from '../../types';
4
+ export interface StatisticProps extends Omit<BoxProps, 'title' | 'prefix'> {
5
+ /**
6
+ * What the number is. The name of the measure, not a sentence about it —
7
+ * "Active users", "MRR", "이탈률".
8
+ *
9
+ * `label` rather than `title`, which is what Card calls the same slot: this is
10
+ * the name of a *value*, which is the thing the library already spells `label`
11
+ * on every field it has.
12
+ */
13
+ label?: React.ReactNode;
14
+ /**
15
+ * The figure. A number is formatted; a string is printed exactly as given, for
16
+ * the values that are not numbers at all — "3h 42m", "A+", "—".
17
+ */
18
+ value: number | string;
19
+ /**
20
+ * How to write a numeric `value` — `Intl.NumberFormat` options, the same prop
21
+ * the progress indicators take. Without it a number is grouped by the reader's
22
+ * own locale and otherwise left alone.
23
+ */
24
+ format?: Intl.NumberFormatOptions;
25
+ /** Set before the figure and never wrapped away from it — a currency sign. */
26
+ prefix?: React.ReactNode;
27
+ /**
28
+ * Set after the figure: `%`, `MB`, `명`.
29
+ *
30
+ * A second slot rather than one `adornment` with a side, because the two are
31
+ * typographically different things and always have been — a currency symbol
32
+ * leads its number and a unit follows it, in every locale that has both.
33
+ */
34
+ unit?: React.ReactNode;
35
+ /** A glyph before the label. An `Icon`, or anything else that draws. */
36
+ icon?: React.ReactNode;
37
+ /**
38
+ * The figure this one is being compared against — last month's, last quarter's,
39
+ * the target. Passing it is what makes the delta appear.
40
+ *
41
+ * Only meaningful for a numeric `value`; with a string there is nothing to
42
+ * subtract and the delta is left out.
43
+ */
44
+ previousValue?: number;
45
+ /**
46
+ * How the difference is written.
47
+ *
48
+ * - `percent` — the change relative to `previousValue`. The default, because a
49
+ * report is nearly always asking "how much has this moved", not "by how many".
50
+ * - `absolute` — the difference itself, in the figure's own units.
51
+ * - `both` — the percentage with the difference after it.
52
+ * - `none` — no delta, even with a `previousValue` given.
53
+ * @default 'percent'
54
+ */
55
+ delta?: 'percent' | 'absolute' | 'both' | 'none';
56
+ /**
57
+ * Which direction counts as good, and so which way the delta is coloured.
58
+ *
59
+ * `up` for revenue, `down` for churn and error rate and page weight. This is
60
+ * not decoration: green-for-larger on a bounce rate says the opposite of what
61
+ * the report means, and it says it to exactly the reader who is skimming.
62
+ * @default 'up'
63
+ */
64
+ betterWhen?: 'up' | 'down';
65
+ /** A line under the figure — "vs. last month", "as of 3 July". */
66
+ caption?: React.ReactNode;
67
+ /**
68
+ * Where the block sits in the card. `center` for a row of tiles that read as
69
+ * one band; `start` — the default — for a card with anything else in it.
70
+ * @default 'start'
71
+ */
72
+ align?: NebaAlign;
73
+ /** Anything below the caption: a sparkline, a ProgressLinear against a target. */
74
+ children?: React.ReactNode;
75
+ }
76
+ /**
77
+ * A number with its name on it, and — when there is something to compare it
78
+ * against — how far it has moved.
79
+ *
80
+ * A Box with a fixed arrangement laid on it, exactly as Card is. The slots are
81
+ * props and not compound sub-components for the reason Card gives: the order
82
+ * never varies, so what a caller wants to decide is what goes in each slot.
83
+ *
84
+ * The delta is a Chip rather than a coloured span, and that is the whole reason
85
+ * it looks right next to everything else — it is the same token the rest of the
86
+ * library uses, at the same step down the control ladder, with the same acrylic
87
+ * on it. It also carries a shape and not only a colour: a report whose "down" is
88
+ * red and nothing else is a report that says nothing to a reader who cannot
89
+ * separate red from green.
90
+ */
91
+ export declare const Statistic: React.ForwardRefExoticComponent<StatisticProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{Box as n}from"../box/Box";import{Chip as a}from"../chip/Chip";import{MinusIcon as r,TrendDownIcon as s,TrendUpIcon as m}from"../../internal/icons";import{hasContent as i,metaTextClasses as o,sheetSectionGapClasses as c}from"../../internal/styles";const u={xs:"text-[1.125rem]/[1.375rem]",sm:"text-[1.375rem]/[1.625rem]",md:"text-[1.75rem]/[2rem]",lg:"text-[2.25rem]/[2.5rem]",xl:"text-[2.875rem]/[3.25rem]"},d={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1rem]",lg:"text-[1.25rem]",xl:"text-[1.5rem]"},x={xs:"gap-y-0.5",sm:"gap-y-0.5",md:"gap-y-1",lg:"gap-y-1",xl:"gap-y-1.5"},f={start:"items-start text-start",center:"items-center text-center",end:"items-end text-end"},p={up:e(m,{}),down:e(s,{}),flat:e(r,{})};export const Statistic=l.forwardRef(function({size:r="md",color:s="primary",density:m="default",label:b,value:h,format:g,prefix:w,unit:N,icon:y,previousValue:v,delta:$="percent",betterWhen:j="up",caption:M,align:z="start",className:B,children:k,...F},I){const C=l.useMemo(()=>new Intl.NumberFormat(void 0,g),[g]),R="number"==typeof h?h:null,S=null===R?h:C.format(R),V=null!==R&&void 0!==v?R-v:null,W=null!==V&&0!==v&&void 0!==v?V/Math.abs(v):null,q=null===V?null:V>0?"up":V<0?"down":"flat";let A=null;if(null!==V&&null!==q&&"none"!==$){const e=V>0?"+":V<0?"-":"",t=`${e}${C.format(Math.abs(V))}`,l=null===W?null:`${e}${(100*Math.abs(W)).toFixed(1).replace(/\.0$/,"")}%`;A="absolute"===$?t:"both"===$?[l,t].filter(Boolean).join(" · "):l??t}const D=null===q||"flat"===q?"secondary":q===j?"success":"danger",E=null!==A||i(M);return t(n,{ref:I,size:r,color:s,density:m,className:["flex flex-col",c[r],f[z],B??""].filter(Boolean).join(" "),...F,children:[i(b)||i(y)?t("div",{className:["flex min-w-0 items-center gap-1.5 font-medium text-(--neba-muted-fg)",o[r]].join(" "),children:[i(y)?e("span",{className:"flex shrink-0 items-center",children:y}):null,i(b)?e("span",{className:"min-w-0 truncate",children:b}):null]}):null,t("div",{className:["flex min-w-0 flex-wrap items-baseline gap-1 font-semibold text-(--neba-fg) tabular-nums",u[r]].join(" "),children:[i(w)?e("span",{className:`font-medium text-(--neba-muted-fg) ${d[r]}`,children:w}):null,e("span",{className:"min-w-0 break-words",children:S}),i(N)?e("span",{className:`font-medium text-(--neba-muted-fg) ${d[r]}`,children:N}):null]}),E?t("div",{className:`flex min-w-0 flex-wrap items-center gap-x-2 ${x[r]}`,children:[null!==A&&null!==q?e(a,{size:r,variant:"text",color:D,startIcon:p[q],className:"tabular-nums",children:A}):null,i(M)?e("span",{className:`min-w-0 text-(--neba-muted-fg) ${o[r]}`,children:M}):null]}):null,k]})});
@@ -0,0 +1,2 @@
1
+ export { Statistic } from './Statistic';
2
+ export type { StatisticProps } from './Statistic';
@@ -0,0 +1 @@
1
+ export{Statistic}from"./Statistic";
@@ -1 +1 @@
1
- import{jsx as e,jsxs as a,Fragment as r}from"react/jsx-runtime";import*as n from"react";import{Switch as l}from"@base-ui/react/switch";import{Field as o}from"@base-ui/react/field";import{controlTextClasses as t,metaTextClasses as i,surfaceClasses as c}from"../../internal/styles";const s={xs:"h-3.5 w-6",sm:"h-4 w-7",md:"h-5 w-9",lg:"h-6 w-11",xl:"h-7 w-13"},d={xs:"data-[checked]:left-[calc(100%-0.75rem)]",sm:"data-[checked]:left-[calc(100%-0.875rem)]",md:"data-[checked]:left-[calc(100%-1.125rem)]",lg:"data-[checked]:left-[calc(100%-1.375rem)]",xl:"data-[checked]:left-[calc(100%-1.625rem)]"},b=["relative inline-flex shrink-0 border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","rounded-full","[transition-property:background-color,border-color,box-shadow]","[transition-duration:var(--neba-duration-fill),var(--neba-duration),var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),h=[c,"cursor-pointer bg-(--n-panel) [border-color:var(--n-line)]","[box-shadow:var(--neba-plate-glass)]","hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","data-[checked]:bg-(--n-fill) data-[checked]:[border-color:transparent]","data-[checked]:[box-shadow:var(--neba-plate-solid)]","data-[checked]:hover:bg-(--n-fill-hover)"].join(" "),f=[c,"cursor-default bg-(--n-panel) [border-color:var(--n-line)]","[box-shadow:var(--neba-plate-glass)] [filter:saturate(0.55)]","data-[checked]:bg-(--n-fill) data-[checked]:[border-color:transparent]"].join(" "),m=["cursor-not-allowed bg-transparent [border-color:var(--neba-disabled-border)] shadow-none","data-[checked]:bg-(--neba-disabled-bg)"].join(" "),v=["absolute inset-y-0.5 left-0.5 aspect-square rounded-full bg-(--neba-surface)","[box-shadow:var(--neba-shadow-1)]","[transition:left_var(--neba-duration)_var(--neba-ease)]"].join(" ");export const Switch=n.forwardRef(function({size:n="md",color:c="primary",label:u,description:p,error:g,invalid:x,labelPlacement:w="end",disabled:k=!1,readOnly:j=!1,className:$,style:N,...y},_){const R=null!=g&&!1!==g&&""!==g,B=x??R,O=B?"danger":c,S={"--n-fill":`var(--neba-${O}-fill)`,"--n-fill-hover":`var(--neba-${O}-fill-hover)`,"--n-accent":`var(--neba-${O}-accent)`,"--n-panel":"var(--neba-panel)","--n-panel-hover":"var(--neba-panel-hover)","--n-line":`var(--neba-${O}-line)`,"--n-line-hover":`var(--neba-${O}-line-hover)`,"--n-ring":`var(--neba-${O}-ring)`},q=e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:_,className:[b,s[n],k?m:j?f:h].join(" "),disabled:k,readOnly:j,...y,children:e(l.Thumb,{className:`${v} ${d[n]}`})})}),z=u||p?a("span",{className:["flex min-w-0 flex-col gap-0.5","start"===w?"flex-1":""].filter(Boolean).join(" "),children:[u?e(o.Label,{className:["leading-[1.4]",k?"text-(--neba-disabled-fg)":"cursor-pointer text-(--neba-fg)"].join(" "),children:u}):null,p?e(o.Description,{className:`${i[n]} text-(--neba-muted-fg)`,children:p}):null]}):null;return a(o.Root,{disabled:k,invalid:B,className:["inline-flex flex-col gap-1 align-top",$??""].filter(Boolean).join(" "),style:{...S,...N},children:[e("div",{className:`flex items-start gap-2.5 ${t[n]}`,children:a(r,"start"===w?{children:[z,q]}:{children:[q,z]})}),R?e(o.Error,{match:!0,className:`${i[n]} text-(--n-accent)`,children:g}):null]})});
1
+ import{jsx as e,jsxs as a,Fragment as r}from"react/jsx-runtime";import*as n from"react";import{Switch as l}from"@base-ui/react/switch";import{Field as o}from"@base-ui/react/field";import{controlTextClasses as t,metaTextClasses as i,surfaceClasses as c,tickRowLeadingClasses as s}from"../../internal/styles";const d={xs:"h-3.5 w-6",sm:"h-4 w-7",md:"h-5 w-9",lg:"h-6 w-11",xl:"h-7 w-13"},b={xs:"data-[checked]:left-[calc(100%-0.75rem)]",sm:"data-[checked]:left-[calc(100%-0.875rem)]",md:"data-[checked]:left-[calc(100%-1.125rem)]",lg:"data-[checked]:left-[calc(100%-1.375rem)]",xl:"data-[checked]:left-[calc(100%-1.625rem)]"},h=["relative inline-flex shrink-0 border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","rounded-full","[transition-property:background-color,border-color,box-shadow]","[transition-duration:var(--neba-duration-fill),var(--neba-duration),var(--neba-duration)]","[transition-timing-function:var(--neba-ease)]","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),f=[c,"cursor-pointer bg-(--n-panel) [border-color:var(--n-line)]","hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)]","data-[checked]:bg-(--n-fill) data-[checked]:[border-color:transparent]","data-[checked]:hover:bg-(--n-fill-hover)"].join(" "),m=[c,"cursor-default bg-(--n-panel) [border-color:var(--n-line)]","[filter:saturate(0.55)]","data-[checked]:bg-(--n-fill) data-[checked]:[border-color:transparent]"].join(" "),u=["cursor-not-allowed bg-transparent [border-color:var(--neba-disabled-border)] shadow-none","data-[checked]:bg-(--neba-disabled-bg)"].join(" "),v=["absolute inset-y-0.5 left-0.5 aspect-square rounded-full bg-(--neba-surface)","[box-shadow:var(--neba-shadow-1)]","[transition:left_var(--neba-duration)_var(--neba-ease)]"].join(" ");export const Switch=n.forwardRef(function({size:n="md",color:c="primary",label:p,description:g,error:x,invalid:w,labelPlacement:k="end",disabled:j=!1,readOnly:$=!1,className:N,style:y,..._},R){const B=null!=x&&!1!==x&&""!==x,O=w??B,S=O?"danger":c,q={"--n-fill":`var(--neba-${S}-fill)`,"--n-fill-hover":`var(--neba-${S}-fill-hover)`,"--n-accent":`var(--neba-${S}-accent)`,"--n-panel":"var(--neba-panel)","--n-panel-hover":"var(--neba-panel-hover)","--n-line":`var(--neba-${S}-line)`,"--n-line-hover":`var(--neba-${S}-line-hover)`,"--n-ring":`var(--neba-${S}-ring)`},z=e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:R,className:[h,d[n],j?u:$?m:f].join(" "),disabled:j,readOnly:$,..._,children:e(l.Thumb,{className:`${v} ${b[n]}`})})}),D=p||g?a("span",{className:["flex min-w-0 flex-col gap-0.5","start"===k?"flex-1":""].filter(Boolean).join(" "),children:[p?e(o.Label,{className:["leading-[1.4]",j?"text-(--neba-disabled-fg)":"cursor-pointer text-(--neba-fg)"].join(" "),children:p}):null,g?e(o.Description,{className:`${i[n]} text-(--neba-muted-fg)`,children:g}):null]}):null;return a(o.Root,{disabled:j,invalid:O,className:["inline-flex flex-col gap-1 align-top",N??""].filter(Boolean).join(" "),style:{...q,...y},children:[e("div",{className:`flex items-start gap-2.5 ${t[n]} ${s}`,children:a(r,"start"===k?{children:[D,z]}:{children:[z,D]})}),B?e(o.Error,{match:!0,className:`${i[n]} text-(--n-accent)`,children:x}):null]})});
@@ -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";