@pipelex/mthds-form 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -112,6 +112,7 @@ var Switch = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
112
112
  {
113
113
  className: cn(
114
114
  "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
115
+ "max-sm:relative max-sm:after:absolute max-sm:after:-inset-x-0.5 max-sm:after:-inset-y-3 max-sm:after:content-['']",
115
116
  className
116
117
  ),
117
118
  ...props,
@@ -736,7 +737,7 @@ function FileField({
736
737
  type: "button",
737
738
  disabled: busy,
738
739
  onClick: () => setShowUrl(true),
739
- className: "flex w-fit items-center gap-1 font-mono text-[11px] text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50",
740
+ 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",
740
741
  children: [
741
742
  /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3" }),
742
743
  s.pasteUrlInstead
@@ -803,25 +804,27 @@ function FileChip({
803
804
  () => fileChipSubtitle(url, filename, formats, presentation, s),
804
805
  [url, filename, formats, presentation, s]
805
806
  );
806
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-md border border-border bg-input px-3 py-2.5", children: [
807
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 rounded-md border border-border bg-input px-3 py-2.5", children: [
807
808
  /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted", children: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4 text-muted-foreground" }) }),
808
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
809
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 basis-32 [contain:inline-size]", children: [
809
810
  /* @__PURE__ */ jsx("p", { className: "truncate text-[13px] font-medium text-foreground", children: value?.filename ?? s.uploadedFile }),
810
811
  subtitle && /* @__PURE__ */ jsx("p", { className: "truncate font-mono text-[10.5px] text-muted-foreground", children: subtitle })
811
812
  ] }),
812
- canPreview && /* @__PURE__ */ jsxs(
813
- "button",
814
- {
815
- type: "button",
816
- onClick: onTogglePreview,
817
- 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",
818
- children: [
819
- previewOpen ? /* @__PURE__ */ jsx(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" }),
820
- s.preview
821
- ]
822
- }
823
- ),
824
- /* @__PURE__ */ jsx(ClearButton, { disabled, onClick: onClear })
813
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-3", children: [
814
+ canPreview && /* @__PURE__ */ jsxs(
815
+ "button",
816
+ {
817
+ type: "button",
818
+ onClick: onTogglePreview,
819
+ 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",
820
+ children: [
821
+ previewOpen ? /* @__PURE__ */ jsx(EyeOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5" }),
822
+ s.preview
823
+ ]
824
+ }
825
+ ),
826
+ /* @__PURE__ */ jsx(ClearButton, { disabled, onClick: onClear })
827
+ ] })
825
828
  ] });
826
829
  }
827
830
  function ClearButton({ disabled, onClick }) {
@@ -833,7 +836,7 @@ function ClearButton({ disabled, onClick }) {
833
836
  onClick,
834
837
  disabled,
835
838
  "aria-label": s.removeFileAria,
836
- 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",
839
+ 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",
837
840
  children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
838
841
  }
839
842
  );
@@ -1209,7 +1212,7 @@ function OptionalToggle({ count, expanded, onToggle, noun = "field" }) {
1209
1212
  type: "button",
1210
1213
  onClick: onToggle,
1211
1214
  "aria-expanded": expanded,
1212
- className: "flex w-fit items-center gap-1.5 text-[11px] text-muted-foreground transition-colors hover:text-foreground",
1215
+ className: "flex w-fit items-center gap-1.5 text-[11px] text-muted-foreground transition-colors hover:text-foreground max-sm:min-h-11",
1213
1216
  children: [
1214
1217
  expanded ? /* @__PURE__ */ jsx(Minus, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
1215
1218
  expanded ? noun === "field" ? s.hideOptionalFields : s.hideOptionalInputs : noun === "field" ? s.optionalFieldsCount(count) : s.optionalInputsCount(count)
@@ -1381,7 +1384,7 @@ function ListField({ field, value, onChange, id, error, env }) {
1381
1384
  onClick: () => removeItem(index),
1382
1385
  disabled: env?.disabled || busy,
1383
1386
  "aria-label": s.removeItemAria(index + 1),
1384
- 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",
1387
+ 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",
1385
1388
  children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
1386
1389
  }
1387
1390
  )
@@ -1396,7 +1399,7 @@ function ListField({ field, value, onChange, id, error, env }) {
1396
1399
  onClick: addItem,
1397
1400
  disabled: env?.disabled || isFull,
1398
1401
  className: cn(
1399
- "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",
1402
+ "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",
1400
1403
  "hover:border-primary/40 hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
1401
1404
  ),
1402
1405
  children: [
@@ -2155,6 +2158,7 @@ function ResultEnvProvider({
2155
2158
  resolveShareUrl,
2156
2159
  proseImages,
2157
2160
  tableColumns,
2161
+ tableLayout,
2158
2162
  saveFiles,
2159
2163
  downloads,
2160
2164
  children
@@ -2166,15 +2170,26 @@ function ResultEnvProvider({
2166
2170
  resolveShareUrl,
2167
2171
  proseImages,
2168
2172
  tableColumns,
2173
+ tableLayout,
2169
2174
  saveFiles,
2170
2175
  downloads
2171
2176
  }),
2172
- [resolveUrl, resolveUrls, resolveShareUrl, proseImages, tableColumns, saveFiles, downloads]
2177
+ [
2178
+ resolveUrl,
2179
+ resolveUrls,
2180
+ resolveShareUrl,
2181
+ proseImages,
2182
+ tableColumns,
2183
+ tableLayout,
2184
+ saveFiles,
2185
+ downloads
2186
+ ]
2173
2187
  );
2174
2188
  return /* @__PURE__ */ jsx(ResultEnvContext, { value: env, children });
2175
2189
  }
2176
- function DownloadDisplayOverride({
2190
+ function PanelEnvOverride({
2177
2191
  downloads,
2192
+ tableLayout,
2178
2193
  children
2179
2194
  }) {
2180
2195
  const env = use(ResultEnvContext);
@@ -2182,18 +2197,22 @@ function DownloadDisplayOverride({
2182
2197
  const files = downloads?.files;
2183
2198
  const pdf = downloads?.pdf;
2184
2199
  const askFileName = downloads?.askFileName;
2185
- const merged = useMemo(
2186
- () => result === void 0 && files === void 0 && pdf === void 0 && askFileName === void 0 ? env : {
2200
+ const merged = useMemo(() => {
2201
+ const ownDownloads = result !== void 0 || files !== void 0 || pdf !== void 0 || askFileName !== void 0;
2202
+ if (!ownDownloads && tableLayout === void 0) return env;
2203
+ return {
2187
2204
  ...env,
2188
- downloads: {
2189
- result: result ?? env.downloads?.result,
2190
- files: files ?? env.downloads?.files,
2191
- pdf: pdf ?? env.downloads?.pdf,
2192
- askFileName: askFileName ?? env.downloads?.askFileName
2193
- }
2194
- },
2195
- [env, result, files, pdf, askFileName]
2196
- );
2205
+ ...tableLayout === void 0 ? {} : { tableLayout },
2206
+ ...ownDownloads ? {
2207
+ downloads: {
2208
+ result: result ?? env.downloads?.result,
2209
+ files: files ?? env.downloads?.files,
2210
+ pdf: pdf ?? env.downloads?.pdf,
2211
+ askFileName: askFileName ?? env.downloads?.askFileName
2212
+ }
2213
+ } : {}
2214
+ };
2215
+ }, [env, result, files, pdf, askFileName, tableLayout]);
2197
2216
  return /* @__PURE__ */ jsx(ResultEnvContext, { value: merged, children });
2198
2217
  }
2199
2218
  function useResolvedUrl(url) {
@@ -2255,6 +2274,9 @@ function useTableColumns() {
2255
2274
  if (budget === void 0 || Number.isNaN(budget)) return DEFAULT_TABLE_COLUMNS;
2256
2275
  return Math.max(1, Math.floor(budget));
2257
2276
  }
2277
+ function useTableLayout() {
2278
+ return use(ResultEnvContext).tableLayout ?? "scroll";
2279
+ }
2258
2280
  var ResultLocationContext = createContext(void 0);
2259
2281
  function useResultLocation() {
2260
2282
  return use(ResultLocationContext);
@@ -3594,6 +3616,7 @@ function pathLabel(url) {
3594
3616
  const segment = path.split("/").filter(Boolean).pop();
3595
3617
  return segment && segment.length > 0 ? segment : url;
3596
3618
  }
3619
+ var FILE_BUTTON_ON_A_PHONE = "max-sm:grid max-sm:size-11 max-sm:place-items-center";
3597
3620
  function CopyButton({
3598
3621
  value,
3599
3622
  provide,
@@ -3630,7 +3653,10 @@ function CopyButton({
3630
3653
  },
3631
3654
  ...title ? { title } : {},
3632
3655
  "aria-label": label,
3633
- className: "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",
3656
+ className: cn(
3657
+ "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",
3658
+ FILE_BUTTON_ON_A_PHONE
3659
+ ),
3634
3660
  children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": true, className: "size-3.5" })
3635
3661
  }
3636
3662
  );
@@ -3668,7 +3694,7 @@ function FileRef({
3668
3694
  target: "_blank",
3669
3695
  rel: "noreferrer",
3670
3696
  title,
3671
- className: "min-w-0 truncate font-mono text-[12px] text-foreground underline underline-offset-2",
3697
+ className: "min-w-0 truncate font-mono text-[12px] text-foreground underline underline-offset-2 max-sm:min-w-11 max-sm:leading-11",
3672
3698
  children: label
3673
3699
  }
3674
3700
  ) : /* @__PURE__ */ jsx(
@@ -3750,6 +3776,7 @@ ${planned.url ?? planned.text}`;
3750
3776
  ...failed ? { "aria-describedby": statusId } : {},
3751
3777
  className: cn(
3752
3778
  "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",
3779
+ FILE_BUTTON_ON_A_PHONE,
3753
3780
  failed ? "text-destructive" : "text-muted-foreground hover:text-foreground"
3754
3781
  ),
3755
3782
  children: state === "saving" ? /* @__PURE__ */ jsx(Loader2, { "aria-hidden": true, className: "size-3.5 animate-spin" }) : state === "saved" ? /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: "size-3.5" }) : failed ? /* @__PURE__ */ jsx(TriangleAlert, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Download, { "aria-hidden": true, className: "size-3.5" })
@@ -3826,7 +3853,7 @@ function DocumentValue({ value }) {
3826
3853
  type: "button",
3827
3854
  onClick: () => setOpen((current) => !current),
3828
3855
  "aria-expanded": open,
3829
- 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",
3856
+ 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",
3830
3857
  children: [
3831
3858
  open ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": true, className: "size-3.5" }),
3832
3859
  s.preview
@@ -4045,7 +4072,66 @@ function isInlineColumn(field) {
4045
4072
  return TABULAR_KINDS.has(field.kind);
4046
4073
  }
4047
4074
  var CELL_LENGTH_LIMIT = 80;
4048
- var EXPAND_COLUMN = "2rem";
4075
+ var EXPAND_COLUMN = "var(--expand-column,2rem)";
4076
+ var EXPAND_COLUMN_WIDTH = "[--expand-column:2rem] max-sm:[--expand-column:3.25rem]";
4077
+ 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";
4078
+ var STACK_NEVER_UP_TO = 3;
4079
+ var STACK_ALWAYS_BEYOND = 6;
4080
+ function stackingFor(columns) {
4081
+ if (columns <= STACK_NEVER_UP_TO) return "never";
4082
+ return columns > STACK_ALWAYS_BEYOND ? "always" : "narrow";
4083
+ }
4084
+ var STACKED = {
4085
+ narrow: {
4086
+ table: "@max-[640px]:block",
4087
+ head: "@max-[640px]:hidden",
4088
+ body: "@max-[640px]:block",
4089
+ row: "@max-[640px]:relative @max-[640px]:block @max-[640px]:px-3 @max-[640px]:py-2",
4090
+ rowWithToggle: "@max-[640px]:pl-8 max-sm:@max-[640px]:pl-12",
4091
+ toggle: "@max-[640px]:absolute @max-[640px]:top-2 @max-[640px]:left-1 @max-[640px]:p-0 max-sm:@max-[640px]:top-0 max-sm:@max-[640px]:left-0",
4092
+ cell: "@max-[640px]:grid @max-[640px]:grid-cols-[minmax(0,min(40%,10rem))_minmax(0,1fr)] @max-[640px]:items-baseline @max-[640px]:gap-x-3 @max-[640px]:px-0 @max-[640px]:py-0.5 @max-[640px]:after:hidden",
4093
+ label: "@max-[640px]:block",
4094
+ detail: "@max-[640px]:block",
4095
+ detailInner: "@max-[640px]:px-0 @max-[640px]:py-1"
4096
+ },
4097
+ always: {
4098
+ table: "block",
4099
+ head: "hidden",
4100
+ body: "block",
4101
+ row: "relative block px-3 py-2",
4102
+ rowWithToggle: "pl-8 max-sm:pl-12",
4103
+ toggle: "absolute top-2 left-1 p-0 max-sm:top-0 max-sm:left-0",
4104
+ cell: "grid grid-cols-[minmax(0,min(40%,10rem))_minmax(0,1fr)] items-baseline gap-x-3 px-0 py-0.5 after:hidden",
4105
+ label: "block",
4106
+ detail: "block",
4107
+ detailInner: "px-0 py-1"
4108
+ }
4109
+ };
4110
+ var FIT_CELL = "min-w-[min(8ch,14cqw)] wrap-anywhere [&>span]:whitespace-normal";
4111
+ var FIT_NAME = "min-w-[min(16ch,28cqw)] wrap-anywhere [&>span]:whitespace-normal";
4112
+ var WORD_FLOOR = "after:block after:h-0 after:max-w-[var(--fit-share,0px)] after:overflow-hidden after:invisible after:wrap-normal after:content-[attr(data-fit)]";
4113
+ var FIT_SHARE_BESIDE_NAME = {
4114
+ 2: "[--fit-share:calc(72cqw_-_3rem_-_var(--expand-column,2rem))]",
4115
+ 3: "[--fit-share:calc((72cqw_-_4.5rem_-_var(--expand-column,2rem))/2)]",
4116
+ 4: "[--fit-share:calc((72cqw_-_6rem_-_var(--expand-column,2rem))/3)]",
4117
+ 5: "[--fit-share:calc((72cqw_-_7.5rem_-_var(--expand-column,2rem))/4)]",
4118
+ 6: "[--fit-share:calc((72cqw_-_9rem_-_var(--expand-column,2rem))/5)]"
4119
+ };
4120
+ var FIT_SHARE_WITHOUT_NAME = {
4121
+ 1: "[--fit-share:calc(100cqw_-_1.5rem_-_var(--expand-column,2rem))]",
4122
+ 2: "[--fit-share:calc((100cqw_-_3rem_-_var(--expand-column,2rem))/2)]",
4123
+ 3: "[--fit-share:calc((100cqw_-_4.5rem_-_var(--expand-column,2rem))/3)]",
4124
+ 4: "[--fit-share:calc((100cqw_-_6rem_-_var(--expand-column,2rem))/4)]",
4125
+ 5: "[--fit-share:calc((100cqw_-_7.5rem_-_var(--expand-column,2rem))/5)]",
4126
+ 6: "[--fit-share:calc((100cqw_-_9rem_-_var(--expand-column,2rem))/6)]"
4127
+ };
4128
+ function cellWords(column, cell, presentation) {
4129
+ return typeof cell === "string" || typeof cell === "number" ? cellTitle(column, cell, presentation) : void 0;
4130
+ }
4131
+ function clampsInStack(column, name) {
4132
+ if (column === name || fitsACellWhole(column)) return false;
4133
+ return column.kind !== "list" && column.kind !== "document" && column.kind !== "image";
4134
+ }
4049
4135
  function fitsACellWhole(field) {
4050
4136
  switch (field.kind) {
4051
4137
  case "boolean":
@@ -4072,21 +4158,28 @@ function ObjectTable({
4072
4158
  const s = useFieldStrings();
4073
4159
  const presentation = useFieldPresentation();
4074
4160
  const budget = useTableColumns();
4161
+ const layout = useTableLayout();
4075
4162
  const scrollerRef = useRef(null);
4076
4163
  const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set());
4077
4164
  const [viewportWidth, setViewportWidth] = useState();
4078
4165
  const { shown, hidden, name } = chooseColumns(columns, budget);
4079
4166
  const canExpand = hidden > 0 || shown.some((column) => column !== name && !fitsACellWhole(column));
4167
+ const fits = layout === "stack";
4168
+ const stacking = fits ? stackingFor(shown.length) : "never";
4169
+ const stacked = stacking === "never" ? void 0 : STACKED[stacking];
4170
+ const nameShown = name !== void 0 && shown.includes(name);
4171
+ const fitShare = fits ? (nameShown ? FIT_SHARE_BESIDE_NAME : FIT_SHARE_WITHOUT_NAME)[shown.length] : void 0;
4172
+ const floorsWords = (column) => fitShare !== void 0 && column !== name;
4080
4173
  useEffect(() => {
4081
4174
  const scroller = scrollerRef.current;
4082
- if (!scroller) return;
4175
+ if (!scroller || fits) return;
4083
4176
  const measure = () => setViewportWidth(scroller.clientWidth);
4084
4177
  measure();
4085
4178
  if (typeof ResizeObserver === "undefined") return;
4086
4179
  const observer = new ResizeObserver(measure);
4087
4180
  observer.observe(scroller);
4088
4181
  return () => observer.disconnect();
4089
- }, []);
4182
+ }, [fits]);
4090
4183
  const toggle = (index) => setExpanded((current) => {
4091
4184
  const next = new Set(current);
4092
4185
  if (!next.delete(index)) next.add(index);
@@ -4110,76 +4203,138 @@ function ObjectTable({
4110
4203
  // of them with the same name - which is what a result rendered twice, or a
4111
4204
  // structure holding two lists, produces - is `landmark-unique`. A group is
4112
4205
  // named without claiming to be a section of the page.
4206
+ //
4207
+ // Under `tableLayout="stack"` the box is the SIZE CONTAINER its stacking
4208
+ // rules query, so the table answers to its own width rather than the
4209
+ // viewport's, and it takes no focus: nothing scrolls, so the stop would have
4210
+ // nothing to do. It still clips to its rounded border, and should anything
4211
+ // ever overflow it, the a11y gate names the scroll a keyboard cannot reach.
4113
4212
  /* @__PURE__ */ jsx(
4114
4213
  "div",
4115
4214
  {
4116
4215
  ref: scrollerRef,
4117
4216
  role: "group",
4118
4217
  "aria-label": label,
4119
- tabIndex: 0,
4120
- className: "overflow-x-auto rounded-lg border border-border",
4121
- children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-full border-collapse text-[13px]", children: [
4122
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted text-left", children: [
4123
- canExpand && /* @__PURE__ */ jsx("th", { scope: "col", style: { width: EXPAND_COLUMN }, className: "px-1", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: s.rowDetailsColumn }) }),
4124
- shown.map((column) => /* @__PURE__ */ jsx(
4125
- "th",
4126
- {
4127
- scope: "col",
4128
- className: cn(
4129
- "whitespace-nowrap px-3 py-2 text-[12px] font-semibold text-foreground",
4130
- presentation === "app" ? void 0 : "font-mono"
4131
- ),
4132
- children: /* @__PURE__ */ jsx(Described, { description: column.description, children: fieldLabel(column.title, column.name, presentation) })
4133
- },
4134
- column.name
4135
- ))
4136
- ] }) }),
4137
- /* @__PURE__ */ jsx("tbody", { children: items.map((item, index) => {
4138
- const isOpen = canExpand && expanded.has(index);
4139
- return /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border/60 last:border-b-0", children: [
4140
- canExpand && /* @__PURE__ */ jsx("td", { className: "px-1 pt-px align-top", children: /* @__PURE__ */ jsx(
4141
- "button",
4142
- {
4143
- type: "button",
4144
- onClick: () => toggle(index),
4145
- "aria-expanded": isOpen,
4146
- "aria-label": s.toggleRowDetails(index + 1),
4147
- className: "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",
4148
- children: isOpen ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5" })
4149
- }
4150
- ) }),
4151
- isOpen ? /* @__PURE__ */ jsx("td", { colSpan: shown.length, className: "bg-card/40 p-0", children: /* @__PURE__ */ jsx(
4152
- "div",
4153
- {
4154
- className: "sticky left-0 px-3.5 py-3",
4155
- ...viewportWidth ? {
4156
- style: {
4157
- // Minus the chevron column: this cell starts
4158
- // after it, so pinning it to the FULL visible
4159
- // width pushes its right edge that far past the
4160
- // scroller. See `EXPAND_COLUMN`.
4161
- width: canExpand ? `calc(${viewportWidth}px - ${EXPAND_COLUMN})` : viewportWidth
4162
- }
4163
- } : {},
4164
- children: /* @__PURE__ */ jsx(ResultField, { field: element, value: item, hideLabel: true })
4165
- }
4166
- ) }) : shown.map((column) => {
4167
- const cell = typeof item === "object" && item !== null ? ownProp(item, column.name) : void 0;
4168
- return /* @__PURE__ */ jsx("td", { className: "px-3 py-1.5 align-top", children: /* @__PURE__ */ jsx(
4169
- "div",
4218
+ ...fits ? {} : { tabIndex: 0 },
4219
+ className: cn(
4220
+ "overflow-x-auto rounded-lg border border-border",
4221
+ EXPAND_COLUMN_WIDTH,
4222
+ fits && "@container"
4223
+ ),
4224
+ children: /* @__PURE__ */ jsxs(
4225
+ "table",
4226
+ {
4227
+ className: cn("w-full min-w-full border-collapse text-[13px]", stacked?.table, fitShare),
4228
+ children: [
4229
+ /* @__PURE__ */ jsx("thead", { className: stacked?.head, children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted text-left", children: [
4230
+ canExpand && /* @__PURE__ */ jsx("th", { scope: "col", style: { width: EXPAND_COLUMN }, className: "px-1", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: s.rowDetailsColumn }) }),
4231
+ shown.map((column) => /* @__PURE__ */ jsx(
4232
+ "th",
4170
4233
  {
4234
+ scope: "col",
4235
+ ...floorsWords(column) ? { "data-fit": fieldLabel(column.title, column.name, presentation) } : {},
4171
4236
  className: cn(
4172
- "max-w-[44ch]",
4173
- column === name ? "max-w-none min-w-[16ch] wrap-anywhere [&>span]:whitespace-normal" : column.kind === "list" && isInlineColumn(column) ? "min-w-[16ch]" : "truncate"
4237
+ // One line, or wrapped anywhere so a header is never what
4238
+ // widens a table that has to fit its box. See `FIT_CELL`.
4239
+ fits ? "wrap-anywhere" : "whitespace-nowrap",
4240
+ "px-3 py-2 text-[12px] font-semibold text-foreground",
4241
+ presentation === "app" ? void 0 : "font-mono",
4242
+ floorsWords(column) && WORD_FLOOR
4174
4243
  ),
4175
- ...typeof cell === "string" || typeof cell === "number" ? { title: cellTitle(column, cell, presentation) } : {},
4176
- children: /* @__PURE__ */ jsx(ResultAt, { segment: column.name, children: /* @__PURE__ */ jsx(LeafValue, { field: column, value: cell, compact: true }) })
4244
+ children: /* @__PURE__ */ jsx(Described, { description: column.description, children: fieldLabel(column.title, column.name, presentation) })
4245
+ },
4246
+ column.name
4247
+ ))
4248
+ ] }) }),
4249
+ /* @__PURE__ */ jsx("tbody", { className: stacked?.body, children: items.map((item, index) => {
4250
+ const isOpen = canExpand && expanded.has(index);
4251
+ return /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsxs(
4252
+ "tr",
4253
+ {
4254
+ className: cn(
4255
+ "border-b border-border/60 last:border-b-0",
4256
+ stacked?.row,
4257
+ canExpand && stacked?.rowWithToggle
4258
+ ),
4259
+ children: [
4260
+ canExpand && /* @__PURE__ */ jsx("td", { className: cn("px-1 pt-px align-top", stacked?.toggle), children: /* @__PURE__ */ jsx(
4261
+ "button",
4262
+ {
4263
+ type: "button",
4264
+ onClick: () => toggle(index),
4265
+ "aria-expanded": isOpen,
4266
+ "aria-label": s.toggleRowDetails(index + 1),
4267
+ className: TOGGLE,
4268
+ children: isOpen ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-3.5" }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5" })
4269
+ }
4270
+ ) }),
4271
+ isOpen ? /* @__PURE__ */ jsx("td", { colSpan: shown.length, className: cn("bg-card/40 p-0", stacked?.detail), children: /* @__PURE__ */ jsx(
4272
+ "div",
4273
+ {
4274
+ className: cn(
4275
+ !fits && "sticky left-0",
4276
+ "px-3.5 py-3",
4277
+ stacked?.detailInner
4278
+ ),
4279
+ ...viewportWidth && !fits ? {
4280
+ style: {
4281
+ // Minus the chevron column: this cell starts
4282
+ // after it, so pinning it to the FULL visible
4283
+ // width pushes its right edge that far past the
4284
+ // scroller. See `EXPAND_COLUMN`.
4285
+ width: canExpand ? `calc(${viewportWidth}px - ${EXPAND_COLUMN})` : viewportWidth
4286
+ }
4287
+ } : {},
4288
+ children: /* @__PURE__ */ jsx(ResultField, { field: element, value: item, hideLabel: true })
4289
+ }
4290
+ ) }) : shown.map((column) => {
4291
+ const cell = typeof item === "object" && item !== null ? ownProp(item, column.name) : void 0;
4292
+ const columnLabel = fieldLabel(column.title, column.name, presentation);
4293
+ const words = floorsWords(column) ? cellWords(column, cell, presentation) : void 0;
4294
+ return /* @__PURE__ */ jsxs(
4295
+ "td",
4296
+ {
4297
+ ...words === void 0 ? {} : { "data-fit": words },
4298
+ className: cn(
4299
+ "px-3 py-1.5 align-top",
4300
+ floorsWords(column) && WORD_FLOOR,
4301
+ stacked?.cell
4302
+ ),
4303
+ children: [
4304
+ stacked && /* @__PURE__ */ jsx(
4305
+ "span",
4306
+ {
4307
+ className: cn(
4308
+ "hidden text-[12px] text-muted-foreground wrap-anywhere",
4309
+ presentation === "app" ? void 0 : "font-mono",
4310
+ stacked.label
4311
+ ),
4312
+ children: canExpand ? columnLabel : /* @__PURE__ */ jsx(Described, { description: column.description, children: columnLabel })
4313
+ }
4314
+ ),
4315
+ /* @__PURE__ */ jsx(
4316
+ "div",
4317
+ {
4318
+ className: fits ? column === name ? FIT_NAME : cn(FIT_CELL, clampsInStack(column, name) && "line-clamp-3") : cn(
4319
+ "max-w-[44ch]",
4320
+ column === name ? "max-w-none min-w-[16ch] wrap-anywhere [&>span]:whitespace-normal" : column.kind === "list" && isInlineColumn(column) ? "min-w-[16ch]" : "truncate"
4321
+ ),
4322
+ ...typeof cell === "string" || typeof cell === "number" ? { title: cellTitle(column, cell, presentation) } : {},
4323
+ children: /* @__PURE__ */ jsx(ResultAt, { segment: column.name, children: /* @__PURE__ */ jsx(LeafValue, { field: column, value: cell, compact: true }) })
4324
+ }
4325
+ )
4326
+ ]
4327
+ },
4328
+ column.name
4329
+ );
4330
+ })
4331
+ ]
4177
4332
  }
4178
- ) }, column.name);
4179
- })
4180
- ] }) }, index);
4181
- }) })
4182
- ] })
4333
+ ) }, index);
4334
+ }) })
4335
+ ]
4336
+ }
4337
+ )
4183
4338
  }
4184
4339
  )
4185
4340
  );
@@ -4513,8 +4668,8 @@ function resultKey(field, baseName, value) {
4513
4668
  return void 0;
4514
4669
  }
4515
4670
  }
4516
- function StuffViewer({ downloads, ...props }) {
4517
- return /* @__PURE__ */ jsx(DownloadDisplayOverride, { downloads, children: /* @__PURE__ */ jsx(StuffPanel, { ...props }) });
4671
+ function StuffViewer({ downloads, tableLayout, ...props }) {
4672
+ return /* @__PURE__ */ jsx(PanelEnvOverride, { downloads, tableLayout, children: /* @__PURE__ */ jsx(StuffPanel, { ...props }) });
4518
4673
  }
4519
4674
  function StuffPanel({
4520
4675
  field,
@@ -4680,5 +4835,5 @@ function pdfFileName(field, value, baseName) {
4680
4835
  }
4681
4836
 
4682
4837
  export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, 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, cn, fieldControlClass, fieldStringsFor, humanizeFieldName, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
4683
- //# sourceMappingURL=chunk-3KK2DO7T.js.map
4684
- //# sourceMappingURL=chunk-3KK2DO7T.js.map
4838
+ //# sourceMappingURL=chunk-Y4MTDG2R.js.map
4839
+ //# sourceMappingURL=chunk-Y4MTDG2R.js.map