camox 0.53.1 → 0.54.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.
@@ -0,0 +1,49 @@
1
+ //#region src/features/og/documentFonts.ts
2
+ const GOOGLE_FONTS_CSS2 = "https://fonts.googleapis.com/css2";
3
+ /**
4
+ * The Google Fonts families the document's stylesheet links load, in link order, so page images
5
+ * render in the site's fonts. Other stylesheets are ignored.
6
+ */
7
+ function documentGoogleFonts(document) {
8
+ return (Array.isArray(document.link) ? document.link : []).flatMap((link) => {
9
+ if (typeof link !== "object" || link === null) return [];
10
+ const { rel, href } = link;
11
+ if (rel !== "stylesheet" || typeof href !== "string") return [];
12
+ const url = URL.parse(href);
13
+ if (!url || `${url.origin}${url.pathname}` !== GOOGLE_FONTS_CSS2) return [];
14
+ return url.searchParams.getAll("family").map(parseFamily);
15
+ });
16
+ }
17
+ /**
18
+ * One css2 `family` parameter: `Inter`, or a name with its axes and their values, such as
19
+ * `Archivo:ital,wght@0,100..900;1,100..900` (one `;`-separated tuple per face).
20
+ */
21
+ function parseFamily(param) {
22
+ const [name = "", spec] = param.split(":");
23
+ if (!spec) return { name };
24
+ const [axisList = "", tupleList = ""] = spec.split("@");
25
+ const axes = axisList.split(",");
26
+ const tuples = tupleList.split(";").map((tuple) => tuple.split(","));
27
+ const valuesOf = (axis) => {
28
+ const index = axes.indexOf(axis);
29
+ return index < 0 ? [] : [...new Set(tuples.map((tuple) => tuple[index] ?? ""))];
30
+ };
31
+ const weights = valuesOf("wght");
32
+ const weightRange = weights.find(isRange);
33
+ const otherAxes = Object.fromEntries(axes.filter((axis) => axis !== "wght" && axis !== "ital").map((axis) => {
34
+ const [value = ""] = valuesOf(axis);
35
+ return [axis, isRange(value) ? value : Number(value)];
36
+ }));
37
+ return {
38
+ name,
39
+ ...weights.length > 0 && { weight: weightRange ?? weights.map(Number) },
40
+ ...axes.includes("ital") && { style: valuesOf("ital").map((ital) => ital === "1" ? "italic" : "normal") },
41
+ ...Object.keys(otherAxes).length > 0 && { axes: otherAxes }
42
+ };
43
+ }
44
+ function isRange(value) {
45
+ return value.includes("..");
46
+ }
47
+
48
+ //#endregion
49
+ export { documentGoogleFonts };
@@ -1,8 +1,17 @@
1
- import { ReactNode } from "react";
2
- import { ImageResponse as ImageResponse$1, ImageResponseOptions } from "@takumi-rs/image-response";
1
+ import { ReactElement } from "react";
2
+ import { GoogleFontFamily } from "takumi-js/helpers";
3
+ import { ImageResponse } from "takumi-js/response";
3
4
  //#region src/features/og/imageResponse.d.ts
4
- export declare class ImageResponse extends ImageResponse$1 {
5
- constructor(component: ReactNode, options?: ImageResponseOptions);
5
+ export interface ImageStyle {
6
+ /** The site's compiled stylesheet, which the image's `className`s match. */
7
+ css?: string;
8
+ /** The Google Fonts families the site loads, in fallback order. */
9
+ fonts: GoogleFontFamily[];
6
10
  }
11
+ /** Renders `element` as a PNG response, styled like the site. */
12
+ export declare function createImageResponse(element: ReactElement, size: {
13
+ width: number;
14
+ height: number;
15
+ }, { css, fonts }: ImageStyle): Promise<Response>;
7
16
  //#endregion
8
- export type { ImageResponseOptions };
17
+ export { ImageResponse };
@@ -1,26 +1,25 @@
1
- import { DEFAULT_FONTS } from "./defaultFonts.js";
2
- import { ImageResponse as ImageResponse$1 } from "@takumi-rs/image-response";
1
+ import { googleFonts } from "takumi-js/helpers";
2
+ import { ImageResponse } from "takumi-js/response";
3
3
 
4
4
  //#region src/features/og/imageResponse.ts
5
- /**
6
- * OG image renderer for the Worker.
7
- *
8
- * Under the `workerd` export condition, `@takumi-rs/image-response` picks Takumi's wasm
9
- * backend, which imports the wasm binary itself. The Cloudflare Vite plugin turns that
10
- * `.wasm` import into a `WebAssembly.Module`, and Takumi lazy-inits it inside the
11
- * response stream.
12
- *
13
- * Geist is bundled in `./defaultFonts` to compensate for the wasm renderer shipping with
14
- * no embedded fonts.
15
- */
16
- var ImageResponse = class extends ImageResponse$1 {
17
- constructor(component, options) {
18
- super(component, {
19
- ...options,
20
- fonts: options?.fonts ?? DEFAULT_FONTS
21
- });
5
+ /** Renders `element` as a PNG response, styled like the site. */
6
+ async function createImageResponse(element, size, { css, fonts }) {
7
+ return new ImageResponse(element, {
8
+ ...size,
9
+ css,
10
+ fonts: await loadFonts(fonts)
11
+ });
12
+ }
13
+ /** The families' font files, loaded lazily. Without them, the image falls back to Geist. */
14
+ async function loadFonts(families) {
15
+ if (families.length === 0) return [];
16
+ try {
17
+ return await googleFonts(families);
18
+ } catch (error) {
19
+ console.warn("[camox] Page image fonts failed to load; rendering with Geist.", error);
20
+ return [];
22
21
  }
23
- };
22
+ }
24
23
 
25
24
  //#endregion
26
- export { ImageResponse };
25
+ export { ImageResponse, createImageResponse };
@@ -78,11 +78,14 @@ function DefaultPageImage(t0) {
78
78
  } else t5 = $[8];
79
79
  return t5;
80
80
  }
81
- /** Renders a page image as a PNG response. Server only. */
82
- async function renderPageImage(element) {
81
+ /**
82
+ * Renders a page image as a PNG response, styled like the site: its elements' `className`s match
83
+ * the site's compiled stylesheet, and its text uses the site's fonts. Server only.
84
+ */
85
+ async function renderPageImage(element, style) {
83
86
  if (import.meta.env?.SSR === false) throw new Error("OG images can only be rendered on the server.");
84
- const { ImageResponse } = await import("camox/_internal/imageResponse");
85
- return new ImageResponse(element, PAGE_IMAGE_SIZE);
87
+ const { createImageResponse } = await import("camox/_internal/imageResponse");
88
+ return createImageResponse(element, PAGE_IMAGE_SIZE, style);
86
89
  }
87
90
 
88
91
  //#endregion
@@ -14,8 +14,8 @@ import { useMutation } from "@tanstack/react-query";
14
14
  import { Copy, Trash2 } from "lucide-react";
15
15
  import { toast } from "@camox/ui/toaster";
16
16
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
17
- import { Command as Command$1, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from "@camox/ui/command";
18
17
  import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
18
+ import { Command as Command$1, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from "@camox/ui/command";
19
19
 
20
20
  //#region src/features/preview/components/BlockActionsPopover.tsx
21
21
  const BlockActionsPopover = ({ block, children, open, onOpenChange, align = "start", isLayoutBlock, layoutSlot }) => {
@@ -5,9 +5,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Button } from "@camox/ui/button";
6
6
  import { ChevronsUpDown, SearchIcon } from "lucide-react";
7
7
  import { Combobox } from "@base-ui/react/combobox";
8
+ import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
8
9
  import { commandFilter } from "@camox/ui/command";
9
10
  import { InputGroup, InputGroupAddon, InputGroupInput } from "@camox/ui/input-group";
10
- import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
11
11
  import { defaultRangeExtractor, useVirtualizer } from "@tanstack/react-virtual";
12
12
 
13
13
  //#region src/features/preview/components/IconFieldEditor.tsx
@@ -10,8 +10,8 @@ import { Input } from "@camox/ui/input";
10
10
  import { Label } from "@camox/ui/label";
11
11
  import { Switch } from "@camox/ui/switch";
12
12
  import { Check, ChevronsUpDown } from "lucide-react";
13
- import { Command as Command$1, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@camox/ui/command";
14
13
  import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
14
+ import { Command as Command$1, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@camox/ui/command";
15
15
  import { Tabs, TabsList, TabsTrigger } from "@camox/ui/tabs";
16
16
 
17
17
  //#region src/features/preview/components/LinkFieldEditor.tsx
@@ -16,8 +16,8 @@ import { Check, ChevronsUpDown, Pencil, Plus, Trash2 } from "lucide-react";
16
16
  import { toast } from "@camox/ui/toaster";
17
17
  import { Skeleton } from "@camox/ui/skeleton";
18
18
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@camox/ui/alert-dialog";
19
- import { Command as Command$1, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from "@camox/ui/command";
20
19
  import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
20
+ import { Command as Command$1, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from "@camox/ui/command";
21
21
 
22
22
  //#region src/features/preview/components/PagePicker.tsx
23
23
  const CREATE_PAGE_VALUE = "__create_page__";
@@ -27,13 +27,33 @@ import { useMutation } from "@tanstack/react-query";
27
27
  import { Button } from "@camox/ui/button";
28
28
  import { Label } from "@camox/ui/label";
29
29
  import { Switch } from "@camox/ui/switch";
30
- import { CirclePlus, Trash2 } from "lucide-react";
30
+ import { CirclePlus, Ellipsis, Trash2 } from "lucide-react";
31
31
  import { ButtonGroup } from "@camox/ui/button-group";
32
32
  import { Spinner } from "@camox/ui/spinner";
33
33
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@camox/ui/select";
34
34
 
35
35
  //#region src/features/preview/components/SelectionEditor.tsx
36
36
  const EMPTY_CONTENT = {};
37
+ /**
38
+ * The path's headers. The `kept` first steps, the selection and its parent always show; two or
39
+ * more steps between them collapse into one header, which lists them.
40
+ */
41
+ function stackRows(items, kept) {
42
+ const rows = items.map((item, index) => ({
43
+ index,
44
+ item
45
+ }));
46
+ const between = items.slice(kept, -2);
47
+ if (between.length < 2) return rows;
48
+ return [
49
+ ...rows.slice(0, kept),
50
+ {
51
+ index: kept,
52
+ collapsed: between
53
+ },
54
+ ...rows.slice(kept + between.length)
55
+ ];
56
+ }
37
57
  const getSettingsFields = (schema) => {
38
58
  const properties = schema?.properties;
39
59
  if (!properties) return [];
@@ -119,7 +139,7 @@ const SelectionEditor = (t0) => {
119
139
  return t2;
120
140
  };
121
141
  const SelectionEditorContent = (t0) => {
122
- const $ = c(145);
142
+ const $ = c(131);
123
143
  const { owner, pageCrumb } = t0;
124
144
  let t1;
125
145
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
@@ -611,30 +631,15 @@ const SelectionEditorContent = (t0) => {
611
631
  $[90] = t33;
612
632
  } else t33 = $[90];
613
633
  const blockCrumbs = t33;
614
- const t34 = owner.kind === "page" ? "Page" : "Layout";
615
- let t35;
616
- if ($[91] !== t34) {
617
- t35 = {
634
+ const navigationItems = [
635
+ {
618
636
  key: "page",
619
637
  hoverTarget: null,
620
- label: t34,
638
+ label: owner.kind === "page" ? "Page" : "Layout",
621
639
  isCurrent: false,
622
640
  onClick: _temp5
623
- };
624
- $[91] = t34;
625
- $[92] = t35;
626
- } else t35 = $[92];
627
- let t36;
628
- if ($[93] !== block || $[94] !== blockCrumbs || $[95] !== blockDef) {
629
- t36 = block && blockDef ? blockCrumbs(block, blockDef) : [];
630
- $[93] = block;
631
- $[94] = blockCrumbs;
632
- $[95] = blockDef;
633
- $[96] = t36;
634
- } else t36 = $[96];
635
- const navigationItems = [
636
- t35,
637
- ...t36,
641
+ },
642
+ ...block && blockDef ? blockCrumbs(block, blockDef) : [],
638
643
  ...recordCrumbs(fieldHasOwnView),
639
644
  ...fieldHasOwnView && fieldInfo ? [{
640
645
  key: `field-${fieldInfo.fieldName}`,
@@ -647,48 +652,66 @@ const SelectionEditorContent = (t0) => {
647
652
  const stackedItems = pageCrumb ? navigationItems : navigationItems.slice(1);
648
653
  const firstDepth = pageCrumb ? 1 : 2;
649
654
  const front = stackedItems[stackedItems.length - 1];
650
- let t37;
651
- if ($[97] !== stackedItems.length) {
652
- t37 = /* @__PURE__ */ jsx(SelectionViewCount, { count: stackedItems.length });
653
- $[97] = stackedItems.length;
654
- $[98] = t37;
655
- } else t37 = $[98];
655
+ const rows = stackRows(stackedItems, pageCrumb ? 1 : 0);
656
+ const t34 = "Selection path";
657
+ const t35 = "shrink-0";
658
+ const t36 = "flex flex-col";
659
+ const t37 = rows.map((row, index) => {
660
+ const distance = rows.length - 1 - index;
661
+ const covered = distance > 0;
662
+ const depth = firstDepth + row.index;
663
+ if (row.collapsed) return /* @__PURE__ */ jsx("li", {
664
+ className: "relative flex flex-col",
665
+ children: /* @__PURE__ */ jsx(SidebarStackHeader, {
666
+ depth,
667
+ distance,
668
+ popover: /* @__PURE__ */ jsx("ol", {
669
+ "aria-label": "Collapsed parents",
670
+ className: "flex flex-col",
671
+ children: row.collapsed.map(_temp6)
672
+ }),
673
+ children: /* @__PURE__ */ jsxs("span", {
674
+ className: "flex min-w-0 items-center gap-1.5",
675
+ children: [/* @__PURE__ */ jsx(Ellipsis, { className: "size-3.5 shrink-0" }), /* @__PURE__ */ jsxs("span", {
676
+ className: "truncate",
677
+ children: [row.collapsed.length, " parents"]
678
+ })]
679
+ })
680
+ })
681
+ }, "collapsed-parents");
682
+ const { item: item_0 } = row;
683
+ return /* @__PURE__ */ jsx("li", {
684
+ className: "relative flex flex-col",
685
+ children: /* @__PURE__ */ jsx(SidebarStackHeader, {
686
+ depth,
687
+ distance,
688
+ first: pageCrumb && row.index === 0,
689
+ onSelect: item_0.onClick,
690
+ hoverTarget: item_0.hoverTarget,
691
+ children: covered ? item_0.label : /* @__PURE__ */ jsx("span", {
692
+ className: "truncate font-medium",
693
+ children: item_0.label
694
+ })
695
+ })
696
+ }, item_0.key);
697
+ });
656
698
  let t38;
657
- if ($[99] !== firstDepth || $[100] !== pageCrumb || $[101] !== stackedItems) {
699
+ if ($[91] !== t37) {
658
700
  t38 = /* @__PURE__ */ jsx("nav", {
659
- "aria-label": "Selection path",
660
- className: "shrink-0",
701
+ "aria-label": t34,
702
+ className: t35,
661
703
  children: /* @__PURE__ */ jsx("ol", {
662
- className: "flex flex-col",
663
- children: stackedItems.map((item, index) => {
664
- const distance = stackedItems.length - 1 - index;
665
- const covered = distance > 0;
666
- return /* @__PURE__ */ jsx("li", {
667
- className: "relative flex flex-col",
668
- children: /* @__PURE__ */ jsx(SidebarStackHeader, {
669
- depth: firstDepth + index,
670
- distance,
671
- first: pageCrumb && index === 0,
672
- onSelect: item.onClick,
673
- hoverTarget: item.hoverTarget,
674
- children: covered ? item.label : /* @__PURE__ */ jsx("span", {
675
- className: "truncate font-medium",
676
- children: item.label
677
- })
678
- })
679
- }, item.key);
680
- })
704
+ className: t36,
705
+ children: t37
681
706
  })
682
707
  });
683
- $[99] = firstDepth;
684
- $[100] = pageCrumb;
685
- $[101] = stackedItems;
686
- $[102] = t38;
687
- } else t38 = $[102];
708
+ $[91] = t37;
709
+ $[92] = t38;
710
+ } else t38 = $[92];
688
711
  const t39 = `${block?.id ?? "layout"}:${front?.key}`;
689
712
  const t40 = firstDepth + stackedItems.length - 1;
690
713
  let t41;
691
- if ($[103] !== addSibling || $[104] !== assetAccept || $[105] !== assetFieldName || $[106] !== assetType || $[107] !== block || $[108] !== blockDef || $[109] !== canAddSibling || $[110] !== canRemoveCurrent || $[111] !== currentData || $[112] !== currentItem || $[113] !== currentItemId || $[114] !== currentSchema || $[115] !== fieldHasOwnView || $[116] !== fieldIdPrefix || $[117] !== fieldInfo?.fieldName || $[118] !== filesMap || $[119] !== isItemLoading || $[120] !== isMultipleAsset || $[121] !== isViewingAsset || $[122] !== isViewingLink || $[123] !== itemArraySchema || $[124] !== itemSettingsFields || $[125] !== itemsMap || $[126] !== linkFieldName || $[127] !== owner || $[128] !== recordInList || $[129] !== recordView || $[130] !== removeCurrent || $[131] !== send || $[132] !== settingsFields || $[133] !== updateRepeatableSettings || $[134] !== updateSettings || $[135] !== writeField) {
714
+ if ($[93] !== addSibling || $[94] !== assetAccept || $[95] !== assetFieldName || $[96] !== assetType || $[97] !== block || $[98] !== blockDef || $[99] !== canAddSibling || $[100] !== canRemoveCurrent || $[101] !== currentData || $[102] !== currentItem || $[103] !== currentItemId || $[104] !== currentSchema || $[105] !== fieldHasOwnView || $[106] !== fieldIdPrefix || $[107] !== fieldInfo?.fieldName || $[108] !== filesMap || $[109] !== isItemLoading || $[110] !== isMultipleAsset || $[111] !== isViewingAsset || $[112] !== isViewingLink || $[113] !== itemArraySchema || $[114] !== itemSettingsFields || $[115] !== itemsMap || $[116] !== linkFieldName || $[117] !== owner || $[118] !== recordInList || $[119] !== recordView || $[120] !== removeCurrent || $[121] !== send || $[122] !== settingsFields || $[123] !== updateRepeatableSettings || $[124] !== updateSettings || $[125] !== writeField) {
692
715
  t41 = /* @__PURE__ */ jsx("div", { children: isItemLoading ? /* @__PURE__ */ jsx("div", {
693
716
  className: "flex h-full items-center justify-center py-12",
694
717
  children: /* @__PURE__ */ jsx(Spinner, {})
@@ -895,66 +918,58 @@ const SelectionEditorContent = (t0) => {
895
918
  fieldIdPrefix
896
919
  }, `${block?.id ?? "layout"}-${recordView ? `record-${recordView.record.id}` : currentItemId ?? "block"}-${fieldInfo?.fieldName ?? "fields"}`)
897
920
  ] }) });
898
- $[103] = addSibling;
899
- $[104] = assetAccept;
900
- $[105] = assetFieldName;
901
- $[106] = assetType;
902
- $[107] = block;
903
- $[108] = blockDef;
904
- $[109] = canAddSibling;
905
- $[110] = canRemoveCurrent;
906
- $[111] = currentData;
907
- $[112] = currentItem;
908
- $[113] = currentItemId;
909
- $[114] = currentSchema;
910
- $[115] = fieldHasOwnView;
911
- $[116] = fieldIdPrefix;
912
- $[117] = fieldInfo?.fieldName;
913
- $[118] = filesMap;
914
- $[119] = isItemLoading;
915
- $[120] = isMultipleAsset;
916
- $[121] = isViewingAsset;
917
- $[122] = isViewingLink;
918
- $[123] = itemArraySchema;
919
- $[124] = itemSettingsFields;
920
- $[125] = itemsMap;
921
- $[126] = linkFieldName;
922
- $[127] = owner;
923
- $[128] = recordInList;
924
- $[129] = recordView;
925
- $[130] = removeCurrent;
926
- $[131] = send;
927
- $[132] = settingsFields;
928
- $[133] = updateRepeatableSettings;
929
- $[134] = updateSettings;
930
- $[135] = writeField;
931
- $[136] = t41;
932
- } else t41 = $[136];
921
+ $[93] = addSibling;
922
+ $[94] = assetAccept;
923
+ $[95] = assetFieldName;
924
+ $[96] = assetType;
925
+ $[97] = block;
926
+ $[98] = blockDef;
927
+ $[99] = canAddSibling;
928
+ $[100] = canRemoveCurrent;
929
+ $[101] = currentData;
930
+ $[102] = currentItem;
931
+ $[103] = currentItemId;
932
+ $[104] = currentSchema;
933
+ $[105] = fieldHasOwnView;
934
+ $[106] = fieldIdPrefix;
935
+ $[107] = fieldInfo?.fieldName;
936
+ $[108] = filesMap;
937
+ $[109] = isItemLoading;
938
+ $[110] = isMultipleAsset;
939
+ $[111] = isViewingAsset;
940
+ $[112] = isViewingLink;
941
+ $[113] = itemArraySchema;
942
+ $[114] = itemSettingsFields;
943
+ $[115] = itemsMap;
944
+ $[116] = linkFieldName;
945
+ $[117] = owner;
946
+ $[118] = recordInList;
947
+ $[119] = recordView;
948
+ $[120] = removeCurrent;
949
+ $[121] = send;
950
+ $[122] = settingsFields;
951
+ $[123] = updateRepeatableSettings;
952
+ $[124] = updateSettings;
953
+ $[125] = writeField;
954
+ $[126] = t41;
955
+ } else t41 = $[126];
933
956
  let t42;
934
- if ($[137] !== t39 || $[138] !== t40 || $[139] !== t41) {
957
+ if ($[127] !== t39 || $[128] !== t40 || $[129] !== t41) {
935
958
  t42 = /* @__PURE__ */ jsx(SidebarStackView, {
936
959
  depth: t40,
937
960
  className: "relative min-w-0 overflow-x-hidden overflow-y-auto",
938
961
  children: t41
939
962
  }, t39);
940
- $[137] = t39;
941
- $[138] = t40;
942
- $[139] = t41;
943
- $[140] = t42;
944
- } else t42 = $[140];
945
- let t43;
946
- if ($[141] !== t37 || $[142] !== t38 || $[143] !== t42) {
947
- t43 = /* @__PURE__ */ jsxs(Fragment, { children: [
948
- t37,
949
- t38,
950
- t42
951
- ] });
952
- $[141] = t37;
953
- $[142] = t38;
954
- $[143] = t42;
955
- $[144] = t43;
956
- } else t43 = $[144];
957
- return t43;
963
+ $[127] = t39;
964
+ $[128] = t40;
965
+ $[129] = t41;
966
+ $[130] = t42;
967
+ } else t42 = $[130];
968
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
969
+ /* @__PURE__ */ jsx(SelectionViewCount, { count: rows.length }),
970
+ t38,
971
+ t42
972
+ ] });
958
973
  };
959
974
  function _temp(i) {
960
975
  return [i.id, i];
@@ -971,6 +986,17 @@ function _temp4(f_0) {
971
986
  function _temp5() {
972
987
  return previewStore.send({ type: "clearSelection" });
973
988
  }
989
+ function _temp6(item) {
990
+ return /* @__PURE__ */ jsx("li", {
991
+ className: "flex",
992
+ children: /* @__PURE__ */ jsx("button", {
993
+ type: "button",
994
+ className: "hover:bg-accent hover:text-accent-foreground min-w-0 flex-1 cursor-pointer truncate rounded-sm px-2 py-1.5 text-left text-sm",
995
+ onClick: item.onClick,
996
+ children: item.label
997
+ })
998
+ }, item.key);
999
+ }
974
1000
 
975
1001
  //#endregion
976
1002
  export { SelectionEditor };