@keboola/design 5.0.0 → 6.0.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/dist/index.cjs CHANGED
@@ -1470,11 +1470,12 @@ var variants = classVarianceAuthority.cva(
1470
1470
  "tw-items-center",
1471
1471
  "tw-justify-center",
1472
1472
  "tw-gap-2",
1473
- // text
1473
+ // text — chrome weight/tracking are brand-overridable tokens
1474
+ // (`--font-weight-medium` / `--letter-spacing-chrome`); casing stays `tw-uppercase`.
1474
1475
  "tw-text-xs",
1475
1476
  "tw-leading-5",
1476
1477
  "tw-font-medium",
1477
- "tw-tracking-[1px]",
1478
+ "tw-tracking-chrome",
1478
1479
  "tw-uppercase",
1479
1480
  // border — legacy (non-argo) chrome uses a fixed radius, not the brand token.
1480
1481
  "tw-rounded",
@@ -9043,11 +9044,23 @@ var inputGroupVariants = classVarianceAuthority.cva(
9043
9044
  off: ["has-[:is(input,textarea):focus]:!tw-ring-0"]
9044
9045
  },
9045
9046
  variant: {
9046
- primary: ["tw-bg-white", "has-[:is(input,textarea):disabled]:tw-opacity-40"],
9047
+ primary: [
9048
+ "tw-bg-white",
9049
+ "has-[:is(input,textarea):disabled]:tw-opacity-40",
9050
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
9051
+ // accessible path (mirrors the `state="error"` legacy tokens). Higher specificity than
9052
+ // the default focus selector, so it wins without `!important`.
9053
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-error-500",
9054
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-error-500",
9055
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-error-200"
9056
+ ],
9047
9057
  secondary: [
9048
9058
  "tw-bg-neutral-100",
9049
9059
  "tw-border-neutral-100",
9050
- "has-[:is(input,textarea):disabled]:tw-opacity-40"
9060
+ "has-[:is(input,textarea):disabled]:tw-opacity-40",
9061
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-error-500",
9062
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-error-500",
9063
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-error-200"
9051
9064
  ],
9052
9065
  argo: [
9053
9066
  // argo follows the brand radius token (overrides the static base)
@@ -9058,7 +9071,12 @@ var inputGroupVariants = classVarianceAuthority.cva(
9058
9071
  "tw-text-foreground",
9059
9072
  "has-[:is(input,textarea):disabled]:tw-opacity-50",
9060
9073
  // higher specificity than has-[:is(input,textarea):focus] — prevents focus border on readonly
9061
- "has-[:is(input,textarea)[readonly]:focus]:tw-border-neutral-150"
9074
+ "has-[:is(input,textarea)[readonly]:focus]:tw-border-neutral-150",
9075
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
9076
+ // accessible path (uses the themeable `destructive` status token).
9077
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-destructive",
9078
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-destructive",
9079
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-destructive/20"
9062
9080
  ]
9063
9081
  },
9064
9082
  sizing: {
@@ -10013,23 +10031,23 @@ var TimePicker = ({
10013
10031
  )
10014
10032
  ] });
10015
10033
  };
10016
- var Optional = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("tw-text-muted-foreground", className), children: "(optional)" });
10017
- var Label2 = ({ className, children, id, htmlFor, ...rest }) => {
10018
- return /* @__PURE__ */ jsxRuntime.jsx(
10019
- RLabel__namespace.Root,
10020
- {
10021
- ...rest,
10022
- id: id?.toString(),
10023
- htmlFor: htmlFor?.toString(),
10024
- className: cn(
10025
- "tw-m-0 tw-text-foreground tw-font-normal peer-disabled:tw-opacity-50",
10026
- className
10027
- ),
10028
- children
10029
- }
10030
- );
10031
- };
10034
+ var Optional = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, "aria-hidden": true, className: cn("tw-ml-0.5", "tw-text-muted-foreground", className), children: "(optional)" });
10035
+ var Required = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, "aria-hidden": true, className: cn("tw-ml-0.5", "tw-text-primary", className), children: "*" });
10036
+ var Label2 = ({ className, children, id, htmlFor, ...rest }) => /* @__PURE__ */ jsxRuntime.jsx(
10037
+ RLabel__namespace.Root,
10038
+ {
10039
+ ...rest,
10040
+ id: id?.toString(),
10041
+ htmlFor: htmlFor?.toString(),
10042
+ className: cn(
10043
+ "tw-m-0 tw-text-foreground tw-font-normal peer-disabled:tw-opacity-50",
10044
+ className
10045
+ ),
10046
+ children
10047
+ }
10048
+ );
10032
10049
  Label2.Optional = Optional;
10050
+ Label2.Required = Required;
10033
10051
  var FieldBoxDescription = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
10034
10052
  "span",
10035
10053
  {
@@ -11217,12 +11235,29 @@ var variants4 = classVarianceAuthority.cva(
11217
11235
  ],
11218
11236
  variants: {
11219
11237
  variant: {
11220
- primary: ["tw-bg-white", "disabled:tw-opacity-40", "aria-disabled:tw-opacity-40"],
11238
+ primary: [
11239
+ "tw-bg-white",
11240
+ "disabled:tw-opacity-40",
11241
+ "aria-disabled:tw-opacity-40",
11242
+ // aria-invalid on the trigger surfaces the error chrome without a `state` prop — the
11243
+ // accessible path (mirrors the `state="error"` legacy tokens). The extra attribute
11244
+ // selector outranks the default focus/open state, so it wins without `!important`.
11245
+ "aria-[invalid=true]:tw-border-error-500",
11246
+ "aria-[invalid=true]:focus:tw-border-error-500",
11247
+ "aria-[invalid=true]:focus:tw-ring-error-200",
11248
+ "aria-[invalid=true]:data-[state=open]:tw-border-error-500",
11249
+ "aria-[invalid=true]:data-[state=open]:tw-ring-error-200"
11250
+ ],
11221
11251
  secondary: [
11222
11252
  "tw-bg-neutral-100",
11223
11253
  "tw-border-neutral-100",
11224
11254
  "disabled:tw-opacity-40",
11225
- "aria-disabled:tw-opacity-40"
11255
+ "aria-disabled:tw-opacity-40",
11256
+ "aria-[invalid=true]:tw-border-error-500",
11257
+ "aria-[invalid=true]:focus:tw-border-error-500",
11258
+ "aria-[invalid=true]:focus:tw-ring-error-200",
11259
+ "aria-[invalid=true]:data-[state=open]:tw-border-error-500",
11260
+ "aria-[invalid=true]:data-[state=open]:tw-ring-error-200"
11226
11261
  ],
11227
11262
  argo: [
11228
11263
  // muted filled input surface — gray, distinct from white containers; not the app-background token
@@ -11232,7 +11267,14 @@ var variants4 = classVarianceAuthority.cva(
11232
11267
  "tw-rounded-[var(--radius-lg,0.25rem)]",
11233
11268
  "tw-text-foreground",
11234
11269
  "disabled:tw-opacity-50",
11235
- "aria-disabled:tw-opacity-50"
11270
+ "aria-disabled:tw-opacity-50",
11271
+ // aria-invalid on the trigger surfaces the error chrome without a `state` prop — the
11272
+ // accessible path (uses the themeable `destructive` status token).
11273
+ "aria-[invalid=true]:tw-border-destructive",
11274
+ "aria-[invalid=true]:focus:tw-border-destructive",
11275
+ "aria-[invalid=true]:focus:tw-ring-destructive/20",
11276
+ "aria-[invalid=true]:data-[state=open]:tw-border-destructive",
11277
+ "aria-[invalid=true]:data-[state=open]:tw-ring-destructive/20"
11236
11278
  ]
11237
11279
  },
11238
11280
  sizing: {
@@ -11284,7 +11326,7 @@ var SelectTrigger = ({
11284
11326
  ...props,
11285
11327
  children: [
11286
11328
  /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Value, { placeholder }),
11287
- /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(icons_exports.ChevronDown, { className: "tw-size-5 tw-text-muted-foreground" }) })
11329
+ /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(icons_exports.ChevronDown, { className: "tw-size-4 tw-text-muted-foreground" }) })
11288
11330
  ]
11289
11331
  }
11290
11332
  );
@@ -11609,12 +11651,14 @@ var badgeRootVariants = classVarianceAuthority.cva(
11609
11651
  "tw-h-fit",
11610
11652
  "tw-shrink-0",
11611
11653
  "tw-overflow-hidden",
11612
- // text
11654
+ // text — chrome weight/tracking are brand-overridable tokens
11655
+ // (`--font-weight-medium` / `--letter-spacing-chrome`); casing lives on the
11656
+ // `default` variant below via `tw-uppercase`.
11613
11657
  "tw-whitespace-pre-wrap",
11614
11658
  "tw-break-normal",
11615
11659
  "tw-text-xs",
11616
11660
  "tw-font-medium",
11617
- "tw-tracking-[1px]",
11661
+ "tw-tracking-chrome",
11618
11662
  "tw-text-center",
11619
11663
  "tw-underline",
11620
11664
  // content
@@ -13061,18 +13105,12 @@ var TimeInput = ({
13061
13105
  }
13062
13106
  );
13063
13107
  };
13064
- var InputOtpVariantContext = React26.createContext({
13065
- sizing: "md",
13066
- state: "default"
13067
- });
13068
- var useInputOtpVariant = () => React26.use(InputOtpVariantContext);
13069
- var useInputOtpRenderContext = () => React26.use(inputOtp.OTPInputContext);
13070
- var InputOtpGroup = ({
13108
+ var OtpInputGroup = ({
13071
13109
  ref,
13072
13110
  className,
13073
13111
  ...props
13074
13112
  }) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("tw-flex tw-items-center tw-gap-2", className), ...props });
13075
- var InputOtpSeparator = ({
13113
+ var OtpInputSeparator = ({
13076
13114
  ref,
13077
13115
  children,
13078
13116
  className,
@@ -13088,61 +13126,46 @@ var InputOtpSeparator = ({
13088
13126
  children: children ?? /* @__PURE__ */ jsxRuntime.jsx(icons_exports.Minus, { className: "tw-size-4" })
13089
13127
  }
13090
13128
  );
13091
- var slotVariants = classVarianceAuthority.cva(
13092
- [
13093
- "tw-relative",
13094
- "tw-flex",
13095
- "tw-items-center",
13096
- "tw-justify-center",
13097
- "tw-border",
13098
- "tw-border-input",
13099
- // muted filled input surface — gray, distinct from white containers; not the app-background token
13100
- "tw-bg-muted",
13101
- "tw-text-foreground",
13102
- "tw-font-medium",
13103
- "tw-tabular-nums",
13104
- "tw-rounded-lg",
13105
- "tw-transition",
13106
- "tw-outline-none",
13107
- // active slot sits above its neighbours so its ring isn't clipped
13108
- "data-[active=true]:tw-z-10",
13109
- "data-[active=true]:tw-border-primary",
13110
- "data-[active=true]:tw-ring-2",
13111
- "data-[active=true]:tw-ring-ring/50"
13112
- ],
13113
- {
13114
- defaultVariants: {
13115
- sizing: "md",
13116
- state: "default"
13117
- },
13118
- variants: {
13119
- sizing: {
13120
- sm: ["tw-h-8", "tw-w-8", "tw-text-sm"],
13121
- md: ["tw-h-9", "tw-w-9", "tw-text-base"],
13122
- lg: ["tw-h-10", "tw-w-10", "tw-text-lg"]
13123
- },
13124
- // `!` forces the border colour over the base `tw-border-input` once tailwind-merge dedupes.
13125
- // Matches the pattern InputGroup uses for its argo error state.
13126
- state: {
13127
- default: [],
13128
- error: [
13129
- "!tw-border-destructive",
13130
- "tw-bg-destructive/5",
13131
- "data-[active=true]:!tw-border-destructive",
13132
- "data-[active=true]:tw-ring-destructive/40"
13133
- ]
13134
- }
13135
- }
13136
- }
13137
- );
13138
- var InputOtpSlot = ({
13129
+ var slotClassName = [
13130
+ // layout
13131
+ "tw-relative",
13132
+ "tw-flex",
13133
+ "tw-items-center",
13134
+ "tw-justify-center",
13135
+ "tw-font-medium",
13136
+ "tw-tabular-nums",
13137
+ "tw-outline-none",
13138
+ "tw-transition",
13139
+ // resting chrome — always-visible input border on a muted fill (matches InputGroup)
13140
+ "tw-border",
13141
+ "tw-border-solid",
13142
+ "tw-border-input",
13143
+ "tw-bg-muted",
13144
+ "tw-text-foreground",
13145
+ "tw-rounded-[var(--radius-lg,0.25rem)]",
13146
+ // focus — the active slot mirrors InputGroup's argo focus ring; z-10 so the ring isn't clipped
13147
+ "data-[active=true]:tw-z-10",
13148
+ "data-[active=true]:tw-border-primary",
13149
+ "data-[active=true]:tw-ring-4",
13150
+ "data-[active=true]:tw-ring-ring/50",
13151
+ // size — from `data-size` on the group/otp container
13152
+ "group-data-[size=sm]/otp:tw-h-8 group-data-[size=sm]/otp:tw-w-8 group-data-[size=sm]/otp:tw-text-sm",
13153
+ "group-data-[size=md]/otp:tw-h-9 group-data-[size=md]/otp:tw-w-9 group-data-[size=md]/otp:tw-text-base",
13154
+ "group-data-[size=lg]/otp:tw-h-10 group-data-[size=lg]/otp:tw-w-10 group-data-[size=lg]/otp:tw-text-lg",
13155
+ // error — from `aria-invalid` on the OTP input (mirrors InputGroup argo error chrome). `!` beats
13156
+ // the base/active border once tailwind-merge dedupes.
13157
+ "group-has-[input[aria-invalid=true]]/otp:!tw-border-destructive",
13158
+ "group-has-[input[aria-invalid=true]]/otp:data-[active=true]:!tw-border-destructive",
13159
+ "group-has-[input[aria-invalid=true]]/otp:data-[active=true]:tw-ring-destructive/20"
13160
+ ];
13161
+ var OtpInputSlot = ({
13139
13162
  ref,
13140
13163
  index,
13141
13164
  className,
13142
13165
  ...props
13143
13166
  }) => {
13144
- const { slots } = useInputOtpRenderContext();
13145
- const { sizing, state } = useInputOtpVariant();
13167
+ const { slots } = React26.use(inputOtp.OTPInputContext);
13168
+ if (!slots) throw new Error("<OtpInput.Slot> must be rendered inside <OtpInput>.");
13146
13169
  const slot = slots[index];
13147
13170
  const char = slot?.char ?? null;
13148
13171
  const isActive = slot?.isActive ?? false;
@@ -13153,7 +13176,7 @@ var InputOtpSlot = ({
13153
13176
  ref,
13154
13177
  "data-active": isActive || void 0,
13155
13178
  "data-slot-index": index,
13156
- className: cn(slotVariants({ sizing, state }), className),
13179
+ className: cn(slotClassName, className),
13157
13180
  ...props,
13158
13181
  children: [
13159
13182
  char,
@@ -13172,19 +13195,19 @@ var InputOtpSlot = ({
13172
13195
  var Root23 = ({
13173
13196
  ref,
13174
13197
  sizing = "md",
13175
- state = "default",
13176
13198
  pattern = inputOtp.REGEXP_ONLY_DIGITS,
13177
13199
  containerClassName,
13178
13200
  className,
13179
13201
  children,
13202
+ "aria-invalid": ariaInvalid,
13180
13203
  ...rest
13181
- }) => /* @__PURE__ */ jsxRuntime.jsx(InputOtpVariantContext, { value: { sizing, state }, children: /* @__PURE__ */ jsxRuntime.jsx(
13204
+ }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tw-group/otp tw-w-fit", "data-size": sizing, children: /* @__PURE__ */ jsxRuntime.jsx(
13182
13205
  inputOtp.OTPInput,
13183
13206
  {
13184
13207
  ...rest,
13185
13208
  ref,
13186
13209
  pattern,
13187
- "aria-invalid": state === "error" || void 0,
13210
+ "aria-invalid": ariaInvalid,
13188
13211
  containerClassName: cn(
13189
13212
  "tw-flex tw-items-center tw-gap-2 has-[:disabled]:tw-opacity-50",
13190
13213
  containerClassName
@@ -13193,20 +13216,11 @@ var Root23 = ({
13193
13216
  children
13194
13217
  }
13195
13218
  ) });
13196
- var InputOtp = Object.assign(Root23, {
13197
- Group: InputOtpGroup,
13198
- Slot: InputOtpSlot,
13199
- Separator: InputOtpSeparator
13219
+ var OtpInput = Object.assign(Root23, {
13220
+ Group: OtpInputGroup,
13221
+ Slot: OtpInputSlot,
13222
+ Separator: OtpInputSeparator
13200
13223
  });
13201
-
13202
- // src/blocks/InputOtp/index.ts
13203
- var useInputOtpContext = () => {
13204
- const ctx = React26.use(inputOtp.OTPInputContext);
13205
- if (!ctx.slots) {
13206
- throw new Error("useInputOtpContext must be used inside <InputOtp>.");
13207
- }
13208
- return ctx;
13209
- };
13210
13224
  var SearchInput = ({
13211
13225
  ref,
13212
13226
  // group props
@@ -15180,6 +15194,18 @@ var FormGroupColorInput = ({
15180
15194
  const { state } = useFormGroupContext();
15181
15195
  return /* @__PURE__ */ jsxRuntime.jsx(ColorInput, { state, ...props, ref });
15182
15196
  };
15197
+ var toMessage = (entry) => typeof entry === "string" ? entry : entry?.message;
15198
+ var FormGroupError = ({ children, className, errors, ...rest }) => {
15199
+ const content = React26.useMemo(() => {
15200
+ if (children) return children;
15201
+ const messages = (errors ?? []).map(toMessage).filter((message2) => !!message2);
15202
+ if (messages.length === 0) return null;
15203
+ if (messages.length === 1) return messages[0];
15204
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "tw-m-0 tw-flex tw-list-disc tw-flex-col tw-gap-0 tw-pl-4", children: messages.map((message2, index) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: message2 }, index)) });
15205
+ }, [children, errors]);
15206
+ if (!content) return null;
15207
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...rest, role: "alert", className: cn("tw-m-0 tw-text-xs tw-text-destructive", className), children: content });
15208
+ };
15183
15209
  var helpVariants = classVarianceAuthority.cva(["tw-m-0", "tw-text-xs"], {
15184
15210
  defaultVariants: {
15185
15211
  state: "default"
@@ -15187,18 +15213,17 @@ var helpVariants = classVarianceAuthority.cva(["tw-m-0", "tw-text-xs"], {
15187
15213
  variants: {
15188
15214
  state: {
15189
15215
  default: ["tw-text-muted-foreground"],
15190
- error: ["tw-text-destructive"],
15191
15216
  warning: ["tw-text-warning"]
15192
15217
  }
15193
15218
  }
15194
15219
  });
15195
- var HelpBlock = ({ children, className, state = "default", testId }) => {
15220
+ var HelpBlock = ({ children, className, state = "default", ...rest }) => {
15196
15221
  if (!children) return null;
15197
- return /* @__PURE__ */ jsxRuntime.jsx("p", { "data-testid": testId, className: helpVariants({ state, className }), children });
15222
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { ...rest, className: helpVariants({ state, className }), children });
15198
15223
  };
15199
15224
  var FormGroupHelp = ({ children, ...rest }) => {
15200
15225
  const formGroupContext = useFormGroupContext();
15201
- return /* @__PURE__ */ jsxRuntime.jsx(HelpBlock, { state: formGroupContext.state, ...rest, children });
15226
+ return /* @__PURE__ */ jsxRuntime.jsx(HelpBlock, { state: formGroupContext.state === "warning" ? "warning" : "default", ...rest, children });
15202
15227
  };
15203
15228
  var FormGroupNumberInput = ({
15204
15229
  ref,
@@ -15218,10 +15243,11 @@ var FormGroupTextInput = ({
15218
15243
  const { state } = useFormGroupContext();
15219
15244
  return /* @__PURE__ */ jsxRuntime.jsx(TextInput, { state, ...props, ref });
15220
15245
  };
15221
- var FormGroup = ({ className, children, state, testId }) => {
15222
- return /* @__PURE__ */ jsxRuntime.jsx(FormGroupProvider, { value: { state }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, className: cn("tw-flex tw-flex-col tw-gap-1", className), children }) });
15246
+ var FormGroup = ({ className, children, state, ...rest }) => {
15247
+ return /* @__PURE__ */ jsxRuntime.jsx(FormGroupProvider, { value: { state }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ...rest, className: cn("tw-flex tw-flex-col tw-gap-1", className), children }) });
15223
15248
  };
15224
15249
  FormGroup.Help = FormGroupHelp;
15250
+ FormGroup.Error = FormGroupError;
15225
15251
  FormGroup.TextInput = FormGroupTextInput;
15226
15252
  FormGroup.NumberInput = FormGroupNumberInput;
15227
15253
  FormGroup.ColorInput = FormGroupColorInput;
@@ -15450,7 +15476,7 @@ var ANIMATION_CLASS_NAME = cn(
15450
15476
  "tw-relative",
15451
15477
  "tw-overflow-hidden",
15452
15478
  "tw-pointer-events-none",
15453
- "tw-bg-muted",
15479
+ "tw-bg-skeleton",
15454
15480
  // before
15455
15481
  'before:tw-content-[""]',
15456
15482
  "before:tw-opacity-100",
@@ -18444,6 +18470,11 @@ var tokensToCssVars = ({
18444
18470
  vars.set("--font-sans", typography?.fontFamily?.trim() || void 0);
18445
18471
  vars.set("--font-display", typography?.fontDisplay?.trim() || void 0);
18446
18472
  vars.set("--font-mono", typography?.fontMono?.trim() || void 0);
18473
+ vars.set("--font-weight-normal", typography?.weight?.normal);
18474
+ vars.set("--font-weight-medium", typography?.weight?.medium);
18475
+ vars.set("--font-weight-semibold", typography?.weight?.semibold);
18476
+ vars.set("--font-weight-bold", typography?.weight?.bold);
18477
+ vars.set("--letter-spacing-chrome", typography?.letterSpacing?.chrome);
18447
18478
  vars.set("--radius-sm", radii?.sm);
18448
18479
  vars.set("--radius-md", radii?.md);
18449
18480
  vars.set("--radius-lg", radii?.lg);
@@ -20942,13 +20973,29 @@ var BreadcrumbDropdownGroup = ({
20942
20973
  [parent, labelMatched, registerChild]
20943
20974
  );
20944
20975
  const isExpanded = !collapsible || expanded || filtering;
20976
+ const isEmpty = React26.Children.count(children) === 0;
20945
20977
  return /* @__PURE__ */ jsxRuntime.jsxs(
20946
20978
  "div",
20947
20979
  {
20948
20980
  className: cn("tw-flex tw-flex-col", className),
20949
20981
  style: visible ? void 0 : { display: "none" },
20950
20982
  children: [
20951
- collapsible ? /* @__PURE__ */ jsxRuntime.jsxs(
20983
+ collapsible && isEmpty ? /* @__PURE__ */ jsxRuntime.jsxs(
20984
+ "span",
20985
+ {
20986
+ "aria-disabled": true,
20987
+ className: cn(
20988
+ headerClass,
20989
+ "tw-text-muted-foreground",
20990
+ // Fade just the leading chevron lighter than the label text.
20991
+ "[&>svg:first-child]:tw-opacity-50"
20992
+ ),
20993
+ children: [
20994
+ /* @__PURE__ */ jsxRuntime.jsx(icons_exports.ChevronRight, {}),
20995
+ label
20996
+ ]
20997
+ }
20998
+ ) : collapsible && !isEmpty ? /* @__PURE__ */ jsxRuntime.jsxs(
20952
20999
  "button",
20953
21000
  {
20954
21001
  type: "button",
@@ -20961,7 +21008,31 @@ var BreadcrumbDropdownGroup = ({
20961
21008
  ]
20962
21009
  }
20963
21010
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: headerClass, children: label }),
20964
- /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbDropdownContext, { value: childContext, children: /* @__PURE__ */ jsxRuntime.jsx(
21011
+ /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbDropdownContext, { value: childContext, children: collapsible && !isEmpty ? (
21012
+ // Animated expand / collapse via a CSS grid-rows transition (0fr ↔ 1fr). The children stay
21013
+ // mounted while collapsed so the filter registry keeps receiving their visibility; `inert`
21014
+ // + `aria-hidden` take the collapsed content out of the a11y tree and tab order. An active
21015
+ // filter query force-expands (`isExpanded` includes `filtering`).
21016
+ /* @__PURE__ */ jsxRuntime.jsx(
21017
+ "div",
21018
+ {
21019
+ className: cn(
21020
+ "tw-grid tw-transition-[grid-template-rows] tw-duration-200 tw-ease-out",
21021
+ "motion-reduce:tw-transition-none",
21022
+ isExpanded ? "tw-grid-rows-[1fr]" : "tw-grid-rows-[0fr]"
21023
+ ),
21024
+ children: /* @__PURE__ */ jsxRuntime.jsx(
21025
+ "div",
21026
+ {
21027
+ className: "tw-overflow-hidden",
21028
+ inert: !isExpanded,
21029
+ "aria-hidden": isExpanded ? void 0 : true,
21030
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tw-flex tw-flex-col tw-pl-6", children })
21031
+ }
21032
+ )
21033
+ }
21034
+ )
21035
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
20965
21036
  "div",
20966
21037
  {
20967
21038
  className: "tw-flex tw-flex-col tw-pl-6",
@@ -21087,11 +21158,12 @@ var chevronButtonClass = cn(
21087
21158
  "tw-flex",
21088
21159
  "tw-items-center",
21089
21160
  "tw-justify-center",
21090
- "tw-rounded-sm",
21161
+ "tw-rounded-md",
21091
21162
  "tw-border-none",
21092
21163
  "tw-bg-transparent",
21093
21164
  "tw-cursor-pointer",
21094
- "tw-p-0.5",
21165
+ // Generous 24px hit target (was ~18px) — colour-only hover, no background box.
21166
+ "tw-size-6",
21095
21167
  "tw-text-muted-foreground",
21096
21168
  "tw-transition-colors",
21097
21169
  "hover:tw-text-foreground",
@@ -22944,84 +23016,179 @@ var SubmitButton = ({ children = "Submit", ...buttonProps }) => {
22944
23016
  }
22945
23017
  );
22946
23018
  };
22947
- var errorMessage = (field) => {
22948
- const first = field.state.meta.errors[0];
22949
- if (!first) return void 0;
22950
- if (typeof first === "string") return first;
22951
- if (typeof first === "object" && first !== null && "message" in first) {
22952
- const message2 = first.message;
22953
- return typeof message2 === "string" ? message2 : void 0;
22954
- }
22955
- return void 0;
22956
- };
22957
- var FieldShell = ({ field, label, required, help, className, children }) => {
22958
- const error = errorMessage(field);
22959
- const showError = field.state.meta.isTouched && !!error;
22960
- return /* @__PURE__ */ jsxRuntime.jsxs(FormGroup, { className, state: showError ? "error" : void 0, children: [
22961
- label && /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: field.name, children: [
22962
- label,
22963
- required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tw-ml-0.5 tw-text-primary", children: "*" })
23019
+ var FieldItem = ({
23020
+ label,
23021
+ required,
23022
+ requiredMark = "required",
23023
+ help,
23024
+ tooltip,
23025
+ className,
23026
+ "aria-describedby": ariaDescribedBy,
23027
+ children
23028
+ }) => {
23029
+ const field = useFieldContext();
23030
+ const { errors, isTouched } = field.state.meta;
23031
+ const isInvalid = isTouched && errors.length > 0;
23032
+ const errorId = `${field.name}-error`;
23033
+ const descriptionId = `${field.name}-description`;
23034
+ const describedBy = [ariaDescribedBy, !!help && descriptionId, isInvalid && errorId].filter(Boolean).join(" ") || void 0;
23035
+ return /* @__PURE__ */ jsxRuntime.jsxs(FormGroup, { className, children: [
23036
+ label && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tw-flex tw-items-center tw-gap-1", children: [
23037
+ /* @__PURE__ */ jsxRuntime.jsxs(Label2, { htmlFor: field.name, children: [
23038
+ label,
23039
+ requiredMark === "required" && required && /* @__PURE__ */ jsxRuntime.jsx(Label2.Required, {}),
23040
+ requiredMark === "optional" && !required && /* @__PURE__ */ jsxRuntime.jsx(Label2.Optional, {})
23041
+ ] }),
23042
+ tooltip && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { tooltip, placement: "top", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
23043
+ "button",
23044
+ {
23045
+ type: "button",
23046
+ "aria-label": typeof label === "string" ? `More information about ${label}` : "More information",
23047
+ className: "tailwindcss-preflight tw-text-muted-foreground focus:tw-outline-none focus-visible:tw-text-primary",
23048
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons_exports.Info, { className: "tw-size-3" })
23049
+ }
23050
+ ) })
22964
23051
  ] }),
22965
- children,
22966
- showError ? /* @__PURE__ */ jsxRuntime.jsx(FormGroup.Help, { children: error }) : help && /* @__PURE__ */ jsxRuntime.jsx(FormGroup.Help, { children: help })
23052
+ children({
23053
+ id: field.name,
23054
+ name: field.name,
23055
+ "aria-required": required || void 0,
23056
+ "aria-invalid": isInvalid || void 0,
23057
+ "aria-describedby": describedBy
23058
+ }),
23059
+ (help || isInvalid) && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
23060
+ help && /* @__PURE__ */ jsxRuntime.jsx(FormGroup.Help, { id: descriptionId, children: help }),
23061
+ isInvalid && /* @__PURE__ */ jsxRuntime.jsx(FormGroup.Error, { id: errorId, errors })
23062
+ ] })
22967
23063
  ] });
22968
23064
  };
22969
- var CheckboxField = ({ label, help, className, children, ...checkboxProps }) => {
23065
+ var CheckboxField = ({ className, children, ...checkboxProps }) => {
22970
23066
  const field = useFieldContext();
22971
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
23067
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldItem, { className, children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
22972
23068
  Checkbox,
22973
23069
  {
22974
- id: field.name,
22975
- name: field.name,
23070
+ ...checkboxProps,
23071
+ ...control,
22976
23072
  checked: field.state.value ?? false,
22977
- onCheckedChange: (checked) => {
22978
- field.handleChange(checked === true);
22979
- },
23073
+ onCheckedChange: (checked) => field.handleChange(checked === true),
22980
23074
  onBlur: field.handleBlur,
22981
- ...checkboxProps,
22982
- children: children ?? label
23075
+ children
22983
23076
  }
22984
23077
  ) });
22985
23078
  };
22986
- var NumberField = ({ label, required, help, className, ...inputProps }) => {
23079
+ var NumberField = ({
23080
+ label,
23081
+ required,
23082
+ requiredMark,
23083
+ help,
23084
+ tooltip,
23085
+ className,
23086
+ "aria-describedby": ariaDescribedBy,
23087
+ ...inputProps
23088
+ }) => {
23089
+ const field = useFieldContext();
23090
+ return /* @__PURE__ */ jsxRuntime.jsx(
23091
+ FieldItem,
23092
+ {
23093
+ label,
23094
+ required,
23095
+ requiredMark,
23096
+ help,
23097
+ tooltip,
23098
+ className,
23099
+ "aria-describedby": ariaDescribedBy,
23100
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23101
+ NumberInput,
23102
+ {
23103
+ ...inputProps,
23104
+ ...control,
23105
+ value: field.state.value ?? null,
23106
+ onValueChange: field.handleChange,
23107
+ onBlur: field.handleBlur
23108
+ }
23109
+ )
23110
+ }
23111
+ );
23112
+ };
23113
+ var OtpInputField = ({
23114
+ label,
23115
+ required,
23116
+ requiredMark,
23117
+ help,
23118
+ tooltip,
23119
+ className,
23120
+ "aria-describedby": ariaDescribedBy,
23121
+ maxLength,
23122
+ ...otpProps
23123
+ }) => {
22987
23124
  const field = useFieldContext();
22988
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, label, required, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
22989
- FormGroup.NumberInput,
23125
+ return /* @__PURE__ */ jsxRuntime.jsx(
23126
+ FieldItem,
22990
23127
  {
22991
- id: field.name,
22992
- name: field.name,
22993
- value: field.state.value ?? null,
22994
- onValueChange: (value) => {
22995
- field.handleChange(value);
22996
- },
22997
- onBlur: field.handleBlur,
22998
- ...inputProps
23128
+ label,
23129
+ required,
23130
+ requiredMark,
23131
+ help,
23132
+ tooltip,
23133
+ className,
23134
+ "aria-describedby": ariaDescribedBy,
23135
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23136
+ OtpInput,
23137
+ {
23138
+ ...otpProps,
23139
+ ...control,
23140
+ maxLength,
23141
+ value: field.state.value ?? "",
23142
+ onChange: field.handleChange,
23143
+ onBlur: field.handleBlur,
23144
+ children: /* @__PURE__ */ jsxRuntime.jsx(OtpInput.Group, { children: Array.from({ length: maxLength }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(OtpInput.Slot, { index }, index)) })
23145
+ }
23146
+ )
22999
23147
  }
23000
- ) });
23148
+ );
23001
23149
  };
23002
- var PasswordField = ({ label, required, help, className, ...inputProps }) => {
23150
+ var PasswordField = ({
23151
+ label,
23152
+ required,
23153
+ requiredMark,
23154
+ help,
23155
+ tooltip,
23156
+ className,
23157
+ "aria-describedby": ariaDescribedBy,
23158
+ ...inputProps
23159
+ }) => {
23003
23160
  const field = useFieldContext();
23004
- const showError = field.state.meta.isTouched && field.state.meta.errors.length > 0;
23005
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, label, required, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
23006
- PasswordInput,
23161
+ return /* @__PURE__ */ jsxRuntime.jsx(
23162
+ FieldItem,
23007
23163
  {
23008
- id: field.name,
23009
- name: field.name,
23010
- value: field.state.value ?? "",
23011
- state: showError ? "error" : void 0,
23012
- onValueChange: (value) => {
23013
- field.handleChange(value);
23014
- },
23015
- onBlur: field.handleBlur,
23016
- ...inputProps
23164
+ label,
23165
+ required,
23166
+ requiredMark,
23167
+ help,
23168
+ tooltip,
23169
+ className,
23170
+ "aria-describedby": ariaDescribedBy,
23171
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23172
+ PasswordInput,
23173
+ {
23174
+ ...inputProps,
23175
+ ...control,
23176
+ value: field.state.value ?? "",
23177
+ onValueChange: field.handleChange,
23178
+ onBlur: field.handleBlur
23179
+ }
23180
+ )
23017
23181
  }
23018
- ) });
23182
+ );
23019
23183
  };
23020
23184
  var SelectField = ({
23021
23185
  label,
23022
23186
  required,
23187
+ requiredMark,
23023
23188
  help,
23189
+ tooltip,
23024
23190
  className,
23191
+ "aria-describedby": ariaDescribedBy,
23025
23192
  items,
23026
23193
  options,
23027
23194
  placeholder,
@@ -23033,80 +23200,125 @@ var SelectField = ({
23033
23200
  }) => {
23034
23201
  const field = useFieldContext();
23035
23202
  const resolved = items ?? options ?? [];
23036
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, label, required, help, className, children: /* @__PURE__ */ jsxRuntime.jsxs(
23037
- Select2.Root,
23203
+ return /* @__PURE__ */ jsxRuntime.jsx(
23204
+ FieldItem,
23038
23205
  {
23039
- value: field.state.value ?? "",
23040
- onValueChange: (value) => {
23041
- field.handleChange(value);
23042
- },
23043
- ...rootProps,
23044
- children: [
23045
- /* @__PURE__ */ jsxRuntime.jsx(
23046
- Select2.Trigger,
23047
- {
23048
- id: field.name,
23049
- className: triggerClassName ?? "tw-w-full",
23050
- placeholder,
23051
- variant,
23052
- state,
23053
- sizing,
23054
- onBlur: field.handleBlur
23055
- }
23056
- ),
23057
- /* @__PURE__ */ jsxRuntime.jsx(Select2.Content, { children: resolved.map((option) => /* @__PURE__ */ jsxRuntime.jsx(Select2.Item, { value: option.value, children: option.label }, option.value)) })
23058
- ]
23206
+ label,
23207
+ required,
23208
+ requiredMark,
23209
+ help,
23210
+ tooltip,
23211
+ className,
23212
+ "aria-describedby": ariaDescribedBy,
23213
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsxs(
23214
+ Select2.Root,
23215
+ {
23216
+ value: field.state.value ?? "",
23217
+ onValueChange: (value) => {
23218
+ field.handleChange(value);
23219
+ },
23220
+ ...rootProps,
23221
+ children: [
23222
+ /* @__PURE__ */ jsxRuntime.jsx(
23223
+ Select2.Trigger,
23224
+ {
23225
+ ...control,
23226
+ className: triggerClassName ?? "tw-w-full",
23227
+ placeholder,
23228
+ variant,
23229
+ state,
23230
+ sizing,
23231
+ onBlur: field.handleBlur
23232
+ }
23233
+ ),
23234
+ /* @__PURE__ */ jsxRuntime.jsx(Select2.Content, { children: resolved.map((option) => /* @__PURE__ */ jsxRuntime.jsx(Select2.Item, { value: option.value, children: option.label }, option.value)) })
23235
+ ]
23236
+ }
23237
+ )
23059
23238
  }
23060
- ) });
23239
+ );
23061
23240
  };
23062
- var SwitchField = ({ label, help, className, children, ...switchProps }) => {
23241
+ var SwitchField = ({ className, children, ...switchProps }) => {
23063
23242
  const field = useFieldContext();
23064
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
23243
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldItem, { className, children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23065
23244
  Switch,
23066
23245
  {
23067
- id: field.name,
23068
- name: field.name,
23246
+ ...switchProps,
23247
+ ...control,
23069
23248
  checked: field.state.value ?? false,
23070
- onCheckedChange: (checked) => {
23071
- field.handleChange(checked);
23072
- },
23249
+ onCheckedChange: field.handleChange,
23073
23250
  onBlur: field.handleBlur,
23074
- ...switchProps,
23075
- children: children ?? label
23251
+ children
23076
23252
  }
23077
23253
  ) });
23078
23254
  };
23079
- var TextAreaField = ({ label, required, help, className, ...inputProps }) => {
23255
+ var TextareaField = ({
23256
+ label,
23257
+ required,
23258
+ requiredMark,
23259
+ help,
23260
+ tooltip,
23261
+ className,
23262
+ "aria-describedby": ariaDescribedBy,
23263
+ ...inputProps
23264
+ }) => {
23080
23265
  const field = useFieldContext();
23081
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, label, required, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
23082
- FormGroup.Textarea,
23266
+ return /* @__PURE__ */ jsxRuntime.jsx(
23267
+ FieldItem,
23083
23268
  {
23084
- id: field.name,
23085
- name: field.name,
23086
- value: field.state.value ?? "",
23087
- onValueChange: (value) => {
23088
- field.handleChange(value);
23089
- },
23090
- onBlur: field.handleBlur,
23091
- ...inputProps
23269
+ label,
23270
+ required,
23271
+ requiredMark,
23272
+ help,
23273
+ tooltip,
23274
+ className,
23275
+ "aria-describedby": ariaDescribedBy,
23276
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23277
+ Textarea,
23278
+ {
23279
+ ...inputProps,
23280
+ ...control,
23281
+ value: field.state.value ?? "",
23282
+ onValueChange: field.handleChange,
23283
+ onBlur: field.handleBlur
23284
+ }
23285
+ )
23092
23286
  }
23093
- ) });
23287
+ );
23094
23288
  };
23095
- var TextField = ({ label, required, help, className, ...inputProps }) => {
23289
+ var TextField = ({
23290
+ label,
23291
+ required,
23292
+ requiredMark,
23293
+ help,
23294
+ tooltip,
23295
+ className,
23296
+ "aria-describedby": ariaDescribedBy,
23297
+ ...inputProps
23298
+ }) => {
23096
23299
  const field = useFieldContext();
23097
- return /* @__PURE__ */ jsxRuntime.jsx(FieldShell, { field, label, required, help, className, children: /* @__PURE__ */ jsxRuntime.jsx(
23098
- FormGroup.TextInput,
23300
+ return /* @__PURE__ */ jsxRuntime.jsx(
23301
+ FieldItem,
23099
23302
  {
23100
- id: field.name,
23101
- name: field.name,
23102
- value: field.state.value ?? "",
23103
- onChange: (e) => {
23104
- field.handleChange(e.target.value);
23105
- },
23106
- onBlur: field.handleBlur,
23107
- ...inputProps
23303
+ label,
23304
+ required,
23305
+ requiredMark,
23306
+ help,
23307
+ tooltip,
23308
+ className,
23309
+ "aria-describedby": ariaDescribedBy,
23310
+ children: (control) => /* @__PURE__ */ jsxRuntime.jsx(
23311
+ TextInput,
23312
+ {
23313
+ ...inputProps,
23314
+ ...control,
23315
+ value: field.state.value ?? "",
23316
+ onValueChange: field.handleChange,
23317
+ onBlur: field.handleBlur
23318
+ }
23319
+ )
23108
23320
  }
23109
- ) });
23321
+ );
23110
23322
  };
23111
23323
 
23112
23324
  // src/blocks/Form/formHook.ts
@@ -23117,10 +23329,11 @@ var { useAppForm, withForm } = reactForm.createFormHook({
23117
23329
  TextField,
23118
23330
  NumberField,
23119
23331
  PasswordField,
23120
- TextAreaField,
23332
+ TextareaField,
23121
23333
  SelectField,
23122
23334
  CheckboxField,
23123
- SwitchField
23335
+ SwitchField,
23336
+ OtpInputField
23124
23337
  },
23125
23338
  formComponents: {
23126
23339
  FormBody,
@@ -23344,7 +23557,6 @@ exports.HoverCard = HoverCard;
23344
23557
  exports.InlineStepDetail = InlineStepDetail;
23345
23558
  exports.InlineStepLabel = InlineStepLabel;
23346
23559
  exports.InputGroup = InputGroup;
23347
- exports.InputOtp = InputOtp;
23348
23560
  exports.Kbd = Kbd;
23349
23561
  exports.Label = Label2;
23350
23562
  exports.Link = Link;
@@ -23356,6 +23568,7 @@ exports.MultiActionButtonGroup = MultiActionButtonGroup;
23356
23568
  exports.MultiCombobox = MultiCombobox;
23357
23569
  exports.Navbar = Navbar;
23358
23570
  exports.NumberInput = NumberInput;
23571
+ exports.OtpInput = OtpInput;
23359
23572
  exports.PageHeader = PageHeader;
23360
23573
  exports.PageLayout = PageLayout;
23361
23574
  exports.PageToolbar = PageToolbar;
@@ -23429,7 +23642,6 @@ exports.toast = toast;
23429
23642
  exports.useAppForm = useAppForm;
23430
23643
  exports.useArgoDesign = useArgoDesign;
23431
23644
  exports.useAutosizeInput = useAutosizeInput;
23432
- exports.useInputOtpContext = useInputOtpContext;
23433
23645
  exports.useMergeDiff = useMergeDiff;
23434
23646
  exports.useNotification = useNotification;
23435
23647
  exports.useScrollbarPosition = useScrollbarPosition;