@olundot/ui 0.13.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @olundot/ui
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - DataTable: wrap the loading skeleton and empty state in `role="rowgroup"` / `role="row"` / `role="cell"` structure so `role="table"` only has permitted children — fixes the `aria-required-children` violation (WCAG 1.3.1, axe Critical). Same pattern the data rows already used; visuals and `data-slot` markers are unchanged. (#56, #57)
8
+ - DetailLayout: wire tab triggers to their panels with a real `tab`/`tabpanel` contract — `aria-controls` targets, `role="tabpanel"` panels (including wrapped panel children), and stable panel ids. Public API is unchanged. (#59, #60)
9
+
10
+ This is a compatibility-preserving accessibility stabilization release: no public API or visual contract changes from 0.13.0.
11
+
3
12
  ## 0.13.0
4
13
 
5
14
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -32,8 +32,8 @@ declare function useOlunTheme(): UseOlunThemeValue;
32
32
  type SurfaceLevel = "surface" | "canvas" | "raised";
33
33
 
34
34
  declare const buttonVariants: (props?: ({
35
- variant?: "primary" | "secondary" | "destructive" | "default" | "outline" | "ghost" | "danger" | "emergency" | "subtle" | "link" | null | undefined;
36
- size?: "xs" | "sm" | "md" | "lg" | "xl" | "default" | "icon" | "icon-xs" | null | undefined;
35
+ variant?: "default" | "primary" | "outline" | "ghost" | "danger" | "emergency" | "subtle" | "destructive" | "secondary" | "link" | null | undefined;
36
+ size?: "default" | "xs" | "sm" | "md" | "lg" | "xl" | "icon" | "icon-xs" | null | undefined;
37
37
  } & class_variance_authority_types.ClassProp) | undefined) => string;
38
38
  type ButtonVariant = NonNullable<VariantProps<typeof buttonVariants>['variant']>;
39
39
  type ButtonSize = NonNullable<VariantProps<typeof buttonVariants>['size']>;
@@ -54,7 +54,7 @@ type CopyButtonProps = Omit<ButtonProps, 'children' | 'leadingIcon' | 'loading'
54
54
  variant?: ButtonVariant;
55
55
  duration?: number;
56
56
  };
57
- declare const CopyButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "variant" | "size" | "leadingIcon" | "trailingIcon" | "loading" | "children"> & {
57
+ declare const CopyButton: React.ForwardRefExoticComponent<Omit<ButtonProps, "size" | "variant" | "leadingIcon" | "trailingIcon" | "loading" | "children"> & {
58
58
  value: string;
59
59
  label?: React.ReactNode;
60
60
  copiedLabel?: React.ReactNode;
@@ -70,7 +70,7 @@ declare const inputVariants: (props?: ({
70
70
  surface?: SurfaceLevel | null | undefined;
71
71
  } & class_variance_authority_types.ClassProp) | undefined) => string;
72
72
  declare const inputMessageVariants: (props?: ({
73
- state?: "error" | "success" | "default" | null | undefined;
73
+ state?: "default" | "error" | "success" | null | undefined;
74
74
  size?: "sm" | "md" | "lg" | null | undefined;
75
75
  } & class_variance_authority_types.ClassProp) | undefined) => string;
76
76
  type InputState = NonNullable<VariantProps<typeof inputMessageVariants>["state"]>;
@@ -119,11 +119,11 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
119
119
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
120
120
 
121
121
  declare const fileUploadZoneVariants: (props?: ({
122
- size?: "compact" | "default" | null | undefined;
122
+ size?: "default" | "compact" | null | undefined;
123
123
  surface?: SurfaceLevel | null | undefined;
124
124
  } & class_variance_authority_types.ClassProp) | undefined) => string;
125
125
  declare const fileUploadIconVariants: (props?: ({
126
- size?: "compact" | "default" | null | undefined;
126
+ size?: "default" | "compact" | null | undefined;
127
127
  } & class_variance_authority_types.ClassProp) | undefined) => string;
128
128
  interface FileUploadZoneProps extends Omit<React.LabelHTMLAttributes<HTMLLabelElement>, "onChange">, VariantProps<typeof fileUploadZoneVariants> {
129
129
  accept?: string;
@@ -166,7 +166,7 @@ declare const textareaVariants: (props?: ({
166
166
  surface?: SurfaceLevel | null | undefined;
167
167
  } & class_variance_authority_types.ClassProp) | undefined) => string;
168
168
  declare const textareaMessageVariants: (props?: ({
169
- state?: "error" | "success" | "default" | null | undefined;
169
+ state?: "default" | "error" | "success" | null | undefined;
170
170
  } & class_variance_authority_types.ClassProp) | undefined) => string;
171
171
  type TextareaState = NonNullable<VariantProps<typeof textareaMessageVariants>["state"]>;
172
172
  /** Canonical size type (0.2.0+). Use `size` prop with these values. */
@@ -221,7 +221,7 @@ declare const selectVariants: (props?: ({
221
221
  surface?: SurfaceLevel | null | undefined;
222
222
  } & class_variance_authority_types.ClassProp) | undefined) => string;
223
223
  declare const selectMessageVariants: (props?: ({
224
- state?: "error" | "success" | "default" | null | undefined;
224
+ state?: "default" | "error" | "success" | null | undefined;
225
225
  size?: "sm" | "md" | "lg" | null | undefined;
226
226
  } & class_variance_authority_types.ClassProp) | undefined) => string;
227
227
  type SelectState = NonNullable<VariantProps<typeof selectMessageVariants>["state"]>;
@@ -1020,12 +1020,12 @@ declare const NotificationBadge: React.ForwardRefExoticComponent<NotificationBad
1020
1020
 
1021
1021
  declare const chipVariants: (props?: ({
1022
1022
  variant?: "filter" | "choice" | "removable" | "status-filter" | null | undefined;
1023
- tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
1023
+ tone?: "accent" | "danger" | "success" | "warning" | "neutral" | "muted" | null | undefined;
1024
1024
  size?: "sm" | "md" | "lg" | null | undefined;
1025
1025
  pressed?: boolean | null | undefined;
1026
1026
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1027
1027
  declare const chipCountVariants: (props?: ({
1028
- tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
1028
+ tone?: "accent" | "danger" | "success" | "warning" | "neutral" | "muted" | null | undefined;
1029
1029
  size?: "sm" | "md" | "lg" | null | undefined;
1030
1030
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1031
1031
  type ChipVariant = NonNullable<VariantProps<typeof chipVariants>["variant"]>;
@@ -1264,7 +1264,7 @@ interface ActionFooterProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
1264
1264
  declare const ActionFooter: React.ForwardRefExoticComponent<ActionFooterProps & React.RefAttributes<HTMLDivElement>>;
1265
1265
 
1266
1266
  declare const toastVariants: (props?: ({
1267
- variant?: "error" | "warning" | "info" | "success" | "default" | null | undefined;
1267
+ variant?: "default" | "error" | "success" | "info" | "warning" | null | undefined;
1268
1268
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1269
1269
  declare const toastViewportVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
1270
1270
  type ToastVariant = NonNullable<VariantProps<typeof toastVariants>['variant']>;
@@ -1318,19 +1318,19 @@ interface ToastProviderProps extends React.HTMLAttributes<HTMLDivElement> {
1318
1318
  declare function ToastProvider({ children, maxToasts, className, ...props }: ToastProviderProps): react_jsx_runtime.JSX.Element;
1319
1319
 
1320
1320
  declare const otpFieldVariants: (props?: ({
1321
- size?: "compact" | "default" | null | undefined;
1321
+ size?: "default" | "compact" | null | undefined;
1322
1322
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1323
1323
  declare const otpFieldGroupVariants: (props?: ({
1324
- size?: "compact" | "default" | null | undefined;
1324
+ size?: "default" | "compact" | null | undefined;
1325
1325
  fluid?: boolean | null | undefined;
1326
1326
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1327
1327
  declare const otpCellVariants: (props?: ({
1328
- size?: "compact" | "default" | null | undefined;
1328
+ size?: "default" | "compact" | null | undefined;
1329
1329
  fluid?: boolean | null | undefined;
1330
1330
  surface?: SurfaceLevel | null | undefined;
1331
1331
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1332
1332
  declare const otpFieldMessageVariants: (props?: ({
1333
- state?: "error" | "default" | null | undefined;
1333
+ state?: "default" | "error" | null | undefined;
1334
1334
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1335
1335
  type OTPFieldSize = NonNullable<VariantProps<typeof otpCellVariants>["size"]>;
1336
1336
  interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetElement>, "onChange" | "children" | "defaultValue" | "value">, VariantProps<typeof otpFieldVariants> {
@@ -1387,11 +1387,11 @@ declare const checkboxBoxVariants: (props?: ({
1387
1387
  size?: "sm" | "md" | null | undefined;
1388
1388
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1389
1389
  declare const checkboxGroupItemVariants: (props?: ({
1390
- appearance?: "card" | "plain" | null | undefined;
1390
+ appearance?: "plain" | "card" | null | undefined;
1391
1391
  density?: "compact" | "comfortable" | null | undefined;
1392
1392
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1393
1393
  declare const checkboxGroupBoxVariants: (props?: ({
1394
- appearance?: "card" | "plain" | null | undefined;
1394
+ appearance?: "plain" | "card" | null | undefined;
1395
1395
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1396
1396
  type CheckboxSize = NonNullable<VariantProps<typeof checkboxBoxVariants>["size"]>;
1397
1397
  type CheckboxCheckedState = React.ComponentProps<typeof Checkbox$1.Root>["checked"];
@@ -1416,7 +1416,7 @@ interface CheckboxProps extends Omit<React.ComponentPropsWithoutRef<typeof Check
1416
1416
  declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLButtonElement>>;
1417
1417
 
1418
1418
  declare const checkboxGroupVariants: (props?: ({
1419
- appearance?: "card" | "plain" | null | undefined;
1419
+ appearance?: "plain" | "card" | null | undefined;
1420
1420
  orientation?: "horizontal" | "vertical" | null | undefined;
1421
1421
  columns?: "one" | "two" | "three" | null | undefined;
1422
1422
  } & class_variance_authority_types.ClassProp) | undefined) => string;
@@ -1437,16 +1437,16 @@ interface CheckboxGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
1437
1437
  declare const CheckboxGroup: React.ForwardRefExoticComponent<CheckboxGroupProps & React.RefAttributes<HTMLDivElement>>;
1438
1438
 
1439
1439
  declare const radioGroupVariants: (props?: ({
1440
- appearance?: "card" | "plain" | null | undefined;
1440
+ appearance?: "plain" | "card" | null | undefined;
1441
1441
  orientation?: "horizontal" | "vertical" | null | undefined;
1442
1442
  columns?: "one" | "two" | "three" | null | undefined;
1443
1443
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1444
1444
  declare const radioVariants: (props?: ({
1445
- appearance?: "card" | "plain" | null | undefined;
1445
+ appearance?: "plain" | "card" | null | undefined;
1446
1446
  density?: "compact" | "comfortable" | null | undefined;
1447
1447
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1448
1448
  declare const radioControlVariants: (props?: ({
1449
- appearance?: "card" | "plain" | null | undefined;
1449
+ appearance?: "plain" | "card" | null | undefined;
1450
1450
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1451
1451
  type RadioGroupAppearance = NonNullable<VariantProps<typeof radioGroupVariants>["appearance"]>;
1452
1452
  type RadioGroupColumns = NonNullable<VariantProps<typeof radioGroupVariants>["columns"]>;
package/dist/index.js CHANGED
@@ -3149,6 +3149,38 @@ function DetailLayoutBody({
3149
3149
  }
3150
3150
  );
3151
3151
  }
3152
+ function isTabsContentChild(child) {
3153
+ return React18.isValidElement(child) && child.type === TabsContent;
3154
+ }
3155
+ function containsTabsContent(children) {
3156
+ return React18.Children.toArray(children).some((child) => {
3157
+ if (isTabsContentChild(child)) return true;
3158
+ return React18.isValidElement(child) && containsTabsContent(child.props.children);
3159
+ });
3160
+ }
3161
+ function appendFooterToActiveTabsContent(children, activeTab, footer) {
3162
+ return React18.Children.map(children, (child) => {
3163
+ if (isTabsContentChild(child)) {
3164
+ if (child.props.tabKey !== activeTab || !footer) return child;
3165
+ return React18.cloneElement(
3166
+ child,
3167
+ void 0,
3168
+ /* @__PURE__ */ jsxs18(Fragment6, { children: [
3169
+ child.props.children,
3170
+ /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer })
3171
+ ] })
3172
+ );
3173
+ }
3174
+ if (React18.isValidElement(child)) {
3175
+ return React18.cloneElement(
3176
+ child,
3177
+ void 0,
3178
+ appendFooterToActiveTabsContent(child.props.children, activeTab, footer)
3179
+ );
3180
+ }
3181
+ return child;
3182
+ });
3183
+ }
3152
3184
  var DetailLayout = React18.forwardRef(
3153
3185
  ({
3154
3186
  className,
@@ -3179,6 +3211,7 @@ var DetailLayout = React18.forwardRef(
3179
3211
  children
3180
3212
  }
3181
3213
  );
3214
+ const hasExplicitTabsContent = containsTabsContent(children);
3182
3215
  return /* @__PURE__ */ jsxs18(
3183
3216
  "section",
3184
3217
  {
@@ -3188,10 +3221,31 @@ var DetailLayout = React18.forwardRef(
3188
3221
  ...props,
3189
3222
  children: [
3190
3223
  /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-header", className: "min-w-0", children: header }),
3191
- tabs ? /* @__PURE__ */ jsxs18(Tabs, { tabs, activeKey: activeTab, onChange: onTabChange, baseId, children: [
3192
- body,
3193
- footer ? /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer }) : null
3194
- ] }) : /* @__PURE__ */ jsxs18(Fragment6, { children: [
3224
+ tabs ? /* @__PURE__ */ jsx19(Tabs, { tabs, activeKey: activeTab, onChange: onTabChange, baseId, children: hasExplicitTabsContent ? /* @__PURE__ */ jsx19(
3225
+ DetailLayoutBody,
3226
+ {
3227
+ aside,
3228
+ bodyClassName,
3229
+ contentClassName,
3230
+ asideClassName,
3231
+ stickyAside,
3232
+ stickyAsideTopClassName,
3233
+ children: appendFooterToActiveTabsContent(children, activeTab, footer)
3234
+ }
3235
+ ) : tabs.map((tab) => /* @__PURE__ */ jsx19(
3236
+ TabsContent,
3237
+ {
3238
+ tabKey: tab.key,
3239
+ baseId,
3240
+ forceMount: true,
3241
+ hidden: tab.key !== activeTab,
3242
+ children: tab.key === activeTab ? /* @__PURE__ */ jsxs18(Fragment6, { children: [
3243
+ body,
3244
+ footer ? /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer }) : null
3245
+ ] }) : null
3246
+ },
3247
+ tab.key
3248
+ )) }) : /* @__PURE__ */ jsxs18(Fragment6, { children: [
3195
3249
  body,
3196
3250
  footer ? /* @__PURE__ */ jsx19("div", { "data-slot": "detail-layout-footer", className: "min-w-0", children: footer }) : null
3197
3251
  ] })
@@ -4309,27 +4363,35 @@ function SkeletonRows({
4309
4363
  gridTemplateColumns,
4310
4364
  count
4311
4365
  }) {
4312
- return /* @__PURE__ */ jsx26("div", { "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", role: "status", children: Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs25(
4313
- "div",
4314
- {
4315
- "data-slot": "data-table-skeleton-row",
4316
- className: "grid min-h-[48px] items-center border-t border-[var(--border-subtle)]",
4317
- style: { gridTemplateColumns },
4318
- children: [
4319
- selectable ? /* @__PURE__ */ jsx26("div", { "aria-hidden": "true", className: "px-[var(--space-4)]" }) : null,
4320
- columns.map((column, columnIndex) => /* @__PURE__ */ jsx26("div", { className: "px-[var(--space-4)] py-[var(--space-2)]", children: /* @__PURE__ */ jsx26(
4321
- "div",
4322
- {
4323
- className: cn(
4324
- "h-[14px] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-raised)]",
4325
- columnIndex === 0 ? "w-[72%]" : column.align === "right" ? "ml-auto w-[54%]" : "w-[62%]"
4326
- )
4327
- }
4328
- ) }, column.key))
4329
- ]
4330
- },
4331
- rowIndex
4332
- )) });
4366
+ return (
4367
+ // role="table"의 허용 자식은 row/rowgroup뿐이라 컨테이너는 rowgroup이어야 한다.
4368
+ // 로딩 알림은 그 안의 row/cell 안에 둔다 — 종전에는 컨테이너가 role="status"라
4369
+ // aria-required-children(Critical)이 났다.
4370
+ /* @__PURE__ */ jsxs25("div", { role: "rowgroup", children: [
4371
+ /* @__PURE__ */ jsx26("div", { role: "row", children: /* @__PURE__ */ jsx26("div", { role: "cell", "aria-colindex": 1, "aria-label": "\uB370\uC774\uD130 \uB85C\uB4DC \uC911", children: /* @__PURE__ */ jsx26("span", { role: "status", className: "sr-only", children: "\uB370\uC774\uD130 \uB85C\uB4DC \uC911" }) }) }),
4372
+ Array.from({ length: count }, (_, rowIndex) => /* @__PURE__ */ jsxs25(
4373
+ "div",
4374
+ {
4375
+ "data-slot": "data-table-skeleton-row",
4376
+ className: "grid min-h-[48px] items-center border-t border-[var(--border-subtle)]",
4377
+ style: { gridTemplateColumns },
4378
+ children: [
4379
+ selectable ? /* @__PURE__ */ jsx26("div", { "aria-hidden": "true", className: "px-[var(--space-4)]" }) : null,
4380
+ columns.map((column, columnIndex) => /* @__PURE__ */ jsx26("div", { className: "px-[var(--space-4)] py-[var(--space-2)]", children: /* @__PURE__ */ jsx26(
4381
+ "div",
4382
+ {
4383
+ className: cn(
4384
+ "h-[14px] animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-raised)]",
4385
+ columnIndex === 0 ? "w-[72%]" : column.align === "right" ? "ml-auto w-[54%]" : "w-[62%]"
4386
+ )
4387
+ }
4388
+ ) }, column.key))
4389
+ ]
4390
+ },
4391
+ rowIndex
4392
+ ))
4393
+ ] })
4394
+ );
4333
4395
  }
4334
4396
  function MobileSkeletonCards({ count }) {
4335
4397
  return /* @__PURE__ */ jsx26(
@@ -4493,7 +4555,20 @@ function DataTableInner({
4493
4555
  gridTemplateColumns,
4494
4556
  count: skeletonRowCount
4495
4557
  }
4496
- ) : data.length === 0 ? /* @__PURE__ */ jsx26("div", { "data-slot": "data-table-empty", className: "border-t border-[var(--border-subtle)] p-[var(--space-4)]", children: emptyState }) : /* @__PURE__ */ jsx26("div", { role: "rowgroup", children: data.map((row) => {
4558
+ ) : data.length === 0 ? (
4559
+ /* role="table" 직계 자식은 row/rowgroup이어야 한다. data-slot과 테두리는
4560
+ 그대로 유지해 시각 계약을 깨지 않는다(빈 상태에서도 표가 테두리를 그린다). */
4561
+ /* @__PURE__ */ jsx26("div", { role: "rowgroup", children: /* @__PURE__ */ jsx26("div", { role: "row", children: /* @__PURE__ */ jsx26(
4562
+ "div",
4563
+ {
4564
+ role: "cell",
4565
+ "aria-colindex": 1,
4566
+ "data-slot": "data-table-empty",
4567
+ className: "border-t border-[var(--border-subtle)] p-[var(--space-4)]",
4568
+ children: emptyState
4569
+ }
4570
+ ) }) })
4571
+ ) : /* @__PURE__ */ jsx26("div", { role: "rowgroup", children: data.map((row) => {
4497
4572
  const rowId = getRowId(row, keyField);
4498
4573
  const selected = resolvedSelectedIds.has(rowId);
4499
4574
  const visuallySelected = selected || rowId === activeRowId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olundot/ui",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "OLUN. shared React UI components built on OLUN design tokens",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -38,13 +38,21 @@
38
38
  "import": "./dist/tailwind.preset.js"
39
39
  }
40
40
  },
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "lint": "node scripts/verify-source-imports.mjs",
44
+ "test": "sh -c 'set -e; if [ \"$#\" -gt 0 ]; then for test_file in \"$@\"; do node --import tsx \"$test_file\"; done; else for test_file in src/components/ui/*.test.tsx; do node --import tsx \"$test_file\"; done; fi' --",
45
+ "test:accent-contracts": "node scripts/verify-accent-contracts.mjs",
46
+ "type-check": "tsc --noEmit",
47
+ "prepublishOnly": "pnpm build && pnpm test && pnpm test:accent-contracts && pnpm type-check && pnpm lint"
48
+ },
41
49
  "dependencies": {
50
+ "@olundot/tokens": "workspace:^",
42
51
  "class-variance-authority": "^0.7.1",
43
52
  "clsx": "^2.1.1",
44
53
  "lucide-react": "^1.8.0",
45
54
  "radix-ui": "^1.4.3",
46
- "tailwind-merge": "^3.5.0",
47
- "@olundot/tokens": "^0.14.0"
55
+ "tailwind-merge": "^3.5.0"
48
56
  },
49
57
  "peerDependencies": {
50
58
  "react": ">=18",
@@ -69,12 +77,5 @@
69
77
  },
70
78
  "publishConfig": {
71
79
  "access": "public"
72
- },
73
- "scripts": {
74
- "build": "tsup",
75
- "lint": "node scripts/verify-source-imports.mjs",
76
- "test": "sh -c 'set -e; if [ \"$#\" -gt 0 ]; then for test_file in \"$@\"; do node --import tsx \"$test_file\"; done; else for test_file in src/components/ui/*.test.tsx; do node --import tsx \"$test_file\"; done; fi' --",
77
- "test:accent-contracts": "node scripts/verify-accent-contracts.mjs",
78
- "type-check": "tsc --noEmit"
79
80
  }
80
- }
81
+ }