@open-mercato/ui 0.6.1-develop.3246.1.dbef9d7392 → 0.6.1-develop.3260.1.dc719cac84

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 (164) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/__integration__/TC-AI-UI-003-aichat-registry.spec.tsx +13 -0
  3. package/dist/ai/AiAssistantLauncher.js +8 -0
  4. package/dist/ai/AiAssistantLauncher.js.map +2 -2
  5. package/dist/ai/AiChat.js +226 -58
  6. package/dist/ai/AiChat.js.map +2 -2
  7. package/dist/ai/AiDock.js +3 -2
  8. package/dist/ai/AiDock.js.map +2 -2
  9. package/dist/ai/ModelPicker.js +186 -0
  10. package/dist/ai/ModelPicker.js.map +7 -0
  11. package/dist/ai/index.js +3 -1
  12. package/dist/ai/index.js.map +2 -2
  13. package/dist/ai/useAiChat.js +12 -16
  14. package/dist/ai/useAiChat.js.map +2 -2
  15. package/dist/backend/CrudForm.js +46 -129
  16. package/dist/backend/CrudForm.js.map +3 -3
  17. package/dist/backend/DataTable.js +10 -3
  18. package/dist/backend/DataTable.js.map +2 -2
  19. package/dist/backend/EmptyState.js +1 -47
  20. package/dist/backend/EmptyState.js.map +2 -2
  21. package/dist/backend/FilterOverlay.js +31 -26
  22. package/dist/backend/FilterOverlay.js.map +2 -2
  23. package/dist/backend/FlashMessages.js +23 -25
  24. package/dist/backend/FlashMessages.js.map +2 -2
  25. package/dist/backend/JsonBuilder.js +4 -2
  26. package/dist/backend/JsonBuilder.js.map +2 -2
  27. package/dist/backend/LogList.js +49 -0
  28. package/dist/backend/LogList.js.map +7 -0
  29. package/dist/backend/crud/CollapsibleGroup.js +13 -3
  30. package/dist/backend/crud/CollapsibleGroup.js.map +2 -2
  31. package/dist/backend/detail/InlineEditors.js +80 -32
  32. package/dist/backend/detail/InlineEditors.js.map +2 -2
  33. package/dist/backend/inputs/ComboboxInput.js +60 -6
  34. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  35. package/dist/backend/inputs/DatePicker.js +6 -142
  36. package/dist/backend/inputs/DatePicker.js.map +2 -2
  37. package/dist/backend/inputs/DateTimePicker.js +6 -182
  38. package/dist/backend/inputs/DateTimePicker.js.map +2 -2
  39. package/dist/backend/inputs/TagsInput.js +16 -19
  40. package/dist/backend/inputs/TagsInput.js.map +2 -2
  41. package/dist/backend/inputs/TimeInput.js +1 -1
  42. package/dist/backend/inputs/TimeInput.js.map +2 -2
  43. package/dist/backend/inputs/TimePicker.js +83 -72
  44. package/dist/backend/inputs/TimePicker.js.map +2 -2
  45. package/dist/backend/utils/customFieldForms.js +2 -2
  46. package/dist/backend/utils/customFieldForms.js.map +1 -1
  47. package/dist/portal/components/PortalEmptyState.js +13 -9
  48. package/dist/portal/components/PortalEmptyState.js.map +2 -2
  49. package/dist/primitives/accordion.js +137 -0
  50. package/dist/primitives/accordion.js.map +7 -0
  51. package/dist/primitives/alert.js +180 -12
  52. package/dist/primitives/alert.js.map +2 -2
  53. package/dist/primitives/calendar.js +122 -32
  54. package/dist/primitives/calendar.js.map +2 -2
  55. package/dist/primitives/compact-select.js +47 -0
  56. package/dist/primitives/compact-select.js.map +7 -0
  57. package/dist/primitives/counter-input.js +174 -0
  58. package/dist/primitives/counter-input.js.map +7 -0
  59. package/dist/primitives/date-picker-helpers.js +79 -0
  60. package/dist/primitives/date-picker-helpers.js.map +7 -0
  61. package/dist/primitives/date-picker.js +216 -0
  62. package/dist/primitives/date-picker.js.map +7 -0
  63. package/dist/primitives/date-range-picker.js +239 -0
  64. package/dist/primitives/date-range-picker.js.map +7 -0
  65. package/dist/primitives/digit-input.js +157 -0
  66. package/dist/primitives/digit-input.js.map +7 -0
  67. package/dist/primitives/empty-state.js +93 -0
  68. package/dist/primitives/empty-state.js.map +7 -0
  69. package/dist/primitives/inline-input.js +29 -0
  70. package/dist/primitives/inline-input.js.map +7 -0
  71. package/dist/primitives/inline-select.js +41 -0
  72. package/dist/primitives/inline-select.js.map +7 -0
  73. package/dist/primitives/notification-stack.js +116 -0
  74. package/dist/primitives/notification-stack.js.map +7 -0
  75. package/dist/primitives/notification.js +62 -0
  76. package/dist/primitives/notification.js.map +7 -0
  77. package/dist/primitives/rich-editor.js +1230 -0
  78. package/dist/primitives/rich-editor.js.map +7 -0
  79. package/dist/primitives/select.js +1 -0
  80. package/dist/primitives/select.js.map +2 -2
  81. package/dist/primitives/skeleton.js +55 -0
  82. package/dist/primitives/skeleton.js.map +7 -0
  83. package/dist/primitives/tag-input.js +186 -0
  84. package/dist/primitives/tag-input.js.map +7 -0
  85. package/dist/primitives/tag.js +66 -13
  86. package/dist/primitives/tag.js.map +2 -2
  87. package/dist/primitives/time-picker.js +793 -0
  88. package/dist/primitives/time-picker.js.map +7 -0
  89. package/package.json +4 -3
  90. package/src/ai/AiAssistantLauncher.tsx +8 -0
  91. package/src/ai/AiChat.tsx +229 -11
  92. package/src/ai/AiDock.tsx +3 -2
  93. package/src/ai/ModelPicker.tsx +248 -0
  94. package/src/ai/__tests__/AiAssistantLauncher.test.tsx +58 -0
  95. package/src/ai/__tests__/AiChat.conversation.test.tsx +16 -0
  96. package/src/ai/__tests__/AiChat.debug.test.tsx +16 -0
  97. package/src/ai/__tests__/AiChat.registry.test.tsx +16 -0
  98. package/src/ai/__tests__/AiChat.test.tsx +180 -0
  99. package/src/ai/__tests__/AiChat.thinking-unmount.test.tsx +16 -0
  100. package/src/ai/__tests__/AiDock.test.tsx +12 -1
  101. package/src/ai/__tests__/ModelPicker.test.tsx +252 -0
  102. package/src/ai/index.ts +1 -0
  103. package/src/ai/useAiChat.ts +29 -16
  104. package/src/backend/CrudForm.tsx +61 -113
  105. package/src/backend/DataTable.tsx +17 -5
  106. package/src/backend/EmptyState.tsx +13 -63
  107. package/src/backend/FilterOverlay.tsx +38 -22
  108. package/src/backend/FlashMessages.tsx +23 -24
  109. package/src/backend/JsonBuilder.tsx +4 -2
  110. package/src/backend/LogList.tsx +109 -0
  111. package/src/backend/__tests__/CrudForm.datetime.test.tsx +12 -7
  112. package/src/backend/__tests__/FilterOverlay.dateRange.test.tsx +89 -0
  113. package/src/backend/__tests__/LogList.test.tsx +163 -0
  114. package/src/backend/crud/CollapsibleGroup.tsx +17 -3
  115. package/src/backend/detail/InlineEditors.tsx +78 -25
  116. package/src/backend/detail/__tests__/InlineEditors.test.tsx +81 -1
  117. package/src/backend/inputs/ComboboxInput.tsx +81 -9
  118. package/src/backend/inputs/DatePicker.tsx +28 -155
  119. package/src/backend/inputs/DateTimePicker.tsx +25 -193
  120. package/src/backend/inputs/TagsInput.tsx +10 -13
  121. package/src/backend/inputs/TimeInput.tsx +2 -1
  122. package/src/backend/inputs/TimePicker.tsx +99 -70
  123. package/src/backend/inputs/__tests__/ComboboxInput.test.tsx +133 -0
  124. package/src/backend/inputs/__tests__/TimePicker.test.tsx +2 -2
  125. package/src/backend/utils/__tests__/richTextSanitizer.test.ts +5 -2
  126. package/src/backend/utils/customFieldForms.ts +2 -2
  127. package/src/portal/components/PortalEmptyState.tsx +27 -22
  128. package/src/primitives/__tests__/accordion.test.tsx +197 -0
  129. package/src/primitives/__tests__/alert.test.tsx +204 -0
  130. package/src/primitives/__tests__/compact-select.test.tsx +98 -0
  131. package/src/primitives/__tests__/counter-input.test.tsx +165 -0
  132. package/src/primitives/__tests__/date-picker.test.tsx +221 -0
  133. package/src/primitives/__tests__/date-range-picker.test.tsx +173 -0
  134. package/src/primitives/__tests__/digit-input.test.tsx +168 -0
  135. package/src/primitives/__tests__/empty-state.test.tsx +154 -0
  136. package/src/primitives/__tests__/inline-input.test.tsx +100 -0
  137. package/src/primitives/__tests__/inline-select.test.tsx +103 -0
  138. package/src/primitives/__tests__/notification-stack.test.tsx +174 -0
  139. package/src/primitives/__tests__/notification.test.tsx +119 -0
  140. package/src/primitives/__tests__/rich-editor.test.tsx +411 -0
  141. package/src/primitives/__tests__/skeleton.test.tsx +76 -0
  142. package/src/primitives/__tests__/tag-input.test.tsx +198 -0
  143. package/src/primitives/__tests__/tag.test.tsx +123 -0
  144. package/src/primitives/__tests__/time-picker.test.tsx +392 -0
  145. package/src/primitives/accordion.tsx +225 -0
  146. package/src/primitives/alert.tsx +234 -24
  147. package/src/primitives/calendar.tsx +146 -38
  148. package/src/primitives/compact-select.tsx +59 -0
  149. package/src/primitives/counter-input.tsx +211 -0
  150. package/src/primitives/date-picker-helpers.ts +96 -0
  151. package/src/primitives/date-picker.tsx +290 -0
  152. package/src/primitives/date-range-picker.tsx +281 -0
  153. package/src/primitives/digit-input.tsx +208 -0
  154. package/src/primitives/empty-state.tsx +140 -0
  155. package/src/primitives/inline-input.tsx +55 -0
  156. package/src/primitives/inline-select.tsx +74 -0
  157. package/src/primitives/notification-stack.tsx +185 -0
  158. package/src/primitives/notification.tsx +136 -0
  159. package/src/primitives/rich-editor.tsx +1578 -0
  160. package/src/primitives/select.tsx +1 -0
  161. package/src/primitives/skeleton.tsx +70 -0
  162. package/src/primitives/tag-input.tsx +223 -0
  163. package/src/primitives/tag.tsx +69 -10
  164. package/src/primitives/time-picker.tsx +1059 -0
@@ -24,6 +24,7 @@ function ComboboxInput({
24
24
  onChange,
25
25
  placeholder,
26
26
  suggestions,
27
+ seedOptions,
27
28
  loadSuggestions,
28
29
  resolveLabel,
29
30
  resolveDescription,
@@ -33,34 +34,48 @@ function ComboboxInput({
33
34
  }) {
34
35
  const [input, setInput] = React.useState("");
35
36
  const [asyncOptions, setAsyncOptions] = React.useState([]);
37
+ const [resolvedOptions, setResolvedOptions] = React.useState([]);
36
38
  const [loading, setLoading] = React.useState(false);
37
39
  const [touched, setTouched] = React.useState(false);
38
40
  const [showSuggestions, setShowSuggestions] = React.useState(false);
39
41
  const [selectedIndex, setSelectedIndex] = React.useState(-1);
40
42
  const inputRef = React.useRef(null);
41
43
  const suppressOpenOnFocusRef = React.useRef(Boolean(autoFocus && !disabled));
42
- const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions]);
44
+ const staticOptions = React.useMemo(
45
+ () => normalizeOptions([...seedOptions ?? [], ...suggestions ?? []]),
46
+ [seedOptions, suggestions]
47
+ );
48
+ const knownLabelValues = React.useMemo(() => {
49
+ const set = /* @__PURE__ */ new Set();
50
+ for (const option of [...staticOptions, ...asyncOptions, ...resolvedOptions]) {
51
+ if (option.label && option.label !== option.value) set.add(option.value);
52
+ }
53
+ return set;
54
+ }, [staticOptions, asyncOptions, resolvedOptions]);
43
55
  const optionMap = React.useMemo(() => {
44
56
  const map = /* @__PURE__ */ new Map();
45
57
  const register = (option) => {
46
- if (!map.has(option.value)) {
58
+ const existing = map.get(option.value);
59
+ if (!existing || existing.label === existing.value && option.label !== option.value) {
47
60
  map.set(option.value, option);
48
61
  }
49
62
  };
50
63
  staticOptions.forEach(register);
51
64
  asyncOptions.forEach(register);
65
+ resolvedOptions.forEach(register);
52
66
  if (value) {
53
67
  const existing = map.get(value);
54
68
  if (!existing) {
69
+ const sync = typeof resolveLabel === "function" ? resolveLabel(value) : void 0;
55
70
  map.set(value, {
56
71
  value,
57
- label: resolveLabel?.(value) ?? value,
72
+ label: typeof sync === "string" && sync ? sync : value,
58
73
  description: resolveDescription?.(value) ?? null
59
74
  });
60
75
  }
61
76
  }
62
77
  return map;
63
- }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value]);
78
+ }, [asyncOptions, resolvedOptions, resolveDescription, resolveLabel, staticOptions, value]);
64
79
  const availableOptions = React.useMemo(() => {
65
80
  return Array.from(optionMap.values());
66
81
  }, [optionMap]);
@@ -93,6 +108,41 @@ function ComboboxInput({
93
108
  window.clearTimeout(handle);
94
109
  };
95
110
  }, [disabled, input, loadSuggestions, touched]);
111
+ const eagerResolveLabel = typeof resolveLabel === "function" ? resolveLabel : void 0;
112
+ React.useEffect(() => {
113
+ if (!value || disabled) return;
114
+ if (knownLabelValues.has(value)) return;
115
+ let cancelled = false;
116
+ const apply = (label, description) => {
117
+ const clean = typeof label === "string" ? label.trim() : "";
118
+ if (cancelled || !clean || clean === value) return;
119
+ setResolvedOptions((prev) => {
120
+ if (prev.some((option) => option.value === value && option.label === clean)) return prev;
121
+ return [...prev.filter((option) => option.value !== value), { value, label: clean, description: description ?? null }];
122
+ });
123
+ };
124
+ if (eagerResolveLabel) {
125
+ Promise.resolve().then(() => eagerResolveLabel(value)).then((label) => apply(label, resolveDescription?.(value))).catch(() => {
126
+ });
127
+ return () => {
128
+ cancelled = true;
129
+ };
130
+ }
131
+ if (loadSuggestions) {
132
+ setLoading(true);
133
+ Promise.resolve().then(() => loadSuggestions()).then((items) => {
134
+ if (cancelled) return;
135
+ const normalized = normalizeOptions(items);
136
+ setAsyncOptions(normalized);
137
+ }).catch(() => {
138
+ }).finally(() => {
139
+ if (!cancelled) setLoading(false);
140
+ });
141
+ }
142
+ return () => {
143
+ cancelled = true;
144
+ };
145
+ }, [value, disabled, knownLabelValues, eagerResolveLabel, loadSuggestions]);
96
146
  React.useEffect(() => {
97
147
  if (document.activeElement !== inputRef.current) {
98
148
  const option = optionMap.get(value);
@@ -132,9 +182,13 @@ function ComboboxInput({
132
182
  return;
133
183
  }
134
184
  if (!allowCustomValues) {
135
- const currentOption = optionMap.get(value);
136
- setInput(currentOption?.label ?? value ?? "");
137
185
  setShowSuggestions(false);
186
+ const currentOption = optionMap.get(value);
187
+ if (currentOption && currentOption.label !== currentOption.value) {
188
+ setInput(currentOption.label);
189
+ } else if (!value) {
190
+ setInput("");
191
+ }
138
192
  return;
139
193
  }
140
194
  selectValue(raw);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/inputs/ComboboxInput.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n resolveLabel?: (value: string) => string\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n const suppressOpenOnFocusRef = React.useRef(Boolean(autoFocus && !disabled))\n\n const staticOptions = React.useMemo(() => normalizeOptions(suggestions), [suggestions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n if (!map.has(option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n map.set(value, {\n value,\n label: resolveLabel?.(value) ?? value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Sync input with value when value changes externally and input is not focused\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to current value if custom values not allowed\n const currentOption = optionMap.get(value)\n setInput(currentOption?.label ?? value ?? '')\n setShowSuggestions(false)\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n {/* Use raw <input> here instead of the DS Input primitive: ComboboxInput's\n focus / suggestions-popup interplay relies on the trigger being a plain\n input element. The DS wrapper introduces a <div> that desyncs autocomplete\n on this specific surface. Keeps the rest of the form on Input primitive. */}\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n if (suppressOpenOnFocusRef.current) {\n suppressOpenOnFocusRef.current = false\n return\n }\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-popover w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto\">\n {loading && touched ? (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">Loading suggestions\u2026</div>\n ) : (\n filteredSuggestions.map((option, index) => (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={[\n 'w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2',\n index === selectedIndex ? 'bg-accent' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectValue(option.value)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n <span className=\"font-medium\">{option.label}</span>\n {option.description ? (\n <span className=\"text-xs text-muted-foreground\">{option.description}</span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '../../primitives/button'\n\nexport type ComboboxOption = {\n value: string\n label: string\n description?: string | null\n}\n\nexport type ComboboxInputProps = {\n value: string\n onChange: (next: string) => void\n placeholder?: string\n suggestions?: Array<string | ComboboxOption>\n // Options to hydrate the option map up front (typically the linked entity's\n // display fields, already present in a record-detail payload). Merged with\n // `suggestions` so a pre-selected value renders its label without interaction.\n seedOptions?: ComboboxOption[]\n loadSuggestions?: (query?: string) => Promise<Array<string | ComboboxOption>>\n // Eagerly resolve a pre-selected `value` to a human label when it is not\n // covered by `suggestions`/`seedOptions`/`loadSuggestions` results. Runs once\n // per value, before any user interaction. May be sync or async.\n resolveLabel?: (value: string) => string | Promise<string>\n resolveDescription?: (value: string) => string | null | undefined\n autoFocus?: boolean\n disabled?: boolean\n allowCustomValues?: boolean\n}\n\nfunction normalizeOptions(input?: Array<string | ComboboxOption>): ComboboxOption[] {\n if (!Array.isArray(input)) return []\n return input\n .map((option) => {\n if (typeof option === 'string') {\n const trimmed = option.trim()\n if (!trimmed) return null\n return { value: trimmed, label: trimmed }\n }\n const value = typeof option.value === 'string' ? option.value.trim() : ''\n if (!value) return null\n return {\n value,\n label: option.label?.trim() || value,\n description: option.description ?? null,\n }\n })\n .filter((option): option is ComboboxOption => !!option)\n}\n\nexport function ComboboxInput({\n value,\n onChange,\n placeholder,\n suggestions,\n seedOptions,\n loadSuggestions,\n resolveLabel,\n resolveDescription,\n autoFocus,\n disabled = false,\n allowCustomValues = true,\n}: ComboboxInputProps) {\n const [input, setInput] = React.useState('')\n const [asyncOptions, setAsyncOptions] = React.useState<ComboboxOption[]>([])\n const [resolvedOptions, setResolvedOptions] = React.useState<ComboboxOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const [touched, setTouched] = React.useState(false)\n const [showSuggestions, setShowSuggestions] = React.useState(false)\n const [selectedIndex, setSelectedIndex] = React.useState(-1)\n const inputRef = React.useRef<HTMLInputElement>(null)\n const suppressOpenOnFocusRef = React.useRef(Boolean(autoFocus && !disabled))\n\n const staticOptions = React.useMemo(\n () => normalizeOptions([...(seedOptions ?? []), ...(suggestions ?? [])]),\n [seedOptions, suggestions]\n )\n\n // Options whose label is genuinely known (not a self-mapping `value === label`\n // placeholder). Used to decide whether eager resolution still needs to run.\n const knownLabelValues = React.useMemo(() => {\n const set = new Set<string>()\n for (const option of [...staticOptions, ...asyncOptions, ...resolvedOptions]) {\n if (option.label && option.label !== option.value) set.add(option.value)\n }\n return set\n }, [staticOptions, asyncOptions, resolvedOptions])\n\n const optionMap = React.useMemo(() => {\n const map = new Map<string, ComboboxOption>()\n const register = (option: ComboboxOption) => {\n const existing = map.get(option.value)\n // Prefer an entry that carries a real label over a self-mapping placeholder.\n if (!existing || (existing.label === existing.value && option.label !== option.value)) {\n map.set(option.value, option)\n }\n }\n staticOptions.forEach(register)\n asyncOptions.forEach(register)\n resolvedOptions.forEach(register)\n if (value) {\n const existing = map.get(value)\n if (!existing) {\n const sync = typeof resolveLabel === 'function' ? resolveLabel(value) : undefined\n map.set(value, {\n value,\n label: typeof sync === 'string' && sync ? sync : value,\n description: resolveDescription?.(value) ?? null,\n })\n }\n }\n return map\n }, [asyncOptions, resolvedOptions, resolveDescription, resolveLabel, staticOptions, value])\n\n const availableOptions = React.useMemo(() => {\n return Array.from(optionMap.values())\n }, [optionMap])\n\n const filteredSuggestions = React.useMemo(() => {\n const query = input.toLowerCase().trim()\n if (!query) return availableOptions\n return availableOptions.filter((option) => {\n const labelMatch = option.label.toLowerCase().includes(query)\n const descMatch = option.description?.toLowerCase().includes(query)\n return labelMatch || Boolean(descMatch)\n })\n }, [availableOptions, input])\n\n React.useEffect(() => {\n if (!loadSuggestions || !touched || disabled) return\n const query = input.trim()\n let cancelled = false\n const handle = window.setTimeout(async () => {\n setLoading(true)\n try {\n const items = await loadSuggestions(query)\n if (!cancelled) {\n setAsyncOptions(normalizeOptions(items))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n window.clearTimeout(handle)\n }\n }, [disabled, input, loadSuggestions, touched])\n\n // Eagerly resolve a pre-selected value to its label without requiring the user\n // to focus the field. Runs once per value when it is not already covered.\n const eagerResolveLabel = typeof resolveLabel === 'function' ? resolveLabel : undefined\n React.useEffect(() => {\n if (!value || disabled) return\n if (knownLabelValues.has(value)) return\n let cancelled = false\n const apply = (label?: string | null, description?: string | null) => {\n const clean = typeof label === 'string' ? label.trim() : ''\n if (cancelled || !clean || clean === value) return\n setResolvedOptions((prev) => {\n if (prev.some((option) => option.value === value && option.label === clean)) return prev\n return [...prev.filter((option) => option.value !== value), { value, label: clean, description: description ?? null }]\n })\n }\n if (eagerResolveLabel) {\n Promise.resolve()\n .then(() => eagerResolveLabel(value))\n .then((label) => apply(label, resolveDescription?.(value)))\n .catch(() => {})\n return () => { cancelled = true }\n }\n // Fallback: pull the first page of async suggestions so a remount that lost\n // its option cache can still recover the label without user interaction.\n if (loadSuggestions) {\n setLoading(true)\n Promise.resolve()\n .then(() => loadSuggestions())\n .then((items) => {\n if (cancelled) return\n const normalized = normalizeOptions(items)\n setAsyncOptions(normalized)\n })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n }\n return () => { cancelled = true }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value, disabled, knownLabelValues, eagerResolveLabel, loadSuggestions])\n\n // Sync input with value when value changes externally and input is not focused.\n React.useEffect(() => {\n if (document.activeElement !== inputRef.current) {\n const option = optionMap.get(value)\n setInput(option?.label ?? value ?? '')\n }\n }, [value, optionMap])\n\n const selectValue = React.useCallback(\n (nextValue: string) => {\n if (disabled) return\n const trimmed = nextValue.trim()\n onChange(trimmed)\n const option = optionMap.get(trimmed)\n setInput(option?.label ?? trimmed)\n setShowSuggestions(false)\n setSelectedIndex(-1)\n },\n [disabled, onChange, optionMap]\n )\n\n const findOptionForInput = React.useCallback(\n (raw: string): ComboboxOption | null => {\n const query = raw.trim().toLowerCase()\n if (!query) return null\n for (const option of optionMap.values()) {\n if (option.value === raw.trim()) return option\n if (option.label.toLowerCase() === query) return option\n }\n return null\n },\n [optionMap]\n )\n\n const confirmSelection = React.useCallback(\n (raw: string) => {\n if (disabled) return\n const option = findOptionForInput(raw)\n if (option) {\n selectValue(option.value)\n return\n }\n if (!allowCustomValues) {\n // Revert to the current value's label \u2014 but only if we actually know it.\n // Baking the raw value back in while eager resolution is still pending\n // would freeze a placeholder (e.g. a UUID) into the visible input.\n setShowSuggestions(false)\n const currentOption = optionMap.get(value)\n if (currentOption && currentOption.label !== currentOption.value) {\n setInput(currentOption.label)\n } else if (!value) {\n setInput('')\n }\n return\n }\n selectValue(raw)\n },\n [allowCustomValues, disabled, findOptionForInput, optionMap, selectValue, value]\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return\n\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n if (!showSuggestions) {\n setShowSuggestions(true)\n setSelectedIndex(0)\n } else {\n setSelectedIndex((prev) => Math.min(prev + 1, filteredSuggestions.length - 1))\n }\n } else if (event.key === 'ArrowUp') {\n event.preventDefault()\n setSelectedIndex((prev) => Math.max(prev - 1, -1))\n } else if (event.key === 'Enter') {\n event.preventDefault()\n if (selectedIndex >= 0 && filteredSuggestions[selectedIndex]) {\n selectValue(filteredSuggestions[selectedIndex].value)\n } else {\n confirmSelection(input)\n }\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setShowSuggestions(false)\n setSelectedIndex(-1)\n }\n },\n [confirmSelection, disabled, filteredSuggestions, input, selectValue, selectedIndex, showSuggestions]\n )\n\n return (\n <div className=\"relative w-full\">\n {/* Use raw <input> here instead of the DS Input primitive: ComboboxInput's\n focus / suggestions-popup interplay relies on the trigger being a plain\n input element. The DS wrapper introduces a <div> that desyncs autocomplete\n on this specific surface. Keeps the rest of the form on Input primitive. */}\n <input\n ref={inputRef}\n type=\"text\"\n className=\"w-full h-9 rounded border px-2 text-sm disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed\"\n value={input}\n placeholder={placeholder || 'Type to search...'}\n autoFocus={autoFocus}\n data-crud-focus-target=\"\"\n disabled={disabled}\n onFocus={() => {\n setTouched(true)\n if (suppressOpenOnFocusRef.current) {\n suppressOpenOnFocusRef.current = false\n return\n }\n setShowSuggestions(true)\n }}\n onChange={(event) => {\n setTouched(true)\n setInput(event.target.value)\n setShowSuggestions(true)\n setSelectedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n onBlur={() => {\n // Delay to allow click on suggestions\n setTimeout(() => {\n if (disabled) return\n confirmSelection(input)\n }, 200)\n }}\n />\n\n {showSuggestions && !disabled && (loading || filteredSuggestions.length > 0) && (\n <div className=\"absolute z-popover w-full mt-1 rounded border bg-popover shadow-lg max-h-48 sm:max-h-60 overflow-auto\">\n {loading && touched ? (\n <div className=\"px-3 py-2 text-xs text-muted-foreground\">Loading suggestions\u2026</div>\n ) : (\n filteredSuggestions.map((option, index) => (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={[\n 'w-full h-auto justify-start font-normal text-left flex flex-col items-start px-3 py-2',\n index === selectedIndex ? 'bg-accent' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n onMouseDown={(event) => event.preventDefault()}\n onClick={() => selectValue(option.value)}\n onMouseEnter={() => setSelectedIndex(index)}\n >\n <span className=\"font-medium\">{option.label}</span>\n {option.description ? (\n <span className=\"text-xs text-muted-foreground\">{option.description}</span>\n ) : null}\n </Button>\n ))\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,146 +1,10 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { format } from "date-fns";
5
- import { CalendarIcon } from "lucide-react";
6
- import { cn } from "@open-mercato/shared/lib/utils";
7
- import { useT } from "@open-mercato/shared/lib/i18n/context";
8
- import { Popover, PopoverContent, PopoverTrigger } from "../../primitives/popover.js";
9
- import { Calendar } from "../../primitives/calendar.js";
10
- const DAY_FIRST_LOCALE_CODES = /* @__PURE__ */ new Set([
11
- "pl",
12
- "de",
13
- "fr",
14
- "es",
15
- "it",
16
- "pt",
17
- "nl",
18
- "ru",
19
- "cs",
20
- "sk",
21
- "hu",
22
- "ro"
23
- ]);
24
- function deriveDisplayFormat(locale) {
25
- if (!locale) return "MMM d, yyyy";
26
- const code = locale.code?.split("-")[0]?.toLowerCase() ?? "";
27
- return DAY_FIRST_LOCALE_CODES.has(code) ? "d MMM yyyy" : "MMM d, yyyy";
28
- }
29
- function DatePicker({
30
- value,
31
- onChange,
32
- placeholder,
33
- disabled = false,
34
- readOnly = false,
35
- className,
36
- locale,
37
- displayFormat,
38
- showTodayButton = true,
39
- showClearButton = true,
40
- closeOnSelect = true,
41
- minDate,
42
- maxDate
43
- }) {
44
- const t = useT();
45
- const [open, setOpen] = React.useState(false);
46
- const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale);
47
- const placeholderText = placeholder ?? t("ui.datePicker.placeholder", "Pick a date");
48
- const todayText = t("ui.datePicker.todayButton", "Today");
49
- const clearText = t("ui.datePicker.clearButton", "Clear");
50
- const formattedValue = React.useMemo(() => {
51
- if (!value) return null;
52
- try {
53
- return format(value, resolvedFormat, locale ? { locale } : void 0);
54
- } catch {
55
- return null;
56
- }
57
- }, [value, resolvedFormat, locale]);
58
- const handleDaySelect = React.useCallback(
59
- (day) => {
60
- if (!day) return;
61
- const next = new Date(day);
62
- next.setHours(0, 0, 0, 0);
63
- onChange(next);
64
- if (closeOnSelect) setOpen(false);
65
- },
66
- [onChange, closeOnSelect]
67
- );
68
- const handleToday = React.useCallback(() => {
69
- const today = /* @__PURE__ */ new Date();
70
- today.setHours(0, 0, 0, 0);
71
- onChange(today);
72
- setOpen(false);
73
- }, [onChange]);
74
- const handleClear = React.useCallback(() => {
75
- onChange(null);
76
- setOpen(false);
77
- }, [onChange]);
78
- const isInteractive = !disabled && !readOnly;
79
- const disabledMatcher = React.useMemo(() => {
80
- if (!minDate && !maxDate) return void 0;
81
- const matchers = [];
82
- if (minDate) matchers.push({ before: minDate });
83
- if (maxDate) matchers.push({ after: maxDate });
84
- return matchers;
85
- }, [minDate, maxDate]);
86
- return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: isInteractive ? setOpen : void 0, children: [
87
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
88
- "button",
89
- {
90
- type: "button",
91
- "data-crud-focus-target": "",
92
- disabled,
93
- "aria-haspopup": "dialog",
94
- className: cn(
95
- "w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
96
- "bg-background transition-colors",
97
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
98
- "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
99
- readOnly && "cursor-default opacity-70",
100
- !formattedValue && "text-muted-foreground",
101
- className
102
- ),
103
- onClick: isInteractive ? void 0 : (e) => e.preventDefault(),
104
- children: [
105
- /* @__PURE__ */ jsx(CalendarIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
106
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: formattedValue ?? placeholderText })
107
- ]
108
- }
109
- ) }),
110
- /* @__PURE__ */ jsxs(PopoverContent, { className: "p-0 w-auto", children: [
111
- /* @__PURE__ */ jsx(
112
- Calendar,
113
- {
114
- mode: "single",
115
- selected: value ?? void 0,
116
- onSelect: handleDaySelect,
117
- locale,
118
- disabled: disabledMatcher,
119
- initialFocus: true
120
- }
121
- ),
122
- (showTodayButton || showClearButton) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-t px-3 py-2", children: [
123
- showTodayButton && /* @__PURE__ */ jsx(
124
- "button",
125
- {
126
- type: "button",
127
- onClick: handleToday,
128
- className: "text-sm text-primary hover:underline focus-visible:outline-none",
129
- children: todayText
130
- }
131
- ),
132
- showClearButton && /* @__PURE__ */ jsx(
133
- "button",
134
- {
135
- type: "button",
136
- onClick: handleClear,
137
- className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
138
- children: clearText
139
- }
140
- )
141
- ] })
142
- ] })
143
- ] });
2
+ import { jsx } from "react/jsx-runtime";
3
+ import {
4
+ DatePicker as DatePickerPrimitive
5
+ } from "../../primitives/date-picker.js";
6
+ function DatePicker(props) {
7
+ return /* @__PURE__ */ jsx(DatePickerPrimitive, { ...props });
144
8
  }
145
9
  export {
146
10
  DatePicker
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/inputs/DatePicker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\n\nexport type DatePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n showTodayButton?: boolean\n showClearButton?: boolean\n closeOnSelect?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy' : 'MMM d, yyyy'\n}\n\nexport function DatePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n showTodayButton = true,\n showClearButton = true,\n closeOnSelect = true,\n minDate,\n maxDate,\n}: DatePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.datePicker.placeholder', 'Pick a date')\n const todayText = t('ui.datePicker.todayButton', 'Today')\n const clearText = t('ui.datePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const next = new Date(day)\n next.setHours(0, 0, 0, 0)\n onChange(next)\n if (closeOnSelect) setOpen(false)\n },\n [onChange, closeOnSelect]\n )\n\n const handleToday = React.useCallback(() => {\n const today = new Date()\n today.setHours(0, 0, 0, 0)\n onChange(today)\n setOpen(false)\n }, [onChange])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2 border-t px-3 py-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus-visible:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
- "mappings": ";AAyGQ,SAgBE,KAhBF;AAvGR,YAAY,WAAW;AACvB,SAAS,cAAc;AAEvB,SAAS,oBAAoB;AAC7B,SAAS,UAAU;AACnB,SAAS,YAAY;AACrB,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,gBAAgB;AAkBzB,MAAM,yBAAyB,oBAAI,IAAI;AAAA,EACrC;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AACpE,CAAC;AAED,SAAS,oBAAoB,QAAyB;AACpD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,YAAY,KAAK;AAC1D,SAAO,uBAAuB,IAAI,IAAI,IAAI,eAAe;AAC3D;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAE5C,QAAM,iBAAiB,iBAAiB,oBAAoB,MAAM;AAClE,QAAM,kBAAkB,eAAe,EAAE,6BAA6B,aAAa;AACnF,QAAM,YAAY,EAAE,6BAA6B,OAAO;AACxD,QAAM,YAAY,EAAE,6BAA6B,OAAO;AAExD,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACzC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI;AACF,aAAO,OAAO,OAAO,gBAAgB,SAAS,EAAE,OAAO,IAAI,MAAS;AAAA,IACtE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,OAAO,gBAAgB,MAAM,CAAC;AAElC,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,QAA0B;AACzB,UAAI,CAAC,IAAK;AACV,YAAM,OAAO,IAAI,KAAK,GAAG;AACzB,WAAK,SAAS,GAAG,GAAG,GAAG,CAAC;AACxB,eAAS,IAAI;AACb,UAAI,cAAe,SAAQ,KAAK;AAAA,IAClC;AAAA,IACA,CAAC,UAAU,aAAa;AAAA,EAC1B;AAEA,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AACzB,aAAS,KAAK;AACd,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,cAAc,MAAM,YAAY,MAAM;AAC1C,aAAS,IAAI;AACb,YAAQ,KAAK;AAAA,EACf,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,gBAAgB,CAAC,YAAY,CAAC;AAEpC,QAAM,kBAAkB,MAAM,QAAQ,MAAM;AAC1C,QAAI,CAAC,WAAW,CAAC,QAAS,QAAO;AACjC,UAAM,WAAiD,CAAC;AACxD,QAAI,QAAS,UAAS,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAC9C,QAAI,QAAS,UAAS,KAAK,EAAE,OAAO,QAAQ,CAAC;AAC7C,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,SACE,qBAAC,WAAQ,MAAY,cAAc,gBAAgB,UAAU,QAC3D;AAAA,wBAAC,kBAAe,SAAO,MACrB;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,0BAAuB;AAAA,QACvB;AAAA,QACA,iBAAc;AAAA,QACd,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ,CAAC,kBAAkB;AAAA,UACnB;AAAA,QACF;AAAA,QACA,SAAS,gBAAgB,SAAY,CAAC,MAAM,EAAE,eAAe;AAAA,QAE7D;AAAA,8BAAC,gBAAa,WAAU,0CAAyC;AAAA,UACjE,oBAAC,UAAK,WAAU,mBACb,4BAAkB,iBACrB;AAAA;AAAA;AAAA,IACF,GACF;AAAA,IACA,qBAAC,kBAAe,WAAU,cACxB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,SAAS;AAAA,UACnB,UAAU;AAAA,UACV;AAAA,UACA,UAAU;AAAA,UACV,cAAY;AAAA;AAAA,MACd;AAAA,OACE,mBAAmB,oBACnB,qBAAC,SAAI,WAAU,8DACZ;AAAA,2BACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,QAED,mBACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAU;AAAA,YAET;AAAA;AAAA,QACH;AAAA,SAEJ;AAAA,OAEJ;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["/**\n * @deprecated Import from `@open-mercato/ui/primitives/date-picker` instead.\n *\n * This shim preserves the legacy import path\n * `@open-mercato/ui/backend/inputs/DatePicker` for existing consumers\n * (CrudForm, example pages) while the DatePicker is promoted to a\n * primitive in DS Foundation v3.\n *\n * Default footer is the Figma-aligned `'apply-cancel'` mode (per user\n * directive 2026-05-09 \u2014 \"zmie\u0144 globalnie\"). Consumers that explicitly\n * need the legacy `Today` / `Clear` footer can pass `footer=\"today-clear\"`.\n *\n * Migration: replace\n * import { DatePicker } from '@open-mercato/ui/backend/inputs/DatePicker'\n * with\n * import { DatePicker } from '@open-mercato/ui/primitives/date-picker'\n */\n\n\"use client\"\n\nimport * as React from 'react'\nimport {\n DatePicker as DatePickerPrimitive,\n type DatePickerProps as DatePickerPrimitivePropsBase,\n type DatePickerFooter,\n} from '../../primitives/date-picker'\n\nexport type DatePickerProps = DatePickerPrimitivePropsBase\n\n/** @deprecated Use `DatePicker` from `@open-mercato/ui/primitives/date-picker`. */\nexport function DatePicker(props: DatePickerProps) {\n return <DatePickerPrimitive {...props} />\n}\n\nexport type { DatePickerFooter }\n"],
5
+ "mappings": ";AA+BS;AAVT;AAAA,EACE,cAAc;AAAA,OAGT;AAKA,SAAS,WAAW,OAAwB;AACjD,SAAO,oBAAC,uBAAqB,GAAG,OAAO;AACzC;",
6
6
  "names": []
7
7
  }
@@ -1,186 +1,10 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import * as React from "react";
4
- import { format } from "date-fns";
5
- import { CalendarIcon } from "lucide-react";
6
- import { cn } from "@open-mercato/shared/lib/utils";
7
- import { useT } from "@open-mercato/shared/lib/i18n/context";
8
- import { Popover, PopoverContent, PopoverTrigger } from "../../primitives/popover.js";
9
- import { Calendar } from "../../primitives/calendar.js";
10
- import { TimeInput } from "./TimeInput.js";
11
- const DAY_FIRST_LOCALE_CODES = /* @__PURE__ */ new Set([
12
- "pl",
13
- "de",
14
- "fr",
15
- "es",
16
- "it",
17
- "pt",
18
- "nl",
19
- "ru",
20
- "cs",
21
- "sk",
22
- "hu",
23
- "ro"
24
- ]);
25
- function deriveDisplayFormat(locale) {
26
- if (!locale) return "MMM d, yyyy HH:mm";
27
- const code = locale.code?.split("-")[0]?.toLowerCase() ?? "";
28
- return DAY_FIRST_LOCALE_CODES.has(code) ? "d MMM yyyy HH:mm" : "MMM d, yyyy HH:mm";
29
- }
30
- function extractTime(date) {
31
- const hour = String(date.getHours()).padStart(2, "0");
32
- const minute = String(date.getMinutes()).padStart(2, "0");
33
- return `${hour}:${minute}`;
34
- }
35
- function applyTimeToDate(base, time) {
36
- const parts = time.split(":");
37
- const hour = parseInt(parts[0] ?? "0", 10);
38
- const minute = parseInt(parts[1] ?? "0", 10);
39
- const next = new Date(base);
40
- next.setHours(isNaN(hour) ? 0 : hour);
41
- next.setMinutes(isNaN(minute) ? 0 : minute);
42
- next.setSeconds(0);
43
- next.setMilliseconds(0);
44
- return next;
45
- }
46
- function DateTimePicker({
47
- value,
48
- onChange,
49
- placeholder,
50
- disabled = false,
51
- readOnly = false,
52
- className,
53
- locale,
54
- displayFormat,
55
- minuteStep = 1,
56
- showTodayButton = true,
57
- showClearButton = true,
58
- minDate,
59
- maxDate
60
- }) {
61
- const t = useT();
62
- const [open, setOpen] = React.useState(false);
63
- const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale);
64
- const placeholderText = placeholder ?? t("ui.dateTimePicker.placeholder", "Pick date and time");
65
- const timeLabelText = t("ui.dateTimePicker.timeLabel", "Time");
66
- const todayText = t("ui.dateTimePicker.todayButton", "Today");
67
- const clearText = t("ui.dateTimePicker.clearButton", "Clear");
68
- const formattedValue = React.useMemo(() => {
69
- if (!value) return null;
70
- try {
71
- return format(value, resolvedFormat, locale ? { locale } : void 0);
72
- } catch {
73
- return null;
74
- }
75
- }, [value, resolvedFormat, locale]);
76
- const handleDaySelect = React.useCallback(
77
- (day) => {
78
- if (!day) return;
79
- const currentTime = value ? extractTime(value) : "00:00";
80
- onChange(applyTimeToDate(day, currentTime));
81
- },
82
- [onChange, value]
83
- );
84
- const handleTimeChange = React.useCallback(
85
- (time) => {
86
- const base = value ?? null;
87
- if (!base) return;
88
- onChange(applyTimeToDate(base, time));
89
- },
90
- [onChange, value]
91
- );
92
- const handleToday = React.useCallback(() => {
93
- const now = /* @__PURE__ */ new Date();
94
- const currentTime = value ? extractTime(value) : extractTime(now);
95
- onChange(applyTimeToDate(now, currentTime));
96
- setOpen(false);
97
- }, [onChange, value]);
98
- const handleClear = React.useCallback(() => {
99
- onChange(null);
100
- setOpen(false);
101
- }, [onChange]);
102
- const isInteractive = !disabled && !readOnly;
103
- const disabledMatcher = React.useMemo(() => {
104
- if (!minDate && !maxDate) return void 0;
105
- const matchers = [];
106
- if (minDate) matchers.push({ before: minDate });
107
- if (maxDate) matchers.push({ after: maxDate });
108
- return matchers;
109
- }, [minDate, maxDate]);
110
- return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: isInteractive ? setOpen : void 0, children: [
111
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
112
- "button",
113
- {
114
- type: "button",
115
- "data-crud-focus-target": "",
116
- disabled,
117
- "aria-haspopup": "dialog",
118
- className: cn(
119
- "w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left",
120
- "bg-background transition-colors",
121
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
122
- "disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed",
123
- readOnly && "cursor-default opacity-70",
124
- !formattedValue && "text-muted-foreground",
125
- className
126
- ),
127
- onClick: isInteractive ? void 0 : (e) => e.preventDefault(),
128
- children: [
129
- /* @__PURE__ */ jsx(CalendarIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
130
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: formattedValue ?? placeholderText })
131
- ]
132
- }
133
- ) }),
134
- /* @__PURE__ */ jsxs(PopoverContent, { className: "p-0 w-auto", children: [
135
- /* @__PURE__ */ jsx(
136
- Calendar,
137
- {
138
- mode: "single",
139
- selected: value ?? void 0,
140
- onSelect: handleDaySelect,
141
- locale,
142
- disabled: disabledMatcher,
143
- initialFocus: true
144
- }
145
- ),
146
- /* @__PURE__ */ jsxs("div", { className: "border-t px-3 py-2 space-y-2", children: [
147
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
148
- /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground shrink-0", children: [
149
- timeLabelText,
150
- ":"
151
- ] }),
152
- /* @__PURE__ */ jsx(
153
- TimeInput,
154
- {
155
- value: value ? extractTime(value) : void 0,
156
- onChange: handleTimeChange,
157
- minuteStep
158
- }
159
- )
160
- ] }),
161
- (showTodayButton || showClearButton) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
162
- showTodayButton && /* @__PURE__ */ jsx(
163
- "button",
164
- {
165
- type: "button",
166
- onClick: handleToday,
167
- className: "text-sm text-primary hover:underline focus-visible:outline-none",
168
- children: todayText
169
- }
170
- ),
171
- showClearButton && /* @__PURE__ */ jsx(
172
- "button",
173
- {
174
- type: "button",
175
- onClick: handleClear,
176
- className: "text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto",
177
- children: clearText
178
- }
179
- )
180
- ] })
181
- ] })
182
- ] })
183
- ] });
2
+ import { jsx } from "react/jsx-runtime";
3
+ import {
4
+ DatePicker as DatePickerPrimitive
5
+ } from "../../primitives/date-picker.js";
6
+ function DateTimePicker(props) {
7
+ return /* @__PURE__ */ jsx(DatePickerPrimitive, { ...props, withTime: true });
184
8
  }
185
9
  export {
186
10
  DateTimePicker
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/backend/inputs/DateTimePicker.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { format } from 'date-fns'\nimport type { Locale } from 'date-fns'\nimport { CalendarIcon } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../primitives/popover'\nimport { Calendar } from '../../primitives/calendar'\nimport { TimeInput } from './TimeInput'\n\nexport type DateTimePickerProps = {\n value?: Date | null\n onChange: (date: Date | null) => void\n placeholder?: string\n disabled?: boolean\n readOnly?: boolean\n className?: string\n locale?: Locale\n displayFormat?: string\n minuteStep?: number\n showTodayButton?: boolean\n showClearButton?: boolean\n minDate?: Date\n maxDate?: Date\n}\n\nconst DAY_FIRST_LOCALE_CODES = new Set([\n 'pl', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'ru', 'cs', 'sk', 'hu', 'ro',\n])\n\nfunction deriveDisplayFormat(locale?: Locale): string {\n if (!locale) return 'MMM d, yyyy HH:mm'\n const code = locale.code?.split('-')[0]?.toLowerCase() ?? ''\n return DAY_FIRST_LOCALE_CODES.has(code) ? 'd MMM yyyy HH:mm' : 'MMM d, yyyy HH:mm'\n}\n\nfunction extractTime(date: Date): string {\n const hour = String(date.getHours()).padStart(2, '0')\n const minute = String(date.getMinutes()).padStart(2, '0')\n return `${hour}:${minute}`\n}\n\nfunction applyTimeToDate(base: Date, time: string): Date {\n const parts = time.split(':')\n const hour = parseInt(parts[0] ?? '0', 10)\n const minute = parseInt(parts[1] ?? '0', 10)\n const next = new Date(base)\n next.setHours(isNaN(hour) ? 0 : hour)\n next.setMinutes(isNaN(minute) ? 0 : minute)\n next.setSeconds(0)\n next.setMilliseconds(0)\n return next\n}\n\nexport function DateTimePicker({\n value,\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n className,\n locale,\n displayFormat,\n minuteStep = 1,\n showTodayButton = true,\n showClearButton = true,\n minDate,\n maxDate,\n}: DateTimePickerProps) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n\n const resolvedFormat = displayFormat ?? deriveDisplayFormat(locale)\n const placeholderText = placeholder ?? t('ui.dateTimePicker.placeholder', 'Pick date and time')\n const timeLabelText = t('ui.dateTimePicker.timeLabel', 'Time')\n const todayText = t('ui.dateTimePicker.todayButton', 'Today')\n const clearText = t('ui.dateTimePicker.clearButton', 'Clear')\n\n const formattedValue = React.useMemo(() => {\n if (!value) return null\n try {\n return format(value, resolvedFormat, locale ? { locale } : undefined)\n } catch {\n return null\n }\n }, [value, resolvedFormat, locale])\n\n const handleDaySelect = React.useCallback(\n (day: Date | undefined) => {\n if (!day) return\n const currentTime = value ? extractTime(value) : '00:00'\n onChange(applyTimeToDate(day, currentTime))\n },\n [onChange, value]\n )\n\n const handleTimeChange = React.useCallback(\n (time: string) => {\n const base = value ?? null\n if (!base) return\n onChange(applyTimeToDate(base, time))\n },\n [onChange, value]\n )\n\n const handleToday = React.useCallback(() => {\n const now = new Date()\n const currentTime = value ? extractTime(value) : extractTime(now)\n onChange(applyTimeToDate(now, currentTime))\n setOpen(false)\n }, [onChange, value])\n\n const handleClear = React.useCallback(() => {\n onChange(null)\n setOpen(false)\n }, [onChange])\n\n const isInteractive = !disabled && !readOnly\n\n const disabledMatcher = React.useMemo(() => {\n if (!minDate && !maxDate) return undefined\n const matchers: import('react-day-picker').Matcher[] = []\n if (minDate) matchers.push({ before: minDate })\n if (maxDate) matchers.push({ after: maxDate })\n return matchers\n }, [minDate, maxDate])\n\n return (\n <Popover open={open} onOpenChange={isInteractive ? setOpen : undefined}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-crud-focus-target=\"\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n className={cn(\n 'w-full h-9 flex items-center gap-2 rounded border px-3 text-sm text-left',\n 'bg-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed',\n readOnly && 'cursor-default opacity-70',\n !formattedValue && 'text-muted-foreground',\n className\n )}\n onClick={isInteractive ? undefined : (e) => e.preventDefault()}\n >\n <CalendarIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex-1 truncate\">\n {formattedValue ?? placeholderText}\n </span>\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0 w-auto\">\n <Calendar\n mode=\"single\"\n selected={value ?? undefined}\n onSelect={handleDaySelect}\n locale={locale}\n disabled={disabledMatcher}\n initialFocus\n />\n <div className=\"border-t px-3 py-2 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground shrink-0\">{timeLabelText}:</span>\n <TimeInput\n value={value ? extractTime(value) : undefined}\n onChange={handleTimeChange}\n minuteStep={minuteStep}\n />\n </div>\n {(showTodayButton || showClearButton) && (\n <div className=\"flex items-center justify-between gap-2\">\n {showTodayButton && (\n <button\n type=\"button\"\n onClick={handleToday}\n className=\"text-sm text-primary hover:underline focus-visible:outline-none\"\n >\n {todayText}\n </button>\n )}\n {showClearButton && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"text-sm text-muted-foreground hover:text-foreground hover:underline focus-visible:outline-none ml-auto\"\n >\n {clearText}\n </button>\n )}\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @deprecated Import `DatePicker` from `@open-mercato/ui/primitives/date-picker`\n * and pass `withTime` instead. The standalone `DateTimePicker` is replaced by\n * a `withTime` prop on the unified primitive in DS Foundation v3.\n *\n * Default footer is the Figma-aligned `'apply-cancel'` mode (per user\n * directive 2026-05-09 \u2014 \"zmie\u0144 globalnie\"). Consumers that explicitly\n * need the legacy `Today` / `Clear` footer can pass `footer=\"today-clear\"`.\n *\n * Migration: replace\n * import { DateTimePicker } from '@open-mercato/ui/backend/inputs/DateTimePicker'\n * <DateTimePicker value={...} onChange={...} />\n * with\n * import { DatePicker } from '@open-mercato/ui/primitives/date-picker'\n * <DatePicker value={...} onChange={...} withTime />\n */\n\n\"use client\"\n\nimport * as React from 'react'\nimport {\n DatePicker as DatePickerPrimitive,\n type DatePickerProps as DatePickerPrimitiveProps,\n} from '../../primitives/date-picker'\n\nexport type DateTimePickerProps = Omit<DatePickerPrimitiveProps, 'withTime'>\n\n/** @deprecated Use `DatePicker withTime` from `@open-mercato/ui/primitives/date-picker`. */\nexport function DateTimePicker(props: DateTimePickerProps) {\n return <DatePickerPrimitive {...props} withTime />\n}\n"],
5
+ "mappings": ";AA6BS;AATT;AAAA,EACE,cAAc;AAAA,OAET;AAKA,SAAS,eAAe,OAA4B;AACzD,SAAO,oBAAC,uBAAqB,GAAG,OAAO,UAAQ,MAAC;AAClD;",
6
6
  "names": []
7
7
  }