@neasg/design-system 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -125,15 +125,28 @@ One-time setup:
125
125
 
126
126
  Release flow:
127
127
 
128
- ```bash
129
- npm version patch # 0.2.0 0.2.1
130
- npm version minor # 0.2.0 → 0.3.0
131
- npm version major # 0.2.0 → 1.0.0
132
- npm version 0.5.0 # set an exact version
133
- git push origin main --follow-tags
134
- ```
135
-
136
- Pushing a `v*` tag triggers `.github/workflows/publish.yml`, which runs tests, builds the package, and publishes it to npm.
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/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-9 px-4 py-2 [&_svg]:h-4 [&_svg]:w-4",
18
- sm: "h-8 rounded-md px-3 text-xs [&_svg]:h-4 [&_svg]:w-4",
19
- lg: "h-10 rounded-md px-8 [&_svg]:h-5 [&_svg]:w-5",
20
- icon: "h-9 w-9 [&_svg]:h-4 [&_svg]:w-4",
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: {
@@ -57,8 +57,8 @@ function CommandSearch({ value, onValueChange, sections, children, className, is
57
57
  }
58
58
  }, [isOpen]);
59
59
  return (_jsxs("div", { className: className, ...props, children: [_jsxs(Button, { type: "button", onClick: () => setIsOpen(true), variant: "ghost", className: cn(isCollapsed
60
- ? "h-9 w-full justify-center rounded-lg px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"
61
- : "h-9 w-full min-w-[14rem] justify-start gap-3 rounded-lg border border-gray-200 bg-white px-3 !font-normal text-muted-foreground shadow-sm 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: () => {
60
+ ? "h-10 w-full justify-center rounded-lg px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"
61
+ : "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 shadow-sm 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
62
  var _a;
63
63
  (_a = item.onSelect) === null || _a === void 0 ? void 0 : _a.call(item);
64
64
  if (item.closeOnSelect !== false) {
@@ -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-9 w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
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: "h-8 w-8 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] }));
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
@@ -33,6 +33,8 @@ export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, Command
33
33
  export { CommandSearch, type CommandSearchFilter, type CommandSearchItem, type CommandSearchProps, type CommandSearchSection, } from "./command-search";
34
34
  export { SearchInput } from "./search-input";
35
35
  export type { SearchInputProps } from "./search-input";
36
+ export { GovtMasthead } from "./govt-masthead";
37
+ export type { GovtMastheadProps } from "./govt-masthead";
36
38
  export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
37
39
  export type { SearchHighlightProps, SearchHighlightSegment, } from "./use-search-highlight";
38
40
  export { Textarea } from "./textarea";
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ export { Dialog } from "./dialog";
17
17
  export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
18
18
  export { CommandSearch, } from "./command-search";
19
19
  export { SearchInput } from "./search-input";
20
+ export { GovtMasthead } from "./govt-masthead";
20
21
  export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
21
22
  export { Textarea } from "./textarea";
22
23
  export { DraggableTabs, } from "./draggable-tabs";
@@ -1,4 +1,4 @@
1
1
  import * as React from "react";
2
- declare const inputControlClassName = "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 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";
2
+ declare const inputControlClassName = "h-10 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm 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 };
@@ -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-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 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";
4
+ const inputControlClassName = "h-10 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm 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/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
- return (_jsx("div", { className: cn("flex min-h-screen bg-[hsl(var(--layout-shell-background))]", className), ...props, children: children }));
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: "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-0 z-30 flex h-screen 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
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
  }
@@ -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
  }
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-9 items-center justify-center rounded-md border bg-transparent text-sm font-medium shadow-sm 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 &&
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 shadow-sm 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 };
@@ -13,7 +13,7 @@ function SelectGroup(props) {
13
13
  function SelectValue(props) {
14
14
  return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
15
15
  }
16
- const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsxs(SelectPrimitive.Trigger, { ref: ref, "data-slot": "select-trigger", className: cn("flex h-9 w-full cursor-pointer items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-[color,box-shadow] 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" }) })] })));
16
+ 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-sm shadow-sm transition-[color,box-shadow] 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
17
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
18
18
  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
19
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neasg/design-system",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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,6 +33,7 @@
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",
38
39
  "@radix-ui/react-select": "^2.2.6",