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,67 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaElevation, NebaPosition, NebaStyleProps } from '../../types';
|
|
4
|
+
export interface ToolbarProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
5
|
+
/**
|
|
6
|
+
* Drop shadow depth. `0` — the default — is flat even when the bar is pinned:
|
|
7
|
+
* a shadow under a header is a way of saying "there is content beneath this",
|
|
8
|
+
* and that is only true once the page has been scrolled. Raise it yourself, or
|
|
9
|
+
* leave it flat and turn on `divider`.
|
|
10
|
+
* @default 0
|
|
11
|
+
*/
|
|
12
|
+
elevation?: NebaElevation;
|
|
13
|
+
/**
|
|
14
|
+
* How the bar sits in the page's scroll.
|
|
15
|
+
*
|
|
16
|
+
* - `static` — in the flow, scrolling away with the content.
|
|
17
|
+
* - `sticky` — in the flow until it reaches the edge, then held there. What an
|
|
18
|
+
* application header usually wants: it takes up its own space, so nothing
|
|
19
|
+
* underneath has to be padded around it.
|
|
20
|
+
* - `fixed` — out of the flow entirely. The page needs padding of its own, or
|
|
21
|
+
* the first screenful sits behind the bar.
|
|
22
|
+
* @default 'static'
|
|
23
|
+
*/
|
|
24
|
+
position?: NebaPosition;
|
|
25
|
+
/** Which edge it is held against when `position` is not `static`. @default 'top' */
|
|
26
|
+
side?: 'top' | 'bottom';
|
|
27
|
+
/**
|
|
28
|
+
* Draws a hairline along the edge that faces the content — under a `top` bar,
|
|
29
|
+
* over a `bottom` one.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
divider?: boolean;
|
|
33
|
+
/** Pinned to the start of the bar: a logo, a title, a back button. */
|
|
34
|
+
start?: React.ReactNode;
|
|
35
|
+
/** Pinned to the end: the actions. */
|
|
36
|
+
end?: React.ReactNode;
|
|
37
|
+
/**
|
|
38
|
+
* Renders something other than a `<div>` — `render={<header />}`,
|
|
39
|
+
* `render={<nav />}`. Base UI's own escape hatch, and worth reaching for here:
|
|
40
|
+
* a page's header should be a `<header>`.
|
|
41
|
+
*/
|
|
42
|
+
render?: useRender.RenderProp;
|
|
43
|
+
/** The middle. Takes whatever width `start` and `end` leave. */
|
|
44
|
+
children?: React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A bar of controls: an application header, a page's action row, the strip along
|
|
48
|
+
* the bottom of an editor.
|
|
49
|
+
*
|
|
50
|
+
* Three slots and a row. `start` and `end` are pinned to their ends and
|
|
51
|
+
* `children` takes what is left, which is the arrangement every toolbar has ever
|
|
52
|
+
* had — so it is laid out here rather than left to a caller and a spacer `<div>`
|
|
53
|
+
* they have to remember.
|
|
54
|
+
*
|
|
55
|
+
* The one thing it does not do is take a height. A toolbar is as tall as the
|
|
56
|
+
* controls in it plus its padding, and that padding is the `size`/`density` pair
|
|
57
|
+
* every other surface uses — so `density="compact"` gives the dense bar without
|
|
58
|
+
* a second prop meaning the same thing, and without the type scale moving.
|
|
59
|
+
*
|
|
60
|
+
* It has no `role="toolbar"`, deliberately. That role is a promise about
|
|
61
|
+
* keyboard behaviour — one tab stop for the whole bar, arrow keys between the
|
|
62
|
+
* controls in it — and a bar that claims it without implementing it is worse for
|
|
63
|
+
* a keyboard reader than one that never claimed anything. What a header wants is
|
|
64
|
+
* `render={<header />}`; what a genuine roving-focus toolbar wants is a
|
|
65
|
+
* ButtonGroup, which is one.
|
|
66
|
+
*/
|
|
67
|
+
export declare const Toolbar: React.ForwardRefExoticComponent<ToolbarProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,Fragment as t,jsxs as r}from"react/jsx-runtime";import*as o from"react";import{useRender as n}from"@base-ui/react/use-render";import{boxPaddingXClasses as i,boxPaddingYClasses as a}from"../box/Box";import{hasContent as s,radiusClasses as l,sheetSectionGapClasses as d,surfaceClasses as m,surfaceSlots as c,transitionClasses as b}from"../../internal/styles";const p={solid:[m,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[m,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"},f={static:{top:"",bottom:""},sticky:{top:"sticky top-0 z-20",bottom:"sticky bottom-0 z-20"},fixed:{top:"fixed inset-x-0 top-0 z-30",bottom:"fixed inset-x-0 bottom-0 z-30"}},x={top:"border-b [border-color:var(--n-line)]",bottom:"border-t [border-color:var(--n-line)]"};export const Toolbar=o.forwardRef(function({variant:o="outline",size:m="md",color:v="primary",density:g="default",elevation:h=0,position:u="static",side:w="top",divider:y=!1,start:j,end:k,render:z,className:N,style:B,children:F,...R},T){const q=["flex w-full min-w-0 items-center",i[g][m],a[g][m],d[m],"static"===u?l[m]:"",p[o],y?x[w]:"",f[u][w],b,N??""].filter(Boolean).join(" ");return n({render:z,ref:T,props:{className:q,style:{...c(v,h),...B},children:r(t,{children:[s(j)?e("div",{className:"flex min-w-0 shrink-0 items-center gap-2",children:j}):null,e("div",{className:"flex min-w-0 flex-1 items-center gap-2",children:F}),s(k)?e("div",{className:"flex min-w-0 shrink-0 items-center gap-2",children:k}):null]}),...R}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Toolbar}from"./Toolbar";
|
package/dist/index.d.ts
CHANGED
|
@@ -2,31 +2,49 @@ export * from './types';
|
|
|
2
2
|
export * from './components/accordion';
|
|
3
3
|
export * from './components/alert';
|
|
4
4
|
export * from './components/badge';
|
|
5
|
+
export * from './components/blockquote';
|
|
5
6
|
export * from './components/box';
|
|
6
7
|
export * from './components/button';
|
|
7
8
|
export * from './components/button-group';
|
|
8
9
|
export * from './components/card';
|
|
10
|
+
export * from './components/carousel';
|
|
9
11
|
export * from './components/checkbox';
|
|
10
12
|
export * from './components/chip';
|
|
11
13
|
export * from './components/combobox';
|
|
14
|
+
export * from './components/container';
|
|
15
|
+
export * from './components/date-picker';
|
|
16
|
+
export * from './components/date-range-picker';
|
|
17
|
+
export * from './components/date-time-picker';
|
|
12
18
|
export * from './components/dialog';
|
|
13
19
|
export * from './components/divider';
|
|
14
20
|
export * from './components/file-picker';
|
|
21
|
+
export * from './components/grid';
|
|
22
|
+
export * from './components/grid-container';
|
|
23
|
+
export * from './components/highlight';
|
|
24
|
+
export * from './components/icon';
|
|
25
|
+
export * from './components/icon-button';
|
|
15
26
|
export * from './components/list';
|
|
16
27
|
export * from './components/menu';
|
|
17
28
|
export * from './components/number-field';
|
|
18
29
|
export * from './components/overlay';
|
|
19
30
|
export * from './components/pagination';
|
|
31
|
+
export * from './components/pill';
|
|
20
32
|
export * from './components/progress-box';
|
|
21
33
|
export * from './components/progress-circular';
|
|
22
34
|
export * from './components/progress-linear';
|
|
23
35
|
export * from './components/radio-group';
|
|
36
|
+
export * from './components/segmented-button';
|
|
24
37
|
export * from './components/select';
|
|
38
|
+
export * from './components/shortcut';
|
|
25
39
|
export * from './components/slider';
|
|
40
|
+
export * from './components/statistic';
|
|
26
41
|
export * from './components/switch';
|
|
27
42
|
export * from './components/table';
|
|
28
43
|
export * from './components/tabs';
|
|
29
44
|
export * from './components/text-field';
|
|
45
|
+
export * from './components/time-picker';
|
|
46
|
+
export * from './components/timeline';
|
|
30
47
|
export * from './components/toast';
|
|
48
|
+
export * from './components/toolbar';
|
|
31
49
|
export * from './components/tooltip';
|
|
32
50
|
export * from './components/typography';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./types";export*from"./components/accordion";export*from"./components/alert";export*from"./components/badge";export*from"./components/box";export*from"./components/button";export*from"./components/button-group";export*from"./components/card";export*from"./components/checkbox";export*from"./components/chip";export*from"./components/combobox";export*from"./components/dialog";export*from"./components/divider";export*from"./components/file-picker";export*from"./components/list";export*from"./components/menu";export*from"./components/number-field";export*from"./components/overlay";export*from"./components/pagination";export*from"./components/progress-box";export*from"./components/progress-circular";export*from"./components/progress-linear";export*from"./components/radio-group";export*from"./components/select";export*from"./components/slider";export*from"./components/switch";export*from"./components/table";export*from"./components/tabs";export*from"./components/text-field";export*from"./components/toast";export*from"./components/tooltip";export*from"./components/typography";
|
|
1
|
+
export*from"./types";export*from"./components/accordion";export*from"./components/alert";export*from"./components/badge";export*from"./components/blockquote";export*from"./components/box";export*from"./components/button";export*from"./components/button-group";export*from"./components/card";export*from"./components/carousel";export*from"./components/checkbox";export*from"./components/chip";export*from"./components/combobox";export*from"./components/container";export*from"./components/date-picker";export*from"./components/date-range-picker";export*from"./components/date-time-picker";export*from"./components/dialog";export*from"./components/divider";export*from"./components/file-picker";export*from"./components/grid";export*from"./components/grid-container";export*from"./components/highlight";export*from"./components/icon";export*from"./components/icon-button";export*from"./components/list";export*from"./components/menu";export*from"./components/number-field";export*from"./components/overlay";export*from"./components/pagination";export*from"./components/pill";export*from"./components/progress-box";export*from"./components/progress-circular";export*from"./components/progress-linear";export*from"./components/radio-group";export*from"./components/segmented-button";export*from"./components/select";export*from"./components/shortcut";export*from"./components/slider";export*from"./components/statistic";export*from"./components/switch";export*from"./components/table";export*from"./components/tabs";export*from"./components/text-field";export*from"./components/time-picker";export*from"./components/timeline";export*from"./components/toast";export*from"./components/toolbar";export*from"./components/tooltip";export*from"./components/typography";
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type TimeUnit } from './date';
|
|
3
|
+
import type { NebaColor, NebaDensity, NebaSize, NebaWeekday } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* The calendar grid and the clock columns, written once for the four pickers.
|
|
6
|
+
*
|
|
7
|
+
* They live in `internal/` for the reason `button-group.ts` does: a
|
|
8
|
+
* DateTimePicker is a DatePicker and a TimePicker in one popup, and a
|
|
9
|
+
* DateRangePicker is two calendars, so three components need this and none of
|
|
10
|
+
* them should have to import another. The one thing it reaches *up* for is
|
|
11
|
+
* `Button` — the header's steppers are buttons, they are not a new kind of
|
|
12
|
+
* control, and Pagination already makes that argument. Nothing here is exported
|
|
13
|
+
* from `src/index.ts`.
|
|
14
|
+
*
|
|
15
|
+
* The day cells are deliberately *not* Buttons. A cell has states a Button has
|
|
16
|
+
* no vocabulary for — inside a range, at the end of a range, today, belonging to
|
|
17
|
+
* the month next door — and four of them have to be told apart at a glance in a
|
|
18
|
+
* grid of forty-two.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Every string a picker says that is not a date.
|
|
22
|
+
*
|
|
23
|
+
* One object rather than eighteen props. These are a set: a caller who has to
|
|
24
|
+
* translate "Previous month" has to translate "Next month" in the same breath,
|
|
25
|
+
* and a component with eighteen `*Label` props is a component whose signature is
|
|
26
|
+
* mostly apology. The dates themselves are never in here — those come from
|
|
27
|
+
* `Intl`, which already knows what July is called in more languages than this
|
|
28
|
+
* file ever will.
|
|
29
|
+
*/
|
|
30
|
+
export interface PickerLabels {
|
|
31
|
+
/** The calendar's steppers, in day view. */
|
|
32
|
+
previousMonth: string;
|
|
33
|
+
nextMonth: string;
|
|
34
|
+
/** The same steppers in month view, where they move by a year. */
|
|
35
|
+
previousYear: string;
|
|
36
|
+
nextYear: string;
|
|
37
|
+
/** And in year view, where they move by a page of twelve. */
|
|
38
|
+
previousYears: string;
|
|
39
|
+
nextYears: string;
|
|
40
|
+
/** The two header buttons that open the month grid and the year grid. */
|
|
41
|
+
chooseMonth: string;
|
|
42
|
+
chooseYear: string;
|
|
43
|
+
/** The footer's actions. */
|
|
44
|
+
today: string;
|
|
45
|
+
now: string;
|
|
46
|
+
clear: string;
|
|
47
|
+
done: string;
|
|
48
|
+
/** The clock's columns. */
|
|
49
|
+
hour: string;
|
|
50
|
+
minute: string;
|
|
51
|
+
second: string;
|
|
52
|
+
meridiem: string;
|
|
53
|
+
/** Which end of a range the calendar is currently asking for. */
|
|
54
|
+
start: string;
|
|
55
|
+
end: string;
|
|
56
|
+
}
|
|
57
|
+
export declare const defaultPickerLabels: PickerLabels;
|
|
58
|
+
/** Merges a caller's overrides over the defaults, once per render. */
|
|
59
|
+
export declare function usePickerLabels(overrides?: Partial<PickerLabels>): PickerLabels;
|
|
60
|
+
export interface CalendarProps {
|
|
61
|
+
size: NebaSize;
|
|
62
|
+
color: NebaColor;
|
|
63
|
+
locale?: string;
|
|
64
|
+
weekStartsOn: NebaWeekday;
|
|
65
|
+
/** The month on screen. Controlled, so two panels can be kept a month apart. */
|
|
66
|
+
month: Date;
|
|
67
|
+
onMonthChange: (month: Date) => void;
|
|
68
|
+
/** The days drawn filled — one for a single picker, up to two for a range. */
|
|
69
|
+
selected: readonly (Date | null | undefined)[];
|
|
70
|
+
/** The two ends the band is drawn between. Both `null` outside range mode. */
|
|
71
|
+
rangeStart?: Date | null;
|
|
72
|
+
rangeEnd?: Date | null;
|
|
73
|
+
onSelect: (date: Date) => void;
|
|
74
|
+
/** The day under the pointer, for a range that is only half chosen. */
|
|
75
|
+
onPreviewChange?: (date: Date | null) => void;
|
|
76
|
+
minDate?: Date | null;
|
|
77
|
+
maxDate?: Date | null;
|
|
78
|
+
shouldDisableDate?: (date: Date) => boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Draws the leading and trailing days that belong to the neighbouring months.
|
|
81
|
+
*
|
|
82
|
+
* On by default, because clicking the 1st of next month from this month's
|
|
83
|
+
* panel is a real shortcut. A two-month range picker turns it *off*, and not
|
|
84
|
+
* as a matter of taste: with both panels showing six full weeks, the 1st of
|
|
85
|
+
* August appears twice — once as a trailing day of July and once as itself —
|
|
86
|
+
* and two cells with the same name in the same popup is ambiguous to a pointer
|
|
87
|
+
* and outright broken to a screen reader.
|
|
88
|
+
* @default true
|
|
89
|
+
*/
|
|
90
|
+
showOutsideDays?: boolean;
|
|
91
|
+
/** Takes the focus on mount — the popup has just opened. */
|
|
92
|
+
autoFocus?: boolean;
|
|
93
|
+
showPreviousButton?: boolean;
|
|
94
|
+
showNextButton?: boolean;
|
|
95
|
+
labels: PickerLabels;
|
|
96
|
+
className?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* One month, with a way to reach every other one.
|
|
100
|
+
*
|
|
101
|
+
* Three views on the same footprint: the days of a month, the twelve months of a
|
|
102
|
+
* year, twelve years at a time. They are deliberately the same width *and* the
|
|
103
|
+
* same height — the day view is seven rows counting its header, and the other
|
|
104
|
+
* two stretch four rows and three rows across that same height — so switching
|
|
105
|
+
* view never resizes the popup under the pointer that opened it.
|
|
106
|
+
*
|
|
107
|
+
* Arrow keys move by one cell, `PageUp`/`PageDown` by a month (a year with
|
|
108
|
+
* Shift), `Home`/`End` to the ends of the week, and running off an edge steps
|
|
109
|
+
* the calendar rather than stopping. One roving tab stop, so `Tab` leaves the
|
|
110
|
+
* grid instead of walking forty-two cells — the pattern the ARIA date-picker
|
|
111
|
+
* practice describes, and the reason none of the cells is a `disabled` button.
|
|
112
|
+
*/
|
|
113
|
+
export declare function Calendar({ size, color, locale, weekStartsOn, month, onMonthChange, selected, rangeStart, rangeEnd, onSelect, onPreviewChange, minDate, maxDate, shouldDisableDate, showOutsideDays, autoFocus, showPreviousButton, showNextButton, labels, className }: CalendarProps): React.JSX.Element;
|
|
114
|
+
export type { TimeUnit };
|
|
115
|
+
export interface TimeGridProps {
|
|
116
|
+
size: NebaSize;
|
|
117
|
+
density: NebaDensity;
|
|
118
|
+
locale?: string;
|
|
119
|
+
/** The time on screen, or `null` while nothing has been chosen. */
|
|
120
|
+
value: Date | null;
|
|
121
|
+
/** The day the columns write into while `value` is still `null`. */
|
|
122
|
+
referenceDate: Date;
|
|
123
|
+
onChange: (value: Date) => void;
|
|
124
|
+
/** A 12-hour dial with an AM/PM column. Defaults to whatever the locale does. */
|
|
125
|
+
hour12: boolean;
|
|
126
|
+
showSeconds: boolean;
|
|
127
|
+
hourStep: number;
|
|
128
|
+
minuteStep: number;
|
|
129
|
+
secondStep: number;
|
|
130
|
+
shouldDisableTime?: (value: Date, unit: TimeUnit) => boolean;
|
|
131
|
+
/** Takes the focus on mount — the popup has just opened. */
|
|
132
|
+
autoFocus?: boolean;
|
|
133
|
+
labels: PickerLabels;
|
|
134
|
+
className?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Hours, minutes and — when asked for — seconds, as columns you scroll rather
|
|
138
|
+
* than as a dial you drag.
|
|
139
|
+
*
|
|
140
|
+
* Columns because they are the shape that answers what a time picker is actually
|
|
141
|
+
* asked: "half past nine" is two glances, and "any time at all, on the hour" is
|
|
142
|
+
* a column you never touch. A clock face is prettier and needs a `transform` to
|
|
143
|
+
* read, which this library does not have.
|
|
144
|
+
*
|
|
145
|
+
* The chosen row in each column is scrolled into view once, on open. That is the
|
|
146
|
+
* only imperative work here and it is not optional: a column of sixty minutes
|
|
147
|
+
* that opens at `00` while the value is `45` has hidden its own answer.
|
|
148
|
+
*/
|
|
149
|
+
export declare function TimeGrid({ size, density, locale, value, referenceDate, onChange, hour12, showSeconds, hourStep, minuteStep, secondStep, shouldDisableTime, autoFocus, labels, className }: TimeGridProps): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as o from"react";import{Button as r}from"../components/button/Button";import{ChevronIcon as a}from"./icons";import{controlHeightClasses as l,controlTextClasses as s,cx as i,gapClasses as c,metaTextClasses as u,pressTransitionClasses as d,srOnlyClasses as m,transitionClasses as h}from"./styles";import{addDays as g,addMonths as f,addYears as b,calendarWeeks as p,compareDay as v,dateFormatter as x,daysInMonth as w,isDayOutside as y,isMonthBeforeYear as D,isSameDay as N,isSameMonth as S,isValidDate as M,makeDate as P,meridiemLabels as C,monthLabels as k,startOfDay as Y,startOfMonth as z,today as A,weekdayLabels as F,withTime as E,YEAR_PAGE_SIZE as T,yearPageStart as j}from"./date";export const defaultPickerLabels={previousMonth:"Previous month",nextMonth:"Next month",previousYear:"Previous year",nextYear:"Next year",previousYears:"Previous years",nextYears:"Next years",chooseMonth:"Choose a month",chooseYear:"Choose a year",today:"Today",now:"Now",clear:"Clear",done:"Done",hour:"Hour",minute:"Minute",second:"Second",meridiem:"AM/PM",start:"Start",end:"End"};export function usePickerLabels(e){return o.useMemo(()=>e?{...defaultPickerLabels,...e}:defaultPickerLabels,[e])}const R={xs:"1.375rem",sm:"1.625rem",md:"2rem",lg:"2.5rem",xl:"3rem"},B={xs:"rounded-(--neba-radius-xs)",sm:"rounded-(--neba-radius-xs)",md:"rounded-(--neba-radius-sm)",lg:"rounded-(--neba-radius-md)",xl:"rounded-(--neba-radius-lg)"},H={xs:"rounded-s-(--neba-radius-xs)",sm:"rounded-s-(--neba-radius-xs)",md:"rounded-s-(--neba-radius-sm)",lg:"rounded-s-(--neba-radius-md)",xl:"rounded-s-(--neba-radius-lg)"},L={xs:"rounded-e-(--neba-radius-xs)",sm:"rounded-e-(--neba-radius-xs)",md:"rounded-e-(--neba-radius-sm)",lg:"rounded-e-(--neba-radius-md)",xl:"rounded-e-(--neba-radius-lg)"},K=["relative flex select-none items-center justify-center tabular-nums","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",h,d,"focus-visible:z-10 focus-visible:[outline:2px_solid_var(--n-ring)]","focus-visible:[outline-offset:-2px]"].join(" ");function O({children:n,label:o,selected:r,inRange:a=!1,rangeEdge:l=null,current:s=!1,muted:c=!1,disabled:u=!1,focused:d=!1,size:m,className:h,onClick:g,onPointerEnter:f,onKeyDown:b}){return t("button",{type:"button",role:"gridcell","aria-label":o,"aria-selected":r,"aria-current":s?"date":void 0,"aria-disabled":u||void 0,tabIndex:d?0:-1,"data-focus-target":d?"true":void 0,className:i(K,"start"===l?H[m]:"end"===l?L[m]:"middle"===l?"rounded-none":B[m],u?"cursor-not-allowed text-(--neba-disabled-fg)":r?"cursor-pointer bg-(--n-fill) font-semibold text-(--n-on-solid) hover:bg-(--n-fill-hover) active:bg-(--n-fill-active)":a?"cursor-pointer bg-(--n-soft) text-(--neba-fg) hover:bg-(--n-soft-hover) active:bg-(--n-soft-press)":s?"cursor-pointer font-semibold text-(--n-accent) hover:bg-(--n-soft) active:bg-(--n-soft-press)":c?"cursor-pointer text-(--neba-muted-fg) hover:bg-(--n-soft) active:bg-(--n-soft-press)":"cursor-pointer text-(--neba-fg) hover:bg-(--n-soft) active:bg-(--n-soft-press)",h),onClick:()=>{u||g()},onPointerEnter:f,onKeyDown:b,children:[n,s?e("span",{"aria-hidden":"true",className:"absolute bottom-[0.18em] size-[0.22em] rounded-full bg-current"}):null]})}function U({size:o,color:u,view:d,month:m,locale:h,labels:g,showPreviousButton:f,showNextButton:b,onStep:p,onViewChange:v}){const x=k(h,"long")[m.getMonth()],w=String(m.getFullYear()),y=D(h),N="day"===d?[g.previousMonth,g.nextMonth]:"month"===d?[g.previousYear,g.nextYear]:[g.previousYears,g.nextYears],S=(t,n)=>n?e(r,{variant:"text",size:o,color:u,density:"compact","aria-label":N[-1===t?0:1],onClick:()=>p(t),startIcon:e("span",{className:i("flex items-center",-1===t?"rotate-90 rtl:-rotate-90":"-rotate-90 rtl:rotate-90"),children:e(a,{})})}):e("span",{"aria-hidden":"true",className:i(l[o],"w-(--n-cell)")}),M=t=>e("span",{className:i("flex items-center text-(--neba-muted-fg)","[transition:rotate_var(--neba-duration)_var(--neba-ease)]",t&&"rotate-180"),children:e(a,{})}),P=e(r,{variant:"text",size:o,color:u,density:"compact","aria-label":g.chooseMonth,"aria-expanded":"month"===d,onClick:()=>v("month"===d?"day":"month"),endIcon:M("month"===d),children:x},"month"),C=e(r,{variant:"text",size:o,color:u,density:"compact",className:"tabular-nums","aria-label":g.chooseYear,"aria-expanded":"year"===d,onClick:()=>v("year"===d?"day":"year"),endIcon:M("year"===d),children:w},"year"),Y=j(m.getFullYear());return t("div",{className:"flex items-center justify-between gap-1",children:[S(-1,f),e("div",{className:i("flex min-w-0 flex-1 items-center justify-center",c[o]),children:"year"===d?e("span",{className:i("flex items-center font-medium tabular-nums text-(--neba-fg)",l[o],s[o]),children:`${Y}–${Y+T-1}`}):"month"===d?C:t(n,y?{children:[P,C]}:{children:[C,P]})}),S(1,b)]})}export function Calendar({size:n,color:r,locale:a,weekStartsOn:l,month:s,onMonthChange:u,selected:d,rangeStart:m=null,rangeEnd:h=null,onSelect:g,onPreviewChange:p,minDate:v,maxDate:x,shouldDisableDate:w,showOutsideDays:D=!0,autoFocus:N=!1,showPreviousButton:C=!0,showNextButton:k=!0,labels:F,className:E}){const[j,B]=o.useState("day"),H=o.useMemo(()=>d.filter(M),[d]),[L,K]=o.useState(()=>{const e=H.find(e=>S(e,s));return e?Y(e):S(A(),s)?A():z(s)}),O=o.useRef(N),_=o.useRef(null);o.useEffect(()=>{K(e=>S(e,s)?e:z(s))},[s]),o.useLayoutEffect(()=>{O.current&&(O.current=!1,_.current?.querySelector('[data-focus-target="true"]')?.focus({preventScroll:!0}))});const V=o.useCallback(e=>y(e,v,x)||(w?.(e)??!1),[v,x,w]),G=e=>{O.current=!0,B(e)},J=e=>{O.current=!0,u(e)};return t("div",{ref:_,className:i("flex flex-col",c[n],E),style:{"--n-cell":R[n]},onPointerLeave:()=>p?.(null),children:[e(U,{size:n,color:r,view:j,month:s,locale:a,labels:F,showPreviousButton:C,showNextButton:k,onStep:e=>{u("day"===j?f(s,e):b(s,"month"===j?e:e*T))},onViewChange:G}),e("div",{className:"h-[calc(var(--n-cell)*7)] w-[calc(var(--n-cell)*7)]",children:"day"===j?e(q,{size:n,locale:a,weekStartsOn:l,month:s,chosen:H,rangeStart:m,rangeEnd:h,focusedDate:L,showOutsideDays:D,isDisabled:V,onSelect:e=>{K(e),g(e)},onPreviewChange:p,onMoveFocus:e=>{O.current=!0,K(e),S(e,s)||u(z(e))}}):"month"===j?e(I,{size:n,locale:a,month:s,chosen:H,minDate:v,maxDate:x,onMoveCursor:J,onPick:e=>{u(P(s.getFullYear(),e,1)),G("day")}}):e($,{size:n,month:s,chosen:H,minDate:v,maxDate:x,onMoveCursor:J,onPick:e=>{u(P(e,s.getMonth(),1)),G("month")}})})]})}function q({size:n,locale:o,weekStartsOn:r,month:a,chosen:l,rangeStart:c,rangeEnd:d,focusedDate:m,showOutsideDays:h,isDisabled:b,onSelect:w,onPreviewChange:y,onMoveFocus:D}){const P=p(a,r),C=F(o,r,"short"),k=F(o,r,"long"),Y=x(o,{dateStyle:"full"}),z=(T=d,M(E=c)&&M(T)?v(E,T)<=0?[E,T]:[T,E]:null);var E,T;const j=A();return t("div",{role:"grid",className:"flex h-full flex-col",children:[e("div",{role:"row",className:"grid grid-cols-7",children:C.map((t,o)=>e("span",{role:"columnheader","aria-label":k[o],className:i("flex h-(--n-cell) items-center justify-center font-medium text-(--neba-muted-fg) select-none",u[n]),children:t},o))}),P.map((t,o)=>e("div",{role:"row",className:"grid grid-cols-7",children:t.map(t=>{const o=!S(t,a);if(o&&!h)return e("span",{role:"gridcell","aria-hidden":"true",className:"size-(--n-cell)"},t.getTime());const c=l.some(e=>N(e,t)),u=null!==z&&v(t,z[0])>=0&&v(t,z[1])<=0,d=null!==z&&u&&N(t,z[0]),p=null!==z&&u&&N(t,z[1]);return e(O,{size:n,label:Y.format(t),selected:c,inRange:u&&!c,rangeEdge:u?d&&p?"both":d?"start":p?"end":"middle":null,current:N(t,j)&&!c,muted:o,disabled:b(t),focused:N(t,m),className:i("size-(--n-cell)",s[n]),onClick:()=>w(t),onPointerEnter:()=>y?.(t),onKeyDown:e=>((e,t)=>{const n=(t.getDay()-r+7)%7,o={ArrowLeft:()=>g(t,-1),ArrowRight:()=>g(t,1),ArrowUp:()=>g(t,-7),ArrowDown:()=>g(t,7),Home:()=>g(t,-n),End:()=>g(t,6-n),PageUp:()=>f(t,e.shiftKey?-12:-1),PageDown:()=>f(t,e.shiftKey?12:1)}[e.key];o&&(e.preventDefault(),D(o()))})(e,t),children:t.getDate()},t.getTime())})},o))]})}function I({size:t,locale:n,month:o,chosen:r,minDate:a,maxDate:l,onMoveCursor:c,onPick:u}){const d=k(n,"short"),m=k(n,"long"),h=o.getFullYear(),g=new Date,b=e=>{const t={ArrowLeft:-1,ArrowRight:1,ArrowUp:-3,ArrowDown:3,PageUp:-12,PageDown:12}[e.key];void 0!==t&&(e.preventDefault(),c(f(z(o),t)))};return e("div",{role:"grid",className:"flex h-full flex-col justify-evenly",children:[0,1,2,3].map(n=>e("div",{role:"row",className:"grid grid-cols-3 gap-1",children:[0,1,2].map(c=>{const f=3*n+c,p=P(h,f,1),x=P(h,f,w(h,f));return e(O,{size:t,label:`${m[f]} ${h}`,selected:r.some(e=>e.getFullYear()===h&&e.getMonth()===f),current:g.getFullYear()===h&&g.getMonth()===f,disabled:M(a)&&v(x,a)<0||M(l)&&v(p,l)>0,focused:f===o.getMonth(),className:i("h-(--n-cell) w-full",s[t]),onClick:()=>u(f),onKeyDown:b,children:d[f]},f)})},n))})}function $({size:t,month:n,chosen:o,minDate:r,maxDate:a,onMoveCursor:l,onPick:c}){const u=j(n.getFullYear()),d=(new Date).getFullYear(),m=e=>{const t={ArrowLeft:-1,ArrowRight:1,ArrowUp:-4,ArrowDown:4,PageUp:-T,PageDown:T}[e.key];void 0!==t&&(e.preventDefault(),l(b(z(n),t)))};return e("div",{role:"grid",className:"flex h-full flex-col justify-evenly",children:[0,1,2].map(l=>e("div",{role:"row",className:"grid grid-cols-4 gap-1",children:[0,1,2,3].map(h=>{const g=u+4*l+h;return e(O,{size:t,label:String(g),selected:o.some(e=>e.getFullYear()===g),current:g===d,disabled:M(r)&&g<r.getFullYear()||M(a)&&g>a.getFullYear(),focused:g===n.getFullYear(),className:i("h-(--n-cell) w-full",s[t]),onClick:()=>c(g),onKeyDown:m,children:g},g)})},l))})}function _(e){const t=e.parentElement;if(!t)return;const n=e.getBoundingClientRect(),o=t.getBoundingClientRect(),r=n.top-o.top-t.clientTop+t.scrollTop,a=r+n.height;r<t.scrollTop?t.scrollTop=r:a>t.scrollTop+t.clientHeight&&(t.scrollTop=a-t.clientHeight)}export function TimeGrid({size:n,density:r,locale:a,value:c,referenceDate:u,onChange:d,hour12:h,showSeconds:g,hourStep:f,minuteStep:b,secondStep:p,shouldDisableTime:v,autoFocus:w=!1,labels:y,className:D}){const N=c??u,S=o.useRef(null),[M,P]=o.useMemo(()=>C(a),[a]);o.useEffect(()=>{const e=S.current;if(e?.querySelectorAll('[data-chosen="true"]').forEach(_),w){const t=e?.querySelector('[role="listbox"]');(t?.querySelector('[data-chosen="true"]')??t?.querySelector('[role="option"]'))?.focus({preventScroll:!0})}},[w]);const k=o.useMemo(()=>{const e=Math.ceil((h?12:24)/f),t=Array.from({length:e},(e,t)=>t*f);return h?t.map(e=>0===e?12:e):t},[h,f]),Y=o.useMemo(()=>Array.from({length:Math.ceil(60/b)},(e,t)=>t*b),[b]),z=o.useMemo(()=>Array.from({length:Math.ceil(60/p)},(e,t)=>t*p),[p]),A=e=>String(e).padStart(2,"0"),F=h?N.getHours()%12||12:N.getHours(),T=(t,o,r,a,u)=>e("div",{role:"listbox","aria-label":o,className:i("flex flex-col gap-0.5 overflow-y-auto overscroll-contain","h-[calc(var(--n-cell)*7)] w-[calc(var(--n-cell)*2)]","scroll-py-0.5 [scrollbar-width:thin]"),children:r.map(o=>{const r=((e,t)=>E(N,"hour"===e?{hours:h?t%12+(N.getHours()>=12?12:0):t}:"minute"===e?{minutes:t}:"second"===e?{seconds:t}:{hours:N.getHours()%12+12*t}))(t,o),m=null!==c&&a(o),g=v?.(r,t)??!1;return e("button",{type:"button",role:"option","aria-selected":m,"aria-disabled":g||void 0,"data-chosen":m?"true":void 0,className:i(K,B[n],l[n],s[n],"w-full shrink-0",g?"cursor-not-allowed text-(--neba-disabled-fg)":m?"cursor-pointer bg-(--n-fill) font-semibold text-(--n-on-solid) hover:bg-(--n-fill-hover) active:bg-(--n-fill-active)":"cursor-pointer text-(--neba-fg) hover:bg-(--n-soft) active:bg-(--n-soft-press)"),onClick:()=>{g||d(r)},children:u(o)},o)})},t);return t("div",{ref:S,className:i("flex","compact"===r?"gap-0.5":"gap-1",D),style:{"--n-cell":R[n]},children:[T("hour",y.hour,k,e=>e===F,e=>h?String(e):A(e)),T("minute",y.minute,Y,e=>e===N.getMinutes(),A),g?T("second",y.second,z,e=>e===N.getSeconds(),A):null,h?T("meridiem",y.meridiem,[0,1],e=>(N.getHours()>=12?1:0)===e,e=>0===e?M:P):null,e("span",{className:m,"aria-live":"polite",children:null===c?"":x(a,{hour:"numeric",minute:"2-digit",...g?{second:"2-digit"}:{}}).format(c)})]})}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the naming the four pickers share.
|
|
3
|
+
*
|
|
4
|
+
* No date library under it, deliberately. Neba's one runtime dependency is Base
|
|
5
|
+
* UI, and a component library that quietly adds `date-fns` — or worse, picks a
|
|
6
|
+
* side in the dayjs/luxon/Temporal argument on its consumer's behalf — has made
|
|
7
|
+
* a decision that was not its to make. Everything here is either `Date`
|
|
8
|
+
* arithmetic, which is a dozen lines, or `Intl`, which the platform already
|
|
9
|
+
* ships and which knows more about month names in more languages than any
|
|
10
|
+
* bundled table ever will.
|
|
11
|
+
*
|
|
12
|
+
* Two rules hold everywhere below:
|
|
13
|
+
*
|
|
14
|
+
* - **Local time, always.** A calendar day is a thing a person is looking at on
|
|
15
|
+
* a wall, not an instant on a line. `new Date(2026, 6, 27)` is midnight local
|
|
16
|
+
* and every comparison here is made on the local Y/M/D triple, so a picker in
|
|
17
|
+
* Seoul and a picker in São Paulo both light up the cell that says 27.
|
|
18
|
+
* - **Nothing is mutated.** `Date` is mutable and every method on it that sounds
|
|
19
|
+
* like a question is actually a command. Each function here copies first, so a
|
|
20
|
+
* `value` handed in by a caller is never the object that comes back out.
|
|
21
|
+
*/
|
|
22
|
+
import type { NebaWeekday } from '../types';
|
|
23
|
+
/** Which unit the calendar is currently letting you pick. */
|
|
24
|
+
export type CalendarView = 'day' | 'month' | 'year';
|
|
25
|
+
/** How many years one page of the year grid holds. Four columns of three. */
|
|
26
|
+
export declare const YEAR_PAGE_SIZE = 12;
|
|
27
|
+
/**
|
|
28
|
+
* A local midnight on the given Y/M/D, with out-of-range parts normalised —
|
|
29
|
+
* month `12` rolls into January, day `0` into the last day of the month before.
|
|
30
|
+
*
|
|
31
|
+
* Built through `setFullYear` rather than `new Date(year, month, day)` because
|
|
32
|
+
* the two-argument constructor maps years 0–99 onto 1900–1999. Nobody is going
|
|
33
|
+
* to pick a date in the year 47, but a component that silently rewrites the year
|
|
34
|
+
* it was handed is a component that will eventually be blamed for something else.
|
|
35
|
+
*/
|
|
36
|
+
export declare function makeDate(year: number, month: number, day: number): Date;
|
|
37
|
+
/** Is this a `Date` that stands for a real instant? `new Date('nope')` is not. */
|
|
38
|
+
export declare function isValidDate(value: unknown): value is Date;
|
|
39
|
+
/** The same day with the clock wound back to midnight. */
|
|
40
|
+
export declare function startOfDay(date: Date): Date;
|
|
41
|
+
/** The first day of the month this date is in, at midnight. */
|
|
42
|
+
export declare function startOfMonth(date: Date): Date;
|
|
43
|
+
/** How many days a month has, leap years included. */
|
|
44
|
+
export declare function daysInMonth(year: number, month: number): number;
|
|
45
|
+
/** Today, at midnight. The one place the pickers read the clock for a *date*. */
|
|
46
|
+
export declare function today(): Date;
|
|
47
|
+
export declare function addDays(date: Date, amount: number): Date;
|
|
48
|
+
/**
|
|
49
|
+
* Months, with the day of the month clamped rather than allowed to overflow.
|
|
50
|
+
*
|
|
51
|
+
* 31 January plus one month is 28 February, not 3 March. The naive
|
|
52
|
+
* `setMonth(getMonth() + 1)` gives the second answer, which is why stepping a
|
|
53
|
+
* calendar forward from a 31st with it skips February entirely.
|
|
54
|
+
*/
|
|
55
|
+
export declare function addMonths(date: Date, amount: number): Date;
|
|
56
|
+
export declare function addYears(date: Date, amount: number): Date;
|
|
57
|
+
/** Negative, zero or positive, the way a sort comparator wants it. */
|
|
58
|
+
export declare function compareDay(a: Date, b: Date): number;
|
|
59
|
+
export declare function isSameDay(a: Date | null | undefined, b: Date | null | undefined): boolean;
|
|
60
|
+
export declare function isSameMonth(a: Date | null | undefined, b: Date | null | undefined): boolean;
|
|
61
|
+
/** Strictly between the two ends, both of which are optional. */
|
|
62
|
+
export declare function isDayInRange(date: Date, start: Date | null, end: Date | null): boolean;
|
|
63
|
+
/** Holds a date inside `[min, max]`, at whatever precision the bounds carry. */
|
|
64
|
+
export declare function clampDate(date: Date, min?: Date | null, max?: Date | null): Date;
|
|
65
|
+
/**
|
|
66
|
+
* Is this calendar *day* outside the allowed span?
|
|
67
|
+
*
|
|
68
|
+
* Day-granular on purpose. A `maxDate` of 27 July at 09:00 still leaves the 27th
|
|
69
|
+
* pickable — the bound is about which days exist, and the time of day is the
|
|
70
|
+
* time picker's problem. `DateTimePicker` re-checks at full precision once an
|
|
71
|
+
* hour has been chosen.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isDayOutside(date: Date, min?: Date | null, max?: Date | null): boolean;
|
|
74
|
+
/** Minutes since local midnight — what `minTime`/`maxTime` are compared on. */
|
|
75
|
+
export declare function minutesOfDay(date: Date): number;
|
|
76
|
+
/** Seconds since local midnight, for the pickers that show a seconds column. */
|
|
77
|
+
export declare function secondsOfDay(date: Date): number;
|
|
78
|
+
/** Which column of a clock a candidate time is being offered for. */
|
|
79
|
+
export type TimeUnit = 'hour' | 'minute' | 'second' | 'meridiem';
|
|
80
|
+
/**
|
|
81
|
+
* The span of the day one row of one column covers, in seconds since midnight.
|
|
82
|
+
*
|
|
83
|
+
* This is the detail that separates a working time picker from a frustrating
|
|
84
|
+
* one. A bound has to be checked against the *span* a row stands for, not
|
|
85
|
+
* against one instant inside it: with a `minTime` of 09:30, the hour `9` covers
|
|
86
|
+
* 09:00:00–09:59:59, which overlaps what is allowed, so it stays available and
|
|
87
|
+
* the minute column is where `00` through `25` grey out. Comparing the whole
|
|
88
|
+
* candidate instead hides the 9 and makes half past nine unreachable.
|
|
89
|
+
*/
|
|
90
|
+
export declare function timeUnitSpan(unit: TimeUnit, at: Date): [number, number];
|
|
91
|
+
/** The same instant with one or more clock fields replaced. */
|
|
92
|
+
export declare function withTime(date: Date, parts: {
|
|
93
|
+
hours?: number;
|
|
94
|
+
minutes?: number;
|
|
95
|
+
seconds?: number;
|
|
96
|
+
}): Date;
|
|
97
|
+
/** `date`'s calendar day wearing `time`'s clock. */
|
|
98
|
+
export declare function mergeDateAndTime(date: Date, time: Date): Date;
|
|
99
|
+
/**
|
|
100
|
+
* Six weeks of seven days, always — including the leading and trailing days that
|
|
101
|
+
* belong to the neighbouring months.
|
|
102
|
+
*
|
|
103
|
+
* Six rows whatever the month, and that is the whole point. A February that
|
|
104
|
+
* starts on a Sunday needs four rows and a 31-day month starting on a Saturday
|
|
105
|
+
* needs six; a grid that renders only the rows it needs is a grid that changes
|
|
106
|
+
* height when you step a month forward, moving every cell out from under the
|
|
107
|
+
* pointer that just pressed one. The same reason Pagination pins its slot count.
|
|
108
|
+
*/
|
|
109
|
+
export declare function calendarWeeks(month: Date, weekStartsOn: NebaWeekday): Date[][];
|
|
110
|
+
/** The first year on the page a given year falls on. 2026 → 2016 at 12 a page. */
|
|
111
|
+
export declare function yearPageStart(year: number): number;
|
|
112
|
+
/** A memoised `Intl.DateTimeFormat`. `undefined` locale means the runtime's own. */
|
|
113
|
+
export declare function dateFormatter(locale: string | undefined, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
|
|
114
|
+
/** Formats a date, tolerating the `null` a cleared picker holds. */
|
|
115
|
+
export declare function formatDate(date: Date | null | undefined, locale: string | undefined, options: Intl.DateTimeFormatOptions): string;
|
|
116
|
+
/**
|
|
117
|
+
* Every distinct string those instants format to. Deduplicated, because a
|
|
118
|
+
* date-only format collapses twenty-four of them into a handful.
|
|
119
|
+
*/
|
|
120
|
+
export declare function displaySamples(locale: string | undefined, options: Intl.DateTimeFormatOptions): string[];
|
|
121
|
+
/**
|
|
122
|
+
* The samples plus the placeholder, when the placeholder is a string.
|
|
123
|
+
*
|
|
124
|
+
* An empty picker shows the placeholder, which can easily be longer than any
|
|
125
|
+
* date — "Pick a departure date" against "3 Aug 2026" — and a trigger that
|
|
126
|
+
* shrinks the moment the first date is chosen is the same jump from the other
|
|
127
|
+
* direction. A `ReactNode` placeholder is left out: there is nothing to measure
|
|
128
|
+
* without rendering it twice.
|
|
129
|
+
*/
|
|
130
|
+
export declare function withPlaceholder(samples: string[], placeholder: unknown): string[];
|
|
131
|
+
/**
|
|
132
|
+
* The three machine-readable spellings, for the hidden input that makes a picker
|
|
133
|
+
* submit with a form.
|
|
134
|
+
*
|
|
135
|
+
* Local, not UTC, and that is the whole point: `toISOString()` on a `Date`
|
|
136
|
+
* standing for 27 July in Seoul gives `2026-07-26T15:00:00Z`, and a form field
|
|
137
|
+
* that quietly reports the day before the one on screen is the single most
|
|
138
|
+
* expensive bug a date picker can ship. The shapes are the ones the native
|
|
139
|
+
* `<input type="date">`, `type="time"` and `type="datetime-local"` submit, so a
|
|
140
|
+
* server that already parses those needs no new code.
|
|
141
|
+
*/
|
|
142
|
+
export declare function toISODate(date: Date): string;
|
|
143
|
+
export declare function toISOTime(date: Date, withSeconds?: boolean): string;
|
|
144
|
+
export declare function toISODateTime(date: Date, withSeconds?: boolean): string;
|
|
145
|
+
/**
|
|
146
|
+
* The seven column headers, rotated so the first one is `weekStartsOn`.
|
|
147
|
+
*
|
|
148
|
+
* `short` rather than `narrow`: narrow gives `S`, `M`, `T`, `W`, `T`, `F`, `S`
|
|
149
|
+
* in English, where two pairs are indistinguishable. The full name goes on the
|
|
150
|
+
* header's `aria-label` so a screen reader hears "Monday" rather than "Mon".
|
|
151
|
+
*/
|
|
152
|
+
export declare function weekdayLabels(locale: string | undefined, weekStartsOn: NebaWeekday, weekday?: 'narrow' | 'short' | 'long'): string[];
|
|
153
|
+
/** The twelve month names, January first, in the locale's own words. */
|
|
154
|
+
export declare function monthLabels(locale: string | undefined, month?: 'short' | 'long'): string[];
|
|
155
|
+
/**
|
|
156
|
+
* Does this locale write the month before the year?
|
|
157
|
+
*
|
|
158
|
+
* The calendar's header is two separate buttons — one that opens the month grid
|
|
159
|
+
* and one that opens the year grid — so it cannot just print what `Intl` gives
|
|
160
|
+
* it. Asking `formatToParts` which part came first is how the two buttons end up
|
|
161
|
+
* in the order the reader expects: `July 2026` in English, `2026년 7월` in
|
|
162
|
+
* Korean. Getting this wrong is subtle and reads as broken to exactly the people
|
|
163
|
+
* it is wrong for.
|
|
164
|
+
*/
|
|
165
|
+
export declare function isMonthBeforeYear(locale: string | undefined): boolean;
|
|
166
|
+
/** Does this locale put a clock on a 12-hour dial? */
|
|
167
|
+
export declare function isHour12(locale: string | undefined): boolean;
|
|
168
|
+
/** What this locale calls AM and PM. */
|
|
169
|
+
export declare function meridiemLabels(locale: string | undefined): [string, string];
|
|
170
|
+
export declare function localeWeekStart(locale: string | undefined): NebaWeekday;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const YEAR_PAGE_SIZE=12;export function makeDate(t,e,r){const n=new Date(0);return n.setFullYear(t,e,r),n.setHours(0,0,0,0),n}export function isValidDate(t){return t instanceof Date&&!Number.isNaN(t.getTime())}export function startOfDay(t){const e=new Date(t.getTime());return e.setHours(0,0,0,0),e}export function startOfMonth(t){return makeDate(t.getFullYear(),t.getMonth(),1)}export function daysInMonth(t,e){return makeDate(t,e+1,0).getDate()}export function today(){return startOfDay(new Date)}export function addDays(t,e){const r=new Date(t.getTime());return r.setDate(r.getDate()+e),r}export function addMonths(t,e){const r=t.getFullYear(),n=t.getMonth()+e,o=new Date(t.getTime()),a=makeDate(r,n,1);return o.setFullYear(a.getFullYear(),a.getMonth(),Math.min(t.getDate(),daysInMonth(a.getFullYear(),a.getMonth()))),o}export function addYears(t,e){return addMonths(t,12*e)}export function compareDay(t,e){return startOfDay(t).getTime()-startOfDay(e).getTime()}export function isSameDay(t,e){return isValidDate(t)&&isValidDate(e)&&0===compareDay(t,e)}export function isSameMonth(t,e){return isValidDate(t)&&isValidDate(e)&&t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()}export function isDayInRange(t,e,r){return!(!isValidDate(e)||!isValidDate(r))&&(compareDay(t,e)>0&&compareDay(t,r)<0)}export function clampDate(t,e,r){return isValidDate(e)&&t.getTime()<e.getTime()?new Date(e.getTime()):isValidDate(r)&&t.getTime()>r.getTime()?new Date(r.getTime()):t}export function isDayOutside(t,e,r){return!!(isValidDate(e)&&compareDay(t,e)<0)||isValidDate(r)&&compareDay(t,r)>0}export function minutesOfDay(t){return 60*t.getHours()+t.getMinutes()}export function secondsOfDay(t){return 3600*t.getHours()+60*t.getMinutes()+t.getSeconds()}export function timeUnitSpan(t,e){const r=secondsOfDay(e);if("hour"===t){const t=3600*Math.floor(r/3600);return[t,t+3599]}if("minute"===t){const t=60*Math.floor(r/60);return[t,t+59]}if("second"===t)return[r,r];const n=e.getHours()<12?0:43200;return[n,n+43200-1]}export function withTime(t,e){const r=new Date(t.getTime());return r.setHours(e.hours??r.getHours(),e.minutes??r.getMinutes(),e.seconds??r.getSeconds(),0),r}export function mergeDateAndTime(t,e){return withTime(startOfDay(t),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()})}export function calendarWeeks(t,e){const r=startOfMonth(t),n=(r.getDay()-e+7)%7,o=addDays(r,-n);return Array.from({length:6},(t,e)=>Array.from({length:7},(t,r)=>addDays(o,7*e+r)))}export function yearPageStart(t){return t-(t%12+12)%12}const t=new Map;export function dateFormatter(e,r){const n=`${e??""}\0${JSON.stringify(r)}`;let o=t.get(n);return o||(o=new Intl.DateTimeFormat(e,r),t.set(n,o)),o}export function formatDate(t,e,r){return isValidDate(t)?dateFormatter(e,r).format(t):""}const e=Array.from({length:24},(t,e)=>new Date(2027,e%12,21+e%7,e,58,58));export function displaySamples(t,r){const n=dateFormatter(t,r);return[...new Set(e.map(t=>n.format(t)))]}export function withPlaceholder(t,e){return"string"==typeof e&&""!==e?[...t,e]:t}export function toISODate(t){const e=t=>String(t).padStart(2,"0");return`${String(t.getFullYear()).padStart(4,"0")}-${e(t.getMonth()+1)}-${e(t.getDate())}`}export function toISOTime(t,e=!1){const r=t=>String(t).padStart(2,"0"),n=`${r(t.getHours())}:${r(t.getMinutes())}`;return e?`${n}:${r(t.getSeconds())}`:n}export function toISODateTime(t,e=!1){return`${toISODate(t)}T${toISOTime(t,e)}`}const r=makeDate(2021,7,1);export function weekdayLabels(t,e,n="short"){const o=dateFormatter(t,{weekday:n});return Array.from({length:7},(t,n)=>o.format(addDays(r,(e+n)%7)))}export function monthLabels(t,e="short"){const r=dateFormatter(t,{month:e});return Array.from({length:12},(t,e)=>r.format(makeDate(2021,e,1)))}export function isMonthBeforeYear(t){const e=dateFormatter(t,{year:"numeric",month:"long"}).formatToParts(r);return e.findIndex(t=>"month"===t.type)<e.findIndex(t=>"year"===t.type)}export function isHour12(t){const e=dateFormatter(t,{hour:"numeric"}).resolvedOptions();return e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle:!0===e.hour12}export function meridiemLabels(t){const e=dateFormatter(t,{hour:"numeric",hour12:!0}),n=t=>{const n=e.formatToParts(withTime(r,{hours:t})).find(t=>"dayPeriod"===t.type);return n?.value??(t<12?"AM":"PM")};return[n(9),n(21)]}export function localeWeekStart(t){try{const e=t??(new Intl.DateTimeFormat).resolvedOptions().locale,r=new Intl.Locale(e),n="function"==typeof r.getWeekInfo?r.getWeekInfo():r.weekInfo;if("number"==typeof n?.firstDay)return n.firstDay%7}catch{}return 0}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic and the vocabulary the three layout components share.
|
|
3
|
+
*
|
|
4
|
+
* Like `internal/styles.ts` this is the library talking to itself, and it lives
|
|
5
|
+
* here rather than in either component's folder for the same reason
|
|
6
|
+
* `internal/button-group.ts` does: `GridContainer` and `Grid` are one system in
|
|
7
|
+
* two elements, and neither should have to import the other.
|
|
8
|
+
*
|
|
9
|
+
* What is *not* here is the layout itself. A column width is
|
|
10
|
+
* `(100% + gap) * span / columns - gap`, it has to change at four breakpoints,
|
|
11
|
+
* and it is the width of an element whose column count is declared on its
|
|
12
|
+
* parent — none of which Tailwind can spell, because Tailwind only ever sees
|
|
13
|
+
* class names written out literally and `columns` is a number a caller picks.
|
|
14
|
+
* So the widths are real CSS in `styles.css`, driven by the `--n-*` slots this
|
|
15
|
+
* file generates. That is the same split the rest of the library makes: per-
|
|
16
|
+
* instance values go in inline custom properties, never in class names.
|
|
17
|
+
*/
|
|
18
|
+
import type * as React from 'react';
|
|
19
|
+
import type { NebaAlignItems, NebaAlignSelf, NebaBreakpoint, NebaJustifyContent, NebaResponsive } from '../types';
|
|
20
|
+
/** Smallest first, which is also the order the media queries have to be in. */
|
|
21
|
+
export declare const breakpoints: readonly NebaBreakpoint[];
|
|
22
|
+
/**
|
|
23
|
+
* Turns a responsive value into the `--n-{name}-{breakpoint}` slots the CSS
|
|
24
|
+
* reads, emitting only the breakpoints the caller actually named.
|
|
25
|
+
*
|
|
26
|
+
* The gaps are filled in by CSS rather than here: each breakpoint's rule falls
|
|
27
|
+
* back through the ones below it, so `{ md: 6 }` needs one slot and not five.
|
|
28
|
+
* That keeps the inline style on a grid item down to what was asked for.
|
|
29
|
+
*/
|
|
30
|
+
export declare function responsiveSlots<T>(name: string, value: NebaResponsive<T> | undefined, toCss: (value: T) => string): React.CSSProperties;
|
|
31
|
+
/**
|
|
32
|
+
* Fills in the `xs` entry of a partial map with the prop's own default.
|
|
33
|
+
*
|
|
34
|
+
* Without this, `spacing={{ md: 4 }}` would be a grid with no gutter at all
|
|
35
|
+
* below 48rem — the CSS fallback rather than the documented default of 2 — and
|
|
36
|
+
* a caller who narrowed one breakpoint would silently lose every other one. A
|
|
37
|
+
* map says "from here up, use this instead"; it does not say "and nothing
|
|
38
|
+
* below".
|
|
39
|
+
*/
|
|
40
|
+
export declare function withBaseline<T>(value: NebaResponsive<T> | undefined, baseline: T): NebaResponsive<T>;
|
|
41
|
+
/**
|
|
42
|
+
* A count of columns, as a plain number for `calc()` to divide by.
|
|
43
|
+
*
|
|
44
|
+
* Rounded and floored at 1 because the value ends up as a divisor: a grid of
|
|
45
|
+
* 2.5 columns is not a thing anyone meant, and a grid of 0 is a division by
|
|
46
|
+
* zero that would take the width declaration down with it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function columnCount(value: number): string;
|
|
49
|
+
/** A span or an offset. Same rounding; an offset of 0 is meaningful. */
|
|
50
|
+
export declare function columnUnits(value: number, min: number): string;
|
|
51
|
+
export declare const spanValue: (value: number) => string;
|
|
52
|
+
export declare const offsetValue: (value: number) => string;
|
|
53
|
+
/**
|
|
54
|
+
* A gutter, as a length.
|
|
55
|
+
*
|
|
56
|
+
* Fractions are the point — `spacing={1.5}` is `0.375rem`, the same step
|
|
57
|
+
* `gap-1.5` is — so the multiplication is rounded to five places rather than
|
|
58
|
+
* left to print `0.30000000000000004rem` into the DOM.
|
|
59
|
+
*/
|
|
60
|
+
export declare function spacingValue(units: number): string;
|
|
61
|
+
export declare const justifyContentClasses: Record<NebaJustifyContent, string>;
|
|
62
|
+
export declare const alignItemsClasses: Record<NebaAlignItems, string>;
|
|
63
|
+
/**
|
|
64
|
+
* Where the *rows* sit when the grid is shorter than the box holding it. Only
|
|
65
|
+
* ever visible on a container with a height of its own, which is why it takes
|
|
66
|
+
* the full distribution vocabulary and `alignItems` does not.
|
|
67
|
+
*/
|
|
68
|
+
export declare const alignContentClasses: Record<NebaJustifyContent, string>;
|
|
69
|
+
export declare const alignSelfClasses: Record<NebaAlignSelf, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const breakpoints=["xs","sm","md","lg","xl"];export function responsiveSlots(t,e,n){const s=function(t){return null==t?{}:"object"==typeof t?t:{xs:t}}(e),o={};for(const e of breakpoints){const r=s[e];void 0!==r&&(o[`--n-${t}-${e}`]=n(r))}return o}export function withBaseline(t,e){return null==t?e:"object"==typeof t?{xs:e,...t}:t}export function columnCount(t){return String(Math.max(1,Math.round(t)))}export function columnUnits(t,e){return String(Math.max(e,Math.round(t)))}export const spanValue=t=>columnUnits(t,1);export const offsetValue=t=>columnUnits(t,0);export function spacingValue(t){const e=.25*Math.max(0,t);return`${Number(e.toFixed(5))}rem`}export const justifyContentClasses={start:"justify-start",center:"justify-center",end:"justify-end","space-between":"justify-between","space-around":"justify-around","space-evenly":"justify-evenly",stretch:"justify-stretch"};export const alignItemsClasses={start:"items-start",center:"items-center",end:"items-end",stretch:"items-stretch",baseline:"items-baseline"};export const alignContentClasses={start:"content-start",center:"content-center",end:"content-end","space-between":"content-between","space-around":"content-around","space-evenly":"content-evenly",stretch:"content-stretch"};export const alignSelfClasses={auto:"self-auto",start:"self-start",center:"self-center",end:"self-end",stretch:"self-stretch",baseline:"self-baseline"};
|
package/dist/internal/icons.d.ts
CHANGED
|
@@ -36,6 +36,37 @@ export declare function CheckIcon(): React.JSX.Element;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare function MinusIcon(): React.JSX.Element;
|
|
38
38
|
export declare function PlusIcon(): React.JSX.Element;
|
|
39
|
+
/**
|
|
40
|
+
* The two trend arrows a comparison draws.
|
|
41
|
+
*
|
|
42
|
+
* A pair, and they stay one: an arrow that rises at a different angle from the
|
|
43
|
+
* one that falls beside it reads as two toolkits in one report. Statistic draws
|
|
44
|
+
* both, and reaches for `MinusIcon` above when a figure has not moved — the
|
|
45
|
+
* third state of a comparison is genuinely the absence of an arrow.
|
|
46
|
+
*
|
|
47
|
+
* The shape carries the meaning for the same reason the severity set does: a
|
|
48
|
+
* delta that says "down" only in red says it only to some readers.
|
|
49
|
+
*/
|
|
50
|
+
export declare function TrendUpIcon(): React.JSX.Element;
|
|
51
|
+
export declare function TrendDownIcon(): React.JSX.Element;
|
|
52
|
+
/**
|
|
53
|
+
* The two glyphs a picker's trigger wears.
|
|
54
|
+
*
|
|
55
|
+
* They are a pair in the same sense the steppers are: a DateTimePicker draws
|
|
56
|
+
* only the calendar, because a control cannot say two things at once and the
|
|
57
|
+
* date is the part you scan for. Drawn on the same 16×16 grid at the same
|
|
58
|
+
* weight, so a row of a DatePicker and a TimePicker does not look like two
|
|
59
|
+
* icon sets pushed together.
|
|
60
|
+
*/
|
|
61
|
+
export declare function CalendarIcon(): React.JSX.Element;
|
|
62
|
+
export declare function ClockIcon(): React.JSX.Element;
|
|
63
|
+
/**
|
|
64
|
+
* The arrow between the two ends of a range.
|
|
65
|
+
*
|
|
66
|
+
* Drawn pointing right and turned under RTL by the component, for the same
|
|
67
|
+
* reason the chevron is: it is a glyph, and there is no text in it to resample.
|
|
68
|
+
*/
|
|
69
|
+
export declare function ArrowRightIcon(): React.JSX.Element;
|
|
39
70
|
/** The filled dot: the chosen one of a set, where a tick would say "and". */
|
|
40
71
|
export declare function DotIcon(): React.JSX.Element;
|
|
41
72
|
/**
|