@neasg/design-system 0.2.0 → 0.3.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 +22 -9
- package/dist/badge.d.ts +3 -1
- package/dist/badge.js +13 -2
- package/dist/button.d.ts +1 -1
- package/dist/button.js +4 -4
- package/dist/calendar.d.ts +8 -0
- package/dist/calendar.js +80 -0
- package/dist/card.d.ts +14 -0
- package/dist/card.js +9 -0
- package/dist/command-search.js +4 -3
- package/dist/date-input.d.ts +22 -0
- package/dist/date-input.js +61 -0
- package/dist/editable-table.js +2 -2
- package/dist/govt-masthead.d.ts +9 -0
- package/dist/govt-masthead.js +8 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +7 -0
- package/dist/input-control.d.ts +1 -1
- package/dist/input-control.js +1 -1
- package/dist/label-value.js +2 -1
- package/dist/layout.d.ts +3 -1
- package/dist/layout.js +31 -5
- package/dist/multi-select.d.ts +29 -0
- package/dist/multi-select.js +77 -0
- package/dist/otp-input.js +2 -2
- package/dist/pagination.js +2 -1
- package/dist/popover.d.ts +7 -0
- package/dist/popover.js +11 -0
- package/dist/select-primitive.d.ts +3 -1
- package/dist/select-primitive.js +3 -2
- package/dist/select.d.ts +1 -0
- package/dist/select.js +1 -1
- package/dist/tab-with-dropdown.d.ts +18 -0
- package/dist/tab-with-dropdown.js +70 -0
- package/dist/textarea.js +1 -1
- package/dist/toaster.d.ts +13 -0
- package/dist/toaster.js +18 -0
- package/dist/typography.d.ts +2 -0
- package/dist/typography.js +9 -2
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -125,15 +125,28 @@ One-time setup:
|
|
|
125
125
|
|
|
126
126
|
Release flow:
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
npm version
|
|
132
|
-
npm version 0.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
1. Make sure all your changes are committed and pushed to `main`.
|
|
129
|
+
2. Bump the version — this updates `package.json` and creates a git tag automatically:
|
|
130
|
+
```bash
|
|
131
|
+
npm version patch # 0.2.0 → 0.2.1
|
|
132
|
+
npm version minor # 0.2.0 → 0.3.0
|
|
133
|
+
npm version major # 0.2.0 → 1.0.0
|
|
134
|
+
npm version 0.5.0 # set an exact version
|
|
135
|
+
```
|
|
136
|
+
3. Push the commit and tag together:
|
|
137
|
+
```bash
|
|
138
|
+
git push origin main --follow-tags
|
|
139
|
+
```
|
|
140
|
+
4. The `v*` tag triggers `.github/workflows/publish.yml`, which runs tests, builds, and publishes to npm.
|
|
141
|
+
|
|
142
|
+
> **Note:** If GPG signing fails on step 2, you can do it manually:
|
|
143
|
+
> ```bash
|
|
144
|
+
> npm version 0.2.0 --no-git-tag-version
|
|
145
|
+
> git add package.json package-lock.json
|
|
146
|
+
> git commit -m "0.2.0"
|
|
147
|
+
> git tag v0.2.0
|
|
148
|
+
> git push origin main --follow-tags
|
|
149
|
+
> ```
|
|
137
150
|
|
|
138
151
|
## Storybook Deployment
|
|
139
152
|
|
package/dist/badge.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ declare const badgeVariants: (props?: ({
|
|
|
9
9
|
* surface the full label via `title`.
|
|
10
10
|
*/
|
|
11
11
|
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
12
|
+
/** Show a visible border matching the badge colour. */
|
|
13
|
+
bordered?: boolean;
|
|
12
14
|
}
|
|
13
|
-
declare function Badge({ className, variant, children, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare function Badge({ className, variant, bordered, children, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
|
|
14
16
|
export { Badge, badgeVariants };
|
package/dist/badge.js
CHANGED
|
@@ -19,12 +19,23 @@ const badgeVariants = cva("inline-flex max-w-[200px] items-center justify-center
|
|
|
19
19
|
variant: "secondary",
|
|
20
20
|
},
|
|
21
21
|
});
|
|
22
|
-
function Badge({ className, variant, children, ...props }) {
|
|
22
|
+
function Badge({ className, variant, bordered = false, children, ...props }) {
|
|
23
23
|
const textContent = typeof children === "string"
|
|
24
24
|
? children
|
|
25
25
|
: React.Children.toArray(children)
|
|
26
26
|
.filter((child) => typeof child === "string")
|
|
27
27
|
.join("");
|
|
28
|
-
|
|
28
|
+
const resolvedVariant = variant !== null && variant !== void 0 ? variant : "secondary";
|
|
29
|
+
const borderedClasses = {
|
|
30
|
+
secondary: "border-secondary-foreground/30",
|
|
31
|
+
muted: "border-muted-foreground/30",
|
|
32
|
+
destructive: "border-[hsl(var(--status-destructive-foreground))]/30",
|
|
33
|
+
outline: "border-foreground/30",
|
|
34
|
+
success: "border-[hsl(var(--status-success-foreground))]/30",
|
|
35
|
+
warning: "border-[hsl(var(--status-warning-foreground))]/30",
|
|
36
|
+
info: "border-[hsl(var(--status-info-foreground))]/30",
|
|
37
|
+
accent: "border-[hsl(var(--status-accent-foreground))]/30",
|
|
38
|
+
};
|
|
39
|
+
return (_jsx("div", { className: cn(badgeVariants({ variant }), bordered && borderedClasses[resolvedVariant], className), title: textContent || undefined, ...props, children: children }));
|
|
29
40
|
}
|
|
30
41
|
export { Badge, badgeVariants };
|
package/dist/button.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
4
|
variant?: "link" | "default" | "outline" | "secondary" | "destructive" | "ghost" | null | undefined;
|
|
5
|
-
size?: "default" | "sm" | "
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
8
|
/**
|
package/dist/button.js
CHANGED
|
@@ -14,10 +14,10 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
|
|
|
14
14
|
link: "text-primary underline-offset-4 hover:underline",
|
|
15
15
|
},
|
|
16
16
|
size: {
|
|
17
|
-
default: "h-
|
|
18
|
-
sm: "h-
|
|
19
|
-
lg: "h-
|
|
20
|
-
icon: "h-
|
|
17
|
+
default: "h-10 px-4 py-2 [&_svg]:h-4 [&_svg]:w-4",
|
|
18
|
+
sm: "h-9 rounded-md px-3 text-xs [&_svg]:h-4 [&_svg]:w-4",
|
|
19
|
+
lg: "h-11 rounded-md px-8 [&_svg]:h-5 [&_svg]:w-5",
|
|
20
|
+
icon: "h-10 w-10 [&_svg]:h-4 [&_svg]:w-4",
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
23
|
defaultVariants: {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { DayButton, DayPicker } from "react-day-picker";
|
|
3
|
+
import { Button } from "./button";
|
|
4
|
+
declare function CalendarDayButton({ className, day, modifiers, children, disabled, onClick, onFocus, onBlur, onKeyDown, onMouseEnter, onMouseLeave, tabIndex, type, "aria-label": ariaLabel, "aria-pressed": ariaPressed, "aria-selected": ariaSelected, }: React.ComponentProps<typeof DayButton>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function Calendar({ className, classNames, showOutsideDays, captionLayout, buttonVariant, formatters, components, ...props }: React.ComponentProps<typeof DayPicker> & {
|
|
6
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export { Calendar, CalendarDayButton };
|
package/dist/calendar.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { DayPicker, getDefaultClassNames } from "react-day-picker";
|
|
5
|
+
import { buttonVariants } from "./button";
|
|
6
|
+
import { cn } from "./lib/utils";
|
|
7
|
+
function CalendarDayButton({ className, day, modifiers, children, disabled, onClick, onFocus, onBlur, onKeyDown, onMouseEnter, onMouseLeave, tabIndex, type, "aria-label": ariaLabel, "aria-pressed": ariaPressed, "aria-selected": ariaSelected, }) {
|
|
8
|
+
const defaultClassNames = getDefaultClassNames();
|
|
9
|
+
const ref = React.useRef(null);
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
var _a;
|
|
12
|
+
if (modifiers.focused)
|
|
13
|
+
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
14
|
+
}, [modifiers.focused]);
|
|
15
|
+
return (_jsx("button", { ref: ref, type: type, disabled: disabled, onClick: onClick, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, tabIndex: tabIndex, "aria-label": ariaLabel, "aria-pressed": ariaPressed, "aria-selected": ariaSelected, "data-day": day.date.toLocaleDateString(), "data-selected-single": modifiers.selected &&
|
|
16
|
+
!modifiers.range_start &&
|
|
17
|
+
!modifiers.range_end &&
|
|
18
|
+
!modifiers.range_middle, "data-range-start": modifiers.range_start, "data-range-end": modifiers.range_end, "data-range-middle": modifiers.range_middle, className: cn("inline-flex cursor-pointer items-center justify-center rounded-md text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", "data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 aspect-square w-full min-w-[--cell-size] font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px]", defaultClassNames.day, className), children: children }));
|
|
19
|
+
}
|
|
20
|
+
function Calendar({ className, classNames, showOutsideDays = true, captionLayout = "label", buttonVariant = "ghost", formatters, components, ...props }) {
|
|
21
|
+
const defaultClassNames = getDefaultClassNames();
|
|
22
|
+
return (_jsx(DayPicker, { showOutsideDays: showOutsideDays, className: cn("bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent", String.raw `rtl:**:[.rdp-button\_next>svg]:rotate-180`, String.raw `rtl:**:[.rdp-button\_previous>svg]:rotate-180`, className), captionLayout: captionLayout, formatters: {
|
|
23
|
+
formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
|
|
24
|
+
...formatters,
|
|
25
|
+
}, classNames: {
|
|
26
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
27
|
+
months: cn("relative flex flex-col gap-4 md:flex-row", defaultClassNames.months),
|
|
28
|
+
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
29
|
+
nav: cn("absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", defaultClassNames.nav),
|
|
30
|
+
button_previous: cn(buttonVariants({ variant: buttonVariant }), "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50", defaultClassNames.button_previous),
|
|
31
|
+
button_next: cn(buttonVariants({ variant: buttonVariant }), "h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50", defaultClassNames.button_next),
|
|
32
|
+
month_caption: cn("flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]", defaultClassNames.month_caption),
|
|
33
|
+
dropdowns: cn("flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium", defaultClassNames.dropdowns),
|
|
34
|
+
dropdown_root: cn("has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border", defaultClassNames.dropdown_root),
|
|
35
|
+
dropdown: cn("bg-popover absolute inset-0 opacity-0", defaultClassNames.dropdown),
|
|
36
|
+
caption_label: cn("select-none font-medium", captionLayout === "label"
|
|
37
|
+
? "text-sm"
|
|
38
|
+
: "[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5", defaultClassNames.caption_label),
|
|
39
|
+
table: "w-full border-collapse",
|
|
40
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
41
|
+
weekday: cn("text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal", defaultClassNames.weekday),
|
|
42
|
+
week: cn("mt-2 flex w-full", defaultClassNames.week),
|
|
43
|
+
week_number_header: cn("w-[--cell-size] select-none", defaultClassNames.week_number_header),
|
|
44
|
+
week_number: cn("text-muted-foreground select-none text-[0.8rem]", defaultClassNames.week_number),
|
|
45
|
+
day: cn("group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md", defaultClassNames.day),
|
|
46
|
+
range_start: cn("bg-accent rounded-l-md", defaultClassNames.range_start),
|
|
47
|
+
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
|
48
|
+
range_end: cn("bg-accent rounded-r-md", defaultClassNames.range_end),
|
|
49
|
+
today: cn("bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none", defaultClassNames.today),
|
|
50
|
+
outside: cn("text-muted-foreground aria-selected:text-muted-foreground", defaultClassNames.outside),
|
|
51
|
+
disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
|
|
52
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
53
|
+
...classNames,
|
|
54
|
+
}, components: {
|
|
55
|
+
Root: ({ className: rootClassName, rootRef, ...rootProps }) => (_jsx("div", { "data-slot": "calendar", ref: rootRef, className: cn(rootClassName), ...rootProps })),
|
|
56
|
+
Chevron: ({ className: chevronClassName, orientation }) => {
|
|
57
|
+
const svgProps = {
|
|
58
|
+
className: cn("size-4", chevronClassName),
|
|
59
|
+
viewBox: "0 0 24 24",
|
|
60
|
+
fill: "none",
|
|
61
|
+
stroke: "currentColor",
|
|
62
|
+
strokeWidth: 2,
|
|
63
|
+
strokeLinecap: "round",
|
|
64
|
+
strokeLinejoin: "round",
|
|
65
|
+
"aria-hidden": true,
|
|
66
|
+
};
|
|
67
|
+
if (orientation === "left") {
|
|
68
|
+
return _jsx("svg", { ...svgProps, children: _jsx("path", { d: "m15 18-6-6 6-6" }) });
|
|
69
|
+
}
|
|
70
|
+
if (orientation === "right") {
|
|
71
|
+
return _jsx("svg", { ...svgProps, children: _jsx("path", { d: "m9 18 6-6-6-6" }) });
|
|
72
|
+
}
|
|
73
|
+
return _jsx("svg", { ...svgProps, children: _jsx("path", { d: "m6 9 6 6 6-6" }) });
|
|
74
|
+
},
|
|
75
|
+
DayButton: CalendarDayButton,
|
|
76
|
+
WeekNumber: ({ children, ...weekNumberProps }) => (_jsx("td", { ...weekNumberProps, children: _jsx("div", { className: "flex size-[--cell-size] items-center justify-center text-center", children: children }) })),
|
|
77
|
+
...components,
|
|
78
|
+
}, ...props }));
|
|
79
|
+
}
|
|
80
|
+
export { Calendar, CalendarDayButton };
|
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
3
|
+
title: React.ReactNode;
|
|
4
|
+
description?: React.ReactNode;
|
|
5
|
+
variant?: "default" | "elevated" | "gradient";
|
|
6
|
+
/** Large value displayed above the title — use for stat/metric cards. */
|
|
7
|
+
stat?: React.ReactNode;
|
|
8
|
+
/** Small supporting text below the stat or body — use for sub-metrics. */
|
|
9
|
+
subMetric?: React.ReactNode;
|
|
10
|
+
footer?: React.ReactNode;
|
|
11
|
+
active?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
|
+
export { Card };
|
package/dist/card.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "./lib/utils";
|
|
5
|
+
import { Typography } from "./typography";
|
|
6
|
+
const Card = React.forwardRef(({ title, description, variant = "default", stat, subMetric, footer, active, children, className, onClick, ...props }, ref) => (_jsxs("div", { ref: ref, onClick: onClick, className: cn("rounded-xl border text-card-foreground", variant === "default" && "bg-card", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
|
|
7
|
+
"border-primary/20 bg-gradient-to-br from-primary to-primary/80 text-primary-foreground", active && "border-primary bg-primary/10 ring-1 ring-primary/20", onClick && "cursor-pointer transition-colors hover:border-primary", className), ...props, children: [_jsxs("div", { className: "flex flex-col gap-2 p-6", children: [_jsx(Typography, { as: "p", variant: "label", color: variant === "gradient" ? "inherit" : "muted", className: variant === "gradient" ? "opacity-80" : undefined, children: title }), description ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-70" : undefined, children: description })) : null, stat ? (_jsx(Typography, { as: "p", variant: "title", color: variant === "gradient" ? "inherit" : undefined, children: stat })) : null, subMetric ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-80" : undefined, children: subMetric })) : null] }), children ? _jsx("div", { className: "p-6 pt-0", children: children }) : null, footer ? (_jsx("div", { className: "flex items-center p-6 pt-0", children: footer })) : null] })));
|
|
8
|
+
Card.displayName = "Card";
|
|
9
|
+
export { Card };
|
package/dist/command-search.js
CHANGED
|
@@ -8,6 +8,7 @@ import { SearchIcon } from "./animated-icons/search";
|
|
|
8
8
|
import { DialogRoot, DialogSurface } from "./dialog-primitive";
|
|
9
9
|
import { FilterToggle } from "./filter-toggle";
|
|
10
10
|
import { cn } from "./lib/utils";
|
|
11
|
+
import { Typography } from "./typography";
|
|
11
12
|
import { SearchHighlight } from "./use-search-highlight";
|
|
12
13
|
function CommandSearchEmptyIcon({ className }) {
|
|
13
14
|
return _jsx(SearchIcon, { className: className, size: 20 });
|
|
@@ -57,14 +58,14 @@ function CommandSearch({ value, onValueChange, sections, children, className, is
|
|
|
57
58
|
}
|
|
58
59
|
}, [isOpen]);
|
|
59
60
|
return (_jsxs("div", { className: className, ...props, children: [_jsxs(Button, { type: "button", onClick: () => setIsOpen(true), variant: "ghost", className: cn(isCollapsed
|
|
60
|
-
? "h-
|
|
61
|
-
: "h-
|
|
61
|
+
? "h-10 w-full justify-center rounded-lg px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"
|
|
62
|
+
: "h-10 w-full min-w-[14rem] justify-start gap-3 rounded-lg border border-gray-200 bg-white px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"), children: [_jsx(SearchIcon, { className: "shrink-0", size: 16 }), !isCollapsed ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex-1 text-left text-sm", children: triggerPlaceholder }), _jsx("kbd", { className: "hidden h-5 items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] text-muted-foreground sm:inline-flex", children: resolvedLabel })] })) : null] }), _jsx(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, children: _jsx(DialogSurface, { className: cn("max-w-xl gap-0 overflow-hidden p-0 sm:max-w-xl", dialogClassName), hideCloseButton: true, children: _jsxs(Command, { shouldFilter: false, className: "rounded-none border-0", children: [_jsx(CommandInput, { ref: inputRef, value: value, onValueChange: onValueChange, placeholder: inputPlaceholder, className: "text-sm" }), allFilter || filters.length ? (_jsxs("div", { className: "flex items-center gap-1 border-b px-3 py-2", children: [allFilter ? (_jsx(FilterToggle, { selected: allFilter.selected, onClick: allFilter.onSelect, children: allFilter.label })) : null, filters.map((filter) => (_jsx(FilterToggle, { selected: filter.selected, onClick: filter.onSelect, children: filter.label }, filter.value)))] })) : null, _jsx(CommandList, { className: cn("max-h-[400px] p-1", resultsClassName), children: children !== undefined ? children : sections ? (visibleSections.length ? (visibleSections.map((section, index) => (_jsxs(React.Fragment, { children: [index > 0 ? _jsx(CommandSeparator, { alwaysRender: true }) : null, _jsx(CommandGroup, { heading: section.heading, children: section.items.map((item) => (_jsx(CommandItem, { value: getCommandSearchItemValue(item), disabled: item.disabled, onSelect: () => {
|
|
62
63
|
var _a;
|
|
63
64
|
(_a = item.onSelect) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
64
65
|
if (item.closeOnSelect !== false) {
|
|
65
66
|
setIsOpen(false);
|
|
66
67
|
}
|
|
67
|
-
}, children: _jsxs("div", { className: "min-w-0", children: [_jsx("p",
|
|
68
|
+
}, children: _jsxs("div", { className: "min-w-0", children: [_jsx(Typography, { as: "p", variant: "label", className: "truncate", children: _jsx(SearchHighlight, { text: item.title, query: value }) }), item.subtitle ? (_jsx(Typography, { as: "p", variant: "caption", className: "truncate", children: _jsx(SearchHighlight, { text: item.subtitle, query: value }) })) : null] }) }, item.id))) })] }, section.key)))) : (_jsx(EmptyState, { icon: CommandSearchEmptyIcon, message: normalizedValue ? "No results found" : "Start typing to search", description: normalizedValue
|
|
68
69
|
? `No results found for "${value}".`
|
|
69
70
|
: "Results will appear here as you type." }))) : (_jsx(EmptyState, { icon: CommandSearchEmptyIcon, message: normalizedValue ? "No results found" : "Start typing to search", description: normalizedValue
|
|
70
71
|
? `No results found for "${value}".`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface DateInputProps {
|
|
3
|
+
label: React.ReactNode;
|
|
4
|
+
value: string;
|
|
5
|
+
onValueChange: (value: string) => void;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
error?: React.ReactNode;
|
|
8
|
+
invalid?: boolean;
|
|
9
|
+
hideLabel?: boolean;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
minDate?: Date;
|
|
13
|
+
maxDate?: Date;
|
|
14
|
+
className?: string;
|
|
15
|
+
triggerClassName?: string;
|
|
16
|
+
labelClassName?: string;
|
|
17
|
+
descriptionClassName?: string;
|
|
18
|
+
errorClassName?: string;
|
|
19
|
+
id?: string;
|
|
20
|
+
}
|
|
21
|
+
declare const DateInput: React.ForwardRefExoticComponent<DateInputProps & React.RefAttributes<HTMLButtonElement>>;
|
|
22
|
+
export { DateInput };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { format, parse } from "date-fns";
|
|
5
|
+
import { Calendar } from "./calendar";
|
|
6
|
+
import { inputControlClassName } from "./input-control";
|
|
7
|
+
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
8
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
|
|
9
|
+
import { cn } from "./lib/utils";
|
|
10
|
+
function parseDateString(dateStr) {
|
|
11
|
+
if (!(dateStr === null || dateStr === void 0 ? void 0 : dateStr.trim()))
|
|
12
|
+
return undefined;
|
|
13
|
+
try {
|
|
14
|
+
const nativeDate = new Date(dateStr);
|
|
15
|
+
if (!isNaN(nativeDate.getTime()))
|
|
16
|
+
return nativeDate;
|
|
17
|
+
const ddmmyyyyMatch = dateStr.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
|
|
18
|
+
if (ddmmyyyyMatch) {
|
|
19
|
+
const [, day, month, year] = ddmmyyyyMatch;
|
|
20
|
+
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
|
21
|
+
if (!isNaN(date.getTime()))
|
|
22
|
+
return date;
|
|
23
|
+
}
|
|
24
|
+
const date = parse(dateStr, "yyyy-MM-dd", new Date());
|
|
25
|
+
if (!isNaN(date.getTime()))
|
|
26
|
+
return date;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function formatISODate(date) {
|
|
34
|
+
return format(date, "yyyy-MM-dd");
|
|
35
|
+
}
|
|
36
|
+
const DateInput = React.forwardRef(({ label, value, onValueChange, description, error, invalid = false, hideLabel = false, placeholder = "Pick a date", disabled = false, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }, ref) => {
|
|
37
|
+
const [open, setOpen] = React.useState(false);
|
|
38
|
+
const generatedId = React.useId();
|
|
39
|
+
const inputId = id !== null && id !== void 0 ? id : `date-input-${generatedId}`;
|
|
40
|
+
const errorId = error ? `${inputId}-error` : undefined;
|
|
41
|
+
const showDescription = Boolean(description) && !error;
|
|
42
|
+
const descriptionId = showDescription ? `${inputId}-description` : undefined;
|
|
43
|
+
const isInvalid = invalid || Boolean(error);
|
|
44
|
+
const selectedDate = React.useMemo(() => parseDateString(value), [value]);
|
|
45
|
+
const displayValue = selectedDate
|
|
46
|
+
? format(selectedDate, "d MMM yyyy")
|
|
47
|
+
: undefined;
|
|
48
|
+
const handleSelect = (date) => {
|
|
49
|
+
onValueChange(date ? formatISODate(date) : "");
|
|
50
|
+
setOpen(false);
|
|
51
|
+
};
|
|
52
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: "relative w-full", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", style: { width: 14, height: 14 }, "aria-hidden": "true", children: [_jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", ry: "2" }), _jsx("line", { x1: "16", x2: "16", y1: "2", y2: "6" }), _jsx("line", { x1: "8", x2: "8", y1: "2", y2: "6" }), _jsx("line", { x1: "3", x2: "21", y1: "10", y2: "10" })] }), _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "cursor-pointer pl-9 text-left", !selectedDate && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: displayValue !== null && displayValue !== void 0 ? displayValue : _jsx("span", { children: placeholder }) })] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: (date) => {
|
|
53
|
+
if (minDate && date < minDate)
|
|
54
|
+
return true;
|
|
55
|
+
if (maxDate && date > maxDate)
|
|
56
|
+
return true;
|
|
57
|
+
return false;
|
|
58
|
+
}, defaultMonth: selectedDate, autoFocus: true }) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
59
|
+
});
|
|
60
|
+
DateInput.displayName = "DateInput";
|
|
61
|
+
export { DateInput };
|
package/dist/editable-table.js
CHANGED
|
@@ -101,7 +101,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
101
101
|
const cellValue = getNestedValue(row, column.path);
|
|
102
102
|
const isEditingCell = (editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
|
|
103
103
|
(editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === column.path;
|
|
104
|
-
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-
|
|
104
|
+
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-10 w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
|
|
105
105
|
cellValue === undefined ||
|
|
106
106
|
cellValue === ""
|
|
107
107
|
? "text-muted-foreground"
|
|
@@ -116,7 +116,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
116
116
|
insertRow: (nextRow, index = rowIndex + 1) => handleInsertRow(nextRow, index),
|
|
117
117
|
removeRow: () => handleDeleteRow(rowIndex),
|
|
118
118
|
})
|
|
119
|
-
: null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "
|
|
119
|
+
: null, isEditing ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "text-destructive hover:bg-destructive/10 hover:text-destructive", onClick: () => handleDeleteRow(rowIndex), "aria-label": `Delete row ${rowIndex + 1}`, children: _jsx(TrashIcon, { size: 16 }) })) : null] }) })) : null] }, `row-${rowIndex}`)))) })] }) }), isEditing ? (_jsxs(Button, { type: "button", variant: "outline", onClick: handleAddRow, className: "w-full justify-center", children: [_jsx(PlusIcon, { size: 16 }), "Add Row"] })) : null] }));
|
|
120
120
|
}
|
|
121
121
|
EditableTable.displayName = "EditableTable";
|
|
122
122
|
export { EditableTable };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface GovtMastheadProps extends React.HTMLAttributes<HTMLElement> {
|
|
3
|
+
fluid?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare function GovtMasthead({ fluid, ...props }: GovtMastheadProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare namespace GovtMasthead {
|
|
7
|
+
var displayName: string;
|
|
8
|
+
}
|
|
9
|
+
export { GovtMasthead };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { SgdsMasthead } from "@govtechsg/sgds-web-component/react";
|
|
4
|
+
function GovtMasthead({ fluid = false, ...props }) {
|
|
5
|
+
return _jsx(SgdsMasthead, { fluid: fluid, ...props });
|
|
6
|
+
}
|
|
7
|
+
GovtMasthead.displayName = "GovtMasthead";
|
|
8
|
+
export { GovtMasthead };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,12 @@ export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback, } from
|
|
|
2
2
|
export type { AvatarProps, AvatarProfileProps, AvatarRootProps, } from "./avatar";
|
|
3
3
|
export * from "./animated-icons";
|
|
4
4
|
export { Badge, badgeVariants } from "./badge";
|
|
5
|
+
export { Card } from "./card";
|
|
6
|
+
export type { CardProps } from "./card";
|
|
5
7
|
export type { BadgeProps } from "./badge";
|
|
8
|
+
export { Calendar, CalendarDayButton } from "./calendar";
|
|
9
|
+
export { DateInput } from "./date-input";
|
|
10
|
+
export type { DateInputProps } from "./date-input";
|
|
6
11
|
export { CountBadge } from "./count-badge";
|
|
7
12
|
export type { CountBadgeProps } from "./count-badge";
|
|
8
13
|
export { EmptyState } from "./empty-state";
|
|
@@ -15,6 +20,8 @@ export { Input } from "./input";
|
|
|
15
20
|
export type { InputProps } from "./input";
|
|
16
21
|
export { Select } from "./select";
|
|
17
22
|
export type { SelectOption, SelectProps } from "./select";
|
|
23
|
+
export { MultiSelect } from "./multi-select";
|
|
24
|
+
export type { MultiSelectOption, MultiSelectProps } from "./multi-select";
|
|
18
25
|
export { DEFAULT_COUNTRY_CODES, PhoneInput, } from "./phone-input";
|
|
19
26
|
export type { CountryCode, PhoneInputProps, } from "./phone-input";
|
|
20
27
|
export { OtpInput } from "./otp-input";
|
|
@@ -33,6 +40,8 @@ export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, Command
|
|
|
33
40
|
export { CommandSearch, type CommandSearchFilter, type CommandSearchItem, type CommandSearchProps, type CommandSearchSection, } from "./command-search";
|
|
34
41
|
export { SearchInput } from "./search-input";
|
|
35
42
|
export type { SearchInputProps } from "./search-input";
|
|
43
|
+
export { GovtMasthead } from "./govt-masthead";
|
|
44
|
+
export type { GovtMastheadProps } from "./govt-masthead";
|
|
36
45
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
37
46
|
export type { SearchHighlightProps, SearchHighlightSegment, } from "./use-search-highlight";
|
|
38
47
|
export { Textarea } from "./textarea";
|
|
@@ -54,5 +63,9 @@ export type { TableToolbarProps } from "./table-toolbar";
|
|
|
54
63
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
55
64
|
export type { TableColumn, TableProps, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
56
65
|
export { Tabs, TabsRoot, type TabsItem, type TabsProps, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
66
|
+
export { TabWithDropdown } from "./tab-with-dropdown";
|
|
67
|
+
export type { TabWithDropdownProps, TabDropdownSection } from "./tab-with-dropdown";
|
|
57
68
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
|
|
69
|
+
export { Toaster, toast } from "./toaster";
|
|
70
|
+
export type { ToasterProps } from "./toaster";
|
|
58
71
|
export { cn } from "./lib/utils";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback, } from "./avatar";
|
|
2
2
|
export * from "./animated-icons";
|
|
3
3
|
export { Badge, badgeVariants } from "./badge";
|
|
4
|
+
export { Card } from "./card";
|
|
5
|
+
export { Calendar, CalendarDayButton } from "./calendar";
|
|
6
|
+
export { DateInput } from "./date-input";
|
|
4
7
|
export { CountBadge } from "./count-badge";
|
|
5
8
|
export { EmptyState } from "./empty-state";
|
|
6
9
|
export { EditableTable } from "./editable-table";
|
|
7
10
|
export { EmailInput } from "./email-input";
|
|
8
11
|
export { Input } from "./input";
|
|
9
12
|
export { Select } from "./select";
|
|
13
|
+
export { MultiSelect } from "./multi-select";
|
|
10
14
|
export { DEFAULT_COUNTRY_CODES, PhoneInput, } from "./phone-input";
|
|
11
15
|
export { OtpInput } from "./otp-input";
|
|
12
16
|
export { LabelValue, isEmptyValue, } from "./label-value";
|
|
@@ -17,6 +21,7 @@ export { Dialog } from "./dialog";
|
|
|
17
21
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
18
22
|
export { CommandSearch, } from "./command-search";
|
|
19
23
|
export { SearchInput } from "./search-input";
|
|
24
|
+
export { GovtMasthead } from "./govt-masthead";
|
|
20
25
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
21
26
|
export { Textarea } from "./textarea";
|
|
22
27
|
export { DraggableTabs, } from "./draggable-tabs";
|
|
@@ -30,5 +35,7 @@ export { Pagination } from "./pagination";
|
|
|
30
35
|
export { TableToolbar } from "./table-toolbar";
|
|
31
36
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
32
37
|
export { Tabs, TabsRoot, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
|
|
38
|
+
export { TabWithDropdown } from "./tab-with-dropdown";
|
|
33
39
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, } from "./tooltip";
|
|
40
|
+
export { Toaster, toast } from "./toaster";
|
|
34
41
|
export { cn } from "./lib/utils";
|
package/dist/input-control.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
declare const inputControlClassName = "h-
|
|
2
|
+
declare const inputControlClassName = "h-10 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 md:text-sm";
|
|
3
3
|
declare const InputControl: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
4
4
|
export { InputControl, inputControlClassName };
|
package/dist/input-control.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cn } from "./lib/utils";
|
|
4
|
-
const inputControlClassName = "h-
|
|
4
|
+
const inputControlClassName = "h-10 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-8 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 md:text-sm";
|
|
5
5
|
const InputControl = React.forwardRef(({ className, type = "text", ...props }, ref) => (_jsx("input", { ref: ref, type: type, "data-slot": "input", className: cn(inputControlClassName, className), ...props })));
|
|
6
6
|
InputControl.displayName = "InputControl";
|
|
7
7
|
export { InputControl, inputControlClassName };
|
package/dist/label-value.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "./lib/utils";
|
|
3
|
+
import { Typography } from "./typography";
|
|
3
4
|
export function isEmptyValue(value) {
|
|
4
5
|
if (value === null || value === undefined || value === "")
|
|
5
6
|
return true;
|
|
@@ -14,6 +15,6 @@ function LabelValue({ label, value, className, labelClassName, hideIfEmpty = fal
|
|
|
14
15
|
if (hideIfEmpty && empty) {
|
|
15
16
|
return null;
|
|
16
17
|
}
|
|
17
|
-
return (_jsxs("div", { className: cn("min-w-0 h-full space-y-1", className), children: [_jsx(
|
|
18
|
+
return (_jsxs("div", { className: cn("min-w-0 h-full space-y-1", className), children: [_jsx(Typography, { as: "p", variant: "label", className: labelClassName, children: label }), _jsx("div", { className: cn("min-w-0 break-words text-sm text-foreground", empty && "italic text-muted-foreground/60"), children: empty ? "-" : value })] }));
|
|
18
19
|
}
|
|
19
20
|
export { LabelValue };
|
package/dist/layout.d.ts
CHANGED
|
@@ -9,8 +9,10 @@ export declare function SidebarProvider({ children }: {
|
|
|
9
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
export declare function useSidebar(): SidebarContextType;
|
|
11
11
|
export interface DashboardLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
masthead?: React.ReactNode;
|
|
13
|
+
prototypeBanner?: React.ReactNode;
|
|
12
14
|
}
|
|
13
|
-
declare function DashboardLayout({ className, children, ...props }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare function DashboardLayout({ className, masthead, prototypeBanner, children, style, ...props }: DashboardLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
14
16
|
export interface DashboardSidebarProps extends React.HTMLAttributes<HTMLElement> {
|
|
15
17
|
logo?: React.ReactNode | ((context: {
|
|
16
18
|
isCollapsed: boolean;
|
package/dist/layout.js
CHANGED
|
@@ -9,7 +9,9 @@ import { CountBadge } from "./count-badge";
|
|
|
9
9
|
import { Tooltip } from "./tooltip";
|
|
10
10
|
import { cn } from "./lib/utils";
|
|
11
11
|
const COLLAPSE_BREAKPOINT = 1280;
|
|
12
|
+
const TOP_OFFSET_CSS_VAR = "--layout-top-offset";
|
|
12
13
|
const SidebarContext = React.createContext(undefined);
|
|
14
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
13
15
|
export function SidebarProvider({ children }) {
|
|
14
16
|
const [isCollapsed, setIsCollapsed] = React.useState(false);
|
|
15
17
|
const manualCollapsedRef = React.useRef(false);
|
|
@@ -42,11 +44,35 @@ export function useSidebar() {
|
|
|
42
44
|
}
|
|
43
45
|
return context;
|
|
44
46
|
}
|
|
45
|
-
function DashboardLayout({ className, children, ...props }) {
|
|
46
|
-
|
|
47
|
+
function DashboardLayout({ className, masthead, prototypeBanner, children, style, ...props }) {
|
|
48
|
+
const chromeRef = React.useRef(null);
|
|
49
|
+
const [topOffset, setTopOffset] = React.useState(0);
|
|
50
|
+
const layoutStyle = React.useMemo(() => ({
|
|
51
|
+
...style,
|
|
52
|
+
[TOP_OFFSET_CSS_VAR]: `${topOffset}px`,
|
|
53
|
+
}), [style, topOffset]);
|
|
54
|
+
useIsomorphicLayoutEffect(() => {
|
|
55
|
+
const node = chromeRef.current;
|
|
56
|
+
if (!node) {
|
|
57
|
+
setTopOffset(0);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const updateOffset = () => {
|
|
61
|
+
setTopOffset(node.getBoundingClientRect().height);
|
|
62
|
+
};
|
|
63
|
+
updateOffset();
|
|
64
|
+
if (typeof ResizeObserver === "undefined") {
|
|
65
|
+
window.addEventListener("resize", updateOffset);
|
|
66
|
+
return () => window.removeEventListener("resize", updateOffset);
|
|
67
|
+
}
|
|
68
|
+
const observer = new ResizeObserver(() => updateOffset());
|
|
69
|
+
observer.observe(node);
|
|
70
|
+
return () => observer.disconnect();
|
|
71
|
+
}, [masthead, prototypeBanner]);
|
|
72
|
+
return (_jsxs("div", { className: cn("flex min-h-screen flex-col bg-[hsl(var(--layout-shell-background))]", className), style: layoutStyle, ...props, children: [masthead || prototypeBanner ? (_jsxs("div", { ref: chromeRef, className: "sticky top-0 z-40 shrink-0", children: [masthead, prototypeBanner] })) : null, _jsx("div", { className: "flex min-h-0 flex-1", children: children })] }));
|
|
47
73
|
}
|
|
48
74
|
function SidebarShell({ isCollapsed, className, children, ...props }) {
|
|
49
|
-
return (_jsx("aside", { className: cn("fixed left-0 top-
|
|
75
|
+
return (_jsx("aside", { className: cn("fixed left-0 top-[var(--layout-top-offset)] z-30 flex h-[calc(100dvh-var(--layout-top-offset))] shrink-0 flex-col overflow-hidden bg-[hsl(var(--layout-shell-background))] pb-2 pl-[var(--layout-sidebar-padding-inline)] pt-[var(--layout-sidebar-padding-top)] transition-all duration-300 ease-in-out", isCollapsed
|
|
50
76
|
? "w-[var(--layout-sidebar-collapsed-width)]"
|
|
51
77
|
: "w-[var(--layout-sidebar-width)]", className), ...props, children: children }));
|
|
52
78
|
}
|
|
@@ -72,7 +98,7 @@ function SidebarMenuItem({ className, children, }) {
|
|
|
72
98
|
return _jsx("li", { className: className, children: children });
|
|
73
99
|
}
|
|
74
100
|
function SidebarMenuButton({ active = false, collapsed = false, disabled = false, className, asChild = false, children, ...props }) {
|
|
75
|
-
return (_jsx(Button, { asChild: asChild, variant: "ghost", disabled: disabled, className: cn("h-
|
|
101
|
+
return (_jsx(Button, { asChild: asChild, variant: "ghost", disabled: disabled, className: cn("h-10 w-full justify-start gap-3 rounded-lg text-sm font-medium shadow-none", collapsed ? "justify-center px-3" : "px-3", disabled
|
|
76
102
|
? "text-muted-foreground/50 hover:bg-transparent hover:text-muted-foreground/50"
|
|
77
103
|
: active
|
|
78
104
|
? "bg-white text-foreground hover:bg-white hover:text-foreground"
|
|
@@ -133,7 +159,7 @@ function DashboardContent({ className, surfaceClassName, children, ...props }) {
|
|
|
133
159
|
toggle();
|
|
134
160
|
}
|
|
135
161
|
}, [isCollapsed, toggle]);
|
|
136
|
-
return (_jsx("main", { onClick: handleContentClick, className: cn("flex min-w-0 flex-1 flex-col bg-[hsl(var(--layout-shell-background))] pb-[var(--layout-content-padding)] pl-[var(--layout-content-gap-start)] pr-[var(--layout-content-padding)] pt-[var(--layout-content-padding)] transition-all duration-300 md:pb-[var(--layout-content-padding-md)] md:pl-[var(--layout-content-gap-start-md)] md:pr-[var(--layout-content-padding-md)] md:pt-[var(--layout-content-padding-md)] lg:pb-[var(--layout-content-padding-lg)] lg:pl-[var(--layout-content-gap-start-lg)] lg:pr-[var(--layout-content-padding-lg)] lg:pt-[var(--layout-content-padding-lg)]", isCollapsed
|
|
162
|
+
return (_jsx("main", { onClick: handleContentClick, className: cn("flex min-h-[calc(100dvh-var(--layout-top-offset))] min-w-0 flex-1 flex-col bg-[hsl(var(--layout-shell-background))] pb-[var(--layout-content-padding)] pl-[var(--layout-content-gap-start)] pr-[var(--layout-content-padding)] pt-[var(--layout-content-padding)] transition-all duration-300 md:pb-[var(--layout-content-padding-md)] md:pl-[var(--layout-content-gap-start-md)] md:pr-[var(--layout-content-padding-md)] md:pt-[var(--layout-content-padding-md)] lg:pb-[var(--layout-content-padding-lg)] lg:pl-[var(--layout-content-gap-start-lg)] lg:pr-[var(--layout-content-padding-lg)] lg:pt-[var(--layout-content-padding-lg)]", isCollapsed
|
|
137
163
|
? "ml-[var(--layout-sidebar-collapsed-width)]"
|
|
138
164
|
: "ml-[var(--layout-sidebar-width)]", className), ...props, children: _jsx("div", { className: cn("flex flex-1 flex-col gap-[var(--layout-surface-gap)] overflow-x-clip rounded-[var(--radius-lg)] bg-background p-[var(--layout-surface-padding)] shadow-sm md:p-[var(--layout-surface-padding-md)] lg:p-[var(--layout-surface-padding-lg)]", surfaceClassName), children: children }) }));
|
|
139
165
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface MultiSelectOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface MultiSelectProps {
|
|
9
|
+
label: React.ReactNode;
|
|
10
|
+
options: MultiSelectOption[];
|
|
11
|
+
value: string[];
|
|
12
|
+
onValueChange: (value: string[]) => void;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
description?: React.ReactNode;
|
|
15
|
+
error?: React.ReactNode;
|
|
16
|
+
invalid?: boolean;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
hideLabel?: boolean;
|
|
19
|
+
searchable?: boolean;
|
|
20
|
+
searchPlaceholder?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
triggerClassName?: string;
|
|
23
|
+
labelClassName?: string;
|
|
24
|
+
descriptionClassName?: string;
|
|
25
|
+
errorClassName?: string;
|
|
26
|
+
id?: string;
|
|
27
|
+
}
|
|
28
|
+
declare function MultiSelect({ label, options, value, onValueChange, placeholder, description, error, invalid, disabled, hideLabel, searchable, searchPlaceholder, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export { MultiSelect };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { XIcon } from "./animated-icons/x";
|
|
5
|
+
import { Badge } from "./badge";
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
8
|
+
import { InputControl } from "./input-control";
|
|
9
|
+
import { cn } from "./lib/utils";
|
|
10
|
+
import { Typography } from "./typography";
|
|
11
|
+
function MultiSelect({ label, options, value, onValueChange, placeholder = "Select options", description, error, invalid = false, disabled = false, hideLabel = false, searchable = false, searchPlaceholder = "Search...", className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, }) {
|
|
12
|
+
const generatedId = React.useId();
|
|
13
|
+
const selectId = id !== null && id !== void 0 ? id : `multi-select-${generatedId}`;
|
|
14
|
+
const errorId = error ? `${selectId}-error` : undefined;
|
|
15
|
+
const showDescription = Boolean(description) && !error;
|
|
16
|
+
const descriptionId = showDescription ? `${selectId}-description` : undefined;
|
|
17
|
+
const isInvalid = invalid || Boolean(error);
|
|
18
|
+
const [open, setOpen] = React.useState(false);
|
|
19
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
20
|
+
const containerRef = React.useRef(null);
|
|
21
|
+
const searchInputRef = React.useRef(null);
|
|
22
|
+
const normalizedQuery = searchQuery.trim().toLowerCase();
|
|
23
|
+
const filteredOptions = searchable && normalizedQuery
|
|
24
|
+
? options.filter((opt) => {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
return opt.label.toLowerCase().includes(normalizedQuery) ||
|
|
27
|
+
((_b = (_a = opt.description) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(normalizedQuery)) !== null && _b !== void 0 ? _b : false);
|
|
28
|
+
})
|
|
29
|
+
: options;
|
|
30
|
+
const selectedLabels = value
|
|
31
|
+
.map((v) => options.find((opt) => opt.value === v))
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
const toggleOption = React.useCallback((optionValue) => {
|
|
34
|
+
const next = value.includes(optionValue)
|
|
35
|
+
? value.filter((v) => v !== optionValue)
|
|
36
|
+
: [...value, optionValue];
|
|
37
|
+
onValueChange(next);
|
|
38
|
+
}, [value, onValueChange]);
|
|
39
|
+
const removeOption = React.useCallback((optionValue) => {
|
|
40
|
+
onValueChange(value.filter((v) => v !== optionValue));
|
|
41
|
+
}, [value, onValueChange]);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
if (!open) {
|
|
44
|
+
setSearchQuery("");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (searchable) {
|
|
48
|
+
const frame = window.requestAnimationFrame(() => {
|
|
49
|
+
var _a;
|
|
50
|
+
(_a = searchInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
51
|
+
});
|
|
52
|
+
return () => window.cancelAnimationFrame(frame);
|
|
53
|
+
}
|
|
54
|
+
}, [open, searchable]);
|
|
55
|
+
React.useEffect(() => {
|
|
56
|
+
const handleClickOutside = (event) => {
|
|
57
|
+
if (containerRef.current &&
|
|
58
|
+
!containerRef.current.contains(event.target)) {
|
|
59
|
+
setOpen(false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (open) {
|
|
63
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
64
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
65
|
+
}
|
|
66
|
+
}, [open]);
|
|
67
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: selectId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs("div", { ref: containerRef, className: "relative", children: [_jsx("button", { type: "button", id: selectId, disabled: disabled, onClick: () => setOpen((prev) => !prev), "aria-expanded": open, "aria-haspopup": "listbox", "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("flex min-h-10 w-full flex-wrap items-center gap-1.5 rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background md:text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", isInvalid ? "border-destructive" : "border-input", triggerClassName), children: selectedLabels.length > 0 ? (selectedLabels.map((opt) => (_jsxs(Badge, { variant: "secondary", className: "gap-1 pr-1", children: [opt.label, _jsx(Button, { variant: "ghost", size: "icon", className: "h-4 w-4 p-0 hover:bg-transparent", onClick: (e) => {
|
|
68
|
+
e.stopPropagation();
|
|
69
|
+
removeOption(opt.value);
|
|
70
|
+
}, "aria-label": `Remove ${opt.label}`, children: _jsx(XIcon, { size: 10 }) })] }, opt.value)))) : (_jsx("span", { className: "text-muted-foreground", children: placeholder })) }), open ? (_jsxs("div", { className: "absolute z-50 mt-1 w-full rounded-md border bg-popover shadow-md", children: [searchable ? (_jsx("div", { className: "border-b p-2", children: _jsx(InputControl, { ref: searchInputRef, value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: searchPlaceholder, className: "h-8 border-0 bg-transparent px-2 py-0 text-sm shadow-none focus-visible:ring-0", onKeyDown: (e) => e.stopPropagation() }) })) : null, _jsx("div", { role: "listbox", "aria-label": typeof label === "string" ? label : "Options", "aria-multiselectable": "true", className: "max-h-64 overflow-y-auto p-1", children: filteredOptions.length > 0 ? (filteredOptions.map((option) => {
|
|
71
|
+
const isSelected = value.includes(option.value);
|
|
72
|
+
return (_jsxs("button", { type: "button", role: "option", "aria-selected": isSelected, disabled: option.disabled, onClick: () => toggleOption(option.value), className: cn("flex h-10 w-full cursor-pointer items-center gap-2 rounded-sm px-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50", isSelected && "bg-accent"), children: [_jsx("div", { className: cn("mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border", isSelected
|
|
73
|
+
? "border-primary bg-primary text-primary-foreground"
|
|
74
|
+
: "border-input"), children: isSelected ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", className: "h-3 w-3", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) : null }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { children: option.label }), option.description ? (_jsx(Typography, { as: "span", variant: "caption", children: option.description })) : null] })] }, option.value));
|
|
75
|
+
})) : (_jsx("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "No options found." })) })] })) : null] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
76
|
+
}
|
|
77
|
+
export { MultiSelect };
|
package/dist/otp-input.js
CHANGED
|
@@ -7,7 +7,7 @@ import { validateOtp } from "./input-validation";
|
|
|
7
7
|
import { cn } from "./lib/utils";
|
|
8
8
|
function OtpSlot({ slot, invalid, className, }) {
|
|
9
9
|
var _a, _b;
|
|
10
|
-
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-
|
|
10
|
+
return (_jsxs("div", { "data-slot": "otp-slot", className: cn("relative flex size-10 items-center justify-center rounded-md border bg-transparent text-sm font-medium transition-[border-color,box-shadow,color] outline-none group-data-[disabled=true]/field:cursor-not-allowed group-data-[disabled=true]/field:bg-muted/30 group-data-[disabled=true]/field:text-muted-foreground group-data-[disabled=true]/field:opacity-50", invalid ? "border-destructive" : "border-input", slot.isActive &&
|
|
11
11
|
(invalid
|
|
12
12
|
? "border-destructive ring-[3px] ring-destructive/20"
|
|
13
13
|
: "border-ring ring-[3px] ring-ring/50"), className), children: [_jsx("span", { className: cn("pointer-events-none", !slot.char && slot.placeholderChar ? "text-muted-foreground" : ""), children: (_b = (_a = slot.char) !== null && _a !== void 0 ? _a : slot.placeholderChar) !== null && _b !== void 0 ? _b : "" }), slot.hasFakeCaret ? (_jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("span", { className: "h-4 w-px animate-pulse bg-foreground" }) })) : null] }));
|
|
@@ -54,7 +54,7 @@ const OtpInput = React.forwardRef(({ label, value, onValueChange, description, e
|
|
|
54
54
|
setInternalError(validate(value));
|
|
55
55
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
|
|
56
56
|
}, [onBlur, validate, value]);
|
|
57
|
-
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(OTPInput, { ref: ref, id: inputId, value: value, onChange: handleChange, onBlur: handleBlur, disabled: disabled, maxLength: length, autoComplete: autoComplete, inputMode: inputMode, pattern: pattern, pushPasswordManagerStrategy: pushPasswordManagerStrategy, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, containerClassName: cn("flex w-full items-center gap-2", groupClassName), render: ({ slots }) => slots.map((slot, index) => (_jsx(OtpSlot, { slot: slot, invalid: isInvalid, className: slotClassName }, `${inputId}-${index}`))), ...props }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: displayError })] }));
|
|
57
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsx(OTPInput, { ref: ref, id: inputId, value: value, onChange: handleChange, onBlur: handleBlur, disabled: disabled, maxLength: length, autoComplete: autoComplete, inputMode: inputMode, pattern: pattern, pushPasswordManagerStrategy: pushPasswordManagerStrategy, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": describedBy, containerClassName: cn("flex w-full items-center justify-center gap-2", groupClassName), render: ({ slots }) => slots.map((slot, index) => (_jsx(OtpSlot, { slot: slot, invalid: isInvalid, className: slotClassName }, `${inputId}-${index}`))), ...props }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: displayError })] }));
|
|
58
58
|
});
|
|
59
59
|
OtpInput.displayName = "OtpInput";
|
|
60
60
|
export { OtpInput };
|
package/dist/pagination.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ChevronRightIcon } from "./animated-icons/chevron-right";
|
|
|
6
6
|
import { Button } from "./button";
|
|
7
7
|
import { SelectContent, SelectItem, SelectRoot, SelectTrigger, SelectValue, } from "./select-primitive";
|
|
8
8
|
import { cn } from "./lib/utils";
|
|
9
|
+
import { Typography } from "./typography";
|
|
9
10
|
const PaginationNav = React.forwardRef(({ className, ...props }, ref) => (_jsx("nav", { ref: ref, role: "navigation", "aria-label": "pagination", className: cn("flex w-full justify-center", className), ...props })));
|
|
10
11
|
PaginationNav.displayName = "PaginationNav";
|
|
11
12
|
const PaginationContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("ul", { ref: ref, className: cn("flex flex-row items-center gap-1", className), ...props })));
|
|
@@ -16,7 +17,7 @@ function Pagination({ currentPage, totalPages, totalItems, itemsPerPage = 5, onP
|
|
|
16
17
|
const normalizedTotalPages = totalPages || 1;
|
|
17
18
|
const startItem = totalItems === 0 ? 0 : (currentPage - 1) * itemsPerPage + 1;
|
|
18
19
|
const endItem = Math.min(currentPage * itemsPerPage, totalItems);
|
|
19
|
-
return (_jsxs("div", { className: cn("flex items-center justify-between gap-6", className), ...props, children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { className: "flex items-center gap-6", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(
|
|
20
|
+
return (_jsxs("div", { className: cn("flex items-center justify-between gap-6", className), ...props, children: [_jsxs("div", { className: "text-sm text-muted-foreground", children: ["Showing ", startItem, "-", endItem, " out of ", totalItems] }), _jsxs("div", { className: "flex items-center gap-6", children: [onItemsPerPageChange ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Typography, { as: "span", variant: "caption", children: "Rows per page" }), _jsxs(SelectRoot, { value: itemsPerPage.toString(), onValueChange: (value) => {
|
|
20
21
|
onItemsPerPageChange(Number(value));
|
|
21
22
|
onPageChange(1);
|
|
22
23
|
}, children: [_jsx(SelectTrigger, { className: "h-8 w-[70px] text-sm", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: itemsPerPageOptions.map((option) => (_jsx(SelectItem, { value: option.toString(), children: option }, option))) })] })] })) : null, _jsxs("div", { className: "text-sm text-muted-foreground", children: ["Page ", currentPage, " of ", normalizedTotalPages] }), _jsx(PaginationNav, { className: "mx-0 w-auto justify-start", children: _jsxs(PaginationContent, { children: [_jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8", onClick: () => onPageChange(1), disabled: currentPage === 1, "aria-label": "Go to first page", children: _jsx(ChevronsLeft, { className: "h-4 w-4" }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8", onClick: () => onPageChange(Math.max(1, currentPage - 1)), disabled: currentPage === 1, "aria-label": "Go to previous page", children: _jsx(ChevronLeftIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8", onClick: () => onPageChange(Math.min(normalizedTotalPages, currentPage + 1)), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to next page", children: _jsx(ChevronRightIcon, { size: 16 }) }) }), _jsx(PaginationItem, { children: _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8", onClick: () => onPageChange(normalizedTotalPages), disabled: currentPage === normalizedTotalPages || totalPages === 0, "aria-label": "Go to last page", children: _jsx(ChevronsRight, { className: "h-4 w-4" }) }) })] }) })] })] }));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
3
|
+
declare const Popover: React.FC<PopoverPrimitive.PopoverProps>;
|
|
4
|
+
declare const PopoverTrigger: React.ForwardRefExoticComponent<PopoverPrimitive.PopoverTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
declare const PopoverAnchor: React.ForwardRefExoticComponent<PopoverPrimitive.PopoverAnchorProps & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
declare const PopoverContent: React.ForwardRefExoticComponent<Omit<PopoverPrimitive.PopoverContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
package/dist/popover.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
5
|
+
import { cn } from "./lib/utils";
|
|
6
|
+
const Popover = PopoverPrimitive.Root;
|
|
7
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
8
|
+
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
9
|
+
const PopoverContent = React.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { ref: ref, align: align, sideOffset: sideOffset, className: cn("z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) })));
|
|
10
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
11
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
|
@@ -12,6 +12,8 @@ interface SelectContentProps extends React.ComponentPropsWithoutRef<typeof Selec
|
|
|
12
12
|
}
|
|
13
13
|
declare const SelectContent: React.ForwardRefExoticComponent<SelectContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
14
14
|
declare const SelectLabel: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectLabelProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
15
|
-
declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> &
|
|
15
|
+
declare const SelectItem: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
16
|
+
description?: React.ReactNode;
|
|
17
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
16
18
|
declare const SelectSeparator: React.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectSeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
17
19
|
export { SelectContent, SelectGroup, SelectItem, SelectLabel, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
|
package/dist/select-primitive.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
5
5
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
6
6
|
import { cn } from "./lib/utils";
|
|
7
|
+
import { Typography } from "./typography";
|
|
7
8
|
function SelectRoot(props) {
|
|
8
9
|
return _jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
9
10
|
}
|
|
@@ -13,7 +14,7 @@ function SelectGroup(props) {
|
|
|
13
14
|
function SelectValue(props) {
|
|
14
15
|
return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
15
16
|
}
|
|
16
|
-
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-
|
|
17
|
+
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-10 w-full cursor-pointer items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-base transition-[color,box-shadow] md:text-sm outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 data-[placeholder]:text-muted-foreground [&>span]:line-clamp-1 [&_svg]:pointer-events-none [&_svg]:shrink-0", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" }) })] })));
|
|
17
18
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
18
19
|
const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.ScrollUpButton, { ref: ref, "data-slot": "select-scroll-up-button", className: cn("flex cursor-pointer items-center justify-center py-1", className), ...props, children: _jsx(ChevronUp, { className: "h-4 w-4" }) })));
|
|
19
20
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
@@ -26,7 +27,7 @@ const SelectContent = React.forwardRef(({ className, children, header, position
|
|
|
26
27
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
27
28
|
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Label, { ref: ref, "data-slot": "select-label", className: cn("px-2 py-1.5 text-xs text-muted-foreground", className), ...props })));
|
|
28
29
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
29
|
-
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex w-full cursor-pointer select-none items-center gap-2 rounded-sm
|
|
30
|
+
const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => (_jsxs(SelectPrimitive.Item, { ref: ref, "data-slot": "select-item", className: cn("relative flex h-10 w-full cursor-pointer select-none items-center gap-2 rounded-sm pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props, children: [_jsx("span", { "data-slot": "select-item-indicator", className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "h-4 w-4" }) }) }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(SelectPrimitive.ItemText, { className: "break-words font-normal", children: children }), description ? (_jsx(Typography, { as: "span", variant: "caption", children: description })) : null] })] })));
|
|
30
31
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
31
32
|
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx(SelectPrimitive.Separator, { ref: ref, "data-slot": "select-separator", className: cn("-mx-1 my-1 h-px bg-border", className), ...props })));
|
|
32
33
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
package/dist/select.d.ts
CHANGED
package/dist/select.js
CHANGED
|
@@ -91,7 +91,7 @@ function Select({ label, options, placeholder = "Select an option", description,
|
|
|
91
91
|
event.stopPropagation();
|
|
92
92
|
} })) : undefined, viewportClassName: searchable ? "max-h-64" : undefined, children: hasVisibleOptions ? (optionGroups.map((group, groupIndex) => {
|
|
93
93
|
var _a;
|
|
94
|
-
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) => (_jsx(SelectItem, { value: option.value, disabled: option.disabled, textValue: getOptionTextValue(option), children: renderHighlightedLabel(option.label, searchQuery) }, option.value)))] }), groupIndex < optionGroups.length - 1 ? _jsx(SelectSeparator, {}) : null] }, (_a = group.group) !== null && _a !== void 0 ? _a : `group-${groupIndex}`));
|
|
94
|
+
return (_jsxs(React.Fragment, { children: [_jsxs(SelectGroup, { children: [group.group ? (_jsx(SelectLabel, { children: _jsx(SearchHighlight, { text: group.group, query: searchQuery }) })) : null, group.options.map((option) => (_jsx(SelectItem, { value: option.value, disabled: option.disabled, textValue: getOptionTextValue(option), description: option.description, children: renderHighlightedLabel(option.label, searchQuery) }, option.value)))] }), groupIndex < optionGroups.length - 1 ? _jsx(SelectSeparator, {}) : null] }, (_a = group.group) !== null && _a !== void 0 ? _a : `group-${groupIndex}`));
|
|
95
95
|
})) : (_jsx("div", { className: "px-3 py-6 text-sm text-muted-foreground", children: searchEmptyMessage })) })] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
96
96
|
}
|
|
97
97
|
export { Select };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface TabDropdownSection {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export interface TabWithDropdownProps {
|
|
6
|
+
/** Tab value — must match a TabsContent value. */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Tab label shown in the trigger. */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Dropdown sections shown on hover. */
|
|
11
|
+
sections: TabDropdownSection[];
|
|
12
|
+
/** Called when a section is selected. Receives the section id. */
|
|
13
|
+
onSectionSelect?: (sectionId: string) => void;
|
|
14
|
+
/** Scroll offset in pixels when scrolling to a section. */
|
|
15
|
+
scrollOffset?: number;
|
|
16
|
+
}
|
|
17
|
+
declare function TabWithDropdown({ value, label, sections, onSectionSelect, scrollOffset, }: TabWithDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export { TabWithDropdown };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as ReactDOM from "react-dom";
|
|
5
|
+
import { ChevronDownIcon } from "./animated-icons/chevron-down";
|
|
6
|
+
import { cn } from "./lib/utils";
|
|
7
|
+
import { TabsTrigger, useTabsContext } from "./tabs";
|
|
8
|
+
function TabWithDropdown({ value, label, sections, onSectionSelect, scrollOffset = 200, }) {
|
|
9
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
10
|
+
const [dropdownPosition, setDropdownPosition] = React.useState({
|
|
11
|
+
top: 0,
|
|
12
|
+
left: 0,
|
|
13
|
+
});
|
|
14
|
+
const triggerRef = React.useRef(null);
|
|
15
|
+
const timeoutRef = React.useRef(null);
|
|
16
|
+
const tabsContext = useTabsContext();
|
|
17
|
+
const updatePosition = React.useCallback(() => {
|
|
18
|
+
if (triggerRef.current) {
|
|
19
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
20
|
+
setDropdownPosition({
|
|
21
|
+
top: rect.bottom + 8,
|
|
22
|
+
left: rect.left,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
const handleMouseEnter = () => {
|
|
27
|
+
if (timeoutRef.current)
|
|
28
|
+
clearTimeout(timeoutRef.current);
|
|
29
|
+
updatePosition();
|
|
30
|
+
setIsOpen(true);
|
|
31
|
+
};
|
|
32
|
+
const handleMouseLeave = () => {
|
|
33
|
+
timeoutRef.current = setTimeout(() => setIsOpen(false), 150);
|
|
34
|
+
};
|
|
35
|
+
const handleDropdownMouseEnter = () => {
|
|
36
|
+
if (timeoutRef.current)
|
|
37
|
+
clearTimeout(timeoutRef.current);
|
|
38
|
+
};
|
|
39
|
+
const handleDropdownMouseLeave = () => {
|
|
40
|
+
timeoutRef.current = setTimeout(() => setIsOpen(false), 150);
|
|
41
|
+
};
|
|
42
|
+
const handleSectionClick = (sectionId) => {
|
|
43
|
+
if (onSectionSelect) {
|
|
44
|
+
onSectionSelect(sectionId);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Default: switch tab and scroll to the section element
|
|
48
|
+
const doScroll = () => {
|
|
49
|
+
const element = document.getElementById(sectionId);
|
|
50
|
+
if (!element)
|
|
51
|
+
return;
|
|
52
|
+
const top = element.getBoundingClientRect().top + window.scrollY - scrollOffset;
|
|
53
|
+
window.scrollTo({ top, behavior: "smooth" });
|
|
54
|
+
};
|
|
55
|
+
if (tabsContext && tabsContext.value !== value) {
|
|
56
|
+
tabsContext.setValue(value);
|
|
57
|
+
setTimeout(doScroll, 50);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
doScroll();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
setIsOpen(false);
|
|
64
|
+
};
|
|
65
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: triggerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: _jsxs(TabsTrigger, { value: value, className: "flex items-center gap-1", children: [label, sections.length > 0 ? (_jsx(ChevronDownIcon, { className: cn("transition-transform duration-200", isOpen && "rotate-180"), size: 12 })) : null] }) }), isOpen &&
|
|
66
|
+
sections.length > 0 &&
|
|
67
|
+
typeof document !== "undefined" &&
|
|
68
|
+
ReactDOM.createPortal(_jsx("div", { className: "fixed z-[100] rounded-md border bg-popover p-1 shadow-lg animate-in fade-in-0 zoom-in-95", style: { top: dropdownPosition.top, left: dropdownPosition.left }, onMouseEnter: handleDropdownMouseEnter, onMouseLeave: handleDropdownMouseLeave, children: sections.map((section) => (_jsx("button", { type: "button", onClick: () => handleSectionClick(section.id), className: "block w-full rounded-sm px-3 py-2 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground", children: section.label }, section.id))) }), document.body)] }));
|
|
69
|
+
}
|
|
70
|
+
export { TabWithDropdown };
|
package/dist/textarea.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
4
4
|
import { cn } from "./lib/utils";
|
|
5
|
-
const TextareaControl = React.forwardRef(({ className, ...props }, ref) => (_jsx("textarea", { ref: ref, "data-slot": "textarea", className: cn("flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base
|
|
5
|
+
const TextareaControl = React.forwardRef(({ className, ...props }, ref) => (_jsx("textarea", { ref: ref, "data-slot": "textarea", className: cn("flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/20 md:text-sm", className), ...props })));
|
|
6
6
|
TextareaControl.displayName = "TextareaControl";
|
|
7
7
|
const Textarea = React.forwardRef(({ label, description, error, invalid = false, hideLabel = false, className, textareaClassName, labelClassName, descriptionClassName, errorClassName, id, disabled, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, ...props }, ref) => {
|
|
8
8
|
const generatedId = React.useId();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { toast } from "sonner";
|
|
2
|
+
export interface ToasterProps {
|
|
3
|
+
/** Position of the toast container. */
|
|
4
|
+
position?: "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
|
|
5
|
+
/** Maximum number of toasts visible at once. */
|
|
6
|
+
visibleToasts?: number;
|
|
7
|
+
/** Whether to show the close button on each toast. */
|
|
8
|
+
closeButton?: boolean;
|
|
9
|
+
/** Duration in milliseconds before auto-dismiss. */
|
|
10
|
+
duration?: number;
|
|
11
|
+
}
|
|
12
|
+
declare function Toaster({ position, visibleToasts, closeButton, duration, }: ToasterProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export { Toaster, toast };
|
package/dist/toaster.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Toaster as SonnerToaster, toast } from "sonner";
|
|
4
|
+
function Toaster({ position = "bottom-right", visibleToasts = 3, closeButton = true, duration = 4000, }) {
|
|
5
|
+
return (_jsx(SonnerToaster, { position: position, visibleToasts: visibleToasts, closeButton: closeButton, duration: duration, toastOptions: {
|
|
6
|
+
classNames: {
|
|
7
|
+
toast: "group border border-border bg-background text-foreground shadow-md rounded-lg p-4 flex items-start gap-3",
|
|
8
|
+
title: "text-sm font-medium",
|
|
9
|
+
description: "text-sm text-muted-foreground",
|
|
10
|
+
closeButton: "text-muted-foreground hover:text-foreground",
|
|
11
|
+
success: "border-[hsl(var(--status-success-foreground))]/20",
|
|
12
|
+
error: "border-destructive/20",
|
|
13
|
+
warning: "border-[hsl(var(--status-warning-foreground))]/20",
|
|
14
|
+
info: "border-[hsl(var(--status-info-foreground))]/20",
|
|
15
|
+
},
|
|
16
|
+
} }));
|
|
17
|
+
}
|
|
18
|
+
export { Toaster, toast };
|
package/dist/typography.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ declare const typographyVariants: (props?: ({
|
|
|
6
6
|
export interface TypographyProps extends React.HTMLAttributes<HTMLElement>, VariantProps<typeof typographyVariants> {
|
|
7
7
|
as?: keyof React.JSX.IntrinsicElements;
|
|
8
8
|
asChild?: boolean;
|
|
9
|
+
/** Override the built-in text colour. Use "inherit" to inherit from a parent container. */
|
|
10
|
+
color?: "inherit" | "foreground" | "muted";
|
|
9
11
|
}
|
|
10
12
|
declare const Typography: React.ForwardRefExoticComponent<TypographyProps & React.RefAttributes<HTMLElement>>;
|
|
11
13
|
export { Typography, typographyVariants };
|
package/dist/typography.js
CHANGED
|
@@ -30,12 +30,19 @@ const defaultElementByVariant = {
|
|
|
30
30
|
caption: "span",
|
|
31
31
|
eyebrow: "span",
|
|
32
32
|
};
|
|
33
|
-
const Typography = React.forwardRef(({ as, asChild = false, className, variant, ...props }, ref) => {
|
|
33
|
+
const Typography = React.forwardRef(({ as, asChild = false, className, variant, color, ...props }, ref) => {
|
|
34
34
|
const resolvedVariant = (variant !== null && variant !== void 0 ? variant : "body");
|
|
35
35
|
const Comp = asChild
|
|
36
36
|
? Slot
|
|
37
37
|
: as !== null && as !== void 0 ? as : defaultElementByVariant[resolvedVariant];
|
|
38
|
-
|
|
38
|
+
const colorClass = color === "inherit"
|
|
39
|
+
? "text-inherit"
|
|
40
|
+
: color === "foreground"
|
|
41
|
+
? "text-foreground"
|
|
42
|
+
: color === "muted"
|
|
43
|
+
? "text-muted-foreground"
|
|
44
|
+
: undefined;
|
|
45
|
+
return (_jsx(Comp, { ref: ref, className: cn(typographyVariants({ variant: resolvedVariant }), colorClass, className), ...props }));
|
|
39
46
|
});
|
|
40
47
|
Typography.displayName = "Typography";
|
|
41
48
|
export { Typography, typographyVariants };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neasg/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"README.md"
|
|
16
16
|
],
|
|
17
17
|
"scripts": {
|
|
18
|
-
"build": "tsc -p tsconfig.build.json && node scripts/copy-css.mjs",
|
|
18
|
+
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json && node scripts/copy-css.mjs",
|
|
19
19
|
"storybook": "storybook dev -p 6007 -c .storybook",
|
|
20
20
|
"build-storybook": "storybook build -c .storybook",
|
|
21
21
|
"test": "vitest run",
|
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
"@dnd-kit/core": "^6.3.1",
|
|
34
34
|
"@dnd-kit/sortable": "^10.0.0",
|
|
35
35
|
"@dnd-kit/utilities": "^3.2.2",
|
|
36
|
+
"@govtechsg/sgds-web-component": "^3.8.1",
|
|
36
37
|
"@radix-ui/react-avatar": "^1.1.11",
|
|
37
38
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
39
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
38
40
|
"@radix-ui/react-select": "^2.2.6",
|
|
39
41
|
"@radix-ui/react-slot": "^1.2.4",
|
|
40
42
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
@@ -42,10 +44,13 @@
|
|
|
42
44
|
"class-variance-authority": "^0.7.0",
|
|
43
45
|
"clsx": "^2.1.1",
|
|
44
46
|
"cmdk": "^1.1.1",
|
|
47
|
+
"date-fns": "^4.1.0",
|
|
45
48
|
"input-otp": "^1.4.2",
|
|
46
49
|
"libphonenumber-js": "^1.12.41",
|
|
47
50
|
"lucide-react": "^0.555.0",
|
|
48
51
|
"motion": "^12.33.0",
|
|
52
|
+
"react-day-picker": "^9.14.0",
|
|
53
|
+
"sonner": "^2.0.7",
|
|
49
54
|
"tailwind-merge": "^2.3.0",
|
|
50
55
|
"tailwindcss-animate": "^1.0.7"
|
|
51
56
|
},
|