neba 1.0.0 → 1.1.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.
- package/README.md +23 -15
- package/dist/components/blockquote/Blockquote.d.ts +65 -0
- package/dist/components/blockquote/Blockquote.js +1 -0
- package/dist/components/blockquote/index.d.ts +2 -0
- package/dist/components/blockquote/index.js +1 -0
- package/dist/components/carousel/Carousel.d.ts +74 -0
- package/dist/components/carousel/Carousel.js +1 -0
- package/dist/components/carousel/index.d.ts +2 -0
- package/dist/components/carousel/index.js +1 -0
- package/dist/components/checkbox/Checkbox.js +1 -1
- package/dist/components/combobox/Combobox.js +1 -1
- package/dist/components/container/Container.d.ts +55 -0
- package/dist/components/container/Container.js +1 -0
- package/dist/components/container/index.d.ts +2 -0
- package/dist/components/container/index.js +1 -0
- package/dist/components/date-picker/DatePicker.d.ts +75 -0
- package/dist/components/date-picker/DatePicker.js +1 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-range-picker/DateRangePicker.d.ts +81 -0
- package/dist/components/date-range-picker/DateRangePicker.js +1 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.js +1 -0
- package/dist/components/date-time-picker/DateTimePicker.d.ts +68 -0
- package/dist/components/date-time-picker/DateTimePicker.js +1 -0
- package/dist/components/date-time-picker/index.d.ts +2 -0
- package/dist/components/date-time-picker/index.js +1 -0
- package/dist/components/dialog/Dialog.js +1 -1
- package/dist/components/divider/Divider.d.ts +19 -0
- package/dist/components/divider/Divider.js +1 -1
- package/dist/components/grid/Grid.d.ts +50 -0
- package/dist/components/grid/Grid.js +1 -0
- package/dist/components/grid/index.d.ts +2 -0
- package/dist/components/grid/index.js +1 -0
- package/dist/components/grid-container/GridContainer.d.ts +79 -0
- package/dist/components/grid-container/GridContainer.js +1 -0
- package/dist/components/grid-container/index.d.ts +2 -0
- package/dist/components/grid-container/index.js +1 -0
- package/dist/components/highlight/Highlight.d.ts +84 -0
- package/dist/components/highlight/Highlight.js +1 -0
- package/dist/components/highlight/index.d.ts +2 -0
- package/dist/components/highlight/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +58 -0
- package/dist/components/icon/Icon.js +1 -0
- package/dist/components/icon/index.d.ts +2 -0
- package/dist/components/icon/index.js +1 -0
- package/dist/components/icon-button/IconButton.d.ts +39 -0
- package/dist/components/icon-button/IconButton.js +1 -0
- package/dist/components/icon-button/index.d.ts +2 -0
- package/dist/components/icon-button/index.js +1 -0
- package/dist/components/pagination/Pagination.js +1 -1
- package/dist/components/pill/Pill.d.ts +80 -0
- package/dist/components/pill/Pill.js +1 -0
- package/dist/components/pill/index.d.ts +2 -0
- package/dist/components/pill/index.js +1 -0
- package/dist/components/radio-group/RadioGroup.js +1 -1
- package/dist/components/segmented-button/SegmentedButton.d.ts +77 -0
- package/dist/components/segmented-button/SegmentedButton.js +1 -0
- package/dist/components/segmented-button/index.d.ts +2 -0
- package/dist/components/segmented-button/index.js +1 -0
- package/dist/components/select/Select.js +1 -1
- package/dist/components/shortcut/Shortcut.d.ts +60 -0
- package/dist/components/shortcut/Shortcut.js +1 -0
- package/dist/components/shortcut/index.d.ts +2 -0
- package/dist/components/shortcut/index.js +1 -0
- package/dist/components/statistic/Statistic.d.ts +91 -0
- package/dist/components/statistic/Statistic.js +1 -0
- package/dist/components/statistic/index.d.ts +2 -0
- package/dist/components/statistic/index.js +1 -0
- package/dist/components/switch/Switch.js +1 -1
- package/dist/components/time-picker/TimePicker.d.ts +76 -0
- package/dist/components/time-picker/TimePicker.js +1 -0
- package/dist/components/time-picker/index.d.ts +2 -0
- package/dist/components/time-picker/index.js +1 -0
- package/dist/components/timeline/Timeline.d.ts +98 -0
- package/dist/components/timeline/Timeline.js +1 -0
- package/dist/components/timeline/index.d.ts +2 -0
- package/dist/components/timeline/index.js +1 -0
- package/dist/components/toolbar/Toolbar.d.ts +67 -0
- package/dist/components/toolbar/Toolbar.js +1 -0
- package/dist/components/toolbar/index.d.ts +2 -0
- package/dist/components/toolbar/index.js +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1 -1
- package/dist/internal/calendar.d.ts +149 -0
- package/dist/internal/calendar.js +1 -0
- package/dist/internal/date.d.ts +170 -0
- package/dist/internal/date.js +1 -0
- package/dist/internal/grid.d.ts +69 -0
- package/dist/internal/grid.js +1 -0
- package/dist/internal/icons.d.ts +31 -0
- package/dist/internal/icons.js +1 -1
- package/dist/internal/picker.d.ts +111 -0
- package/dist/internal/picker.js +1 -0
- package/dist/internal/sizer.d.ts +33 -0
- package/dist/internal/sizer.js +1 -0
- package/dist/internal/styles.d.ts +33 -0
- package/dist/internal/styles.js +1 -1
- package/dist/styles.css +2 -758
- package/dist/tailwind.css +892 -0
- package/dist/types.d.ts +65 -0
- package/package.json +18 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n,Fragment as t}from"react/jsx-runtime";import*as o from"react";import{controlSlots as l,controlTextClasses as r,focusRingClasses as i,gapClasses as s,hasContent as a,iconClasses as c,iconSizeClasses as d,metaTextClasses as m,paddingXClasses as x,pressTransitionClasses as f,sheetBodyClasses as p,surfaceClasses as u,transitionClasses as h}from"../../internal/styles";const v={solid:[u,"text-(--n-on-solid) bg-(--n-fill)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[u,"border text-(--n-accent) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:`${u} text-(--n-accent) bg-(--n-soft)`},b={solid:"hover:bg-(--n-fill-hover) active:bg-(--n-fill-active)",outline:"hover:bg-(--n-panel-hover) hover:[border-color:var(--n-line-hover)] active:bg-(--n-panel-press)",text:"hover:bg-(--n-soft-hover) active:bg-(--n-soft-press)"},g={xs:"min-h-5.5",sm:"min-h-6.5",md:"min-h-8",lg:"min-h-10",xl:"min-h-12"},w={xs:"rounded-[0.6875rem]",sm:"rounded-[0.8125rem]",md:"rounded-[1rem]",lg:"rounded-[1.25rem]",xl:"rounded-[1.5rem]"},j={default:{xs:"px-3",sm:"px-4",md:"px-5",lg:"px-6",xl:"px-8"},compact:{xs:"px-1.5",sm:"px-2",md:"px-2.5",lg:"px-3",xl:"px-4"}},y={static:{top:"",bottom:""},sticky:{top:"sticky top-3 z-20",bottom:"sticky bottom-3 z-20"},fixed:{top:"fixed inset-x-0 top-3 z-30 mx-auto w-fit",bottom:"fixed inset-x-0 bottom-3 z-30 mx-auto w-fit"}};export const Pill=o.forwardRef(function({variant:u="solid",size:N="md",color:k="secondary",density:z="default",elevation:$=2,startIcon:_,endIcon:C,title:R,description:B,details:H,expanded:I=!1,position:E="static",side:F="top",className:O,style:P,children:S,onClick:q,...A},D){const G=o.useRef(null),[J,K]=o.useState(0);o.useEffect(()=>{const e=G.current;if(!e)return;const n=new ResizeObserver(()=>{K(e.scrollHeight)});return n.observe(e),K(e.scrollHeight),()=>n.disconnect()},[H]);const L=Boolean(q),M=x[z][N],Q=n(t,{children:[a(_)?e("span",{className:`flex shrink-0 items-center justify-center overflow-hidden rounded-full [&_img]:size-full [&_img]:object-cover ${d[N]}`,children:_}):null,a(R)||a(B)||a(S)?n("span",{className:["flex min-w-0 flex-1 flex-col items-center justify-center text-center",j[z][N]].join(" "),children:[a(R)?e("span",{className:"max-w-full truncate",children:R}):null,a(B)?e("span",{className:`max-w-full truncate font-normal ${m[N]} [color:color-mix(in_oklab,currentColor_72%,transparent)]`,children:B}):null,S]}):null]});return n("div",{ref:D,className:["inline-flex max-w-full flex-col overflow-hidden align-middle",w[N],"font-medium whitespace-nowrap select-none",r[N],v[u],h,f,c,L?`neba-glow ${b[u]}`:"",y[E][F],O??""].filter(Boolean).join(" "),style:{...l(k,$,u),...P},...A,children:[n("div",{className:["flex shrink-0 items-center py-1",g[N],s[N],L?"ps-0":M,a(C)?"pe-1":L?"pe-0":""].join(" "),children:[L?e("button",{type:"button",className:["flex min-w-0 flex-1 cursor-pointer items-center justify-center self-stretch","rounded-[inherit]",s[N],M,i].join(" "),onClick:q,children:Q}):Q,a(C)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:C}):null]}),a(H)?e("div",{className:["overflow-hidden","[transition:height_var(--neba-duration)_var(--neba-ease)]","motion-reduce:[transition-duration:0ms]"].join(" "),style:{height:I?J:0},inert:!I,children:e("div",{ref:G,className:`whitespace-normal ${M} pb-2 ${p[N]}`,children:H})}):null]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Pill}from"./Pill";
|
|
@@ -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,
|
|
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 @@
|
|
|
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
|
|
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 @@
|
|
|
1
|
+
export{Shortcut}from"./Shortcut";
|
|
@@ -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 @@
|
|
|
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
|
|
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,76 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PickerLabels, type TimeUnit } from '../../internal/calendar';
|
|
3
|
+
import { type PickerShellProps } from '../../internal/picker';
|
|
4
|
+
/**
|
|
5
|
+
* Which column of the clock a row belongs to. Re-exported so a caller writing a
|
|
6
|
+
* `shouldDisableTime` rule can name the argument it is handed.
|
|
7
|
+
*/
|
|
8
|
+
export type { TimeUnit };
|
|
9
|
+
export interface TimePickerProps extends PickerShellProps {
|
|
10
|
+
/** The chosen time. A `Date`, so it carries a day as well — see `referenceDate`. */
|
|
11
|
+
value?: Date | null;
|
|
12
|
+
defaultValue?: Date | null;
|
|
13
|
+
onValueChange?: (value: Date | null) => void;
|
|
14
|
+
open?: boolean;
|
|
15
|
+
defaultOpen?: boolean;
|
|
16
|
+
onOpenChange?: (open: boolean) => void;
|
|
17
|
+
/**
|
|
18
|
+
* The day a chosen time is written onto while there is no value yet.
|
|
19
|
+
* @default today
|
|
20
|
+
*/
|
|
21
|
+
referenceDate?: Date;
|
|
22
|
+
/** The earliest time of day that may be chosen. Only the clock is read. */
|
|
23
|
+
minTime?: Date | null;
|
|
24
|
+
/** The latest time of day that may be chosen. */
|
|
25
|
+
maxTime?: Date | null;
|
|
26
|
+
/**
|
|
27
|
+
* Blocks individual rows. Called once per row per column with the instant that
|
|
28
|
+
* row would produce and the column it is in, so a rule may be as coarse as
|
|
29
|
+
* "no afternoons" or as fine as one minute.
|
|
30
|
+
*/
|
|
31
|
+
shouldDisableTime?: (value: Date, unit: TimeUnit) => boolean;
|
|
32
|
+
/** A 12-hour dial with an AM/PM column. Defaults to whatever the locale does. */
|
|
33
|
+
hour12?: boolean;
|
|
34
|
+
/** Adds the seconds column. @default false */
|
|
35
|
+
showSeconds?: boolean;
|
|
36
|
+
/** How far apart the rows of each column are. @default 1 */
|
|
37
|
+
hourStep?: number;
|
|
38
|
+
minuteStep?: number;
|
|
39
|
+
secondStep?: number;
|
|
40
|
+
locale?: string;
|
|
41
|
+
/**
|
|
42
|
+
* How the trigger writes the chosen time. Passed straight to `Intl`.
|
|
43
|
+
* @default { hour: 'numeric', minute: '2-digit' }, plus seconds when shown
|
|
44
|
+
*/
|
|
45
|
+
format?: Intl.DateTimeFormatOptions;
|
|
46
|
+
placeholder?: React.ReactNode;
|
|
47
|
+
clearable?: boolean;
|
|
48
|
+
/** Offers the shortcut to the current time in the footer. @default true */
|
|
49
|
+
showNowButton?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Closes the popup as soon as any column is touched. `false` by default and
|
|
52
|
+
* unlike DatePicker, because a time is two answers and closing after the first
|
|
53
|
+
* one would make choosing 9:30 a matter of opening the popup twice.
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
closeOnSelect?: boolean;
|
|
57
|
+
labels?: Partial<PickerLabels>;
|
|
58
|
+
/** Identifies the field when a form is submitted, as `HH:MM` (`HH:MM:SS`). */
|
|
59
|
+
name?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A time of day, chosen from columns.
|
|
63
|
+
*
|
|
64
|
+
* The bounds are checked at the granularity of the column being drawn, which is
|
|
65
|
+
* the detail that separates a working time picker from a frustrating one. With a
|
|
66
|
+
* `minTime` of 09:30, the hour `9` stays available — the hour *contains* allowed
|
|
67
|
+
* minutes — and it is the minute column that greys out `00` through `25`. The
|
|
68
|
+
* naive check compares the whole candidate instant and hides the 9 entirely,
|
|
69
|
+
* which makes half past nine unreachable.
|
|
70
|
+
*
|
|
71
|
+
* The value is a `Date` rather than a string or a number of minutes, because
|
|
72
|
+
* everything else in this library that carries a moment is one, and because a
|
|
73
|
+
* time on its own has nowhere to record that it crossed a DST boundary.
|
|
74
|
+
* `referenceDate` is the day a bare time is written onto.
|
|
75
|
+
*/
|
|
76
|
+
export declare const TimePicker: React.ForwardRefExoticComponent<TimePickerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as o from"react";import{Button as t}from"../button/Button";import{TimeGrid as l,usePickerLabels as a}from"../../internal/calendar";import{ClockIcon as i}from"../../internal/icons";import{PickerFooter as r,PickerShell as s}from"../../internal/picker";import{displaySamples as c,formatDate as d,isHour12 as u,isValidDate as m,secondsOfDay as p,timeUnitSpan as h,toISOTime as f,withPlaceholder as S,withTime as b}from"../../internal/date";import{cx as g}from"../../internal/styles";export const TimePicker=o.forwardRef(function({value:y,defaultValue:v,onValueChange:x,open:C,defaultOpen:w,onOpenChange:z,referenceDate:k,minTime:D,maxTime:O,shouldDisableTime:T,hour12:j,showSeconds:V=!1,hourStep:B=1,minuteStep:I=1,secondStep:M=1,locale:N,format:R,placeholder:F,clearable:H=!1,showNowButton:P=!0,closeOnSelect:q=!1,labels:A,name:E,size:G="md",color:J="primary",density:K="default",readOnly:L=!1,disabled:Q=!1,startIcon:U,...W},X){const Y=a(A),Z=j??u(N),[$,_]=o.useState(v??null),ee=void 0!==y?y:$,[ne,oe]=o.useState(w??!1),te=C??ne,[le]=o.useState(()=>k??new Date),ae=e=>{e&&(L||Q)||(void 0===C&&oe(e),z?.(e))},ie=e=>{void 0===y&&_(e),x?.(e)},re=o.useCallback((e,n)=>{const[o,t]=h(n,e);return!!(m(D)&&t<p(D))||(!!(m(O)&&o>p(O))||(T?.(e,n)??!1))},[D,O,T]),se=R??{hour:"numeric",minute:"2-digit",...V?{second:"2-digit"}:{}},ce=new Date,de=b(k??le,{hours:ce.getHours(),minutes:ce.getMinutes(),seconds:V?ce.getSeconds():0}),ue=P||H||!q,me=o.useMemo(()=>S(c(N,se),F),[N,se,F]);return e(s,{...W,size:G,color:J,density:K,readOnly:L,disabled:Q,triggerRef:X,startIcon:U??e(i,{}),display:m(ee)?d(ee,N,se):F??"",samples:me,empty:!m(ee),clearable:H,onClear:()=>ie(null),open:te,onOpenChange:ae,labels:Y,hiddenValues:E?[{name:E,value:m(ee)?f(ee,V):""}]:void 0,children:n("div",{className:g("flex flex-col",ue&&"gap-1.5"),children:[e(l,{size:G,density:K,locale:N,value:m(ee)?ee:null,referenceDate:k??le,onChange:e=>{ie(e),q&&ae(!1)},hour12:Z,showSeconds:V,hourStep:B,minuteStep:I,secondStep:M,shouldDisableTime:re,labels:Y,autoFocus:!0}),ue?n(r,{size:G,children:[H?e(t,{variant:"text",size:G,color:J,density:"compact",onClick:()=>{ie(null),ae(!1)},children:Y.clear}):null,P?e(t,{variant:"text",size:G,color:J,density:"compact",disabled:re(de,"second"),onClick:()=>{ie(de),ae(!1)},children:Y.now}):null,q?null:e(t,{variant:"solid",size:G,color:J,density:"compact",onClick:()=>ae(!1),children:Y.done})]}):null]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{TimePicker}from"./TimePicker";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaColor, NebaDensity, NebaOrientation, NebaSize } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* How far along one item is.
|
|
6
|
+
*
|
|
7
|
+
* Three states rather than two, because "the one you are on" is not the same
|
|
8
|
+
* claim as "done" and a sequence that cannot say which step is current is a
|
|
9
|
+
* list. Each gets its own axis — a filled bullet, a filled bullet with a halo
|
|
10
|
+
* around it, an empty one — rather than three shades of the same thing.
|
|
11
|
+
*/
|
|
12
|
+
export type TimelineStatus = 'complete' | 'current' | 'upcoming';
|
|
13
|
+
/** How the line between two items is drawn. `none` leaves the gap open. */
|
|
14
|
+
export type TimelineConnector = 'solid' | 'dashed' | 'dotted' | 'none';
|
|
15
|
+
export interface TimelineProps extends Omit<React.ComponentPropsWithoutRef<'ol'>, 'color'> {
|
|
16
|
+
/**
|
|
17
|
+
* How far the sequence has got: the index of the item being worked on now.
|
|
18
|
+
* Everything before it is complete, everything after it is still to come.
|
|
19
|
+
*
|
|
20
|
+
* An index rather than a value, because a timeline has no selection — nothing
|
|
21
|
+
* here is chosen, and the only question is how far down the list reality has
|
|
22
|
+
* reached. Omit it and every item is `upcoming` unless it says otherwise; pass
|
|
23
|
+
* the item count to mark the whole sequence done.
|
|
24
|
+
*/
|
|
25
|
+
active?: number;
|
|
26
|
+
/** @default 'md' */
|
|
27
|
+
size?: NebaSize;
|
|
28
|
+
/** @default 'primary' */
|
|
29
|
+
color?: NebaColor;
|
|
30
|
+
/** Spacing between items. Never the type scale, never the bullet. */
|
|
31
|
+
density?: NebaDensity;
|
|
32
|
+
/**
|
|
33
|
+
* Which way the sequence runs. `vertical` is the default and the one that
|
|
34
|
+
* takes an arbitrary number of steps with an arbitrary amount to say about
|
|
35
|
+
* each; `horizontal` is the stepper across the top of a checkout, and it is
|
|
36
|
+
* only honest while every label is short.
|
|
37
|
+
* @default 'vertical'
|
|
38
|
+
*/
|
|
39
|
+
orientation?: NebaOrientation;
|
|
40
|
+
/** Renders something other than an `<ol>` — Base UI's own escape hatch. */
|
|
41
|
+
render?: useRender.RenderProp;
|
|
42
|
+
children?: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
export interface TimelineItemProps extends Omit<React.ComponentPropsWithoutRef<'li'>, 'color' | 'title'> {
|
|
45
|
+
/** The heading of this step. */
|
|
46
|
+
title?: React.ReactNode;
|
|
47
|
+
/**
|
|
48
|
+
* When it happened — a date, a duration, a name. Set beside the title on a
|
|
49
|
+
* wide item and under it on a narrow one.
|
|
50
|
+
*/
|
|
51
|
+
meta?: React.ReactNode;
|
|
52
|
+
/**
|
|
53
|
+
* What goes inside the bullet: a number, an icon, an avatar. Omit it and the
|
|
54
|
+
* bullet is a plain disc, which is what a step with nothing to say about
|
|
55
|
+
* itself should be.
|
|
56
|
+
*/
|
|
57
|
+
bullet?: React.ReactNode;
|
|
58
|
+
/**
|
|
59
|
+
* Overrides what the timeline's `active` would have computed for this item —
|
|
60
|
+
* a step that failed and stopped the sequence, a step that was skipped.
|
|
61
|
+
*/
|
|
62
|
+
status?: TimelineStatus;
|
|
63
|
+
/** Overrides the timeline's colour family for this item alone. */
|
|
64
|
+
color?: NebaColor;
|
|
65
|
+
/**
|
|
66
|
+
* How the line to the next item is drawn.
|
|
67
|
+
* @default 'solid'
|
|
68
|
+
*/
|
|
69
|
+
connector?: TimelineConnector;
|
|
70
|
+
/** The body of the step. */
|
|
71
|
+
children?: React.ReactNode;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One step.
|
|
75
|
+
*
|
|
76
|
+
* Its index is not a prop and cannot be: an item that had to be told where it
|
|
77
|
+
* was in the list would be an item every caller could put in the wrong place,
|
|
78
|
+
* and `active={2}` would stop meaning anything. The Timeline numbers its
|
|
79
|
+
* children as it walks them, and hands each one its index through a context.
|
|
80
|
+
*/
|
|
81
|
+
export declare const TimelineItem: React.ForwardRefExoticComponent<TimelineItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
82
|
+
/**
|
|
83
|
+
* A sequence of steps, in the order they happen in.
|
|
84
|
+
*
|
|
85
|
+
* There is no Base UI primitive under this and there should not be: a timeline
|
|
86
|
+
* has no selection, no roving focus and no keyboard contract — it is a list, and
|
|
87
|
+
* reaching for a composite primitive to draw one would hand every consumer's
|
|
88
|
+
* record of events the semantics of a widget.
|
|
89
|
+
*
|
|
90
|
+
* It is an `<ol>` for the reason it exists at all: the order *is* the content. A
|
|
91
|
+
* screen reader announcing "list of 5 items" over an unordered list would be
|
|
92
|
+
* describing something else.
|
|
93
|
+
*
|
|
94
|
+
* The children are numbered here rather than by a prop on each item, so `active`
|
|
95
|
+
* has something to count against and inserting a step in the middle does not
|
|
96
|
+
* mean renumbering the ones after it.
|
|
97
|
+
*/
|
|
98
|
+
export declare const Timeline: React.ForwardRefExoticComponent<TimelineProps & React.RefAttributes<HTMLOListElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as r from"react";import{useRender as t}from"@base-ui/react/use-render";import{cx as n,hasContent as a,iconClasses as o,metaTextClasses as s,sheetBodyClasses as i,sheetTitleClasses as d,surfaceClasses as c,surfaceSlots as m,transitionClasses as p}from"../../internal/styles";const u=r.createContext(null),b=r.createContext({index:0,last:!1}),x={xs:"0.875rem",sm:"1rem",md:"1.25rem",lg:"1.5rem",xl:"1.875rem"},f={xs:"gap-2",sm:"gap-2.5",md:"gap-3",lg:"gap-3.5",xl:"gap-4"},v={default:{xs:"pb-5",sm:"pb-6",md:"pb-7",lg:"pb-8",xl:"pb-10"},compact:{xs:"pb-3",sm:"pb-3.5",md:"pb-4",lg:"pb-5",xl:"pb-6"}},g={default:{xs:"pe-5",sm:"pe-6",md:"pe-7",lg:"pe-8",xl:"pe-10"},compact:{xs:"pe-3",sm:"pe-3.5",md:"pe-4",lg:"pe-5",xl:"pe-6"}},h={solid:"border-solid",dashed:"border-dashed",dotted:"border-dotted",none:""},y={complete:`${c} bg-(--n-fill) text-(--n-on-solid) [box-shadow:var(--neba-plate-solid)]`,current:`${c} bg-(--n-fill) text-(--n-on-solid) [box-shadow:0_0_0_0.25rem_var(--n-soft),var(--neba-plate-solid)]`,upcoming:`${c} border-2 bg-(--n-panel) text-(--neba-muted-fg) [border-color:var(--n-line)]`},N={complete:"[border-color:var(--n-line-hover)]",current:"[border-color:var(--neba-border)]",upcoming:"[border-color:var(--neba-border)]"},w={complete:"text-(--neba-fg)",current:"text-(--n-accent)",upcoming:"text-(--neba-muted-fg)"};export const TimelineItem=r.forwardRef(function({title:t,meta:c,bullet:_,status:z,color:C,connector:$="solid",className:j,children:P,...R},T){const k=r.useContext(u),{index:A,last:I}=r.useContext(b),M=k?.size??"md",q=k?.density??"default",B=k?.orientation??"vertical",D=C??k?.color??"primary",E=k?.active??null,F=z??(null===E?"upcoming":A<E?"complete":A===E?"current":"upcoming"),G="horizontal"===B,H="none"!==$&&!I,J=e("span",{"aria-hidden":"true",className:n("relative z-10 flex shrink-0 items-center justify-center rounded-full","size-(--n-bullet) text-[calc(var(--n-bullet)*0.5)] leading-none font-semibold tabular-nums",y[F],p,o),children:_}),K=H?e("span",{"aria-hidden":"true",className:n("pointer-events-none absolute",G?"top-[calc(var(--n-bullet)/2_-_1px)] start-(--n-bullet) end-0 border-t-2":"start-[calc(var(--n-bullet)/2_-_1px)] top-(--n-bullet) bottom-0 border-s-2",h[$],N[F],p)}):null,L=l("div",{className:n("flex min-w-0 flex-col gap-0.5",G?"mt-2":""),children:[a(t)||a(c)?l("div",{className:"flex flex-wrap items-baseline gap-x-2",children:[a(t)?e("span",{className:n("font-semibold",d[M],w[F],p),children:t}):null,a(c)?e("span",{className:n("text-(--neba-muted-fg)",s[M]),children:c}):null]}):null,a(P)?e("div",{className:n("text-(--neba-muted-fg)",i[M]),children:P}):null]});return l("li",{ref:T,"aria-current":"current"===F?"step":void 0,"data-status":F,className:n("relative",G?n("flex min-w-0 flex-1 flex-col",I?"":g[q][M]):n("flex",f[M],I?"":v[q][M]),j),style:{"--n-bullet":x[M],...m(D,0),"--n-fill":`var(--neba-${D}-fill)`,"--n-on-solid":`var(--neba-${D}-on-solid)`},...R,children:[K,J,L]})});export const Timeline=r.forwardRef(function({active:l,size:a="md",color:o="primary",density:s="default",orientation:i="vertical",render:d,className:c,style:p,children:x,...f},v){const g=r.Children.toArray(x),h=g.length,y=r.useMemo(()=>({size:a,density:s,orientation:i,color:o,active:l??null}),[a,s,i,o,l]),N=t({render:d??e("ol",{}),ref:v,props:{role:"list",className:n("flex","horizontal"===i?"flex-row":"flex-col",c),style:{...m(o,0),...p},children:g.map((l,r)=>e(b.Provider,{value:{index:r,last:r===h-1},children:l},r)),...f}});return e(u.Provider,{value:y,children:N})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Timeline,TimelineItem}from"./Timeline";
|