@keboola/design 5.1.0 → 6.1.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.
@@ -590,11 +590,12 @@ var init_styles = __esm({
590
590
  "tw-items-center",
591
591
  "tw-justify-center",
592
592
  "tw-gap-2",
593
- // text
593
+ // text — chrome weight/tracking are brand-overridable tokens
594
+ // (`--font-weight-medium` / `--letter-spacing-chrome`); casing stays `tw-uppercase`.
594
595
  "tw-text-xs",
595
596
  "tw-leading-5",
596
597
  "tw-font-medium",
597
- "tw-tracking-[1px]",
598
+ "tw-tracking-chrome",
598
599
  "tw-uppercase",
599
600
  // border — legacy (non-argo) chrome uses a fixed radius, not the brand token.
600
601
  "tw-rounded",
@@ -1042,13 +1043,14 @@ var init_Clipboard2 = __esm({
1042
1043
  init_Clipboard();
1043
1044
  }
1044
1045
  });
1045
- var DEFAULT_ICON, ClipboardButton;
1046
+ var DEFAULT_ICON, DEFAULT_ARIA_LABEL, ClipboardButton;
1046
1047
  var init_ClipboardButton = __esm({
1047
1048
  "src/blocks/ClipboardButton/ClipboardButton.tsx"() {
1048
1049
  init_Button2();
1049
1050
  init_Clipboard2();
1050
1051
  init_icons();
1051
1052
  DEFAULT_ICON = /* @__PURE__ */ jsx(icons_exports.Copy, {});
1053
+ DEFAULT_ARIA_LABEL = "Copy";
1052
1054
  ClipboardButton = ({
1053
1055
  // clipboard props
1054
1056
  text,
@@ -1060,20 +1062,24 @@ var init_ClipboardButton = __esm({
1060
1062
  variant = "outline",
1061
1063
  children,
1062
1064
  ...rest
1063
- }) => /* @__PURE__ */ jsx(
1064
- Clipboard,
1065
- {
1066
- asChild: true,
1067
- tooltip,
1068
- tooltipPlacement,
1069
- tooltipVariant,
1070
- text,
1071
- children: /* @__PURE__ */ jsxs(Button, { ...rest, variant, disabled: !text, children: [
1072
- icon,
1073
- children
1074
- ] })
1075
- }
1076
- );
1065
+ }) => {
1066
+ const defaultAriaLabel = typeof tooltip === "string" && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;
1067
+ const ariaLabel = rest["aria-label"] ?? (children == null ? defaultAriaLabel : void 0);
1068
+ return /* @__PURE__ */ jsx(
1069
+ Clipboard,
1070
+ {
1071
+ asChild: true,
1072
+ tooltip,
1073
+ tooltipPlacement,
1074
+ tooltipVariant,
1075
+ text,
1076
+ children: /* @__PURE__ */ jsxs(Button, { ...rest, "aria-label": ariaLabel, variant, disabled: !text, children: [
1077
+ icon,
1078
+ children
1079
+ ] })
1080
+ }
1081
+ );
1082
+ };
1077
1083
  }
1078
1084
  });
1079
1085
 
@@ -3426,11 +3432,23 @@ var inputGroupVariants = cva(
3426
3432
  off: ["has-[:is(input,textarea):focus]:!tw-ring-0"]
3427
3433
  },
3428
3434
  variant: {
3429
- primary: ["tw-bg-white", "has-[:is(input,textarea):disabled]:tw-opacity-40"],
3435
+ primary: [
3436
+ "tw-bg-white",
3437
+ "has-[:is(input,textarea):disabled]:tw-opacity-40",
3438
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
3439
+ // accessible path (mirrors the `state="error"` legacy tokens). Higher specificity than
3440
+ // the default focus selector, so it wins without `!important`.
3441
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-error-500",
3442
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-error-500",
3443
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-error-200"
3444
+ ],
3430
3445
  secondary: [
3431
3446
  "tw-bg-neutral-100",
3432
3447
  "tw-border-neutral-100",
3433
- "has-[:is(input,textarea):disabled]:tw-opacity-40"
3448
+ "has-[:is(input,textarea):disabled]:tw-opacity-40",
3449
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-error-500",
3450
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-error-500",
3451
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-error-200"
3434
3452
  ],
3435
3453
  argo: [
3436
3454
  // argo follows the brand radius token (overrides the static base)
@@ -3441,7 +3459,12 @@ var inputGroupVariants = cva(
3441
3459
  "tw-text-foreground",
3442
3460
  "has-[:is(input,textarea):disabled]:tw-opacity-50",
3443
3461
  // higher specificity than has-[:is(input,textarea):focus] — prevents focus border on readonly
3444
- "has-[:is(input,textarea)[readonly]:focus]:tw-border-neutral-150"
3462
+ "has-[:is(input,textarea)[readonly]:focus]:tw-border-neutral-150",
3463
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
3464
+ // accessible path (uses the themeable `destructive` status token).
3465
+ "has-[:is(input,textarea)[aria-invalid=true]]:tw-border-destructive",
3466
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-border-destructive",
3467
+ "has-[:is(input,textarea)[aria-invalid=true]:focus]:tw-ring-destructive/20"
3445
3468
  ]
3446
3469
  },
3447
3470
  sizing: {
@@ -3729,6 +3752,21 @@ var FormGroupColorInput = ({
3729
3752
  const { state } = useFormGroupContext();
3730
3753
  return /* @__PURE__ */ jsx(ColorInput, { state, ...props, ref });
3731
3754
  };
3755
+
3756
+ // src/components/FormGroup/FormGroupError.tsx
3757
+ init_utils2();
3758
+ var toMessage = (entry) => typeof entry === "string" ? entry : entry?.message;
3759
+ var FormGroupError = ({ children, className, errors, ...rest }) => {
3760
+ const content = useMemo(() => {
3761
+ if (children) return children;
3762
+ const messages = (errors ?? []).map(toMessage).filter((message) => !!message);
3763
+ if (messages.length === 0) return null;
3764
+ if (messages.length === 1) return messages[0];
3765
+ return /* @__PURE__ */ jsx("ul", { className: "tw-m-0 tw-flex tw-list-disc tw-flex-col tw-gap-0 tw-pl-4", children: messages.map((message, index) => /* @__PURE__ */ jsx("li", { children: message }, index)) });
3766
+ }, [children, errors]);
3767
+ if (!content) return null;
3768
+ return /* @__PURE__ */ jsx("div", { ...rest, role: "alert", className: cn("tw-m-0 tw-text-xs tw-text-destructive", className), children: content });
3769
+ };
3732
3770
  var helpVariants = cva(["tw-m-0", "tw-text-xs"], {
3733
3771
  defaultVariants: {
3734
3772
  state: "default"
@@ -3736,18 +3774,17 @@ var helpVariants = cva(["tw-m-0", "tw-text-xs"], {
3736
3774
  variants: {
3737
3775
  state: {
3738
3776
  default: ["tw-text-muted-foreground"],
3739
- error: ["tw-text-destructive"],
3740
3777
  warning: ["tw-text-warning"]
3741
3778
  }
3742
3779
  }
3743
3780
  });
3744
- var HelpBlock = ({ children, className, state = "default", testId }) => {
3781
+ var HelpBlock = ({ children, className, state = "default", ...rest }) => {
3745
3782
  if (!children) return null;
3746
- return /* @__PURE__ */ jsx("p", { "data-testid": testId, className: helpVariants({ state, className }), children });
3783
+ return /* @__PURE__ */ jsx("p", { ...rest, className: helpVariants({ state, className }), children });
3747
3784
  };
3748
3785
  var FormGroupHelp = ({ children, ...rest }) => {
3749
3786
  const formGroupContext = useFormGroupContext();
3750
- return /* @__PURE__ */ jsx(HelpBlock, { state: formGroupContext.state, ...rest, children });
3787
+ return /* @__PURE__ */ jsx(HelpBlock, { state: formGroupContext.state === "warning" ? "warning" : "default", ...rest, children });
3751
3788
  };
3752
3789
  var toNumberOrNull = (event) => Number.isNaN(event.target.valueAsNumber) ? null : event.target.valueAsNumber;
3753
3790
  var NumberInput = ({
@@ -4002,10 +4039,11 @@ var FormGroupTextInput = ({
4002
4039
  const { state } = useFormGroupContext();
4003
4040
  return /* @__PURE__ */ jsx(TextInput, { state, ...props, ref });
4004
4041
  };
4005
- var FormGroup = ({ className, children, state, testId }) => {
4006
- return /* @__PURE__ */ jsx(FormGroupProvider, { value: { state }, children: /* @__PURE__ */ jsx("div", { "data-testid": testId, className: cn("tw-flex tw-flex-col tw-gap-1", className), children }) });
4042
+ var FormGroup = ({ className, children, state, ...rest }) => {
4043
+ return /* @__PURE__ */ jsx(FormGroupProvider, { value: { state }, children: /* @__PURE__ */ jsx("div", { ...rest, className: cn("tw-flex tw-flex-col tw-gap-1", className), children }) });
4007
4044
  };
4008
4045
  FormGroup.Help = FormGroupHelp;
4046
+ FormGroup.Error = FormGroupError;
4009
4047
  FormGroup.TextInput = FormGroupTextInput;
4010
4048
  FormGroup.NumberInput = FormGroupNumberInput;
4011
4049
  FormGroup.ColorInput = FormGroupColorInput;
@@ -4013,23 +4051,23 @@ FormGroup.Textarea = FormGroupTextarea;
4013
4051
 
4014
4052
  // src/components/Label/Label.tsx
4015
4053
  init_utils2();
4016
- var Optional = ({ className }) => /* @__PURE__ */ jsx("span", { className: cn("tw-text-muted-foreground", className), children: "(optional)" });
4017
- var Label2 = ({ className, children, id, htmlFor, ...rest }) => {
4018
- return /* @__PURE__ */ jsx(
4019
- RLabel.Root,
4020
- {
4021
- ...rest,
4022
- id: id?.toString(),
4023
- htmlFor: htmlFor?.toString(),
4024
- className: cn(
4025
- "tw-m-0 tw-text-foreground tw-font-normal peer-disabled:tw-opacity-50",
4026
- className
4027
- ),
4028
- children
4029
- }
4030
- );
4031
- };
4054
+ var Optional = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, "aria-hidden": true, className: cn("tw-ml-0.5", "tw-text-muted-foreground", className), children: "(optional)" });
4055
+ var Required = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, "aria-hidden": true, className: cn("tw-ml-0.5", "tw-text-primary", className), children: "*" });
4056
+ var Label2 = ({ className, children, id, htmlFor, ...rest }) => /* @__PURE__ */ jsx(
4057
+ RLabel.Root,
4058
+ {
4059
+ ...rest,
4060
+ id: id?.toString(),
4061
+ htmlFor: htmlFor?.toString(),
4062
+ className: cn(
4063
+ "tw-m-0 tw-text-foreground tw-font-normal peer-disabled:tw-opacity-50",
4064
+ className
4065
+ ),
4066
+ children
4067
+ }
4068
+ );
4032
4069
  Label2.Optional = Optional;
4070
+ Label2.Required = Required;
4033
4071
 
4034
4072
  // src/components/MarkdownEditor/plugins/toolbar/ToolbarButton.tsx
4035
4073
  init_utils2();