@burojs/ui-shadcn 0.6.0 → 0.8.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 (158) hide show
  1. package/README.md +9 -0
  2. package/dist/bulk-summary-2HLgz7Il.cjs +169 -0
  3. package/dist/bulk-summary-2HLgz7Il.cjs.map +1 -0
  4. package/dist/bulk-summary-D6A0ua21.js +169 -0
  5. package/dist/bulk-summary-D6A0ua21.js.map +1 -0
  6. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs → candidates-relation-picker-C47mF260.cjs} +4 -4
  7. package/dist/{candidates-relation-picker-Cy0rTxvI.cjs.map → candidates-relation-picker-C47mF260.cjs.map} +1 -1
  8. package/dist/{candidates-relation-picker-B116Bmqi.js → candidates-relation-picker-CGXItMN0.js} +3 -3
  9. package/dist/{candidates-relation-picker-B116Bmqi.js.map → candidates-relation-picker-CGXItMN0.js.map} +1 -1
  10. package/dist/{check-confirm-dialog--gPFnEeg.cjs → check-confirm-dialog-BT04Mieo.cjs} +475 -107
  11. package/dist/check-confirm-dialog-BT04Mieo.cjs.map +1 -0
  12. package/dist/{check-confirm-dialog-bRT8lt0d.js → check-confirm-dialog-CtiRzOAt.js} +391 -108
  13. package/dist/check-confirm-dialog-CtiRzOAt.js.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-ByGhxLf_.cjs} +1021 -154
  19. package/dist/filter-builder-ByGhxLf_.cjs.map +1 -0
  20. package/dist/{filter-builder-Bhn-dhZV.js → filter-builder-z3Axzf9Y.js} +929 -140
  21. package/dist/filter-builder-z3Axzf9Y.js.map +1 -0
  22. package/dist/{flow-runtime-D3avVH0I.cjs → flow-runtime-BVFjMU5-.cjs} +64 -29
  23. package/dist/flow-runtime-BVFjMU5-.cjs.map +1 -0
  24. package/dist/{flow-runtime-s6lkRPKF.js → flow-runtime-DrUWyTS0.js} +65 -30
  25. package/dist/flow-runtime-DrUWyTS0.js.map +1 -0
  26. package/dist/{flow-screen-CCvgDI9G.js → flow-screen-3fk6J33y.js} +130 -87
  27. package/dist/flow-screen-3fk6J33y.js.map +1 -0
  28. package/dist/{flow-screen-Ci_Sik4Y.cjs → flow-screen-6y5E_HT6.cjs} +130 -87
  29. package/dist/flow-screen-6y5E_HT6.cjs.map +1 -0
  30. package/dist/index.cjs +1186 -950
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +631 -322
  33. package/dist/index.d.ts +631 -322
  34. package/dist/index.js +1100 -870
  35. package/dist/index.js.map +1 -1
  36. package/dist/{inline-flow-host-DV1et3c6.cjs → inline-flow-host-C4KmZIYE.cjs} +5 -5
  37. package/dist/inline-flow-host-C4KmZIYE.cjs.map +1 -0
  38. package/dist/{inline-flow-host-B6FI0ctQ.js → inline-flow-host-YnnvWjdU.js} +5 -5
  39. package/dist/inline-flow-host-YnnvWjdU.js.map +1 -0
  40. package/dist/{candidates-gate-D33jXLHO.cjs → lazy-relation-picker-dialog-BAKBRn3V.cjs} +10 -10
  41. package/dist/lazy-relation-picker-dialog-BAKBRn3V.cjs.map +1 -0
  42. package/dist/{candidates-gate-Bb70LPAy.js → lazy-relation-picker-dialog-DN4bvQfg.js} +11 -11
  43. package/dist/lazy-relation-picker-dialog-DN4bvQfg.js.map +1 -0
  44. package/dist/{page-flow-route-i3ZfJ1sd.js → page-flow-route-CtEfqAvU.js} +35 -23
  45. package/dist/page-flow-route-CtEfqAvU.js.map +1 -0
  46. package/dist/{page-flow-route-hdnULWqd.cjs → page-flow-route-DEjAxHe3.cjs} +42 -30
  47. package/dist/page-flow-route-DEjAxHe3.cjs.map +1 -0
  48. package/dist/{place-node-NraNYKPx.js → place-node-BdxT-30h.js} +1980 -1041
  49. package/dist/place-node-BdxT-30h.js.map +1 -0
  50. package/dist/{place-node-C5SmIAYU.cjs → place-node-Bhl8B3fF.cjs} +2038 -1087
  51. package/dist/place-node-Bhl8B3fF.cjs.map +1 -0
  52. package/dist/{related-list-cards-CFq3meUn.cjs → related-list-cards-Bc_vfCE_.cjs} +9 -4
  53. package/dist/{related-list-cards-CFq3meUn.cjs.map → related-list-cards-Bc_vfCE_.cjs.map} +1 -1
  54. package/dist/{related-list-cards-BWZ9GfOG.js → related-list-cards-BvkD5OcC.js} +9 -4
  55. package/dist/{related-list-cards-BWZ9GfOG.js.map → related-list-cards-BvkD5OcC.js.map} +1 -1
  56. package/dist/related-list-timeline-DCrwN9oO.js +167 -0
  57. package/dist/related-list-timeline-DCrwN9oO.js.map +1 -0
  58. package/dist/related-list-timeline-k0DtnxTs.cjs +167 -0
  59. package/dist/related-list-timeline-k0DtnxTs.cjs.map +1 -0
  60. package/dist/{related-rows-ea43qhhy.cjs → related-rows-BW9Jr07T.cjs} +27 -16
  61. package/dist/related-rows-BW9Jr07T.cjs.map +1 -0
  62. package/dist/{related-rows-o0_t-Yce.js → related-rows-CPE-9FFr.js} +25 -14
  63. package/dist/related-rows-CPE-9FFr.js.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-BlrGRwMV.js} +210 -104
  69. package/dist/relation-many-picker-BlrGRwMV.js.map +1 -0
  70. package/dist/{relation-many-picker-C8zFEjwd.cjs → relation-many-picker-Br-zBHxT.cjs} +218 -112
  71. package/dist/relation-many-picker-Br-zBHxT.cjs.map +1 -0
  72. package/dist/{relation-picker-gag0qSR5.cjs → relation-picker-ADjxI_TI.cjs} +36 -73
  73. package/dist/relation-picker-ADjxI_TI.cjs.map +1 -0
  74. package/dist/{relation-picker-dialog-B6nIiJBf.js → relation-picker-dialog-CyKliBkN.js} +134 -36
  75. package/dist/relation-picker-dialog-CyKliBkN.js.map +1 -0
  76. package/dist/{relation-picker-dialog-0IzkjmiA.cjs → relation-picker-dialog-DimVQF9Y.cjs} +133 -35
  77. package/dist/relation-picker-dialog-DimVQF9Y.cjs.map +1 -0
  78. package/dist/{relation-picker-Z0ZJJ5uS.js → relation-picker-x7P5HKie.js} +30 -61
  79. package/dist/relation-picker-x7P5HKie.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-3RUf9d1j.js → resource-page-router-BRpUnhay.js} +634 -264
  85. package/dist/resource-page-router-BRpUnhay.js.map +1 -0
  86. package/dist/{resource-page-router-PXfMW9nh.cjs → resource-page-router-qEd2xb55.cjs} +694 -312
  87. package/dist/resource-page-router-qEd2xb55.cjs.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/dist/use-record-subtitle-bfwIoUme.cjs +70 -0
  105. package/dist/use-record-subtitle-bfwIoUme.cjs.map +1 -0
  106. package/dist/use-record-subtitle-gIaCGgbI.js +53 -0
  107. package/dist/use-record-subtitle-gIaCGgbI.js.map +1 -0
  108. package/package.json +11 -11
  109. package/dist/bulk-summary-CwSd6Yjb.cjs +0 -108
  110. package/dist/bulk-summary-CwSd6Yjb.cjs.map +0 -1
  111. package/dist/bulk-summary-GxMDP4bw.js +0 -108
  112. package/dist/bulk-summary-GxMDP4bw.js.map +0 -1
  113. package/dist/candidates-gate-Bb70LPAy.js.map +0 -1
  114. package/dist/candidates-gate-D33jXLHO.cjs.map +0 -1
  115. package/dist/check-confirm-dialog--gPFnEeg.cjs.map +0 -1
  116. package/dist/check-confirm-dialog-bRT8lt0d.js.map +0 -1
  117. package/dist/dialog-B_rt9S1c.js.map +0 -1
  118. package/dist/dialog-DRNUq9EA.cjs.map +0 -1
  119. package/dist/filter-builder-Bhn-dhZV.js.map +0 -1
  120. package/dist/filter-builder-nXqtM_h4.cjs.map +0 -1
  121. package/dist/flow-runtime-D3avVH0I.cjs.map +0 -1
  122. package/dist/flow-runtime-s6lkRPKF.js.map +0 -1
  123. package/dist/flow-screen-CCvgDI9G.js.map +0 -1
  124. package/dist/flow-screen-Ci_Sik4Y.cjs.map +0 -1
  125. package/dist/inline-flow-host-B6FI0ctQ.js.map +0 -1
  126. package/dist/inline-flow-host-DV1et3c6.cjs.map +0 -1
  127. package/dist/page-flow-route-hdnULWqd.cjs.map +0 -1
  128. package/dist/page-flow-route-i3ZfJ1sd.js.map +0 -1
  129. package/dist/place-node-C5SmIAYU.cjs.map +0 -1
  130. package/dist/place-node-NraNYKPx.js.map +0 -1
  131. package/dist/related-list-timeline-CCzl71aA.cjs +0 -142
  132. package/dist/related-list-timeline-CCzl71aA.cjs.map +0 -1
  133. package/dist/related-list-timeline-yrPsjA3F.js +0 -142
  134. package/dist/related-list-timeline-yrPsjA3F.js.map +0 -1
  135. package/dist/related-rows-ea43qhhy.cjs.map +0 -1
  136. package/dist/related-rows-o0_t-Yce.js.map +0 -1
  137. package/dist/relation-create-IA40t1hi.cjs +0 -364
  138. package/dist/relation-create-IA40t1hi.cjs.map +0 -1
  139. package/dist/relation-create-h6F9B4C4.js +0 -339
  140. package/dist/relation-create-h6F9B4C4.js.map +0 -1
  141. package/dist/relation-many-picker-C8zFEjwd.cjs.map +0 -1
  142. package/dist/relation-many-picker-bvkjkv-k.js.map +0 -1
  143. package/dist/relation-picker-Z0ZJJ5uS.js.map +0 -1
  144. package/dist/relation-picker-dialog-0IzkjmiA.cjs.map +0 -1
  145. package/dist/relation-picker-dialog-B6nIiJBf.js.map +0 -1
  146. package/dist/relation-picker-gag0qSR5.cjs.map +0 -1
  147. package/dist/resource-page-router-3RUf9d1j.js.map +0 -1
  148. package/dist/resource-page-router-PXfMW9nh.cjs.map +0 -1
  149. package/dist/search-access-CPPmfuvy.js.map +0 -1
  150. package/dist/search-access-Dugvttlg.cjs.map +0 -1
  151. package/dist/shell-BPlk8hEa.js +0 -205
  152. package/dist/shell-BPlk8hEa.js.map +0 -1
  153. package/dist/shell-DxhlsPwm.cjs +0 -271
  154. package/dist/shell-DxhlsPwm.cjs.map +0 -1
  155. package/dist/toaster-C02XbB9r.js.map +0 -1
  156. package/dist/toaster-Cr51X7bz.cjs.map +0 -1
  157. package/dist/use-dialog-filter-state-C--oMAZG.js.map +0 -1
  158. package/dist/use-dialog-filter-state-Dhe8PcB5.cjs.map +0 -1
@@ -1,15 +1,17 @@
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, canonicalInstant, canonicalResourceKey, convertValueForOp, declaredText, enumValueText, formatEntityRef, formatTimeValue, instantToWall, isCalendarDate, isCompletePredicate, isFilterGroup, isWallTime, opArity, resolveEnumLabel, resolveSurfaceUi, resolveTimeZone, wallToInstant } 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, useTimeContext, useTimeZone } 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";
14
+ import { normaliseFieldZone } from "@burojs/core/internal";
13
15
  import * as SelectPrimitive from "@radix-ui/react-select";
14
16
  //#region src/layout/language-storage.ts
15
17
  function loadLocale(storageKey = DEFAULT_LANGUAGE_STORAGE_KEY) {
@@ -27,6 +29,536 @@ function saveLocale(code, storageKey = DEFAULT_LANGUAGE_STORAGE_KEY) {
27
29
  } catch {}
28
30
  }
29
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
+ "zone",
104
+ "texts",
105
+ "options",
106
+ "items",
107
+ "properties",
108
+ "additionalProperties",
109
+ "variants"
110
+ ]);
111
+ function ownData(value, key) {
112
+ if (value === null || typeof value !== "object" && typeof value !== "function") return { present: false };
113
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
114
+ if (descriptor === void 0 || !Object.prototype.propertyIsEnumerable.call(value, key) || !("value" in descriptor)) return { present: false };
115
+ return {
116
+ present: true,
117
+ value: descriptor.value
118
+ };
119
+ }
120
+ function ownString(value, key) {
121
+ const candidate = ownData(value, key).value;
122
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : void 0;
123
+ }
124
+ function ownSelection(value, key) {
125
+ const candidate = ownData(value, key).value;
126
+ if (typeof candidate === "string") return candidate.length > 0 ? candidate : void 0;
127
+ return candidate !== null && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : void 0;
128
+ }
129
+ function projectUiSelection(input) {
130
+ const selection = {};
131
+ const inputId = ownSelection(input, "input");
132
+ const displayId = ownSelection(input, "display");
133
+ const layout = ownData(input, "layout").value;
134
+ if (inputId !== void 0) selection.input = inputId;
135
+ if (displayId !== void 0) selection.display = displayId;
136
+ if (Array.isArray(layout)) selection.layout = layout;
137
+ return Object.keys(selection).length === 0 ? void 0 : Object.freeze(selection);
138
+ }
139
+ function projectFieldDeclaration(input) {
140
+ const type = ownString(input, "type");
141
+ if (type === void 0) return void 0;
142
+ const projected = { type };
143
+ for (const key of SEMANTIC_KEYS) {
144
+ if (key === "type" || key === "items" || key === "properties" || key === "variants") continue;
145
+ const candidate = ownData(input, key);
146
+ if (candidate.present && candidate.value !== void 0) projected[key] = candidate.value;
147
+ }
148
+ const ui = projectUiSelection(ownData(input, "ui").value);
149
+ if (ui !== void 0) projected.ui = ui;
150
+ if (type === "array") {
151
+ const item = projectFieldDeclaration(ownData(input, "items").value);
152
+ if (item !== void 0) projected.items = item;
153
+ }
154
+ if (type === "object") {
155
+ const properties = ownData(input, "properties").value;
156
+ if (Array.isArray(properties)) {
157
+ const output = {};
158
+ for (let index = 0; index < properties.length; index += 1) {
159
+ const entry = ownData(properties, index).value;
160
+ const name = ownString(entry, "name");
161
+ const child = projectFieldDeclaration(entry);
162
+ if (name !== void 0 && child !== void 0) output[name] = child;
163
+ }
164
+ projected.properties = Object.freeze(output);
165
+ } else if (properties !== null && typeof properties === "object") {
166
+ const output = {};
167
+ for (const key of Object.keys(properties)) {
168
+ const child = projectFieldDeclaration(ownData(properties, key).value);
169
+ if (child !== void 0) output[key] = child;
170
+ }
171
+ projected.properties = Object.freeze(output);
172
+ }
173
+ }
174
+ if (type === "union") {
175
+ const variants = ownData(input, "variants").value;
176
+ if (Array.isArray(variants)) {
177
+ const output = [];
178
+ for (let index = 0; index < variants.length; index += 1) {
179
+ const child = projectFieldDeclaration(ownData(variants, index).value);
180
+ if (child !== void 0) output.push(child);
181
+ }
182
+ projected.variants = Object.freeze(output);
183
+ }
184
+ }
185
+ return Object.freeze(projected);
186
+ }
187
+ function projectUiHints(input) {
188
+ if (input === null || typeof input !== "object" || Array.isArray(input)) return void 0;
189
+ const projected = {};
190
+ for (const key of Object.keys(input)) {
191
+ const candidate = ownData(input, key);
192
+ if (candidate.present) projected[key] = candidate.value;
193
+ }
194
+ return Object.freeze(projected);
195
+ }
196
+ function enumValueOptions(field) {
197
+ const own = ownData(field, "values").value;
198
+ const values = Array.isArray(own) ? own : ownData(ownData(field, "ui").value, "values").value;
199
+ if (!Array.isArray(values)) return void 0;
200
+ const options = values.filter((value) => typeof value === "string").map((value) => Object.freeze({ value }));
201
+ return options.length === 0 ? void 0 : Object.freeze(options);
202
+ }
203
+ function lowerLegacyField(field) {
204
+ const declaration = projectFieldDeclaration(ownData(field, "declaration").value);
205
+ if (declaration !== void 0) return declaration;
206
+ const direct = projectFieldDeclaration(field);
207
+ const kind = ownString(field, "kind");
208
+ const mapping = kind === void 0 ? void 0 : LEGACY_KIND_DECLARATIONS[kind];
209
+ if (direct !== void 0) {
210
+ const format = direct.format ?? mapping?.format ?? kind;
211
+ return format === void 0 ? direct : Object.freeze({
212
+ ...direct,
213
+ format
214
+ });
215
+ }
216
+ const ui = projectUiHints(ownData(field, "ui").value);
217
+ const type = kind === "file" && ui?.multiple !== true ? "unknown" : mapping?.type ?? "unknown";
218
+ const format = ownString(field, "format") ?? mapping?.format ?? kind;
219
+ const items = type === "array" ? projectFieldDeclaration(ownData(field, "items").value) ?? mapping?.items ?? STRING_ITEM : void 0;
220
+ const meta = ownData(field, "meta");
221
+ const texts = ownData(field, "texts");
222
+ const zone = ownData(field, "zone");
223
+ const options = kind === "enum" ? enumValueOptions(field) : void 0;
224
+ const required = ownData(field, "required");
225
+ const nullable = ownData(field, "nullable");
226
+ const opts = ownData(field, "opts").value;
227
+ const optionRequired = ownData(opts, "required");
228
+ const optionNullable = ownData(opts, "nullable");
229
+ const requiredValue = required.present ? required.value : optionRequired.value;
230
+ const nullableValue = nullable.present ? nullable.value : optionNullable.value;
231
+ return Object.freeze({
232
+ type,
233
+ ...format === void 0 ? {} : { format },
234
+ ...items === void 0 ? {} : { items },
235
+ ...meta.present && meta.value !== void 0 ? { meta: meta.value } : {},
236
+ ...options === void 0 ? {} : { options },
237
+ ...texts.present && texts.value !== void 0 ? { texts: texts.value } : {},
238
+ ...zone.present && zone.value !== void 0 ? { zone: zone.value } : {},
239
+ ...requiredValue === true ? { required: true } : {},
240
+ ...nullableValue === true ? { nullable: true } : {}
241
+ });
242
+ }
243
+ function lowerLegacyFieldSource(field) {
244
+ const declaration = lowerLegacyField(field);
245
+ const ui = projectUiHints(ownData(field, "ui").value);
246
+ if (ui === void 0) return declaration;
247
+ return Object.freeze({
248
+ ...declaration,
249
+ ui
250
+ });
251
+ }
252
+ function fieldDescription(field) {
253
+ const declaration = field?.declaration;
254
+ return declaredText("field", declaration, "description") ?? declaredText("field", field, "description");
255
+ }
256
+ //#endregion
257
+ //#region src/fields/resolved-field.tsx
258
+ const EMPTY = Object.freeze({});
259
+ const EMPTY_ISSUES = Object.freeze([]);
260
+ const EMPTY_OPTIONS = Object.freeze([]);
261
+ function canonical(field) {
262
+ return lowerLegacyField(field);
263
+ }
264
+ function useLoweredField(source) {
265
+ return useMemo(() => {
266
+ const sourceAtEdge = lowerLegacyFieldSource(source);
267
+ return {
268
+ sourceAtEdge,
269
+ field: canonical(sourceAtEdge),
270
+ ui: sourceAtEdge.ui ?? EMPTY
271
+ };
272
+ }, [source]);
273
+ }
274
+ const warnedObjectLabels = new Set();
275
+ function optionsFor(field, name) {
276
+ if (Array.isArray(field.options)) return field.options;
277
+ const candidate = field.meta?.options;
278
+ if (!Array.isArray(candidate)) return EMPTY_OPTIONS;
279
+ const output = [];
280
+ for (const item of candidate) {
281
+ if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
282
+ const raw = item;
283
+ if (typeof raw.value !== "string" && typeof raw.value !== "number" && typeof raw.value !== "boolean" && raw.value !== null) continue;
284
+ const { value, label, description, ...legacyMeta } = raw;
285
+ if (typeof label !== "string" && process.env.NODE_ENV !== "production" && !warnedObjectLabels.has(`${name}:${value}`)) {
286
+ warnedObjectLabels.add(`${name}:${value}`);
287
+ 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).`);
288
+ }
289
+ output.push(Object.freeze({
290
+ value,
291
+ label: typeof label === "string" ? label : String(value),
292
+ ...typeof description === "string" ? { description } : {},
293
+ ...Object.keys(legacyMeta).length === 0 ? {} : { meta: Object.freeze(legacyMeta) }
294
+ }));
295
+ }
296
+ return Object.freeze(output);
297
+ }
298
+ function useContextOptions(field, name, meta, ui, resource) {
299
+ const legacy = field.meta?.options;
300
+ const options = useMemo(() => optionsFor(field, name), [
301
+ field.options,
302
+ legacy,
303
+ name
304
+ ]);
305
+ return useResolvedFieldOptions({
306
+ name,
307
+ meta,
308
+ ui,
309
+ texts: field.texts
310
+ }, options, resource.id);
311
+ }
312
+ function useContextTexts(field, name, resolved, resource) {
313
+ return useImplementationTexts({
314
+ fieldName: name,
315
+ fieldTexts: field.texts,
316
+ id: resolved.id,
317
+ implementation: resolved.implementation
318
+ }, resource.id);
319
+ }
320
+ function useFieldRuntimeContext(resource, record, values, metaSources) {
321
+ const locale = useLocale();
322
+ const caps = useI18nCaps(canonicalResourceKey(resource));
323
+ const metaSourcesOut = useFieldMetaSources({
324
+ record,
325
+ values,
326
+ extra: metaSources
327
+ });
328
+ const scopeState = metaSourcesOut.scope;
329
+ const scope = scopeState === void 0 ? void 0 : scopeValueOf(scopeState);
330
+ return useMemo(() => Object.freeze({
331
+ i18n: Object.freeze({
332
+ locale,
333
+ has: caps.has,
334
+ t: caps.t
335
+ }),
336
+ sources: Object.freeze({
337
+ record: record ?? EMPTY,
338
+ values: values ?? EMPTY,
339
+ scope: scope ?? EMPTY
340
+ }),
341
+ metaSources: metaSourcesOut
342
+ }), [
343
+ caps,
344
+ locale,
345
+ record,
346
+ scope,
347
+ values,
348
+ metaSourcesOut
349
+ ]);
350
+ }
351
+ function useFieldMetaDiagnostic(state, resource, name, field, surface, entry) {
352
+ const reported = useRef(void 0);
353
+ const reason = state.status === "failed" ? state.reason : void 0;
354
+ useEffect(() => {
355
+ if (reason === void 0 || reported.current === reason || process.env.NODE_ENV === "production") return;
356
+ reported.current = reason;
357
+ const implementation = resolveSurfaceUi(field, surface, entry).use ?? field.format ?? field.type;
358
+ console.error(`[burojs] field.meta-invalid: ${formatEntityRef(resource)}.${name} (${implementation}): ${reason}`);
359
+ }, [
360
+ reason,
361
+ resource,
362
+ name,
363
+ field,
364
+ surface,
365
+ entry
366
+ ]);
367
+ }
368
+ function MetaPlaceholder({ state }) {
369
+ const t = useOptionalT();
370
+ if (state.status === "pending") return jsx(Skeleton, {
371
+ "data-buro-skeleton": "",
372
+ "data-buro-field-meta": "pending",
373
+ className: "h-9 w-full"
374
+ });
375
+ return jsx("div", {
376
+ role: "alert",
377
+ "data-buro-field-meta": "failed",
378
+ className: "rounded-md border border-dashed px-3 py-2 text-sm text-muted-foreground",
379
+ children: t("field.misconfigured", { defaultValue: "This field is misconfigured" })
380
+ });
381
+ }
382
+ function useFieldImplementationDiagnostic(diagnostic) {
383
+ const reported = useRef(void 0);
384
+ useEffect(() => {
385
+ if (diagnostic === void 0 || reported.current === diagnostic || process.env.NODE_ENV === "production") return;
386
+ reported.current = diagnostic;
387
+ console.warn("[buro/ui-shadcn] missing-field-implementation; rendering fallback.", diagnostic);
388
+ }, [diagnostic]);
389
+ }
390
+ function ResolvedFieldDisplay({ resource, name, field: source, value, record, testId, fallback, presentation, metaSources, uiSurface = "display", columnEntry, absentPaths, pathStatus }) {
391
+ const { sourceAtEdge, field, ui } = useLoweredField(source);
392
+ const surfaceField = useMemo(() => sourceAtEdge.ui === void 0 ? field : Object.freeze({
393
+ ...field,
394
+ ui
395
+ }), [
396
+ sourceAtEdge,
397
+ field,
398
+ ui
399
+ ]);
400
+ const resolved = useFieldImplementation({
401
+ field: surfaceField,
402
+ surface: "display",
403
+ uiSurface,
404
+ ...columnEntry === void 0 ? {} : { uiEntry: columnEntry }
405
+ });
406
+ const runtimeContext = useFieldRuntimeContext(resource, record, record, metaSources);
407
+ const metaState = useFieldMeta(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
408
+ const textField = useMemo(() => Object.freeze({
409
+ ...surfaceField,
410
+ name
411
+ }), [surfaceField, name]);
412
+ const text = useFieldDisplayText(textField, value, {
413
+ surface: uiSurface,
414
+ ...columnEntry === void 0 ? {} : { entry: columnEntry },
415
+ resource: canonicalResourceKey(resource),
416
+ ...record === void 0 ? {} : { record }
417
+ });
418
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
419
+ const texts = useContextTexts(field, name, resolved, resource);
420
+ const dateDisplay = resolveSurfaceUi(surfaceField, uiSurface, columnEntry).dateDisplay;
421
+ const contextUi = useMemo(() => dateDisplay === void 0 ? ui : Object.freeze({
422
+ ...ui,
423
+ display: Object.freeze({
424
+ ...typeof ui.display === "object" && ui.display !== null ? ui.display : {},
425
+ ...dateDisplay
426
+ })
427
+ }), [ui, dateDisplay]);
428
+ useFieldMetaDiagnostic(metaState, resource, name, surfaceField, uiSurface, columnEntry);
429
+ useFieldImplementationDiagnostic(resolved.diagnostic);
430
+ if (resolved.Component === void 0) return jsx(Fragment$1, { children: fallback });
431
+ if (metaState.status !== "ready") return jsx(MetaPlaceholder, { state: metaState });
432
+ const Component = resolved.Component;
433
+ const context = {
434
+ owner: resource,
435
+ resource,
436
+ field,
437
+ path: Object.freeze([name]),
438
+ ...absentPaths === void 0 || absentPaths.length === 0 ? {} : { absentPaths },
439
+ ...pathStatus === void 0 ? {} : { pathStatus },
440
+ surface: "display",
441
+ presentation: presentation ?? "default",
442
+ record,
443
+ meta: metaState.meta,
444
+ ui: contextUi,
445
+ options,
446
+ texts,
447
+ ...text === void 0 ? {} : { text },
448
+ i18n: runtimeContext.i18n,
449
+ sources: runtimeContext.sources,
450
+ pending: false,
451
+ touched: false,
452
+ issues: EMPTY_ISSUES,
453
+ accessibility: EMPTY,
454
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ display: testId })
455
+ };
456
+ if (resolved.multiple) return createElement(Component, {
457
+ ...context,
458
+ multiple: true,
459
+ value: Array.isArray(value) ? value : []
460
+ });
461
+ return createElement(Component, {
462
+ ...context,
463
+ multiple: false,
464
+ value
465
+ });
466
+ }
467
+ 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, optionSubtitle, link, metaSources, baseline, fallback, absentPaths, pathStatus }) {
468
+ const { sourceAtEdge, field: base } = useLoweredField(source);
469
+ const field = useMemo(() => required === void 0 || required === base.required ? base : Object.freeze({
470
+ ...base,
471
+ required
472
+ }), [base, required]);
473
+ const ui = useMemo(() => Object.freeze({
474
+ ...sourceAtEdge.ui ?? EMPTY,
475
+ ...placeholder === void 0 ? {} : { placeholder }
476
+ }), [sourceAtEdge, placeholder]);
477
+ const inputField = useMemo(() => ({
478
+ ...field,
479
+ ui
480
+ }), [field, ui]);
481
+ const resolved = useFieldImplementation({
482
+ field: inputField,
483
+ surface: "input"
484
+ });
485
+ const runtimeContext = useFieldRuntimeContext(resource, record, form, metaSources);
486
+ const metaState = useFieldMeta(field, resolved.implementation, runtimeContext.metaSources, resolved.params);
487
+ const options = useContextOptions(field, name, metaState.status === "ready" ? metaState.meta : void 0, ui, resource);
488
+ const texts = useContextTexts(field, name, resolved, resource);
489
+ useFieldMetaDiagnostic(metaState, resource, name, inputField, "input");
490
+ useFieldImplementationDiagnostic(resolved.diagnostic);
491
+ if (resolved.Component === void 0) return jsx(Fragment$1, { children: fallback });
492
+ if (metaState.status !== "ready") return jsx(MetaPlaceholder, { state: metaState });
493
+ const Component = resolved.Component;
494
+ const issues = suppliedIssues ?? (errorMessage == null ? EMPTY_ISSUES : Object.freeze([Object.freeze({
495
+ code: "ui.field-error",
496
+ message: {
497
+ key: "ui.field-error",
498
+ default: errorMessage
499
+ },
500
+ path: Object.freeze([]),
501
+ source: "field",
502
+ severity: "error"
503
+ })]));
504
+ const context = {
505
+ owner: resource,
506
+ resource,
507
+ field,
508
+ path: Object.freeze([name]),
509
+ ...absentPaths === void 0 || absentPaths.length === 0 ? {} : { absentPaths },
510
+ ...pathStatus === void 0 ? {} : { pathStatus },
511
+ surface: "input",
512
+ presentation: "default",
513
+ record,
514
+ form,
515
+ meta: metaState.meta,
516
+ ui,
517
+ options,
518
+ texts,
519
+ i18n: runtimeContext.i18n,
520
+ sources: runtimeContext.sources,
521
+ pending,
522
+ touched,
523
+ issues,
524
+ accessibility: Object.freeze({
525
+ input: inputId ?? name,
526
+ label: labelId,
527
+ description: descriptionId,
528
+ error: errorId
529
+ }),
530
+ testIds: testId === void 0 ? EMPTY : Object.freeze({ input: testId })
531
+ };
532
+ if (resolved.multiple) return createElement(Component, {
533
+ ...context,
534
+ multiple: true,
535
+ value: Array.isArray(value) ? value : [],
536
+ onChange,
537
+ onBlur,
538
+ disabled,
539
+ relationSeeds,
540
+ fixedFilters,
541
+ optionSubtitle,
542
+ link,
543
+ metaSources: runtimeContext.metaSources,
544
+ ...baseline === void 0 ? {} : { baseline }
545
+ });
546
+ return createElement(Component, {
547
+ ...context,
548
+ multiple: false,
549
+ value,
550
+ onChange,
551
+ onBlur,
552
+ disabled,
553
+ relationSeeds,
554
+ fixedFilters,
555
+ optionSubtitle,
556
+ link,
557
+ metaSources: runtimeContext.metaSources,
558
+ ...baseline === void 0 ? {} : { baseline }
559
+ });
560
+ }
561
+ //#endregion
30
562
  //#region src/primitives/badge.tsx
31
563
  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
564
  variants: { variant: {
@@ -104,11 +636,11 @@ const SelectGroup = SelectPrimitive.Group;
104
636
  const SelectValue = SelectPrimitive.Value;
105
637
  const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => jsxs(SelectPrimitive.Trigger, {
106
638
  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),
639
+ 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
640
  ...props,
109
641
  children: [children, jsx(SelectPrimitive.Icon, {
110
642
  asChild: true,
111
- children: jsx(IconChevronDown, { className: "h-4 w-4 opacity-50" })
643
+ children: jsx(IconChevronDown, { className: "h-4 w-4 shrink-0 opacity-50" })
112
644
  })]
113
645
  }));
114
646
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
@@ -147,15 +679,24 @@ const SelectLabel = React.forwardRef(({ className, ...props }, ref) => jsx(Selec
147
679
  ...props
148
680
  }));
149
681
  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
- }));
682
+ const SelectItem = React.forwardRef(({ className, children, description, ...props }, ref) => {
683
+ const hasDescription = description !== void 0 && description !== null;
684
+ return jsxs(SelectPrimitive.Item, {
685
+ ref,
686
+ 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),
687
+ ...props,
688
+ children: [jsx("span", {
689
+ className: cn("absolute left-2 flex h-3.5 w-3.5 items-center justify-center", hasDescription && "top-[9px]"),
690
+ children: jsx(SelectPrimitive.ItemIndicator, { children: jsx(IconCheck, { className: "h-4 w-4" }) })
691
+ }), !hasDescription ? jsx(SelectPrimitive.ItemText, { children }) : jsxs("span", {
692
+ className: "flex min-w-0 flex-col gap-0.5",
693
+ children: [jsx(SelectPrimitive.ItemText, { children }), jsx("span", {
694
+ className: "text-xs leading-snug text-muted-foreground",
695
+ children: description
696
+ })]
697
+ })]
698
+ });
699
+ });
159
700
  SelectItem.displayName = SelectPrimitive.Item.displayName;
160
701
  const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => jsx(SelectPrimitive.Separator, {
161
702
  ref,
@@ -168,8 +709,6 @@ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
168
709
  function localeTag(locale) {
169
710
  return locale || loadLocale() || "en-US";
170
711
  }
171
- const dateCache = new Map();
172
- const dateTimeCache = new Map();
173
712
  const numberCache = new Map();
174
713
  function cached(cache, key, make) {
175
714
  const hit = cache.get(key);
@@ -183,24 +722,6 @@ function cached(cache, key, make) {
183
722
  cache.set(key, made);
184
723
  return made;
185
724
  }
186
- function formatDate(d, locale) {
187
- const tag = localeTag(locale);
188
- return cached(dateCache, tag, (t) => new Intl.DateTimeFormat(t, {
189
- year: "numeric",
190
- month: "short",
191
- day: "numeric"
192
- })).format(d);
193
- }
194
- function formatDateTime(d, locale) {
195
- const tag = localeTag(locale);
196
- return cached(dateTimeCache, tag, (t) => new Intl.DateTimeFormat(t, {
197
- year: "numeric",
198
- month: "short",
199
- day: "numeric",
200
- hour: "2-digit",
201
- minute: "2-digit"
202
- })).format(d);
203
- }
204
725
  function formatNumber(n, locale) {
205
726
  const tag = localeTag(locale);
206
727
  return cached(numberCache, tag, (t) => new Intl.NumberFormat(t)).format(n);
@@ -208,31 +729,31 @@ function formatNumber(n, locale) {
208
729
  //#endregion
209
730
  //#region src/list-kit/filter-builder/describe-row.ts
210
731
  const MAX_DESCRIBE_DEPTH = 2;
211
- function describeValue(value, t, spec, formatValue) {
732
+ function describeValue(value, chromeT, spec, formatValue) {
212
733
  if (value === void 0) return null;
213
- if (Array.isArray(value)) return t("filters.selectedCount", { count: value.length }, `${value.length} selected`);
734
+ if (Array.isArray(value)) return chromeT("filters.selectedCount", { count: value.length }, `${value.length} selected`);
214
735
  const optionLabel = spec?.options?.find((o) => o.value === String(value))?.label;
215
736
  if (optionLabel !== void 0) return optionLabel;
216
737
  if (spec && formatValue) {
217
- const formatted = formatValue(spec.kind, value);
738
+ const formatted = formatValue(spec.kind, value, spec.zone);
218
739
  if (formatted !== void 0) return formatted;
219
740
  }
220
741
  return String(value);
221
742
  }
222
- function describeAt(row, available, t, depth, formatValue) {
743
+ function describeAt(row, available, chromeT, depth, formatValue) {
223
744
  if (isFilterGroup(row)) {
224
745
  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} `)})`;
746
+ const joinLabel = chromeT(`filters.${row.join}`, void 0, row.join);
747
+ return `(${row.rows.map((child) => describeAt(child, available, chromeT, depth + 1, formatValue)).join(` ${joinLabel} `)})`;
227
748
  }
228
749
  const spec = available.find((s) => s.field === row.field);
229
750
  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);
751
+ const opLabel = chromeT(`filters.operators.${row.op}`, void 0, row.op);
752
+ const valueText = opArity(row.op) === "none" ? null : describeValue(row.value, chromeT, spec, formatValue);
232
753
  return valueText === null ? `${label} ${opLabel}` : `${label} ${opLabel} ${valueText}`;
233
754
  }
234
- function describeRow(row, available, t, formatValue) {
235
- return describeAt(row, available, t, 1, formatValue);
755
+ function describeRow(row, available, chromeT, formatValue) {
756
+ return describeAt(row, available, chromeT, 1, formatValue);
236
757
  }
237
758
  function relationLabelKey(to, by, value) {
238
759
  return `${by === void 0 ? to : `${to}#${by}`}::${value}`;
@@ -365,23 +886,33 @@ function badgeKey(row, index) {
365
886
  if (isFilterGroup(row)) return `${index}:group:${row.join}`;
366
887
  return `${index}:${row.field}:${row.op}`;
367
888
  }
889
+ const BADGE_ROW = "inline-flex max-w-full items-center gap-1 align-middle";
890
+ 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
891
  function FilterBadges(props) {
369
892
  const { group, setGroup, available, fixed, testIdBase, onOpenAt, onRemoved, pinnedFields = [], pinnedValue = [], setPinnedValue } = props;
370
- const t = useOptionalT();
371
- const tt = (key, params, fallback) => t(key, {
893
+ const chromeT = useChromeT();
894
+ const locale = useOptionalLocale();
895
+ const viewer = useTimeZone();
896
+ const timeContext = useTimeContext();
897
+ const tt = (key, params, fallback) => chromeT(key, {
372
898
  params,
373
899
  ...typeof params?.count === "number" ? { count: params.count } : {},
374
900
  defaultValue: fallback
375
901
  });
376
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
902
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
377
903
  const { enumLabels, relationLabels, onEnumResolved, onRelationResolved } = useFormatValueMaps();
378
- const formatValue = (kind, value) => {
904
+ const formatValue = (kind, value, fieldZone) => {
379
905
  if (kind.kind === "enum") return enumLabels[kind.enumName]?.[String(value)];
380
906
  if (kind.kind === "relation") return relationLabels[relationLabelKey(kind.to, kind.by, String(value))];
381
- if (kind.kind === "date") {
382
- const d = new Date(String(value));
383
- if (Number.isNaN(d.getTime())) return void 0;
384
- return kind.time ? formatDateTime(d) : formatDate(d);
907
+ if (kind.kind === "date" && viewer.status === "ready") {
908
+ const zone = resolveTimeZone(timeContext.levels, fieldZone, timeContext.sources);
909
+ if (zone.status === "pending") return void 0;
910
+ return formatTimeValue(kind.time ? "dateTime" : "date", String(value), {
911
+ zone: zone.zone,
912
+ viewerZone: viewer.zone,
913
+ locale: localeTag(locale),
914
+ params: {}
915
+ });
385
916
  }
386
917
  };
387
918
  const orphanPinned = useMemo(() => {
@@ -415,49 +946,56 @@ function FilterBadges(props) {
415
946
  onEnumResolved,
416
947
  onRelationResolved
417
948
  }),
418
- group.rows.map((row, index) => jsxs(Badge, {
949
+ group.rows.map((row, index) => jsx(Badge, {
419
950
  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
- })]
951
+ className: "py-1 pr-1",
952
+ children: jsxs("span", {
953
+ className: BADGE_ROW,
954
+ children: [jsx("button", {
955
+ type: "button",
956
+ "data-testid": `${testIdBase}:badge:${index}`,
957
+ onClick: () => onOpenAt([index]),
958
+ className: "min-w-0 cursor-pointer truncate bg-transparent p-0 text-left",
959
+ children: describeRow(row, available, tt, formatValue)
960
+ }), jsx("button", {
961
+ type: "button",
962
+ "data-testid": `${testIdBase}:badge:${index}:remove`,
963
+ "aria-label": removeLabel,
964
+ onClick: () => handleRemove(index),
965
+ className: REMOVE_BUTTON,
966
+ children: jsx(IconX, {
967
+ className: "size-3",
968
+ "aria-hidden": "true"
969
+ })
970
+ })]
971
+ })
438
972
  }, badgeKey(row, index))),
439
973
  labelledFixed.map((entry, index) => jsx(Badge, {
440
974
  variant: "outline",
441
975
  "data-testid": `${testIdBase}:badge:fixed:${index}`,
442
976
  children: entry.label
443
977
  }, `fixed-${index}`)),
444
- orphanPinned.map(({ expr, index }) => jsxs(Badge, {
978
+ orphanPinned.map(({ expr, index }) => jsx(Badge, {
445
979
  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
- })]
980
+ className: "py-1 pr-1",
981
+ children: jsxs("span", {
982
+ className: BADGE_ROW,
983
+ children: [jsx("span", {
984
+ "data-testid": `${testIdBase}:badge:pinned:${index}`,
985
+ className: "min-w-0 truncate",
986
+ children: describeRow(expr, available, tt, formatValue)
987
+ }), jsx("button", {
988
+ type: "button",
989
+ "data-testid": `${testIdBase}:badge:pinned:${index}:remove`,
990
+ "aria-label": removeLabel,
991
+ onClick: () => handleRemovePinned(index),
992
+ className: REMOVE_BUTTON,
993
+ children: jsx(IconX, {
994
+ className: "size-3",
995
+ "aria-hidden": "true"
996
+ })
997
+ })]
998
+ })
461
999
  }, `pinned-${index}`))
462
1000
  ]
463
1001
  });
@@ -647,14 +1185,15 @@ const OPTIONS = ["true", "false"];
647
1185
  function BooleanValueControl(props) {
648
1186
  const { value, onChange, testId, arity, autoFocus, fieldLabel, fill } = props;
649
1187
  const t = useOptionalT();
650
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1188
+ const chromeT = useChromeT();
1189
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
651
1190
  defaultValue: `Value for ${fieldLabel}`,
652
1191
  params: { field: fieldLabel }
653
- }) : t("filters.value", { defaultValue: "Value" });
1192
+ }) : chromeT("filters.value", { defaultValue: "Value" });
654
1193
  const yesLabel = t("boolean.yes", { defaultValue: "Yes" });
655
1194
  const noLabel = t("boolean.no", { defaultValue: "No" });
656
1195
  const labelOf = (token) => token === "true" ? yesLabel : noLabel;
657
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1196
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
658
1197
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
659
1198
  value,
660
1199
  arity,
@@ -674,7 +1213,7 @@ function BooleanValueControl(props) {
674
1213
  "data-testid": testId,
675
1214
  "aria-label": ariaLabel,
676
1215
  className: cn("h-8 justify-between", fill && "w-full"),
677
- children: triggerLabel(labelOf, ariaLabel)
1216
+ children: triggerLabel(labelOf, props.placeholder ?? ariaLabel)
678
1217
  })
679
1218
  }), jsx(PopoverContent, {
680
1219
  className: "w-[140px] p-0",
@@ -707,12 +1246,13 @@ function BooleanValueControl(props) {
707
1246
  function SelectListValueControl(props) {
708
1247
  const { options, value, onChange, testId, arity, autoFocus, fieldLabel, isLoading = false } = props;
709
1248
  const t = useOptionalT();
710
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1249
+ const chromeT = useChromeT();
1250
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
711
1251
  defaultValue: `Value for ${fieldLabel}`,
712
1252
  params: { field: fieldLabel }
713
- }) : t("filters.value", { defaultValue: "Value" });
1253
+ }) : chromeT("filters.value", { defaultValue: "Value" });
714
1254
  const loadingLabel = t("table.loading", { defaultValue: "Loading…" });
715
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1255
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
716
1256
  const labelFor = props.labelFor ?? ((raw) => options.find((o) => o.value === raw)?.label ?? raw);
717
1257
  const { open, setOpen, selected, select, triggerLabel, clear } = useSelectableValueControl({
718
1258
  value,
@@ -734,7 +1274,7 @@ function SelectListValueControl(props) {
734
1274
  className: cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[200px]"),
735
1275
  children: jsx("span", {
736
1276
  className: "truncate",
737
- children: isLoading ? loadingLabel : triggerLabel(labelFor, ariaLabel)
1277
+ children: isLoading ? loadingLabel : triggerLabel(labelFor, props.placeholder ?? ariaLabel)
738
1278
  })
739
1279
  })
740
1280
  }), jsx(PopoverContent, {
@@ -797,6 +1337,7 @@ function EnumValueControl(props) {
797
1337
  arity,
798
1338
  autoFocus,
799
1339
  fieldLabel,
1340
+ placeholder: props.placeholder,
800
1341
  options,
801
1342
  labelFor,
802
1343
  isLoading,
@@ -843,6 +1384,7 @@ function RelationValueControl(props) {
843
1384
  const { to, by, value, onChange, testId, arity, autoFocus, fieldLabel } = props;
844
1385
  const app = useApp();
845
1386
  const t = useOptionalT();
1387
+ const chromeT = useChromeT();
846
1388
  const targetDef = app.registry.get(to);
847
1389
  const displayField = targetDef?.displayField ?? "name";
848
1390
  const [search, setSearch] = useState("");
@@ -881,11 +1423,11 @@ function RelationValueControl(props) {
881
1423
  if (fromRows) return rowTitle(fromRows);
882
1424
  return fallbackLabels[id] ?? id;
883
1425
  };
884
- const ariaLabel = fieldLabel ? t("filters.valueFor", {
1426
+ const ariaLabel = fieldLabel ? chromeT("filters.valueFor", {
885
1427
  defaultValue: `Value for ${fieldLabel}`,
886
1428
  params: { field: fieldLabel }
887
- }) : t("filters.value", { defaultValue: "Value" });
888
- const clearLabel = t("filters.clear", { defaultValue: "Clear" });
1429
+ }) : chromeT("filters.value", { defaultValue: "Value" });
1430
+ const clearLabel = chromeT("filters.clear", { defaultValue: "Clear" });
889
1431
  return jsxs(Popover, {
890
1432
  open,
891
1433
  onOpenChange: setOpen,
@@ -901,7 +1443,7 @@ function RelationValueControl(props) {
901
1443
  className: cn("h-8 justify-between truncate", props.fill ? "w-full" : "max-w-[220px]"),
902
1444
  children: jsx("span", {
903
1445
  className: "truncate",
904
- children: triggerLabel(labelFor, ariaLabel)
1446
+ children: triggerLabel(labelFor, props.placeholder ?? ariaLabel)
905
1447
  })
906
1448
  })
907
1449
  }), jsx(PopoverContent, {
@@ -957,7 +1499,56 @@ function RelationValueControl(props) {
957
1499
  });
958
1500
  }
959
1501
  //#endregion
1502
+ //#region src/fields/field-time-zone.ts
1503
+ function useFieldTimeZone(zone, row) {
1504
+ const { sources: session } = useTimeContext();
1505
+ const sources = useMemo(() => row === void 0 ? session : {
1506
+ ...session,
1507
+ record: {
1508
+ status: "ready",
1509
+ value: row,
1510
+ refreshing: false
1511
+ }
1512
+ }, [session, row]);
1513
+ const fieldZone = useMemo(() => normaliseFieldZone(zone), [zone]);
1514
+ return useTimeZone(fieldZone, sources);
1515
+ }
1516
+ const DATE_KEYS = [
1517
+ "dateStyle",
1518
+ "timeStyle",
1519
+ "zoneName"
1520
+ ];
1521
+ function dateDisplayParams(ui) {
1522
+ const display = ui?.display;
1523
+ if (display === null || typeof display !== "object") return {};
1524
+ const params = {};
1525
+ for (const key of DATE_KEYS) {
1526
+ const value = display[key];
1527
+ if (value !== void 0) params[key] = value;
1528
+ }
1529
+ return params;
1530
+ }
1531
+ //#endregion
1532
+ //#region src/fields/local-date-time.ts
1533
+ function toLocalDateTimeText(value, zone) {
1534
+ if (value === void 0 || value === null || value === "") return "";
1535
+ const instant = canonicalInstant(value instanceof Date ? value.toISOString() : String(value));
1536
+ if (instant === void 0) return "";
1537
+ const { date, time } = instantToWall(instant, zone);
1538
+ return `${date}T${time.slice(0, 5)}`;
1539
+ }
1540
+ function fromLocalDateTimeText(text, zone) {
1541
+ const [date, time, ...rest] = text.split("T");
1542
+ if (date === void 0 || time === void 0 || rest.length > 0) return void 0;
1543
+ if (!isCalendarDate(date) || !isWallTime(time)) return void 0;
1544
+ return wallToInstant(date, time, zone);
1545
+ }
1546
+ //#endregion
960
1547
  //#region src/list-kit/filter-builder/values/scalar-value-input.tsx
1548
+ function useFilterZone(fieldZone) {
1549
+ const zone = useFieldTimeZone(fieldZone, void 0);
1550
+ return zone.status === "ready" ? zone.zone : "UTC";
1551
+ }
961
1552
  function isDateTime(kind) {
962
1553
  return kind.kind === "date" && kind.time === true;
963
1554
  }
@@ -968,33 +1559,27 @@ function inputTypeFor(kind) {
968
1559
  default: return "text";
969
1560
  }
970
1561
  }
971
- function toText(kind, value) {
1562
+ function toText(kind, value, zone) {
1563
+ if (isDateTime(kind)) return toLocalDateTimeText(value, zone);
972
1564
  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())}`;
1565
+ return String(value);
978
1566
  }
979
- function parseOne(kind, raw) {
1567
+ function parseOne(kind, raw, zone) {
980
1568
  if (raw === "") return void 0;
981
1569
  if (kind.kind === "number") {
982
1570
  const n = Number(raw);
983
1571
  return Number.isFinite(n) ? n : void 0;
984
1572
  }
985
- if (isDateTime(kind)) {
986
- const d = new Date(raw);
987
- return Number.isNaN(d.getTime()) ? void 0 : d.toISOString();
988
- }
1573
+ if (isDateTime(kind)) return fromLocalDateTimeText(raw, zone);
989
1574
  return raw;
990
1575
  }
991
1576
  function ScalarValueInput(props) {
992
- const t = useOptionalT();
1577
+ const chromeT = useChromeT();
993
1578
  const inputType = inputTypeFor(props.kind);
994
- const ariaLabel = props.fieldLabel ? t("filters.valueFor", {
1579
+ const ariaLabel = props.fieldLabel ? chromeT("filters.valueFor", {
995
1580
  defaultValue: `Value for ${props.fieldLabel}`,
996
1581
  params: { field: props.fieldLabel }
997
- }) : t("filters.value", { defaultValue: "Value" });
1582
+ }) : chromeT("filters.value", { defaultValue: "Value" });
998
1583
  if (props.arity === "multi") return jsx(ScalarMultiInput, {
999
1584
  ...props,
1000
1585
  inputType,
@@ -1008,7 +1593,8 @@ function ScalarValueInput(props) {
1008
1593
  }
1009
1594
  function ScalarSingleInput(props) {
1010
1595
  const { value, onChange, kind, testId, autoFocus, inputType, ariaLabel, debounceMs = 300 } = props;
1011
- const storedText = toText(kind, value);
1596
+ const zone = useFilterZone(props.zone);
1597
+ const storedText = toText(kind, value, zone);
1012
1598
  const [text, setText] = useState(storedText);
1013
1599
  const lastPushedRef = useRef(storedText);
1014
1600
  const timerRef = useRef(null);
@@ -1016,8 +1602,8 @@ function ScalarSingleInput(props) {
1016
1602
  const commitRef = useRef(() => {});
1017
1603
  useEffect(() => {
1018
1604
  commitRef.current = (raw) => {
1019
- const parsed = parseOne(kind, raw);
1020
- lastPushedRef.current = toText(kind, parsed);
1605
+ const parsed = parseOne(kind, raw, zone);
1606
+ lastPushedRef.current = toText(kind, parsed, zone);
1021
1607
  pendingRawRef.current = null;
1022
1608
  onChange(parsed);
1023
1609
  };
@@ -1066,8 +1652,9 @@ function ScalarMultiInput(props) {
1066
1652
  const { value, onChange, kind, testId, autoFocus, inputType, ariaLabel } = props;
1067
1653
  const chips = Array.isArray(value) ? value.map((v) => String(v)) : [];
1068
1654
  const [draft, setDraft] = useState("");
1655
+ const zone = useFilterZone(props.zone);
1069
1656
  const addChip = () => {
1070
- const parsed = parseOne(kind, draft.trim());
1657
+ const parsed = parseOne(kind, draft.trim(), zone);
1071
1658
  if (parsed === void 0) return;
1072
1659
  const text = String(parsed);
1073
1660
  setDraft("");
@@ -1124,6 +1711,7 @@ function FilterValueControl(props) {
1124
1711
  arity,
1125
1712
  autoFocus: props.autoFocus,
1126
1713
  fieldLabel: props.fieldLabel,
1714
+ placeholder: props.placeholder,
1127
1715
  options: props.options,
1128
1716
  fill: props.fill
1129
1717
  });
@@ -1140,6 +1728,7 @@ function FilterValueControl(props) {
1140
1728
  arity,
1141
1729
  autoFocus: props.autoFocus,
1142
1730
  fieldLabel: props.fieldLabel,
1731
+ placeholder: props.placeholder,
1143
1732
  options: props.kind.values.map((entry) => ({
1144
1733
  value: entry,
1145
1734
  label: entry
@@ -1168,10 +1757,10 @@ const FIELD_CLASS = "h-8 min-w-0 shrink basis-40";
1168
1757
  const OPERATOR_CLASS = "h-8 min-w-0 shrink basis-[9.5rem]";
1169
1758
  function FilterRow(props) {
1170
1759
  const { row, path, available, onPatch, onRemove, testIdBase, debounceMs } = props;
1171
- const t = useOptionalT();
1760
+ const chromeT = useChromeT();
1172
1761
  const base = `${testIdBase}:row:${path.join("-")}`;
1173
1762
  const spec = available.find((s) => s.field === row.field);
1174
- const removeLabel = t("filters.removeRow", { defaultValue: "Remove filter" });
1763
+ const removeLabel = chromeT("filters.removeRow", { defaultValue: "Remove filter" });
1175
1764
  if (!spec) return jsxs("div", {
1176
1765
  className: ROW_CLASS,
1177
1766
  children: [
@@ -1211,8 +1800,8 @@ function FilterRow(props) {
1211
1800
  };
1212
1801
  const handleOpChange = (op) => onPatch(path, { op });
1213
1802
  const handleValueChange = (value) => onPatch(path, { value });
1214
- const fieldAriaLabel = t("filters.field", { defaultValue: "Field" });
1215
- const operatorAriaLabel = t("filters.operator", { defaultValue: "Operator" });
1803
+ const fieldAriaLabel = chromeT("filters.field", { defaultValue: "Field" });
1804
+ const operatorAriaLabel = chromeT("filters.operator", { defaultValue: "Operator" });
1216
1805
  return jsxs("div", {
1217
1806
  className: ROW_CLASS,
1218
1807
  children: [
@@ -1241,7 +1830,7 @@ function FilterRow(props) {
1241
1830
  }), jsx(SelectContent, { children: spec.operators.map((op) => jsx(SelectItem, {
1242
1831
  value: op,
1243
1832
  "data-testid": `${opTestId}:option:${op}`,
1244
- children: t(`filters.operators.${op}`, { defaultValue: op })
1833
+ children: chromeT(`filters.operators.${op}`, { defaultValue: op })
1245
1834
  }, op)) })]
1246
1835
  }),
1247
1836
  jsx("div", {
@@ -1255,6 +1844,7 @@ function FilterRow(props) {
1255
1844
  debounceMs,
1256
1845
  fieldLabel: spec.label,
1257
1846
  options: spec.options,
1847
+ ...spec.zone === void 0 ? {} : { zone: spec.zone },
1258
1848
  fill: true
1259
1849
  })
1260
1850
  }),
@@ -1289,10 +1879,10 @@ function FilterGroupEditor(props) {
1289
1879
  }
1290
1880
  function GroupEditorInner(props) {
1291
1881
  const { group, path, available, onChange, testIdBase, onRemove, addGroupAt, debounceMs } = props;
1292
- const t = useOptionalT();
1882
+ const chromeT = useChromeT();
1293
1883
  const base = `${testIdBase}:group:${path.join("-")}`;
1294
1884
  const canNestGroup = depthOf(path) < 3;
1295
- const joinLabel = (join) => t(`filters.${join}`, { defaultValue: join });
1885
+ const joinLabel = (join) => chromeT(`filters.${join}`, { defaultValue: join });
1296
1886
  const handlePatch = (rowPath, patch) => {
1297
1887
  const index = rowPath[rowPath.length - 1];
1298
1888
  if (index === void 0) return;
@@ -1325,11 +1915,11 @@ function GroupEditorInner(props) {
1325
1915
  return jsxs(Fragment, { children: [jsxs("div", {
1326
1916
  className: CONNECTOR_CLASS,
1327
1917
  children: [
1328
- index === 0 && t("filters.where", { defaultValue: "Where" }),
1918
+ index === 0 && chromeT("filters.where", { defaultValue: "Where" }),
1329
1919
  index === 1 && jsx("button", {
1330
1920
  type: "button",
1331
1921
  "data-testid": `${base}:join`,
1332
- "aria-label": t("filters.toggleJoin", {
1922
+ "aria-label": chromeT("filters.toggleJoin", {
1333
1923
  defaultValue: `Join: ${joinLabel(group.join)} — activate to switch to ${joinLabel(otherJoin)}`,
1334
1924
  params: {
1335
1925
  current: joinLabel(group.join),
@@ -1381,7 +1971,7 @@ function GroupEditorInner(props) {
1381
1971
  children: [jsx(IconPlus, {
1382
1972
  className: "h-4 w-4",
1383
1973
  "aria-hidden": "true"
1384
- }), t("filters.addRow", { defaultValue: "Add filter" })]
1974
+ }), chromeT("filters.addRow", { defaultValue: "Add filter" })]
1385
1975
  }),
1386
1976
  canNestGroup && jsxs(Button, {
1387
1977
  type: "button",
@@ -1392,7 +1982,7 @@ function GroupEditorInner(props) {
1392
1982
  children: [jsx(IconFolderPlus, {
1393
1983
  className: "h-4 w-4",
1394
1984
  "aria-hidden": "true"
1395
- }), t("filters.addGroup", { defaultValue: "Add group" })]
1985
+ }), chromeT("filters.addGroup", { defaultValue: "Add group" })]
1396
1986
  }),
1397
1987
  onRemove && jsxs(Button, {
1398
1988
  type: "button",
@@ -1403,7 +1993,7 @@ function GroupEditorInner(props) {
1403
1993
  children: [jsx(IconX, {
1404
1994
  className: "h-4 w-4",
1405
1995
  "aria-hidden": "true"
1406
- }), t("filters.removeGroup", { defaultValue: "Remove group" })]
1996
+ }), chromeT("filters.removeGroup", { defaultValue: "Remove group" })]
1407
1997
  })
1408
1998
  ]
1409
1999
  })
@@ -1419,7 +2009,7 @@ function countGroupRows(group) {
1419
2009
  }
1420
2010
  function FilterPanel(props) {
1421
2011
  const { group, setGroup, available, setPage, testIdBase, open, onOpenChange, focusPath, externalRemoval } = props;
1422
- const t = useOptionalT();
2012
+ const chromeT = useChromeT();
1423
2013
  const [draft, setDraft] = useState(() => toDraft(group));
1424
2014
  const wasOpenRef = useRef(open);
1425
2015
  const topLevelIdsRef = useRef([]);
@@ -1471,7 +2061,7 @@ function FilterPanel(props) {
1471
2061
  className: "h-4 w-4",
1472
2062
  "aria-hidden": "true"
1473
2063
  }),
1474
- t("filters.title", { defaultValue: "Filters" }),
2064
+ chromeT("filters.title", { defaultValue: "Filters" }),
1475
2065
  appliedCount > 0 && jsx("span", {
1476
2066
  "data-testid": `${testIdBase}:count`,
1477
2067
  className: "ml-1 rounded-full bg-primary px-1.5 text-xs text-primary-foreground",
@@ -1499,13 +2089,13 @@ function FilterPanel(props) {
1499
2089
  size: "sm",
1500
2090
  "data-testid": `${testIdBase}:reset`,
1501
2091
  onClick: handleReset,
1502
- children: t("filters.reset", { defaultValue: "Reset" })
2092
+ children: chromeT("filters.reset", { defaultValue: "Reset" })
1503
2093
  }), jsx(Button, {
1504
2094
  type: "button",
1505
2095
  size: "sm",
1506
2096
  "data-testid": `${testIdBase}:apply`,
1507
2097
  onClick: handleApply,
1508
- children: t("filters.apply", { defaultValue: "Apply" })
2098
+ children: chromeT("filters.apply", { defaultValue: "Apply" })
1509
2099
  })]
1510
2100
  })]
1511
2101
  })]
@@ -1556,15 +2146,209 @@ function PinnedControl(props) {
1556
2146
  testId: `${testIdBase}:pinned:${spec.field}`,
1557
2147
  fieldLabel: spec.label,
1558
2148
  placeholder: spec.label,
1559
- options: spec.options
2149
+ options: spec.options,
2150
+ ...spec.zone === void 0 ? {} : { zone: spec.zone }
1560
2151
  });
1561
2152
  }
1562
2153
  //#endregion
2154
+ //#region src/data-table/data-table-faceted-filter.tsx
2155
+ function DataTableFacetedFilter({ column, getTestId, ...rest }) {
2156
+ const filterValue = column.getFilterValue();
2157
+ return jsx(FacetedFilterPicker, {
2158
+ ...rest,
2159
+ ...getTestId === void 0 ? {} : { getTestId: (role, value) => role === "hint" ? void 0 : getTestId(role, value) },
2160
+ selected: Array.isArray(filterValue) ? filterValue.map(String) : [],
2161
+ onChange: (next) => column.setFilterValue(next.length === 0 ? void 0 : next)
2162
+ });
2163
+ }
2164
+ function FacetedFilterPicker({ title, options = [], loadOptions, selectedLabelFor, searchPlaceholder, emptyText, getTestId, className, selected: selectedList, onChange, hint, emptyLabel, clearable = true }) {
2165
+ const t = useOptionalT();
2166
+ const chromeT = useChromeT();
2167
+ const selected = useMemo(() => new Set(selectedList), [selectedList]);
2168
+ const [search, setSearch] = useState("");
2169
+ const [asyncOptions, setAsyncOptions] = useState([]);
2170
+ const [loading, setLoading] = useState(false);
2171
+ const debounceRef = useRef(null);
2172
+ const loadOptionsRef = useRef(loadOptions);
2173
+ useEffect(() => {
2174
+ loadOptionsRef.current = loadOptions;
2175
+ });
2176
+ useEffect(() => {
2177
+ if (!loadOptionsRef.current) return;
2178
+ setLoading(true);
2179
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2180
+ let cancelled = false;
2181
+ debounceRef.current = setTimeout(() => {
2182
+ const loader = loadOptionsRef.current;
2183
+ if (!loader) return;
2184
+ loader(search).then((results) => {
2185
+ if (!cancelled) {
2186
+ setAsyncOptions(results);
2187
+ setLoading(false);
2188
+ }
2189
+ }).catch(() => {
2190
+ if (!cancelled) setLoading(false);
2191
+ });
2192
+ }, 250);
2193
+ return () => {
2194
+ cancelled = true;
2195
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
2196
+ };
2197
+ }, [search]);
2198
+ const effectiveOptions = loadOptions ? asyncOptions : options;
2199
+ const labelFor = (value) => {
2200
+ const opt = effectiveOptions.find((o) => o.value === value);
2201
+ if (opt) return opt.label;
2202
+ return selectedLabelFor?.(value) ?? value;
2203
+ };
2204
+ const toggle = (value) => {
2205
+ const next = new Set(selected);
2206
+ if (next.has(value)) next.delete(value);
2207
+ else next.add(value);
2208
+ onChange(Array.from(next));
2209
+ };
2210
+ const selectedValues = Array.from(selected);
2211
+ return jsxs(Popover, { children: [jsx(PopoverTrigger, {
2212
+ asChild: true,
2213
+ children: jsxs(Button, {
2214
+ type: "button",
2215
+ variant: "outline",
2216
+ size: "sm",
2217
+ "data-testid": getTestId?.("trigger"),
2218
+ title: hint,
2219
+ className: cn("h-8 border-dashed", className),
2220
+ children: [
2221
+ jsx(IconCirclePlus, {
2222
+ className: "mr-2 h-4 w-4",
2223
+ "aria-hidden": "true"
2224
+ }),
2225
+ title,
2226
+ selected.size === 0 && emptyLabel !== void 0 && jsxs(Fragment$1, { children: [jsx("span", {
2227
+ className: "mx-2 h-4 w-px bg-border",
2228
+ "aria-hidden": "true"
2229
+ }), jsx(Badge, {
2230
+ variant: "secondary",
2231
+ className: "rounded-sm px-1 font-normal",
2232
+ children: emptyLabel
2233
+ })] }),
2234
+ selected.size > 0 && jsxs(Fragment$1, { children: [
2235
+ jsx("span", {
2236
+ className: "mx-2 h-4 w-px bg-border",
2237
+ "aria-hidden": "true"
2238
+ }),
2239
+ jsx(Badge, {
2240
+ variant: "secondary",
2241
+ className: "rounded-sm px-1 font-normal lg:hidden",
2242
+ children: selected.size
2243
+ }),
2244
+ jsx("div", {
2245
+ className: "hidden gap-1 lg:flex",
2246
+ children: selected.size > 2 ? jsx(Badge, {
2247
+ variant: "secondary",
2248
+ className: "rounded-sm px-1 font-normal",
2249
+ children: t("table.selectedCount", {
2250
+ count: selected.size,
2251
+ defaultValue: "{{count}} selected"
2252
+ })
2253
+ }) : selectedValues.map((value) => jsx(Badge, {
2254
+ variant: "secondary",
2255
+ className: "rounded-sm px-1 font-normal",
2256
+ children: labelFor(value)
2257
+ }, value))
2258
+ })
2259
+ ] })
2260
+ ]
2261
+ })
2262
+ }), jsx(PopoverContent, {
2263
+ className: "w-[220px] p-0",
2264
+ align: "start",
2265
+ children: jsxs(Command, {
2266
+ shouldFilter: !loadOptions,
2267
+ children: [
2268
+ hint !== void 0 && jsx("p", {
2269
+ "data-testid": getTestId?.("hint"),
2270
+ className: "border-b px-3 py-2 text-xs text-muted-foreground",
2271
+ children: hint
2272
+ }),
2273
+ jsx(CommandInput, {
2274
+ placeholder: searchPlaceholder ?? title,
2275
+ "data-testid": getTestId?.("search"),
2276
+ ...loadOptions ? {
2277
+ value: search,
2278
+ onValueChange: setSearch
2279
+ } : {}
2280
+ }),
2281
+ jsxs(CommandList, { children: [
2282
+ loading && jsx("div", {
2283
+ className: "py-6 text-center text-sm text-muted-foreground",
2284
+ children: t("list.loadingShort", { defaultValue: "Loading…" })
2285
+ }),
2286
+ jsx(CommandEmpty, { children: emptyText ?? t("relation.noResults", { defaultValue: "No results." }) }),
2287
+ jsx(CommandGroup, { children: effectiveOptions.map((opt) => {
2288
+ const isSelected = selected.has(opt.value);
2289
+ const Icon = opt.icon;
2290
+ return jsxs(CommandItem, {
2291
+ value: opt.label,
2292
+ "data-testid": getTestId?.("option", opt.value),
2293
+ role: "option",
2294
+ "aria-selected": isSelected,
2295
+ "aria-checked": isSelected,
2296
+ onSelect: () => toggle(opt.value),
2297
+ children: [
2298
+ jsx("span", {
2299
+ 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"),
2300
+ "aria-hidden": "true",
2301
+ children: isSelected && jsx(IconCheck, { className: "h-3.5 w-3.5" })
2302
+ }),
2303
+ Icon && jsx(Icon, {
2304
+ className: "mr-2 h-4 w-4 text-muted-foreground",
2305
+ "aria-hidden": "true"
2306
+ }),
2307
+ jsxs("span", {
2308
+ className: "flex min-w-0 flex-1 flex-col text-left",
2309
+ children: [jsx("span", { children: opt.label }), opt.summary !== void 0 && jsx("span", {
2310
+ className: "text-xs text-muted-foreground",
2311
+ children: opt.summary
2312
+ })]
2313
+ })
2314
+ ]
2315
+ }, opt.value);
2316
+ }) })
2317
+ ] }),
2318
+ clearable && selected.size > 0 && jsx("button", {
2319
+ type: "button",
2320
+ "data-testid": getTestId?.("clear"),
2321
+ onClick: () => onChange([]),
2322
+ className: "flex w-full items-center justify-center border-t px-2 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground",
2323
+ children: chromeT("filters.clearAll", { defaultValue: "Clear filters" })
2324
+ })
2325
+ ]
2326
+ })
2327
+ })] });
2328
+ }
2329
+ //#endregion
2330
+ //#region src/list-kit/filter-builder/preset-filter-controls.tsx
2331
+ function PresetFilterControls(props) {
2332
+ const { presets, setPreset, testIdBase } = props;
2333
+ return jsx(Fragment$1, { children: presets.map((filter) => jsx(FacetedFilterPicker, {
2334
+ title: filter.label,
2335
+ ...filter.hint === void 0 ? {} : { hint: filter.hint },
2336
+ options: filter.options.map((option) => ({
2337
+ value: option.id,
2338
+ label: option.label,
2339
+ ...option.summary === void 0 ? {} : { summary: option.summary }
2340
+ })),
2341
+ selected: filter.selected,
2342
+ onChange: (next) => setPreset(filter.id, filter.options.map((option) => option.id).filter((id) => next.includes(id))),
2343
+ getTestId: (role, value) => `${testIdBase}:preset:${filter.id}:${role}${value === void 0 ? "" : `:${value}`}`
2344
+ }, filter.id)) });
2345
+ }
2346
+ //#endregion
1563
2347
  //#region src/list-kit/filter-builder/filter-builder.tsx
1564
2348
  const EMPTY_PINNED_FIELDS = Object.freeze([]);
1565
2349
  const EMPTY_PINNED_VALUE = Object.freeze([]);
1566
2350
  function FilterBuilder(props) {
1567
- const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, setPage, testIdBase } = props;
2351
+ const { group, setGroup, available, fixed, pinnedFields = EMPTY_PINNED_FIELDS, pinnedValue = EMPTY_PINNED_VALUE, setPinnedValue, presets, setPreset, setPage, testIdBase } = props;
1568
2352
  const [open, setOpen] = useState(false);
1569
2353
  const [focusPath, setFocusPath] = useState(void 0);
1570
2354
  const [externalRemoval, setExternalRemoval] = useState(void 0);
@@ -1581,6 +2365,11 @@ function FilterBuilder(props) {
1581
2365
  setPinnedValue?.(next);
1582
2366
  };
1583
2367
  return jsxs(Fragment$1, { children: [
2368
+ presets !== void 0 && presets.length > 0 && setPreset !== void 0 && jsx(PresetFilterControls, {
2369
+ presets,
2370
+ setPreset,
2371
+ testIdBase
2372
+ }),
1584
2373
  jsx(PinnedFilterControls, {
1585
2374
  pinnedFields,
1586
2375
  value: pinnedValue,
@@ -1616,6 +2405,6 @@ function FilterBuilder(props) {
1616
2405
  ] });
1617
2406
  }
1618
2407
  //#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 };
2408
+ export { TableHeader as A, DEFAULT_LANGUAGE_STORAGE_KEY as B, SelectTrigger as C, TableCaption as D, TableBody as E, ResolvedFieldDisplay as F, saveLocale as H, ResolvedFieldInput as I, useFieldMetaDiagnostic as L, Badge as M, badgeVariants as N, TableCell as O, MetaPlaceholder as P, fieldDescription as R, SelectSeparator as S, Table as T, loadLocale as V, SelectGroup as _, PinnedFilterControls as a, SelectScrollDownButton as b, fromLocalDateTimeText as c, useFieldTimeZone as d, FilterBadges as f, SelectContent as g, Select as h, FacetedFilterPicker as i, TableRow as j, TableHead as k, toLocalDateTimeText as l, localeTag as m, PresetFilterControls as n, FilterPanel as o, formatNumber as p, DataTableFacetedFilter as r, FilterValueControl as s, FilterBuilder as t, dateDisplayParams as u, SelectItem as v, SelectValue as w, SelectScrollUpButton as x, SelectLabel as y, lowerLegacyField as z };
1620
2409
 
1621
- //# sourceMappingURL=filter-builder-Bhn-dhZV.js.map
2410
+ //# sourceMappingURL=filter-builder-z3Axzf9Y.js.map