neba 1.4.0 → 1.6.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 (135) hide show
  1. package/README.md +7 -5
  2. package/dist/components/alert/Alert.d.ts +9 -1
  3. package/dist/components/alert/Alert.js +1 -1
  4. package/dist/components/area-chart/AreaChart.d.ts +54 -0
  5. package/dist/components/area-chart/AreaChart.js +1 -0
  6. package/dist/components/area-chart/index.d.ts +2 -0
  7. package/dist/components/area-chart/index.js +1 -0
  8. package/dist/components/bar-chart/BarChart.d.ts +63 -0
  9. package/dist/components/bar-chart/BarChart.js +1 -0
  10. package/dist/components/bar-chart/index.d.ts +2 -0
  11. package/dist/components/bar-chart/index.js +1 -0
  12. package/dist/components/bottom-navigation/BottomNavigation.d.ts +99 -0
  13. package/dist/components/bottom-navigation/BottomNavigation.js +1 -0
  14. package/dist/components/bottom-navigation/index.d.ts +1 -0
  15. package/dist/components/bottom-navigation/index.js +1 -0
  16. package/dist/components/breadcrumb/Breadcrumb.d.ts +35 -2
  17. package/dist/components/breadcrumb/Breadcrumb.js +1 -1
  18. package/dist/components/button/Button.d.ts +16 -0
  19. package/dist/components/button/Button.js +1 -1
  20. package/dist/components/carousel/Carousel.d.ts +10 -4
  21. package/dist/components/carousel/Carousel.js +1 -1
  22. package/dist/components/chip/Chip.d.ts +9 -1
  23. package/dist/components/chip/Chip.js +1 -1
  24. package/dist/components/collapsible/Collapsible.d.ts +88 -0
  25. package/dist/components/collapsible/Collapsible.js +1 -0
  26. package/dist/components/collapsible/index.d.ts +1 -0
  27. package/dist/components/collapsible/index.js +1 -0
  28. package/dist/components/combobox/Combobox.d.ts +19 -7
  29. package/dist/components/combobox/Combobox.js +1 -1
  30. package/dist/components/dialog/Dialog.d.ts +11 -5
  31. package/dist/components/dialog/Dialog.js +1 -1
  32. package/dist/components/drawer/Drawer.d.ts +11 -5
  33. package/dist/components/drawer/Drawer.js +1 -1
  34. package/dist/components/file-picker/FilePicker.d.ts +1 -3
  35. package/dist/components/file-picker/FilePicker.js +1 -1
  36. package/dist/components/floating-action-button/FloatingActionButton.d.ts +146 -0
  37. package/dist/components/floating-action-button/FloatingActionButton.js +1 -0
  38. package/dist/components/floating-action-button/index.d.ts +1 -0
  39. package/dist/components/floating-action-button/index.js +1 -0
  40. package/dist/components/floating-bottom-navigation/FloatingBottomNavigation.d.ts +91 -0
  41. package/dist/components/floating-bottom-navigation/FloatingBottomNavigation.js +1 -0
  42. package/dist/components/floating-bottom-navigation/index.d.ts +2 -0
  43. package/dist/components/floating-bottom-navigation/index.js +1 -0
  44. package/dist/components/heatmap-chart/HeatmapChart.d.ts +69 -0
  45. package/dist/components/heatmap-chart/HeatmapChart.js +1 -0
  46. package/dist/components/heatmap-chart/index.d.ts +2 -0
  47. package/dist/components/heatmap-chart/index.js +1 -0
  48. package/dist/components/highlight/Highlight.js +1 -1
  49. package/dist/components/line-chart/LineChart.d.ts +74 -0
  50. package/dist/components/line-chart/LineChart.js +1 -0
  51. package/dist/components/line-chart/index.d.ts +2 -0
  52. package/dist/components/line-chart/index.js +1 -0
  53. package/dist/components/number-field/NumberField.d.ts +10 -6
  54. package/dist/components/number-field/NumberField.js +1 -1
  55. package/dist/components/overlay/Overlay.d.ts +11 -6
  56. package/dist/components/overlay/Overlay.js +1 -1
  57. package/dist/components/pagination/Pagination.d.ts +28 -6
  58. package/dist/components/pagination/Pagination.js +1 -1
  59. package/dist/components/panes/Panes.js +1 -1
  60. package/dist/components/pie-chart/PieChart.d.ts +58 -0
  61. package/dist/components/pie-chart/PieChart.js +1 -0
  62. package/dist/components/pie-chart/index.d.ts +2 -0
  63. package/dist/components/pie-chart/index.js +1 -0
  64. package/dist/components/popover/Popover.d.ts +11 -5
  65. package/dist/components/popover/Popover.js +1 -1
  66. package/dist/components/progress-box/ProgressBox.js +1 -1
  67. package/dist/components/progress-circular/ProgressCircular.js +1 -1
  68. package/dist/components/progress-linear/ProgressLinear.js +1 -1
  69. package/dist/components/rating/Rating.d.ts +100 -0
  70. package/dist/components/rating/Rating.js +1 -0
  71. package/dist/components/rating/index.d.ts +1 -0
  72. package/dist/components/rating/index.js +1 -0
  73. package/dist/components/scatter-chart/ScatterChart.d.ts +45 -0
  74. package/dist/components/scatter-chart/ScatterChart.js +1 -0
  75. package/dist/components/scatter-chart/index.d.ts +2 -0
  76. package/dist/components/scatter-chart/index.js +1 -0
  77. package/dist/components/scroll-zone/ScrollZone.d.ts +126 -0
  78. package/dist/components/scroll-zone/ScrollZone.js +1 -0
  79. package/dist/components/scroll-zone/index.d.ts +2 -0
  80. package/dist/components/scroll-zone/index.js +1 -0
  81. package/dist/components/select/Select.d.ts +1 -3
  82. package/dist/components/select/Select.js +1 -1
  83. package/dist/components/sparkline/Sparkline.d.ts +67 -0
  84. package/dist/components/sparkline/Sparkline.js +1 -0
  85. package/dist/components/sparkline/index.d.ts +2 -0
  86. package/dist/components/sparkline/index.js +1 -0
  87. package/dist/components/statistic/Statistic.d.ts +7 -0
  88. package/dist/components/statistic/Statistic.js +1 -1
  89. package/dist/components/table/Table.d.ts +13 -2
  90. package/dist/components/table/Table.js +1 -1
  91. package/dist/components/text-link/TextLink.js +1 -1
  92. package/dist/components/time-picker/TimePicker.js +1 -1
  93. package/dist/components/timeline-chart/TimelineChart.d.ts +44 -0
  94. package/dist/components/timeline-chart/TimelineChart.js +1 -0
  95. package/dist/components/timeline-chart/index.d.ts +2 -0
  96. package/dist/components/timeline-chart/index.js +1 -0
  97. package/dist/components/toast/Toast.d.ts +10 -2
  98. package/dist/components/toast/Toast.js +1 -1
  99. package/dist/components/tooltip/Tooltip.d.ts +2 -4
  100. package/dist/components/tooltip/Tooltip.js +1 -1
  101. package/dist/components/tree-view/TreeView.js +1 -1
  102. package/dist/components/window-pane/WindowPane.d.ts +178 -0
  103. package/dist/components/window-pane/WindowPane.js +1 -0
  104. package/dist/components/window-pane/index.d.ts +2 -0
  105. package/dist/components/window-pane/index.js +1 -0
  106. package/dist/index.d.ts +15 -0
  107. package/dist/index.js +1 -1
  108. package/dist/internal/animate.d.ts +0 -9
  109. package/dist/internal/animate.js +1 -1
  110. package/dist/internal/bottom-navigation.d.ts +57 -0
  111. package/dist/internal/bottom-navigation.js +1 -0
  112. package/dist/internal/calendar.js +1 -1
  113. package/dist/internal/chart-frame.d.ts +409 -0
  114. package/dist/internal/chart-frame.js +1 -0
  115. package/dist/internal/chart-line.d.ts +44 -0
  116. package/dist/internal/chart-line.js +1 -0
  117. package/dist/internal/chart.d.ts +456 -0
  118. package/dist/internal/chart.js +1 -0
  119. package/dist/internal/date.d.ts +0 -2
  120. package/dist/internal/date.js +1 -1
  121. package/dist/internal/format.d.ts +29 -0
  122. package/dist/internal/format.js +1 -0
  123. package/dist/internal/i18n.d.ts +143 -0
  124. package/dist/internal/i18n.js +1 -1
  125. package/dist/internal/icons.d.ts +2 -0
  126. package/dist/internal/icons.js +1 -1
  127. package/dist/internal/picker.d.ts +2 -4
  128. package/dist/internal/picker.js +1 -1
  129. package/dist/internal/progress.d.ts +1 -3
  130. package/dist/internal/window.d.ts +201 -0
  131. package/dist/internal/window.js +1 -0
  132. package/dist/styles.css +1 -1
  133. package/dist/tailwind.css +211 -0
  134. package/dist/types.d.ts +214 -0
  135. package/package.json +21 -17
@@ -10,7 +10,7 @@ import type { NebaAlign, NebaSide, NebaStyleProps } from '../../types';
10
10
  * the page by definition, so it carries a shadow at level 3 and a prop that
11
11
  * could sit it flat would be a prop that could stop it being a popover.
12
12
  */
13
- export interface PopoverProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'> {
13
+ export interface PopoverProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'>, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title' | 'children'> {
14
14
  /**
15
15
  * The element the popup hangs off and that opens it. Exactly one element,
16
16
  * which must accept a ref and spread props — every Neba component does.
@@ -69,7 +69,15 @@ export interface PopoverProps extends Pick<NebaStyleProps, 'size' | 'color' | 'd
69
69
  dismissible?: boolean;
70
70
  /** Shows the × in the corner. @default false */
71
71
  showClose?: boolean;
72
- /** Accessible name of the × button. */
72
+ /**
73
+ * Which language the × is named in — a BCP 47 tag such as `ko`, `pt-BR` or
74
+ * `zh-Hant`. Unsupported tags fall back to English.
75
+ *
76
+ * `closeLabel` writes the word out instead; this is for the far more common
77
+ * case where the page already knows its own language.
78
+ */
79
+ locale?: string;
80
+ /** Accessible name of the × button. Defaults to the `locale`'s word for it. */
73
81
  closeLabel?: string;
74
82
  /**
75
83
  * A hard cap on the popup's width, overriding the one `size` implies. Numbers
@@ -77,8 +85,6 @@ export interface PopoverProps extends Pick<NebaStyleProps, 'size' | 'color' | 'd
77
85
  * single line of help — rather than for tuning the scale, which is `size`.
78
86
  */
79
87
  width?: number | string;
80
- className?: string;
81
- style?: React.CSSProperties;
82
88
  }
83
89
  export type PopoverCloseProps = React.ComponentPropsWithoutRef<typeof BaseUIPopover.Close>;
84
90
  /**
@@ -106,4 +112,4 @@ export declare const PopoverClose: React.ForwardRefExoticComponent<Omit<import("
106
112
  * the `aria-labelledby` / `aria-describedby` wiring. What is left here is the
107
113
  * surface, the width ladder and the header.
108
114
  */
109
- export declare function Popover({ size, color, density, trigger, title, description, children, side, align, sideOffset, alignOffset, arrow, open, defaultOpen, onOpenChange, modal, dismissible, showClose, closeLabel, width, className, style }: PopoverProps): React.JSX.Element;
115
+ export declare function Popover({ size, color, density, trigger, title, description, children, side, align, sideOffset, alignOffset, arrow, open, defaultOpen, onOpenChange, modal, dismissible, showClose, locale, closeLabel, width, className, style, ...props }: PopoverProps): React.JSX.Element;
@@ -1 +1 @@
1
- import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Popover as o}from"@base-ui/react/popover";import{boxPaddingXClasses as t,boxPaddingYClasses as n}from"../box/Box";import{CloseIcon as s}from"../../internal/icons";import{hasContent as i,metaTextClasses as l,radiusClasses as r,sheetBodyClasses as d,sheetHeaderGapClasses as c,sheetSectionGapClasses as m,sheetTitleClasses as p,surfaceClasses as f,surfaceSlots as u}from"../../internal/styles";const h={xs:"max-w-56",sm:"max-w-64",md:"max-w-80",lg:"max-w-96",xl:"max-w-lg"},x=[f,"relative flex flex-col","border text-(--neba-fg) bg-(--n-panel-press)","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),b={xs:8,sm:9,md:10,lg:11,xl:12};export const PopoverClose=o.Close;export function Popover({size:f="md",color:g="primary",density:v="default",trigger:w,title:y,description:N,children:_,side:k="bottom",align:j="center",sideOffset:O=6,alignOffset:C=0,arrow:P=!1,open:z,defaultOpen:$,onOpenChange:B,modal:L=!1,dismissible:M=!0,showClose:T=!1,closeLabel:W="Close",width:A,className:D,style:E}){const R=t[v][f],q=n[v][f],F=b[f],G=i(y)||i(N);return a(o.Root,{open:z,defaultOpen:$,modal:L,onOpenChange:(e,a)=>{M||e||"escape-key"!==a.reason&&"outside-press"!==a.reason&&"focus-out"!==a.reason?B?.(e):a.cancel()},children:[w?e(o.Trigger,{render:w}):null,e(o.Portal,{children:e(o.Positioner,{className:"neba-portal z-50 [outline:none]",side:k,align:j,sideOffset:O,alignOffset:C,children:a(o.Popup,{className:[x,r[f],d[f],m[f],R,q,void 0===A?h[f]:"",D??""].filter(Boolean).join(" "),style:{...u(g,3),...void 0===A?null:{maxWidth:"number"==typeof A?`${A}px`:A},...E},children:[P?e(o.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:a("svg",{width:F,height:F/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:[e("path",{d:"M0 0h10L5 5z",fill:"var(--n-panel-press)"}),e("path",{d:"M0 0 5 5 10 0",fill:"none",stroke:"var(--n-line)",strokeWidth:"1",vectorEffect:"non-scaling-stroke"})]})}):null,G||T?a("div",{className:"flex shrink-0 items-start gap-3",children:[a("div",{className:`flex min-w-0 flex-1 flex-col ${c[f]}`,children:[i(y)?e(o.Title,{className:`m-0 font-semibold ${p[f]}`,children:y}):null,i(N)?e(o.Description,{className:`m-0 text-(--neba-muted-fg) ${l[f]}`,children:N}):null]}),T?e(o.Close,{"aria-label":W,className:["flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center","rounded-full text-(--neba-muted-fg)","[&_svg]:size-[1.1em] [&_svg]:shrink-0","[transition:background-color_var(--neba-duration)_var(--neba-ease),color_var(--neba-duration)_var(--neba-ease)]","hover:bg-(--n-soft) hover:text-(--neba-fg)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),children:e(s,{})}):null]}):null,i(_)?e("div",{className:"min-w-0",children:_}):null]})})})]})}
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import{Popover as o}from"@base-ui/react/popover";import{boxPaddingXClasses as t,boxPaddingYClasses as n}from"../box/Box";import{useMessages as i}from"../../internal/i18n";import{CloseIcon as s}from"../../internal/icons";import{hasContent as l,metaTextClasses as r,radiusClasses as d,sheetBodyClasses as c,sheetHeaderGapClasses as m,sheetSectionGapClasses as p,sheetTitleClasses as f,surfaceClasses as u,surfaceSlots as h}from"../../internal/styles";const x={xs:"max-w-56",sm:"max-w-64",md:"max-w-80",lg:"max-w-96",xl:"max-w-lg"},b=[u,"relative flex flex-col","border text-(--neba-fg) bg-(--n-panel-press)","[border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]","[outline:none]","[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),g={xs:8,sm:9,md:10,lg:11,xl:12};export const PopoverClose=o.Close;export function Popover({size:u="md",color:v="primary",density:w="default",trigger:y,title:N,description:_,children:k,side:j="bottom",align:O="center",sideOffset:C=6,alignOffset:P=0,arrow:z=!1,open:$,defaultOpen:B,onOpenChange:L,modal:M=!1,dismissible:T=!0,showClose:W=!1,locale:A,closeLabel:D,width:E,className:R,style:q,...F}){const G=i(A),H=t[w][u],I=n[w][u],J=g[u],K=l(N)||l(_);return a(o.Root,{open:$,defaultOpen:B,modal:M,onOpenChange:(e,a)=>{T||e||"escape-key"!==a.reason&&"outside-press"!==a.reason&&"focus-out"!==a.reason?L?.(e):a.cancel()},children:[y?e(o.Trigger,{render:y}):null,e(o.Portal,{children:e(o.Positioner,{className:"neba-portal z-50 [outline:none]",side:j,align:O,sideOffset:C,alignOffset:P,children:a(o.Popup,{className:[b,d[u],c[u],p[u],H,I,void 0===E?x[u]:"",R??""].filter(Boolean).join(" "),style:{...h(v,3),...void 0===E?null:{maxWidth:"number"==typeof E?`${E}px`:E},...q},...F,children:[z?e(o.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:a("svg",{width:J,height:J/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:[e("path",{d:"M0 0h10L5 5z",fill:"var(--n-panel-press)"}),e("path",{d:"M0 0 5 5 10 0",fill:"none",stroke:"var(--n-line)",strokeWidth:"1",vectorEffect:"non-scaling-stroke"})]})}):null,K||W?a("div",{className:"flex shrink-0 items-start gap-3",children:[a("div",{className:`flex min-w-0 flex-1 flex-col ${m[u]}`,children:[l(N)?e(o.Title,{className:`m-0 font-semibold ${f[u]}`,children:N}):null,l(_)?e(o.Description,{className:`m-0 text-(--neba-muted-fg) ${r[u]}`,children:_}):null]}),W?e(o.Close,{"aria-label":D??G.action.close,className:["flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center","rounded-full text-(--neba-muted-fg)","[&_svg]:size-[1.1em] [&_svg]:shrink-0","[transition:background-color_var(--neba-duration)_var(--neba-ease),color_var(--neba-duration)_var(--neba-ease)]","hover:bg-(--n-soft) hover:text-(--neba-fg)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" "),children:e(s,{})}):null]}):null,l(k)?e("div",{className:"min-w-0",children:k}):null]})})})]})}
@@ -1 +1 @@
1
- import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Progress as t}from"@base-ui/react/progress";import{plateGapClasses as n,plateRadiusClasses as r,plateSizeClasses as s,progressAriaText as i,progressFraction as o,progressSlots as m,progressText as f}from"../../internal/progress";import{metaTextClasses as c,stackGapClasses as u}from"../../internal/styles";export const ProgressBox=l.forwardRef(function({size:l="md",color:d="primary",count:h=4,value:x=null,min:b=0,max:p=100,label:g,showValue:v=!1,format:y,className:w,style:j},N){const M=o(x,b,p),B=null===M,V=void 0!==y,k=Math.max(1,Math.floor(h));return a(t.Root,{ref:N,value:x??null,min:b,max:p,format:y,getAriaValueText:i(M,V),className:["inline-flex flex-col",u[l],w??""].filter(Boolean).join(" "),style:{...m(d),...j},children:[g||v?a("div",{className:["flex items-baseline gap-2",g?"justify-between":"justify-end",c[l]].join(" "),children:[g?e(t.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:g}):null,v?e(t.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>f(M,e,V)}):null]}):null,e(t.Track,{className:`flex ${n[l]}`,children:Array.from({length:k},(a,t)=>e("span",{className:["relative overflow-hidden bg-(--n-soft)","[box-shadow:var(--neba-plate-glass)]",s[l],r[l],B?"neba-plate-wave":""].filter(Boolean).join(" "),style:B?{"--n-i":t}:void 0,children:B?null:e("span",{className:"absolute inset-y-0 start-0 bg-(--n-fill) [transition:width_var(--neba-duration-fill)_var(--neba-ease)]",style:{width:`${Math.min(100,Math.max(0,100*(M*k-t)))}%`}})},t))})]})});
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Progress as t}from"@base-ui/react/progress";import{plateGapClasses as n,plateRadiusClasses as r,plateSizeClasses as s,progressAriaText as i,progressFraction as o,progressSlots as m,progressText as f}from"../../internal/progress";import{metaTextClasses as c,stackGapClasses as u}from"../../internal/styles";export const ProgressBox=l.forwardRef(function({size:l="md",color:d="primary",count:h=4,value:x=null,min:b=0,max:p=100,label:g,showValue:v=!1,format:y,className:w,style:j,...N},M){const B=o(x,b,p),V=null===B,k=void 0!==y,A=Math.max(1,Math.floor(h));return a(t.Root,{ref:M,value:x??null,min:b,max:p,format:y,getAriaValueText:i(B,k),className:["inline-flex flex-col",u[l],w??""].filter(Boolean).join(" "),style:{...m(d),...j},...N,children:[g||v?a("div",{className:["flex items-baseline gap-2",g?"justify-between":"justify-end",c[l]].join(" "),children:[g?e(t.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:g}):null,v?e(t.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>f(B,e,k)}):null]}):null,e(t.Track,{className:`flex ${n[l]}`,children:Array.from({length:A},(a,t)=>e("span",{className:["relative overflow-hidden bg-(--n-soft)","[box-shadow:var(--neba-plate-glass)]",s[l],r[l],V?"neba-plate-wave":""].filter(Boolean).join(" "),style:V?{"--n-i":t}:void 0,children:V?null:e("span",{className:"absolute inset-y-0 start-0 bg-(--n-fill) [transition:width_var(--neba-duration-fill)_var(--neba-ease)]",style:{width:`${Math.min(100,Math.max(0,100*(B*A-t)))}%`}})},t))})]})});
@@ -1 +1 @@
1
- import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{Progress as t}from"@base-ui/react/progress";import{progressAriaText as s,progressFraction as n,progressSlots as i,progressText as o,ringDiameters as l,ringStrokes as c}from"../../internal/progress";import{gapClasses as m,metaTextClasses as f}from"../../internal/styles";export const ProgressCircular=a.forwardRef(function({size:a="md",color:u="primary",value:h=null,min:d=0,max:x=100,label:k,showValue:p=!1,format:b,className:g,style:v},y){const $=n(h,d,x),N=null===$,w=void 0!==b,j=l[a],V=c[a],B=j/2,D=B-V/2,L=2*Math.PI*D,P=N?`${.28*L} ${L}`:`${L}`,R=N?0:L*(1-$);return r(t.Root,{ref:y,value:h??null,min:d,max:x,format:b,getAriaValueText:s($,w),className:["inline-flex items-center",m[a],f[a],g??""].filter(Boolean).join(" "),style:{...i(u),...v},children:[r("svg",{className:N?"neba-ring-spin shrink-0":"shrink-0",width:j,height:j,viewBox:`0 0 ${j} ${j}`,fill:"none","aria-hidden":"true",children:[e("circle",{cx:B,cy:B,r:D,stroke:"var(--n-soft)",strokeWidth:V}),e("circle",{cx:B,cy:B,r:D,stroke:"var(--n-accent)",strokeWidth:V,strokeLinecap:"round",strokeDasharray:P,strokeDashoffset:R,transform:`rotate(-90 ${B} ${B})`,className:"[transition:stroke-dashoffset_var(--neba-duration-fill)_var(--neba-ease)]"})]}),k?e(t.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:k}):null,p?e(t.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>o($,e,w)}):null]})});
1
+ import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{Progress as t}from"@base-ui/react/progress";import{progressAriaText as s,progressFraction as n,progressSlots as i,progressText as o,ringDiameters as l,ringStrokes as c}from"../../internal/progress";import{gapClasses as m,metaTextClasses as f}from"../../internal/styles";export const ProgressCircular=a.forwardRef(function({size:a="md",color:u="primary",value:h=null,min:d=0,max:x=100,label:k,showValue:p=!1,format:b,className:g,style:v,...y},$){const N=n(h,d,x),w=null===N,j=void 0!==b,V=l[a],B=c[a],D=V/2,L=D-B/2,P=2*Math.PI*L,R=w?`${.28*P} ${P}`:`${P}`,W=w?0:P*(1-N);return r(t.Root,{ref:$,value:h??null,min:d,max:x,format:b,getAriaValueText:s(N,j),className:["inline-flex items-center",m[a],f[a],g??""].filter(Boolean).join(" "),style:{...i(u),...v},...y,children:[r("svg",{className:w?"neba-ring-spin shrink-0":"shrink-0",width:V,height:V,viewBox:`0 0 ${V} ${V}`,fill:"none","aria-hidden":"true",children:[e("circle",{cx:D,cy:D,r:L,stroke:"var(--n-soft)",strokeWidth:B}),e("circle",{cx:D,cy:D,r:L,stroke:"var(--n-accent)",strokeWidth:B,strokeLinecap:"round",strokeDasharray:R,strokeDashoffset:W,transform:`rotate(-90 ${D} ${D})`,className:"[transition:stroke-dashoffset_var(--neba-duration-fill)_var(--neba-ease)]"})]}),k?e(t.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:k}):null,p?e(t.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>o(N,e,j)}):null]})});
@@ -1 +1 @@
1
- import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as a from"react";import{Progress as r}from"@base-ui/react/progress";import{barThicknessClasses as n,progressAriaText as s,progressFraction as t,progressSlots as i,progressText as o}from"../../internal/progress";import{metaTextClasses as m,stackGapClasses as u}from"../../internal/styles";export const ProgressLinear=a.forwardRef(function({size:a="md",color:f="primary",value:c=null,min:d=0,max:b=100,label:p,showValue:x=!1,format:g,className:h,style:w},j){const v=t(c,d,b),N=null===v,y=void 0!==g;return l(r.Root,{ref:j,value:c??null,min:d,max:b,format:g,getAriaValueText:s(v,y),className:["flex w-full flex-col",u[a],h??""].filter(Boolean).join(" "),style:{...i(f),...w},children:[p||x?l("div",{className:["flex items-baseline gap-2",p?"justify-between":"justify-end",m[a]].join(" "),children:[p?e(r.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:p}):null,x?e(r.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>o(v,e,y)}):null]}):null,e(r.Track,{className:`relative w-full overflow-hidden rounded-full bg-(--n-soft) ${n[a]}`,children:e(r.Indicator,{className:["absolute rounded-full bg-(--n-fill)",N?"neba-sweep":"top-0 [transition:width_var(--neba-duration-fill)_var(--neba-ease)]"].join(" ")})})]})});
1
+ import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as a from"react";import{Progress as r}from"@base-ui/react/progress";import{barThicknessClasses as n,progressAriaText as s,progressFraction as t,progressSlots as i,progressText as o}from"../../internal/progress";import{metaTextClasses as m,stackGapClasses as u}from"../../internal/styles";export const ProgressLinear=a.forwardRef(function({size:a="md",color:f="primary",value:c=null,min:d=0,max:b=100,label:p,showValue:x=!1,format:g,className:h,style:w,...j},v){const N=t(c,d,b),y=null===N,V=void 0!==g;return l(r.Root,{ref:v,value:c??null,min:d,max:b,format:g,getAriaValueText:s(N,V),className:["flex w-full flex-col",u[a],h??""].filter(Boolean).join(" "),style:{...i(f),...w},...j,children:[p||x?l("div",{className:["flex items-baseline gap-2",p?"justify-between":"justify-end",m[a]].join(" "),children:[p?e(r.Label,{className:"min-w-0 truncate text-(--neba-fg)",children:p}):null,x?e(r.Value,{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:e=>o(N,e,V)}):null]}):null,e(r.Track,{className:`relative w-full overflow-hidden rounded-full bg-(--n-soft) ${n[a]}`,children:e(r.Indicator,{className:["absolute rounded-full bg-(--n-fill)",y?"neba-sweep":"top-0 [transition:width_var(--neba-duration-fill)_var(--neba-ease)]"].join(" ")})})]})});
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import type { NebaColor, NebaSize } from '../../types';
3
+ export interface RatingProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
4
+ /** How much is rated. Use with `onValueChange` for a controlled Rating. */
5
+ value?: number;
6
+ /**
7
+ * Where an uncontrolled Rating starts.
8
+ * @default 0
9
+ */
10
+ defaultValue?: number;
11
+ /** Called with the new score. `0` is what a cleared Rating reports. */
12
+ onValueChange?: (value: number) => void;
13
+ /**
14
+ * How many stars there are, and therefore the highest score.
15
+ * @default 5
16
+ */
17
+ count?: number;
18
+ /**
19
+ * The smallest step that can be *chosen*, as a fraction of one star — `0.5`
20
+ * gives half stars, `1` whole ones. Anything outside `0 < precision <= 1`
21
+ * falls back to `1`.
22
+ *
23
+ * It bounds what a reader can pick and nothing else: a `value` of `4.3` is
24
+ * drawn as four stars and a third at every precision, because an average is
25
+ * not a choice and rounding it to the nearest half would be reporting a
26
+ * different number from the one it was handed.
27
+ * @default 1
28
+ */
29
+ precision?: number;
30
+ /** The glyph a filled star is drawn with. */
31
+ icon?: React.ReactNode;
32
+ /** And the one an empty star is drawn with. Has to be the same shape. */
33
+ emptyIcon?: React.ReactNode;
34
+ /**
35
+ * Choosing the score that is already chosen clears it back to `0`.
36
+ * @default true
37
+ */
38
+ clearable?: boolean;
39
+ /**
40
+ * Shows the score without letting it be changed — a product's average, a
41
+ * rating somebody else left.
42
+ *
43
+ * This is the one `readOnly` in the library that does not drain the
44
+ * saturation, because it is not a control being held still: there are no
45
+ * inputs at all, and what is left is a picture of a number. A row of grey
46
+ * stars would say the score itself was unavailable.
47
+ * @default false
48
+ */
49
+ readOnly?: boolean;
50
+ /** Unavailable. Drops the colour family for neutral grey. */
51
+ disabled?: boolean;
52
+ /** Identifies the value when a form is submitted. */
53
+ name?: string;
54
+ /** A form will not submit until a star has been chosen. */
55
+ required?: boolean;
56
+ /** Height of one star, on the standalone-glyph ladder. @default 'md' */
57
+ size?: NebaSize;
58
+ /**
59
+ * Semantic colour role. `warning` by default — the amber a star is expected
60
+ * to be — rather than `primary`, which is the one place in the library a
61
+ * component's default colour is chosen by what the object is instead of by
62
+ * what it means.
63
+ * @default 'warning'
64
+ */
65
+ color?: NebaColor;
66
+ /**
67
+ * Which language the accessible names are written in — a BCP 47 tag such as
68
+ * `ko`, `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
69
+ */
70
+ locale?: string;
71
+ /** Names the whole control. Defaults to the `locale`'s word for "Rating". */
72
+ label?: string;
73
+ /**
74
+ * What one star, and the whole control once it is read only, is called.
75
+ * Defaults to the `locale`'s way of saying "3 out of 5".
76
+ */
77
+ valueLabel?: (value: number, count: number) => string;
78
+ }
79
+ /**
80
+ * A score out of five, as a row of stars.
81
+ *
82
+ * Underneath an interactive Rating is a radio group of real `<input>`s, one per
83
+ * choosable score, each visually hidden under the half-star it stands for. That
84
+ * is the whole accessibility argument: a rating *is* "exactly one of these", so
85
+ * it gets one tab stop for the row, arrow keys within it, `aria-checked` on the
86
+ * one that is taken, and a value in a form submission — none of which a row of
87
+ * `<button>`s or a `<div>` with a click handler would have.
88
+ *
89
+ * The fraction is drawn by laying the filled star over the empty one and
90
+ * clipping it to a percentage of the width. Nothing is transformed and no glyph
91
+ * is scaled, so a half star is the left half of exactly the star beside it. The
92
+ * clip runs from the inline start, so it fills from the right under RTL without
93
+ * anything being told to.
94
+ *
95
+ * `readOnly` is a different component in the same clothes: no inputs, no radio
96
+ * group, and one `role="img"` carrying the score as a sentence. A star display
97
+ * that keeps twenty focusable radios is twenty tab stops on a page that was
98
+ * only reporting a number.
99
+ */
100
+ export declare const Rating: React.ForwardRefExoticComponent<RatingProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as n from"react";import{StarIcon as t,StarOutlineIcon as r}from"../../internal/icons";import{fillMessage as l,useMessages as i}from"../../internal/i18n";import{controlSlots as o,focusWithinRingClasses as s,gapClasses as d,iconSizeClasses as m,radiusClasses as c,srOnlyClasses as u,transitionClasses as h}from"../../internal/styles";const f="flex items-center justify-center";export const Rating=n.forwardRef(function({value:b,defaultValue:p=0,onValueChange:x,count:g=5,precision:y=1,icon:v,emptyIcon:N,clearable:j=!0,readOnly:M=!1,disabled:w=!1,name:k,required:S=!1,size:C="md",color:L="warning",locale:P,label:q,valueLabel:I,className:A,style:B,onPointerLeave:R,...V},z){const E=i(P),F=n.useId(),O=k??F,[D,G]=n.useState(p),H=void 0!==b,J=H?b:D,[K,Q]=n.useState(null),T=Math.max(1,Math.floor(g)),U=y>0&&y<=1?y:1,W=Math.round(1/U),X=Math.max(0,Math.min(T,K??J)),Y=n.useCallback(e=>I?I(e,T):e<=0?E.rating.empty:l(E.rating.value,{value:String(e),max:String(T)}),[I,T,E]),Z=e=>{H||G(e),x?.(e)},$=Array.from({length:T},(n,l)=>{const i=Math.max(0,Math.min(1,X-l));return a("span",{className:["relative inline-flex shrink-0",m[C],c.xs,M||w?"":s].filter(Boolean).join(" "),children:[e("span",{className:[f,m[C],w?"text-(--neba-disabled-fg)":"text-(--n-empty)"].join(" "),children:N??e(r,{})}),e("span",{"aria-hidden":"true",className:"pointer-events-none absolute inset-y-0 start-0 overflow-hidden",style:{width:100*i+"%"},children:e("span",{className:[f,m[C],w?"text-(--neba-disabled-fg)":"text-(--n-fill)",h].join(" "),children:v??e(t,{})})}),M?null:Array.from({length:W},(a,n)=>{const t=Number((l+(n+1)*U).toFixed(4));return e("label",{className:["absolute inset-y-0",w?"cursor-not-allowed":"cursor-pointer"].join(" "),style:{insetInlineStart:100*n/W+"%",width:100/W+"%"},onPointerEnter:()=>{w||Q(t)},children:e("input",{type:"radio",className:u,name:O,value:t,checked:J===t,disabled:w,required:S,"aria-label":Y(t),onChange:()=>Z(t),onClick:()=>{j&&J===t&&Z(0)}})},t)})]},l)}),_=["inline-flex items-center align-middle",d[C],w?"cursor-not-allowed":"",A??""].filter(Boolean).join(" "),ee={...o(L,0,"solid"),"--n-empty":"color-mix(in oklab, var(--neba-muted-fg) 40%, transparent)",...B};return e("div",M?{ref:z,role:"img","aria-label":Y(Math.max(0,Math.min(T,J))),className:_,style:ee,onPointerLeave:R,...V,children:$}:{ref:z,role:"radiogroup","aria-label":q??E.rating.label,"aria-disabled":w||void 0,"aria-required":S||void 0,className:_,style:ee,onPointerLeave:e=>{Q(null),R?.(e)},...V,children:$})});
@@ -0,0 +1 @@
1
+ export * from './Rating';
@@ -0,0 +1 @@
1
+ export*from"./Rating";
@@ -0,0 +1,45 @@
1
+ import * as React from 'react';
2
+ import { type CartesianChartProps } from '../../internal/chart-frame';
3
+ import { type MarkShape } from '../../internal/chart';
4
+ export interface ScatterChartProps extends CartesianChartProps {
5
+ /**
6
+ * What each mark is drawn as.
7
+ *
8
+ * - `auto` — the default. A circle while colour alone can carry identity, and
9
+ * a shape per series from the fourth on, because past three series it
10
+ * cannot: two of the palette's hues are indistinguishable under
11
+ * deuteranopia, and a shape is the one channel a dot has going spare.
12
+ * - `varied` — a shape per series always, in the fixed order circle, square,
13
+ * triangle, diamond, cross. Reach for it when the chart will be printed or
14
+ * read in greyscale.
15
+ * - one of the five names — every mark the same shape. On four or more series
16
+ * this is opting out of the second channel; do it only when each series
17
+ * carries a `color` of its own.
18
+ * @default 'auto'
19
+ */
20
+ shape?: MarkShape | 'varied' | 'auto';
21
+ /**
22
+ * The radius of a mark with no `z`, in pixels.
23
+ * @default the `size` ladder — 4 at `md`
24
+ */
25
+ pointRadius?: number;
26
+ /**
27
+ * The radius of the largest bubble, in pixels. Everything else is scaled
28
+ * under it by area.
29
+ * @default a twelfth of the chart's height
30
+ */
31
+ maxRadius?: number;
32
+ }
33
+ /**
34
+ * Two numbers per point, and whether they move together.
35
+ *
36
+ * Both axes measure, which is what makes this the only chart in the library
37
+ * with no categories: there is no column a mark belongs to and no order the
38
+ * points could be shuffled out of. A point with a `z` is drawn as a bubble and
39
+ * one without it as a dot, so a scatter and a bubble chart are the same
40
+ * component reading the same data — the third number is simply present or not.
41
+ *
42
+ * `x` must be a number or a `Date`. A string has no place on a number line, and
43
+ * a chart of named things against one measure is a [BarChart](./bar-chart).
44
+ */
45
+ export declare function ScatterChart({ shape, pointRadius, maxRadius, series, categories, size, xAxis, ...props }: ScatterChartProps): React.JSX.Element;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as a from"react";import{CartesianChart as l}from"../../internal/chart-frame";import{bubbleRadius as t,formatCategory as i,markerRadii as s,markGap as o,markPath as n,markShapes as c,plotHeights as u,pointX as d}from"../../internal/chart";import{cx as h,srOnlyClasses as m}from"../../internal/styles";export function ScatterChart({shape:r="auto",pointRadius:i,maxRadius:o,series:h,categories:m,size:p="md",xAxis:b,...v}){const y=i??s[p],g=o??Math.max(y+2,("number"==typeof v.height?v.height:u[p])/12),z=h.reduce((e,r)=>r.color?e:e+1,0),k="auto"===r||"varied"===r?"circle":r,M="varied"===r||"auto"===r&&z>3,j=a.useCallback(e=>M?c[e%c.length]:k,[M,k]),w=a.useCallback(e=>{const r=[];let a=0;return e.values.forEach(e=>{e.forEach(e=>{null!==e.value&&void 0!==e.z&&Number.isFinite(e.z)&&(a=Math.max(a,e.z))})}),e.values.forEach((l,i)=>{e.visible[i]&&l.forEach((l,s)=>{if(null===l.value)return;const o=d(l,s,m);null!==o&&r.push({series:i,index:s,x:e.categoryValuePx(o),y:e.valuePx(l.value),r:void 0===l.z?y:t(l.z,a,g,2)})})}),r},[m,y,g]);return e(l,{...v,series:h,categories:m,size:p,xScale:"value",xAxis:b,marks:w,markInset:g,includeZero:!1,swatch:(r,a)=>e("svg",{viewBox:"0 0 10 10",className:"size-2.5 overflow-visible","aria-hidden":"true",children:e("path",{d:n(j(r),5,5,4),fill:a})}),table:r=>e(f,{id:r,series:h,categories:m,label:v.label,xLabel:b?.label,yLabel:v.yAxis?.label,locale:v.locale,format:v.format}),children:r=>e(x,{context:r,shapeOf:j})})}function x({context:r,shapeOf:l}){const{marks:t,values:i,colors:s,hovered:c,activeMark:u}=r,d=a.useMemo(()=>[...t].sort((e,r)=>r.r-e.r),[t]);return e("g",{children:d.map(r=>{const a=i[r.series]?.[r.index],t=null!==c&&c!==r.series,d=u?.series===r.series&&u?.index===r.index;return e("path",{d:n(l(r.series),r.x,r.y,d?r.r+1:r.r),fill:a?.color??s[r.series],stroke:"var(--neba-chart-gap)",strokeWidth:o,opacity:t?.28:1},`${r.series}-${r.index}`)})})}function f({id:l,series:t,categories:s,label:o,xLabel:n,yLabel:c,locale:u,format:d}){const x=a.useMemo(()=>new Intl.NumberFormat(u,d??{maximumFractionDigits:2}),[u,d]),f=t.some(e=>e.data.some(e=>"object"==typeof e&&null!==e&&void 0!==e.z));return r("table",{id:l,className:h(m),children:[o?e("caption",{children:o}):null,e("thead",{children:r("tr",{children:[e("th",{scope:"col"}),e("th",{scope:"col",children:n??"x"}),e("th",{scope:"col",children:c??"y"}),f?e("th",{scope:"col",children:"z"}):null]})}),e("tbody",{children:t.flatMap((a,l)=>a.data.map((t,o)=>{const n="object"==typeof t&&null!==t?t:null,c=n?n.y:"number"==typeof t?t:null,d=n?.x??s?.[o]??o;return r("tr",{children:[e("th",{scope:"row",children:a.name??l+1}),e("td",{children:i(d,u)}),e("td",{children:null!==c&&Number.isFinite(c)?x.format(c):""}),f?e("td",{children:void 0===n?.z?"":x.format(n.z)}):null]},`${l}-${o}`)}))})]})}
@@ -0,0 +1,2 @@
1
+ export { ScatterChart } from './ScatterChart';
2
+ export type { ScatterChartProps } from './ScatterChart';
@@ -0,0 +1 @@
1
+ export{ScatterChart}from"./ScatterChart";
@@ -0,0 +1,126 @@
1
+ import * as React from 'react';
2
+ import type { NebaOrientation, NebaStyleProps } from '../../types';
3
+ /**
4
+ * When the scroll buttons are drawn.
5
+ *
6
+ * - `auto` — only the one that has somewhere to go, and neither of them while
7
+ * everything fits. The default: a control that cannot do anything is worse
8
+ * than no control, and a row that does not overflow is not a scroller.
9
+ * - `always` — both, from the first paint, with the one that has nowhere to go
10
+ * `disabled` rather than gone. What a row whose content arrives later wants,
11
+ * since the buttons do not appear under the pointer half a second in.
12
+ * - `none` — none at all. Dragging, the wheel and the arrow keys are still
13
+ * there; this is the strip that scrolls the way a phone scrolls.
14
+ */
15
+ export type ScrollZoneButtons = 'auto' | 'always' | 'none';
16
+ /**
17
+ * What pressing a scroll button does.
18
+ *
19
+ * - `item` — moves to the next child along, `step` of them at a time. The
20
+ * default, and the only one that lands on something rather than between two
21
+ * things.
22
+ * - `page` — moves by everything currently on screen, the way Page Down does.
23
+ * - `hold` — scrolls for as long as the button is held, at `speed` pixels a
24
+ * second. A press too short to be a hold falls back to one `item`, so the
25
+ * button is never dead to a quick tap.
26
+ */
27
+ export type ScrollZoneMode = 'item' | 'page' | 'hold';
28
+ /**
29
+ * Where the scroll buttons sit, which is also where the strip ends.
30
+ *
31
+ * - `overlay` — over the ends of the strip, which keeps every pixel of the box
32
+ * for content and lets an item pass under a button. The default, and what a
33
+ * shelf of pictures wants.
34
+ * - `inline` — beside the strip, in the layout. The scroller stops where the
35
+ * button starts, so an item is *cut off* at the button's edge rather than
36
+ * sliding beneath it: nothing is ever half-hidden behind a control, and the
37
+ * button is legible over the page rather than over whatever it landed on.
38
+ *
39
+ * The lane an `inline` button sits in is kept even while that button has
40
+ * nowhere to go, or the strip would resize under the pointer every time it
41
+ * reached an end.
42
+ */
43
+ export type ScrollZoneButtonPlacement = 'overlay' | 'inline';
44
+ export interface ScrollZoneProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
45
+ /**
46
+ * Which way the children run, and therefore which way the zone scrolls.
47
+ * @default 'horizontal'
48
+ */
49
+ orientation?: NebaOrientation;
50
+ /**
51
+ * How many rows a horizontal zone lays its children out in before it starts a
52
+ * new column — and how many columns a vertical one uses. `2` is the shelf
53
+ * that holds twice as much in the same width.
54
+ * @default 1
55
+ */
56
+ lines?: number;
57
+ /**
58
+ * The gap between children, on Tailwind's spacing scale: `2` is `0.5rem`, the
59
+ * same step `gap-2` is. The same ladder GridContainer's own `spacing` is on.
60
+ * @default 2
61
+ */
62
+ spacing?: number;
63
+ /** When the scroll buttons are drawn. @default 'auto' */
64
+ buttons?: ScrollZoneButtons;
65
+ /**
66
+ * Whether the buttons sit over the strip or beside it. `inline` is what to
67
+ * reach for when an item disappearing under a button reads as a bug rather
68
+ * than as depth.
69
+ * @default 'overlay'
70
+ */
71
+ buttonPlacement?: ScrollZoneButtonPlacement;
72
+ /** What pressing one does. @default 'item' */
73
+ mode?: ScrollZoneMode;
74
+ /** How many children one press moves, in `item` mode. @default 1 */
75
+ step?: number;
76
+ /** How fast a held button scrolls, in pixels a second. @default 900 */
77
+ speed?: number;
78
+ /**
79
+ * Snaps the nearest child to the leading edge when the scrolling stops —
80
+ * dragging and the wheel included, not only the buttons.
81
+ * @default false
82
+ */
83
+ snap?: boolean;
84
+ /**
85
+ * Lets a mouse or a pen drag the strip along, the way a finger already does.
86
+ * Touch is left to the browser, whose own scrolling is better than anything a
87
+ * handler can imitate: momentum, rubber-banding and the scrollbar all come
88
+ * with it.
89
+ * @default true
90
+ */
91
+ drag?: boolean;
92
+ /** Shows the native scrollbar. @default false */
93
+ scrollbar?: boolean;
94
+ /**
95
+ * Which language the buttons name themselves in — a BCP 47 tag such as `ko`,
96
+ * `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
97
+ */
98
+ locale?: string;
99
+ /** What the scrollable region is called — "Categories", "Recent files". */
100
+ label?: string;
101
+ /** Overrides the buttons' own names. */
102
+ previousLabel?: string;
103
+ nextLabel?: string;
104
+ /** What is being laid out. Every top-level child is one item of the strip. */
105
+ children?: React.ReactNode;
106
+ }
107
+ /**
108
+ * A strip of anything, laid out in one direction and scrolled in it.
109
+ *
110
+ * The mechanism is an ordinary scroll container, and everything the component
111
+ * offers is a way of driving one. Swiping on a phone, two-finger dragging on a
112
+ * trackpad, the wheel, the arrow keys and the scrollbar are the browser's own
113
+ * and are never intercepted; what is added on top is a pair of buttons for the
114
+ * pointer that has neither a wheel nor a finger, and a mouse drag for the strip
115
+ * that reads as something to pull rather than something to page.
116
+ *
117
+ * Nothing is transformed. A translated track would have to argue for an
118
+ * exception to the house rule; a scroll offset does not, and it is also what
119
+ * makes the strip run the other way under RTL without being told, keeps the
120
+ * scrollbar honest, and lets the browser scroll a focused child into view.
121
+ *
122
+ * `lines` is what separates this from a Carousel: a Carousel is one thing at a
123
+ * time and knows which one, a ScrollZone is a shelf that happens to be longer
124
+ * than the room it is in.
125
+ */
126
+ export declare const ScrollZone: React.ForwardRefExoticComponent<ScrollZoneProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{IconButton as r}from"../icon-button/IconButton";import{spacingValue as o}from"../../internal/grid";import{useMessages as i}from"../../internal/i18n";import{ChevronIcon as s}from"../../internal/icons";import{cx as l}from"../../internal/styles";const a={xs:"p-1",sm:"p-1.5",md:"p-2",lg:"p-3",xl:"p-4"},c={xs:"gap-1",sm:"gap-1.5",md:"gap-2",lg:"gap-3",xl:"gap-4"};export const ScrollZone=n.forwardRef(function({orientation:u="horizontal",lines:d=1,spacing:m=2,buttons:p="auto",buttonPlacement:f="overlay",mode:v="item",step:b=1,speed:w=900,snap:g=!1,drag:h=!0,scrollbar:y=!1,variant:x="solid",size:k="md",color:L="primary",density:E="default",locale:C,label:R,previousLabel:P,nextLabel:M,className:N,style:T,children:A,...z},j){const D=i(C),S="horizontal"===u,B=Math.max(1,Math.round(d)),F=Math.max(1,Math.round(b)),H=n.useRef(null),I=n.useRef(null),[W,$]=n.useState({back:!1,forward:!1}),q=n.useCallback(()=>{const e=H.current;if(!e)return;const t=S?e.clientWidth:e.clientHeight,n=S?e.scrollWidth:e.scrollHeight,r=Math.abs(S?e.scrollLeft:e.scrollTop);$(e=>{const o=r>1,i=n-t-r>1;return e.back===o&&e.forward===i?e:{back:o,forward:i}})},[S]);n.useEffect(()=>{const e=H.current,t=I.current;if(!e)return;if(q(),"undefined"==typeof ResizeObserver)return;const n=new ResizeObserver(q);return n.observe(e),t&&n.observe(t),()=>n.disconnect()},[q]);const O=n.useCallback(()=>{const e=H.current;return e&&S&&"rtl"===getComputedStyle(e).direction?-1:1},[S]),X=n.useCallback((e,t)=>{const n=H.current;if(!n)return;const r=t?"undefined"!=typeof window&&window.matchMedia?.("(prefers-reduced-motion: reduce)").matches?"auto":"smooth":"auto";n.scrollBy(S?{left:e,behavior:r}:{top:e,behavior:r})},[S]),Y=n.useCallback(()=>{const e=H.current,t=I.current;if(!e||!t)return[];const n=S&&"rtl"===getComputedStyle(e).direction,r=S?n?"right":"left":"top",o=n?-1:1,i=e.getBoundingClientRect()[r],s=[];for(const e of Array.from(t.children)){const t=Math.round((e.getBoundingClientRect()[r]-i)*o);s.includes(t)||s.push(t)}return s.sort((e,t)=>e-t)},[S]),_=n.useCallback((e,t=v)=>{const n=H.current;if(!n)return;const r=O(),o=S?n.clientWidth:n.clientHeight;if("page"===t)return void X(o*(e?1:-1)*r,!0);const i=Y(),s=i.filter(e=>e>1),l=i.filter(e=>e<-1),a=e?s[F-1]:l[l.length-F];X(void 0!==a?a*r:o*(e?1:-1)*r,!0)},[O,S,Y,F,v,X]),K=n.useRef(null);n.useEffect(()=>()=>K.current?.(),[]);const V=n.useCallback((e,t)=>{if(K.current)return;const n=O(),r=performance.now();let o=r,i=0;const s=t=>{const r=t-o;o=t,X(w*r/1e3*(e?1:-1)*n,!1),i=requestAnimationFrame(s)};i=requestAnimationFrame(s);const l=()=>{cancelAnimationFrame(i),K.current=null,window.removeEventListener(t,l),window.removeEventListener("pointercancel",l),window.removeEventListener("blur",l),performance.now()-r<140&&_(e,"item")};K.current=l,window.addEventListener(t,l),window.addEventListener("pointercancel",l),window.addEventListener("blur",l)},[_,O,X,w]),Z=n.useRef(null);function G(e){return"hold"!==v?{onClick:()=>_(e)}:{onPointerDown:t=>{0===t.button&&V(e,"pointerup")},onKeyDown:t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),V(e,"keyup"))}}}n.useEffect(()=>()=>Z.current?.(),[]);const J="none"!==p&&("always"===p||W.back||W.forward),Q="inline"===f;function U(t){const n=t?W.forward:W.back;if("auto"===p&&!n&&!Q)return e("span",{});const o=S?t?"-rotate-90 rtl:rotate-90":"rotate-90 rtl:-rotate-90":t?"":"rotate-180",i="auto"===p&&!n,a=e(r,{variant:x,size:k,color:L,density:E,elevation:1,label:t?M??D.scroll.next:P??D.scroll.previous,disabled:!n,className:"pointer-events-auto",icon:e("span",{className:l("flex items-center",o),children:e(s,{})}),...G(t)});return Q?e("span",{className:l("flex shrink-0 items-center justify-center",i?"invisible":""),inert:i,children:a}):a}return t("div",{ref:j,className:l("relative flex min-w-0",Q&&S?"flex-row items-stretch":"flex-col",Q?c[k]:"",N),style:{"--n-ring":`var(--neba-${L}-ring)`,...T},...z,children:[J&&Q?U(!1):null,e("div",{ref:H,tabIndex:0,role:R?"group":void 0,"aria-label":R,className:l("min-h-0 min-w-0 grow",S?"overflow-x-auto overflow-y-hidden":"overflow-y-auto overflow-x-hidden",g?S?"snap-x snap-mandatory":"snap-y snap-mandatory":"",y?"":"[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",h&&(W.back||W.forward)?"cursor-grab data-[dragging]:cursor-grabbing":"","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:[outline-offset:-2px]"),onScroll:q,onPointerDown:function(e){if(!h||"touch"===e.pointerType||0!==e.button)return;Z.current?.();const t=e.currentTarget,n=e.clientX,r=e.clientY,o=t.scrollLeft,i=t.scrollTop;let s=!1;const l=document.body.style.getPropertyValue("-webkit-user-select"),a=e=>{const l=e.clientX-n,a=e.clientY-r;if(!s){if(Math.abs(S?l:a)<4)return;s=!0,t.setPointerCapture(e.pointerId),t.dataset.dragging="true",document.body.style.setProperty("-webkit-user-select","none")}S?t.scrollLeft=o-l:t.scrollTop=i-a},c=()=>{Z.current=null,t.removeEventListener("pointermove",a),t.removeEventListener("pointerup",u),t.removeEventListener("pointercancel",c),delete t.dataset.dragging,l?document.body.style.setProperty("-webkit-user-select",l):document.body.style.removeProperty("-webkit-user-select")},u=()=>{const e=s;if(c(),!e)return;const n=e=>{e.stopPropagation(),e.preventDefault()};t.addEventListener("click",n,{capture:!0,once:!0}),window.setTimeout(()=>t.removeEventListener("click",n,!0),0)};Z.current=c,t.addEventListener("pointermove",a),t.addEventListener("pointerup",u),t.addEventListener("pointercancel",c)},children:e("div",{ref:I,className:l(g?"[&>*]:snap-start":""),style:{display:"grid",gap:o(m),gridAutoFlow:S?"column":"row",...S?{width:"max-content",gridTemplateRows:`repeat(${B}, auto)`,gridAutoColumns:"max-content"}:{gridTemplateColumns:`repeat(${B}, minmax(0, 1fr))`,gridAutoRows:"max-content"}},children:A})}),J&&Q?U(!0):null,J&&!Q?t("div",{className:l("pointer-events-none absolute inset-0 flex justify-between",S?"items-center":"flex-col items-center",a[k]),children:[U(!1),U(!0)]}):null]})});
@@ -0,0 +1,2 @@
1
+ export { ScrollZone } from './ScrollZone';
2
+ export type { ScrollZoneButtonPlacement, ScrollZoneButtons, ScrollZoneMode, ScrollZoneProps } from './ScrollZone';
@@ -0,0 +1 @@
1
+ export{ScrollZone}from"./ScrollZone";
@@ -18,7 +18,7 @@ export interface SelectOption {
18
18
  /** Unavailable, but still listed — the option exists, it just cannot be picked. */
19
19
  disabled?: boolean;
20
20
  }
21
- export interface SelectProps extends NebaStyleProps {
21
+ export interface SelectProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'children'> {
22
22
  /**
23
23
  * The options, as data. There is no `<Select.Option>` to compose: what a
24
24
  * caller has is almost always an array already, and the list has to be
@@ -59,8 +59,6 @@ export interface SelectProps extends NebaStyleProps {
59
59
  /** Identifies the field when a form is submitted. */
60
60
  name?: string;
61
61
  id?: string;
62
- className?: string;
63
- style?: React.CSSProperties;
64
62
  }
65
63
  /**
66
64
  * One value chosen from a list of them.
@@ -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{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]})});
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},J){const K=null!=C&&!1!==C&&""!==C,Q=M??K,U=Q?"danger":w,X=t.useMemo(()=>z.map(e=>({label:e.label??String(e.value),value:e.value})),[z]),Y=t.useMemo(()=>[...z.map(e=>e.label??String(e.value)),...p(R)?[R]:[]],[z,R]);return a(n.Root,{disabled:B,invalid:Q,className:["flex-col align-top",N[b],_?"flex w-full":"inline-flex",F??""].filter(Boolean).join(" "),style:{...j(U,V),...G},...H,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:X,value:k,defaultValue:O,onValueChange:e=>P?.(e),disabled:B,readOnly:D,required:E,children:[a(l.Trigger,{ref:J,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:Y})]}),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(U,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,K?e(n.Error,{match:!0,className:`${g[b]} text-(--n-accent)`,children:C}):null]})});
@@ -0,0 +1,67 @@
1
+ import * as React from 'react';
2
+ import type { NebaChartCurve, NebaChartDatum, NebaColor, NebaSize } from '../../types';
3
+ export interface SparklineProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'children'> {
4
+ /** The values. `null` is a gap, exactly as it is on every other chart. */
5
+ data: readonly NebaChartDatum[];
6
+ /**
7
+ * Which mark. A line for a trend, an area for a quantity, bars for a count of
8
+ * discrete things — the same three sentences the full charts say, at a size
9
+ * where nothing else is being said at all.
10
+ * @default 'line'
11
+ */
12
+ shape?: 'line' | 'area' | 'bar';
13
+ /** @default 'linear' */
14
+ curve?: NebaChartCurve;
15
+ /**
16
+ * How tall the strip is. Sized against the line of text it sits beside rather
17
+ * than against the page — a sparkline is a word in a sentence, not a picture.
18
+ * @default 'md'
19
+ */
20
+ size?: NebaSize;
21
+ /**
22
+ * The mark's colour. A `NebaColor` family, or any CSS colour.
23
+ *
24
+ * Unlike the full charts this one takes it directly: a sparkline has exactly
25
+ * one series and no legend, so there is nothing for a palette to hand out.
26
+ * @default the first chart slot
27
+ */
28
+ color?: NebaColor | (string & {});
29
+ /**
30
+ * Puts a dot on the last point. The one direct label a strip this small has
31
+ * room for, and it says where the series ended up.
32
+ * @default false
33
+ */
34
+ endDot?: boolean;
35
+ /**
36
+ * Draws a rule across the strip at this value — a target, a budget, last
37
+ * year's average. The one piece of context a sparkline can carry.
38
+ */
39
+ baseline?: number;
40
+ /**
41
+ * The ends of the scale. Left out, the strip fills itself with its own range,
42
+ * which is what makes a sparkline legible at twenty pixels tall — and what
43
+ * makes two of them side by side incomparable. Pass the same `min` and `max`
44
+ * to a row of them and they become a small-multiples chart.
45
+ */
46
+ min?: number;
47
+ max?: number;
48
+ /** How wide. Fills its container by default. */
49
+ width?: number | string;
50
+ /** A name for the strip, read out in place of it. */
51
+ label?: string;
52
+ }
53
+ /**
54
+ * A chart with everything taken away except the shape.
55
+ *
56
+ * No axes, no grid, no legend, no tooltip — it is not a small chart, it is a
57
+ * different thing: a word-sized picture that goes inside a sentence, beside a
58
+ * [Statistic](./statistic), or in a table cell, and says which way something has
59
+ * been going. Every number it could label is one the surrounding text already
60
+ * has, which is why it labels none of them.
61
+ *
62
+ * It scales itself to its own range, so the strip is always full. That is what
63
+ * makes it readable this small and it is also the trap: two sparklines side by
64
+ * side are drawn on two different scales unless they are given the same `min`
65
+ * and `max`.
66
+ */
67
+ export declare const Sparkline: React.ForwardRefExoticComponent<SparklineProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ import{jsx as a,jsxs as e,Fragment as l}from"react/jsx-runtime";import*as r from"react";import{areaPath as t,barMaxThickness as n,barPath as i,barRadius as o,extentOf as s,lineWidths as h,markerRadii as m,markGap as c,resolveColor as u,sparklineHeights as d,toValue as p}from"../../internal/chart";import{useMeasuredWidth as f}from"../../internal/chart-frame";import{cx as x,srOnlyClasses as v}from"../../internal/styles";import{linePath as b}from"../../internal/chart";export const Sparkline=r.forwardRef(function({data:g,shape:M="line",curve:k="linear",size:y="md",color:w,endDot:$=!1,baseline:j,min:N,max:W,width:C,label:L,className:R,style:z,...B},D){const F=r.useRef(null),G=f(F),I=r.useId().replace(/:/g,""),S=r.useMemo(()=>g.map(p),[g]),q=d[y],A=h[y],E=m[y],H=s([S],!1),J=N??(H?Math.min(H.min,j??H.min):0),K=(W??(H?Math.max(H.max,j??H.max):1))-J||1,O="number"==typeof C?C:G,P=u(w??"var(--neba-chart-1)"),Q="bar"===M?0:A/2+($?E:0),T=Q,U=Math.max(1,q-2*Q),V=a=>T+(1-(a-J)/K)*U,X=S.length>1?O/(S.length-1):O,Y=S.map((a,e)=>null===a.value?null:{x:e*X,y:V(a.value)}),Z=(()=>{for(let a=S.length-1;a>=0;a--)if(null!==S[a].value)return a;return-1})(),_=Math.min(n[y]/2,Math.max(1,O/Math.max(1,S.length)-c));return e("div",{ref:D,className:x("relative block",R??void 0),style:{width:C??"100%",height:q,...z},...B,children:[a("div",{ref:F,className:"absolute inset-0",children:O>0&&S.length>0?e("svg",{width:O,height:q,viewBox:`0 0 ${O} ${q}`,role:L?"img":"presentation","aria-label":L,"aria-hidden":!L||void 0,className:"block overflow-visible",children:["area"===M?e(l,{children:[a("defs",{children:e("linearGradient",{id:`${I}-fill`,x1:"0",y1:"0",x2:"0",y2:"1",children:[a("stop",{offset:"0%",stopColor:`color-mix(in oklab, ${P} 32%, transparent)`}),a("stop",{offset:"100%",stopColor:`color-mix(in oklab, ${P} 2%, transparent)`})]})}),a("path",{d:t(Y,q,k),fill:`url(#${I}-fill)`})]}):null,void 0!==j?a("line",{x1:0,x2:O,y1:V(j),y2:V(j),stroke:"var(--neba-chart-baseline)",strokeWidth:1}):null,"bar"===M?S.map((e,l)=>null===e.value?null:a("path",{d:i(l*(O/Math.max(1,S.length))+(O/Math.max(1,S.length)-_)/2,Math.min(V(e.value),V(Math.max(J,0))),_,Math.max(1,Math.abs(V(e.value)-V(Math.max(J,0)))),o/2,e.value>=0?"up":"down"),fill:e.color??P},l)):a("path",{d:b(Y,k),fill:"none",stroke:P,strokeWidth:A,strokeLinecap:"round",strokeLinejoin:"round"}),$&&Z>=0&&"bar"!==M?a("circle",{cx:Y[Z].x,cy:Y[Z].y,r:E,fill:P,stroke:"var(--neba-chart-gap)",strokeWidth:c}):null]}):null}),L?a("span",{className:v,children:S.map(a=>null===a.value?"—":a.value).join(", ")}):null]})});
@@ -0,0 +1,2 @@
1
+ export { Sparkline } from './Sparkline';
2
+ export type { SparklineProps } from './Sparkline';
@@ -0,0 +1 @@
1
+ export{Sparkline}from"./Sparkline";
@@ -22,6 +22,13 @@ export interface StatisticProps extends Omit<BoxProps, 'title' | 'prefix'> {
22
22
  * own locale and otherwise left alone.
23
23
  */
24
24
  format?: Intl.NumberFormatOptions;
25
+ /**
26
+ * Which language the figure is written in, the same prop every chart takes.
27
+ * A Statistic is the smallest chart on the page and sits next to the others in
28
+ * a dashboard, so a locale set on one of them has to be settable on all.
29
+ * @default the reader's
30
+ */
31
+ locale?: string;
25
32
  /** Set before the figure and never wrapped away from it — a currency sign. */
26
33
  prefix?: React.ReactNode;
27
34
  /**
@@ -1 +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]})});
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{numberFormatter as i}from"../../internal/format";import{hasContent as o,metaTextClasses as c,sheetSectionGapClasses as u}from"../../internal/styles";const d={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]"},x={xs:"text-[0.75rem]",sm:"text-[0.875rem]",md:"text-[1rem]",lg:"text-[1.25rem]",xl:"text-[1.5rem]"},f={xs:"gap-y-0.5",sm:"gap-y-0.5",md:"gap-y-1",lg:"gap-y-1",xl:"gap-y-1.5"},p={start:"items-start text-start",center:"items-center text-center",end:"items-end text-end"},h={up:e(m,{}),down:e(s,{}),flat:e(r,{})};export const Statistic=l.forwardRef(function({size:l="md",color:r="primary",density:s="default",label:m,value:b,format:g,locale:w,prefix:N,unit:y,icon:$,previousValue:v,delta:j="percent",betterWhen:z="up",caption:B,align:M="start",className:k,children:C,...F},I){const R="number"==typeof b?b:null,S=null===R?b:i(w,g).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"!==j){const e=V>0?"+":V<0?"-":"",t=`${e}${i(w,g).format(Math.abs(V))}`,l=null===W?null:`${e}${(100*Math.abs(W)).toFixed(1).replace(/\.0$/,"")}%`;A="absolute"===j?t:"both"===j?[l,t].filter(Boolean).join(" · "):l??t}const D=null===q||"flat"===q?"secondary":q===z?"success":"danger",E=null!==A||o(B);return t(n,{ref:I,size:l,color:r,density:s,className:["flex flex-col",u[l],p[M],k??""].filter(Boolean).join(" "),...F,children:[o(m)||o($)?t("div",{className:["flex min-w-0 items-center gap-1.5 font-medium text-(--neba-muted-fg)",c[l]].join(" "),children:[o($)?e("span",{className:"flex shrink-0 items-center",children:$}):null,o(m)?e("span",{className:"min-w-0 truncate",children:m}):null]}):null,t("div",{className:["flex min-w-0 flex-wrap items-baseline gap-1 font-semibold text-(--neba-fg) tabular-nums",d[l]].join(" "),children:[o(N)?e("span",{className:`font-medium text-(--neba-muted-fg) ${x[l]}`,children:N}):null,e("span",{className:"min-w-0 break-words",children:S}),o(y)?e("span",{className:`font-medium text-(--neba-muted-fg) ${x[l]}`,children:y}):null]}),E?t("div",{className:`flex min-w-0 flex-wrap items-center gap-x-2 ${f[l]}`,children:[null!==A&&null!==q?e(a,{size:l,variant:"text",color:D,startIcon:h[q],className:"tabular-nums",children:A}):null,o(B)?e("span",{className:`min-w-0 text-(--neba-muted-fg) ${c[l]}`,children:B}):null]}):null,C]})});
@@ -50,7 +50,18 @@ export interface TableProps<Row> extends Omit<BoxProps, 'padded' | 'children' |
50
50
  getRowKey?: (row: Row, index: number) => React.Key;
51
51
  /** Shown above the table, and read out as its accessible name. */
52
52
  caption?: React.ReactNode;
53
- /** What to show instead of rows when `items` is empty. */
53
+ /**
54
+ * Which language the empty state is written in — a BCP 47 tag such as `ko`,
55
+ * `pt-BR` or `zh-Hant`. Unsupported tags fall back to English.
56
+ *
57
+ * `empty` writes the line out instead; this is for the far more common case
58
+ * where the page already knows its own language.
59
+ */
60
+ locale?: string;
61
+ /**
62
+ * What to show instead of rows when `items` is empty. Defaults to the
63
+ * `locale`'s wording for a table with nothing in it.
64
+ */
54
65
  empty?: React.ReactNode;
55
66
  /**
56
67
  * Tints every other row. Useful for a wide table where the eye has to track
@@ -77,4 +88,4 @@ export interface TableProps<Row> extends Omit<BoxProps, 'padded' | 'children' |
77
88
  * might sit next to. What Table adds is the part that is genuinely tabular: the
78
89
  * columns, the rows, and the fact that the two cannot drift apart.
79
90
  */
80
- export declare function Table<Row>({ headers, items, getRowKey, caption, empty, striped, hoverable, stickyHeader, onRowClick, size, density, className, ...boxProps }: TableProps<Row>): React.JSX.Element;
91
+ export declare function Table<Row>({ headers, items, getRowKey, caption, locale, empty, striped, hoverable, stickyHeader, onRowClick, size, density, className, ...boxProps }: TableProps<Row>): React.JSX.Element;