@hackcove/ui-react 0.0.0-stage → 0.8.1
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/LICENSE +21 -0
- package/MIGRATING.md +116 -0
- package/README.md +400 -2
- package/dist/AppShell.d.ts +97 -0
- package/dist/AppShell.js +106 -0
- package/dist/Avatar.d.ts +49 -0
- package/dist/Avatar.js +65 -0
- package/dist/AvatarStack.d.ts +29 -0
- package/dist/AvatarStack.js +26 -0
- package/dist/Badge.d.ts +14 -0
- package/dist/Badge.js +11 -0
- package/dist/Breadcrumbs.d.ts +28 -0
- package/dist/Breadcrumbs.js +30 -0
- package/dist/BulletList.d.ts +4 -0
- package/dist/BulletList.js +5 -0
- package/dist/Button.d.ts +78 -0
- package/dist/Button.js +133 -0
- package/dist/ButtonGroup.d.ts +15 -0
- package/dist/ButtonGroup.js +10 -0
- package/dist/Callout.d.ts +24 -0
- package/dist/Callout.js +28 -0
- package/dist/Card.d.ts +95 -0
- package/dist/Card.js +134 -0
- package/dist/CardBadge.d.ts +7 -0
- package/dist/CardBadge.js +12 -0
- package/dist/CardParts.d.ts +25 -0
- package/dist/CardParts.js +25 -0
- package/dist/Checkbox.d.ts +29 -0
- package/dist/Checkbox.js +36 -0
- package/dist/Chevron.d.ts +5 -0
- package/dist/Chevron.js +6 -0
- package/dist/Cluster.d.ts +51 -0
- package/dist/Cluster.js +38 -0
- package/dist/Code.d.ts +4 -0
- package/dist/Code.js +5 -0
- package/dist/CodeBlock.d.ts +27 -0
- package/dist/CodeBlock.js +12 -0
- package/dist/CodeExample.d.ts +17 -0
- package/dist/CodeExample.js +13 -0
- package/dist/CodeText.d.ts +7 -0
- package/dist/CodeText.js +21 -0
- package/dist/ColourSchemeToggle.d.ts +34 -0
- package/dist/ColourSchemeToggle.js +50 -0
- package/dist/Container.d.ts +22 -0
- package/dist/Container.js +13 -0
- package/dist/CopyButton.d.ts +17 -0
- package/dist/CopyButton.js +13 -0
- package/dist/CopyLine.d.ts +9 -0
- package/dist/CopyLine.js +7 -0
- package/dist/DateCalendar.d.ts +10 -0
- package/dist/DateCalendar.js +45 -0
- package/dist/DateField.d.ts +87 -0
- package/dist/DateField.js +100 -0
- package/dist/DateFieldCalendar.d.ts +6 -0
- package/dist/DateFieldCalendar.js +35 -0
- package/dist/Dialog.d.ts +26 -0
- package/dist/Dialog.js +18 -0
- package/dist/Disclosure.d.ts +15 -0
- package/dist/Disclosure.js +12 -0
- package/dist/Divider.d.ts +4 -0
- package/dist/Divider.js +5 -0
- package/dist/Drawer.d.ts +29 -0
- package/dist/Drawer.js +22 -0
- package/dist/EmptyState.d.ts +18 -0
- package/dist/EmptyState.js +14 -0
- package/dist/Field.d.ts +21 -0
- package/dist/Field.js +19 -0
- package/dist/FieldDialog.d.ts +28 -0
- package/dist/FieldDialog.js +34 -0
- package/dist/FileDrop.d.ts +17 -0
- package/dist/FileDrop.js +12 -0
- package/dist/FilterGroup.d.ts +7 -0
- package/dist/FilterGroup.js +6 -0
- package/dist/FormRow.d.ts +42 -0
- package/dist/FormRow.js +33 -0
- package/dist/Icon.d.ts +20 -0
- package/dist/Icon.js +13 -0
- package/dist/IconButton.d.ts +57 -0
- package/dist/IconButton.js +51 -0
- package/dist/Input.d.ts +22 -0
- package/dist/Input.js +22 -0
- package/dist/InputShell.d.ts +16 -0
- package/dist/InputShell.js +26 -0
- package/dist/Kbd.d.ts +6 -0
- package/dist/Kbd.js +5 -0
- package/dist/KeyValueList.d.ts +23 -0
- package/dist/KeyValueList.js +19 -0
- package/dist/Lightbox.d.ts +28 -0
- package/dist/Lightbox.js +44 -0
- package/dist/ListRow.d.ts +109 -0
- package/dist/ListRow.js +92 -0
- package/dist/Markdown.d.ts +9 -0
- package/dist/Markdown.js +43 -0
- package/dist/MetaList.d.ts +23 -0
- package/dist/MetaList.js +14 -0
- package/dist/OutlineRegion.d.ts +43 -0
- package/dist/OutlineRegion.js +27 -0
- package/dist/PageFade.d.ts +26 -0
- package/dist/PageFade.js +39 -0
- package/dist/PageHeader.d.ts +24 -0
- package/dist/PageHeader.js +14 -0
- package/dist/PageLayouts.d.ts +130 -0
- package/dist/PageLayouts.js +86 -0
- package/dist/Pill.d.ts +53 -0
- package/dist/Pill.js +34 -0
- package/dist/ProgressBar.d.ts +32 -0
- package/dist/ProgressBar.js +32 -0
- package/dist/RadioGroup.d.ts +48 -0
- package/dist/RadioGroup.js +39 -0
- package/dist/SearchInput.d.ts +8 -0
- package/dist/SearchInput.js +40 -0
- package/dist/SegmentedControl.d.ts +20 -0
- package/dist/SegmentedControl.js +31 -0
- package/dist/Select.d.ts +5 -0
- package/dist/Select.js +9 -0
- package/dist/SplitBar.d.ts +27 -0
- package/dist/SplitBar.js +15 -0
- package/dist/Stack.d.ts +70 -0
- package/dist/Stack.js +47 -0
- package/dist/StackedBar.d.ts +56 -0
- package/dist/StackedBar.js +35 -0
- package/dist/StatTile.d.ts +21 -0
- package/dist/StatTile.js +22 -0
- package/dist/StatusPages.d.ts +38 -0
- package/dist/StatusPages.js +57 -0
- package/dist/Steps.d.ts +17 -0
- package/dist/Steps.js +14 -0
- package/dist/StickyBar.d.ts +12 -0
- package/dist/StickyBar.js +10 -0
- package/dist/Table.d.ts +142 -0
- package/dist/Table.js +138 -0
- package/dist/Tabs.d.ts +40 -0
- package/dist/Tabs.js +49 -0
- package/dist/TextLink.d.ts +51 -0
- package/dist/TextLink.js +37 -0
- package/dist/Textarea.d.ts +12 -0
- package/dist/Textarea.js +8 -0
- package/dist/Timeline.d.ts +27 -0
- package/dist/Timeline.js +29 -0
- package/dist/Video.d.ts +13 -0
- package/dist/Video.js +9 -0
- package/dist/colourScheme.d.ts +21 -0
- package/dist/colourScheme.js +53 -0
- package/dist/control.d.ts +31 -0
- package/dist/control.js +38 -0
- package/dist/cx.d.ts +12 -0
- package/dist/cx.js +14 -0
- package/dist/highlight.d.ts +16 -0
- package/dist/highlight.js +292 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +66 -0
- package/dist/isoDate.d.ts +5 -0
- package/dist/isoDate.js +16 -0
- package/dist/lift.harness.d.ts +2 -0
- package/dist/lift.harness.js +3 -0
- package/dist/link.d.ts +50 -0
- package/dist/link.js +25 -0
- package/dist/modal.d.ts +11 -0
- package/dist/modal.js +41 -0
- package/dist/props.d.ts +14 -0
- package/dist/props.js +1 -0
- package/dist/shownDate.d.ts +45 -0
- package/dist/shownDate.js +88 -0
- package/dist/size.d.ts +6 -0
- package/dist/size.js +1 -0
- package/dist/switcher.d.ts +88 -0
- package/dist/switcher.js +71 -0
- package/dist/typography.d.ts +123 -0
- package/dist/typography.js +120 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.js +27 -0
- package/package.json +91 -4
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import type { Passthrough } from "./props.js";
|
|
3
|
+
import { type StackGap } from "./Stack.js";
|
|
4
|
+
/** The first three steps of `Stack`'s scale: `xs` between items in a line, `sm` inside a group, `md` between blocks. */
|
|
5
|
+
export type ClusterGap = Extract<StackGap, "xs" | "sm" | "md">;
|
|
6
|
+
export type ClusterAlign = "center" | "baseline" | "start" | "end";
|
|
7
|
+
export type ClusterJustify = "start" | "between" | "end";
|
|
8
|
+
/**
|
|
9
|
+
* A horizontal row of items a fixed `gap` apart (`xs` by default): the row counterpart of `Stack`. `align` is the
|
|
10
|
+
* cross axis (`center` default, `baseline` for mixed text sizes, `start`, `end`) and `justify` the
|
|
11
|
+
* main one (`start` default, `between` to push the first and last items to the two ends, `end`).
|
|
12
|
+
* `wrap` lets the items flow onto further lines on a narrow viewport (off by default, so a row
|
|
13
|
+
* stays on one line).
|
|
14
|
+
*
|
|
15
|
+
* Put one `ClusterGrow` around the item that takes the room left over, an input beside its
|
|
16
|
+
* buttons, say. An empty `ClusterGrow` is a spacer that pushes what follows it to the end.
|
|
17
|
+
* `ButtonGroup` is the row for buttons; use `Cluster` for any other row. `as="span"` is for a row
|
|
18
|
+
* inside phrasing content, such as a `PageHeader` subtitle (a `<p>`): its items must be phrasing
|
|
19
|
+
* content too, so no `ClusterGrow`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function Cluster({ as: Tag, gap, align, justify, wrap, children, ...rest }: {
|
|
22
|
+
/** The element. `span` for a row inside a `<p>` or other phrasing content; default `div`. */
|
|
23
|
+
as?: "div" | "span" | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* The space between items. Defaults to `xs`, not `md`, one of the library's two exceptions to the
|
|
26
|
+
* `md` default: the items of a row sit closer than the blocks of a column.
|
|
27
|
+
* @default xs
|
|
28
|
+
*/
|
|
29
|
+
gap?: ClusterGap | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* The cross axis: `center`, `baseline` (for mixed text sizes), `start` or `end`.
|
|
32
|
+
* @default center
|
|
33
|
+
*/
|
|
34
|
+
align?: ClusterAlign | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The main axis: `start`, `between` (the first and last items at the two ends) or `end`.
|
|
37
|
+
* @default start
|
|
38
|
+
*/
|
|
39
|
+
justify?: ClusterJustify | undefined;
|
|
40
|
+
/** Let the items flow onto further lines on a narrow viewport. Off, the row stays on one line. */
|
|
41
|
+
wrap?: boolean | undefined;
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
} & Passthrough): ReactElement;
|
|
44
|
+
/**
|
|
45
|
+
* The one child of a `Cluster` that grows to the room left in the row. It can shrink to nothing
|
|
46
|
+
* (`min-w-0`), so the items beside it stay on the line and a long value truncates instead of
|
|
47
|
+
* pushing them out. Empty, it is a spacer.
|
|
48
|
+
*/
|
|
49
|
+
export declare function ClusterGrow({ children, ...rest }: {
|
|
50
|
+
children?: ReactNode;
|
|
51
|
+
} & Passthrough): ReactElement;
|
package/dist/Cluster.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "./cx.js";
|
|
3
|
+
import { STACK_GAP } from "./Stack.js";
|
|
4
|
+
const ALIGN = {
|
|
5
|
+
center: "items-center",
|
|
6
|
+
baseline: "items-baseline",
|
|
7
|
+
start: "items-start",
|
|
8
|
+
end: "items-end",
|
|
9
|
+
};
|
|
10
|
+
const JUSTIFY = {
|
|
11
|
+
start: "justify-start",
|
|
12
|
+
between: "justify-between",
|
|
13
|
+
end: "justify-end",
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A horizontal row of items a fixed `gap` apart (`xs` by default): the row counterpart of `Stack`. `align` is the
|
|
17
|
+
* cross axis (`center` default, `baseline` for mixed text sizes, `start`, `end`) and `justify` the
|
|
18
|
+
* main one (`start` default, `between` to push the first and last items to the two ends, `end`).
|
|
19
|
+
* `wrap` lets the items flow onto further lines on a narrow viewport (off by default, so a row
|
|
20
|
+
* stays on one line).
|
|
21
|
+
*
|
|
22
|
+
* Put one `ClusterGrow` around the item that takes the room left over, an input beside its
|
|
23
|
+
* buttons, say. An empty `ClusterGrow` is a spacer that pushes what follows it to the end.
|
|
24
|
+
* `ButtonGroup` is the row for buttons; use `Cluster` for any other row. `as="span"` is for a row
|
|
25
|
+
* inside phrasing content, such as a `PageHeader` subtitle (a `<p>`): its items must be phrasing
|
|
26
|
+
* content too, so no `ClusterGrow`.
|
|
27
|
+
*/
|
|
28
|
+
export function Cluster({ as: Tag = "div", gap = "xs", align = "center", justify = "start", wrap = false, children, ...rest }) {
|
|
29
|
+
return (_jsx(Tag, { ...rest, className: cx("flex", STACK_GAP[gap], ALIGN[align], JUSTIFY[justify], wrap && "flex-wrap"), children: children }));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The one child of a `Cluster` that grows to the room left in the row. It can shrink to nothing
|
|
33
|
+
* (`min-w-0`), so the items beside it stay on the line and a long value truncates instead of
|
|
34
|
+
* pushing them out. Empty, it is a spacer.
|
|
35
|
+
*/
|
|
36
|
+
export function ClusterGrow({ children, ...rest }) {
|
|
37
|
+
return (_jsx("div", { ...rest, className: "min-w-0 flex-1", children: children }));
|
|
38
|
+
}
|
package/dist/Code.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactElement } from "react";
|
|
2
|
+
import type { Unstyled } from "./props.js";
|
|
3
|
+
/** Inline code: mono, on a subtle inset background. It takes the surrounding text colour and size (a touch smaller, for the mono face). */
|
|
4
|
+
export declare function Code(props: Unstyled<HTMLAttributes<HTMLElement>>): ReactElement;
|
package/dist/Code.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/** Inline code: mono, on a subtle inset background. It takes the surrounding text colour and size (a touch smaller, for the mono face). */
|
|
3
|
+
export function Code(props) {
|
|
4
|
+
return _jsx("code", { ...props, className: "rounded bg-slate-100 px-1 py-0.5 font-mono text-[0.9em]" });
|
|
5
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactElement } from "react";
|
|
2
|
+
import type { CodeLanguage } from "./highlight.js";
|
|
3
|
+
import type { Unstyled } from "./props.js";
|
|
4
|
+
/** Exactly one of `children` (a string, newlines kept) or `lines` (one array entry per line). */
|
|
5
|
+
type CodeBlockSource = {
|
|
6
|
+
children: string;
|
|
7
|
+
/** The code as one array entry per line, in place of `children`. */
|
|
8
|
+
lines?: never;
|
|
9
|
+
} | {
|
|
10
|
+
/** The code as one array entry per line, in place of `children`. */
|
|
11
|
+
lines: string[];
|
|
12
|
+
children?: never;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A static multi-line block of code: mono, in a bordered inset box, long lines wrap. No client JS;
|
|
16
|
+
* `language` colours it, and `label` names the language or file (`bash`, `css`) in a caption above
|
|
17
|
+
* the code. `text` (the default) leaves the code in one colour, for a block that is not a language.
|
|
18
|
+
* Give the text as `children` or as `lines`. Every other figure prop goes on the root `<figure>`.
|
|
19
|
+
* For one line a reader copies, use `CopyLine`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function CodeBlock({ label, language, children, lines, ...rest }: {
|
|
22
|
+
/** A caption above the code naming its language or file (`bash`, `theme.css`). */
|
|
23
|
+
label?: string;
|
|
24
|
+
/** What the code is written in; `text` (the default) colours nothing. */
|
|
25
|
+
language?: CodeLanguage;
|
|
26
|
+
} & CodeBlockSource & Unstyled<Omit<ComponentPropsWithoutRef<"figure">, "children">>): ReactElement;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CodeText } from "./CodeText.js";
|
|
3
|
+
/**
|
|
4
|
+
* A static multi-line block of code: mono, in a bordered inset box, long lines wrap. No client JS;
|
|
5
|
+
* `language` colours it, and `label` names the language or file (`bash`, `css`) in a caption above
|
|
6
|
+
* the code. `text` (the default) leaves the code in one colour, for a block that is not a language.
|
|
7
|
+
* Give the text as `children` or as `lines`. Every other figure prop goes on the root `<figure>`.
|
|
8
|
+
* For one line a reader copies, use `CopyLine`.
|
|
9
|
+
*/
|
|
10
|
+
export function CodeBlock({ label, language = "text", children, lines, ...rest }) {
|
|
11
|
+
return (_jsxs("figure", { ...rest, className: "overflow-hidden rounded-lg border border-slate-200 bg-slate-50 font-mono text-[12.5px] text-slate-900", children: [label && (_jsx("figcaption", { className: "border-b border-slate-200 px-3 py-1.5 text-xs text-slate-500", children: label })), _jsx("pre", { className: "whitespace-pre-wrap break-words px-3 py-2.5", children: _jsx(CodeText, { code: lines ? lines.join("\n") : children, language: language }) })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import type { Passthrough } from "./props.js";
|
|
3
|
+
/**
|
|
4
|
+
* One framed example: the rendered `children` on top and the `code` that makes them attached
|
|
5
|
+
* underneath, in a single bordered box with one divider between. No client JS. An optional `caption`
|
|
6
|
+
* is the frame's last band. The code is React, so it is coloured as TSX. The preview is its own
|
|
7
|
+
* height, never padded to match a neighbour, down to a shared minimum so two frames side by side
|
|
8
|
+
* start alike. A wide preview or a long line of code scrolls inside the frame instead of widening the
|
|
9
|
+
* page or wrapping.
|
|
10
|
+
*/
|
|
11
|
+
export declare function CodeExample({ code, caption, children, ...rest }: {
|
|
12
|
+
/** The source shown under the preview, newlines kept. */
|
|
13
|
+
code: string;
|
|
14
|
+
/** One note on the example, under the code. */
|
|
15
|
+
caption?: ReactNode;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
} & Passthrough): ReactElement;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CodeText } from "./CodeText.js";
|
|
3
|
+
/**
|
|
4
|
+
* One framed example: the rendered `children` on top and the `code` that makes them attached
|
|
5
|
+
* underneath, in a single bordered box with one divider between. No client JS. An optional `caption`
|
|
6
|
+
* is the frame's last band. The code is React, so it is coloured as TSX. The preview is its own
|
|
7
|
+
* height, never padded to match a neighbour, down to a shared minimum so two frames side by side
|
|
8
|
+
* start alike. A wide preview or a long line of code scrolls inside the frame instead of widening the
|
|
9
|
+
* page or wrapping.
|
|
10
|
+
*/
|
|
11
|
+
export function CodeExample({ code, caption, children, ...rest }) {
|
|
12
|
+
return (_jsxs("figure", { ...rest, className: "overflow-hidden rounded-lg border border-slate-200 bg-white", children: [_jsx("div", { className: "min-h-24 overflow-x-auto p-5", children: children }), _jsx("pre", { className: "overflow-x-auto border-t border-slate-200 bg-slate-50 px-3 py-2.5 font-mono text-[12.5px] whitespace-pre text-slate-900", children: _jsx(CodeText, { code: code, language: "tsx" }) }), caption && (_jsx("figcaption", { className: "border-t border-slate-200 px-3 py-2.5 text-sm/5 text-slate-500", children: caption }))] }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { type CodeLanguage } from "./highlight.js";
|
|
3
|
+
/** The `<code>` for a `<pre>`: the source in mono, one span per coloured run. */
|
|
4
|
+
export declare function CodeText({ code, language, }: {
|
|
5
|
+
code: string;
|
|
6
|
+
language: CodeLanguage;
|
|
7
|
+
}): ReactElement;
|
package/dist/CodeText.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { highlight } from "./highlight.js";
|
|
3
|
+
/**
|
|
4
|
+
* Each kind borrows a colour family already in `palette.json`, so a theme recolours code like
|
|
5
|
+
* anything else: keywords and element names read as the accent (violet), strings as positive
|
|
6
|
+
* (emerald), numbers as warn (amber), attribute names as sky, calls as info (blue), comments muted.
|
|
7
|
+
*/
|
|
8
|
+
const TOKEN_CLASS = {
|
|
9
|
+
plain: "",
|
|
10
|
+
comment: "text-slate-500 italic",
|
|
11
|
+
keyword: "text-violet-700",
|
|
12
|
+
tag: "text-red-700",
|
|
13
|
+
attr: "text-sky-700",
|
|
14
|
+
string: "text-emerald-700",
|
|
15
|
+
number: "text-amber-700",
|
|
16
|
+
function: "text-blue-700",
|
|
17
|
+
};
|
|
18
|
+
/** The `<code>` for a `<pre>`: the source in mono, one span per coloured run. */
|
|
19
|
+
export function CodeText({ code, language, }) {
|
|
20
|
+
return (_jsx("code", { children: highlight(code, language).map((token, index) => token.kind === "plain" ? (token.text) : (_jsx("span", { className: TOKEN_CLASS[token.kind], children: token.text }, index))) }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactElement } from "react";
|
|
2
|
+
import { type ColourScheme, type ColourSchemeClasses } from "./colourScheme.js";
|
|
3
|
+
import type { Unstyled } from "./props.js";
|
|
4
|
+
import type { Size } from "./size.js";
|
|
5
|
+
/**
|
|
6
|
+
* A sun/moon button that switches `<html>` between light and dark and remembers the choice. It shows the scheme you would switch to. Pair it with `colourSchemeScript` in `<head>`, unless you pass `schemes` or `initial`: the script knows only the `dark` class and the stored choice, so an app that sets the scheme itself leaves it out.
|
|
7
|
+
*
|
|
8
|
+
* An app whose light scheme has a class of its own passes `schemes` (`{ light: "my-light", dark: "dark" }`);
|
|
9
|
+
* the toggle swaps those classes, and `schemeClass` gives the same one for the server to render on `<html>`.
|
|
10
|
+
* An app that knows the scheme on the server (from a cookie) passes it as `initial`, so the server
|
|
11
|
+
* markup, the hydrating client and the `<html>` class agree; persist a change from `onChange`.
|
|
12
|
+
* The icon follows the class on `<html>` through CSS, so even without `initial` a dark page shows
|
|
13
|
+
* the sun from the first frame; the button's name catches up once the client has hydrated.
|
|
14
|
+
* `store={false}` skips `localStorage`, for an app that keeps the choice in a server cookie and
|
|
15
|
+
* writes it from `onChange`. Every other button prop (`id`, `data-*`, `aria-*`) goes on the button.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ColourSchemeToggle({ onChange, schemes, initial, store, size, ...rest }: {
|
|
18
|
+
/**
|
|
19
|
+
* The button's height, as an `IconButton`'s.
|
|
20
|
+
* @default md
|
|
21
|
+
*/
|
|
22
|
+
size?: Size | undefined;
|
|
23
|
+
/** Called with the new scheme after a click, for an app that persists the choice itself (a cookie). */
|
|
24
|
+
onChange?: (scheme: ColourScheme) => void;
|
|
25
|
+
/** The class each scheme puts on `<html>`. */
|
|
26
|
+
schemes?: ColourSchemeClasses | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The scheme the server rendered. What the server and the hydrating client show; the real state follows right after.
|
|
29
|
+
* @default light
|
|
30
|
+
*/
|
|
31
|
+
initial?: ColourScheme | undefined;
|
|
32
|
+
/** Remember the choice in `localStorage`. `false` leaves persisting to `onChange`. */
|
|
33
|
+
store?: boolean | undefined;
|
|
34
|
+
} & Unstyled<Omit<ComponentPropsWithoutRef<"button">, "onChange" | "onClick" | "children" | "aria-label" | "title">>): ReactElement;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { appliedColourScheme, applyColourScheme, storeColourScheme, } from "./colourScheme.js";
|
|
4
|
+
import { IconButton } from "./IconButton.js";
|
|
5
|
+
const sun = (_jsxs("svg", { "data-scheme-icon": "sun", viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "4" }), _jsx("path", { d: "M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" })] }));
|
|
6
|
+
const moon = (_jsx("svg", { "data-scheme-icon": "moon", viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z" }) }));
|
|
7
|
+
// Both icons are always drawn and the page's own class picks one, so the first frame is right before
|
|
8
|
+
// React runs: a dark visitor with no cookie has the dark class on <html> from the head script, but the
|
|
9
|
+
// server rendered "light". The icon shows the scheme you would switch to: the moon on a light page,
|
|
10
|
+
// the sun on a dark one. The classes are the app's (`schemes`), so the rule is written here: a dark
|
|
11
|
+
// page has the dark class, or, when dark has none, lacks the light one.
|
|
12
|
+
function iconRules(schemes) {
|
|
13
|
+
const sunIcon = '[data-scheme-icon="sun"]';
|
|
14
|
+
const moonIcon = '[data-scheme-icon="moon"]';
|
|
15
|
+
let dark = "";
|
|
16
|
+
if (schemes.dark !== "")
|
|
17
|
+
dark = `:root[class~=${JSON.stringify(schemes.dark)}]`;
|
|
18
|
+
else if (schemes.light !== "")
|
|
19
|
+
dark = `:root:not([class~=${JSON.stringify(schemes.light)}])`;
|
|
20
|
+
return (`${sunIcon}{display:none}` +
|
|
21
|
+
(dark === "" ? "" : `${dark} ${sunIcon}{display:inline}${dark} ${moonIcon}{display:none}`));
|
|
22
|
+
}
|
|
23
|
+
// The scheme's class on <html> is the source of truth: the head script or the server set it before React ran.
|
|
24
|
+
function subscribe(onChange) {
|
|
25
|
+
const observer = new MutationObserver(onChange);
|
|
26
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
|
|
27
|
+
return () => observer.disconnect();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A sun/moon button that switches `<html>` between light and dark and remembers the choice. It shows the scheme you would switch to. Pair it with `colourSchemeScript` in `<head>`, unless you pass `schemes` or `initial`: the script knows only the `dark` class and the stored choice, so an app that sets the scheme itself leaves it out.
|
|
31
|
+
*
|
|
32
|
+
* An app whose light scheme has a class of its own passes `schemes` (`{ light: "my-light", dark: "dark" }`);
|
|
33
|
+
* the toggle swaps those classes, and `schemeClass` gives the same one for the server to render on `<html>`.
|
|
34
|
+
* An app that knows the scheme on the server (from a cookie) passes it as `initial`, so the server
|
|
35
|
+
* markup, the hydrating client and the `<html>` class agree; persist a change from `onChange`.
|
|
36
|
+
* The icon follows the class on `<html>` through CSS, so even without `initial` a dark page shows
|
|
37
|
+
* the sun from the first frame; the button's name catches up once the client has hydrated.
|
|
38
|
+
* `store={false}` skips `localStorage`, for an app that keeps the choice in a server cookie and
|
|
39
|
+
* writes it from `onChange`. Every other button prop (`id`, `data-*`, `aria-*`) goes on the button.
|
|
40
|
+
*/
|
|
41
|
+
export function ColourSchemeToggle({ onChange, schemes = { light: "", dark: "dark" }, initial, store = true, size = "md", ...rest }) {
|
|
42
|
+
const scheme = useSyncExternalStore(subscribe, () => appliedColourScheme(document.documentElement, schemes), () => initial ?? "light");
|
|
43
|
+
const next = scheme === "dark" ? "light" : "dark";
|
|
44
|
+
return (_jsxs(IconButton, { ...rest, size: size, label: `Switch to ${next} theme`, onClick: () => {
|
|
45
|
+
applyColourScheme(next, document.documentElement, schemes);
|
|
46
|
+
if (store)
|
|
47
|
+
storeColourScheme(next);
|
|
48
|
+
onChange?.(next);
|
|
49
|
+
}, children: [_jsx("style", { children: iconRules(schemes) }), sun, moon] }));
|
|
50
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactElement, ReactNode } from "react";
|
|
2
|
+
import type { Unstyled } from "./props.js";
|
|
3
|
+
/**
|
|
4
|
+
* The one content edge: every page's width and side padding. This file is the only place they are
|
|
5
|
+
* defined, so a header, a page and a footer inside a Container start at the same x.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Container({ as, elementRef, children, ...rest }: ContainerProps): ReactElement;
|
|
8
|
+
type ContainerProps = {
|
|
9
|
+
/**
|
|
10
|
+
* The element: `div`, `main`, `header`, `footer`, `section` or `nav`.
|
|
11
|
+
* @default div
|
|
12
|
+
*/
|
|
13
|
+
as?: "div" | "main" | "header" | "footer" | "section" | "nav";
|
|
14
|
+
/** The rendered element, for a parent that measures or scrolls it. */
|
|
15
|
+
elementRef?: ((element: HTMLElement | null) => void) | undefined;
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
} & Unstyled<Omit<HTMLAttributes<HTMLElement>, "children">>;
|
|
18
|
+
/** Container with the extra classes its own parts need (AppShell's padding): internal, not exported. */
|
|
19
|
+
export declare function ContainerFrame({ as: Tag, className, elementRef, children, ...rest }: ContainerProps & {
|
|
20
|
+
className?: string;
|
|
21
|
+
}): ReactElement;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "./cx.js";
|
|
3
|
+
/**
|
|
4
|
+
* The one content edge: every page's width and side padding. This file is the only place they are
|
|
5
|
+
* defined, so a header, a page and a footer inside a Container start at the same x.
|
|
6
|
+
*/
|
|
7
|
+
export function Container({ as, elementRef, children, ...rest }) {
|
|
8
|
+
return (_jsx(ContainerFrame, { ...rest, ...(as && { as }), elementRef: elementRef, children: children }));
|
|
9
|
+
}
|
|
10
|
+
/** Container with the extra classes its own parts need (AppShell's padding): internal, not exported. */
|
|
11
|
+
export function ContainerFrame({ as: Tag = "div", className, elementRef, children, ...rest }) {
|
|
12
|
+
return (_jsx(Tag, { ...rest, ref: elementRef, className: cx("mx-auto w-full max-w-6xl px-4 sm:px-6", className), children: children }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef, type ReactElement } from "react";
|
|
2
|
+
import type { Unstyled } from "./props.js";
|
|
3
|
+
/** Writes `text` to the clipboard and swaps the label to `copiedLabel`. Defaults to `type="button"`. A refused or missing clipboard leaves the label on `label`. Every other button prop, `disabled` included, goes on the `<button>`. */
|
|
4
|
+
export declare function CopyButton({ text, label, copiedLabel, onClick, ...rest }: {
|
|
5
|
+
/** What goes on the clipboard. */
|
|
6
|
+
text: string;
|
|
7
|
+
/**
|
|
8
|
+
* The button's text before a copy.
|
|
9
|
+
* @default copy
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The button's text once the copy has gone through.
|
|
14
|
+
* @default copied
|
|
15
|
+
*/
|
|
16
|
+
copiedLabel?: string;
|
|
17
|
+
} & Unstyled<Omit<ComponentPropsWithoutRef<"button">, "children">>): ReactElement;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { focusRing } from "./cx.js";
|
|
4
|
+
const BASE = `shrink-0 rounded px-1.5 py-0.5 font-sans text-xs text-slate-400 hover:bg-slate-100 disabled:pointer-events-none disabled:opacity-50 ${focusRing}`;
|
|
5
|
+
/** Writes `text` to the clipboard and swaps the label to `copiedLabel`. Defaults to `type="button"`. A refused or missing clipboard leaves the label on `label`. Every other button prop, `disabled` included, goes on the `<button>`. */
|
|
6
|
+
export function CopyButton({ text, label = "copy", copiedLabel = "copied", onClick, ...rest }) {
|
|
7
|
+
const [copied, setCopied] = useState(false);
|
|
8
|
+
return (_jsx("button", { type: "button", ...rest, className: BASE, onClick: (event) => {
|
|
9
|
+
onClick?.(event);
|
|
10
|
+
// The rejection is swallowed on purpose: a denied write is not an error the page can act on.
|
|
11
|
+
navigator.clipboard?.writeText(text).then(() => setCopied(true), () => { });
|
|
12
|
+
}, children: copied ? copiedLabel : label }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactElement } from "react";
|
|
2
|
+
import type { Unstyled } from "./props.js";
|
|
3
|
+
/** One line of mono text in a box, with a `CopyButton`: a command or a token to paste elsewhere. `disabled` disables the button, e.g. until hydration. Every other div prop goes on the root `<div>`, so `data-testid` lands there; the `<code>` holds only `text`. */
|
|
4
|
+
export declare function CopyLine({ text, disabled, ...rest }: {
|
|
5
|
+
/** The line shown, and what the button copies. */
|
|
6
|
+
text: string;
|
|
7
|
+
/** Disables the copy button, e.g. until hydration. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
} & Unstyled<Omit<ComponentPropsWithoutRef<"div">, "children">>): ReactElement;
|
package/dist/CopyLine.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CopyButton } from "./CopyButton.js";
|
|
3
|
+
const BOX = "flex items-center justify-between gap-3 rounded-lg border border-slate-200 bg-white px-2.5 py-2 font-mono text-[12.5px] text-slate-900";
|
|
4
|
+
/** One line of mono text in a box, with a `CopyButton`: a command or a token to paste elsewhere. `disabled` disables the button, e.g. until hydration. Every other div prop goes on the root `<div>`, so `data-testid` lands there; the `<code>` holds only `text`. */
|
|
5
|
+
export function CopyLine({ text, disabled, ...rest }) {
|
|
6
|
+
return (_jsxs("div", { ...rest, className: BOX, children: [_jsx("code", { className: "min-w-0 break-words", children: text }), _jsx(CopyButton, { text: text, disabled: disabled })] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
export declare const calendarIcon: import("react").JSX.Element;
|
|
3
|
+
/**
|
|
4
|
+
* The picker's popover: header, a Monday-first month grid and a Clear footer. `container` is the
|
|
5
|
+
* modal `<dialog>` the picker sits in, if any: a modal makes everything outside it inert and paints
|
|
6
|
+
* above the body, so the popover renders inside it (which also keeps the theme's scope class).
|
|
7
|
+
*/
|
|
8
|
+
export declare function CalendarPopover({ container }: {
|
|
9
|
+
container: Element | undefined;
|
|
10
|
+
}): ReactElement;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { getLocalTimeZone, today } from "@internationalized/date";
|
|
3
|
+
import { useContext } from "react";
|
|
4
|
+
import { Button, Calendar, CalendarCell, CalendarGrid, CalendarGridBody, CalendarGridHeader, CalendarHeaderCell, CalendarStateContext, DatePickerStateContext, Dialog, Popover, } from "react-aria-components";
|
|
5
|
+
import { cx, focusRing } from "./cx.js";
|
|
6
|
+
import { MONTH_OPTIONS, iconButtonClass } from "./DateField.js";
|
|
7
|
+
import { Icon } from "./Icon.js";
|
|
8
|
+
export const calendarIcon = (_jsx(Icon, { children: _jsxs("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", children: [_jsx("rect", { x: "3", y: "4.5", width: "14", height: "12.5", rx: "2" }), _jsx("path", { d: "M3 8.5h14M7 2.5v4M13 2.5v4" })] }) }));
|
|
9
|
+
const chevron = (d) => (_jsx(Icon, { children: _jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: d }) }) }));
|
|
10
|
+
const selectClass = `rounded-md border border-slate-300 bg-white py-1 pr-1 pl-2 text-sm text-slate-900 transition hover:border-violet-400 ${focusRing}`;
|
|
11
|
+
/** ‹, a month dropdown, a year dropdown and ›: a birth date decades back is two picks away. */
|
|
12
|
+
function CalendarHeader() {
|
|
13
|
+
const state = useContext(CalendarStateContext);
|
|
14
|
+
if (!state)
|
|
15
|
+
return null;
|
|
16
|
+
const focused = state.focusedDate;
|
|
17
|
+
const now = today(getLocalTimeZone()).year;
|
|
18
|
+
const first = Math.min(state.minValue?.year ?? now - 100, focused.year);
|
|
19
|
+
const last = Math.max(state.maxValue?.year ?? now + 10, focused.year);
|
|
20
|
+
const years = Array.from({ length: last - first + 1 }, (_, i) => first + i);
|
|
21
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Button, { slot: "previous", className: iconButtonClass, children: chevron("M12.5 15l-5-5 5-5") }), _jsx("select", { "aria-label": "Month", className: cx(selectClass, "flex-1"), value: focused.month, disabled: state.isDisabled, onChange: (event) => state.setFocusedDate(focused.set({ month: Number(event.target.value) })), children: MONTH_OPTIONS.map(({ month, name }) => (_jsx("option", { value: month, children: name }, month))) }), _jsx("select", { "aria-label": "Year", className: selectClass, value: focused.year, disabled: state.isDisabled, onChange: (event) => state.setFocusedDate(focused.set({ year: Number(event.target.value) })), children: years.map((year) => (_jsx("option", { value: year, children: year }, year))) }), _jsx(Button, { slot: "next", className: iconButtonClass, children: chevron("M7.5 5l5 5-5 5") })] }));
|
|
22
|
+
}
|
|
23
|
+
function ClearButton() {
|
|
24
|
+
const picker = useContext(DatePickerStateContext);
|
|
25
|
+
return (_jsx("button", { type: "button", className: `rounded-md px-2 py-1 text-sm font-medium text-violet-600 transition hover:bg-violet-50 ${focusRing}`, onClick: () => {
|
|
26
|
+
picker?.setValue(null);
|
|
27
|
+
picker?.close();
|
|
28
|
+
}, children: "Clear" }));
|
|
29
|
+
}
|
|
30
|
+
const cellClass = ({ isSelected, isOutsideMonth, isDisabled, isUnavailable, isInvalid, }) => {
|
|
31
|
+
let tone = "cursor-pointer text-slate-700 hover:bg-slate-100";
|
|
32
|
+
if (isSelected)
|
|
33
|
+
tone = isInvalid ? "bg-red-50 text-red-700" : "bg-violet-600 text-violet-50";
|
|
34
|
+
else if (isOutsideMonth || isDisabled || isUnavailable)
|
|
35
|
+
tone = "text-slate-300";
|
|
36
|
+
return cx("flex h-9 w-9 items-center justify-center rounded-lg text-sm tabular-nums", tone, focusRing);
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The picker's popover: header, a Monday-first month grid and a Clear footer. `container` is the
|
|
40
|
+
* modal `<dialog>` the picker sits in, if any: a modal makes everything outside it inert and paints
|
|
41
|
+
* above the body, so the popover renders inside it (which also keeps the theme's scope class).
|
|
42
|
+
*/
|
|
43
|
+
export function CalendarPopover({ container }) {
|
|
44
|
+
return (_jsx(Popover, { ...(container ? { UNSTABLE_portalContainer: container } : {}), placement: "bottom start", className: "rounded-xl border border-slate-200 bg-white p-3 text-slate-900 shadow-lg", children: _jsxs(Dialog, { className: "flex flex-col gap-3 outline-none", children: [_jsxs(Calendar, { firstDayOfWeek: "mon", className: "flex flex-col gap-3", children: [_jsx(CalendarHeader, {}), _jsxs(CalendarGrid, { weekdayStyle: "short", children: [_jsx(CalendarGridHeader, { children: (day) => (_jsx(CalendarHeaderCell, { className: "pb-1 text-xs font-medium text-slate-500", children: day })) }), _jsx(CalendarGridBody, { children: (date) => _jsx(CalendarCell, { date: date, className: cellClass }) })] })] }), _jsx("div", { className: "flex justify-end border-t border-slate-200 pt-2", children: _jsx(ClearButton, {}) })] }) }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type CalendarDate } from "@internationalized/date";
|
|
2
|
+
import { type ContextType, type ReactElement, type ReactNode } from "react";
|
|
3
|
+
import { type DateFieldProps as AriaDateFieldProps, DateFieldStateContext } from "react-aria-components";
|
|
4
|
+
import type { DataAttributes } from "./link.js";
|
|
5
|
+
import type { Size } from "./size.js";
|
|
6
|
+
/** Fixed, whatever the browser's locale: DD/MM/YYYY and Monday-first weeks. */
|
|
7
|
+
export declare const LOCALE = "en-GB";
|
|
8
|
+
export declare const MONTH_OPTIONS: {
|
|
9
|
+
month: number;
|
|
10
|
+
name: string;
|
|
11
|
+
}[];
|
|
12
|
+
type Segment = NonNullable<ContextType<typeof DateFieldStateContext>>["segments"][number];
|
|
13
|
+
/** The props of a plain `DateField`, without the calendar. */
|
|
14
|
+
export type FieldProps = {
|
|
15
|
+
/** The field's visible label, above it. Without one, name the field with `aria-label`. */
|
|
16
|
+
label?: ReactNode;
|
|
17
|
+
/** A hint under the field; an error replaces it. */
|
|
18
|
+
description?: ReactNode;
|
|
19
|
+
/** Replaces the built-in error message (an impossible date, or one outside min/max). */
|
|
20
|
+
errorMessage?: ReactNode;
|
|
21
|
+
/** An error from outside the field (a server's, say). Shown in place of the description, in red with `role="alert"`, and marks the field invalid. Like `Field`'s `error`. */
|
|
22
|
+
error?: ReactNode;
|
|
23
|
+
/** Marks the field invalid with no message of its own; pair it with `errorMessage`. */
|
|
24
|
+
isInvalid?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The field's height and text, on the same scale as an `Input`: `sm` is `text-xs`, `lg` is
|
|
27
|
+
* `text-base`.
|
|
28
|
+
* @default md
|
|
29
|
+
*/
|
|
30
|
+
size?: Size;
|
|
31
|
+
} & DataAttributes & Pick<AriaDateFieldProps<CalendarDate>, "value" | "defaultValue" | "onChange" | "minValue" | "maxValue" | "isDisabled" | "isRequired" | "name" | "aria-label" | "aria-labelledby" | "aria-describedby" | "aria-details">;
|
|
32
|
+
export type DateFieldProps = FieldProps & ({
|
|
33
|
+
/** Adds a calendar button that opens a month view in a popover; the field is a date picker. */
|
|
34
|
+
calendar?: false | undefined;
|
|
35
|
+
/** Only a `calendar` field takes `defaultOpen`. */
|
|
36
|
+
defaultOpen?: undefined;
|
|
37
|
+
} | {
|
|
38
|
+
calendar: true;
|
|
39
|
+
/** Open the calendar on mount. */
|
|
40
|
+
defaultOpen?: boolean | undefined;
|
|
41
|
+
});
|
|
42
|
+
/** What the segments show, as the day segment reports it to the field. */
|
|
43
|
+
export type Read = {
|
|
44
|
+
/** The date as `YYYY-MM-DD` once every segment is filled and the day exists, else `""`. */
|
|
45
|
+
typed: string;
|
|
46
|
+
/** "February 1990 has 28 days." when the day does not exist. */
|
|
47
|
+
impossible: string | null;
|
|
48
|
+
/** Some segments are filled and some are not. */
|
|
49
|
+
partial: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** One segment. The day segment also reports what the segments show to the field. */
|
|
52
|
+
export declare function FieldSegment({ segment, onRead, }: {
|
|
53
|
+
segment: Segment;
|
|
54
|
+
onRead?: (read: Read) => void;
|
|
55
|
+
}): ReactElement;
|
|
56
|
+
export declare function frameClass({ isInvalid, isFocusWithin, isDisabled, }: {
|
|
57
|
+
isInvalid: boolean;
|
|
58
|
+
isFocusWithin: boolean;
|
|
59
|
+
isDisabled: boolean;
|
|
60
|
+
}): string;
|
|
61
|
+
/** The props that force a field invalid: an impossible date, `isInvalid`, or an `error` from outside. Spread onto the React Aria field after the rest. */
|
|
62
|
+
export declare function forcedInvalid({ impossible, isInvalid, error, }: {
|
|
63
|
+
impossible: string | null;
|
|
64
|
+
isInvalid: boolean | undefined;
|
|
65
|
+
error: ReactNode;
|
|
66
|
+
}): {
|
|
67
|
+
isInvalid?: true;
|
|
68
|
+
};
|
|
69
|
+
/** The label, the description or the error line: the shared outside of both components. */
|
|
70
|
+
export declare function Notes({ description, errorMessage, error, impossible, isInvalid, }: {
|
|
71
|
+
description: ReactNode;
|
|
72
|
+
errorMessage: ReactNode;
|
|
73
|
+
error: ReactNode;
|
|
74
|
+
impossible: string | null;
|
|
75
|
+
isInvalid: boolean;
|
|
76
|
+
}): ReactElement;
|
|
77
|
+
export declare const labelClass = "text-sm font-medium text-slate-700";
|
|
78
|
+
/** A small icon button inside a date field or calendar, without its box size. */
|
|
79
|
+
export declare const iconButtonLook = "inline-flex shrink-0 items-center justify-center rounded-md text-slate-500 transition hover:bg-slate-100 disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-600";
|
|
80
|
+
export declare const iconButtonClass = "inline-flex shrink-0 items-center justify-center rounded-md text-slate-500 transition hover:bg-slate-100 disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-600 h-7 w-7";
|
|
81
|
+
/**
|
|
82
|
+
* A segmented DD / MM / YYYY date input. Values are `CalendarDate`s; `name` posts it as
|
|
83
|
+
* `YYYY-MM-DD`. `calendar` adds a calendar button that opens a month view in a popover, at the
|
|
84
|
+
* same height as the plain field; `defaultOpen` opens it on mount.
|
|
85
|
+
*/
|
|
86
|
+
export declare function DateField({ calendar, defaultOpen, ...field }: DateFieldProps): ReactElement;
|
|
87
|
+
export {};
|