@open-mercato/ui 0.5.1-develop.2949.009dcdd2d5 → 0.5.1-develop.2954.610bab2d08

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 (96) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +8 -0
  3. package/dist/backend/CrudForm.js +57 -29
  4. package/dist/backend/CrudForm.js.map +2 -2
  5. package/dist/backend/DataTable.js +32 -14
  6. package/dist/backend/DataTable.js.map +2 -2
  7. package/dist/backend/FilterOverlay.js +23 -17
  8. package/dist/backend/FilterOverlay.js.map +2 -2
  9. package/dist/backend/JsonBuilder.js +32 -18
  10. package/dist/backend/JsonBuilder.js.map +2 -2
  11. package/dist/backend/columns/ColumnChooserPanel.js +12 -13
  12. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  13. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +71 -62
  14. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
  15. package/dist/backend/date-range/DateRangeSelect.js +11 -10
  16. package/dist/backend/date-range/DateRangeSelect.js.map +2 -2
  17. package/dist/backend/date-range/InlineDateRangeSelect.js +10 -22
  18. package/dist/backend/date-range/InlineDateRangeSelect.js.map +2 -2
  19. package/dist/backend/detail/ActivitiesSection.js +20 -12
  20. package/dist/backend/detail/ActivitiesSection.js.map +2 -2
  21. package/dist/backend/detail/AddressEditor.js +24 -7
  22. package/dist/backend/detail/AddressEditor.js.map +2 -2
  23. package/dist/backend/detail/InlineEditors.js +12 -6
  24. package/dist/backend/detail/InlineEditors.js.map +2 -2
  25. package/dist/backend/detail/NotesSection.js +20 -14
  26. package/dist/backend/detail/NotesSection.js.map +2 -2
  27. package/dist/backend/filters/AdvancedFilterBuilder.js +52 -24
  28. package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
  29. package/dist/backend/injection/InjectedField.js +12 -7
  30. package/dist/backend/injection/InjectedField.js.map +2 -2
  31. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  32. package/dist/backend/inputs/EventSelect.js +22 -6
  33. package/dist/backend/inputs/EventSelect.js.map +2 -2
  34. package/dist/backend/inputs/PhoneNumberField.js +2 -2
  35. package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
  36. package/dist/backend/inputs/TimeInput.js +9 -10
  37. package/dist/backend/inputs/TimeInput.js.map +2 -2
  38. package/dist/backend/messages/message-compose-form-groups.js +12 -7
  39. package/dist/backend/messages/message-compose-form-groups.js.map +2 -2
  40. package/dist/backend/messages/useMessageCompose.js +7 -1
  41. package/dist/backend/messages/useMessageCompose.js.map +2 -2
  42. package/dist/frontend/LanguageSwitcher.js +19 -14
  43. package/dist/frontend/LanguageSwitcher.js.map +2 -2
  44. package/dist/index.js +5 -0
  45. package/dist/index.js.map +2 -2
  46. package/dist/primitives/checkbox-field.js +17 -5
  47. package/dist/primitives/checkbox-field.js.map +2 -2
  48. package/dist/primitives/input.js +71 -14
  49. package/dist/primitives/input.js.map +2 -2
  50. package/dist/primitives/radio-field.js +74 -0
  51. package/dist/primitives/radio-field.js.map +7 -0
  52. package/dist/primitives/radio.js +37 -0
  53. package/dist/primitives/radio.js.map +7 -0
  54. package/dist/primitives/select.js +155 -0
  55. package/dist/primitives/select.js.map +7 -0
  56. package/dist/primitives/switch-field.js +76 -0
  57. package/dist/primitives/switch-field.js.map +7 -0
  58. package/dist/primitives/switch.js +17 -3
  59. package/dist/primitives/switch.js.map +2 -2
  60. package/dist/primitives/textarea.js +48 -12
  61. package/dist/primitives/textarea.js.map +2 -2
  62. package/dist/primitives/tooltip.js +44 -15
  63. package/dist/primitives/tooltip.js.map +2 -2
  64. package/package.json +5 -3
  65. package/src/backend/CrudForm.tsx +104 -37
  66. package/src/backend/DataTable.tsx +38 -20
  67. package/src/backend/FilterOverlay.tsx +35 -21
  68. package/src/backend/JsonBuilder.tsx +38 -20
  69. package/src/backend/__tests__/FieldDefinitionsEditor.test.tsx +23 -6
  70. package/src/backend/columns/ColumnChooserPanel.tsx +9 -10
  71. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +120 -87
  72. package/src/backend/date-range/DateRangeSelect.tsx +19 -12
  73. package/src/backend/date-range/InlineDateRangeSelect.tsx +16 -20
  74. package/src/backend/detail/ActivitiesSection.tsx +35 -23
  75. package/src/backend/detail/AddressEditor.tsx +30 -16
  76. package/src/backend/detail/InlineEditors.tsx +21 -11
  77. package/src/backend/detail/NotesSection.tsx +35 -25
  78. package/src/backend/filters/AdvancedFilterBuilder.tsx +60 -34
  79. package/src/backend/injection/InjectedField.tsx +21 -12
  80. package/src/backend/inputs/ComboboxInput.tsx +4 -0
  81. package/src/backend/inputs/EventSelect.tsx +30 -17
  82. package/src/backend/inputs/PhoneNumberField.tsx +2 -2
  83. package/src/backend/inputs/TimeInput.tsx +9 -10
  84. package/src/backend/messages/message-compose-form-groups.tsx +21 -12
  85. package/src/backend/messages/useMessageCompose.ts +20 -1
  86. package/src/frontend/LanguageSwitcher.tsx +20 -17
  87. package/src/index.ts +5 -0
  88. package/src/primitives/checkbox-field.tsx +10 -2
  89. package/src/primitives/input.tsx +73 -12
  90. package/src/primitives/radio-field.tsx +92 -0
  91. package/src/primitives/radio.tsx +42 -0
  92. package/src/primitives/select.tsx +200 -0
  93. package/src/primitives/switch-field.tsx +100 -0
  94. package/src/primitives/switch.tsx +17 -4
  95. package/src/primitives/textarea.tsx +67 -11
  96. package/src/primitives/tooltip.tsx +68 -24
@@ -1,3 +1,3 @@
1
1
  Generated lucide registry with 134 icons -> /home/runner/work/open-mercato/open-mercato/packages/ui/src/backend/icons/lucideRegistry.generated.tsx
2
- [build:ui] found 271 entry points
2
+ [build:ui] found 275 entry points
3
3
  [build:ui] built successfully
package/AGENTS.md CHANGED
@@ -23,6 +23,14 @@ When you need… use this. Details (variants, sizes, props, MUST rules) live in
23
23
  | Marketing CTA with brand gradient | `FancyButton` | `@open-mercato/ui/primitives/fancy-button` |
24
24
  | Checkbox primitive (with indeterminate) | `Checkbox` | `@open-mercato/ui/primitives/checkbox` |
25
25
  | Checkbox with label + description | `CheckboxField` | `@open-mercato/ui/primitives/checkbox-field` |
26
+ | Text input (text/email/password/number/etc.) | `Input` | `@open-mercato/ui/primitives/input` |
27
+ | Multi-line text input (with optional char counter) | `Textarea` | `@open-mercato/ui/primitives/textarea` |
28
+ | Dropdown / select | `Select` (with `SelectTrigger` / `SelectContent` / `SelectItem`) | `@open-mercato/ui/primitives/select` |
29
+ | Tooltip on hover (with arrow, dark/light) | `SimpleTooltip` (or `Tooltip`+`TooltipTrigger`+`TooltipContent`) | `@open-mercato/ui/primitives/tooltip` |
30
+ | Toggle switch (binary on/off preference) | `Switch` | `@open-mercato/ui/primitives/switch` |
31
+ | Switch with label + description (preference row) | `SwitchField` | `@open-mercato/ui/primitives/switch-field` |
32
+ | Radio button (single primitive) | `Radio` (inside `RadioGroup`) | `@open-mercato/ui/primitives/radio` |
33
+ | Radio with label + description (form row) | `RadioField` | `@open-mercato/ui/primitives/radio-field` |
26
34
  | User / entity avatar | `Avatar`, `AvatarStack` | `@open-mercato/ui/primitives/avatar` |
27
35
  | Keyboard shortcut keys | `Kbd`, `KbdShortcut` | `@open-mercato/ui/primitives/kbd` |
28
36
  | Entity tag pill | `Tag` (with `TagMap`) | `@open-mercato/ui/primitives/tag` |
@@ -15,6 +15,15 @@ import { SortableContext, verticalListSortingStrategy, useSortable } from "@dnd-
15
15
  import { CSS } from "@dnd-kit/utilities";
16
16
  import { DataLoader } from "../primitives/DataLoader.js";
17
17
  import { Checkbox } from "../primitives/checkbox.js";
18
+ import { Input } from "../primitives/input.js";
19
+ import { Textarea } from "../primitives/textarea.js";
20
+ import {
21
+ Select,
22
+ SelectContent,
23
+ SelectItem,
24
+ SelectTrigger,
25
+ SelectValue
26
+ } from "../primitives/select.js";
18
27
  import { flash } from "./FlashMessages.js";
19
28
  import dynamic from "next/dynamic";
20
29
  import { FormHeader } from "./forms/FormHeader.js";
@@ -86,6 +95,7 @@ import { evaluateInjectedVisibility } from "./injection/visibility-utils.js";
86
95
  import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
87
96
  import { sanitizeHtmlRichText, sanitizeRichTextHref, sanitizeRichTextPasteContent } from "./utils/richTextSanitizer.js";
88
97
  const EMPTY_OPTIONS = [];
98
+ const SELECT_CLEAR_SENTINEL = "__crudform_select_clear__";
89
99
  const FOCUSABLE_SELECTOR = '[data-crud-focus-target], input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
90
100
  const CRUDFORM_EXTENDED_EVENTS_ENABLED = parseBooleanWithDefault(
91
101
  process.env.NEXT_PUBLIC_OM_CRUDFORM_EXTENDED_EVENTS_ENABLED,
@@ -1481,6 +1491,11 @@ function CrudForm({
1481
1491
  if (!fieldId || lastErrorFieldRef.current === fieldId) return;
1482
1492
  const form = document.getElementById(formId);
1483
1493
  if (!form) return;
1494
+ const active = document.activeElement;
1495
+ if (active instanceof HTMLElement && form.contains(active)) {
1496
+ lastErrorFieldRef.current = fieldId;
1497
+ return;
1498
+ }
1484
1499
  const container = form.querySelector(`[data-crud-field-id="${fieldId}"]`);
1485
1500
  const target = container?.querySelector(FOCUSABLE_SELECTOR) ?? form.querySelector(`[name="${fieldId}"]`) ?? container ?? null;
1486
1501
  if (target && typeof target.focus === "function") {
@@ -2127,17 +2142,16 @@ function CrudForm({
2127
2142
  /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [
2128
2143
  /* @__PURE__ */ jsx("label", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: fieldsetSelectorLabel }),
2129
2144
  /* @__PURE__ */ jsxs(
2130
- "select",
2145
+ Select,
2131
2146
  {
2132
- className: "h-9 rounded border pl-3 pr-8 text-sm",
2133
- value: entityLayout.activeFieldset ?? "",
2134
- onChange: (event) => handleFieldsetSelectionChange(
2147
+ value: entityLayout.activeFieldset || void 0,
2148
+ onValueChange: (value) => handleFieldsetSelectionChange(
2135
2149
  entityLayout.entityId,
2136
- event.target.value || null
2150
+ value || null
2137
2151
  ),
2138
2152
  children: [
2139
- /* @__PURE__ */ jsx("option", { value: "", children: defaultFieldsetLabel }),
2140
- entityLayout.availableFieldsets.map((fs) => /* @__PURE__ */ jsx("option", { value: fs.code, children: fs.label }, fs.code))
2153
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-auto min-w-[10rem]", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: defaultFieldsetLabel }) }),
2154
+ /* @__PURE__ */ jsx(SelectContent, { children: entityLayout.availableFieldsets.map((fs) => /* @__PURE__ */ jsx(SelectItem, { value: fs.code, children: fs.label }, fs.code)) })
2141
2155
  ]
2142
2156
  }
2143
2157
  ),
@@ -2634,10 +2648,9 @@ function RelationSelect({
2634
2648
  }, [query, options]);
2635
2649
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2636
2650
  /* @__PURE__ */ jsx(
2637
- "input",
2651
+ Input,
2638
2652
  {
2639
2653
  ref: inputRef,
2640
- className: "w-full h-9 rounded border px-2 text-sm",
2641
2654
  placeholder: placeholder || t("ui.forms.listbox.searchPlaceholder", "Search..."),
2642
2655
  value: query,
2643
2656
  onChange: (e) => setQuery(e.target.value),
@@ -2718,10 +2731,9 @@ function TextInput({
2718
2731
  }, [commitIfChanged]);
2719
2732
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2720
2733
  /* @__PURE__ */ jsx(
2721
- "input",
2734
+ Input,
2722
2735
  {
2723
2736
  type: inputType,
2724
- className: "w-full h-9 rounded border px-2 text-sm",
2725
2737
  placeholder,
2726
2738
  value: local,
2727
2739
  onChange: handleChange,
@@ -2779,10 +2791,9 @@ function NumberInput({
2779
2791
  commitIfChanged();
2780
2792
  }, [commitIfChanged]);
2781
2793
  return /* @__PURE__ */ jsx(
2782
- "input",
2794
+ Input,
2783
2795
  {
2784
2796
  type: "number",
2785
- className: "w-full h-9 rounded border px-2 text-sm",
2786
2797
  placeholder,
2787
2798
  value: local,
2788
2799
  onChange: handleChange,
@@ -2798,7 +2809,11 @@ function TextAreaInput({
2798
2809
  value,
2799
2810
  onChange,
2800
2811
  placeholder,
2801
- autoFocus
2812
+ autoFocus,
2813
+ maxLength,
2814
+ showCount,
2815
+ rows,
2816
+ disabled
2802
2817
  }) {
2803
2818
  const [local, setLocal] = React.useState(value);
2804
2819
  const isFocusedRef = React.useRef(false);
@@ -2822,15 +2837,18 @@ function TextAreaInput({
2822
2837
  commitIfChanged();
2823
2838
  }, [commitIfChanged]);
2824
2839
  return /* @__PURE__ */ jsx(
2825
- "textarea",
2840
+ Textarea,
2826
2841
  {
2827
- className: "w-full rounded border px-2 py-2 min-h-[80px] sm:min-h-[120px] text-sm",
2828
2842
  placeholder,
2829
2843
  value: local,
2830
2844
  onChange: handleChange,
2831
2845
  onFocus: handleFocus,
2832
2846
  onBlur: handleBlur,
2833
2847
  autoFocus,
2848
+ maxLength,
2849
+ showCount,
2850
+ rows,
2851
+ disabled,
2834
2852
  "data-crud-focus-target": ""
2835
2853
  }
2836
2854
  );
@@ -3106,9 +3124,10 @@ const ListboxMultiSelect = React.memo(function ListboxMultiSelect2({
3106
3124
  );
3107
3125
  return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
3108
3126
  /* @__PURE__ */ jsx(
3109
- "input",
3127
+ Input,
3110
3128
  {
3111
- className: "mb-2 w-full h-8 rounded border px-2 text-sm",
3129
+ className: "mb-2",
3130
+ size: "sm",
3112
3131
  placeholder: searchPlaceholder,
3113
3132
  value: query,
3114
3133
  onChange: (e) => setQuery(e.target.value),
@@ -3226,10 +3245,9 @@ const FieldControl = React.memo(
3226
3245
  }
3227
3246
  ),
3228
3247
  field.type === "date" && /* @__PURE__ */ jsx(
3229
- "input",
3248
+ Input,
3230
3249
  {
3231
3250
  type: "date",
3232
- className: "w-full h-9 rounded border px-2 text-sm",
3233
3251
  value: typeof value === "string" ? value : "",
3234
3252
  onChange: (e) => setValue(field.id, e.target.value || void 0),
3235
3253
  autoFocus: autoFocusField,
@@ -3238,10 +3256,9 @@ const FieldControl = React.memo(
3238
3256
  }
3239
3257
  ),
3240
3258
  field.type === "datetime-local" && /* @__PURE__ */ jsx(
3241
- "input",
3259
+ Input,
3242
3260
  {
3243
3261
  type: "datetime-local",
3244
- className: "w-full h-9 rounded border px-2 text-sm",
3245
3262
  value: typeof value === "string" ? value : "",
3246
3263
  onChange: (e) => setValue(field.id, e.target.value || void 0),
3247
3264
  autoFocus: autoFocusField,
@@ -3296,7 +3313,11 @@ const FieldControl = React.memo(
3296
3313
  value: value == null ? "" : String(value),
3297
3314
  placeholder,
3298
3315
  onChange: (next) => fieldSetValue(next),
3299
- autoFocus: autoFocusField
3316
+ autoFocus: autoFocusField,
3317
+ maxLength: builtin?.maxLength,
3318
+ showCount: builtin?.showCount,
3319
+ rows: builtin?.rows,
3320
+ disabled
3300
3321
  }
3301
3322
  ),
3302
3323
  field.type === "richtext" && builtin?.editor === "simple" && /* @__PURE__ */ jsx(SimpleMarkdownEditor, { value: String(value ?? ""), onChange: fieldSetValue }),
@@ -3345,16 +3366,23 @@ const FieldControl = React.memo(
3345
3366
  /* @__PURE__ */ jsx("span", { className: "text-sm", children: field.label })
3346
3367
  ] }),
3347
3368
  field.type === "select" && !builtin?.multiple && /* @__PURE__ */ jsxs(
3348
- "select",
3369
+ Select,
3349
3370
  {
3350
- className: "w-full h-9 rounded border pl-3 pr-8 text-sm",
3351
3371
  value: Array.isArray(value) ? String(value[0] ?? "") : value == null ? "" : String(value),
3352
- onChange: (e) => setValue(field.id, e.target.value || void 0),
3353
- "data-crud-focus-target": "",
3372
+ onValueChange: (next) => {
3373
+ if (!next || next === SELECT_CLEAR_SENTINEL) {
3374
+ setValue(field.id, void 0);
3375
+ return;
3376
+ }
3377
+ setValue(field.id, next);
3378
+ },
3354
3379
  disabled,
3355
3380
  children: [
3356
- /* @__PURE__ */ jsx("option", { value: "", children: t("ui.forms.select.emptyOption", "\u2014") }),
3357
- options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
3381
+ /* @__PURE__ */ jsx(SelectTrigger, { "data-crud-focus-target": "", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("ui.forms.select.emptyOption", "\u2014") }) }),
3382
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
3383
+ !field.required && value != null && value !== "" && /* @__PURE__ */ jsx(SelectItem, { value: SELECT_CLEAR_SENTINEL, children: t("ui.forms.select.clearOption", "\u2014 Clear \u2014") }),
3384
+ options.filter((opt) => opt.value !== "").map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))
3385
+ ] })
3358
3386
  ]
3359
3387
  }
3360
3388
  ),