@burojs/ui-shadcn 0.6.0 → 0.7.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.
Files changed (152) hide show
  1. package/README.md +9 -0
  2. package/dist/bulk-summary-BWSAS7k2.js +143 -0
  3. package/dist/bulk-summary-BWSAS7k2.js.map +1 -0
  4. package/dist/bulk-summary-CrEij5vq.cjs +143 -0
  5. package/dist/bulk-summary-CrEij5vq.cjs.map +1 -0
  6. package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CS_JZ4Fd.js} +3 -3
  7. package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CS_JZ4Fd.js.map} +1 -1
  8. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-y5M6_oe4.cjs} +4 -4
  9. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-y5M6_oe4.cjs.map} +1 -1
  10. package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-2j0gOd7x.js} +384 -108
  11. package/dist/check-confirm-dialog-2j0gOd7x.js.map +1 -0
  12. package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-C-NHgMST.cjs} +468 -107
  13. package/dist/check-confirm-dialog-C-NHgMST.cjs.map +1 -0
  14. package/dist/{dialog-B_rt9S1c.js → dialog-C123sVQ8.js} +4 -4
  15. package/dist/dialog-C123sVQ8.js.map +1 -0
  16. package/dist/{dialog-DRNUq9EA.cjs → dialog-vmMdfUWs.cjs} +3 -3
  17. package/dist/dialog-vmMdfUWs.cjs.map +1 -0
  18. package/dist/{filter-builder-nXqtM_h4.cjs → filter-builder-DFu0JP-1.cjs} +923 -120
  19. package/dist/filter-builder-DFu0JP-1.cjs.map +1 -0
  20. package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-DaWHUZuV.js} +839 -108
  21. package/dist/filter-builder-DaWHUZuV.js.map +1 -0
  22. package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BpmrIUb6.cjs} +61 -29
  23. package/dist/flow-runtime-BpmrIUb6.cjs.map +1 -0
  24. package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DyqTmK3H.js} +62 -30
  25. package/dist/flow-runtime-DyqTmK3H.js.map +1 -0
  26. package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-Bcz9NF2V.cjs} +128 -87
  27. package/dist/flow-screen-Bcz9NF2V.cjs.map +1 -0
  28. package/dist/{flow-screen-CCvgDI9G.js → flow-screen-DCdli6Ha.js} +128 -87
  29. package/dist/flow-screen-DCdli6Ha.js.map +1 -0
  30. package/dist/index.cjs +731 -906
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +455 -247
  33. package/dist/index.d.ts +455 -247
  34. package/dist/index.js +647 -828
  35. package/dist/index.js.map +1 -1
  36. package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-3vw7LzzD.cjs} +5 -5
  37. package/dist/inline-flow-host-3vw7LzzD.cjs.map +1 -0
  38. package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-C0rI9B7f.js} +5 -5
  39. package/dist/inline-flow-host-C0rI9B7f.js.map +1 -0
  40. package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-Bt8lrEIu.cjs} +10 -10
  41. package/dist/lazy-relation-picker-dialog-Bt8lrEIu.cjs.map +1 -0
  42. package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-CAScLPb2.js} +11 -11
  43. package/dist/lazy-relation-picker-dialog-CAScLPb2.js.map +1 -0
  44. package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-BHUEpn0I.js} +36 -23
  45. package/dist/page-flow-route-BHUEpn0I.js.map +1 -0
  46. package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DS8IVTVH.cjs} +41 -28
  47. package/dist/page-flow-route-DS8IVTVH.cjs.map +1 -0
  48. package/dist/{place-node-C5SmIAYU.cjs → place-node-CNb3w-c7.cjs} +1869 -947
  49. package/dist/place-node-CNb3w-c7.cjs.map +1 -0
  50. package/dist/{place-node-NraNYKPx.js → place-node-CfzQvh4Y.js} +1824 -926
  51. package/dist/place-node-CfzQvh4Y.js.map +1 -0
  52. package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BIqqY69Y.js} +9 -4
  53. package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BIqqY69Y.js.map} +1 -1
  54. package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-CelMxl4q.cjs} +9 -4
  55. package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-CelMxl4q.cjs.map} +1 -1
  56. package/dist/{related-list-timeline-yrPsjA3F.js → related-list-timeline-CRh7xwLD.js} +6 -7
  57. package/dist/related-list-timeline-CRh7xwLD.js.map +1 -0
  58. package/dist/{related-list-timeline-CCzl71aA.cjs → related-list-timeline-DsLdi8sv.cjs} +5 -6
  59. package/dist/related-list-timeline-DsLdi8sv.cjs.map +1 -0
  60. package/dist/{related-rows-o0_t-Yce.js → related-rows--uP2iKQC.js} +25 -14
  61. package/dist/related-rows--uP2iKQC.js.map +1 -0
  62. package/dist/{related-rows-ea43qhhy.cjs → related-rows-MPnLCmPF.cjs} +27 -16
  63. package/dist/related-rows-MPnLCmPF.cjs.map +1 -0
  64. package/dist/{search-access-CPPmfuvy.js → relation-create-C43cdPQt.js} +595 -13
  65. package/dist/relation-create-C43cdPQt.js.map +1 -0
  66. package/dist/{search-access-Dugvttlg.cjs → relation-create-DDEYcKfw.cjs} +633 -14
  67. package/dist/relation-create-DDEYcKfw.cjs.map +1 -0
  68. package/dist/{relation-many-picker-bvkjkv-k.js → relation-many-picker-BJhaEqxz.js} +203 -102
  69. package/dist/relation-many-picker-BJhaEqxz.js.map +1 -0
  70. package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-DzuGJpEl.cjs} +211 -110
  71. package/dist/relation-many-picker-DzuGJpEl.cjs.map +1 -0
  72. package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-D-tBBZW_.js} +23 -59
  73. package/dist/relation-picker-D-tBBZW_.js.map +1 -0
  74. package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-DaIMzf2H.cjs} +29 -71
  75. package/dist/relation-picker-DaIMzf2H.cjs.map +1 -0
  76. package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-9Vg5vvR1.cjs} +133 -35
  77. package/dist/relation-picker-dialog-9Vg5vvR1.cjs.map +1 -0
  78. package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-DoEY8EkH.js} +134 -36
  79. package/dist/relation-picker-dialog-DoEY8EkH.js.map +1 -0
  80. package/dist/relation-select-B8Fq4o-t.js +48 -0
  81. package/dist/relation-select-B8Fq4o-t.js.map +1 -0
  82. package/dist/relation-select-Cr3CfNLy.cjs +55 -0
  83. package/dist/relation-select-Cr3CfNLy.cjs.map +1 -0
  84. package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-C_kGW2o_.cjs} +543 -300
  85. package/dist/resource-page-router-C_kGW2o_.cjs.map +1 -0
  86. package/dist/{resource-page-router-3RUf9d1j.js → resource-page-router-Diw6S6TK.js} +498 -255
  87. package/dist/resource-page-router-Diw6S6TK.js.map +1 -0
  88. package/dist/{rich-text-vTyVjDoa.cjs → rich-text-C_7JCvRo.cjs} +2 -2
  89. package/dist/{rich-text-vTyVjDoa.cjs.map → rich-text-C_7JCvRo.cjs.map} +1 -1
  90. package/dist/{rich-text-DFerywgz.js → rich-text-RcPBf6hr.js} +2 -2
  91. package/dist/{rich-text-DFerywgz.js.map → rich-text-RcPBf6hr.js.map} +1 -1
  92. package/dist/success-notices-Dl3M1fZP.cjs +46 -0
  93. package/dist/success-notices-Dl3M1fZP.cjs.map +1 -0
  94. package/dist/success-notices-LDEgEkc4.js +41 -0
  95. package/dist/success-notices-LDEgEkc4.js.map +1 -0
  96. package/dist/{toaster-Cr51X7bz.cjs → toaster-BbByOytP.cjs} +60 -15
  97. package/dist/toaster-BbByOytP.cjs.map +1 -0
  98. package/dist/{toaster-C02XbB9r.js → toaster-Ct_YHGs6.js} +43 -16
  99. package/dist/toaster-Ct_YHGs6.js.map +1 -0
  100. package/dist/{use-dialog-filter-state-C--oMAZG.js → use-dialog-filter-state-B_MqzHaT.js} +5 -4
  101. package/dist/use-dialog-filter-state-B_MqzHaT.js.map +1 -0
  102. package/dist/{use-dialog-filter-state-Dhe8PcB5.cjs → use-dialog-filter-state-tNvqAAjh.cjs} +6 -5
  103. package/dist/use-dialog-filter-state-tNvqAAjh.cjs.map +1 -0
  104. package/package.json +11 -11
  105. package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
  106. package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
  107. package/dist/bulk-summary-GxMDP4bw.js +0 -108
  108. package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
  109. package/dist/candidates-gate-Bb70LPAy.js.map +0 -1
  110. package/dist/candidates-gate-D33jXLHO.cjs.map +0 -1
  111. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +0 -1
  112. package/dist/check-confirm-dialog-bRT8lt0d.js.map +0 -1
  113. package/dist/dialog-B_rt9S1c.js.map +0 -1
  114. package/dist/dialog-DRNUq9EA.cjs.map +0 -1
  115. package/dist/filter-builder-Bhn-dhZV.js.map +0 -1
  116. package/dist/filter-builder-nXqtM_h4.cjs.map +0 -1
  117. package/dist/flow-runtime-D3avVH0I.cjs.map +0 -1
  118. package/dist/flow-runtime-s6lkRPKF.js.map +0 -1
  119. package/dist/flow-screen-CCvgDI9G.js.map +0 -1
  120. package/dist/flow-screen-Ci_Sik4Y.cjs.map +0 -1
  121. package/dist/inline-flow-host-B6FI0ctQ.js.map +0 -1
  122. package/dist/inline-flow-host-DV1et3c6.cjs.map +0 -1
  123. package/dist/page-flow-route-hdnULWqd.cjs.map +0 -1
  124. package/dist/page-flow-route-i3ZfJ1sd.js.map +0 -1
  125. package/dist/place-node-C5SmIAYU.cjs.map +0 -1
  126. package/dist/place-node-NraNYKPx.js.map +0 -1
  127. package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
  128. package/dist/related-list-timeline-yrPsjA3F.js.map +0 -1
  129. package/dist/related-rows-ea43qhhy.cjs.map +0 -1
  130. package/dist/related-rows-o0_t-Yce.js.map +0 -1
  131. package/dist/relation-create-IA40t1hi.cjs +0 -364
  132. package/dist/relation-create-IA40t1hi.cjs.map +0 -1
  133. package/dist/relation-create-h6F9B4C4.js +0 -339
  134. package/dist/relation-create-h6F9B4C4.js.map +0 -1
  135. package/dist/relation-many-picker-C8zFEjwd.cjs.map +0 -1
  136. package/dist/relation-many-picker-bvkjkv-k.js.map +0 -1
  137. package/dist/relation-picker-Z0ZJJ5uS.js.map +0 -1
  138. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +0 -1
  139. package/dist/relation-picker-dialog-B6nIiJBf.js.map +0 -1
  140. package/dist/relation-picker-gag0qSR5.cjs.map +0 -1
  141. package/dist/resource-page-router-3RUf9d1j.js.map +0 -1
  142. package/dist/resource-page-router-PXfMW9nh.cjs.map +0 -1
  143. package/dist/search-access-CPPmfuvy.js.map +0 -1
  144. package/dist/search-access-Dugvttlg.cjs.map +0 -1
  145. package/dist/shell-BPlk8hEa.js +0 -205
  146. package/dist/shell-BPlk8hEa.js.map +0 -1
  147. package/dist/shell-DxhlsPwm.cjs +0 -271
  148. package/dist/shell-DxhlsPwm.cjs.map +0 -1
  149. package/dist/toaster-C02XbB9r.js.map +0 -1
  150. package/dist/toaster-Cr51X7bz.cjs.map +0 -1
  151. package/dist/use-dialog-filter-state-C--oMAZG.js.map +0 -1
  152. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +0 -1
@@ -1,13 +1,14 @@
1
1
  import { l as cn } from "./use-theme-dnE3Od3I.js";
2
- import { d as PopoverTrigger, s as Popover, u as PopoverContent } from "./toaster-C02XbB9r.js";
2
+ import { m as PopoverTrigger, p as PopoverContent, u as Popover } from "./toaster-Ct_YHGs6.js";
3
3
  import { t as Button } from "./button-MWVeZaqj.js";
4
4
  import { t as Input } from "./input-CUPStzZO.js";
5
- import { _ as CommandEmpty, b as CommandItem, d as useRowTitle, h as Command, n as narrowSearchDecl, v as CommandGroup, x as CommandList, y as CommandInput } from "./search-access-CPPmfuvy.js";
6
- import { EMPTY_FILTER_GROUP, convertValueForOp, enumValueText, isCompletePredicate, isFilterGroup, opArity, resolveEnumLabel } from "@burojs/core";
7
- import { DEFAULT_LANGUAGE_STORAGE_KEY, useApp, useEnumValues, useI18nCaps, useList, useListAccess, useOptionalT, useRelatedRecord } from "@burojs/react";
8
- import { IconCheck, IconChevronDown, IconChevronUp, IconFilter, IconFolderPlus, IconLoader2, IconPlus, IconX } from "@tabler/icons-react";
5
+ import { C as CommandEmpty, D as CommandList, E as CommandItem, T as CommandInput, m as useRowTitle, o as narrowSearchDecl, w as CommandGroup, x as Command } from "./relation-create-C43cdPQt.js";
6
+ import { t as Skeleton } from "./skeleton-U2noefj5.js";
7
+ import { EMPTY_FILTER_GROUP, canonicalResourceKey, convertValueForOp, declaredText, enumValueText, formatEntityRef, isCompletePredicate, isFilterGroup, opArity, resolveEnumLabel, resolveSurfaceUi } from "@burojs/core";
8
+ import { DEFAULT_LANGUAGE_STORAGE_KEY, scopeValueOf, useApp, useChromeT, useEnumValues, useFieldDisplayText, useFieldImplementation, useFieldMeta, useFieldMetaSources, useI18nCaps, useImplementationTexts, useList, useListAccess, useLocale, useOptionalLocale, useOptionalT, useRelatedRecord, useResolvedFieldOptions } from "@burojs/react";
9
+ import { IconCheck, IconChevronDown, IconChevronUp, IconCirclePlus, IconFilter, IconFolderPlus, IconLoader2, IconPlus, IconX } from "@tabler/icons-react";
9
10
  import * as React from "react";
10
- import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
11
+ import { Fragment, createElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
11
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
13
  import { cva } from "class-variance-authority";
13
14
  import * as SelectPrimitive from "@radix-ui/react-select";
@@ -27,6 +28,505 @@ function saveLocale(code, storageKey = DEFAULT_LANGUAGE_STORAGE_KEY) {
27
28
  } catch {}
28
29
  }
29
30
  //#endregion
31
+ //#region src/fields/legacy-field.ts
32
+ const STRING_ITEM = Object.freeze({ type: "string" });
33
+ const LEGACY_KIND_DECLARATIONS = Object.freeze({
34
+ string: { type: "string" },
35
+ text: {
36
+ type: "string",
37
+ format: "text"
38
+ },
39
+ textarea: {
40
+ type: "string",
41
+ format: "textarea"
42
+ },
43
+ code: {
44
+ type: "string",
45
+ format: "code"
46
+ },
47
+ email: {
48
+ type: "string",
49
+ format: "email"
50
+ },
51
+ url: {
52
+ type: "string",
53
+ format: "url"
54
+ },
55
+ uuid: {
56
+ type: "string",
57
+ format: "uuid"
58
+ },
59
+ number: { type: "number" },
60
+ boolean: { type: "boolean" },
61
+ date: {
62
+ type: "string",
63
+ format: "date"
64
+ },
65
+ dateTime: {
66
+ type: "string",
67
+ format: "date-time"
68
+ },
69
+ enum: {
70
+ type: "string",
71
+ format: "enum"
72
+ },
73
+ json: {
74
+ type: "object",
75
+ format: "json"
76
+ },
77
+ richText: {
78
+ type: "string",
79
+ format: "rich-text"
80
+ },
81
+ file: {
82
+ type: "array",
83
+ format: "file",
84
+ items: STRING_ITEM
85
+ },
86
+ relation: { type: "relation" },
87
+ relationMany: {
88
+ type: "array",
89
+ format: "relation",
90
+ items: STRING_ITEM
91
+ }
92
+ });
93
+ const SEMANTIC_KEYS = Object.freeze([
94
+ "type",
95
+ "format",
96
+ "meta",
97
+ "required",
98
+ "nullable",
99
+ "empty",
100
+ "default",
101
+ "constraints",
102
+ "texts",
103
+ "options",
104
+ "items",
105
+ "properties",
106
+ "additionalProperties",
107
+ "variants"
108
+ ]);
109
+ function ownData(value, key) {
110
+ if (value === null || typeof value !== "object" && typeof value !== "function") return { present: false };
111
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
112
+ if (descriptor === void 0 || !Object.prototype.propertyIsEnumerable.call(value, key) || !("value" in descriptor)) return { present: false };
113
+ return {
114
+ present: true,
115
+ value: descriptor.value
116
+ };
117
+ }
118
+ function ownString(value, key) {
119
+ const candidate = ownData(value, key).value;
120
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
121
+ }
122
+ function ownSelection(value, key) {
123
+ const candidate = ownData(value, key).value;
124
+ if (typeof candidate === "string") return candidate.length > 0 ? candidate : void 0;
125
+ return candidate !== null && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : void 0;
126
+ }
127
+ function projectUiSelection(input) {
128
+ const selection = {};
129
+ const inputId = ownSelection(input, "input");
130
+ const displayId = ownSelection(input, "display");
131
+ if (inputId !== void 0) selection.input = inputId;
132
+ if (displayId !== void 0) selection.display = displayId;
133
+ return inputId === void 0 && displayId === void 0 ? void 0 : Object.freeze(selection);
134
+ }
135
+ function projectFieldDeclaration(input) {
136
+ const type = ownString(input, "type");
137
+ if (type === void 0) return void 0;
138
+ const projected = { type };
139
+ for (const key of SEMANTIC_KEYS) {
140
+ if (key === "type" || key === "items" || key === "properties" || key === "variants") continue;
141
+ const candidate = ownData(input, key);
142
+ if (candidate.present && candidate.value !== void 0) projected[key] = candidate.value;
143
+ }
144
+ const ui = projectUiSelection(ownData(input, "ui").value);
145
+ if (ui !== void 0) projected.ui = ui;
146
+ if (type === "array") {
147
+ const item = projectFieldDeclaration(ownData(input, "items").value);
148
+ if (item !== void 0) projected.items = item;
149
+ }
150
+ if (type === "object") {
151
+ const properties = ownData(input, "properties").value;
152
+ if (properties !== null && typeof properties === "object" && !Array.isArray(properties)) {
153
+ const output = {};
154
+ for (const key of Object.keys(properties)) {
155
+ const child = projectFieldDeclaration(ownData(properties, key).value);
156
+ if (child !== void 0) output[key] = child;
157
+ }
158
+ projected.properties = Object.freeze(output);
159
+ }
160
+ }
161
+ if (type === "union") {
162
+ const variants = ownData(input, "variants").value;
163
+ if (Array.isArray(variants)) {
164
+ const output = [];
165
+ for (let index = 0; index < variants.length; index += 1) {
166
+ const child = projectFieldDeclaration(ownData(variants, index).value);
167
+ if (child !== void 0) output.push(child);
168
+ }
169
+ projected.variants = Object.freeze(output);
170
+ }
171
+ }
172
+ return Object.freeze(projected);
173
+ }
174
+ function projectUiHints(input) {
175
+ if (input === null || typeof input !== "object" || Array.isArray(input)) return void 0;
176
+ const projected = {};
177
+ for (const key of Object.keys(input)) {
178
+ const candidate = ownData(input, key);
179
+ if (candidate.present) projected[key] = candidate.value;
180
+ }
181
+ return Object.freeze(projected);
182
+ }
183
+ function enumValueOptions(field) {
184
+ const own = ownData(field, "values").value;
185
+ const values = Array.isArray(own) ? own : ownData(ownData(field, "ui").value, "values").value;
186
+ if (!Array.isArray(values)) return void 0;
187
+ const options = values.filter((value) => typeof value === "string").map((value) => Object.freeze({ value }));
188
+ return options.length === 0 ? void 0 : Object.freeze(options);
189
+ }
190
+ function lowerLegacyField(field) {
191
+ const declaration = projectFieldDeclaration(ownData(field, "declaration").value);
192
+ if (declaration !== void 0) return declaration;
193
+ const direct = projectFieldDeclaration(field);
194
+ const kind = ownString(field, "kind");
195
+ const mapping = kind === void 0 ? void 0 : LEGACY_KIND_DECLARATIONS[kind];
196
+ if (direct !== void 0) {
197
+ const format = direct.format ?? mapping?.format ?? kind;
198
+ return format === void 0 ? direct : Object.freeze({
199
+ ...direct,
200
+ format
201
+ });
202
+ }
203
+ const ui = projectUiHints(ownData(field, "ui").value);
204
+ const type = kind === "file" && ui?.multiple !== true ? "unknown" : mapping?.type ?? "unknown";
205
+ const format = ownString(field, "format") ?? mapping?.format ?? kind;
206
+ const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
207
+ const meta = ownData(field, "meta");
208
+ const texts = ownData(field, "texts");
209
+ const options = kind === "enum" ? enumValueOptions(field) : void 0;
210
+ const required = ownData(field, "required");
211
+ const nullable = ownData(field, "nullable");
212
+ const opts = ownData(field, "opts").value;
213
+ const optionRequired = ownData(opts, "required");
214
+ const optionNullable = ownData(opts, "nullable");
215
+ const requiredValue = required.present ? required.value : optionRequired.value;
216
+ const nullableValue = nullable.present ? nullable.value : optionNullable.value;
217
+ return Object.freeze({
218
+ type,
219
+ ...format === void 0 ? {} : { format },
220
+ ...items === void 0 ? {} : { items },
221
+ ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
222
+ ...options === void 0 ? {} : { options },
223
+ ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
224
+ ...requiredValue === true ? { required: true } : {},
225
+ ...nullableValue === true ? { nullable: true } : {}
226
+ });
227
+ }
228
+ function lowerLegacyFieldSource(field) {
229
+ const declaration = lowerLegacyField(field);
230
+ const ui = projectUiHints(ownData(field, "ui").value);
231
+ if (ui === void 0) return declaration;
232
+ return Object.freeze({
233
+ ...declaration,
234
+ ui
235
+ });
236
+ }
237
+ function fieldDescription(field) {
238
+ const declaration = field?.declaration;
239
+ return declaredText("field", declaration, "description") ?? declaredText("field", field, "description");
240
+ }
241
+ //#endregion
242
+ //#region src/fields/resolved-field.tsx
243
+ const EMPTY = Object.freeze({});
244
+ const EMPTY_ISSUES = Object.freeze([]);
245
+ const EMPTY_OPTIONS = Object.freeze([]);
246
+ function canonical(field) {
247
+ return lowerLegacyField(field);
248
+ }
249
+ function useLoweredField(source) {
250
+ return useMemo(() => {
251
+ const sourceAtEdge = lowerLegacyFieldSource(source);
252
+ return {
253
+ sourceAtEdge,
254
+ field: canonical(sourceAtEdge),
255
+ ui: sourceAtEdge.ui ?? EMPTY
256
+ };
257
+ }, [source]);
258
+ }
259
+ const warnedObjectLabels = new Set();
260
+ function optionsFor(field, name) {
261
+ if (Array.isArray(field.options)) return field.options;
262
+ const candidate = field.meta?.options;
263
+ if (!Array.isArray(candidate)) return EMPTY_OPTIONS;
264
+ const output = [];
265
+ for (const item of candidate) {
266
+ if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
267
+ const raw = item;
268
+ if (typeof raw.value !== "string" && typeof raw.value !== "number" && typeof raw.value !== "boolean" && raw.value !== null) continue;
269
+ const { value, label, description, ...legacyMeta } = raw;
270
+ if (typeof label !== "string" && process.env.NODE_ENV !== "production" && !warnedObjectLabels.has(`${name}:${value}`)) {
271
+ warnedObjectLabels.add(`${name}:${value}`);
272
+ console.warn(`[buro/ui-shadcn] field '${name}': option '${value}' has a non-string label, so it renders its raw value. Declare a plain string label and put the translations under fields.${name}.options.${value} (see docs/i18n-guide.md).`);
273
+ }
274
+ output.push(Object.freeze({
275
+ value,
276
+ label: typeof label === "string" ? label : String(value),
277
+ ...typeof description === "string" ? { description } : {},
278
+ ...Object.keys(legacyMeta).length === 0 ? {} : { meta: Object.freeze(legacyMeta) }
279
+ }));
280
+ }
281
+ return Object.freeze(output);
282
+ }
283
+ function useContextOptions(field, name, meta, ui, resource) {
284
+ const legacy = field.meta?.options;
285
+ const options = useMemo(() => optionsFor(field, name), [
286
+ field.options,
287
+ legacy,
288
+ name
289
+ ]);
290
+ return useResolvedFieldOptions({
291
+ name,
292
+ meta,
293
+ ui,
294
+ texts: field.texts
295
+ }, options, resource.id);
296
+ }
297
+ function useContextTexts(field, name, resolved, resource) {
298
+ return useImplementationTexts({
299
+ fieldName: name,
300
+ fieldTexts: field.texts,
301
+ id: resolved.id,
302
+ implementation: resolved.implementation
303
+ }, resource.id);
304
+ }
305
+ function useFieldRuntimeContext(resource, record, values, metaSources) {
306
+ const locale = useLocale();
307
+ const caps = useI18nCaps(canonicalResourceKey(resource));
308
+ const metaSourcesOut = useFieldMetaSources({
309
+ record,
310
+ values,
311
+ extra: metaSources
312
+ });
313
+ const scopeState = metaSourcesOut.scope;
314
+ const scope = scopeState === void 0 ? void 0 : scopeValueOf(scopeState);
315
+ return useMemo(() => Object.freeze({
316
+ i18n: Object.freeze({
317
+ locale,
318
+ has: caps.has,
319
+ t: caps.t
320
+ }),
321
+ sources: Object.freeze({
322
+ record: record ?? EMPTY,
323
+ values: values ?? EMPTY,
324
+ scope: scope ?? EMPTY
325
+ }),
326
+ metaSources: metaSourcesOut
327
+ }), [
328
+ caps,
329
+ locale,
330
+ record,
331
+ scope,
332
+ values,
333
+ metaSourcesOut
334
+ ]);
335
+ }
336
+ function useFieldMetaDiagnostic(state, resource, name, field, surface, entry) {
337
+ const reported = useRef(void 0);
338
+ const reason = state.status === "failed" ? state.reason : void 0;
339
+ useEffect(() => {
340
+ if (reason === void 0 || reported.current === reason || process.env.NODE_ENV === "production") return;
341
+ reported.current = reason;
342
+ const implementation = resolveSurfaceUi(field, surface, entry).use ?? field.format ?? field.type;
343
+ console.error(`[burojs] field.meta-invalid: ${formatEntityRef(resource)}.${name} (${implementation}): ${reason}`);
344
+ }, [
345
+ reason,
346
+ resource,
347
+ name,
348
+ field,
349
+ surface,
350
+ entry
351
+ ]);
352
+ }
353
+ function MetaPlaceholder({ state }) {
354
+ const t = useOptionalT();
355
+ if (state.status === "pending") return jsx(Skeleton, {
356
+ "data-buro-skeleton": "",
357
+ "data-buro-field-meta": "pending",
358
+ className: "h-9 w-full"
359
+ });
360
+ return jsx("div", {
361
+ role: "alert",
362
+ "data-buro-field-meta": "failed",
363
+ className: "rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
364
+ children: t("field.misconfigured", { defaultValue: "This field is misconfigured" })
365
+ });
366
+ }
367
+ function useFieldImplementationDiagnostic(diagnostic) {
368
+ const reported = useRef(void 0);
369
+ useEffect(() => {
370
+ if (diagnostic === void 0 || reported.current === diagnostic || process.env.NODE_ENV === "production") return;
371
+ reported.current = diagnostic;
372
+ console.warn("[buro/ui-shadcn] missing-field-implementation; rendering fallback.", diagnostic);
373
+ }, [diagnostic]);
374
+ }
375
+ function ResolvedFieldDisplay({ resource, name, field: source, value, record, testId, fallback, presentation, metaSources, uiSurface = "display", columnEntry }) {
376
+ const { sourceAtEdge, field, ui } = useLoweredField(source);
377
+ const surfaceField = useMemo(() => sourceAtEdge.ui === void 0 ? field : Object.freeze({
378
+ ...field,
379
+ ui
380
+ }), [
381
+ sourceAtEdge,
382
+ field,
383
+ ui
384
+ ]);
385
+ const resolved = useFieldImplementation({
386
+ field: surfaceField,
387
+ surface: "display",
388
+ uiSurface,
389
+ ...columnEntry === void 0 ? {} : { uiEntry: columnEntry }
390
+ });
391
+ const runtimeContext = useFieldRuntimeContext(resource, record, record, metaSources);
392
+ const metaState = useFieldMeta(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
393
+ const textField = useMemo(() => Object.freeze({
394
+ ...surfaceField,
395
+ name
396
+ }), [surfaceField, name]);
397
+ const text = useFieldDisplayText(textField, value, {
398
+ surface: uiSurface,
399
+ ...columnEntry === void 0 ? {} : { entry: columnEntry },
400
+ resource: canonicalResourceKey(resource)
401
+ });
402
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
403
+ const texts = useContextTexts(field, name, resolved, resource);
404
+ useFieldMetaDiagnostic(metaState, resource, name, surfaceField, uiSurface, columnEntry);
405
+ useFieldImplementationDiagnostic(resolved.diagnostic);
406
+ if (resolved.Component === void 0) return jsx(Fragment$1, { children: fallback });
407
+ if (metaState.status !== "ready") return jsx(MetaPlaceholder, { state: metaState });
408
+ const Component = resolved.Component;
409
+ const context = {
410
+ owner: resource,
411
+ resource,
412
+ field,
413
+ path: Object.freeze([name]),
414
+ surface: "display",
415
+ presentation: presentation ?? "default",
416
+ record,
417
+ meta: metaState.meta,
418
+ ui,
419
+ options,
420
+ texts,
421
+ ...text === void 0 ? {} : { text },
422
+ i18n: runtimeContext.i18n,
423
+ sources: runtimeContext.sources,
424
+ pending: false,
425
+ touched: false,
426
+ issues: EMPTY_ISSUES,
427
+ accessibility: EMPTY,
428
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ display: testId })
429
+ };
430
+ if (resolved.multiple) return createElement(Component, {
431
+ ...context,
432
+ multiple: true,
433
+ value: Array.isArray(value) ? value : []
434
+ });
435
+ return createElement(Component, {
436
+ ...context,
437
+ multiple: false,
438
+ value
439
+ });
440
+ }
441
+ function ResolvedFieldInput({ resource, name, field: source, value, record, form, testId, inputId, onChange, onBlur, disabled, required, placeholder, descriptionId, labelId, errorId, errorMessage, pending = false, touched = errorMessage != null, issues: suppliedIssues, relationSeeds, fixedFilters, link, metaSources, fallback }) {
442
+ const { sourceAtEdge, field: base } = useLoweredField(source);
443
+ const field = useMemo(() => required === void 0 || required === base.required ? base : Object.freeze({
444
+ ...base,
445
+ required
446
+ }), [base, required]);
447
+ const ui = useMemo(() => Object.freeze({
448
+ ...sourceAtEdge.ui ?? EMPTY,
449
+ ...placeholder === void 0 ? {} : { placeholder }
450
+ }), [sourceAtEdge, placeholder]);
451
+ const inputField = useMemo(() => ({
452
+ ...field,
453
+ ui
454
+ }), [field, ui]);
455
+ const resolved = useFieldImplementation({
456
+ field: inputField,
457
+ surface: "input"
458
+ });
459
+ const runtimeContext = useFieldRuntimeContext(resource, record, form, metaSources);
460
+ const metaState = useFieldMeta(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
461
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
462
+ const texts = useContextTexts(field, name, resolved, resource);
463
+ useFieldMetaDiagnostic(metaState, resource, name, inputField, "input");
464
+ useFieldImplementationDiagnostic(resolved.diagnostic);
465
+ if (resolved.Component === void 0) return jsx(Fragment$1, { children: fallback });
466
+ if (metaState.status !== "ready") return jsx(MetaPlaceholder, { state: metaState });
467
+ const Component = resolved.Component;
468
+ const issues = suppliedIssues ?? (errorMessage == null ? EMPTY_ISSUES : Object.freeze([Object.freeze({
469
+ code: "ui.field-error",
470
+ message: {
471
+ key: "ui.field-error",
472
+ default: errorMessage
473
+ },
474
+ path: Object.freeze([]),
475
+ source: "field",
476
+ severity: "error"
477
+ })]));
478
+ const context = {
479
+ owner: resource,
480
+ resource,
481
+ field,
482
+ path: Object.freeze([name]),
483
+ surface: "input",
484
+ presentation: "default",
485
+ record,
486
+ form,
487
+ meta: metaState.meta,
488
+ ui,
489
+ options,
490
+ texts,
491
+ i18n: runtimeContext.i18n,
492
+ sources: runtimeContext.sources,
493
+ pending,
494
+ touched,
495
+ issues,
496
+ accessibility: Object.freeze({
497
+ input: inputId ?? name,
498
+ label: labelId,
499
+ description: descriptionId,
500
+ error: errorId
501
+ }),
502
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ input: testId })
503
+ };
504
+ if (resolved.multiple) return createElement(Component, {
505
+ ...context,
506
+ multiple: true,
507
+ value: Array.isArray(value) ? value : [],
508
+ onChange,
509
+ onBlur,
510
+ disabled,
511
+ relationSeeds,
512
+ fixedFilters,
513
+ link,
514
+ metaSources: runtimeContext.metaSources
515
+ });
516
+ return createElement(Component, {
517
+ ...context,
518
+ multiple: false,
519
+ value,
520
+ onChange,
521
+ onBlur,
522
+ disabled,
523
+ relationSeeds,
524
+ fixedFilters,
525
+ link,
526
+ metaSources: runtimeContext.metaSources
527
+ });
528
+ }
529
+ //#endregion
30
530
  //#region src/primitives/badge.tsx
31
531
  const badgeVariants = cva("inline-flex max-w-full items-center truncate rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2", {
32
532
  variants: { variant: {
@@ -104,11 +604,11 @@ const SelectGroup = SelectPrimitive.Group;
104
604
  const SelectValue = SelectPrimitive.Value;
105
605
  const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => jsxs(SelectPrimitive.Trigger, {
106
606
  ref,
107
- className: cn("flex h-9 w-full items-center justify-between rounded-md border border-input bg-background text-foreground px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-input-disabled [&>span]:line-clamp-1", className),
607
+ className: cn("flex h-9 w-full items-center justify-between rounded-md border border-input bg-background text-foreground px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-input-disabled [&>span]:block [&>span]:truncate [&>span]:min-w-0 [&>span]:max-h-[1lh] [&>span]:overflow-hidden [&>span]:text-left", className),
108
608
  ...props,
109
609
  children: [children, jsx(SelectPrimitive.Icon, {
110
610
  asChild: true,
111
- children: jsx(IconChevronDown, { className: "h-4 w-4 opacity-50" })
611
+ children: jsx(IconChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
112
612
  })]
113
613
  }));
114
614
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
@@ -147,15 +647,24 @@ const SelectLabel = React.forwardRef(({ className, ...props }, ref) => jsx(Selec
147
647
  ...props
148
648
  }));
149
649
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
150
- const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => jsxs(SelectPrimitive.Item, {
151
- ref,
152
- className: cn("relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
153
- ...props,
154
- children: [jsx("span", {
155
- className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
156
- children: jsx(SelectPrimitive.ItemIndicator, { children: jsx(IconCheck, { className: "h-4 w-4" }) })
157
- }), jsx(SelectPrimitive.ItemText, { children })]
158
- }));
650
+ const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => {
651
+ const hasDescription = description !== void 0 && description !== null;
652
+ return jsxs(SelectPrimitive.Item, {
653
+ ref,
654
+ className: cn("relative flex w-full cursor-default select-none rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", hasDescription ? "items-start" : "items-center", className),
655
+ ...props,
656
+ children: [jsx("span", {
657
+ className: cn("absolute left-2 flex h-3.5 w-3.5 items-center justify-center", hasDescription && "top-[9px]"),
658
+ children: jsx(SelectPrimitive.ItemIndicator, { children: jsx(IconCheck, { className: "h-4 w-4" }) })
659
+ }), !hasDescription ? jsx(SelectPrimitive.ItemText, { children }) : jsxs("span", {
660
+ className: "flex min-w-0 flex-col gap-0.5",
661
+ children: [jsx(SelectPrimitive.ItemText, { children }), jsx("span", {
662
+ className: "text-xs leading-snug text-muted-foreground",
663
+ children: description
664
+ })]
665
+ })]
666
+ });
667
+ });
159
668
  SelectItem.displayName = SelectPrimitive.Item.displayName;
160
669
  const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => jsx(SelectPrimitive.Separator, {
161
670
  ref,
@@ -208,9 +717,9 @@ function formatNumber(n, locale) {
208
717
  //#endregion
209
718
  //#region src/list-kit/filter-builder/describe-row.ts
210
719
  const MAX_DESCRIBE_DEPTH = 2;
211
- function describeValue(value, t, spec, formatValue) {
720
+ function describeValue(value, chromeT, spec, formatValue) {
212
721
  if (value === void 0) return null;
213
- if (Array.isArray(value)) return t("filters.selectedCount", { count: value.length }, `${value.length} selected`);
722
+ if (Array.isArray(value)) return chromeT("filters.selectedCount", { count: value.length }, `${value.length} selected`);
214
723
  const optionLabel = spec?.options?.find((o) => o.value === String(value))?.label;
215
724
  if (optionLabel !== void 0) return optionLabel;
216
725
  if (spec && formatValue) {
@@ -219,20 +728,20 @@ function describeValue(value, t, spec, formatValue) {
219
728
  }
220
729
  return String(value);
221
730
  }
222
- function describeAt(row, available, t, depth, formatValue) {
731
+ function describeAt(row, available, chromeT, depth, formatValue) {
223
732
  if (isFilterGroup(row)) {
224
733
  if (depth > MAX_DESCRIBE_DEPTH) return "…";
225
- const joinLabel = t(`filters.${row.join}`, void 0, row.join);
226
- return `(${row.rows.map((child) => describeAt(child, available, t, depth + 1, formatValue)).join(` ${joinLabel} `)})`;
734
+ const joinLabel = chromeT(`filters.${row.join}`, void 0, row.join);
735
+ return `(${row.rows.map((child) => describeAt(child, available, chromeT, depth + 1, formatValue)).join(` ${joinLabel} `)})`;
227
736
  }
228
737
  const spec = available.find((s) => s.field === row.field);
229
738
  const label = spec?.label ?? row.field;
230
- const opLabel = t(`filters.operators.${row.op}`, void 0, row.op);
231
- const valueText = opArity(row.op) === "none" ? null : describeValue(row.value, t, spec, formatValue);
739
+ const opLabel = chromeT(`filters.operators.${row.op}`, void 0, row.op);
740
+ const valueText = opArity(row.op) === "none" ? null : describeValue(row.value, chromeT, spec, formatValue);
232
741
  return valueText === null ? `${label} ${opLabel}` : `${label} ${opLabel} ${valueText}`;
233
742
  }
234
- function describeRow(row, available, t, formatValue) {
235
- return describeAt(row, available, t, 1, formatValue);
743
+ function describeRow(row, available, chromeT, formatValue) {
744
+ return describeAt(row, available, chromeT, 1, formatValue);
236
745
  }
237
746
  function relationLabelKey(to, by, value) {
238
747
  return `${by === void 0 ? to : `${to}#${by}`}::${value}`;
@@ -365,15 +874,18 @@ function badgeKey(row, index) {
365
874
  if (isFilterGroup(row)) return `${index}:group:${row.join}`;
366
875
  return `${index}:${row.field}:${row.op}`;
367
876
  }
877
+ const BADGE_ROW = "inline-flex max-w-full items-center gap-1 align-middle";
878
+ const REMOVE_BUTTON = "inline-flex size-4 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-foreground/10 hover:text-foreground focus:outline-hidden focus-visible:ring-2 focus-visible:ring-ring";
368
879
  function FilterBadges(props) {
369
880
  const { group, setGroup, available, fixed, testIdBase, onOpenAt, onRemoved, pinnedFields = [], pinnedValue = [], setPinnedValue } = props;
370
- const t = useOptionalT();
371
- const tt = (key, params, fallback) => t(key, {
881
+ const chromeT = useChromeT();
882
+ const locale = useOptionalLocale();
883
+ const tt = (key, params, fallback) => chromeT(key, {
372
884
  params,
373
885
  ...typeof params?.count === "number" ? { count: params.count } : {},
374
886
  defaultValue: fallback
375
887
  });
376
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
888
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
377
889
  const { enumLabels, relationLabels, onEnumResolved, onRelationResolved } = useFormatValueMaps();
378
890
  const formatValue = (kind, value) => {
379
891
  if (kind.kind === "enum") return enumLabels[kind.enumName]?.[String(value)];
@@ -381,7 +893,7 @@ function FilterBadges(props) {
381
893
  if (kind.kind === "date") {
382
894
  const d = new Date(String(value));
383
895
  if (Number.isNaN(d.getTime())) return void 0;
384
- return kind.time ? formatDateTime(d) : formatDate(d);
896
+ return kind.time ? formatDateTime(d, locale) : formatDate(d, locale);
385
897
  }
386
898
  };
387
899
  const orphanPinned = useMemo(() => {
@@ -415,49 +927,56 @@ function FilterBadges(props) {
415
927
  onEnumResolved,
416
928
  onRelationResolved
417
929
  }),
418
- group.rows.map((row, index) => jsxs(Badge, {
930
+ group.rows.map((row, index) => jsx(Badge, {
419
931
  variant: "secondary",
420
- className: "gap-1 py-1 pr-1",
421
- children: [jsx("button", {
422
- type: "button",
423
- "data-testid": `${testIdBase}:badge:${index}`,
424
- onClick: () => onOpenAt([index]),
425
- className: "max-w-full cursor-pointer truncate bg-transparent p-0 text-left",
426
- children: describeRow(row, available, tt, formatValue)
427
- }), jsx("button", {
428
- type: "button",
429
- "data-testid": `${testIdBase}:badge:${index}:remove`,
430
- "aria-label": removeLabel,
431
- onClick: () => handleRemove(index),
432
- className: "rounded-sm hover:bg-accent",
433
- children: jsx(IconX, {
434
- className: "h-3 w-3",
435
- "aria-hidden": "true"
436
- })
437
- })]
932
+ className: "py-1 pr-1",
933
+ children: jsxs("span", {
934
+ className: BADGE_ROW,
935
+ children: [jsx("button", {
936
+ type: "button",
937
+ "data-testid": `${testIdBase}:badge:${index}`,
938
+ onClick: () => onOpenAt([index]),
939
+ className: "min-w-0 cursor-pointer truncate bg-transparent p-0 text-left",
940
+ children: describeRow(row, available, tt, formatValue)
941
+ }), jsx("button", {
942
+ type: "button",
943
+ "data-testid": `${testIdBase}:badge:${index}:remove`,
944
+ "aria-label": removeLabel,
945
+ onClick: () => handleRemove(index),
946
+ className: REMOVE_BUTTON,
947
+ children: jsx(IconX, {
948
+ className: "size-3",
949
+ "aria-hidden": "true"
950
+ })
951
+ })]
952
+ })
438
953
  }, badgeKey(row, index))),
439
954
  labelledFixed.map((entry, index) => jsx(Badge, {
440
955
  variant: "outline",
441
956
  "data-testid": `${testIdBase}:badge:fixed:${index}`,
442
957
  children: entry.label
443
958
  }, `fixed-${index}`)),
444
- orphanPinned.map(({ expr, index }) => jsxs(Badge, {
959
+ orphanPinned.map(({ expr, index }) => jsx(Badge, {
445
960
  variant: "secondary",
446
- className: "gap-1 py-1",
447
- children: [jsx("span", {
448
- "data-testid": `${testIdBase}:badge:pinned:${index}`,
449
- children: describeRow(expr, available, tt, formatValue)
450
- }), jsx("button", {
451
- type: "button",
452
- "data-testid": `${testIdBase}:badge:pinned:${index}:remove`,
453
- "aria-label": removeLabel,
454
- onClick: () => handleRemovePinned(index),
455
- className: "rounded-sm hover:bg-accent",
456
- children: jsx(IconX, {
457
- className: "h-3 w-3",
458
- "aria-hidden": "true"
459
- })
460
- })]
961
+ className: "py-1 pr-1",
962
+ children: jsxs("span", {
963
+ className: BADGE_ROW,
964
+ children: [jsx("span", {
965
+ "data-testid": `${testIdBase}:badge:pinned:${index}`,
966
+ className: "min-w-0 truncate",
967
+ children: describeRow(expr, available, tt, formatValue)
968
+ }), jsx("button", {
969
+ type: "button",
970
+ "data-testid": `${testIdBase}:badge:pinned:${index}:remove`,
971
+ "aria-label": removeLabel,
972
+ onClick: () => handleRemovePinned(index),
973
+ className: REMOVE_BUTTON,
974
+ children: jsx(IconX, {
975
+ className: "size-3",
976
+ "aria-hidden": "true"
977
+ })
978
+ })]
979
+ })
461
980
  }, `pinned-${index}`))
462
981
  ]
463
982
  });
@@ -647,14 +1166,15 @@ const OPTIONS = ["true", "false"];
647
1166
  function BooleanValueControl(props) {
648
1167
  const { value, onChange, testId, arity, autoFocus, fieldLabel, fill } = props;
649
1168
  const t = useOptionalT();
650
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1169
+ const chromeT = useChromeT();
1170
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
651
1171
  defaultValue: `Value for ${fieldLabel}`,
652
1172
  params: { field: fieldLabel }
653
- }) : t("filters.value", { defaultValue: "Value" });
1173
+ }) : chromeT("filters.value", { defaultValue: "Value" });
654
1174
  const yesLabel = t("boolean.yes", { defaultValue: "Yes" });
655
1175
  const noLabel = t("boolean.no", { defaultValue: "No" });
656
1176
  const labelOf = (token) => token === "true" ? yesLabel : noLabel;
657
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1177
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
658
1178
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
659
1179
  value,
660
1180
  arity,
@@ -674,7 +1194,7 @@ function BooleanValueControl(props) {
674
1194
  "data-testid": testId,
675
1195
  "aria-label": ariaLabel,
676
1196
  className: cn("h-8 justify-between", fill && "w-full"),
677
- children: triggerLabel(labelOf, ariaLabel)
1197
+ children: triggerLabel(labelOf, props.placeholder ?? ariaLabel)
678
1198
  })
679
1199
  }), jsx(PopoverContent, {
680
1200
  className: "w-[140px] p-0",
@@ -707,12 +1227,13 @@ function BooleanValueControl(props) {
707
1227
  function SelectListValueControl(props) {
708
1228
  const { options, value, onChange, testId, arity, autoFocus, fieldLabel, isLoading = false } = props;
709
1229
  const t = useOptionalT();
710
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1230
+ const chromeT = useChromeT();
1231
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
711
1232
  defaultValue: `Value for ${fieldLabel}`,
712
1233
  params: { field: fieldLabel }
713
- }) : t("filters.value", { defaultValue: "Value" });
1234
+ }) : chromeT("filters.value", { defaultValue: "Value" });
714
1235
  const loadingLabel = t("table.loading", { defaultValue: "Loading…" });
715
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1236
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
716
1237
  const labelFor = props.labelFor ?? ((raw) => options.find((o) => o.value === raw)?.label ?? raw);
717
1238
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
718
1239
  value,
@@ -734,7 +1255,7 @@ function SelectListValueControl(props) {
734
1255
  className: cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[200px]"),
735
1256
  children: jsx("span", {
736
1257
  className: "truncate",
737
- children: isLoading ? loadingLabel : triggerLabel(labelFor, ariaLabel)
1258
+ children: isLoading ? loadingLabel : triggerLabel(labelFor, props.placeholder ?? ariaLabel)
738
1259
  })
739
1260
  })
740
1261
  }), jsx(PopoverContent, {
@@ -797,6 +1318,7 @@ function EnumValueControl(props) {
797
1318
  arity,
798
1319
  autoFocus,
799
1320
  fieldLabel,
1321
+ placeholder: props.placeholder,
800
1322
  options,
801
1323
  labelFor,
802
1324
  isLoading,
@@ -843,6 +1365,7 @@ function RelationValueControl(props) {
843
1365
  const { to, by, value, onChange, testId, arity, autoFocus, fieldLabel } = props;
844
1366
  const app = useApp();
845
1367
  const t = useOptionalT();
1368
+ const chromeT = useChromeT();
846
1369
  const targetDef = app.registry.get(to);
847
1370
  const displayField = targetDef?.displayField ?? "name";
848
1371
  const [search, setSearch] = useState("");
@@ -881,11 +1404,11 @@ function RelationValueControl(props) {
881
1404
  if (fromRows) return rowTitle(fromRows);
882
1405
  return fallbackLabels[id] ?? id;
883
1406
  };
884
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1407
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
885
1408
  defaultValue: `Value for ${fieldLabel}`,
886
1409
  params: { field: fieldLabel }
887
- }) : t("filters.value", { defaultValue: "Value" });
888
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1410
+ }) : chromeT("filters.value", { defaultValue: "Value" });
1411
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
889
1412
  return jsxs(Popover, {
890
1413
  open,
891
1414
  onOpenChange: setOpen,
@@ -901,7 +1424,7 @@ function RelationValueControl(props) {
901
1424
  className: cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[220px]"),
902
1425
  children: jsx("span", {
903
1426
  className: "truncate",
904
- children: triggerLabel(labelFor, ariaLabel)
1427
+ children: triggerLabel(labelFor, props.placeholder ?? ariaLabel)
905
1428
  })
906
1429
  })
907
1430
  }), jsx(PopoverContent, {
@@ -957,6 +1480,20 @@ function RelationValueControl(props) {
957
1480
  });
958
1481
  }
959
1482
  //#endregion
1483
+ //#region src/fields/local-date-time.ts
1484
+ function toLocalDateTimeText(value) {
1485
+ if (value === void 0 || value === null || value === "") return "";
1486
+ const d = value instanceof Date ? value : new Date(String(value));
1487
+ if (Number.isNaN(d.getTime())) return "";
1488
+ const pad = (n) => String(n).padStart(2, "0");
1489
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
1490
+ }
1491
+ function fromLocalDateTimeText(text) {
1492
+ if (text === "") return void 0;
1493
+ const d = new Date(text);
1494
+ return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
1495
+ }
1496
+ //#endregion
960
1497
  //#region src/list-kit/filter-builder/values/scalar-value-input.tsx
961
1498
  function isDateTime(kind) {
962
1499
  return kind.kind === "date" && kind.time === true;
@@ -969,12 +1506,9 @@ function inputTypeFor(kind) {
969
1506
  }
970
1507
  }
971
1508
  function toText(kind, value) {
1509
+ if (isDateTime(kind)) return toLocalDateTimeText(value);
972
1510
  if (value === void 0 || value === null || value === "") return "";
973
- if (!isDateTime(kind)) return String(value);
974
- const d = new Date(String(value));
975
- if (Number.isNaN(d.getTime())) return "";
976
- const pad = (n) => String(n).padStart(2, "0");
977
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
1511
+ return String(value);
978
1512
  }
979
1513
  function parseOne(kind, raw) {
980
1514
  if (raw === "") return void 0;
@@ -982,19 +1516,16 @@ function parseOne(kind, raw) {
982
1516
  const n = Number(raw);
983
1517
  return Number.isFinite(n) ? n : void 0;
984
1518
  }
985
- if (isDateTime(kind)) {
986
- const d = new Date(raw);
987
- return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
988
- }
1519
+ if (isDateTime(kind)) return fromLocalDateTimeText(raw);
989
1520
  return raw;
990
1521
  }
991
1522
  function ScalarValueInput(props) {
992
- const t = useOptionalT();
1523
+ const chromeT = useChromeT();
993
1524
  const inputType = inputTypeFor(props.kind);
994
- const ariaLabel = props.fieldLabel ? t("filters.valueFor", {
1525
+ const ariaLabel = props.fieldLabel ? chromeT("filters.valueFor", {
995
1526
  defaultValue: `Value for ${props.fieldLabel}`,
996
1527
  params: { field: props.fieldLabel }
997
- }) : t("filters.value", { defaultValue: "Value" });
1528
+ }) : chromeT("filters.value", { defaultValue: "Value" });
998
1529
  if (props.arity === "multi") return jsx(ScalarMultiInput, {
999
1530
  ...props,
1000
1531
  inputType,
@@ -1124,6 +1655,7 @@ function FilterValueControl(props) {
1124
1655
  arity,
1125
1656
  autoFocus: props.autoFocus,
1126
1657
  fieldLabel: props.fieldLabel,
1658
+ placeholder: props.placeholder,
1127
1659
  options: props.options,
1128
1660
  fill: props.fill
1129
1661
  });
@@ -1140,6 +1672,7 @@ function FilterValueControl(props) {
1140
1672
  arity,
1141
1673
  autoFocus: props.autoFocus,
1142
1674
  fieldLabel: props.fieldLabel,
1675
+ placeholder: props.placeholder,
1143
1676
  options: props.kind.values.map((entry) => ({
1144
1677
  value: entry,
1145
1678
  label: entry
@@ -1168,10 +1701,10 @@ const FIELD_CLASS = "h-8 min-w-0 shrink basis-40";
1168
1701
  const OPERATOR_CLASS = "h-8 min-w-0 shrink basis-[9.5rem]";
1169
1702
  function FilterRow(props) {
1170
1703
  const { row, path, available, onPatch, onRemove, testIdBase, debounceMs } = props;
1171
- const t = useOptionalT();
1704
+ const chromeT = useChromeT();
1172
1705
  const base = `${testIdBase}:row:${path.join("-")}`;
1173
1706
  const spec = available.find((s) => s.field === row.field);
1174
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
1707
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
1175
1708
  if (!spec) return jsxs("div", {
1176
1709
  className: ROW_CLASS,
1177
1710
  children: [
@@ -1211,8 +1744,8 @@ function FilterRow(props) {
1211
1744
  };
1212
1745
  const handleOpChange = (op) => onPatch(path, { op });
1213
1746
  const handleValueChange = (value) => onPatch(path, { value });
1214
- const fieldAriaLabel = t("filters.field", { defaultValue: "Field" });
1215
- const operatorAriaLabel = t("filters.operator", { defaultValue: "Operator" });
1747
+ const fieldAriaLabel = chromeT("filters.field", { defaultValue: "Field" });
1748
+ const operatorAriaLabel = chromeT("filters.operator", { defaultValue: "Operator" });
1216
1749
  return jsxs("div", {
1217
1750
  className: ROW_CLASS,
1218
1751
  children: [
@@ -1241,7 +1774,7 @@ function FilterRow(props) {
1241
1774
  }), jsx(SelectContent, { children: spec.operators.map((op) => jsx(SelectItem, {
1242
1775
  value: op,
1243
1776
  "data-testid": `${opTestId}:option:${op}`,
1244
- children: t(`filters.operators.${op}`, { defaultValue: op })
1777
+ children: chromeT(`filters.operators.${op}`, { defaultValue: op })
1245
1778
  }, op)) })]
1246
1779
  }),
1247
1780
  jsx("div", {
@@ -1289,10 +1822,10 @@ function FilterGroupEditor(props) {
1289
1822
  }
1290
1823
  function GroupEditorInner(props) {
1291
1824
  const { group, path, available, onChange, testIdBase, onRemove, addGroupAt, debounceMs } = props;
1292
- const t = useOptionalT();
1825
+ const chromeT = useChromeT();
1293
1826
  const base = `${testIdBase}:group:${path.join("-")}`;
1294
1827
  const canNestGroup = depthOf(path) < 3;
1295
- const joinLabel = (join) => t(`filters.${join}`, { defaultValue: join });
1828
+ const joinLabel = (join) => chromeT(`filters.${join}`, { defaultValue: join });
1296
1829
  const handlePatch = (rowPath, patch) => {
1297
1830
  const index = rowPath[rowPath.length - 1];
1298
1831
  if (index === void 0) return;
@@ -1325,11 +1858,11 @@ function GroupEditorInner(props) {
1325
1858
  return jsxs(Fragment, { children: [jsxs("div", {
1326
1859
  className: CONNECTOR_CLASS,
1327
1860
  children: [
1328
- index === 0 && t("filters.where", { defaultValue: "Where" }),
1861
+ index === 0 && chromeT("filters.where", { defaultValue: "Where" }),
1329
1862
  index === 1 && jsx("button", {
1330
1863
  type: "button",
1331
1864
  "data-testid": `${base}:join`,
1332
- "aria-label": t("filters.toggleJoin", {
1865
+ "aria-label": chromeT("filters.toggleJoin", {
1333
1866
  defaultValue: `Join: ${joinLabel(group.join)} — activate to switch to ${joinLabel(otherJoin)}`,
1334
1867
  params: {
1335
1868
  current: joinLabel(group.join),
@@ -1381,7 +1914,7 @@ function GroupEditorInner(props) {
1381
1914
  children: [jsx(IconPlus, {
1382
1915
  className: "h-4 w-4",
1383
1916
  "aria-hidden": "true"
1384
- }), t("filters.addRow", { defaultValue: "Add filter" })]
1917
+ }), chromeT("filters.addRow", { defaultValue: "Add filter" })]
1385
1918
  }),
1386
1919
  canNestGroup && jsxs(Button, {
1387
1920
  type: "button",
@@ -1392,7 +1925,7 @@ function GroupEditorInner(props) {
1392
1925
  children: [jsx(IconFolderPlus, {
1393
1926
  className: "h-4 w-4",
1394
1927
  "aria-hidden": "true"
1395
- }), t("filters.addGroup", { defaultValue: "Add group" })]
1928
+ }), chromeT("filters.addGroup", { defaultValue: "Add group" })]
1396
1929
  }),
1397
1930
  onRemove && jsxs(Button, {
1398
1931
  type: "button",
@@ -1403,7 +1936,7 @@ function GroupEditorInner(props) {
1403
1936
  children: [jsx(IconX, {
1404
1937
  className: "h-4 w-4",
1405
1938
  "aria-hidden": "true"
1406
- }), t("filters.removeGroup", { defaultValue: "Remove group" })]
1939
+ }), chromeT("filters.removeGroup", { defaultValue: "Remove group" })]
1407
1940
  })
1408
1941
  ]
1409
1942
  })
@@ -1419,7 +1952,7 @@ function countGroupRows(group) {
1419
1952
  }
1420
1953
  function FilterPanel(props) {
1421
1954
  const { group, setGroup, available, setPage, testIdBase, open, onOpenChange, focusPath, externalRemoval } = props;
1422
- const t = useOptionalT();
1955
+ const chromeT = useChromeT();
1423
1956
  const [draft, setDraft] = useState(() => toDraft(group));
1424
1957
  const wasOpenRef = useRef(open);
1425
1958
  const topLevelIdsRef = useRef([]);
@@ -1471,7 +2004,7 @@ function FilterPanel(props) {
1471
2004
  className: "h-4 w-4",
1472
2005
  "aria-hidden": "true"
1473
2006
  }),
1474
- t("filters.title", { defaultValue: "Filters" }),
2007
+ chromeT("filters.title", { defaultValue: "Filters" }),
1475
2008
  appliedCount > 0 && jsx("span", {
1476
2009
  "data-testid": `${testIdBase}:count`,
1477
2010
  className: "ml-1 rounded-full bg-primary px-1.5 text-xs text-primary-foreground",
@@ -1499,13 +2032,13 @@ function FilterPanel(props) {
1499
2032
  size: "sm",
1500
2033
  "data-testid": `${testIdBase}:reset`,
1501
2034
  onClick: handleReset,
1502
- children: t("filters.reset", { defaultValue: "Reset" })
2035
+ children: chromeT("filters.reset", { defaultValue: "Reset" })
1503
2036
  }), jsx(Button, {
1504
2037
  type: "button",
1505
2038
  size: "sm",
1506
2039
  "data-testid": `${testIdBase}:apply`,
1507
2040
  onClick: handleApply,
1508
- children: t("filters.apply", { defaultValue: "Apply" })
2041
+ children: chromeT("filters.apply", { defaultValue: "Apply" })
1509
2042
  })]
1510
2043
  })]
1511
2044
  })]
@@ -1560,11 +2093,204 @@ function PinnedControl(props) {
1560
2093
  });
1561
2094
  }
1562
2095
  //#endregion
2096
+ //#region src/data-table/data-table-faceted-filter.tsx
2097
+ function DataTableFacetedFilter({ column, getTestId, ...rest }) {
2098
+ const filterValue = column.getFilterValue();
2099
+ return jsx(FacetedFilterPicker, {
2100
+ ...rest,
2101
+ ...getTestId === void 0 ? {} : { getTestId: (role, value) => role === "hint" ? void 0 : getTestId(role, value) },
2102
+ selected: Array.isArray(filterValue) ? filterValue.map(String) : [],
2103
+ onChange: (next) => column.setFilterValue(next.length === 0 ? void 0 : next)
2104
+ });
2105
+ }
2106
+ function FacetedFilterPicker({ title, options = [], loadOptions, selectedLabelFor, searchPlaceholder, emptyText, getTestId, className, selected: selectedList, onChange, hint, emptyLabel, clearable = true }) {
2107
+ const t = useOptionalT();
2108
+ const chromeT = useChromeT();
2109
+ const selected = useMemo(() => new Set(selectedList), [selectedList]);
2110
+ const [search, setSearch] = useState("");
2111
+ const [asyncOptions, setAsyncOptions] = useState([]);
2112
+ const [loading, setLoading] = useState(false);
2113
+ const debounceRef = useRef(null);
2114
+ const loadOptionsRef = useRef(loadOptions);
2115
+ useEffect(() => {
2116
+ loadOptionsRef.current = loadOptions;
2117
+ });
2118
+ useEffect(() => {
2119
+ if (!loadOptionsRef.current) return;
2120
+ setLoading(true);
2121
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2122
+ let cancelled = false;
2123
+ debounceRef.current = setTimeout(() => {
2124
+ const loader = loadOptionsRef.current;
2125
+ if (!loader) return;
2126
+ loader(search).then((results) => {
2127
+ if (!cancelled) {
2128
+ setAsyncOptions(results);
2129
+ setLoading(false);
2130
+ }
2131
+ }).catch(() => {
2132
+ if (!cancelled) setLoading(false);
2133
+ });
2134
+ }, 250);
2135
+ return () => {
2136
+ cancelled = true;
2137
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2138
+ };
2139
+ }, [search]);
2140
+ const effectiveOptions = loadOptions ? asyncOptions : options;
2141
+ const labelFor = (value) => {
2142
+ const opt = effectiveOptions.find((o) => o.value === value);
2143
+ if (opt) return opt.label;
2144
+ return selectedLabelFor?.(value) ?? value;
2145
+ };
2146
+ const toggle = (value) => {
2147
+ const next = new Set(selected);
2148
+ if (next.has(value)) next.delete(value);
2149
+ else next.add(value);
2150
+ onChange(Array.from(next));
2151
+ };
2152
+ const selectedValues = Array.from(selected);
2153
+ return jsxs(Popover, { children: [jsx(PopoverTrigger, {
2154
+ asChild: true,
2155
+ children: jsxs(Button, {
2156
+ type: "button",
2157
+ variant: "outline",
2158
+ size: "sm",
2159
+ "data-testid": getTestId?.("trigger"),
2160
+ title: hint,
2161
+ className: cn("h-8 border-dashed", className),
2162
+ children: [
2163
+ jsx(IconCirclePlus, {
2164
+ className: "mr-2 h-4 w-4",
2165
+ "aria-hidden": "true"
2166
+ }),
2167
+ title,
2168
+ selected.size === 0 && emptyLabel !== void 0 && jsxs(Fragment$1, { children: [jsx("span", {
2169
+ className: "mx-2 h-4 w-px bg-border",
2170
+ "aria-hidden": "true"
2171
+ }), jsx(Badge, {
2172
+ variant: "secondary",
2173
+ className: "rounded-sm px-1 font-normal",
2174
+ children: emptyLabel
2175
+ })] }),
2176
+ selected.size > 0 && jsxs(Fragment$1, { children: [
2177
+ jsx("span", {
2178
+ className: "mx-2 h-4 w-px bg-border",
2179
+ "aria-hidden": "true"
2180
+ }),
2181
+ jsx(Badge, {
2182
+ variant: "secondary",
2183
+ className: "rounded-sm px-1 font-normal lg:hidden",
2184
+ children: selected.size
2185
+ }),
2186
+ jsx("div", {
2187
+ className: "hidden gap-1 lg:flex",
2188
+ children: selected.size > 2 ? jsx(Badge, {
2189
+ variant: "secondary",
2190
+ className: "rounded-sm px-1 font-normal",
2191
+ children: t("table.selectedCount", {
2192
+ count: selected.size,
2193
+ defaultValue: "{{count}} selected"
2194
+ })
2195
+ }) : selectedValues.map((value) => jsx(Badge, {
2196
+ variant: "secondary",
2197
+ className: "rounded-sm px-1 font-normal",
2198
+ children: labelFor(value)
2199
+ }, value))
2200
+ })
2201
+ ] })
2202
+ ]
2203
+ })
2204
+ }), jsx(PopoverContent, {
2205
+ className: "w-[220px] p-0",
2206
+ align: "start",
2207
+ children: jsxs(Command, {
2208
+ shouldFilter: !loadOptions,
2209
+ children: [
2210
+ hint !== void 0 && jsx("p", {
2211
+ "data-testid": getTestId?.("hint"),
2212
+ className: "border-b px-3 py-2 text-xs text-muted-foreground",
2213
+ children: hint
2214
+ }),
2215
+ jsx(CommandInput, {
2216
+ placeholder: searchPlaceholder ?? title,
2217
+ "data-testid": getTestId?.("search"),
2218
+ ...loadOptions ? {
2219
+ value: search,
2220
+ onValueChange: setSearch
2221
+ } : {}
2222
+ }),
2223
+ jsxs(CommandList, { children: [
2224
+ loading && jsx("div", {
2225
+ className: "py-6 text-center text-sm text-muted-foreground",
2226
+ children: t("list.loadingShort", { defaultValue: "Loading…" })
2227
+ }),
2228
+ jsx(CommandEmpty, { children: emptyText ?? t("relation.noResults", { defaultValue: "No results." }) }),
2229
+ jsx(CommandGroup, { children: effectiveOptions.map((opt) => {
2230
+ const isSelected = selected.has(opt.value);
2231
+ const Icon = opt.icon;
2232
+ return jsxs(CommandItem, {
2233
+ value: opt.label,
2234
+ "data-testid": getTestId?.("option", opt.value),
2235
+ role: "option",
2236
+ "aria-selected": isSelected,
2237
+ "aria-checked": isSelected,
2238
+ onSelect: () => toggle(opt.value),
2239
+ children: [
2240
+ jsx("span", {
2241
+ className: cn("mr-2 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border", isSelected ? "border-primary bg-primary text-primary-foreground" : "border-input opacity-50"),
2242
+ "aria-hidden": "true",
2243
+ children: isSelected && jsx(IconCheck, { className: "h-3.5 w-3.5" })
2244
+ }),
2245
+ Icon && jsx(Icon, {
2246
+ className: "mr-2 h-4 w-4 text-muted-foreground",
2247
+ "aria-hidden": "true"
2248
+ }),
2249
+ jsxs("span", {
2250
+ className: "flex min-w-0 flex-1 flex-col text-left",
2251
+ children: [jsx("span", { children: opt.label }), opt.summary !== void 0 && jsx("span", {
2252
+ className: "text-xs text-muted-foreground",
2253
+ children: opt.summary
2254
+ })]
2255
+ })
2256
+ ]
2257
+ }, opt.value);
2258
+ }) })
2259
+ ] }),
2260
+ clearable && selected.size > 0 && jsx("button", {
2261
+ type: "button",
2262
+ "data-testid": getTestId?.("clear"),
2263
+ onClick: () => onChange([]),
2264
+ className: "flex w-full items-center justify-center border-t px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
2265
+ children: chromeT("filters.clearAll", { defaultValue: "Clear filters" })
2266
+ })
2267
+ ]
2268
+ })
2269
+ })] });
2270
+ }
2271
+ //#endregion
2272
+ //#region src/list-kit/filter-builder/preset-filter-controls.tsx
2273
+ function PresetFilterControls(props) {
2274
+ const { presets, setPreset, testIdBase } = props;
2275
+ return jsx(Fragment$1, { children: presets.map((filter) => jsx(FacetedFilterPicker, {
2276
+ title: filter.label,
2277
+ ...filter.hint === void 0 ? {} : { hint: filter.hint },
2278
+ options: filter.options.map((option) => ({
2279
+ value: option.id,
2280
+ label: option.label,
2281
+ ...option.summary === void 0 ? {} : { summary: option.summary }
2282
+ })),
2283
+ selected: filter.selected,
2284
+ onChange: (next) => setPreset(filter.id, filter.options.map((option) => option.id).filter((id) => next.includes(id))),
2285
+ getTestId: (role, value) => `${testIdBase}:preset:${filter.id}:${role}${value === void 0 ? "" : `:${value}`}`
2286
+ }, filter.id)) });
2287
+ }
2288
+ //#endregion
1563
2289
  //#region src/list-kit/filter-builder/filter-builder.tsx
1564
2290
  const EMPTY_PINNED_FIELDS = Object.freeze([]);
1565
2291
  const EMPTY_PINNED_VALUE = Object.freeze([]);
1566
2292
  function FilterBuilder(props) {
1567
- const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, setPage, testIdBase } = props;
2293
+ const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, presets, setPreset, setPage, testIdBase } = props;
1568
2294
  const [open, setOpen] = useState(false);
1569
2295
  const [focusPath, setFocusPath] = useState(void 0);
1570
2296
  const [externalRemoval, setExternalRemoval] = useState(void 0);
@@ -1581,6 +2307,11 @@ function FilterBuilder(props) {
1581
2307
  setPinnedValue?.(next);
1582
2308
  };
1583
2309
  return jsxs(Fragment$1, { children: [
2310
+ presets !== void 0 && presets.length > 0 && setPreset !== void 0 && jsx(PresetFilterControls, {
2311
+ presets,
2312
+ setPreset,
2313
+ testIdBase
2314
+ }),
1584
2315
  jsx(PinnedFilterControls, {
1585
2316
  pinnedFields,
1586
2317
  value: pinnedValue,
@@ -1616,6 +2347,6 @@ function FilterBuilder(props) {
1616
2347
  ] });
1617
2348
  }
1618
2349
  //#endregion
1619
- export { TableHeader as C, DEFAULT_LANGUAGE_STORAGE_KEY as D, badgeVariants as E, loadLocale as O, TableHead as S, Badge as T, SelectValue as _, FilterBadges as a, TableCaption as b, Select as c, SelectItem as d, SelectLabel as f, SelectTrigger as g, SelectSeparator as h, FilterValueControl as i, saveLocale as k, SelectContent as l, SelectScrollUpButton as m, PinnedFilterControls as n, formatDate as o, SelectScrollDownButton as p, FilterPanel as r, formatNumber as s, FilterBuilder as t, SelectGroup as u, Table as v, TableRow as w, TableCell as x, TableBody as y };
2350
+ export { TableRow as A, loadLocale as B, SelectValue as C, TableCell as D, TableCaption as E, ResolvedFieldInput as F, useFieldMetaDiagnostic as I, fieldDescription as L, badgeVariants as M, MetaPlaceholder as N, TableHead as O, ResolvedFieldDisplay as P, lowerLegacyField as R, SelectTrigger as S, TableBody as T, saveLocale as V, SelectItem as _, PinnedFilterControls as a, SelectScrollUpButton as b, fromLocalDateTimeText as c, formatDate as d, formatDateTime as f, SelectGroup as g, SelectContent as h, FacetedFilterPicker as i, Badge as j, TableHeader as k, toLocalDateTimeText as l, Select as m, PresetFilterControls as n, FilterPanel as o, formatNumber as p, DataTableFacetedFilter as r, FilterValueControl as s, FilterBuilder as t, FilterBadges as u, SelectLabel as v, Table as w, SelectSeparator as x, SelectScrollDownButton as y, DEFAULT_LANGUAGE_STORAGE_KEY as z };
1620
2351
 
1621
- //# sourceMappingURL=filter-builder-Bhn-dhZV.js.map
2352
+ //# sourceMappingURL=filter-builder-DaWHUZuV.js.map