@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,8 +1,9 @@
1
1
  const require_use_theme = require("./use-theme-DFlpXils.cjs");
2
- const require_toaster = require("./toaster-Cr51X7bz.cjs");
2
+ const require_toaster = require("./toaster-BbByOytP.cjs");
3
3
  const require_button = require("./button-BxnnE28H.cjs");
4
4
  const require_input = require("./input-BI0czGyI.cjs");
5
- const require_search_access = require("./search-access-Dugvttlg.cjs");
5
+ const require_relation_create = require("./relation-create-DDEYcKfw.cjs");
6
+ const require_skeleton = require("./skeleton-_1gP7wan.cjs");
6
7
  let _burojs_core = require("@burojs/core");
7
8
  let _burojs_react = require("@burojs/react");
8
9
  let _tabler_icons_react = require("@tabler/icons-react");
@@ -28,6 +29,505 @@ function saveLocale(code, storageKey = _burojs_react.DEFAULT_LANGUAGE_STORAGE_KE
28
29
  } catch {}
29
30
  }
30
31
  //#endregion
32
+ //#region src/fields/legacy-field.ts
33
+ const STRING_ITEM = Object.freeze({ type: "string" });
34
+ const LEGACY_KIND_DECLARATIONS = Object.freeze({
35
+ string: { type: "string" },
36
+ text: {
37
+ type: "string",
38
+ format: "text"
39
+ },
40
+ textarea: {
41
+ type: "string",
42
+ format: "textarea"
43
+ },
44
+ code: {
45
+ type: "string",
46
+ format: "code"
47
+ },
48
+ email: {
49
+ type: "string",
50
+ format: "email"
51
+ },
52
+ url: {
53
+ type: "string",
54
+ format: "url"
55
+ },
56
+ uuid: {
57
+ type: "string",
58
+ format: "uuid"
59
+ },
60
+ number: { type: "number" },
61
+ boolean: { type: "boolean" },
62
+ date: {
63
+ type: "string",
64
+ format: "date"
65
+ },
66
+ dateTime: {
67
+ type: "string",
68
+ format: "date-time"
69
+ },
70
+ enum: {
71
+ type: "string",
72
+ format: "enum"
73
+ },
74
+ json: {
75
+ type: "object",
76
+ format: "json"
77
+ },
78
+ richText: {
79
+ type: "string",
80
+ format: "rich-text"
81
+ },
82
+ file: {
83
+ type: "array",
84
+ format: "file",
85
+ items: STRING_ITEM
86
+ },
87
+ relation: { type: "relation" },
88
+ relationMany: {
89
+ type: "array",
90
+ format: "relation",
91
+ items: STRING_ITEM
92
+ }
93
+ });
94
+ const SEMANTIC_KEYS = Object.freeze([
95
+ "type",
96
+ "format",
97
+ "meta",
98
+ "required",
99
+ "nullable",
100
+ "empty",
101
+ "default",
102
+ "constraints",
103
+ "texts",
104
+ "options",
105
+ "items",
106
+ "properties",
107
+ "additionalProperties",
108
+ "variants"
109
+ ]);
110
+ function ownData(value, key) {
111
+ if (value === null || typeof value !== "object" && typeof value !== "function") return { present: false };
112
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
113
+ if (descriptor === void 0 || !Object.prototype.propertyIsEnumerable.call(value, key) || !("value" in descriptor)) return { present: false };
114
+ return {
115
+ present: true,
116
+ value: descriptor.value
117
+ };
118
+ }
119
+ function ownString(value, key) {
120
+ const candidate = ownData(value, key).value;
121
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
122
+ }
123
+ function ownSelection(value, key) {
124
+ const candidate = ownData(value, key).value;
125
+ if (typeof candidate === "string") return candidate.length > 0 ? candidate : void 0;
126
+ return candidate !== null && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : void 0;
127
+ }
128
+ function projectUiSelection(input) {
129
+ const selection = {};
130
+ const inputId = ownSelection(input, "input");
131
+ const displayId = ownSelection(input, "display");
132
+ if (inputId !== void 0) selection.input = inputId;
133
+ if (displayId !== void 0) selection.display = displayId;
134
+ return inputId === void 0 && displayId === void 0 ? void 0 : Object.freeze(selection);
135
+ }
136
+ function projectFieldDeclaration(input) {
137
+ const type = ownString(input, "type");
138
+ if (type === void 0) return void 0;
139
+ const projected = { type };
140
+ for (const key of SEMANTIC_KEYS) {
141
+ if (key === "type" || key === "items" || key === "properties" || key === "variants") continue;
142
+ const candidate = ownData(input, key);
143
+ if (candidate.present && candidate.value !== void 0) projected[key] = candidate.value;
144
+ }
145
+ const ui = projectUiSelection(ownData(input, "ui").value);
146
+ if (ui !== void 0) projected.ui = ui;
147
+ if (type === "array") {
148
+ const item = projectFieldDeclaration(ownData(input, "items").value);
149
+ if (item !== void 0) projected.items = item;
150
+ }
151
+ if (type === "object") {
152
+ const properties = ownData(input, "properties").value;
153
+ if (properties !== null && typeof properties === "object" && !Array.isArray(properties)) {
154
+ const output = {};
155
+ for (const key of Object.keys(properties)) {
156
+ const child = projectFieldDeclaration(ownData(properties, key).value);
157
+ if (child !== void 0) output[key] = child;
158
+ }
159
+ projected.properties = Object.freeze(output);
160
+ }
161
+ }
162
+ if (type === "union") {
163
+ const variants = ownData(input, "variants").value;
164
+ if (Array.isArray(variants)) {
165
+ const output = [];
166
+ for (let index = 0; index < variants.length; index += 1) {
167
+ const child = projectFieldDeclaration(ownData(variants, index).value);
168
+ if (child !== void 0) output.push(child);
169
+ }
170
+ projected.variants = Object.freeze(output);
171
+ }
172
+ }
173
+ return Object.freeze(projected);
174
+ }
175
+ function projectUiHints(input) {
176
+ if (input === null || typeof input !== "object" || Array.isArray(input)) return void 0;
177
+ const projected = {};
178
+ for (const key of Object.keys(input)) {
179
+ const candidate = ownData(input, key);
180
+ if (candidate.present) projected[key] = candidate.value;
181
+ }
182
+ return Object.freeze(projected);
183
+ }
184
+ function enumValueOptions(field) {
185
+ const own = ownData(field, "values").value;
186
+ const values = Array.isArray(own) ? own : ownData(ownData(field, "ui").value, "values").value;
187
+ if (!Array.isArray(values)) return void 0;
188
+ const options = values.filter((value) => typeof value === "string").map((value) => Object.freeze({ value }));
189
+ return options.length === 0 ? void 0 : Object.freeze(options);
190
+ }
191
+ function lowerLegacyField(field) {
192
+ const declaration = projectFieldDeclaration(ownData(field, "declaration").value);
193
+ if (declaration !== void 0) return declaration;
194
+ const direct = projectFieldDeclaration(field);
195
+ const kind = ownString(field, "kind");
196
+ const mapping = kind === void 0 ? void 0 : LEGACY_KIND_DECLARATIONS[kind];
197
+ if (direct !== void 0) {
198
+ const format = direct.format ?? mapping?.format ?? kind;
199
+ return format === void 0 ? direct : Object.freeze({
200
+ ...direct,
201
+ format
202
+ });
203
+ }
204
+ const ui = projectUiHints(ownData(field, "ui").value);
205
+ const type = kind === "file" && ui?.multiple !== true ? "unknown" : mapping?.type ?? "unknown";
206
+ const format = ownString(field, "format") ?? mapping?.format ?? kind;
207
+ const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
208
+ const meta = ownData(field, "meta");
209
+ const texts = ownData(field, "texts");
210
+ const options = kind === "enum" ? enumValueOptions(field) : void 0;
211
+ const required = ownData(field, "required");
212
+ const nullable = ownData(field, "nullable");
213
+ const opts = ownData(field, "opts").value;
214
+ const optionRequired = ownData(opts, "required");
215
+ const optionNullable = ownData(opts, "nullable");
216
+ const requiredValue = required.present ? required.value : optionRequired.value;
217
+ const nullableValue = nullable.present ? nullable.value : optionNullable.value;
218
+ return Object.freeze({
219
+ type,
220
+ ...format === void 0 ? {} : { format },
221
+ ...items === void 0 ? {} : { items },
222
+ ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
223
+ ...options === void 0 ? {} : { options },
224
+ ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
225
+ ...requiredValue === true ? { required: true } : {},
226
+ ...nullableValue === true ? { nullable: true } : {}
227
+ });
228
+ }
229
+ function lowerLegacyFieldSource(field) {
230
+ const declaration = lowerLegacyField(field);
231
+ const ui = projectUiHints(ownData(field, "ui").value);
232
+ if (ui === void 0) return declaration;
233
+ return Object.freeze({
234
+ ...declaration,
235
+ ui
236
+ });
237
+ }
238
+ function fieldDescription(field) {
239
+ const declaration = field?.declaration;
240
+ return (0, _burojs_core.declaredText)("field", declaration, "description") ?? (0, _burojs_core.declaredText)("field", field, "description");
241
+ }
242
+ //#endregion
243
+ //#region src/fields/resolved-field.tsx
244
+ const EMPTY = Object.freeze({});
245
+ const EMPTY_ISSUES = Object.freeze([]);
246
+ const EMPTY_OPTIONS = Object.freeze([]);
247
+ function canonical(field) {
248
+ return lowerLegacyField(field);
249
+ }
250
+ function useLoweredField(source) {
251
+ return (0, react.useMemo)(() => {
252
+ const sourceAtEdge = lowerLegacyFieldSource(source);
253
+ return {
254
+ sourceAtEdge,
255
+ field: canonical(sourceAtEdge),
256
+ ui: sourceAtEdge.ui ?? EMPTY
257
+ };
258
+ }, [source]);
259
+ }
260
+ const warnedObjectLabels = new Set();
261
+ function optionsFor(field, name) {
262
+ if (Array.isArray(field.options)) return field.options;
263
+ const candidate = field.meta?.options;
264
+ if (!Array.isArray(candidate)) return EMPTY_OPTIONS;
265
+ const output = [];
266
+ for (const item of candidate) {
267
+ if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
268
+ const raw = item;
269
+ if (typeof raw.value !== "string" && typeof raw.value !== "number" && typeof raw.value !== "boolean" && raw.value !== null) continue;
270
+ const { value, label, description, ...legacyMeta } = raw;
271
+ if (typeof label !== "string" && process.env.NODE_ENV !== "production" && !warnedObjectLabels.has(`${name}:${value}`)) {
272
+ warnedObjectLabels.add(`${name}:${value}`);
273
+ 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).`);
274
+ }
275
+ output.push(Object.freeze({
276
+ value,
277
+ label: typeof label === "string" ? label : String(value),
278
+ ...typeof description === "string" ? { description } : {},
279
+ ...Object.keys(legacyMeta).length === 0 ? {} : { meta: Object.freeze(legacyMeta) }
280
+ }));
281
+ }
282
+ return Object.freeze(output);
283
+ }
284
+ function useContextOptions(field, name, meta, ui, resource) {
285
+ const legacy = field.meta?.options;
286
+ const options = (0, react.useMemo)(() => optionsFor(field, name), [
287
+ field.options,
288
+ legacy,
289
+ name
290
+ ]);
291
+ return (0, _burojs_react.useResolvedFieldOptions)({
292
+ name,
293
+ meta,
294
+ ui,
295
+ texts: field.texts
296
+ }, options, resource.id);
297
+ }
298
+ function useContextTexts(field, name, resolved, resource) {
299
+ return (0, _burojs_react.useImplementationTexts)({
300
+ fieldName: name,
301
+ fieldTexts: field.texts,
302
+ id: resolved.id,
303
+ implementation: resolved.implementation
304
+ }, resource.id);
305
+ }
306
+ function useFieldRuntimeContext(resource, record, values, metaSources) {
307
+ const locale = (0, _burojs_react.useLocale)();
308
+ const caps = (0, _burojs_react.useI18nCaps)((0, _burojs_core.canonicalResourceKey)(resource));
309
+ const metaSourcesOut = (0, _burojs_react.useFieldMetaSources)({
310
+ record,
311
+ values,
312
+ extra: metaSources
313
+ });
314
+ const scopeState = metaSourcesOut.scope;
315
+ const scope = scopeState === void 0 ? void 0 : (0, _burojs_react.scopeValueOf)(scopeState);
316
+ return (0, react.useMemo)(() => Object.freeze({
317
+ i18n: Object.freeze({
318
+ locale,
319
+ has: caps.has,
320
+ t: caps.t
321
+ }),
322
+ sources: Object.freeze({
323
+ record: record ?? EMPTY,
324
+ values: values ?? EMPTY,
325
+ scope: scope ?? EMPTY
326
+ }),
327
+ metaSources: metaSourcesOut
328
+ }), [
329
+ caps,
330
+ locale,
331
+ record,
332
+ scope,
333
+ values,
334
+ metaSourcesOut
335
+ ]);
336
+ }
337
+ function useFieldMetaDiagnostic(state, resource, name, field, surface, entry) {
338
+ const reported = (0, react.useRef)(void 0);
339
+ const reason = state.status === "failed" ? state.reason : void 0;
340
+ (0, react.useEffect)(() => {
341
+ if (reason === void 0 || reported.current === reason || process.env.NODE_ENV === "production") return;
342
+ reported.current = reason;
343
+ const implementation = (0, _burojs_core.resolveSurfaceUi)(field, surface, entry).use ?? field.format ?? field.type;
344
+ console.error(`[burojs] field.meta-invalid: ${(0, _burojs_core.formatEntityRef)(resource)}.${name} (${implementation}): ${reason}`);
345
+ }, [
346
+ reason,
347
+ resource,
348
+ name,
349
+ field,
350
+ surface,
351
+ entry
352
+ ]);
353
+ }
354
+ function MetaPlaceholder({ state }) {
355
+ const t = (0, _burojs_react.useOptionalT)();
356
+ if (state.status === "pending") return (0, react_jsx_runtime.jsx)(require_skeleton.Skeleton, {
357
+ "data-buro-skeleton": "",
358
+ "data-buro-field-meta": "pending",
359
+ className: "h-9 w-full"
360
+ });
361
+ return (0, react_jsx_runtime.jsx)("div", {
362
+ role: "alert",
363
+ "data-buro-field-meta": "failed",
364
+ className: "rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
365
+ children: t("field.misconfigured", { defaultValue: "This field is misconfigured" })
366
+ });
367
+ }
368
+ function useFieldImplementationDiagnostic(diagnostic) {
369
+ const reported = (0, react.useRef)(void 0);
370
+ (0, react.useEffect)(() => {
371
+ if (diagnostic === void 0 || reported.current === diagnostic || process.env.NODE_ENV === "production") return;
372
+ reported.current = diagnostic;
373
+ console.warn("[buro/ui-shadcn] missing-field-implementation; rendering fallback.", diagnostic);
374
+ }, [diagnostic]);
375
+ }
376
+ function ResolvedFieldDisplay({ resource, name, field: source, value, record, testId, fallback, presentation, metaSources, uiSurface = "display", columnEntry }) {
377
+ const { sourceAtEdge, field, ui } = useLoweredField(source);
378
+ const surfaceField = (0, react.useMemo)(() => sourceAtEdge.ui === void 0 ? field : Object.freeze({
379
+ ...field,
380
+ ui
381
+ }), [
382
+ sourceAtEdge,
383
+ field,
384
+ ui
385
+ ]);
386
+ const resolved = (0, _burojs_react.useFieldImplementation)({
387
+ field: surfaceField,
388
+ surface: "display",
389
+ uiSurface,
390
+ ...columnEntry === void 0 ? {} : { uiEntry: columnEntry }
391
+ });
392
+ const runtimeContext = useFieldRuntimeContext(resource, record, record, metaSources);
393
+ const metaState = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
394
+ const textField = (0, react.useMemo)(() => Object.freeze({
395
+ ...surfaceField,
396
+ name
397
+ }), [surfaceField, name]);
398
+ const text = (0, _burojs_react.useFieldDisplayText)(textField, value, {
399
+ surface: uiSurface,
400
+ ...columnEntry === void 0 ? {} : { entry: columnEntry },
401
+ resource: (0, _burojs_core.canonicalResourceKey)(resource)
402
+ });
403
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
404
+ const texts = useContextTexts(field, name, resolved, resource);
405
+ useFieldMetaDiagnostic(metaState, resource, name, surfaceField, uiSurface, columnEntry);
406
+ useFieldImplementationDiagnostic(resolved.diagnostic);
407
+ if (resolved.Component === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback });
408
+ if (metaState.status !== "ready") return (0, react_jsx_runtime.jsx)(MetaPlaceholder, { state: metaState });
409
+ const Component = resolved.Component;
410
+ const context = {
411
+ owner: resource,
412
+ resource,
413
+ field,
414
+ path: Object.freeze([name]),
415
+ surface: "display",
416
+ presentation: presentation ?? "default",
417
+ record,
418
+ meta: metaState.meta,
419
+ ui,
420
+ options,
421
+ texts,
422
+ ...text === void 0 ? {} : { text },
423
+ i18n: runtimeContext.i18n,
424
+ sources: runtimeContext.sources,
425
+ pending: false,
426
+ touched: false,
427
+ issues: EMPTY_ISSUES,
428
+ accessibility: EMPTY,
429
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ display: testId })
430
+ };
431
+ if (resolved.multiple) return (0, react.createElement)(Component, {
432
+ ...context,
433
+ multiple: true,
434
+ value: Array.isArray(value) ? value : []
435
+ });
436
+ return (0, react.createElement)(Component, {
437
+ ...context,
438
+ multiple: false,
439
+ value
440
+ });
441
+ }
442
+ 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 }) {
443
+ const { sourceAtEdge, field: base } = useLoweredField(source);
444
+ const field = (0, react.useMemo)(() => required === void 0 || required === base.required ? base : Object.freeze({
445
+ ...base,
446
+ required
447
+ }), [base, required]);
448
+ const ui = (0, react.useMemo)(() => Object.freeze({
449
+ ...sourceAtEdge.ui ?? EMPTY,
450
+ ...placeholder === void 0 ? {} : { placeholder }
451
+ }), [sourceAtEdge, placeholder]);
452
+ const inputField = (0, react.useMemo)(() => ({
453
+ ...field,
454
+ ui
455
+ }), [field, ui]);
456
+ const resolved = (0, _burojs_react.useFieldImplementation)({
457
+ field: inputField,
458
+ surface: "input"
459
+ });
460
+ const runtimeContext = useFieldRuntimeContext(resource, record, form, metaSources);
461
+ const metaState = (0, _burojs_react.useFieldMeta)(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
462
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
463
+ const texts = useContextTexts(field, name, resolved, resource);
464
+ useFieldMetaDiagnostic(metaState, resource, name, inputField, "input");
465
+ useFieldImplementationDiagnostic(resolved.diagnostic);
466
+ if (resolved.Component === void 0) return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: fallback });
467
+ if (metaState.status !== "ready") return (0, react_jsx_runtime.jsx)(MetaPlaceholder, { state: metaState });
468
+ const Component = resolved.Component;
469
+ const issues = suppliedIssues ?? (errorMessage == null ? EMPTY_ISSUES : Object.freeze([Object.freeze({
470
+ code: "ui.field-error",
471
+ message: {
472
+ key: "ui.field-error",
473
+ default: errorMessage
474
+ },
475
+ path: Object.freeze([]),
476
+ source: "field",
477
+ severity: "error"
478
+ })]));
479
+ const context = {
480
+ owner: resource,
481
+ resource,
482
+ field,
483
+ path: Object.freeze([name]),
484
+ surface: "input",
485
+ presentation: "default",
486
+ record,
487
+ form,
488
+ meta: metaState.meta,
489
+ ui,
490
+ options,
491
+ texts,
492
+ i18n: runtimeContext.i18n,
493
+ sources: runtimeContext.sources,
494
+ pending,
495
+ touched,
496
+ issues,
497
+ accessibility: Object.freeze({
498
+ input: inputId ?? name,
499
+ label: labelId,
500
+ description: descriptionId,
501
+ error: errorId
502
+ }),
503
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ input: testId })
504
+ };
505
+ if (resolved.multiple) return (0, react.createElement)(Component, {
506
+ ...context,
507
+ multiple: true,
508
+ value: Array.isArray(value) ? value : [],
509
+ onChange,
510
+ onBlur,
511
+ disabled,
512
+ relationSeeds,
513
+ fixedFilters,
514
+ link,
515
+ metaSources: runtimeContext.metaSources
516
+ });
517
+ return (0, react.createElement)(Component, {
518
+ ...context,
519
+ multiple: false,
520
+ value,
521
+ onChange,
522
+ onBlur,
523
+ disabled,
524
+ relationSeeds,
525
+ fixedFilters,
526
+ link,
527
+ metaSources: runtimeContext.metaSources
528
+ });
529
+ }
530
+ //#endregion
31
531
  //#region src/primitives/badge.tsx
32
532
  const badgeVariants = (0, class_variance_authority.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", {
33
533
  variants: { variant: {
@@ -105,11 +605,11 @@ const SelectGroup = _radix_ui_react_select.Group;
105
605
  const SelectValue = _radix_ui_react_select.Value;
106
606
  const SelectTrigger = react.forwardRef(({ className, children, ...props }, ref) => (0, react_jsx_runtime.jsxs)(_radix_ui_react_select.Trigger, {
107
607
  ref,
108
- className: require_use_theme.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),
608
+ className: require_use_theme.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),
109
609
  ...props,
110
610
  children: [children, (0, react_jsx_runtime.jsx)(_radix_ui_react_select.Icon, {
111
611
  asChild: true,
112
- children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconChevronDown, { className: "h-4 w-4 opacity-50" })
612
+ children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
113
613
  })]
114
614
  }));
115
615
  SelectTrigger.displayName = _radix_ui_react_select.Trigger.displayName;
@@ -148,15 +648,24 @@ const SelectLabel = react.forwardRef(({ className, ...props }, ref) => (0, react
148
648
  ...props
149
649
  }));
150
650
  SelectLabel.displayName = _radix_ui_react_select.Label.displayName;
151
- const SelectItem = react.forwardRef(({ className, children, ...props }, ref) => (0, react_jsx_runtime.jsxs)(_radix_ui_react_select.Item, {
152
- ref,
153
- className: require_use_theme.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),
154
- ...props,
155
- children: [(0, react_jsx_runtime.jsx)("span", {
156
- className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
157
- children: (0, react_jsx_runtime.jsx)(_radix_ui_react_select.ItemIndicator, { children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCheck, { className: "h-4 w-4" }) })
158
- }), (0, react_jsx_runtime.jsx)(_radix_ui_react_select.ItemText, { children })]
159
- }));
651
+ const SelectItem = react.forwardRef(({ className, children, description, ...props }, ref) => {
652
+ const hasDescription = description !== void 0 && description !== null;
653
+ return (0, react_jsx_runtime.jsxs)(_radix_ui_react_select.Item, {
654
+ ref,
655
+ className: require_use_theme.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),
656
+ ...props,
657
+ children: [(0, react_jsx_runtime.jsx)("span", {
658
+ className: require_use_theme.cn("absolute left-2 flex h-3.5 w-3.5 items-center justify-center", hasDescription && "top-[9px]"),
659
+ children: (0, react_jsx_runtime.jsx)(_radix_ui_react_select.ItemIndicator, { children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCheck, { className: "h-4 w-4" }) })
660
+ }), !hasDescription ? (0, react_jsx_runtime.jsx)(_radix_ui_react_select.ItemText, { children }) : (0, react_jsx_runtime.jsxs)("span", {
661
+ className: "flex min-w-0 flex-col gap-0.5",
662
+ children: [(0, react_jsx_runtime.jsx)(_radix_ui_react_select.ItemText, { children }), (0, react_jsx_runtime.jsx)("span", {
663
+ className: "text-xs leading-snug text-muted-foreground",
664
+ children: description
665
+ })]
666
+ })]
667
+ });
668
+ });
160
669
  SelectItem.displayName = _radix_ui_react_select.Item.displayName;
161
670
  const SelectSeparator = react.forwardRef(({ className, ...props }, ref) => (0, react_jsx_runtime.jsx)(_radix_ui_react_select.Separator, {
162
671
  ref,
@@ -209,9 +718,9 @@ function formatNumber(n, locale) {
209
718
  //#endregion
210
719
  //#region src/list-kit/filter-builder/describe-row.ts
211
720
  const MAX_DESCRIBE_DEPTH = 2;
212
- function describeValue(value, t, spec, formatValue) {
721
+ function describeValue(value, chromeT, spec, formatValue) {
213
722
  if (value === void 0) return null;
214
- if (Array.isArray(value)) return t("filters.selectedCount", { count: value.length }, `${value.length} selected`);
723
+ if (Array.isArray(value)) return chromeT("filters.selectedCount", { count: value.length }, `${value.length} selected`);
215
724
  const optionLabel = spec?.options?.find((o) => o.value === String(value))?.label;
216
725
  if (optionLabel !== void 0) return optionLabel;
217
726
  if (spec && formatValue) {
@@ -220,20 +729,20 @@ function describeValue(value, t, spec, formatValue) {
220
729
  }
221
730
  return String(value);
222
731
  }
223
- function describeAt(row, available, t, depth, formatValue) {
732
+ function describeAt(row, available, chromeT, depth, formatValue) {
224
733
  if ((0, _burojs_core.isFilterGroup)(row)) {
225
734
  if (depth > MAX_DESCRIBE_DEPTH) return "…";
226
- const joinLabel = t(`filters.${row.join}`, void 0, row.join);
227
- return `(${row.rows.map((child) => describeAt(child, available, t, depth + 1, formatValue)).join(` ${joinLabel} `)})`;
735
+ const joinLabel = chromeT(`filters.${row.join}`, void 0, row.join);
736
+ return `(${row.rows.map((child) => describeAt(child, available, chromeT, depth + 1, formatValue)).join(` ${joinLabel} `)})`;
228
737
  }
229
738
  const spec = available.find((s) => s.field === row.field);
230
739
  const label = spec?.label ?? row.field;
231
- const opLabel = t(`filters.operators.${row.op}`, void 0, row.op);
232
- const valueText = (0, _burojs_core.opArity)(row.op) === "none" ? null : describeValue(row.value, t, spec, formatValue);
740
+ const opLabel = chromeT(`filters.operators.${row.op}`, void 0, row.op);
741
+ const valueText = (0, _burojs_core.opArity)(row.op) === "none" ? null : describeValue(row.value, chromeT, spec, formatValue);
233
742
  return valueText === null ? `${label} ${opLabel}` : `${label} ${opLabel} ${valueText}`;
234
743
  }
235
- function describeRow(row, available, t, formatValue) {
236
- return describeAt(row, available, t, 1, formatValue);
744
+ function describeRow(row, available, chromeT, formatValue) {
745
+ return describeAt(row, available, chromeT, 1, formatValue);
237
746
  }
238
747
  function relationLabelKey(to, by, value) {
239
748
  return `${by === void 0 ? to : `${to}#${by}`}::${value}`;
@@ -296,7 +805,7 @@ function RelationLabelResolver(props) {
296
805
  const { to, id, by, onResolve } = props;
297
806
  const targetDef = (0, _burojs_react.useApp)().registry.get(to);
298
807
  const { record } = (0, _burojs_react.useRelatedRecord)(to, id, by === void 0 ? void 0 : { by });
299
- const rowTitle = require_search_access.useRowTitle(to, targetDef?.displayField);
808
+ const rowTitle = require_relation_create.useRowTitle(to, targetDef?.displayField);
300
809
  (0, react.useEffect)(() => {
301
810
  if (!record) return;
302
811
  onResolve(relationLabelKey(to, by, id), rowTitle(record));
@@ -366,15 +875,18 @@ function badgeKey(row, index) {
366
875
  if ((0, _burojs_core.isFilterGroup)(row)) return `${index}:group:${row.join}`;
367
876
  return `${index}:${row.field}:${row.op}`;
368
877
  }
878
+ const BADGE_ROW = "inline-flex max-w-full items-center gap-1 align-middle";
879
+ 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";
369
880
  function FilterBadges(props) {
370
881
  const { group, setGroup, available, fixed, testIdBase, onOpenAt, onRemoved, pinnedFields = [], pinnedValue = [], setPinnedValue } = props;
371
- const t = (0, _burojs_react.useOptionalT)();
372
- const tt = (key, params, fallback) => t(key, {
882
+ const chromeT = (0, _burojs_react.useChromeT)();
883
+ const locale = (0, _burojs_react.useOptionalLocale)();
884
+ const tt = (key, params, fallback) => chromeT(key, {
373
885
  params,
374
886
  ...typeof params?.count === "number" ? { count: params.count } : {},
375
887
  defaultValue: fallback
376
888
  });
377
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
889
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
378
890
  const { enumLabels, relationLabels, onEnumResolved, onRelationResolved } = useFormatValueMaps();
379
891
  const formatValue = (kind, value) => {
380
892
  if (kind.kind === "enum") return enumLabels[kind.enumName]?.[String(value)];
@@ -382,7 +894,7 @@ function FilterBadges(props) {
382
894
  if (kind.kind === "date") {
383
895
  const d = new Date(String(value));
384
896
  if (Number.isNaN(d.getTime())) return void 0;
385
- return kind.time ? formatDateTime(d) : formatDate(d);
897
+ return kind.time ? formatDateTime(d, locale) : formatDate(d, locale);
386
898
  }
387
899
  };
388
900
  const orphanPinned = (0, react.useMemo)(() => {
@@ -416,49 +928,56 @@ function FilterBadges(props) {
416
928
  onEnumResolved,
417
929
  onRelationResolved
418
930
  }),
419
- group.rows.map((row, index) => (0, react_jsx_runtime.jsxs)(Badge, {
931
+ group.rows.map((row, index) => (0, react_jsx_runtime.jsx)(Badge, {
420
932
  variant: "secondary",
421
- className: "gap-1 py-1 pr-1",
422
- children: [(0, react_jsx_runtime.jsx)("button", {
423
- type: "button",
424
- "data-testid": `${testIdBase}:badge:${index}`,
425
- onClick: () => onOpenAt([index]),
426
- className: "max-w-full cursor-pointer truncate bg-transparent p-0 text-left",
427
- children: describeRow(row, available, tt, formatValue)
428
- }), (0, react_jsx_runtime.jsx)("button", {
429
- type: "button",
430
- "data-testid": `${testIdBase}:badge:${index}:remove`,
431
- "aria-label": removeLabel,
432
- onClick: () => handleRemove(index),
433
- className: "rounded-sm hover:bg-accent",
434
- children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, {
435
- className: "h-3 w-3",
436
- "aria-hidden": "true"
437
- })
438
- })]
933
+ className: "py-1 pr-1",
934
+ children: (0, react_jsx_runtime.jsxs)("span", {
935
+ className: BADGE_ROW,
936
+ children: [(0, react_jsx_runtime.jsx)("button", {
937
+ type: "button",
938
+ "data-testid": `${testIdBase}:badge:${index}`,
939
+ onClick: () => onOpenAt([index]),
940
+ className: "min-w-0 cursor-pointer truncate bg-transparent p-0 text-left",
941
+ children: describeRow(row, available, tt, formatValue)
942
+ }), (0, react_jsx_runtime.jsx)("button", {
943
+ type: "button",
944
+ "data-testid": `${testIdBase}:badge:${index}:remove`,
945
+ "aria-label": removeLabel,
946
+ onClick: () => handleRemove(index),
947
+ className: REMOVE_BUTTON,
948
+ children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, {
949
+ className: "size-3",
950
+ "aria-hidden": "true"
951
+ })
952
+ })]
953
+ })
439
954
  }, badgeKey(row, index))),
440
955
  labelledFixed.map((entry, index) => (0, react_jsx_runtime.jsx)(Badge, {
441
956
  variant: "outline",
442
957
  "data-testid": `${testIdBase}:badge:fixed:${index}`,
443
958
  children: entry.label
444
959
  }, `fixed-${index}`)),
445
- orphanPinned.map(({ expr, index }) => (0, react_jsx_runtime.jsxs)(Badge, {
960
+ orphanPinned.map(({ expr, index }) => (0, react_jsx_runtime.jsx)(Badge, {
446
961
  variant: "secondary",
447
- className: "gap-1 py-1",
448
- children: [(0, react_jsx_runtime.jsx)("span", {
449
- "data-testid": `${testIdBase}:badge:pinned:${index}`,
450
- children: describeRow(expr, available, tt, formatValue)
451
- }), (0, react_jsx_runtime.jsx)("button", {
452
- type: "button",
453
- "data-testid": `${testIdBase}:badge:pinned:${index}:remove`,
454
- "aria-label": removeLabel,
455
- onClick: () => handleRemovePinned(index),
456
- className: "rounded-sm hover:bg-accent",
457
- children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, {
458
- className: "h-3 w-3",
459
- "aria-hidden": "true"
460
- })
461
- })]
962
+ className: "py-1 pr-1",
963
+ children: (0, react_jsx_runtime.jsxs)("span", {
964
+ className: BADGE_ROW,
965
+ children: [(0, react_jsx_runtime.jsx)("span", {
966
+ "data-testid": `${testIdBase}:badge:pinned:${index}`,
967
+ className: "min-w-0 truncate",
968
+ children: describeRow(expr, available, tt, formatValue)
969
+ }), (0, react_jsx_runtime.jsx)("button", {
970
+ type: "button",
971
+ "data-testid": `${testIdBase}:badge:pinned:${index}:remove`,
972
+ "aria-label": removeLabel,
973
+ onClick: () => handleRemovePinned(index),
974
+ className: REMOVE_BUTTON,
975
+ children: (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, {
976
+ className: "size-3",
977
+ "aria-hidden": "true"
978
+ })
979
+ })]
980
+ })
462
981
  }, `pinned-${index}`))
463
982
  ]
464
983
  });
@@ -648,14 +1167,15 @@ const OPTIONS = ["true", "false"];
648
1167
  function BooleanValueControl(props) {
649
1168
  const { value, onChange, testId, arity, autoFocus, fieldLabel, fill } = props;
650
1169
  const t = (0, _burojs_react.useOptionalT)();
651
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1170
+ const chromeT = (0, _burojs_react.useChromeT)();
1171
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
652
1172
  defaultValue: `Value for ${fieldLabel}`,
653
1173
  params: { field: fieldLabel }
654
- }) : t("filters.value", { defaultValue: "Value" });
1174
+ }) : chromeT("filters.value", { defaultValue: "Value" });
655
1175
  const yesLabel = t("boolean.yes", { defaultValue: "Yes" });
656
1176
  const noLabel = t("boolean.no", { defaultValue: "No" });
657
1177
  const labelOf = (token) => token === "true" ? yesLabel : noLabel;
658
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1178
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
659
1179
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
660
1180
  value,
661
1181
  arity,
@@ -675,12 +1195,12 @@ function BooleanValueControl(props) {
675
1195
  "data-testid": testId,
676
1196
  "aria-label": ariaLabel,
677
1197
  className: require_use_theme.cn("h-8 justify-between", fill && "w-full"),
678
- children: triggerLabel(labelOf, ariaLabel)
1198
+ children: triggerLabel(labelOf, props.placeholder ?? ariaLabel)
679
1199
  })
680
1200
  }), (0, react_jsx_runtime.jsx)(require_toaster.PopoverContent, {
681
1201
  className: "w-[140px] p-0",
682
1202
  align: "start",
683
- children: (0, react_jsx_runtime.jsx)(require_search_access.Command, { children: (0, react_jsx_runtime.jsx)(require_search_access.CommandList, { children: (0, react_jsx_runtime.jsxs)(require_search_access.CommandGroup, { children: [arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1203
+ children: (0, react_jsx_runtime.jsx)(require_relation_create.Command, { children: (0, react_jsx_runtime.jsx)(require_relation_create.CommandList, { children: (0, react_jsx_runtime.jsxs)(require_relation_create.CommandGroup, { children: [arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
684
1204
  "data-testid": `${testId}:clear`,
685
1205
  value: "__clear__",
686
1206
  onSelect: () => clear(),
@@ -690,7 +1210,7 @@ function BooleanValueControl(props) {
690
1210
  }), clearLabel]
691
1211
  }), OPTIONS.map((token) => {
692
1212
  const isSelected = selected.has(token);
693
- return (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1213
+ return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
694
1214
  value: labelOf(token),
695
1215
  "data-testid": `${testId}:option:${token}`,
696
1216
  onSelect: () => select(token),
@@ -708,12 +1228,13 @@ function BooleanValueControl(props) {
708
1228
  function SelectListValueControl(props) {
709
1229
  const { options, value, onChange, testId, arity, autoFocus, fieldLabel, isLoading = false } = props;
710
1230
  const t = (0, _burojs_react.useOptionalT)();
711
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1231
+ const chromeT = (0, _burojs_react.useChromeT)();
1232
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
712
1233
  defaultValue: `Value for ${fieldLabel}`,
713
1234
  params: { field: fieldLabel }
714
- }) : t("filters.value", { defaultValue: "Value" });
1235
+ }) : chromeT("filters.value", { defaultValue: "Value" });
715
1236
  const loadingLabel = t("table.loading", { defaultValue: "Loading…" });
716
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1237
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
717
1238
  const labelFor = props.labelFor ?? ((raw) => options.find((o) => o.value === raw)?.label ?? raw);
718
1239
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
719
1240
  value,
@@ -735,16 +1256,16 @@ function SelectListValueControl(props) {
735
1256
  className: require_use_theme.cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[200px]"),
736
1257
  children: (0, react_jsx_runtime.jsx)("span", {
737
1258
  className: "truncate",
738
- children: isLoading ? loadingLabel : triggerLabel(labelFor, ariaLabel)
1259
+ children: isLoading ? loadingLabel : triggerLabel(labelFor, props.placeholder ?? ariaLabel)
739
1260
  })
740
1261
  })
741
1262
  }), (0, react_jsx_runtime.jsx)(require_toaster.PopoverContent, {
742
1263
  className: "w-[220px] p-0",
743
1264
  align: "start",
744
- children: (0, react_jsx_runtime.jsxs)(require_search_access.Command, { children: [(0, react_jsx_runtime.jsx)(require_search_access.CommandInput, {
1265
+ children: (0, react_jsx_runtime.jsxs)(require_relation_create.Command, { children: [(0, react_jsx_runtime.jsx)(require_relation_create.CommandInput, {
745
1266
  placeholder: ariaLabel,
746
1267
  "data-testid": `${testId}:search`
747
- }), (0, react_jsx_runtime.jsxs)(require_search_access.CommandList, { children: [
1268
+ }), (0, react_jsx_runtime.jsxs)(require_relation_create.CommandList, { children: [
748
1269
  isLoading && (0, react_jsx_runtime.jsxs)("div", {
749
1270
  className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground",
750
1271
  "data-testid": `${testId}:loading`,
@@ -753,8 +1274,8 @@ function SelectListValueControl(props) {
753
1274
  "aria-hidden": "true"
754
1275
  }), loadingLabel]
755
1276
  }),
756
- !isLoading && (0, react_jsx_runtime.jsx)(require_search_access.CommandEmpty, { children: t("relation.noResults", { defaultValue: "No results." }) }),
757
- !isLoading && (0, react_jsx_runtime.jsxs)(require_search_access.CommandGroup, { children: [arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1277
+ !isLoading && (0, react_jsx_runtime.jsx)(require_relation_create.CommandEmpty, { children: t("relation.noResults", { defaultValue: "No results." }) }),
1278
+ !isLoading && (0, react_jsx_runtime.jsxs)(require_relation_create.CommandGroup, { children: [arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
758
1279
  "data-testid": `${testId}:clear`,
759
1280
  value: "__clear__",
760
1281
  onSelect: () => clear(),
@@ -765,7 +1286,7 @@ function SelectListValueControl(props) {
765
1286
  }), options.map((entry) => {
766
1287
  const isSelected = selected.has(entry.value);
767
1288
  const label = labelFor(entry.value);
768
- return (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1289
+ return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
769
1290
  value: label,
770
1291
  "data-testid": `${testId}:option:${entry.value}`,
771
1292
  onSelect: () => select(entry.value),
@@ -798,6 +1319,7 @@ function EnumValueControl(props) {
798
1319
  arity,
799
1320
  autoFocus,
800
1321
  fieldLabel,
1322
+ placeholder: props.placeholder,
801
1323
  options,
802
1324
  labelFor,
803
1325
  isLoading,
@@ -809,7 +1331,7 @@ function EnumValueControl(props) {
809
1331
  function useRelatedLabels(to, ids, by) {
810
1332
  const targetDef = (0, _burojs_react.useApp)().registry.get(to);
811
1333
  const idField = (targetDef?.data)?.idField;
812
- const rowTitle = require_search_access.useRowTitle(to, targetDef?.displayField);
1334
+ const rowTitle = require_relation_create.useRowTitle(to, targetDef?.displayField);
813
1335
  const field = by ?? (typeof idField === "string" && idField.length > 0 ? idField : "id");
814
1336
  const query = (0, _burojs_react.useList)(to, {
815
1337
  pagination: {
@@ -844,6 +1366,7 @@ function RelationValueControl(props) {
844
1366
  const { to, by, value, onChange, testId, arity, autoFocus, fieldLabel } = props;
845
1367
  const app = (0, _burojs_react.useApp)();
846
1368
  const t = (0, _burojs_react.useOptionalT)();
1369
+ const chromeT = (0, _burojs_react.useChromeT)();
847
1370
  const targetDef = app.registry.get(to);
848
1371
  const displayField = targetDef?.displayField ?? "name";
849
1372
  const [search, setSearch] = (0, react.useState)("");
@@ -852,9 +1375,9 @@ function RelationValueControl(props) {
852
1375
  arity,
853
1376
  onChange
854
1377
  });
855
- const rowTitle = require_search_access.useRowTitle(to, targetDef?.displayField);
1378
+ const rowTitle = require_relation_create.useRowTitle(to, targetDef?.displayField);
856
1379
  const access = (0, _burojs_react.useListAccess)(to);
857
- const searchable = (0, react.useMemo)(() => access.status === "ready" && require_search_access.narrowSearchDecl({ fields: [displayField] }, (name) => access.fieldVisible(name)) !== void 0, [access, displayField]);
1380
+ const searchable = (0, react.useMemo)(() => access.status === "ready" && require_relation_create.narrowSearchDecl({ fields: [displayField] }, (name) => access.fieldVisible(name)) !== void 0, [access, displayField]);
858
1381
  const listQuery = (0, _burojs_react.useList)(to, {
859
1382
  pagination: {
860
1383
  kind: "offset",
@@ -882,11 +1405,11 @@ function RelationValueControl(props) {
882
1405
  if (fromRows) return rowTitle(fromRows);
883
1406
  return fallbackLabels[id] ?? id;
884
1407
  };
885
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1408
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
886
1409
  defaultValue: `Value for ${fieldLabel}`,
887
1410
  params: { field: fieldLabel }
888
- }) : t("filters.value", { defaultValue: "Value" });
889
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1411
+ }) : chromeT("filters.value", { defaultValue: "Value" });
1412
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
890
1413
  return (0, react_jsx_runtime.jsxs)(require_toaster.Popover, {
891
1414
  open,
892
1415
  onOpenChange: setOpen,
@@ -902,20 +1425,20 @@ function RelationValueControl(props) {
902
1425
  className: require_use_theme.cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[220px]"),
903
1426
  children: (0, react_jsx_runtime.jsx)("span", {
904
1427
  className: "truncate",
905
- children: triggerLabel(labelFor, ariaLabel)
1428
+ children: triggerLabel(labelFor, props.placeholder ?? ariaLabel)
906
1429
  })
907
1430
  })
908
1431
  }), (0, react_jsx_runtime.jsx)(require_toaster.PopoverContent, {
909
1432
  className: "w-[240px] p-0",
910
1433
  align: "start",
911
- children: (0, react_jsx_runtime.jsxs)(require_search_access.Command, {
1434
+ children: (0, react_jsx_runtime.jsxs)(require_relation_create.Command, {
912
1435
  shouldFilter: false,
913
- children: [searchable && (0, react_jsx_runtime.jsx)(require_search_access.CommandInput, {
1436
+ children: [searchable && (0, react_jsx_runtime.jsx)(require_relation_create.CommandInput, {
914
1437
  value: search,
915
1438
  onValueChange: setSearch,
916
1439
  placeholder: ariaLabel,
917
1440
  "data-testid": `${testId}:search`
918
- }), (0, react_jsx_runtime.jsxs)(require_search_access.CommandList, { children: [
1441
+ }), (0, react_jsx_runtime.jsxs)(require_relation_create.CommandList, { children: [
919
1442
  listQuery.isLoading && (0, react_jsx_runtime.jsxs)("div", {
920
1443
  className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground",
921
1444
  "data-testid": `${testId}:loading`,
@@ -924,8 +1447,8 @@ function RelationValueControl(props) {
924
1447
  "aria-hidden": "true"
925
1448
  }), t("table.loading", { defaultValue: "Loading…" })]
926
1449
  }),
927
- !listQuery.isLoading && rows.length === 0 && (0, react_jsx_runtime.jsx)(require_search_access.CommandEmpty, { children: t("relation.noResults", { defaultValue: "No results." }) }),
928
- !listQuery.isLoading && arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1450
+ !listQuery.isLoading && rows.length === 0 && (0, react_jsx_runtime.jsx)(require_relation_create.CommandEmpty, { children: t("relation.noResults", { defaultValue: "No results." }) }),
1451
+ !listQuery.isLoading && arity === "single" && selected.size > 0 && (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
929
1452
  "data-testid": `${testId}:clear`,
930
1453
  value: "__clear__",
931
1454
  onSelect: () => clear(),
@@ -939,7 +1462,7 @@ function RelationValueControl(props) {
939
1462
  if (id === void 0) return null;
940
1463
  const label = rowTitle(row);
941
1464
  const isSelected = selected.has(id);
942
- return (0, react_jsx_runtime.jsxs)(require_search_access.CommandItem, {
1465
+ return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
943
1466
  value: `${label} ${id}`,
944
1467
  "data-testid": `${testId}:option:${id}`,
945
1468
  onSelect: () => select(id),
@@ -958,6 +1481,20 @@ function RelationValueControl(props) {
958
1481
  });
959
1482
  }
960
1483
  //#endregion
1484
+ //#region src/fields/local-date-time.ts
1485
+ function toLocalDateTimeText(value) {
1486
+ if (value === void 0 || value === null || value === "") return "";
1487
+ const d = value instanceof Date ? value : new Date(String(value));
1488
+ if (Number.isNaN(d.getTime())) return "";
1489
+ const pad = (n) => String(n).padStart(2, "0");
1490
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
1491
+ }
1492
+ function fromLocalDateTimeText(text) {
1493
+ if (text === "") return void 0;
1494
+ const d = new Date(text);
1495
+ return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
1496
+ }
1497
+ //#endregion
961
1498
  //#region src/list-kit/filter-builder/values/scalar-value-input.tsx
962
1499
  function isDateTime(kind) {
963
1500
  return kind.kind === "date" && kind.time === true;
@@ -970,12 +1507,9 @@ function inputTypeFor(kind) {
970
1507
  }
971
1508
  }
972
1509
  function toText(kind, value) {
1510
+ if (isDateTime(kind)) return toLocalDateTimeText(value);
973
1511
  if (value === void 0 || value === null || value === "") return "";
974
- if (!isDateTime(kind)) return String(value);
975
- const d = new Date(String(value));
976
- if (Number.isNaN(d.getTime())) return "";
977
- const pad = (n) => String(n).padStart(2, "0");
978
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
1512
+ return String(value);
979
1513
  }
980
1514
  function parseOne(kind, raw) {
981
1515
  if (raw === "") return void 0;
@@ -983,19 +1517,16 @@ function parseOne(kind, raw) {
983
1517
  const n = Number(raw);
984
1518
  return Number.isFinite(n) ? n : void 0;
985
1519
  }
986
- if (isDateTime(kind)) {
987
- const d = new Date(raw);
988
- return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
989
- }
1520
+ if (isDateTime(kind)) return fromLocalDateTimeText(raw);
990
1521
  return raw;
991
1522
  }
992
1523
  function ScalarValueInput(props) {
993
- const t = (0, _burojs_react.useOptionalT)();
1524
+ const chromeT = (0, _burojs_react.useChromeT)();
994
1525
  const inputType = inputTypeFor(props.kind);
995
- const ariaLabel = props.fieldLabel ? t("filters.valueFor", {
1526
+ const ariaLabel = props.fieldLabel ? chromeT("filters.valueFor", {
996
1527
  defaultValue: `Value for ${props.fieldLabel}`,
997
1528
  params: { field: props.fieldLabel }
998
- }) : t("filters.value", { defaultValue: "Value" });
1529
+ }) : chromeT("filters.value", { defaultValue: "Value" });
999
1530
  if (props.arity === "multi") return (0, react_jsx_runtime.jsx)(ScalarMultiInput, {
1000
1531
  ...props,
1001
1532
  inputType,
@@ -1125,6 +1656,7 @@ function FilterValueControl(props) {
1125
1656
  arity,
1126
1657
  autoFocus: props.autoFocus,
1127
1658
  fieldLabel: props.fieldLabel,
1659
+ placeholder: props.placeholder,
1128
1660
  options: props.options,
1129
1661
  fill: props.fill
1130
1662
  });
@@ -1141,6 +1673,7 @@ function FilterValueControl(props) {
1141
1673
  arity,
1142
1674
  autoFocus: props.autoFocus,
1143
1675
  fieldLabel: props.fieldLabel,
1676
+ placeholder: props.placeholder,
1144
1677
  options: props.kind.values.map((entry) => ({
1145
1678
  value: entry,
1146
1679
  label: entry
@@ -1169,10 +1702,10 @@ const FIELD_CLASS = "h-8 min-w-0 shrink basis-40";
1169
1702
  const OPERATOR_CLASS = "h-8 min-w-0 shrink basis-[9.5rem]";
1170
1703
  function FilterRow(props) {
1171
1704
  const { row, path, available, onPatch, onRemove, testIdBase, debounceMs } = props;
1172
- const t = (0, _burojs_react.useOptionalT)();
1705
+ const chromeT = (0, _burojs_react.useChromeT)();
1173
1706
  const base = `${testIdBase}:row:${path.join("-")}`;
1174
1707
  const spec = available.find((s) => s.field === row.field);
1175
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
1708
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
1176
1709
  if (!spec) return (0, react_jsx_runtime.jsxs)("div", {
1177
1710
  className: ROW_CLASS,
1178
1711
  children: [
@@ -1212,8 +1745,8 @@ function FilterRow(props) {
1212
1745
  };
1213
1746
  const handleOpChange = (op) => onPatch(path, { op });
1214
1747
  const handleValueChange = (value) => onPatch(path, { value });
1215
- const fieldAriaLabel = t("filters.field", { defaultValue: "Field" });
1216
- const operatorAriaLabel = t("filters.operator", { defaultValue: "Operator" });
1748
+ const fieldAriaLabel = chromeT("filters.field", { defaultValue: "Field" });
1749
+ const operatorAriaLabel = chromeT("filters.operator", { defaultValue: "Operator" });
1217
1750
  return (0, react_jsx_runtime.jsxs)("div", {
1218
1751
  className: ROW_CLASS,
1219
1752
  children: [
@@ -1242,7 +1775,7 @@ function FilterRow(props) {
1242
1775
  }), (0, react_jsx_runtime.jsx)(SelectContent, { children: spec.operators.map((op) => (0, react_jsx_runtime.jsx)(SelectItem, {
1243
1776
  value: op,
1244
1777
  "data-testid": `${opTestId}:option:${op}`,
1245
- children: t(`filters.operators.${op}`, { defaultValue: op })
1778
+ children: chromeT(`filters.operators.${op}`, { defaultValue: op })
1246
1779
  }, op)) })]
1247
1780
  }),
1248
1781
  (0, react_jsx_runtime.jsx)("div", {
@@ -1290,10 +1823,10 @@ function FilterGroupEditor(props) {
1290
1823
  }
1291
1824
  function GroupEditorInner(props) {
1292
1825
  const { group, path, available, onChange, testIdBase, onRemove, addGroupAt, debounceMs } = props;
1293
- const t = (0, _burojs_react.useOptionalT)();
1826
+ const chromeT = (0, _burojs_react.useChromeT)();
1294
1827
  const base = `${testIdBase}:group:${path.join("-")}`;
1295
1828
  const canNestGroup = depthOf(path) < 3;
1296
- const joinLabel = (join) => t(`filters.${join}`, { defaultValue: join });
1829
+ const joinLabel = (join) => chromeT(`filters.${join}`, { defaultValue: join });
1297
1830
  const handlePatch = (rowPath, patch) => {
1298
1831
  const index = rowPath[rowPath.length - 1];
1299
1832
  if (index === void 0) return;
@@ -1326,11 +1859,11 @@ function GroupEditorInner(props) {
1326
1859
  return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
1327
1860
  className: CONNECTOR_CLASS,
1328
1861
  children: [
1329
- index === 0 && t("filters.where", { defaultValue: "Where" }),
1862
+ index === 0 && chromeT("filters.where", { defaultValue: "Where" }),
1330
1863
  index === 1 && (0, react_jsx_runtime.jsx)("button", {
1331
1864
  type: "button",
1332
1865
  "data-testid": `${base}:join`,
1333
- "aria-label": t("filters.toggleJoin", {
1866
+ "aria-label": chromeT("filters.toggleJoin", {
1334
1867
  defaultValue: `Join: ${joinLabel(group.join)} — activate to switch to ${joinLabel(otherJoin)}`,
1335
1868
  params: {
1336
1869
  current: joinLabel(group.join),
@@ -1382,7 +1915,7 @@ function GroupEditorInner(props) {
1382
1915
  children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconPlus, {
1383
1916
  className: "h-4 w-4",
1384
1917
  "aria-hidden": "true"
1385
- }), t("filters.addRow", { defaultValue: "Add filter" })]
1918
+ }), chromeT("filters.addRow", { defaultValue: "Add filter" })]
1386
1919
  }),
1387
1920
  canNestGroup && (0, react_jsx_runtime.jsxs)(require_button.Button, {
1388
1921
  type: "button",
@@ -1393,7 +1926,7 @@ function GroupEditorInner(props) {
1393
1926
  children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconFolderPlus, {
1394
1927
  className: "h-4 w-4",
1395
1928
  "aria-hidden": "true"
1396
- }), t("filters.addGroup", { defaultValue: "Add group" })]
1929
+ }), chromeT("filters.addGroup", { defaultValue: "Add group" })]
1397
1930
  }),
1398
1931
  onRemove && (0, react_jsx_runtime.jsxs)(require_button.Button, {
1399
1932
  type: "button",
@@ -1404,7 +1937,7 @@ function GroupEditorInner(props) {
1404
1937
  children: [(0, react_jsx_runtime.jsx)(_tabler_icons_react.IconX, {
1405
1938
  className: "h-4 w-4",
1406
1939
  "aria-hidden": "true"
1407
- }), t("filters.removeGroup", { defaultValue: "Remove group" })]
1940
+ }), chromeT("filters.removeGroup", { defaultValue: "Remove group" })]
1408
1941
  })
1409
1942
  ]
1410
1943
  })
@@ -1420,7 +1953,7 @@ function countGroupRows(group) {
1420
1953
  }
1421
1954
  function FilterPanel(props) {
1422
1955
  const { group, setGroup, available, setPage, testIdBase, open, onOpenChange, focusPath, externalRemoval } = props;
1423
- const t = (0, _burojs_react.useOptionalT)();
1956
+ const chromeT = (0, _burojs_react.useChromeT)();
1424
1957
  const [draft, setDraft] = (0, react.useState)(() => toDraft(group));
1425
1958
  const wasOpenRef = (0, react.useRef)(open);
1426
1959
  const topLevelIdsRef = (0, react.useRef)([]);
@@ -1472,7 +2005,7 @@ function FilterPanel(props) {
1472
2005
  className: "h-4 w-4",
1473
2006
  "aria-hidden": "true"
1474
2007
  }),
1475
- t("filters.title", { defaultValue: "Filters" }),
2008
+ chromeT("filters.title", { defaultValue: "Filters" }),
1476
2009
  appliedCount > 0 && (0, react_jsx_runtime.jsx)("span", {
1477
2010
  "data-testid": `${testIdBase}:count`,
1478
2011
  className: "ml-1 rounded-full bg-primary px-1.5 text-xs text-primary-foreground",
@@ -1500,13 +2033,13 @@ function FilterPanel(props) {
1500
2033
  size: "sm",
1501
2034
  "data-testid": `${testIdBase}:reset`,
1502
2035
  onClick: handleReset,
1503
- children: t("filters.reset", { defaultValue: "Reset" })
2036
+ children: chromeT("filters.reset", { defaultValue: "Reset" })
1504
2037
  }), (0, react_jsx_runtime.jsx)(require_button.Button, {
1505
2038
  type: "button",
1506
2039
  size: "sm",
1507
2040
  "data-testid": `${testIdBase}:apply`,
1508
2041
  onClick: handleApply,
1509
- children: t("filters.apply", { defaultValue: "Apply" })
2042
+ children: chromeT("filters.apply", { defaultValue: "Apply" })
1510
2043
  })]
1511
2044
  })]
1512
2045
  })]
@@ -1561,11 +2094,204 @@ function PinnedControl(props) {
1561
2094
  });
1562
2095
  }
1563
2096
  //#endregion
2097
+ //#region src/data-table/data-table-faceted-filter.tsx
2098
+ function DataTableFacetedFilter({ column, getTestId, ...rest }) {
2099
+ const filterValue = column.getFilterValue();
2100
+ return (0, react_jsx_runtime.jsx)(FacetedFilterPicker, {
2101
+ ...rest,
2102
+ ...getTestId === void 0 ? {} : { getTestId: (role, value) => role === "hint" ? void 0 : getTestId(role, value) },
2103
+ selected: Array.isArray(filterValue) ? filterValue.map(String) : [],
2104
+ onChange: (next) => column.setFilterValue(next.length === 0 ? void 0 : next)
2105
+ });
2106
+ }
2107
+ function FacetedFilterPicker({ title, options = [], loadOptions, selectedLabelFor, searchPlaceholder, emptyText, getTestId, className, selected: selectedList, onChange, hint, emptyLabel, clearable = true }) {
2108
+ const t = (0, _burojs_react.useOptionalT)();
2109
+ const chromeT = (0, _burojs_react.useChromeT)();
2110
+ const selected = (0, react.useMemo)(() => new Set(selectedList), [selectedList]);
2111
+ const [search, setSearch] = (0, react.useState)("");
2112
+ const [asyncOptions, setAsyncOptions] = (0, react.useState)([]);
2113
+ const [loading, setLoading] = (0, react.useState)(false);
2114
+ const debounceRef = (0, react.useRef)(null);
2115
+ const loadOptionsRef = (0, react.useRef)(loadOptions);
2116
+ (0, react.useEffect)(() => {
2117
+ loadOptionsRef.current = loadOptions;
2118
+ });
2119
+ (0, react.useEffect)(() => {
2120
+ if (!loadOptionsRef.current) return;
2121
+ setLoading(true);
2122
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2123
+ let cancelled = false;
2124
+ debounceRef.current = setTimeout(() => {
2125
+ const loader = loadOptionsRef.current;
2126
+ if (!loader) return;
2127
+ loader(search).then((results) => {
2128
+ if (!cancelled) {
2129
+ setAsyncOptions(results);
2130
+ setLoading(false);
2131
+ }
2132
+ }).catch(() => {
2133
+ if (!cancelled) setLoading(false);
2134
+ });
2135
+ }, 250);
2136
+ return () => {
2137
+ cancelled = true;
2138
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2139
+ };
2140
+ }, [search]);
2141
+ const effectiveOptions = loadOptions ? asyncOptions : options;
2142
+ const labelFor = (value) => {
2143
+ const opt = effectiveOptions.find((o) => o.value === value);
2144
+ if (opt) return opt.label;
2145
+ return selectedLabelFor?.(value) ?? value;
2146
+ };
2147
+ const toggle = (value) => {
2148
+ const next = new Set(selected);
2149
+ if (next.has(value)) next.delete(value);
2150
+ else next.add(value);
2151
+ onChange(Array.from(next));
2152
+ };
2153
+ const selectedValues = Array.from(selected);
2154
+ return (0, react_jsx_runtime.jsxs)(require_toaster.Popover, { children: [(0, react_jsx_runtime.jsx)(require_toaster.PopoverTrigger, {
2155
+ asChild: true,
2156
+ children: (0, react_jsx_runtime.jsxs)(require_button.Button, {
2157
+ type: "button",
2158
+ variant: "outline",
2159
+ size: "sm",
2160
+ "data-testid": getTestId?.("trigger"),
2161
+ title: hint,
2162
+ className: require_use_theme.cn("h-8 border-dashed", className),
2163
+ children: [
2164
+ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCirclePlus, {
2165
+ className: "mr-2 h-4 w-4",
2166
+ "aria-hidden": "true"
2167
+ }),
2168
+ title,
2169
+ selected.size === 0 && emptyLabel !== void 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
2170
+ className: "mx-2 h-4 w-px bg-border",
2171
+ "aria-hidden": "true"
2172
+ }), (0, react_jsx_runtime.jsx)(Badge, {
2173
+ variant: "secondary",
2174
+ className: "rounded-sm px-1 font-normal",
2175
+ children: emptyLabel
2176
+ })] }),
2177
+ selected.size > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2178
+ (0, react_jsx_runtime.jsx)("span", {
2179
+ className: "mx-2 h-4 w-px bg-border",
2180
+ "aria-hidden": "true"
2181
+ }),
2182
+ (0, react_jsx_runtime.jsx)(Badge, {
2183
+ variant: "secondary",
2184
+ className: "rounded-sm px-1 font-normal lg:hidden",
2185
+ children: selected.size
2186
+ }),
2187
+ (0, react_jsx_runtime.jsx)("div", {
2188
+ className: "hidden gap-1 lg:flex",
2189
+ children: selected.size > 2 ? (0, react_jsx_runtime.jsx)(Badge, {
2190
+ variant: "secondary",
2191
+ className: "rounded-sm px-1 font-normal",
2192
+ children: t("table.selectedCount", {
2193
+ count: selected.size,
2194
+ defaultValue: "{{count}} selected"
2195
+ })
2196
+ }) : selectedValues.map((value) => (0, react_jsx_runtime.jsx)(Badge, {
2197
+ variant: "secondary",
2198
+ className: "rounded-sm px-1 font-normal",
2199
+ children: labelFor(value)
2200
+ }, value))
2201
+ })
2202
+ ] })
2203
+ ]
2204
+ })
2205
+ }), (0, react_jsx_runtime.jsx)(require_toaster.PopoverContent, {
2206
+ className: "w-[220px] p-0",
2207
+ align: "start",
2208
+ children: (0, react_jsx_runtime.jsxs)(require_relation_create.Command, {
2209
+ shouldFilter: !loadOptions,
2210
+ children: [
2211
+ hint !== void 0 && (0, react_jsx_runtime.jsx)("p", {
2212
+ "data-testid": getTestId?.("hint"),
2213
+ className: "border-b px-3 py-2 text-xs text-muted-foreground",
2214
+ children: hint
2215
+ }),
2216
+ (0, react_jsx_runtime.jsx)(require_relation_create.CommandInput, {
2217
+ placeholder: searchPlaceholder ?? title,
2218
+ "data-testid": getTestId?.("search"),
2219
+ ...loadOptions ? {
2220
+ value: search,
2221
+ onValueChange: setSearch
2222
+ } : {}
2223
+ }),
2224
+ (0, react_jsx_runtime.jsxs)(require_relation_create.CommandList, { children: [
2225
+ loading && (0, react_jsx_runtime.jsx)("div", {
2226
+ className: "py-6 text-center text-sm text-muted-foreground",
2227
+ children: t("list.loadingShort", { defaultValue: "Loading…" })
2228
+ }),
2229
+ (0, react_jsx_runtime.jsx)(require_relation_create.CommandEmpty, { children: emptyText ?? t("relation.noResults", { defaultValue: "No results." }) }),
2230
+ (0, react_jsx_runtime.jsx)(require_relation_create.CommandGroup, { children: effectiveOptions.map((opt) => {
2231
+ const isSelected = selected.has(opt.value);
2232
+ const Icon = opt.icon;
2233
+ return (0, react_jsx_runtime.jsxs)(require_relation_create.CommandItem, {
2234
+ value: opt.label,
2235
+ "data-testid": getTestId?.("option", opt.value),
2236
+ role: "option",
2237
+ "aria-selected": isSelected,
2238
+ "aria-checked": isSelected,
2239
+ onSelect: () => toggle(opt.value),
2240
+ children: [
2241
+ (0, react_jsx_runtime.jsx)("span", {
2242
+ className: require_use_theme.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"),
2243
+ "aria-hidden": "true",
2244
+ children: isSelected && (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconCheck, { className: "h-3.5 w-3.5" })
2245
+ }),
2246
+ Icon && (0, react_jsx_runtime.jsx)(Icon, {
2247
+ className: "mr-2 h-4 w-4 text-muted-foreground",
2248
+ "aria-hidden": "true"
2249
+ }),
2250
+ (0, react_jsx_runtime.jsxs)("span", {
2251
+ className: "flex min-w-0 flex-1 flex-col text-left",
2252
+ children: [(0, react_jsx_runtime.jsx)("span", { children: opt.label }), opt.summary !== void 0 && (0, react_jsx_runtime.jsx)("span", {
2253
+ className: "text-xs text-muted-foreground",
2254
+ children: opt.summary
2255
+ })]
2256
+ })
2257
+ ]
2258
+ }, opt.value);
2259
+ }) })
2260
+ ] }),
2261
+ clearable && selected.size > 0 && (0, react_jsx_runtime.jsx)("button", {
2262
+ type: "button",
2263
+ "data-testid": getTestId?.("clear"),
2264
+ onClick: () => onChange([]),
2265
+ className: "flex w-full items-center justify-center border-t px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
2266
+ children: chromeT("filters.clearAll", { defaultValue: "Clear filters" })
2267
+ })
2268
+ ]
2269
+ })
2270
+ })] });
2271
+ }
2272
+ //#endregion
2273
+ //#region src/list-kit/filter-builder/preset-filter-controls.tsx
2274
+ function PresetFilterControls(props) {
2275
+ const { presets, setPreset, testIdBase } = props;
2276
+ return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: presets.map((filter) => (0, react_jsx_runtime.jsx)(FacetedFilterPicker, {
2277
+ title: filter.label,
2278
+ ...filter.hint === void 0 ? {} : { hint: filter.hint },
2279
+ options: filter.options.map((option) => ({
2280
+ value: option.id,
2281
+ label: option.label,
2282
+ ...option.summary === void 0 ? {} : { summary: option.summary }
2283
+ })),
2284
+ selected: filter.selected,
2285
+ onChange: (next) => setPreset(filter.id, filter.options.map((option) => option.id).filter((id) => next.includes(id))),
2286
+ getTestId: (role, value) => `${testIdBase}:preset:${filter.id}:${role}${value === void 0 ? "" : `:${value}`}`
2287
+ }, filter.id)) });
2288
+ }
2289
+ //#endregion
1564
2290
  //#region src/list-kit/filter-builder/filter-builder.tsx
1565
2291
  const EMPTY_PINNED_FIELDS = Object.freeze([]);
1566
2292
  const EMPTY_PINNED_VALUE = Object.freeze([]);
1567
2293
  function FilterBuilder(props) {
1568
- const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, setPage, testIdBase } = props;
2294
+ const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, presets, setPreset, setPage, testIdBase } = props;
1569
2295
  const [open, setOpen] = (0, react.useState)(false);
1570
2296
  const [focusPath, setFocusPath] = (0, react.useState)(void 0);
1571
2297
  const [externalRemoval, setExternalRemoval] = (0, react.useState)(void 0);
@@ -1582,6 +2308,11 @@ function FilterBuilder(props) {
1582
2308
  setPinnedValue?.(next);
1583
2309
  };
1584
2310
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2311
+ presets !== void 0 && presets.length > 0 && setPreset !== void 0 && (0, react_jsx_runtime.jsx)(PresetFilterControls, {
2312
+ presets,
2313
+ setPreset,
2314
+ testIdBase
2315
+ }),
1585
2316
  (0, react_jsx_runtime.jsx)(PinnedFilterControls, {
1586
2317
  pinnedFields,
1587
2318
  value: pinnedValue,
@@ -1623,6 +2354,18 @@ Object.defineProperty(exports, "Badge", {
1623
2354
  return Badge;
1624
2355
  }
1625
2356
  });
2357
+ Object.defineProperty(exports, "DataTableFacetedFilter", {
2358
+ enumerable: true,
2359
+ get: function() {
2360
+ return DataTableFacetedFilter;
2361
+ }
2362
+ });
2363
+ Object.defineProperty(exports, "FacetedFilterPicker", {
2364
+ enumerable: true,
2365
+ get: function() {
2366
+ return FacetedFilterPicker;
2367
+ }
2368
+ });
1626
2369
  Object.defineProperty(exports, "FilterBadges", {
1627
2370
  enumerable: true,
1628
2371
  get: function() {
@@ -1647,12 +2390,36 @@ Object.defineProperty(exports, "FilterValueControl", {
1647
2390
  return FilterValueControl;
1648
2391
  }
1649
2392
  });
2393
+ Object.defineProperty(exports, "MetaPlaceholder", {
2394
+ enumerable: true,
2395
+ get: function() {
2396
+ return MetaPlaceholder;
2397
+ }
2398
+ });
1650
2399
  Object.defineProperty(exports, "PinnedFilterControls", {
1651
2400
  enumerable: true,
1652
2401
  get: function() {
1653
2402
  return PinnedFilterControls;
1654
2403
  }
1655
2404
  });
2405
+ Object.defineProperty(exports, "PresetFilterControls", {
2406
+ enumerable: true,
2407
+ get: function() {
2408
+ return PresetFilterControls;
2409
+ }
2410
+ });
2411
+ Object.defineProperty(exports, "ResolvedFieldDisplay", {
2412
+ enumerable: true,
2413
+ get: function() {
2414
+ return ResolvedFieldDisplay;
2415
+ }
2416
+ });
2417
+ Object.defineProperty(exports, "ResolvedFieldInput", {
2418
+ enumerable: true,
2419
+ get: function() {
2420
+ return ResolvedFieldInput;
2421
+ }
2422
+ });
1656
2423
  Object.defineProperty(exports, "Select", {
1657
2424
  enumerable: true,
1658
2425
  get: function() {
@@ -1761,29 +2528,65 @@ Object.defineProperty(exports, "badgeVariants", {
1761
2528
  return badgeVariants;
1762
2529
  }
1763
2530
  });
2531
+ Object.defineProperty(exports, "fieldDescription", {
2532
+ enumerable: true,
2533
+ get: function() {
2534
+ return fieldDescription;
2535
+ }
2536
+ });
1764
2537
  Object.defineProperty(exports, "formatDate", {
1765
2538
  enumerable: true,
1766
2539
  get: function() {
1767
2540
  return formatDate;
1768
2541
  }
1769
2542
  });
2543
+ Object.defineProperty(exports, "formatDateTime", {
2544
+ enumerable: true,
2545
+ get: function() {
2546
+ return formatDateTime;
2547
+ }
2548
+ });
1770
2549
  Object.defineProperty(exports, "formatNumber", {
1771
2550
  enumerable: true,
1772
2551
  get: function() {
1773
2552
  return formatNumber;
1774
2553
  }
1775
2554
  });
2555
+ Object.defineProperty(exports, "fromLocalDateTimeText", {
2556
+ enumerable: true,
2557
+ get: function() {
2558
+ return fromLocalDateTimeText;
2559
+ }
2560
+ });
1776
2561
  Object.defineProperty(exports, "loadLocale", {
1777
2562
  enumerable: true,
1778
2563
  get: function() {
1779
2564
  return loadLocale;
1780
2565
  }
1781
2566
  });
2567
+ Object.defineProperty(exports, "lowerLegacyField", {
2568
+ enumerable: true,
2569
+ get: function() {
2570
+ return lowerLegacyField;
2571
+ }
2572
+ });
1782
2573
  Object.defineProperty(exports, "saveLocale", {
1783
2574
  enumerable: true,
1784
2575
  get: function() {
1785
2576
  return saveLocale;
1786
2577
  }
1787
2578
  });
2579
+ Object.defineProperty(exports, "toLocalDateTimeText", {
2580
+ enumerable: true,
2581
+ get: function() {
2582
+ return toLocalDateTimeText;
2583
+ }
2584
+ });
2585
+ Object.defineProperty(exports, "useFieldMetaDiagnostic", {
2586
+ enumerable: true,
2587
+ get: function() {
2588
+ return useFieldMetaDiagnostic;
2589
+ }
2590
+ });
1788
2591
 
1789
- //# sourceMappingURL=filter-builder-nXqtM_h4.cjs.map
2592
+ //# sourceMappingURL=filter-builder-DFu0JP-1.cjs.map