@asteby/metacore-runtime-react 27.1.1 → 27.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 27.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 27edd94: Las opciones del picker de referencias SIEMPRE llevan lead visual. El gate
8
+ `optionsHaveVisual` suprimía el avatar de toda la lista cuando ninguna opción
9
+ traía imagen/icono/color — un select de almacenes quedaba como texto pelado
10
+ mientras el de productos (una opción con foto) mostraba avatares. Ahora cada
11
+ opción renderiza su `OptionLead`, que cae a la inicial neutra cuando no hay
12
+ imagen, en el dropdown y en el trigger.
13
+
3
14
  ## 27.1.1
4
15
 
5
16
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-select-field.d.ts","sourceRoot":"","sources":["../src/dynamic-select-field.tsx"],"names":[],"mappings":"AAwCA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gDAAgD,CAAA;AAEjF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,IAAS,GACZ,EAAE;IACC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,+BAoBA;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,IAAS,GACZ,EAAE;IACC,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAA;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,sCA4BA;AAqBD,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,cAAc,CAAA;IACrB,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IAClC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,QAAgB,GACnB,EAAE,uBAAuB,+BAwOzB;AAED,eAAe,kBAAkB,CAAA"}
1
+ {"version":3,"file":"dynamic-select-field.d.ts","sourceRoot":"","sources":["../src/dynamic-select-field.tsx"],"names":[],"mappings":"AAwCA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gDAAgD,CAAA;AAEjF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,IAAS,GACZ,EAAE;IACC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,+BAoBA;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACvB,MAAM,EACN,IAAS,GACZ,EAAE;IACC,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,CAAA;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;CAChB,sCA4BA;AAWD,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,cAAc,CAAA;IACrB,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAA;IAClC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,QAAgB,GACnB,EAAE,uBAAuB,+BAqOzB;AAED,eAAe,kBAAkB,CAAA"}
@@ -79,11 +79,6 @@ export function OptionLead({ option, size = 20, }) {
79
79
  return _jsx(InitialsAvatar, { name: option.label, size: size, rounded: "sm", tone: "neutral" });
80
80
  return null;
81
81
  }
82
- /** True when any option (or the selected one) carries a renderable visual. */
83
- function optionsHaveVisual(options, selected) {
84
- const has = (o) => !!(o && (o.image || o.color || o.icon));
85
- return has(selected) || options.some(has);
86
- }
87
82
  function useDebounced(value, ms) {
88
83
  const [debounced, setDebounced] = useState(value);
89
84
  useEffect(() => {
@@ -155,7 +150,6 @@ export function DynamicSelectField({ field, value, onChange, seedOption, depends
155
150
  // Only switch the picker into "with thumbnails" mode when the data actually
156
151
  // carries images — a relation whose options have no `image` keeps the plain
157
152
  // text list it had before (no empty placeholder column).
158
- const hasVisual = optionsHaveVisual(options, selectedOption);
159
153
  const handlePick = (opt) => {
160
154
  setPicked(opt);
161
155
  onChange(String(opt.id));
@@ -195,14 +189,14 @@ export function DynamicSelectField({ field, value, onChange, seedOption, depends
195
189
  // (the long empty-state placeholder) and overflows the column, pushing the
196
190
  // "+" off-screen — it only "fit" once a short value was selected.
197
191
  return (_jsxs("div", { className: "flex w-full min-w-0 items-center gap-1.5", children: [_jsxs(Popover, { open: open && !blockedByDependency, onOpenChange: (o) => { if (!blockedByDependency)
198
- setOpen(o); }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", role: "combobox", "aria-expanded": open, id: field.key, disabled: blockedByDependency, className: "min-w-0 flex-1 justify-between font-normal", "data-empty": !value, "data-depends-blocked": blockedByDependency ? '' : undefined, children: [_jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-left", children: [hasVisual && value ? (_jsx(OptionLead, { option: selectedOption, size: 20 })) : null, _jsx("span", { className: 'min-w-0 flex-1 truncate ' + (selectedLabel ? '' : 'text-muted-foreground'), children: blockedByDependency
192
+ setOpen(o); }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "outline", role: "combobox", "aria-expanded": open, id: field.key, disabled: blockedByDependency, className: "min-w-0 flex-1 justify-between font-normal", "data-empty": !value, "data-depends-blocked": blockedByDependency ? '' : undefined, children: [_jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2 text-left", children: [value && selectedOption ? (_jsx(OptionLead, { option: selectedOption, size: 20 })) : null, _jsx("span", { className: 'min-w-0 flex-1 truncate ' + (selectedLabel ? '' : 'text-muted-foreground'), children: blockedByDependency
199
193
  ? (dependsHint || DEFAULT_DEPENDS_HINT)
200
194
  : selectedLabel || field.placeholder || 'Buscar…' })] }), _jsx(ChevronsUpDown, { className: "ml-2 size-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "p-0", align: "start",
201
195
  // Match the trigger width without an arbitrary Tailwind class
202
196
  // (those don't always survive a consuming app's Tailwind scan).
203
197
  style: { width: 'var(--radix-popover-trigger-width)' }, children: _jsxs(Command, { shouldFilter: false, children: [_jsx(CommandInput, { placeholder: field.placeholder || 'Buscar…', value: search, onValueChange: setSearch }), _jsxs(CommandList, { children: [loading && (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-6 text-sm", children: [_jsx(Loader2, { className: "size-4 animate-spin" }), "Buscando\u2026"] })), !loading && options.length === 0 && (_jsx(CommandEmpty, { children: debounced ? 'Sin resultados' : 'Escribí para buscar…' })), !loading && options.length > 0 && (_jsx(CommandGroup, { className: "max-h-64 overflow-auto", children: options.map((opt) => {
204
198
  const isSel = String(opt.id) === String(value);
205
- return (_jsxs(CommandItem, { value: String(opt.id), onSelect: () => handlePick(opt), children: [_jsx(Check, { className: 'mr-2 size-4 shrink-0 ' + (isSel ? 'opacity-100' : 'opacity-0') }), hasVisual && (_jsx(OptionLead, { option: opt, size: 24 })), _jsxs("div", { className: "ml-2 flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: opt.label }), opt.description && (_jsx("span", { className: "text-muted-foreground truncate text-xs", children: opt.description }))] })] }, String(opt.id)));
199
+ return (_jsxs(CommandItem, { value: String(opt.id), onSelect: () => handlePick(opt), children: [_jsx(Check, { className: 'mr-2 size-4 shrink-0 ' + (isSel ? 'opacity-100' : 'opacity-0') }), _jsx(OptionLead, { option: opt, size: 24 }), _jsxs("div", { className: "ml-2 flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: opt.label }), opt.description && (_jsx("span", { className: "text-muted-foreground truncate text-xs", children: opt.description }))] })] }, String(opt.id)));
206
200
  }) }))] })] }) })] }), fieldRef && (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "size-9 shrink-0", onClick: openCreate, title: `Crear ${field.label ?? fieldRef}`, "aria-label": `Crear ${field.label ?? fieldRef}`, children: _jsx(Plus, { className: "size-4" }) }))] }));
207
201
  }
208
202
  export default DynamicSelectField;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "27.1.1",
3
+ "version": "27.2.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,8 +37,8 @@
37
37
  "react-i18next": ">=13",
38
38
  "sonner": ">=1.7",
39
39
  "zustand": ">=5",
40
- "@asteby/metacore-ui": "^2.12.1",
41
- "@asteby/metacore-sdk": "^3.3.0"
40
+ "@asteby/metacore-sdk": "^3.3.0",
41
+ "@asteby/metacore-ui": "^2.12.1"
42
42
  },
43
43
  "peerDependenciesMeta": {
44
44
  "@tanstack/react-router": {
@@ -129,16 +129,6 @@ export function OptionLead({
129
129
  return null
130
130
  }
131
131
 
132
- /** True when any option (or the selected one) carries a renderable visual. */
133
- function optionsHaveVisual(
134
- options: ReadonlyArray<Pick<ResolvedOption, 'image' | 'color' | 'icon'>>,
135
- selected?: Pick<ResolvedOption, 'image' | 'color' | 'icon'> | null,
136
- ): boolean {
137
- const has = (o?: Pick<ResolvedOption, 'image' | 'color' | 'icon'> | null) =>
138
- !!(o && (o.image || o.color || o.icon))
139
- return has(selected) || options.some(has)
140
- }
141
-
142
132
  function useDebounced<T>(value: T, ms: number): T {
143
133
  const [debounced, setDebounced] = useState(value)
144
134
  useEffect(() => {
@@ -257,7 +247,6 @@ export function DynamicSelectField({
257
247
  // Only switch the picker into "with thumbnails" mode when the data actually
258
248
  // carries images — a relation whose options have no `image` keeps the plain
259
249
  // text list it had before (no empty placeholder column).
260
- const hasVisual = optionsHaveVisual(options, selectedOption)
261
250
 
262
251
  const handlePick = (opt: ResolvedOption) => {
263
252
  setPicked(opt)
@@ -336,7 +325,7 @@ export function DynamicSelectField({
336
325
  data-depends-blocked={blockedByDependency ? '' : undefined}
337
326
  >
338
327
  <span className="flex min-w-0 flex-1 items-center gap-2 text-left">
339
- {hasVisual && value ? (
328
+ {value && selectedOption ? (
340
329
  <OptionLead option={selectedOption} size={20} />
341
330
  ) : null}
342
331
  <span className={'min-w-0 flex-1 truncate ' + (selectedLabel ? '' : 'text-muted-foreground')}>
@@ -384,9 +373,7 @@ export function DynamicSelectField({
384
373
  onSelect={() => handlePick(opt)}
385
374
  >
386
375
  <Check className={'mr-2 size-4 shrink-0 ' + (isSel ? 'opacity-100' : 'opacity-0')} />
387
- {hasVisual && (
388
- <OptionLead option={opt} size={24} />
389
- )}
376
+ <OptionLead option={opt} size={24} />
390
377
  <div className="ml-2 flex min-w-0 flex-col">
391
378
  <span className="truncate">{opt.label}</span>
392
379
  {opt.description && (