@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
@@ -93,7 +93,7 @@ import { useGroupOrder } from "./crud/useGroupOrder.js";
93
93
  import { InjectedField } from "./injection/InjectedField.js";
94
94
  import { evaluateInjectedVisibility } from "./injection/visibility-utils.js";
95
95
  import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
96
- import { sanitizeHtmlRichText, sanitizeRichTextHref, sanitizeRichTextPasteContent } from "./utils/richTextSanitizer.js";
96
+ import { RichEditor } from "../primitives/rich-editor.js";
97
97
  const EMPTY_OPTIONS = [];
98
98
  const SELECT_CLEAR_SENTINEL = "__crudform_select_clear__";
99
99
  const FOCUSABLE_SELECTOR = '[data-crud-focus-target], input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
@@ -2913,120 +2913,27 @@ const MarkdownEditor = React.memo(function MarkdownEditor2({ value = "", onChang
2913
2913
  }
2914
2914
  ) });
2915
2915
  }, (prev, next) => prev.value === next.value);
2916
- const HtmlRichTextEditor = React.memo(function HtmlRichTextEditor2({ value = "", onChange }) {
2916
+ const HtmlRichEditorField = React.memo(function HtmlRichEditorField2({ value = "", onChange }) {
2917
2917
  const t = useT();
2918
- const boldLabel = t("ui.forms.richtext.bold");
2919
- const italicLabel = t("ui.forms.richtext.italic");
2920
- const underlineLabel = t("ui.forms.richtext.underline");
2921
- const listLabel = t("ui.forms.richtext.list");
2922
- const heading3Label = t("ui.forms.richtext.heading3");
2923
- const linkLabel = t("ui.forms.richtext.link");
2924
- const linkUrlPrompt = t("ui.forms.richtext.linkUrlPrompt");
2925
- const ref = React.useRef(null);
2926
- const applyingExternal = React.useRef(false);
2927
- const typingRef = React.useRef(false);
2928
- React.useEffect(() => {
2929
- const el = ref.current;
2930
- if (!el) return;
2931
- const current = el.innerHTML;
2932
- const sanitizedValue = sanitizeHtmlRichText(value);
2933
- if (!typingRef.current && current !== sanitizedValue) {
2934
- applyingExternal.current = true;
2935
- el.innerHTML = sanitizedValue;
2936
- requestAnimationFrame(() => {
2937
- applyingExternal.current = false;
2938
- });
2939
- }
2940
- }, [value]);
2941
- const exec = (cmd, arg) => {
2942
- const el = ref.current;
2943
- if (!el) return;
2944
- el.focus();
2945
- try {
2946
- document.execCommand(cmd, false, arg);
2947
- } catch {
2948
- }
2949
- };
2950
- const onKeyDown = (e) => {
2951
- const isMod = e.metaKey || e.ctrlKey;
2952
- if (!isMod) return;
2953
- const k = e.key.toLowerCase();
2954
- if (k === "b") {
2955
- e.preventDefault();
2956
- exec("bold");
2957
- }
2958
- if (k === "i") {
2959
- e.preventDefault();
2960
- exec("italic");
2961
- }
2962
- if (k === "u") {
2963
- e.preventDefault();
2964
- exec("underline");
2965
- }
2966
- };
2967
- const onPaste = (e) => {
2968
- const html = e.clipboardData.getData("text/html");
2969
- const text = e.clipboardData.getData("text/plain");
2970
- const sanitizedPaste = sanitizeRichTextPasteContent(html, text);
2971
- if (!sanitizedPaste) return;
2972
- e.preventDefault();
2973
- exec(sanitizedPaste.command, sanitizedPaste.value);
2974
- };
2975
- return /* @__PURE__ */ jsxs("div", { className: "w-full rounded border", children: [
2976
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1 border-b", children: [
2977
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "h-auto px-2 py-0.5 text-xs", onMouseDown: (e) => e.preventDefault(), onClick: () => exec("bold"), children: boldLabel }),
2978
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "h-auto px-2 py-0.5 text-xs", onMouseDown: (e) => e.preventDefault(), onClick: () => exec("italic"), children: italicLabel }),
2979
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "h-auto px-2 py-0.5 text-xs", onMouseDown: (e) => e.preventDefault(), onClick: () => exec("underline"), children: underlineLabel }),
2980
- /* @__PURE__ */ jsx("span", { className: "mx-2 text-muted-foreground", children: "|" }),
2981
- /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", className: "h-auto px-2 py-0.5 text-xs", onMouseDown: (e) => e.preventDefault(), onClick: () => exec("insertUnorderedList"), children: [
2982
- "\u2022 ",
2983
- listLabel
2984
- ] }),
2985
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "h-auto px-2 py-0.5 text-xs", onMouseDown: (e) => e.preventDefault(), onClick: () => exec("formatBlock", "<h3>"), children: heading3Label }),
2986
- /* @__PURE__ */ jsx(
2987
- Button,
2988
- {
2989
- variant: "ghost",
2990
- size: "sm",
2991
- className: "h-auto px-2 py-0.5 text-xs",
2992
- onMouseDown: (e) => e.preventDefault(),
2993
- onClick: () => {
2994
- const url = sanitizeRichTextHref(window.prompt(linkUrlPrompt));
2995
- if (url) exec("createLink", url);
2996
- },
2997
- children: linkLabel
2998
- }
2999
- )
3000
- ] }),
3001
- /* @__PURE__ */ jsx(
3002
- "div",
3003
- {
3004
- ref,
3005
- className: "w-full px-2 py-2 min-h-[100px] sm:min-h-[160px] focus-visible:outline-none prose prose-sm max-w-none",
3006
- contentEditable: true,
3007
- suppressContentEditableWarning: true,
3008
- onKeyDown,
3009
- onPaste,
3010
- onInput: () => {
3011
- if (!applyingExternal.current) typingRef.current = true;
3012
- },
3013
- onBlur: () => {
3014
- const el = ref.current;
3015
- if (!el) return;
3016
- typingRef.current = false;
3017
- const sanitizedValue = sanitizeHtmlRichText(el.innerHTML);
3018
- if (el.innerHTML !== sanitizedValue) {
3019
- applyingExternal.current = true;
3020
- el.innerHTML = sanitizedValue;
3021
- requestAnimationFrame(() => {
3022
- applyingExternal.current = false;
3023
- });
3024
- }
3025
- onChange(sanitizedValue);
3026
- }
3027
- }
3028
- )
3029
- ] });
2918
+ const labels = React.useMemo(() => ({
2919
+ bold: t("ui.forms.richtext.bold"),
2920
+ italic: t("ui.forms.richtext.italic"),
2921
+ underline: t("ui.forms.richtext.underline"),
2922
+ unorderedList: t("ui.forms.richtext.list"),
2923
+ orderedList: t("ui.forms.richtext.orderedList", "Numbered list"),
2924
+ heading: t("ui.forms.richtext.heading", "Heading"),
2925
+ heading1: t("ui.forms.richtext.heading1", "Heading 1"),
2926
+ heading2: t("ui.forms.richtext.heading2", "Heading 2"),
2927
+ heading3: t("ui.forms.richtext.heading3"),
2928
+ paragraph: t("ui.forms.richtext.paragraph", "Paragraph"),
2929
+ link: t("ui.forms.richtext.link"),
2930
+ linkUrlPrompt: t("ui.forms.richtext.linkUrlPrompt"),
2931
+ placeholder: t("ui.forms.richtext.placeholder"),
2932
+ comment: t("ui.forms.richtext.comment", "Add comment"),
2933
+ mention: t("ui.forms.richtext.mention", "Mention"),
2934
+ more: t("ui.forms.richtext.more", "More")
2935
+ }), [t]);
2936
+ return /* @__PURE__ */ jsx(RichEditor, { value, onChange, variant: "full", labels });
3030
2937
  }, (prev, next) => prev.value === next.value);
3031
2938
  const SimpleMarkdownEditor = React.memo(function SimpleMarkdownEditor2({ value = "", onChange }) {
3032
2939
  const t = useT();
@@ -3252,25 +3159,33 @@ const FieldControl = React.memo(
3252
3159
  }
3253
3160
  ),
3254
3161
  field.type === "date" && /* @__PURE__ */ jsx(
3255
- Input,
3162
+ DatePicker,
3256
3163
  {
3257
- type: "date",
3258
- value: typeof value === "string" ? value : "",
3259
- onChange: (e) => setValue(field.id, e.target.value || void 0),
3260
- autoFocus: autoFocusField,
3261
- "data-crud-focus-target": "",
3262
- disabled
3164
+ value: typeof value === "string" && value ? parseISO(value) : value instanceof Date ? value : null,
3165
+ onChange: (date) => setValue(field.id, date ? format(date, "yyyy-MM-dd") : void 0),
3166
+ disabled,
3167
+ readOnly,
3168
+ placeholder,
3169
+ minDate: builtin?.minDate,
3170
+ maxDate: builtin?.maxDate,
3171
+ displayFormat: builtin?.displayFormat,
3172
+ closeOnSelect: builtin?.closeOnSelect,
3173
+ locale: builtin?.locale
3263
3174
  }
3264
3175
  ),
3265
3176
  field.type === "datetime-local" && /* @__PURE__ */ jsx(
3266
- Input,
3177
+ DateTimePicker,
3267
3178
  {
3268
- type: "datetime-local",
3269
- value: typeof value === "string" ? value : "",
3270
- onChange: (e) => setValue(field.id, e.target.value || void 0),
3271
- autoFocus: autoFocusField,
3272
- "data-crud-focus-target": "",
3273
- disabled
3179
+ value: typeof value === "string" && value ? new Date(value) : value instanceof Date ? value : null,
3180
+ onChange: (date) => setValue(field.id, date ? format(date, "yyyy-MM-dd'T'HH:mm") : void 0),
3181
+ disabled,
3182
+ readOnly,
3183
+ placeholder,
3184
+ minuteStep: builtin?.minuteStep,
3185
+ minDate: builtin?.minDate,
3186
+ maxDate: builtin?.maxDate,
3187
+ displayFormat: builtin?.displayFormat,
3188
+ locale: builtin?.locale
3274
3189
  }
3275
3190
  ),
3276
3191
  field.type === "datepicker" && /* @__PURE__ */ jsx(
@@ -3328,7 +3243,7 @@ const FieldControl = React.memo(
3328
3243
  }
3329
3244
  ),
3330
3245
  field.type === "richtext" && builtin?.editor === "simple" && /* @__PURE__ */ jsx(SimpleMarkdownEditor, { value: String(value ?? ""), onChange: fieldSetValue }),
3331
- field.type === "richtext" && builtin?.editor === "html" && /* @__PURE__ */ jsx(HtmlRichTextEditor, { value: String(value ?? ""), onChange: fieldSetValue }),
3246
+ field.type === "richtext" && builtin?.editor === "html" && /* @__PURE__ */ jsx(HtmlRichEditorField, { value: String(value ?? ""), onChange: fieldSetValue }),
3332
3247
  field.type === "richtext" && (!builtin?.editor || builtin.editor !== "simple" && builtin.editor !== "html") && /* @__PURE__ */ jsx(MarkdownEditor, { value: String(value ?? ""), onChange: fieldSetValue }),
3333
3248
  field.type === "tags" && /* @__PURE__ */ jsx(
3334
3249
  TagsInput,
@@ -3353,6 +3268,8 @@ const FieldControl = React.memo(
3353
3268
  placeholder,
3354
3269
  autoFocus: autoFocusField,
3355
3270
  suggestions: builtin?.suggestions ? builtin.suggestions : options.map((opt) => ({ value: opt.value, label: opt.label })),
3271
+ seedOptions: builtin?.seedOptions ? builtin.seedOptions.map((opt) => ({ value: opt.value, label: opt.label })) : void 0,
3272
+ resolveLabel: builtin?.resolveLabel,
3356
3273
  loadSuggestions: typeof builtin?.loadOptions === "function" ? async (query) => {
3357
3274
  const opts = await loadFieldOptions(field, query);
3358
3275
  return opts.map((opt) => ({ value: opt.value, label: opt.label }));