@pipelex/mthds-form 0.22.0 → 0.23.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.
@@ -566,20 +566,12 @@ function FieldShell({
566
566
  ] });
567
567
  }
568
568
 
569
- // src/react/brand-ink.ts
570
- var brandInkClass = "text-[color:var(--brand,var(--primary,hsl(240_5.9%_10%)))]";
571
- var brandFillInkClass = "text-[color:var(--brand-muted-foreground,var(--brand,var(--primary,hsl(240_5.9%_10%))))]";
572
- var brandFillClass = "bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
573
- var brandFillSelectedClass = "data-[state=on]:bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
574
- var brandFillStrongClass = "bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_15%,transparent))]";
575
- var brandFocusClass = "focus-visible:border-[color:var(--brand,var(--primary,hsl(240_5.9%_10%)))] focus-visible:ring-[color:color-mix(in_oklab,var(--brand,var(--primary,hsl(240_5.9%_10%)))_40%,transparent)]";
576
-
577
569
  // src/react/field-styles.ts
578
570
  var fieldControlClass = cn(
579
571
  "w-full rounded-md border border-border bg-input text-sm text-foreground",
580
572
  "placeholder:text-muted-foreground/70 transition-colors",
581
573
  "focus-visible:outline-hidden focus-visible:ring-1",
582
- brandFocusClass,
574
+ "focus-visible:border-ring focus-visible:ring-ring/40",
583
575
  "disabled:cursor-not-allowed disabled:opacity-50",
584
576
  "aria-invalid:border-destructive aria-invalid:ring-destructive/30"
585
577
  );
@@ -612,6 +604,20 @@ function DateField({ field, value, onChange, id, error, disabled }) {
612
604
  );
613
605
  }
614
606
 
607
+ // src/react/role-tokens.ts
608
+ var linkTextClass = "text-[color:var(--link,var(--primary,hsl(240_5.9%_10%)))]";
609
+ var selectedFillClass = "bg-[color:var(--selected,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
610
+ var selectedStateFillClass = "data-[state=on]:bg-[color:var(--selected,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
611
+ var selectedCheckedFillClass = "aria-checked:bg-[color:var(--selected,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
612
+ var selectedFillStrongClass = "bg-[color:var(--selected,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_15%,transparent))]";
613
+ var selectedBorderClass = "border-[color:color-mix(in_oklab,var(--link,var(--primary,hsl(240_5.9%_10%)))_40%,transparent)]";
614
+ var selectedStateBorderClass = "data-[state=on]:border-[color:color-mix(in_oklab,var(--link,var(--primary,hsl(240_5.9%_10%)))_40%,transparent)]";
615
+ var selectedHoverBorderClass = "hover:border-[color:color-mix(in_oklab,var(--link,var(--primary,hsl(240_5.9%_10%)))_40%,transparent)]";
616
+ var checkedAccentClass = "accent-[color:var(--link,var(--primary,hsl(240_5.9%_10%)))]";
617
+ var focusOutlineClass = "focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring";
618
+ var focusOutlineInsetClass = "focus-visible:outline-solid focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring";
619
+ var frameFocusOutlineClass = "data-focus-visible:outline-solid data-focus-visible:outline-2 data-focus-visible:-outline-offset-2 data-focus-visible:outline-ring";
620
+
615
621
  // src/react/encoded-file.ts
616
622
  function encodedFileSummary(url, strings) {
617
623
  const view = readDataUrl(url);
@@ -748,6 +754,7 @@ function ListAction({
748
754
  onClick,
749
755
  className: cn(
750
756
  "inline-flex min-h-11 items-center justify-center rounded-md border border-border px-4 text-[14px] text-foreground transition-colors hover:bg-muted sm:min-h-9",
757
+ focusOutlineClass,
751
758
  className
752
759
  ),
753
760
  children
@@ -838,12 +845,15 @@ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @
838
845
  ));
839
846
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
840
847
  var toggleVariants = cva(
841
- "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2",
848
+ [
849
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:text-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2",
850
+ selectedStateFillClass
851
+ ],
842
852
  {
843
853
  variants: {
844
854
  variant: {
845
855
  default: "bg-transparent",
846
- outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"
856
+ outline: "border border-border bg-transparent hover:bg-accent hover:text-accent-foreground"
847
857
  },
848
858
  size: {
849
859
  default: "h-10 px-3 min-w-10",
@@ -913,7 +923,10 @@ function FilePickerEntry({ onOpen, label, disabled, ref, id }) {
913
923
  disabled,
914
924
  "aria-haspopup": "dialog",
915
925
  "aria-label": s.chooseFromSourceAria(label),
916
- className: "flex min-h-11 w-full items-center justify-center gap-2 rounded-md border border-border px-3 text-[14px] text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9",
926
+ className: cn(
927
+ "flex min-h-11 w-full items-center justify-center gap-2 rounded-md border border-border px-3 text-[14px] text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9",
928
+ focusOutlineClass
929
+ ),
917
930
  children: [
918
931
  /* @__PURE__ */ jsx(Folder, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
919
932
  s.chooseFromSource
@@ -1025,7 +1038,10 @@ function FilePickerBody({
1025
1038
  },
1026
1039
  placeholder: s.filePickerSearchPlaceholder,
1027
1040
  autoComplete: "off",
1028
- className: "h-11 w-full rounded-md border border-border bg-input pr-3 pl-9 text-[16px] text-foreground placeholder:text-muted-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring"
1041
+ className: cn(
1042
+ "h-11 w-full rounded-md border border-border bg-input pr-3 pl-9 text-[16px] text-foreground placeholder:text-muted-foreground",
1043
+ focusOutlineClass
1044
+ )
1029
1045
  }
1030
1046
  )
1031
1047
  ] }),
@@ -1091,7 +1107,10 @@ function FilePickerBody({
1091
1107
  type: "button",
1092
1108
  onClick: use6,
1093
1109
  disabled: choices.length === 0,
1094
- className: "flex h-12 w-full items-center justify-center rounded-md bg-primary px-4 text-[16px] font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50",
1110
+ className: cn(
1111
+ "flex h-12 w-full items-center justify-center rounded-md bg-primary px-4 text-[16px] font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50",
1112
+ focusOutlineClass
1113
+ ),
1095
1114
  children: /* @__PURE__ */ jsx("span", { className: "truncate", children: s.filePickerUse(choices.length, choices[0]?.name) })
1096
1115
  }
1097
1116
  ) })
@@ -1155,7 +1174,10 @@ function SheetHeader({
1155
1174
  DialogClose,
1156
1175
  {
1157
1176
  "aria-label": s.close,
1158
- className: "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
1177
+ className: cn(
1178
+ "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
1179
+ focusOutlineClass
1180
+ ),
1159
1181
  children: /* @__PURE__ */ jsx(X, { className: "size-5", "aria-hidden": "true" })
1160
1182
  }
1161
1183
  )
@@ -1201,9 +1223,9 @@ function FileRow({
1201
1223
  disabled,
1202
1224
  onClick: onToggle,
1203
1225
  className: cn(
1204
- "flex min-h-16 w-full items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-muted/60 disabled:cursor-not-allowed disabled:opacity-50",
1205
- "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring",
1206
- chosen && "bg-muted"
1226
+ "group flex min-h-16 w-full items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-muted/60 disabled:cursor-not-allowed disabled:opacity-50",
1227
+ focusOutlineInsetClass,
1228
+ selectedCheckedFillClass
1207
1229
  ),
1208
1230
  children: [
1209
1231
  /* @__PURE__ */ jsx(
@@ -1216,7 +1238,7 @@ function FileRow({
1216
1238
  ),
1217
1239
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
1218
1240
  /* @__PURE__ */ jsx("span", { className: "block truncate text-[16px] font-medium text-foreground", children: file.name }),
1219
- (file.kind === "test" || meta) && /* @__PURE__ */ jsxs("span", { className: "block truncate text-[13px] text-muted-foreground", children: [
1241
+ (file.kind === "test" || meta) && /* @__PURE__ */ jsxs("span", { className: "block truncate text-[13px] text-muted-foreground group-aria-checked:text-foreground", children: [
1220
1242
  file.kind === "test" && /* @__PURE__ */ jsxs("span", { className: "text-foreground", children: [
1221
1243
  s.testFile,
1222
1244
  meta && " \xB7 "
@@ -1227,7 +1249,7 @@ function FileRow({
1227
1249
  /* @__PURE__ */ jsx(
1228
1250
  Check,
1229
1251
  {
1230
- className: cn("size-5 shrink-0 text-foreground", !chosen && "invisible"),
1252
+ className: "invisible size-5 shrink-0 text-foreground group-aria-checked:visible",
1231
1253
  "aria-hidden": "true"
1232
1254
  }
1233
1255
  )
@@ -1599,7 +1621,11 @@ function FileField({
1599
1621
  type: "button",
1600
1622
  disabled: busy,
1601
1623
  onClick: () => setShowUrl(true),
1602
- className: "flex w-fit items-center gap-1 font-mono text-[11px] text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 max-sm:min-h-11",
1624
+ className: cn(
1625
+ "flex w-fit items-center gap-1 rounded-sm font-mono text-[11px] text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 max-sm:min-h-11",
1626
+ focusOutlineClass,
1627
+ "focus-visible:outline-offset-2"
1628
+ ),
1603
1629
  children: [
1604
1630
  /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3" }),
1605
1631
  s.pasteUrlInstead
@@ -1709,7 +1735,10 @@ function FileChip({
1709
1735
  {
1710
1736
  type: "button",
1711
1737
  onClick: onTogglePreview,
1712
- className: "inline-flex h-7 shrink-0 items-center gap-1 rounded-md border border-border px-2 text-[11px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground max-sm:h-11 max-sm:px-3",
1738
+ className: cn(
1739
+ "inline-flex h-7 shrink-0 items-center gap-1 rounded-md border border-border px-2 text-[11px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground max-sm:h-11 max-sm:px-3",
1740
+ focusOutlineClass
1741
+ ),
1713
1742
  children: [
1714
1743
  previewOpen ? /* @__PURE__ */ jsx(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" }),
1715
1744
  s.preview
@@ -1729,7 +1758,10 @@ function ClearButton({ disabled, onClick }) {
1729
1758
  onClick,
1730
1759
  disabled,
1731
1760
  "aria-label": s.removeFileAria,
1732
- className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50 max-sm:size-11",
1761
+ className: cn(
1762
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50 max-sm:size-11",
1763
+ focusOutlineClass
1764
+ ),
1733
1765
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
1734
1766
  }
1735
1767
  );
@@ -1874,14 +1906,14 @@ function EnumField({ field, value, onChange, id, error, disabled }) {
1874
1906
  value: option,
1875
1907
  variant: "outline",
1876
1908
  className: cn(
1877
- "h-9 min-w-0 gap-1.5 border-border bg-input px-3 text-[13px] text-muted-foreground hover:bg-muted hover:text-foreground data-[state=on]:border-primary/40 data-[state=on]:font-medium data-[state=on]:text-foreground",
1878
- brandFillSelectedClass
1909
+ "h-9 min-w-0 gap-1.5 border-border bg-input px-3 text-[13px] text-muted-foreground hover:bg-muted hover:text-foreground data-[state=on]:font-medium",
1910
+ selectedStateBorderClass
1879
1911
  ),
1880
1912
  children: [
1881
1913
  value === option && /* @__PURE__ */ jsx(
1882
1914
  Check,
1883
1915
  {
1884
- className: cn("size-3.5", brandFillInkClass),
1916
+ className: cn("size-3.5", linkTextClass),
1885
1917
  strokeWidth: 2.5,
1886
1918
  "aria-hidden": "true"
1887
1919
  }
@@ -1976,7 +2008,8 @@ function StepButton({
1976
2008
  "aria-label": label,
1977
2009
  className: cn(
1978
2010
  "flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-border bg-input text-muted-foreground transition-colors",
1979
- "hover:border-border hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
2011
+ "hover:border-border hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50",
2012
+ focusOutlineClass
1980
2013
  ),
1981
2014
  children
1982
2015
  }
@@ -2053,7 +2086,11 @@ function OptionalToggle({ count, expanded, onToggle, noun = "field" }) {
2053
2086
  type: "button",
2054
2087
  onClick: onToggle,
2055
2088
  "aria-expanded": expanded,
2056
- className: "flex w-fit items-center gap-1.5 text-[11px] text-muted-foreground transition-colors hover:text-foreground max-sm:min-h-11",
2089
+ className: cn(
2090
+ "flex w-fit items-center gap-1.5 rounded-sm text-[11px] text-muted-foreground transition-colors hover:text-foreground max-sm:min-h-11",
2091
+ focusOutlineClass,
2092
+ "focus-visible:outline-offset-2"
2093
+ ),
2057
2094
  children: [
2058
2095
  expanded ? /* @__PURE__ */ jsx(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
2059
2096
  expanded ? noun === "field" ? s.hideOptionalFields : s.hideOptionalInputs : noun === "field" ? s.optionalFieldsCount(count) : s.optionalInputsCount(count)
@@ -2277,7 +2314,10 @@ function ListField({ field, value, onChange, id, error, env }) {
2277
2314
  onClick: () => removeItem(index),
2278
2315
  disabled: env?.disabled || busy,
2279
2316
  "aria-label": s.removeItemAria(index + 1),
2280
- className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-destructive disabled:opacity-50 max-sm:mt-0 max-sm:size-11",
2317
+ className: cn(
2318
+ "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-destructive disabled:opacity-50 max-sm:mt-0 max-sm:size-11",
2319
+ focusOutlineClass
2320
+ ),
2281
2321
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
2282
2322
  }
2283
2323
  )
@@ -2293,7 +2333,11 @@ function ListField({ field, value, onChange, id, error, env }) {
2293
2333
  disabled: env?.disabled || isFull,
2294
2334
  className: cn(
2295
2335
  "inline-flex h-9 w-full items-center justify-center gap-1.5 rounded-md border border-dashed border-border text-[13px] text-muted-foreground transition-colors max-sm:h-11",
2296
- "hover:border-primary/40 hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
2336
+ // The edge under the pointer is the accent's, as a selected pill's
2337
+ // is; the fill under it stays neutral.
2338
+ "hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50",
2339
+ selectedHoverBorderClass,
2340
+ focusOutlineClass
2297
2341
  ),
2298
2342
  children: [
2299
2343
  /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
@@ -2670,7 +2714,10 @@ var DropdownMenuItem = React5.forwardRef(({ className, ...props }, ref) => /* @_
2670
2714
  }
2671
2715
  ));
2672
2716
  DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
2673
- var buttonClass = "inline-flex min-h-11 items-center justify-center gap-2 rounded-md px-4 text-[14px] transition-colors disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9";
2717
+ var buttonClass = cn(
2718
+ "inline-flex min-h-11 items-center justify-center gap-2 rounded-md px-4 text-[14px] transition-colors disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9",
2719
+ focusOutlineClass
2720
+ );
2674
2721
  var secondaryClass = cn(buttonClass, "border border-border text-foreground hover:bg-muted");
2675
2722
  var primaryClass = cn(
2676
2723
  buttonClass,
@@ -2798,7 +2845,10 @@ function FillWithExample({
2798
2845
  {
2799
2846
  ref: closeButton,
2800
2847
  "aria-label": s.close,
2801
- className: "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2848
+ className: cn(
2849
+ "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2850
+ focusOutlineClass
2851
+ ),
2802
2852
  children: /* @__PURE__ */ jsx(X, { className: "size-5", "aria-hidden": "true" })
2803
2853
  }
2804
2854
  )
@@ -2812,7 +2862,10 @@ function FillWithExample({
2812
2862
  ref: register(rows.current, example.id),
2813
2863
  type: "button",
2814
2864
  onClick: () => choose(example),
2815
- className: "flex min-h-16 min-w-0 flex-1 items-center px-4 py-2.5 text-left transition-colors hover:bg-muted/60 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring",
2865
+ className: cn(
2866
+ "flex min-h-16 min-w-0 flex-1 items-center px-4 py-2.5 text-left transition-colors hover:bg-muted/60",
2867
+ focusOutlineInsetClass
2868
+ ),
2816
2869
  children: /* @__PURE__ */ jsx("span", { className: "truncate text-[16px] font-medium text-foreground", children: example.name })
2817
2870
  }
2818
2871
  ),
@@ -2824,7 +2877,10 @@ function FillWithExample({
2824
2877
  {
2825
2878
  ref: register(menus.current, example.id),
2826
2879
  "aria-label": s.exampleActions(example.name),
2827
- className: "flex size-11 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2880
+ className: cn(
2881
+ "flex size-11 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2882
+ focusOutlineInsetClass
2883
+ ),
2828
2884
  children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-5", "aria-hidden": "true" })
2829
2885
  }
2830
2886
  ),
@@ -2968,7 +3024,10 @@ function RenameExampleDialog({
2968
3024
  onKeyDown,
2969
3025
  disabled: state === "busy",
2970
3026
  autoComplete: "off",
2971
- className: "h-11 w-full rounded-md border border-border bg-input px-3 text-[16px] text-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring"
3027
+ className: cn(
3028
+ "h-11 w-full rounded-md border border-border bg-input px-3 text-[16px] text-foreground",
3029
+ focusOutlineClass
3030
+ )
2972
3031
  }
2973
3032
  )
2974
3033
  ] }),
@@ -3929,6 +3988,83 @@ function ResultAt({ segment, children }) {
3929
3988
  );
3930
3989
  return /* @__PURE__ */ jsx(ResultLocationContext, { value: location, children });
3931
3990
  }
3991
+ function FocusFrame({ ref, className, ...props }) {
3992
+ const [frame, setFrame] = useState(null);
3993
+ const focused = useFrameFocus(frame);
3994
+ const attach = useCallback(
3995
+ (node) => {
3996
+ setFrame(node);
3997
+ if (typeof ref === "function") ref(node);
3998
+ else if (ref) ref.current = node;
3999
+ },
4000
+ [ref]
4001
+ );
4002
+ return /* @__PURE__ */ jsx(
4003
+ "iframe",
4004
+ {
4005
+ ...props,
4006
+ ref: attach,
4007
+ ...focused ? { "data-focus-visible": "" } : {},
4008
+ className: cn(className, frameFocusOutlineClass)
4009
+ }
4010
+ );
4011
+ }
4012
+ var frames = /* @__PURE__ */ new Set();
4013
+ var settling;
4014
+ var refresh = () => {
4015
+ for (const check of frames) check();
4016
+ };
4017
+ var onBlur = () => {
4018
+ refresh();
4019
+ clearTimeout(settling);
4020
+ settling = setTimeout(refresh, 0);
4021
+ };
4022
+ function listen(win) {
4023
+ win.addEventListener("blur", onBlur);
4024
+ win.addEventListener("focus", refresh);
4025
+ }
4026
+ function unlisten(win) {
4027
+ win.removeEventListener("blur", onBlur);
4028
+ win.removeEventListener("focus", refresh);
4029
+ }
4030
+ function useFrameFocus(frame) {
4031
+ const [focused, setFocused] = useState(false);
4032
+ useEffect(() => {
4033
+ if (!frame) return;
4034
+ const check = () => setFocused(document.hasFocus() && document.activeElement === frame);
4035
+ if (frames.size === 0) {
4036
+ listen(window);
4037
+ document.addEventListener("focusin", refresh);
4038
+ }
4039
+ frames.add(check);
4040
+ let own = null;
4041
+ const attachOwn = () => {
4042
+ try {
4043
+ own = frame.contentWindow;
4044
+ if (own) listen(own);
4045
+ } catch {
4046
+ own = null;
4047
+ }
4048
+ };
4049
+ attachOwn();
4050
+ frame.addEventListener("load", attachOwn);
4051
+ return () => {
4052
+ frame.removeEventListener("load", attachOwn);
4053
+ try {
4054
+ if (own) unlisten(own);
4055
+ } catch {
4056
+ }
4057
+ frames.delete(check);
4058
+ if (frames.size === 0) {
4059
+ unlisten(window);
4060
+ document.removeEventListener("focusin", refresh);
4061
+ clearTimeout(settling);
4062
+ settling = void 0;
4063
+ }
4064
+ };
4065
+ }, [frame]);
4066
+ return focused;
4067
+ }
3932
4068
  var TooltipProvider = TooltipPrimitive.Provider;
3933
4069
  var TooltipRoot = TooltipPrimitive.Root;
3934
4070
  var TooltipTrigger = TooltipPrimitive.Trigger;
@@ -4070,7 +4206,10 @@ function FileNameDialog({ stem: stem2, extension, onConfirm, onCancel }) {
4070
4206
  {
4071
4207
  type: "button",
4072
4208
  onClick: onCancel,
4073
- className: "rounded-md border border-border px-3 py-1 text-[12px] text-muted-foreground hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1",
4209
+ className: cn(
4210
+ "rounded-md border border-border px-3 py-1 text-[12px] text-muted-foreground hover:text-foreground",
4211
+ focusOutlineClass
4212
+ ),
4074
4213
  children: s.fileNameCancel
4075
4214
  }
4076
4215
  ),
@@ -4079,7 +4218,10 @@ function FileNameDialog({ stem: stem2, extension, onConfirm, onCancel }) {
4079
4218
  {
4080
4219
  type: "button",
4081
4220
  onClick: () => onConfirm(value),
4082
- className: "rounded-md bg-primary px-3 py-1 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1",
4221
+ className: cn(
4222
+ "rounded-md bg-primary px-3 py-1 text-[12px] font-medium text-primary-foreground hover:bg-primary/90",
4223
+ focusOutlineClass
4224
+ ),
4083
4225
  children: s.fileNameConfirm
4084
4226
  }
4085
4227
  )
@@ -4714,7 +4856,8 @@ function PdfDownloadButton({
4714
4856
  title: failed ? s.downloadPdfFailed : name,
4715
4857
  ...failed ? { "aria-describedby": statusId } : {},
4716
4858
  className: cn(
4717
- "inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 text-[12px] font-medium focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 disabled:opacity-70",
4859
+ "inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 text-[12px] font-medium disabled:opacity-70",
4860
+ focusOutlineClass,
4718
4861
  primary ? "bg-primary text-primary-foreground hover:bg-primary/90" : "border border-border text-muted-foreground hover:text-foreground",
4719
4862
  failed && (primary ? "bg-destructive text-white hover:bg-destructive/90" : "text-destructive"),
4720
4863
  className
@@ -4832,28 +4975,31 @@ function HtmlPreview({
4832
4975
  ]
4833
4976
  }
4834
4977
  )
4835
- ) : doc === null ? null : /* @__PURE__ */ jsx(
4836
- "iframe",
4837
- {
4838
- ref: frameRef,
4839
- title: content.cssClass ? `HTML result (${content.cssClass})` : "HTML result",
4840
- srcDoc: doc,
4841
- onLoad,
4842
- sandbox: "allow-same-origin",
4843
- style: {
4844
- display: "block",
4845
- width: "100%",
4846
- border: 0,
4847
- height: height === 0 ? void 0 : limit === void 0 ? height : Math.min(height, limit),
4848
- ...limit === void 0 ? {} : { maxHeight: limit },
4849
- // Its height is the page's, as a flex basis: in a bounded flex
4850
- // column it shrinks to what is left (never below the floor) and the
4851
- // page scrolls inside the frame; anywhere else it is the page's.
4852
- // `minHeight` is explicit because a replaced element's automatic
4853
- // minimum is its own height, which would forbid the shrink.
4854
- ...filling && height > 0 ? { flex: "0 1 auto", minHeight: Math.min(height, FILL_MIN_HEIGHT) } : {}
4978
+ ) : doc === null ? null : (
4979
+ // A tab stop, whose keyboard focus `FocusFrame` draws.
4980
+ /* @__PURE__ */ jsx(
4981
+ FocusFrame,
4982
+ {
4983
+ ref: frameRef,
4984
+ title: content.cssClass ? `HTML result (${content.cssClass})` : "HTML result",
4985
+ srcDoc: doc,
4986
+ onLoad,
4987
+ sandbox: "allow-same-origin",
4988
+ style: {
4989
+ display: "block",
4990
+ width: "100%",
4991
+ border: 0,
4992
+ height: height === 0 ? void 0 : limit === void 0 ? height : Math.min(height, limit),
4993
+ ...limit === void 0 ? {} : { maxHeight: limit },
4994
+ // Its height is the page's, as a flex basis: in a bounded flex
4995
+ // column it shrinks to what is left (never below the floor) and the
4996
+ // page scrolls inside the frame; anywhere else it is the page's.
4997
+ // `minHeight` is explicit because a replaced element's automatic
4998
+ // minimum is its own height, which would forbid the shrink.
4999
+ ...filling && height > 0 ? { flex: "0 1 auto", minHeight: Math.min(height, FILL_MIN_HEIGHT) } : {}
5000
+ }
4855
5001
  }
4856
- }
5002
+ )
4857
5003
  )
4858
5004
  }
4859
5005
  );
@@ -5063,7 +5209,7 @@ function InlineToken({ token }) {
5063
5209
  href,
5064
5210
  target: "_blank",
5065
5211
  rel: "noreferrer noopener",
5066
- className: "underline underline-offset-2",
5212
+ className: cn("rounded-sm underline underline-offset-2", focusOutlineClass),
5067
5213
  children: /* @__PURE__ */ jsx(Inline, { tokens: link.tokens })
5068
5214
  }
5069
5215
  ) })
@@ -5098,7 +5244,7 @@ function ProseImage({ token }) {
5098
5244
  href: src,
5099
5245
  target: "_blank",
5100
5246
  rel: "noreferrer noopener",
5101
- className: "underline underline-offset-2",
5247
+ className: cn("rounded-sm underline underline-offset-2", focusOutlineClass),
5102
5248
  children: token.text || src
5103
5249
  }
5104
5250
  );
@@ -5287,7 +5433,8 @@ function CopyButton({
5287
5433
  ...title ? { title } : {},
5288
5434
  "aria-label": label,
5289
5435
  className: cn(
5290
- "shrink-0 rounded p-0.5 text-muted-foreground hover:bg-card hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1",
5436
+ "shrink-0 rounded p-0.5 text-muted-foreground hover:bg-card hover:text-foreground",
5437
+ focusOutlineClass,
5291
5438
  FILE_BUTTON_ON_A_PHONE
5292
5439
  ),
5293
5440
  children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": true, className: "size-3.5" })
@@ -5327,7 +5474,10 @@ function FileRef({
5327
5474
  target: "_blank",
5328
5475
  rel: "noreferrer",
5329
5476
  title,
5330
- className: "min-w-0 truncate font-mono text-[12px] text-foreground underline underline-offset-2 max-sm:min-w-11 max-sm:leading-11",
5477
+ className: cn(
5478
+ "min-w-0 truncate rounded-sm font-mono text-[12px] text-foreground underline underline-offset-2 max-sm:min-w-11 max-sm:leading-11",
5479
+ focusOutlineClass
5480
+ ),
5331
5481
  children: label
5332
5482
  }
5333
5483
  ) : /* @__PURE__ */ jsx(
@@ -5408,7 +5558,8 @@ ${planned.url ?? planned.text}`;
5408
5558
  title: failed ? s.downloadFileFailed : label,
5409
5559
  ...failed ? { "aria-describedby": statusId } : {},
5410
5560
  className: cn(
5411
- "shrink-0 rounded p-0.5 hover:bg-card focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 disabled:opacity-60",
5561
+ "shrink-0 rounded p-0.5 hover:bg-card disabled:opacity-60",
5562
+ focusOutlineClass,
5412
5563
  FILE_BUTTON_ON_A_PHONE,
5413
5564
  failed ? "text-destructive" : "text-muted-foreground hover:text-foreground"
5414
5565
  ),
@@ -5444,7 +5595,7 @@ function previewableUrl(content, resolve) {
5444
5595
  }
5445
5596
  function DocumentPreview({ url, name }) {
5446
5597
  return /* @__PURE__ */ jsx(
5447
- "iframe",
5598
+ FocusFrame,
5448
5599
  {
5449
5600
  src: url,
5450
5601
  title: name,
@@ -5486,7 +5637,10 @@ function DocumentValue({ value }) {
5486
5637
  type: "button",
5487
5638
  onClick: () => setOpen((current) => !current),
5488
5639
  "aria-expanded": open,
5489
- className: "flex shrink-0 items-center gap-1.5 rounded-md border border-border px-2 py-1 text-[12px] text-muted-foreground hover:bg-card hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 max-sm:min-h-11 max-sm:px-3",
5640
+ className: cn(
5641
+ "flex shrink-0 items-center gap-1.5 rounded-md border border-border px-2 py-1 text-[12px] text-muted-foreground hover:bg-card hover:text-foreground max-sm:min-h-11 max-sm:px-3",
5642
+ focusOutlineClass
5643
+ ),
5490
5644
  children: [
5491
5645
  open ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": true, className: "size-3.5" }),
5492
5646
  s.preview
@@ -5522,7 +5676,10 @@ function ImageValue({
5522
5676
  target: "_blank",
5523
5677
  rel: "noreferrer",
5524
5678
  title: content.url,
5525
- className: inGallery || compact ? "inline-block" : "block w-full",
5679
+ className: cn(
5680
+ inGallery || compact ? "inline-block" : "block w-full",
5681
+ focusOutlineInsetClass
5682
+ ),
5526
5683
  children: /* @__PURE__ */ jsx(
5527
5684
  LoadingImage,
5528
5685
  {
@@ -5707,7 +5864,10 @@ function isInlineColumn(field) {
5707
5864
  var CELL_LENGTH_LIMIT = 80;
5708
5865
  var EXPAND_COLUMN = "var(--expand-column,2rem)";
5709
5866
  var EXPAND_COLUMN_WIDTH = "[--expand-column:2rem] max-sm:[--expand-column:3.25rem]";
5710
- var TOGGLE = "mt-0.5 flex size-6 items-center justify-center rounded text-muted-foreground hover:bg-card hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 max-sm:mt-0 max-sm:size-11";
5867
+ var TOGGLE = cn(
5868
+ "mt-0.5 flex size-6 items-center justify-center rounded text-muted-foreground hover:bg-card hover:text-foreground max-sm:mt-0 max-sm:size-11",
5869
+ focusOutlineClass
5870
+ );
5711
5871
  var STACK_NEVER_UP_TO = 3;
5712
5872
  var STACK_ALWAYS_BEYOND = 6;
5713
5873
  function stackingFor(columns) {
@@ -5851,6 +6011,7 @@ function ObjectTable({
5851
6011
  ...fits ? {} : { tabIndex: 0 },
5852
6012
  className: cn(
5853
6013
  "overflow-x-auto rounded-lg border border-border",
6014
+ focusOutlineInsetClass,
5854
6015
  EXPAND_COLUMN_WIDTH,
5855
6016
  fits && "@container"
5856
6017
  ),
@@ -6278,7 +6439,10 @@ function JsonView({ value }) {
6278
6439
  void navigator.clipboard.writeText(text).then(() => setCopied(true));
6279
6440
  },
6280
6441
  "aria-label": s.copyJson,
6281
- className: "absolute right-2 top-2 rounded border border-border bg-card p-1 text-muted-foreground hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1",
6442
+ className: cn(
6443
+ "absolute right-2 top-2 rounded border border-border bg-card p-1 text-muted-foreground hover:text-foreground",
6444
+ focusOutlineClass
6445
+ ),
6282
6446
  children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": true, className: "size-3.5" })
6283
6447
  }
6284
6448
  ),
@@ -6408,7 +6572,10 @@ function StuffPanel({
6408
6572
  onClick: () => void handleDownload(),
6409
6573
  disabled: savingShown,
6410
6574
  "aria-label": page ? s.downloadHtml : s.download,
6411
- className: "inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-[12px] text-muted-foreground hover:text-foreground focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1 disabled:opacity-60",
6575
+ className: cn(
6576
+ "inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-[12px] text-muted-foreground hover:text-foreground disabled:opacity-60",
6577
+ focusOutlineClass
6578
+ ),
6412
6579
  children: [
6413
6580
  savingShown ? /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Download, { className: "h-3.5 w-3.5" }),
6414
6581
  savingShown ? s.downloading : page ? s.downloadHtml : s.download
@@ -6429,7 +6596,8 @@ function StuffPanel({
6429
6596
  onClick: () => setView(id),
6430
6597
  "aria-pressed": view === id,
6431
6598
  className: cn(
6432
- "rounded px-2 py-0.5 text-[12px] focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-1",
6599
+ "rounded px-2 py-0.5 text-[12px]",
6600
+ focusOutlineClass,
6433
6601
  view === id ? "bg-card font-medium text-foreground" : "text-muted-foreground hover:text-foreground"
6434
6602
  ),
6435
6603
  children: labels[id]
@@ -6467,6 +6635,6 @@ function pdfFileName(field, value, baseName) {
6467
6635
  return name === void 0 ? "" : name.replace(/\.[^.]+$/, "");
6468
6636
  }
6469
6637
 
6470
- export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, FilePicker, FilePickerEntry, FillWithExample, HtmlPreview, ImageField, JsonView, ListField, Markdown, MethodForm, NumberField, ObjectField, OptionalToggle, PdfDownloadButton, ProseField, ResultEnvProvider, ResultField, ResultRoot, SUPPORTED_LOCALES, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StuffViewer, Switch, TextField, ToggleGroup, ToggleGroupItem, UnknownField, brandFillClass, brandFillInkClass, brandFillStrongClass, brandInkClass, cn, fieldControlClass, fieldStringsFor, humanizeFieldName, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
6471
- //# sourceMappingURL=chunk-5IZWP2X4.js.map
6472
- //# sourceMappingURL=chunk-5IZWP2X4.js.map
6638
+ export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, FilePicker, FilePickerEntry, FillWithExample, HtmlPreview, ImageField, JsonView, ListField, Markdown, MethodForm, NumberField, ObjectField, OptionalToggle, PdfDownloadButton, ProseField, ResultEnvProvider, ResultField, ResultRoot, SUPPORTED_LOCALES, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StuffViewer, Switch, TextField, ToggleGroup, ToggleGroupItem, UnknownField, checkedAccentClass, cn, fieldControlClass, fieldStringsFor, focusOutlineClass, humanizeFieldName, linkTextClass, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, selectedBorderClass, selectedFillClass, selectedFillStrongClass, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
6639
+ //# sourceMappingURL=chunk-NOSHTDID.js.map
6640
+ //# sourceMappingURL=chunk-NOSHTDID.js.map