@asteby/metacore-runtime-react 28.1.0 → 28.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,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 28.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c9206cf: Nuevo widget de formulario `icon` (IconPickerField): buscador de íconos lucide con grid y preview, más un modo Imagen que delega en UploadField. El valor almacenado sigue siendo un string retrocompatible (nombre lucide o url/path). Las celdas `image` y los thumbnails de opciones ahora reconocen nombres lucide (PascalCase o kebab, ej. "credit-card") y renderizan el glifo en vez de un `<img>` roto.
8
+
3
9
  ## 28.1.0
4
10
 
5
11
  ### Minor Changes
@@ -1,3 +1,4 @@
1
+ import * as React from 'react';
1
2
  import { type Locale } from 'date-fns';
2
3
  import type { ColumnDefinition } from './types';
3
4
  import type { GetDynamicColumns } from './dynamic-columns-shim';
@@ -142,6 +143,16 @@ export declare const resolveRelationSubtitle: (col: ColumnDefinition, row: any)
142
143
  * does not supply its own. Pass `{ getImageUrl, apiBaseUrl }` to wire avatar
143
144
  * URL resolution.
144
145
  */
146
+ /**
147
+ * `image`-type cell body. A value that is a lucide icon name (PascalCase or
148
+ * kebab slug, e.g. "Banknote" / "credit-card") — the convention the `icon`
149
+ * form widget stores — renders the glyph instead of an <img> that would 404
150
+ * into an empty grey box. Exported for tests.
151
+ */
152
+ export declare const ImageCell: React.FC<{
153
+ value: unknown;
154
+ getImageUrl: (path: string) => string;
155
+ }>;
145
156
  export declare function makeDefaultGetDynamicColumns(helpers?: DynamicColumnsHelpers): GetDynamicColumns;
146
157
  /**
147
158
  * Eager-built variant — equivalent to `makeDefaultGetDynamicColumns()`. Use
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAwC9C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,KAAK,EAER,iBAAiB,EACpB,MAAM,wBAAwB,CAAA;AAE/B,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AA0BD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,gBAAgB,EAAE,cAAc,MAAM,KAAG,MACzB,CAAA;AAQrD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,gBAAgB,KAAG,MAAM,GAAG,SAG5D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC7B,KAAK,gBAAgB,EACrB,OAAO,OAAO,EACd,WAAW,MAAM,EACjB,SAAS,MAAM,KAChB,MAyBF,CAAA;AAyCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAiB5D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OACqB,CAAA;AAwFhF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,KAAG,MAGnE,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,2DAA4D,CAAA;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6C5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAWtE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOtE,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,GACzB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACR,OAAO,GAAG,EACV,mBAAe,KAChB,MAAM,GAAG,SAcX,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOzE,CAAA;AA+ID;;;;GAIG;AACH,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CAwnBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
1
+ {"version":3,"file":"dynamic-columns.d.ts","sourceRoot":"","sources":["../src/dynamic-columns.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAwC9C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,KAAK,EAER,iBAAiB,EACpB,MAAM,wBAAwB,CAAA;AAE/B,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AA0BD;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,gBAAgB,EAAE,cAAc,MAAM,KAAG,MACzB,CAAA;AAQrD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,gBAAgB,KAAG,MAAM,GAAG,SAG5D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC7B,KAAK,gBAAgB,EACrB,OAAO,OAAO,EACd,WAAW,MAAM,EACjB,SAAS,MAAM,KAChB,MAyBF,CAAA;AAyCD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAMlE,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OAiB5D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,EAAE,KAAK,GAAG,KAAG,OACqB,CAAA;AAwFhF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,KAAG,MAGnE,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,2DAA4D,CAAA;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6C5C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAWtE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOtE,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,GACzB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACR,OAAO,GAAG,EACV,mBAAe,KAChB,MAAM,GAAG,SAcX,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAI,KAAK,gBAAgB,EAAE,KAAK,GAAG,KAAG,MAOzE,CAAA;AA+ID;;;;GAIG;AACH;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CACxC,CAqBA,CAAA;AAED,wBAAgB,4BAA4B,CACxC,OAAO,GAAE,qBAA0B,GACpC,iBAAiB,CAkmBnB;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBACL,CAAA"}
@@ -459,6 +459,23 @@ const AvatarCell = ({ name, desc, avatarSrc, getImageUrl }) => (_jsxs("div", { c
459
459
  * does not supply its own. Pass `{ getImageUrl, apiBaseUrl }` to wire avatar
460
460
  * URL resolution.
461
461
  */
462
+ /**
463
+ * `image`-type cell body. A value that is a lucide icon name (PascalCase or
464
+ * kebab slug, e.g. "Banknote" / "credit-card") — the convention the `icon`
465
+ * form widget stores — renders the glyph instead of an <img> that would 404
466
+ * into an empty grey box. Exported for tests.
467
+ */
468
+ export const ImageCell = ({ value, getImageUrl }) => {
469
+ if (!value)
470
+ return _jsx("span", { className: "text-muted-foreground", children: "-" });
471
+ if (isLucideIconName(value)) {
472
+ return (_jsx("div", { className: "h-10 w-10 flex items-center justify-center rounded bg-muted", children: _jsx(DynamicIcon, { name: value, className: "h-5 w-5" }) }));
473
+ }
474
+ return (_jsx("div", { className: "h-10 w-10 relative rounded overflow-hidden bg-muted flex items-center justify-center", children: _jsx("img", { src: getImageUrl(String(value)), alt: "Thumbnail", className: "h-full w-full object-contain", onError: (e) => {
475
+ ;
476
+ e.currentTarget.style.display = 'none';
477
+ } }) }));
478
+ };
462
479
  export function makeDefaultGetDynamicColumns(helpers = {}) {
463
480
  const getImageUrl = helpers.getImageUrl ?? defaultGetImageUrl;
464
481
  const apiBaseUrl = helpers.apiBaseUrl ?? '';
@@ -753,18 +770,7 @@ export function makeDefaultGetDynamicColumns(helpers = {}) {
753
770
  (Array.isArray(row.original.media)
754
771
  ? row.original.media.find((m) => m.type === 'image')?.url
755
772
  : null);
756
- if (!imageValue)
757
- return _jsx("span", { className: "text-muted-foreground", children: "-" });
758
- // Lucide icon name, not an image path (e.g. an addon's
759
- // `icon` column seeded as "Banknote") — render the glyph;
760
- // an <img> here would 404 into an empty grey box.
761
- if (isLucideIconName(imageValue)) {
762
- return (_jsx("div", { className: "h-10 w-10 flex items-center justify-center rounded bg-muted", children: _jsx(DynamicIcon, { name: imageValue, className: "h-5 w-5" }) }));
763
- }
764
- return (_jsx("div", { className: "h-10 w-10 relative rounded overflow-hidden bg-muted flex items-center justify-center", children: _jsx("img", { src: getImageUrl(String(imageValue)), alt: "Thumbnail", className: "h-full w-full object-contain", onError: (e) => {
765
- ;
766
- e.currentTarget.style.display = 'none';
767
- } }) }));
773
+ return _jsx(ImageCell, { value: imageValue, getImageUrl: getImageUrl });
768
774
  }
769
775
  default: {
770
776
  if (typeof value === 'object' && value !== null) {
@@ -5,6 +5,7 @@ export { DynamicLineItems } from './dynamic-line-items';
5
5
  export { DynamicSelectField } from './dynamic-select-field';
6
6
  export { DynamicDateField } from './dynamic-date-field';
7
7
  export { UploadField } from './upload-field';
8
+ export { IconPickerField } from './icon-picker-field';
8
9
  export interface DynamicFormProps {
9
10
  fields: ActionFieldDef[];
10
11
  initialValues?: Record<string, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAKhB,MAAM,uBAAuB,CAAA;AAO9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,GACnB,EAAE,gBAAgB,+BA8FlB"}
1
+ {"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAKhB,MAAM,uBAAuB,CAAA;AAQ9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,GACnB,EAAE,gBAAgB,+BA8FlB"}
@@ -10,11 +10,13 @@ import { DynamicLineItems } from './dynamic-line-items';
10
10
  import { DynamicSelectField } from './dynamic-select-field';
11
11
  import { DynamicDateField } from './dynamic-date-field';
12
12
  import { UploadField } from './upload-field';
13
+ import { IconPickerField } from './icon-picker-field';
13
14
  export { buildZodSchema, resolveWidget };
14
15
  export { DynamicLineItems } from './dynamic-line-items';
15
16
  export { DynamicSelectField } from './dynamic-select-field';
16
17
  export { DynamicDateField } from './dynamic-date-field';
17
18
  export { UploadField } from './upload-field';
19
+ export { IconPickerField } from './icon-picker-field';
18
20
  export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitLabel = 'Guardar', cancelLabel = 'Cancelar', disabled = false, }) {
19
21
  const [values, setValues] = useState({});
20
22
  const [errors, setErrors] = useState({});
@@ -151,6 +153,12 @@ function FieldRenderer({ field, value, onChange, initialValues, effectiveOptions
151
153
  if (widget === 'upload') {
152
154
  return _jsx(UploadField, { field: field, value: value, onChange: onChange });
153
155
  }
156
+ // Icon picker → lucide glyph search grid, with an "Imagen" mode that
157
+ // delegates to the same UploadField as `upload`. Stores a plain string:
158
+ // lucide name or uploaded url/path.
159
+ if (widget === 'icon') {
160
+ return _jsx(IconPickerField, { field: field, value: value, onChange: onChange });
161
+ }
154
162
  // Ref-driven select: hook into useOptionsResolver so the canonical
155
163
  // /api/options/<ref>?field=id endpoint feeds the dropdown. This is
156
164
  // the path the kernel auto-derives for FK columns; legacy callers
@@ -3,5 +3,6 @@ export interface DynamicIconProps {
3
3
  className?: string;
4
4
  }
5
5
  export declare function DynamicIcon({ name, className }: DynamicIconProps): import("react").JSX.Element | null;
6
+ export declare function resolveLucideIconName(value: unknown): string | null;
6
7
  export declare function isLucideIconName(value: unknown): value is string;
7
8
  //# sourceMappingURL=dynamic-icon.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-icon.d.ts","sourceRoot":"","sources":["../src/dynamic-icon.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,gBAAgB,sCAIhE;AAQD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAIhE"}
1
+ {"version":3,"file":"dynamic-icon.d.ts","sourceRoot":"","sources":["../src/dynamic-icon.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,gBAAgB,sCAKhE;AAMD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAYnE;AASD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhE"}
@@ -4,21 +4,39 @@ import { jsx as _jsx } from "react/jsx-runtime";
4
4
  // icon sets can override by shadowing this component via their own prop.
5
5
  import * as icons from 'lucide-react';
6
6
  export function DynamicIcon({ name, className }) {
7
- const Icon = icons[name];
7
+ const resolved = resolveLucideIconName(name) ?? name;
8
+ const Icon = icons[resolved];
8
9
  if (!Icon)
9
10
  return null;
10
11
  return _jsx(Icon, { className: className });
11
12
  }
13
+ // resolveLucideIconName — canonical PascalCase lucide name for a value that is
14
+ // either already PascalCase ("CreditCard") or the kebab slug lucide documents
15
+ // ("credit-card"). Returns null for anything that is not a real glyph: empty,
16
+ // path-like strings (slash, dot, scheme), or the generic "Icon" base export.
17
+ export function resolveLucideIconName(value) {
18
+ if (typeof value !== 'string' || value === '' || value === 'Icon')
19
+ return null;
20
+ if (/[/\\.:\s]/.test(value))
21
+ return null;
22
+ let name = value;
23
+ if (/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
24
+ name = value
25
+ .split('-')
26
+ .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
27
+ .join('');
28
+ }
29
+ if (!/^[A-Z][A-Za-z0-9]*$/.test(name))
30
+ return null;
31
+ return icons[name] ? name : null;
32
+ }
12
33
  // isLucideIconName — true when a string is a lucide-react icon name
13
- // ("Banknote", "CreditCard"). Lets image-ish renderers tell an icon name apart
14
- // from an image path/URL: addons declare icons by lucide slug (same convention
15
- // as OptionDef.icon), so a column inferred as `image` may carry one. Path-like
16
- // strings (slash, dot, scheme) are rejected before the registry lookup; "Icon"
17
- // itself is the generic base component, not a real glyph.
34
+ // ("Banknote", "CreditCard", or the kebab slug "credit-card"). Lets image-ish
35
+ // renderers tell an icon name apart from an image path/URL: addons declare
36
+ // icons by lucide slug (same convention as OptionDef.icon), so a column
37
+ // inferred as `image` may carry one. Path-like strings (slash, dot, scheme)
38
+ // are rejected before the registry lookup; "Icon" itself is the generic base
39
+ // component, not a real glyph.
18
40
  export function isLucideIconName(value) {
19
- if (typeof value !== 'string' || value === '' || value === 'Icon')
20
- return false;
21
- if (!/^[A-Z][A-Za-z0-9]*$/.test(value))
22
- return false;
23
- return Boolean(icons[value]);
41
+ return resolveLucideIconName(value) !== null;
24
42
  }
@@ -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;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"}
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,+BA6BA;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"}
@@ -26,7 +26,7 @@ import { useEffect, useRef, useState } from 'react';
26
26
  import { Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Popover, PopoverContent, PopoverTrigger, InitialsAvatar, } from '@asteby/metacore-ui/primitives';
27
27
  import { Check, ChevronsUpDown, Loader2, Plus } from 'lucide-react';
28
28
  import { resolveColorCss } from '@asteby/metacore-ui/lib';
29
- import { DynamicIcon } from './dynamic-icon';
29
+ import { DynamicIcon, isLucideIconName } from './dynamic-icon';
30
30
  import { useOptionsResolver } from './use-options-resolver';
31
31
  import { getDependsOn, getFieldRef, resolveOptionsSource } from './dynamic-form-schema';
32
32
  /**
@@ -49,6 +49,11 @@ export function OptionThumb({ image, name, size = 20, }) {
49
49
  if (!image) {
50
50
  return _jsx(InitialsAvatar, { name: name, size: size, rounded: "sm", tone: "neutral" });
51
51
  }
52
+ // A lucide icon name stored where an image url/path is expected (the `icon`
53
+ // form widget's icon mode) → render the glyph instead of a broken <img>.
54
+ if (isLucideIconName(image)) {
55
+ return (_jsx("span", { className: "flex shrink-0 items-center justify-center rounded-sm bg-muted", style: box, "aria-hidden": true, children: _jsx(DynamicIcon, { name: image, className: "size-4" }) }));
56
+ }
52
57
  return (_jsx("img", { src: image, alt: "", "aria-hidden": true, loading: "lazy", className: "shrink-0 rounded-sm object-cover", style: box,
53
58
  // A broken image url shouldn't leave a torn-icon glyph; collapse to
54
59
  // the neutral placeholder background instead.
@@ -0,0 +1,10 @@
1
+ import type { ActionFieldDef } from './types';
2
+ export interface IconPickerFieldProps {
3
+ field: ActionFieldDef;
4
+ value: any;
5
+ onChange: (v: any) => void;
6
+ }
7
+ /** True when a stored value looks like an image url/path rather than an icon name. */
8
+ export declare function looksLikeImageValue(value: unknown): boolean;
9
+ export declare function IconPickerField({ field, value, onChange }: IconPickerFieldProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=icon-picker-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon-picker-field.d.ts","sourceRoot":"","sources":["../src/icon-picker-field.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,cAAc,CAAA;IACrB,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;CAC7B;AAOD,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,oBAAoB,+BAiG/E"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // IconPickerField — the `icon` widget renderer for DynamicForm. Two modes:
3
+ //
4
+ // - "Ícono" (default): search box + grid of lucide glyphs filtered by name.
5
+ // Clicking one stores the PascalCase lucide name ("CreditCard") as the
6
+ // field value — the same convention OptionDef.icon and image-ish cell
7
+ // renderers already understand (see dynamic-icon.tsx).
8
+ // - "Imagen": delegates to the existing UploadField untouched, so the value
9
+ // is the uploaded file url/path exactly as the `upload` widget stores it.
10
+ //
11
+ // The stored value stays a plain string (retrocompatible): a lucide name when
12
+ // an icon was picked, a url/path when an image was uploaded. When editing, the
13
+ // initial mode is inferred from the current value — path-like ("/" or ".")
14
+ // means image, anything else means icon.
15
+ import { useMemo, useState } from 'react';
16
+ import { icons } from 'lucide-react';
17
+ import { Button, Input } from '@asteby/metacore-ui/primitives';
18
+ import { DynamicIcon, resolveLucideIconName } from './dynamic-icon';
19
+ import { UploadField } from './upload-field';
20
+ /** Max glyphs shown in the grid at once — keeps the DOM light while searching. */
21
+ const MAX_RESULTS = 48;
22
+ const ALL_ICON_NAMES = Object.keys(icons);
23
+ /** True when a stored value looks like an image url/path rather than an icon name. */
24
+ export function looksLikeImageValue(value) {
25
+ return typeof value === 'string' && value !== '' && /[/.]/.test(value);
26
+ }
27
+ export function IconPickerField({ field, value, onChange }) {
28
+ const [mode, setMode] = useState(() => looksLikeImageValue(value) ? 'image' : 'icon');
29
+ const [query, setQuery] = useState('');
30
+ const selected = mode === 'icon' ? resolveLucideIconName(value) : null;
31
+ const results = useMemo(() => {
32
+ const q = query.trim().toLowerCase().replace(/[\s_-]/g, '');
33
+ const names = q
34
+ ? ALL_ICON_NAMES.filter((n) => n.toLowerCase().includes(q))
35
+ : ALL_ICON_NAMES;
36
+ // Keep the current selection visible even when it doesn't match the query.
37
+ if (selected && !names.slice(0, MAX_RESULTS).includes(selected)) {
38
+ return [selected, ...names.filter((n) => n !== selected)].slice(0, MAX_RESULTS);
39
+ }
40
+ return names.slice(0, MAX_RESULTS);
41
+ }, [query, selected]);
42
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex gap-1", role: "tablist", "aria-label": "Tipo de \u00EDcono", children: [_jsx(Button, { type: "button", role: "tab", "aria-selected": mode === 'icon', variant: mode === 'icon' ? 'secondary' : 'ghost', size: "sm", onClick: () => setMode('icon'), children: "\u00CDcono" }), _jsx(Button, { type: "button", role: "tab", "aria-selected": mode === 'image', variant: mode === 'image' ? 'secondary' : 'ghost', size: "sm", onClick: () => setMode('image'), children: "Imagen" })] }), mode === 'image' ? (_jsx(UploadField, { field: field, value: value, onChange: onChange })) : (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Input, { id: field.key, value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Buscar \u00EDcono...", "aria-label": "Buscar \u00EDcono" }), selected && (_jsx("div", { "data-testid": "icon-picker-preview", className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-md border bg-muted", title: selected, children: _jsx(DynamicIcon, { name: selected, className: "h-6 w-6" }) }))] }), _jsxs("div", { className: "grid max-h-56 grid-cols-8 gap-1 overflow-y-auto rounded-md border p-2", role: "listbox", "aria-label": "\u00CDconos", children: [results.map((name) => (_jsx("button", { type: "button", role: "option", "aria-selected": name === selected, "aria-label": name, title: name, onClick: () => onChange(name), className: `flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent ${name === selected ? 'bg-accent ring-1 ring-primary' : ''}`, children: _jsx(DynamicIcon, { name: name, className: "h-4 w-4" }) }, name))), results.length === 0 && (_jsx("span", { className: "col-span-8 py-4 text-center text-sm text-muted-foreground", children: "Sin resultados" }))] })] }))] }));
43
+ }
package/dist/types.d.ts CHANGED
@@ -296,7 +296,7 @@ export interface FieldValidation {
296
296
  max?: number;
297
297
  custom?: string;
298
298
  }
299
- export type FieldWidget = 'text' | 'textarea' | 'richtext' | 'color' | 'number' | 'date' | 'select' | 'dynamic_select' | 'switch' | 'upload';
299
+ export type FieldWidget = 'text' | 'textarea' | 'richtext' | 'color' | 'number' | 'date' | 'select' | 'dynamic_select' | 'switch' | 'upload' | 'icon';
300
300
  /**
301
301
  * Per-option visibility gate for a STATIC enum (`options[]`). The option is only
302
302
  * offered when the value of a sibling field (`field`, defaulting to the
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "28.1.0",
3
+ "version": "28.2.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -67,8 +67,8 @@
67
67
  "typescript": "^6.0.0",
68
68
  "vitest": "^4.0.0",
69
69
  "zustand": "^5.0.0",
70
- "@asteby/metacore-ui": "2.12.1",
71
- "@asteby/metacore-sdk": "3.4.0"
70
+ "@asteby/metacore-sdk": "3.4.0",
71
+ "@asteby/metacore-ui": "2.12.1"
72
72
  },
73
73
  "scripts": {
74
74
  "build": "tsc -p tsconfig.json",
@@ -0,0 +1,67 @@
1
+ // @vitest-environment happy-dom
2
+ //
3
+ // IconPickerField — the `icon` form widget: lucide search grid (icon mode) and
4
+ // delegation to UploadField (image mode). UploadField is stubbed so the image
5
+ // mode asserts delegation without needing an ApiProvider.
6
+ import { afterEach, describe, expect, it, vi } from 'vitest'
7
+ import { cleanup, render, screen, fireEvent } from '@testing-library/react'
8
+
9
+ vi.mock('../upload-field', () => ({
10
+ UploadField: ({ field, value }: any) => (
11
+ <div data-testid="upload-field" data-field-key={field.key} data-value={String(value ?? '')} />
12
+ ),
13
+ }))
14
+
15
+ import { IconPickerField, looksLikeImageValue } from '../icon-picker-field'
16
+ import type { ActionFieldDef } from '../types'
17
+
18
+ afterEach(cleanup)
19
+
20
+ const field: ActionFieldDef = { key: 'icon', label: 'Ícono', type: 'text', widget: 'icon' }
21
+
22
+ describe('IconPickerField', () => {
23
+ it('busca "credit", muestra CreditCard y al click emite onChange con el nombre', () => {
24
+ const onChange = vi.fn()
25
+ render(<IconPickerField field={field} value="" onChange={onChange} />)
26
+ fireEvent.change(screen.getByLabelText('Buscar ícono'), { target: { value: 'credit' } })
27
+ const option = screen.getByRole('option', { name: 'CreditCard' })
28
+ fireEvent.click(option)
29
+ expect(onChange).toHaveBeenCalledWith('CreditCard')
30
+ })
31
+
32
+ it('resalta el seleccionado y muestra el preview grande', () => {
33
+ render(<IconPickerField field={field} value="CreditCard" onChange={() => {}} />)
34
+ expect(screen.getByTestId('icon-picker-preview')).toBeTruthy()
35
+ expect(
36
+ screen.getByRole('option', { name: 'CreditCard' }).getAttribute('aria-selected'),
37
+ ).toBe('true')
38
+ })
39
+
40
+ it('limita el grid a 48 resultados', () => {
41
+ render(<IconPickerField field={field} value="" onChange={() => {}} />)
42
+ expect(screen.getAllByRole('option').length).toBeLessThanOrEqual(48)
43
+ })
44
+
45
+ it('modo imagen delega a UploadField con los mismos props', () => {
46
+ render(<IconPickerField field={field} value="" onChange={() => {}} />)
47
+ fireEvent.click(screen.getByRole('tab', { name: 'Imagen' }))
48
+ const stub = screen.getByTestId('upload-field')
49
+ expect(stub.getAttribute('data-field-key')).toBe('icon')
50
+ })
51
+
52
+ it('arranca en modo Imagen cuando el valor parece path/URL', () => {
53
+ render(<IconPickerField field={field} value="/uploads/logo.png" onChange={() => {}} />)
54
+ expect(screen.getByTestId('upload-field').getAttribute('data-value')).toBe('/uploads/logo.png')
55
+ })
56
+ })
57
+
58
+ describe('looksLikeImageValue', () => {
59
+ it('distingue paths/URLs de nombres lucide', () => {
60
+ expect(looksLikeImageValue('/uploads/a.png')).toBe(true)
61
+ expect(looksLikeImageValue('logo.png')).toBe(true)
62
+ expect(looksLikeImageValue('https://x/y')).toBe(true)
63
+ expect(looksLikeImageValue('CreditCard')).toBe(false)
64
+ expect(looksLikeImageValue('credit-card')).toBe(false)
65
+ expect(looksLikeImageValue('')).toBe(false)
66
+ })
67
+ })
@@ -0,0 +1,52 @@
1
+ // @vitest-environment happy-dom
2
+ //
3
+ // ImageCell — an `image` cell whose value is a lucide icon name (PascalCase or
4
+ // kebab, as stored by the `icon` form widget) renders the glyph instead of a
5
+ // broken <img>; real paths/urls keep rendering an <img>.
6
+ import { afterEach, describe, expect, it } from 'vitest'
7
+ import { cleanup, render } from '@testing-library/react'
8
+ import { ImageCell } from '../dynamic-columns'
9
+ import { isLucideIconName, resolveLucideIconName } from '../dynamic-icon'
10
+
11
+ afterEach(cleanup)
12
+
13
+ const getImageUrl = (p: string) => `/img${p}`
14
+
15
+ describe('ImageCell con nombre lucide', () => {
16
+ it('renderiza el ícono (svg) para un nombre PascalCase, sin <img>', () => {
17
+ const { container } = render(<ImageCell value="CreditCard" getImageUrl={getImageUrl} />)
18
+ expect(container.querySelector('svg')).toBeTruthy()
19
+ expect(container.querySelector('img')).toBeNull()
20
+ })
21
+
22
+ it('renderiza el ícono también para el slug kebab "credit-card"', () => {
23
+ const { container } = render(<ImageCell value="credit-card" getImageUrl={getImageUrl} />)
24
+ expect(container.querySelector('svg')).toBeTruthy()
25
+ expect(container.querySelector('img')).toBeNull()
26
+ })
27
+
28
+ it('un path real sigue renderizando <img> con getImageUrl aplicado', () => {
29
+ const { container } = render(<ImageCell value="/uploads/x.png" getImageUrl={getImageUrl} />)
30
+ const img = container.querySelector('img')
31
+ expect(img?.getAttribute('src')).toBe('/img/uploads/x.png')
32
+ })
33
+
34
+ it('valor vacío cae al guion', () => {
35
+ const { container } = render(<ImageCell value="" getImageUrl={getImageUrl} />)
36
+ expect(container.textContent).toBe('-')
37
+ })
38
+ })
39
+
40
+ describe('resolveLucideIconName / isLucideIconName', () => {
41
+ it('normaliza kebab a PascalCase', () => {
42
+ expect(resolveLucideIconName('credit-card')).toBe('CreditCard')
43
+ expect(resolveLucideIconName('CreditCard')).toBe('CreditCard')
44
+ })
45
+ it('rechaza paths, vacíos y el base "Icon"', () => {
46
+ expect(resolveLucideIconName('/a/b.png')).toBeNull()
47
+ expect(resolveLucideIconName('logo.png')).toBeNull()
48
+ expect(resolveLucideIconName('')).toBeNull()
49
+ expect(resolveLucideIconName('Icon')).toBeNull()
50
+ expect(isLucideIconName('no-such-icon-xyz')).toBe(false)
51
+ })
52
+ })
@@ -664,6 +664,38 @@ const AvatarCell: React.FC<{
664
664
  * does not supply its own. Pass `{ getImageUrl, apiBaseUrl }` to wire avatar
665
665
  * URL resolution.
666
666
  */
667
+ /**
668
+ * `image`-type cell body. A value that is a lucide icon name (PascalCase or
669
+ * kebab slug, e.g. "Banknote" / "credit-card") — the convention the `icon`
670
+ * form widget stores — renders the glyph instead of an <img> that would 404
671
+ * into an empty grey box. Exported for tests.
672
+ */
673
+ export const ImageCell: React.FC<{
674
+ value: unknown
675
+ getImageUrl: (path: string) => string
676
+ }> = ({ value, getImageUrl }) => {
677
+ if (!value) return <span className="text-muted-foreground">-</span>
678
+ if (isLucideIconName(value)) {
679
+ return (
680
+ <div className="h-10 w-10 flex items-center justify-center rounded bg-muted">
681
+ <DynamicIcon name={value} className="h-5 w-5" />
682
+ </div>
683
+ )
684
+ }
685
+ return (
686
+ <div className="h-10 w-10 relative rounded overflow-hidden bg-muted flex items-center justify-center">
687
+ <img
688
+ src={getImageUrl(String(value))}
689
+ alt="Thumbnail"
690
+ className="h-full w-full object-contain"
691
+ onError={(e) => {
692
+ ;(e.currentTarget as HTMLImageElement).style.display = 'none'
693
+ }}
694
+ />
695
+ </div>
696
+ )
697
+ }
698
+
667
699
  export function makeDefaultGetDynamicColumns(
668
700
  helpers: DynamicColumnsHelpers = {},
669
701
  ): GetDynamicColumns {
@@ -1155,29 +1187,7 @@ export function makeDefaultGetDynamicColumns(
1155
1187
  (Array.isArray(row.original.media)
1156
1188
  ? row.original.media.find((m: any) => m.type === 'image')?.url
1157
1189
  : null)
1158
- if (!imageValue) return <span className="text-muted-foreground">-</span>
1159
- // Lucide icon name, not an image path (e.g. an addon's
1160
- // `icon` column seeded as "Banknote") — render the glyph;
1161
- // an <img> here would 404 into an empty grey box.
1162
- if (isLucideIconName(imageValue)) {
1163
- return (
1164
- <div className="h-10 w-10 flex items-center justify-center rounded bg-muted">
1165
- <DynamicIcon name={imageValue} className="h-5 w-5" />
1166
- </div>
1167
- )
1168
- }
1169
- return (
1170
- <div className="h-10 w-10 relative rounded overflow-hidden bg-muted flex items-center justify-center">
1171
- <img
1172
- src={getImageUrl(String(imageValue))}
1173
- alt="Thumbnail"
1174
- className="h-full w-full object-contain"
1175
- onError={(e) => {
1176
- ;(e.currentTarget as HTMLImageElement).style.display = 'none'
1177
- }}
1178
- />
1179
- </div>
1180
- )
1190
+ return <ImageCell value={imageValue} getImageUrl={getImageUrl} />
1181
1191
  }
1182
1192
 
1183
1193
  default: {
@@ -28,12 +28,14 @@ import { DynamicLineItems } from './dynamic-line-items'
28
28
  import { DynamicSelectField } from './dynamic-select-field'
29
29
  import { DynamicDateField } from './dynamic-date-field'
30
30
  import { UploadField } from './upload-field'
31
+ import { IconPickerField } from './icon-picker-field'
31
32
 
32
33
  export { buildZodSchema, resolveWidget }
33
34
  export { DynamicLineItems } from './dynamic-line-items'
34
35
  export { DynamicSelectField } from './dynamic-select-field'
35
36
  export { DynamicDateField } from './dynamic-date-field'
36
37
  export { UploadField } from './upload-field'
38
+ export { IconPickerField } from './icon-picker-field'
37
39
 
38
40
  export interface DynamicFormProps {
39
41
  fields: ActionFieldDef[]
@@ -264,6 +266,12 @@ function FieldRenderer({
264
266
  if (widget === 'upload') {
265
267
  return <UploadField field={field} value={value} onChange={onChange} />
266
268
  }
269
+ // Icon picker → lucide glyph search grid, with an "Imagen" mode that
270
+ // delegates to the same UploadField as `upload`. Stores a plain string:
271
+ // lucide name or uploaded url/path.
272
+ if (widget === 'icon') {
273
+ return <IconPickerField field={field} value={value} onChange={onChange} />
274
+ }
267
275
  // Ref-driven select: hook into useOptionsResolver so the canonical
268
276
  // /api/options/<ref>?field=id endpoint feeds the dropdown. This is
269
277
  // the path the kernel auto-derives for FK columns; legacy callers
@@ -9,19 +9,37 @@ export interface DynamicIconProps {
9
9
  }
10
10
 
11
11
  export function DynamicIcon({ name, className }: DynamicIconProps) {
12
- const Icon = (icons as unknown as Record<string, React.ComponentType<{ className?: string }>>)[name]
12
+ const resolved = resolveLucideIconName(name) ?? name
13
+ const Icon = (icons as unknown as Record<string, React.ComponentType<{ className?: string }>>)[resolved]
13
14
  if (!Icon) return null
14
15
  return <Icon className={className} />
15
16
  }
16
17
 
18
+ // resolveLucideIconName — canonical PascalCase lucide name for a value that is
19
+ // either already PascalCase ("CreditCard") or the kebab slug lucide documents
20
+ // ("credit-card"). Returns null for anything that is not a real glyph: empty,
21
+ // path-like strings (slash, dot, scheme), or the generic "Icon" base export.
22
+ export function resolveLucideIconName(value: unknown): string | null {
23
+ if (typeof value !== 'string' || value === '' || value === 'Icon') return null
24
+ if (/[/\\.:\s]/.test(value)) return null
25
+ let name = value
26
+ if (/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
27
+ name = value
28
+ .split('-')
29
+ .map((p) => p.charAt(0).toUpperCase() + p.slice(1))
30
+ .join('')
31
+ }
32
+ if (!/^[A-Z][A-Za-z0-9]*$/.test(name)) return null
33
+ return (icons as unknown as Record<string, unknown>)[name] ? name : null
34
+ }
35
+
17
36
  // isLucideIconName — true when a string is a lucide-react icon name
18
- // ("Banknote", "CreditCard"). Lets image-ish renderers tell an icon name apart
19
- // from an image path/URL: addons declare icons by lucide slug (same convention
20
- // as OptionDef.icon), so a column inferred as `image` may carry one. Path-like
21
- // strings (slash, dot, scheme) are rejected before the registry lookup; "Icon"
22
- // itself is the generic base component, not a real glyph.
37
+ // ("Banknote", "CreditCard", or the kebab slug "credit-card"). Lets image-ish
38
+ // renderers tell an icon name apart from an image path/URL: addons declare
39
+ // icons by lucide slug (same convention as OptionDef.icon), so a column
40
+ // inferred as `image` may carry one. Path-like strings (slash, dot, scheme)
41
+ // are rejected before the registry lookup; "Icon" itself is the generic base
42
+ // component, not a real glyph.
23
43
  export function isLucideIconName(value: unknown): value is string {
24
- if (typeof value !== 'string' || value === '' || value === 'Icon') return false
25
- if (!/^[A-Z][A-Za-z0-9]*$/.test(value)) return false
26
- return Boolean((icons as unknown as Record<string, unknown>)[value])
44
+ return resolveLucideIconName(value) !== null
27
45
  }
@@ -37,7 +37,7 @@ import {
37
37
  } from '@asteby/metacore-ui/primitives'
38
38
  import { Check, ChevronsUpDown, Loader2, Plus } from 'lucide-react'
39
39
  import { resolveColorCss } from '@asteby/metacore-ui/lib'
40
- import { DynamicIcon } from './dynamic-icon'
40
+ import { DynamicIcon, isLucideIconName } from './dynamic-icon'
41
41
  import { useOptionsResolver, type ResolvedOption } from './use-options-resolver'
42
42
  import { getDependsOn, getFieldRef, resolveOptionsSource } from './dynamic-form-schema'
43
43
  import type { ActionFieldDef } from './types'
@@ -71,6 +71,15 @@ export function OptionThumb({
71
71
  if (!image) {
72
72
  return <InitialsAvatar name={name} size={size} rounded="sm" tone="neutral" />
73
73
  }
74
+ // A lucide icon name stored where an image url/path is expected (the `icon`
75
+ // form widget's icon mode) → render the glyph instead of a broken <img>.
76
+ if (isLucideIconName(image)) {
77
+ return (
78
+ <span className="flex shrink-0 items-center justify-center rounded-sm bg-muted" style={box} aria-hidden>
79
+ <DynamicIcon name={image} className="size-4" />
80
+ </span>
81
+ )
82
+ }
74
83
  return (
75
84
  <img
76
85
  src={image}
@@ -0,0 +1,134 @@
1
+ // IconPickerField — the `icon` widget renderer for DynamicForm. Two modes:
2
+ //
3
+ // - "Ícono" (default): search box + grid of lucide glyphs filtered by name.
4
+ // Clicking one stores the PascalCase lucide name ("CreditCard") as the
5
+ // field value — the same convention OptionDef.icon and image-ish cell
6
+ // renderers already understand (see dynamic-icon.tsx).
7
+ // - "Imagen": delegates to the existing UploadField untouched, so the value
8
+ // is the uploaded file url/path exactly as the `upload` widget stores it.
9
+ //
10
+ // The stored value stays a plain string (retrocompatible): a lucide name when
11
+ // an icon was picked, a url/path when an image was uploaded. When editing, the
12
+ // initial mode is inferred from the current value — path-like ("/" or ".")
13
+ // means image, anything else means icon.
14
+ import { useMemo, useState } from 'react'
15
+ import { icons } from 'lucide-react'
16
+ import { Button, Input } from '@asteby/metacore-ui/primitives'
17
+ import { DynamicIcon, resolveLucideIconName } from './dynamic-icon'
18
+ import { UploadField } from './upload-field'
19
+ import type { ActionFieldDef } from './types'
20
+
21
+ export interface IconPickerFieldProps {
22
+ field: ActionFieldDef
23
+ value: any
24
+ onChange: (v: any) => void
25
+ }
26
+
27
+ /** Max glyphs shown in the grid at once — keeps the DOM light while searching. */
28
+ const MAX_RESULTS = 48
29
+
30
+ const ALL_ICON_NAMES = Object.keys(icons)
31
+
32
+ /** True when a stored value looks like an image url/path rather than an icon name. */
33
+ export function looksLikeImageValue(value: unknown): boolean {
34
+ return typeof value === 'string' && value !== '' && /[/.]/.test(value)
35
+ }
36
+
37
+ export function IconPickerField({ field, value, onChange }: IconPickerFieldProps) {
38
+ const [mode, setMode] = useState<'icon' | 'image'>(() =>
39
+ looksLikeImageValue(value) ? 'image' : 'icon',
40
+ )
41
+ const [query, setQuery] = useState('')
42
+
43
+ const selected = mode === 'icon' ? resolveLucideIconName(value) : null
44
+
45
+ const results = useMemo(() => {
46
+ const q = query.trim().toLowerCase().replace(/[\s_-]/g, '')
47
+ const names = q
48
+ ? ALL_ICON_NAMES.filter((n) => n.toLowerCase().includes(q))
49
+ : ALL_ICON_NAMES
50
+ // Keep the current selection visible even when it doesn't match the query.
51
+ if (selected && !names.slice(0, MAX_RESULTS).includes(selected)) {
52
+ return [selected, ...names.filter((n) => n !== selected)].slice(0, MAX_RESULTS)
53
+ }
54
+ return names.slice(0, MAX_RESULTS)
55
+ }, [query, selected])
56
+
57
+ return (
58
+ <div className="flex flex-col gap-2">
59
+ <div className="flex gap-1" role="tablist" aria-label="Tipo de ícono">
60
+ <Button
61
+ type="button"
62
+ role="tab"
63
+ aria-selected={mode === 'icon'}
64
+ variant={mode === 'icon' ? 'secondary' : 'ghost'}
65
+ size="sm"
66
+ onClick={() => setMode('icon')}
67
+ >
68
+ Ícono
69
+ </Button>
70
+ <Button
71
+ type="button"
72
+ role="tab"
73
+ aria-selected={mode === 'image'}
74
+ variant={mode === 'image' ? 'secondary' : 'ghost'}
75
+ size="sm"
76
+ onClick={() => setMode('image')}
77
+ >
78
+ Imagen
79
+ </Button>
80
+ </div>
81
+ {mode === 'image' ? (
82
+ <UploadField field={field} value={value} onChange={onChange} />
83
+ ) : (
84
+ <div className="flex flex-col gap-2">
85
+ <div className="flex items-center gap-3">
86
+ <Input
87
+ id={field.key}
88
+ value={query}
89
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}
90
+ placeholder="Buscar ícono..."
91
+ aria-label="Buscar ícono"
92
+ />
93
+ {selected && (
94
+ <div
95
+ data-testid="icon-picker-preview"
96
+ className="flex h-10 w-10 shrink-0 items-center justify-center rounded-md border bg-muted"
97
+ title={selected}
98
+ >
99
+ <DynamicIcon name={selected} className="h-6 w-6" />
100
+ </div>
101
+ )}
102
+ </div>
103
+ <div
104
+ className="grid max-h-56 grid-cols-8 gap-1 overflow-y-auto rounded-md border p-2"
105
+ role="listbox"
106
+ aria-label="Íconos"
107
+ >
108
+ {results.map((name) => (
109
+ <button
110
+ key={name}
111
+ type="button"
112
+ role="option"
113
+ aria-selected={name === selected}
114
+ aria-label={name}
115
+ title={name}
116
+ onClick={() => onChange(name)}
117
+ className={`flex h-8 w-8 items-center justify-center rounded-md hover:bg-accent ${
118
+ name === selected ? 'bg-accent ring-1 ring-primary' : ''
119
+ }`}
120
+ >
121
+ <DynamicIcon name={name} className="h-4 w-4" />
122
+ </button>
123
+ ))}
124
+ {results.length === 0 && (
125
+ <span className="col-span-8 py-4 text-center text-sm text-muted-foreground">
126
+ Sin resultados
127
+ </span>
128
+ )}
129
+ </div>
130
+ </div>
131
+ )}
132
+ </div>
133
+ )
134
+ }
package/src/types.ts CHANGED
@@ -344,6 +344,7 @@ export type FieldWidget =
344
344
  | 'dynamic_select'
345
345
  | 'switch'
346
346
  | 'upload'
347
+ | 'icon'
347
348
 
348
349
  /**
349
350
  * Per-option visibility gate for a STATIC enum (`options[]`). The option is only