@spfx-fast/sharepoint-ui 0.4.3 → 0.5.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/QUICKSTART.md +13 -128
- package/README.md +19 -26
- package/components.json +240 -5834
- package/dist/accordion.d.ts +11 -0
- package/dist/accordion.js +4 -0
- package/dist/alert.d.ts +3 -0
- package/dist/alert.js +4 -0
- package/dist/attachment-list.d.ts +15 -0
- package/dist/attachment-list.js +14 -0
- package/dist/avatar-group.d.ts +12 -0
- package/dist/avatar-group.js +7 -0
- package/dist/avatar.d.ts +6 -0
- package/dist/avatar.js +5 -0
- package/dist/badge.d.ts +3 -0
- package/dist/badge.js +4 -0
- package/dist/breadcrumb.d.ts +10 -0
- package/dist/breadcrumb.js +9 -0
- package/dist/button-group.d.ts +6 -0
- package/dist/button-group.js +4 -0
- package/dist/button.d.ts +3 -0
- package/dist/button.js +4 -0
- package/dist/card.d.ts +3 -0
- package/dist/card.js +4 -0
- package/dist/carousel.d.ts +11 -0
- package/dist/carousel.js +6 -0
- package/dist/checkbox.d.ts +3 -0
- package/dist/checkbox.js +4 -0
- package/dist/combobox.d.ts +9 -0
- package/dist/combobox.js +6 -0
- package/dist/command-bar.d.ts +6 -0
- package/dist/command-bar.js +4 -0
- package/dist/copy-button.d.ts +7 -0
- package/dist/copy-button.js +19 -0
- package/dist/data-grid.d.ts +25 -0
- package/dist/data-grid.js +39 -0
- package/dist/date-range-picker.d.ts +12 -0
- package/dist/date-range-picker.js +4 -0
- package/dist/dialog.d.ts +9 -0
- package/dist/dialog.js +21 -0
- package/dist/divider.d.ts +3 -0
- package/dist/divider.js +4 -0
- package/dist/drawer.d.ts +6 -0
- package/dist/drawer.js +5 -0
- package/dist/empty-state.d.ts +7 -0
- package/dist/empty-state.js +5 -0
- package/dist/field.d.ts +15 -0
- package/dist/field.js +11 -0
- package/dist/file-dropzone.d.ts +15 -0
- package/dist/file-dropzone.js +21 -0
- package/dist/filter-bar.d.ts +9 -0
- package/dist/filter-bar.js +9 -0
- package/dist/image.d.ts +5 -0
- package/dist/image.js +4 -0
- package/dist/index.d.ts +68 -78
- package/dist/index.js +60 -68
- package/dist/input.d.ts +3 -0
- package/dist/input.js +4 -0
- package/dist/label.d.ts +3 -0
- package/dist/label.js +4 -0
- package/dist/link.d.ts +3 -0
- package/dist/link.js +9 -0
- package/dist/list-view.d.ts +29 -0
- package/dist/list-view.js +14 -0
- package/dist/list.d.ts +6 -0
- package/dist/list.js +5 -0
- package/dist/lookup-picker.d.ts +12 -0
- package/dist/lookup-picker.js +4 -0
- package/dist/menu.d.ts +6 -0
- package/dist/menu.js +4 -0
- package/dist/nav.d.ts +12 -0
- package/dist/nav.js +4 -0
- package/dist/pagination.d.ts +11 -0
- package/dist/pagination.js +5 -0
- package/dist/person-picker.d.ts +13 -0
- package/dist/person-picker.js +4 -0
- package/dist/persona.d.ts +7 -0
- package/dist/persona.js +5 -0
- package/dist/popover.d.ts +6 -0
- package/dist/popover.js +4 -0
- package/dist/progress-bar.d.ts +5 -0
- package/dist/progress-bar.js +5 -0
- package/dist/radio-group.d.ts +6 -0
- package/dist/radio-group.js +4 -0
- package/dist/radio.d.ts +3 -0
- package/dist/radio.js +4 -0
- package/dist/rating.d.ts +8 -0
- package/dist/rating.js +5 -0
- package/dist/react.d.ts +1 -4715
- package/dist/react.js +1 -7097
- package/dist/select.d.ts +3 -0
- package/dist/select.js +4 -0
- package/dist/sharepoint-field.d.ts +18 -0
- package/dist/sharepoint-field.js +54 -0
- package/dist/skeleton.d.ts +6 -0
- package/dist/skeleton.js +9 -0
- package/dist/spinner.d.ts +5 -0
- package/dist/spinner.js +4 -0
- package/dist/swatch-picker.d.ts +17 -0
- package/dist/swatch-picker.js +11 -0
- package/dist/switch.d.ts +3 -0
- package/dist/switch.js +4 -0
- package/dist/table.d.ts +6 -0
- package/dist/table.js +4 -0
- package/dist/tabs.d.ts +14 -0
- package/dist/tabs.js +30 -0
- package/dist/tag-group.d.ts +6 -0
- package/dist/tag-group.js +4 -0
- package/dist/tag-picker.d.ts +12 -0
- package/dist/tag-picker.js +4 -0
- package/dist/tag.d.ts +7 -0
- package/dist/tag.js +5 -0
- package/dist/text.d.ts +5 -0
- package/dist/text.js +4 -0
- package/dist/textarea.d.ts +3 -0
- package/dist/textarea.js +4 -0
- package/dist/theme.d.ts +15 -175
- package/dist/theme.js +36 -239
- package/dist/toast.d.ts +9 -0
- package/dist/toast.js +12 -0
- package/dist/tree.d.ts +13 -0
- package/dist/tree.js +9 -0
- package/dist/view-card.d.ts +8 -0
- package/dist/view-card.js +4 -0
- package/dist/view-switcher.d.ts +13 -0
- package/dist/view-switcher.js +7 -0
- package/dist/virtual-list.d.ts +11 -0
- package/dist/virtual-list.js +25 -0
- package/measurements.json +365 -0
- package/package.json +14 -46
- package/src/theme.css +125 -0
- package/AGENTS.md +0 -231
- package/dist/appearance.d.ts +0 -6
- package/dist/appearance.js +0 -217
- package/dist/elements/accordion.d.ts +0 -9
- package/dist/elements/accordion.js +0 -338
- package/dist/elements/alert.d.ts +0 -2
- package/dist/elements/alert.js +0 -86
- package/dist/elements/avatar-group-primitives.d.ts +0 -3
- package/dist/elements/avatar-group-primitives.js +0 -189
- package/dist/elements/avatar-group.d.ts +0 -2
- package/dist/elements/avatar-group.js +0 -110
- package/dist/elements/avatar.d.ts +0 -4
- package/dist/elements/avatar.js +0 -251
- package/dist/elements/badge.d.ts +0 -8
- package/dist/elements/badge.js +0 -182
- package/dist/elements/breadcrumb.d.ts +0 -4
- package/dist/elements/breadcrumb.js +0 -233
- package/dist/elements/button-group.d.ts +0 -1
- package/dist/elements/button-group.js +0 -20
- package/dist/elements/button-variants.d.ts +0 -6
- package/dist/elements/button-variants.js +0 -339
- package/dist/elements/button.d.ts +0 -5
- package/dist/elements/button.js +0 -233
- package/dist/elements/card-primitives.d.ts +0 -3
- package/dist/elements/card-primitives.js +0 -83
- package/dist/elements/card.d.ts +0 -5
- package/dist/elements/card.js +0 -213
- package/dist/elements/carousel.d.ts +0 -92
- package/dist/elements/carousel.js +0 -1115
- package/dist/elements/color-picker.d.ts +0 -24
- package/dist/elements/color-picker.js +0 -1004
- package/dist/elements/combobox.d.ts +0 -1
- package/dist/elements/combobox.js +0 -1012
- package/dist/elements/data-grid-model.d.ts +0 -120
- package/dist/elements/data-grid-model.js +0 -294
- package/dist/elements/data-grid.d.ts +0 -30
- package/dist/elements/data-grid.js +0 -1576
- package/dist/elements/date-picker.d.ts +0 -1
- package/dist/elements/date-picker.js +0 -486
- package/dist/elements/dialog.d.ts +0 -23
- package/dist/elements/dialog.js +0 -409
- package/dist/elements/divider.d.ts +0 -2
- package/dist/elements/divider.js +0 -66
- package/dist/elements/drawer.d.ts +0 -3
- package/dist/elements/drawer.js +0 -308
- package/dist/elements/field-composition.d.ts +0 -26
- package/dist/elements/field-composition.js +0 -133
- package/dist/elements/field.d.ts +0 -1
- package/dist/elements/field.js +0 -67
- package/dist/elements/file-upload.d.ts +0 -6
- package/dist/elements/file-upload.js +0 -211
- package/dist/elements/floating-position.d.ts +0 -36
- package/dist/elements/floating-position.js +0 -92
- package/dist/elements/image.d.ts +0 -28
- package/dist/elements/image.js +0 -38
- package/dist/elements/info.d.ts +0 -9
- package/dist/elements/info.js +0 -102
- package/dist/elements/input.d.ts +0 -5
- package/dist/elements/input.js +0 -255
- package/dist/elements/label.d.ts +0 -15
- package/dist/elements/label.js +0 -56
- package/dist/elements/link.d.ts +0 -1
- package/dist/elements/link.js +0 -92
- package/dist/elements/list.d.ts +0 -19
- package/dist/elements/list.js +0 -297
- package/dist/elements/menu.d.ts +0 -33
- package/dist/elements/menu.js +0 -1103
- package/dist/elements/message-bar.d.ts +0 -10
- package/dist/elements/message-bar.js +0 -327
- package/dist/elements/nav.d.ts +0 -32
- package/dist/elements/nav.js +0 -794
- package/dist/elements/overflow.d.ts +0 -10
- package/dist/elements/overflow.js +0 -218
- package/dist/elements/persona.d.ts +0 -3
- package/dist/elements/persona.js +0 -125
- package/dist/elements/popover.d.ts +0 -77
- package/dist/elements/popover.js +0 -840
- package/dist/elements/progress-bar.d.ts +0 -4
- package/dist/elements/progress-bar.js +0 -82
- package/dist/elements/radio-group.d.ts +0 -1
- package/dist/elements/radio-group.js +0 -303
- package/dist/elements/rating-display.d.ts +0 -2
- package/dist/elements/rating-display.js +0 -125
- package/dist/elements/rating.d.ts +0 -2
- package/dist/elements/rating.js +0 -206
- package/dist/elements/rich-text-editor.d.ts +0 -32
- package/dist/elements/rich-text-editor.js +0 -1367
- package/dist/elements/search.d.ts +0 -3
- package/dist/elements/search.js +0 -200
- package/dist/elements/select.d.ts +0 -6
- package/dist/elements/select.js +0 -291
- package/dist/elements/shared.d.ts +0 -22
- package/dist/elements/shared.js +0 -409
- package/dist/elements/sharepoint-field-basic-controls.d.ts +0 -1
- package/dist/elements/sharepoint-field-basic-controls.js +0 -14
- package/dist/elements/sharepoint-fields.d.ts +0 -29
- package/dist/elements/sharepoint-fields.js +0 -460
- package/dist/elements/skeleton.d.ts +0 -6
- package/dist/elements/skeleton.js +0 -91
- package/dist/elements/slider.d.ts +0 -1
- package/dist/elements/slider.js +0 -248
- package/dist/elements/spin-button.d.ts +0 -7
- package/dist/elements/spin-button.js +0 -499
- package/dist/elements/spinner.d.ts +0 -4
- package/dist/elements/spinner.js +0 -124
- package/dist/elements/swatch-picker.d.ts +0 -5
- package/dist/elements/swatch-picker.js +0 -363
- package/dist/elements/table.d.ts +0 -21
- package/dist/elements/table.js +0 -261
- package/dist/elements/tabs.d.ts +0 -1
- package/dist/elements/tabs.js +0 -276
- package/dist/elements/tag-picker.d.ts +0 -29
- package/dist/elements/tag-picker.js +0 -715
- package/dist/elements/tags.d.ts +0 -21
- package/dist/elements/tags.js +0 -421
- package/dist/elements/teaching-popover.d.ts +0 -32
- package/dist/elements/teaching-popover.js +0 -412
- package/dist/elements/text.d.ts +0 -9
- package/dist/elements/text.js +0 -75
- package/dist/elements/textarea.d.ts +0 -1
- package/dist/elements/textarea.js +0 -182
- package/dist/elements/toast.d.ts +0 -25
- package/dist/elements/toast.js +0 -337
- package/dist/elements/toaster.d.ts +0 -6
- package/dist/elements/toaster.js +0 -357
- package/dist/elements/toggle.d.ts +0 -2
- package/dist/elements/toggle.js +0 -246
- package/dist/elements/toolbar.d.ts +0 -12
- package/dist/elements/toolbar.js +0 -381
- package/dist/elements/tooltip.d.ts +0 -76
- package/dist/elements/tooltip.js +0 -527
- package/dist/elements/tree-model.d.ts +0 -19
- package/dist/elements/tree-model.js +0 -34
- package/dist/elements/tree.d.ts +0 -5
- package/dist/elements/tree.js +0 -273
- package/dist/elements/view-card.d.ts +0 -2
- package/dist/elements/view-card.js +0 -78
- package/dist/elements/virtual-list.d.ts +0 -41
- package/dist/elements/virtual-list.js +0 -369
- package/dist/elements.d.ts +0 -73
- package/dist/elements.js +0 -210
- package/dist/sharepoint-fields.d.ts +0 -135
- package/dist/sharepoint-fields.js +0 -402
- package/dist/virtualizer-hooks.d.ts +0 -80
- package/dist/virtualizer-hooks.js +0 -253
- package/scripts/generate-token-index.mjs +0 -43
- package/scripts/sync-component-catalog-signatures.mjs +0 -55
- package/scripts/validate-component-catalog.mjs +0 -44
- package/skills/sharepoint-ui/SKILL.md +0 -12
- package/skills/sharepoint-ui/references/choosing-components.md +0 -20
- package/skills/sharepoint-ui/references/sharepoint-patterns.md +0 -17
- package/tokens.json +0 -3777
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type AccordionItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
open?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type AccordionProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
9
|
+
items: readonly AccordionItem[];
|
|
10
|
+
};
|
|
11
|
+
export declare function Accordion({ items, className, ...props }: AccordionProps): ReactElement;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function Accordion({ items, className = "", ...props }) {
|
|
3
|
+
return createElement("div", { ...props, className: `spui-accordion ${className}`.trim() }, items.map(item => createElement("details", { key: item.id, open: item.open }, createElement("summary", null, item.label), createElement("div", { className: "spui-accordion-content" }, item.content))));
|
|
4
|
+
}
|
package/dist/alert.d.ts
ADDED
package/dist/alert.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type AttachmentItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
status?: "ready" | "uploading" | "uploaded" | "error";
|
|
6
|
+
progress?: number;
|
|
7
|
+
message?: string;
|
|
8
|
+
};
|
|
9
|
+
export type AttachmentListProps = Omit<HTMLAttributes<HTMLUListElement>, "children" | "aria-label"> & {
|
|
10
|
+
label: string;
|
|
11
|
+
items: readonly AttachmentItem[];
|
|
12
|
+
onRemove?: (id: string) => void;
|
|
13
|
+
removeLabel?: (name: string) => string;
|
|
14
|
+
};
|
|
15
|
+
export declare function AttachmentList({ label, items, onRemove, removeLabel, className, ...props }: AttachmentListProps): ReactElement;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
const statusLabels = { ready: "Ready", uploading: "Uploading", uploaded: "Uploaded", error: "Upload failed" };
|
|
3
|
+
export function AttachmentList({ label, items, onRemove, removeLabel = name => `Remove ${name}`, className = "", ...props }) {
|
|
4
|
+
return createElement("ul", { ...props, "aria-label": label, className: `spui-attachment-list ${className}`.trim() }, items.map(item => {
|
|
5
|
+
const status = item.status ?? "ready";
|
|
6
|
+
return createElement("li", { key: item.id, className: `spui-attachment spui-attachment-${status}` }, createElement("span", null, item.name), status === "uploading" && createElement("progress", {
|
|
7
|
+
max: 100, value: item.progress === undefined ? undefined : Math.max(0, Math.min(100, item.progress)),
|
|
8
|
+
"aria-label": `${item.name} upload progress`,
|
|
9
|
+
}), createElement("span", { role: status === "error" ? "alert" : "status", "aria-live": "polite" }, item.message ?? statusLabels[status]), onRemove && createElement("button", {
|
|
10
|
+
type: "button", onClick: () => onRemove(item.id),
|
|
11
|
+
"aria-label": removeLabel(item.name), disabled: status === "uploading",
|
|
12
|
+
}, "Remove"));
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type AvatarGroupPerson = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
src?: string;
|
|
6
|
+
};
|
|
7
|
+
export type AvatarGroupProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "aria-label"> & {
|
|
8
|
+
label: string;
|
|
9
|
+
people: readonly AvatarGroupPerson[];
|
|
10
|
+
maxVisible?: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function AvatarGroup({ label, people, maxVisible, className, ...props }: AvatarGroupProps): ReactElement;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
import { Avatar } from "./avatar.js";
|
|
3
|
+
export function AvatarGroup({ label, people, maxVisible = 4, className = "", ...props }) {
|
|
4
|
+
const visible = people.slice(0, Math.max(0, maxVisible));
|
|
5
|
+
const remaining = people.length - visible.length;
|
|
6
|
+
return createElement("div", { ...props, role: "group", "aria-label": label, className: `spui-avatar-group ${className}`.trim() }, visible.map(person => createElement(Avatar, { key: person.id, name: person.name, src: person.src })), remaining > 0 && createElement("span", { className: "spui-avatar-overflow", "aria-label": `${remaining} more people` }, `+${remaining}`));
|
|
7
|
+
}
|
package/dist/avatar.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type AvatarProps = Omit<HTMLAttributes<HTMLSpanElement>, "children" | "aria-label"> & {
|
|
3
|
+
name: string;
|
|
4
|
+
src?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function Avatar({ name, src, className, ...props }: AvatarProps): ReactElement;
|
package/dist/avatar.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function Avatar({ name, src, className = "", ...props }) {
|
|
3
|
+
const initials = name.trim().split(/\s+/).slice(0, 2).map(part => part[0]?.toLocaleUpperCase()).join("");
|
|
4
|
+
return createElement("span", { ...props, role: "img", "aria-label": name, className: `spui-avatar ${className}`.trim() }, src ? createElement("img", { src, alt: "" }) : initials);
|
|
5
|
+
}
|
package/dist/badge.d.ts
ADDED
package/dist/badge.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type BreadcrumbItem = {
|
|
3
|
+
label: ReactNode;
|
|
4
|
+
href?: string;
|
|
5
|
+
};
|
|
6
|
+
export type BreadcrumbProps = Omit<HTMLAttributes<HTMLElement>, "children" | "aria-label"> & {
|
|
7
|
+
label?: string;
|
|
8
|
+
items: readonly BreadcrumbItem[];
|
|
9
|
+
};
|
|
10
|
+
export declare function Breadcrumb({ label, items, className, ...props }: BreadcrumbProps): ReactElement;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function Breadcrumb({ label = "Breadcrumb", items, className = "", ...props }) {
|
|
3
|
+
return createElement("nav", { ...props, "aria-label": label, className: `spui-breadcrumb ${className}`.trim() }, createElement("ol", null, items.map((item, index) => {
|
|
4
|
+
const current = index === items.length - 1;
|
|
5
|
+
return createElement("li", { key: `${index}-${item.href ?? "current"}` }, !current && item.href
|
|
6
|
+
? createElement("a", { href: item.href }, item.label)
|
|
7
|
+
: createElement("span", { "aria-current": current ? "page" : undefined }, item.label));
|
|
8
|
+
})));
|
|
9
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type ButtonGroupProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "aria-label"> & {
|
|
3
|
+
label: string;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
};
|
|
6
|
+
export declare function ButtonGroup({ label, className, children, ...props }: ButtonGroupProps): ReactElement;
|
package/dist/button.d.ts
ADDED
package/dist/button.js
ADDED
package/dist/card.d.ts
ADDED
package/dist/card.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type CarouselItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export type CarouselProps = Omit<HTMLAttributes<HTMLElement>, "children" | "aria-label"> & {
|
|
8
|
+
label: string;
|
|
9
|
+
items: readonly CarouselItem[];
|
|
10
|
+
};
|
|
11
|
+
export declare function Carousel({ label, items, className, ...props }: CarouselProps): ReactElement;
|
package/dist/carousel.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function Carousel({ label, items, className = "", ...props }) {
|
|
3
|
+
return createElement("section", { ...props, role: "region", "aria-label": label, "aria-roledescription": "carousel", tabIndex: 0, className: `spui-carousel ${className}`.trim() }, createElement("ul", null, items.map((item, index) => createElement("li", {
|
|
4
|
+
key: item.id, "aria-roledescription": "slide", "aria-label": `${item.label}, ${index + 1} of ${items.length}`,
|
|
5
|
+
}, item.content))));
|
|
6
|
+
}
|
package/dist/checkbox.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type ComboBoxOption = {
|
|
3
|
+
value: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
};
|
|
6
|
+
export type ComboBoxProps = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "list"> & {
|
|
7
|
+
options: readonly ComboBoxOption[];
|
|
8
|
+
};
|
|
9
|
+
export declare function ComboBox({ className, id, options, ...props }: ComboBoxProps): ReactElement;
|
package/dist/combobox.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createElement, useId } from "react";
|
|
2
|
+
export function ComboBox({ className = "", id, options, ...props }) {
|
|
3
|
+
const generatedId = useId();
|
|
4
|
+
const listId = `${id ?? generatedId}-options`;
|
|
5
|
+
return createElement("span", { className: "spui-combobox" }, createElement("input", { ...props, id, type: "text", list: listId, className: `spui-input ${className}`.trim() }), createElement("datalist", { id: listId }, options.map(option => createElement("option", { key: option.value, value: option.value, label: option.label }))));
|
|
6
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type CommandBarProps = Omit<HTMLAttributes<HTMLElement>, "children" | "aria-label"> & {
|
|
3
|
+
label: string;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
};
|
|
6
|
+
export declare function CommandBar({ label, className, children, ...props }: CommandBarProps): ReactElement;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type CopyButtonProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "value"> & {
|
|
3
|
+
value: string;
|
|
4
|
+
copiedLabel?: string;
|
|
5
|
+
failedLabel?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function CopyButton({ value, copiedLabel, failedLabel, className, type, onClick, children, ...props }: CopyButtonProps): ReactElement;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createElement, useState } from "react";
|
|
2
|
+
export function CopyButton({ value, copiedLabel = "Copied", failedLabel = "Copy failed", className = "", type = "button", onClick, children = "Copy", ...props }) {
|
|
3
|
+
const [message, setMessage] = useState("");
|
|
4
|
+
return createElement("span", { className: "spui-copy" }, createElement("button", {
|
|
5
|
+
...props,
|
|
6
|
+
type,
|
|
7
|
+
className: `spui-button ${className}`.trim(),
|
|
8
|
+
onClick: (event) => {
|
|
9
|
+
onClick?.(event);
|
|
10
|
+
if (event.defaultPrevented)
|
|
11
|
+
return;
|
|
12
|
+
if (typeof navigator === "undefined" || !navigator.clipboard) {
|
|
13
|
+
setMessage(failedLabel);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
void navigator.clipboard.writeText(value).then(() => setMessage(copiedLabel), () => setMessage(failedLabel));
|
|
17
|
+
},
|
|
18
|
+
}, children), createElement("span", { className: "spui-visually-hidden", role: "status", "aria-live": "polite" }, message));
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode, type TableHTMLAttributes } from "react";
|
|
2
|
+
export type DataGridColumn<Row> = {
|
|
3
|
+
key: keyof Row & string;
|
|
4
|
+
label: string;
|
|
5
|
+
render?: (row: Row) => ReactNode;
|
|
6
|
+
sortable?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type DataGridSort<Row> = {
|
|
9
|
+
key: keyof Row & string;
|
|
10
|
+
direction: "ascending" | "descending";
|
|
11
|
+
};
|
|
12
|
+
export type DataGridProps<Row extends Record<string, unknown>> = Omit<TableHTMLAttributes<HTMLTableElement>, "children"> & {
|
|
13
|
+
label: string;
|
|
14
|
+
caption?: ReactNode;
|
|
15
|
+
rows: readonly Row[];
|
|
16
|
+
columns: readonly DataGridColumn<Row>[];
|
|
17
|
+
getRowId: (row: Row) => string;
|
|
18
|
+
rowLabel?: (row: Row) => string;
|
|
19
|
+
selectable?: boolean;
|
|
20
|
+
selectedIds?: readonly string[];
|
|
21
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
22
|
+
initialSort?: DataGridSort<Row>;
|
|
23
|
+
onSortChange?: (sort: DataGridSort<Row>) => void;
|
|
24
|
+
};
|
|
25
|
+
export declare function DataGrid<Row extends Record<string, unknown>>({ label, caption, rows, columns, getRowId, rowLabel, selectable, selectedIds, onSelectionChange, initialSort, onSortChange, className, ...props }: DataGridProps<Row>): ReactElement;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createElement, useState } from "react";
|
|
2
|
+
export function DataGrid({ label, caption, rows, columns, getRowId, rowLabel, selectable = false, selectedIds, onSelectionChange, initialSort, onSortChange, className = "", ...props }) {
|
|
3
|
+
const [sort, setSort] = useState(initialSort);
|
|
4
|
+
const [internalSelected, setInternalSelected] = useState(() => new Set(selectedIds));
|
|
5
|
+
const selected = selectedIds === undefined ? internalSelected : new Set(selectedIds);
|
|
6
|
+
const orderedRows = sort ? [...rows].sort((a, b) => {
|
|
7
|
+
const left = a[sort.key], right = b[sort.key];
|
|
8
|
+
const comparison = typeof left === "number" && typeof right === "number"
|
|
9
|
+
? left - right : String(left ?? "").localeCompare(String(right ?? ""), undefined, { numeric: true });
|
|
10
|
+
return sort.direction === "ascending" ? comparison : -comparison;
|
|
11
|
+
}) : rows;
|
|
12
|
+
const changeSort = (key) => {
|
|
13
|
+
const next = { key, direction: sort?.key === key && sort.direction === "ascending" ? "descending" : "ascending" };
|
|
14
|
+
setSort(next);
|
|
15
|
+
onSortChange?.(next);
|
|
16
|
+
};
|
|
17
|
+
const toggle = (id) => {
|
|
18
|
+
const next = new Set(selected);
|
|
19
|
+
next.has(id) ? next.delete(id) : next.add(id);
|
|
20
|
+
if (selectedIds === undefined)
|
|
21
|
+
setInternalSelected(next);
|
|
22
|
+
onSelectionChange?.([...next]);
|
|
23
|
+
};
|
|
24
|
+
return createElement("table", { ...props, "aria-label": label, className: `spui-table spui-data-grid ${className}`.trim() }, caption && createElement("caption", null, caption), createElement("thead", null, createElement("tr", null, selectable && createElement("th", { scope: "col" }, "Select"), columns.map(column => createElement("th", {
|
|
25
|
+
key: column.key, scope: "col",
|
|
26
|
+
"aria-sort": sort?.key === column.key ? sort.direction : undefined,
|
|
27
|
+
}, column.sortable === false ? column.label : createElement("button", {
|
|
28
|
+
type: "button", onClick: () => changeSort(column.key),
|
|
29
|
+
"aria-label": `Sort by ${column.label}`,
|
|
30
|
+
}, column.label))))), createElement("tbody", null, orderedRows.map(row => {
|
|
31
|
+
const id = getRowId(row);
|
|
32
|
+
const name = rowLabel?.(row) ?? id;
|
|
33
|
+
return createElement("tr", { key: id, "aria-selected": selectable ? selected.has(id) : undefined }, selectable && createElement("td", null, createElement("input", {
|
|
34
|
+
type: "checkbox", className: "spui-checkbox", checked: selected.has(id),
|
|
35
|
+
"aria-label": `Select ${name}`, onChange: () => toggle(id),
|
|
36
|
+
})), columns.map(column => createElement("td", { key: column.key }, column.render
|
|
37
|
+
? column.render(row) : String(row[column.key] ?? ""))));
|
|
38
|
+
})));
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type FieldsetHTMLAttributes, type InputHTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type DateRangePickerProps = Omit<FieldsetHTMLAttributes<HTMLFieldSetElement>, "id" | "children"> & {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
startLabel?: string;
|
|
6
|
+
endLabel?: string;
|
|
7
|
+
startName?: string;
|
|
8
|
+
endName?: string;
|
|
9
|
+
startProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "id" | "name" | "type">;
|
|
10
|
+
endProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "id" | "name" | "type">;
|
|
11
|
+
};
|
|
12
|
+
export declare function DateRangePicker({ id, label, startLabel, endLabel, startName, endName, startProps, endProps, className, ...props }: DateRangePickerProps): ReactElement;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function DateRangePicker({ id, label, startLabel = "Start date", endLabel = "End date", startName = "start", endName = "end", startProps, endProps, className = "", ...props }) {
|
|
3
|
+
return createElement("fieldset", { ...props, className: `spui-date-range ${className}`.trim() }, createElement("legend", null, label), createElement("label", { htmlFor: `${id}-start` }, startLabel, createElement("input", { ...startProps, id: `${id}-start`, name: startName, type: "date", className: `spui-input ${startProps?.className ?? ""}`.trim() })), createElement("label", { htmlFor: `${id}-end` }, endLabel, createElement("input", { ...endProps, id: `${id}-end`, name: endName, type: "date", className: `spui-input ${endProps?.className ?? ""}`.trim() })));
|
|
4
|
+
}
|
package/dist/dialog.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DialogHTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type DialogProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, "children" | "open" | "onClose"> & {
|
|
3
|
+
open: boolean;
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
closeLabel?: string;
|
|
7
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function Dialog({ open, title, children, closeLabel, onOpenChange, className, ...props }: DialogProps): ReactElement;
|
package/dist/dialog.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createElement, useEffect, useId, useRef } from "react";
|
|
2
|
+
export function Dialog({ open, title, children, closeLabel = "Close", onOpenChange, className = "", ...props }) {
|
|
3
|
+
const ref = useRef(null);
|
|
4
|
+
const titleId = useId();
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const dialog = ref.current;
|
|
7
|
+
if (!dialog)
|
|
8
|
+
return;
|
|
9
|
+
if (open && !dialog.open)
|
|
10
|
+
dialog.showModal();
|
|
11
|
+
if (!open && dialog.open)
|
|
12
|
+
dialog.close();
|
|
13
|
+
}, [open]);
|
|
14
|
+
return createElement("dialog", {
|
|
15
|
+
...props,
|
|
16
|
+
ref,
|
|
17
|
+
"aria-labelledby": titleId,
|
|
18
|
+
className: `spui-dialog ${className}`.trim(),
|
|
19
|
+
onClose: () => onOpenChange?.(false),
|
|
20
|
+
}, createElement("header", null, createElement("h2", { id: titleId }, title), createElement("button", { type: "button", onClick: () => ref.current?.close(), "aria-label": closeLabel }, closeLabel)), children);
|
|
21
|
+
}
|
package/dist/divider.js
ADDED
package/dist/drawer.d.ts
ADDED
package/dist/drawer.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
import { Dialog } from "./dialog.js";
|
|
3
|
+
export function Drawer({ placement = "end", className = "", ...props }) {
|
|
4
|
+
return createElement(Dialog, { ...props, className: `spui-drawer spui-drawer-${placement} ${className}`.trim() });
|
|
5
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type EmptyStateProps = Omit<HTMLAttributes<HTMLElement>, "children" | "title"> & {
|
|
3
|
+
title: ReactNode;
|
|
4
|
+
description?: ReactNode;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export declare function EmptyState({ title, description, className, children, ...props }: EmptyStateProps): ReactElement;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createElement, useId } from "react";
|
|
2
|
+
export function EmptyState({ title, description, className = "", children, ...props }) {
|
|
3
|
+
const headingId = useId();
|
|
4
|
+
return createElement("section", { ...props, "aria-labelledby": headingId, className: `spui-empty-state ${className}`.trim() }, createElement("h2", { id: headingId }, title), description && createElement("p", null, description), children);
|
|
5
|
+
}
|
package/dist/field.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AriaAttributes, type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type FieldProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "id"> & {
|
|
3
|
+
id: string;
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
hint?: ReactNode;
|
|
6
|
+
error?: ReactNode;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
children: ReactElement<{
|
|
9
|
+
id?: string;
|
|
10
|
+
"aria-describedby"?: string;
|
|
11
|
+
"aria-invalid"?: AriaAttributes["aria-invalid"];
|
|
12
|
+
required?: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
export declare function Field({ id, label, hint, error, required, children, className, ...props }: FieldProps): ReactElement;
|
package/dist/field.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { cloneElement, createElement } from "react";
|
|
2
|
+
export function Field({ id, label, hint, error, required, children, className = "", ...props }) {
|
|
3
|
+
const describedBy = [children.props["aria-describedby"], hint && `${id}-hint`, error && `${id}-error`].filter(Boolean).join(" ");
|
|
4
|
+
const control = cloneElement(children, {
|
|
5
|
+
id,
|
|
6
|
+
required: required || children.props.required,
|
|
7
|
+
"aria-describedby": describedBy || undefined,
|
|
8
|
+
"aria-invalid": error ? true : children.props["aria-invalid"],
|
|
9
|
+
});
|
|
10
|
+
return createElement("div", { ...props, className: `spui-field ${className}`.trim() }, createElement("label", { htmlFor: id }, label, required && createElement("span", { "aria-hidden": true }, " *")), control, hint && createElement("div", { id: `${id}-hint`, className: "spui-hint" }, hint), error && createElement("div", { id: `${id}-error`, className: "spui-error", role: "alert" }, error));
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type HTMLAttributes, type InputHTMLAttributes, type ReactElement } from "react";
|
|
2
|
+
export type FileDropzoneProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "aria-label" | "aria-labelledby" | "onDrop" | "onDragOver"> & {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
hint?: string;
|
|
6
|
+
accept?: string;
|
|
7
|
+
multiple?: boolean;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
files?: readonly File[];
|
|
12
|
+
onFiles: (files: File[]) => void;
|
|
13
|
+
inputProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "id" | "name" | "accept" | "multiple" | "disabled" | "required" | "onChange">;
|
|
14
|
+
};
|
|
15
|
+
export declare function FileDropzone({ id, label, hint, accept, multiple, disabled, required, name, files, onFiles, inputProps, className, ...props }: FileDropzoneProps): ReactElement;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function FileDropzone({ id, label, hint, accept, multiple = true, disabled = false, required = false, name, files = [], onFiles, inputProps, className = "", ...props }) {
|
|
3
|
+
const notifyFiles = (incoming) => {
|
|
4
|
+
if (!disabled)
|
|
5
|
+
onFiles(Array.from(incoming ?? []).slice(0, multiple ? undefined : 1));
|
|
6
|
+
};
|
|
7
|
+
const handleDrop = (event) => {
|
|
8
|
+
event.preventDefault();
|
|
9
|
+
notifyFiles(event.dataTransfer.files);
|
|
10
|
+
};
|
|
11
|
+
return createElement("div", {
|
|
12
|
+
...props, role: "group", "aria-labelledby": `${id}-label`, className: `spui-file-dropzone ${className}`.trim(),
|
|
13
|
+
onDragOver: (event) => event.preventDefault(),
|
|
14
|
+
onDrop: handleDrop,
|
|
15
|
+
}, createElement("label", { id: `${id}-label`, htmlFor: id }, label), hint && createElement("p", { id: `${id}-hint`, className: "spui-hint" }, hint), createElement("input", {
|
|
16
|
+
...inputProps, id, name, type: "file", accept, multiple, disabled, required,
|
|
17
|
+
"aria-describedby": [inputProps?.["aria-describedby"], hint && `${id}-hint`].filter(Boolean).join(" ") || undefined,
|
|
18
|
+
onChange: (event) => notifyFiles(event.currentTarget.files),
|
|
19
|
+
className: `spui-file-input ${inputProps?.className ?? ""}`.trim(),
|
|
20
|
+
}), createElement("span", { className: "spui-file-drop-hint", "aria-hidden": true }, "Drop files here or choose files"), createElement("span", { className: "spui-sr-only", role: "status", "aria-live": "polite" }, files.length ? `${files.length} file${files.length === 1 ? "" : "s"} selected` : "No files selected"));
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
export type FilterBarProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "aria-label"> & {
|
|
3
|
+
label: string;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
onClear?: () => void;
|
|
6
|
+
clearLabel?: string;
|
|
7
|
+
activeFilterCount?: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function FilterBar({ label, children, onClear, clearLabel, activeFilterCount, className, ...props }: FilterBarProps): ReactElement;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
export function FilterBar({ label, children, onClear, clearLabel = "Clear filters", activeFilterCount, className = "", ...props }) {
|
|
3
|
+
return createElement("div", {
|
|
4
|
+
...props, role: "search", "aria-label": label, className: `spui-filter-bar ${className}`.trim(),
|
|
5
|
+
}, createElement("div", { className: "spui-filter-controls" }, children), onClear && createElement("button", {
|
|
6
|
+
type: "button", className: "spui-filter-clear", onClick: onClear,
|
|
7
|
+
disabled: activeFilterCount === 0,
|
|
8
|
+
}, clearLabel));
|
|
9
|
+
}
|
package/dist/image.d.ts
ADDED
package/dist/image.js
ADDED