@almadar/ui 5.0.0 → 5.1.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.
@@ -194,12 +194,15 @@ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAtt
194
194
  /**
195
195
  * Icon Atom Component
196
196
  *
197
- * A wrapper component for Lucide icons with consistent sizing and styling.
198
- * Uses theme-aware CSS variables for stroke width and color.
197
+ * Renders an icon from the active icon family (Layer 1 Iconography axis —
198
+ * see lib/iconFamily.ts). Canonical names are lucide kebab-case; the resolver
199
+ * dispatches to phosphor / tabler / fa-solid when `--icon-family` selects them,
200
+ * re-rendering automatically on theme switch.
199
201
  *
200
202
  * Supports two APIs:
201
- * - `icon` prop: Pass a LucideIcon component directly
202
- * - `name` prop: Pass a string icon name (resolved from iconMap)
203
+ * - `icon` prop: Pass a LucideIcon component directly (bypasses family resolver
204
+ * used for direct lucide component refs, stays in lucide regardless of theme)
205
+ * - `name` prop: Pass a canonical kebab-case name (family-aware, swaps on theme)
203
206
  */
204
207
 
205
208
  type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
@@ -1,8 +1,11 @@
1
- import React5, { createContext, useCallback, useContext, useMemo, useState, useRef, useEffect } from 'react';
1
+ import React7, { createContext, useCallback, useContext, useMemo, useSyncExternalStore, useState, useRef, useEffect } from 'react';
2
2
  import { createLogger } from '@almadar/logger';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import * as LucideIcons from 'lucide-react';
5
- import { Loader2, ChevronDown, X } from 'lucide-react';
5
+ import { Loader2 } from 'lucide-react';
6
+ import * as PhosphorIcons from '@phosphor-icons/react';
7
+ import * as TablerIcons from '@tabler/icons-react';
8
+ import * as FaIcons from 'react-icons/fa';
6
9
 
7
10
  // node_modules/clsx/dist/clsx.mjs
8
11
  function r(e) {
@@ -2705,7 +2708,7 @@ var positionStyles = {
2705
2708
  fixed: "fixed",
2706
2709
  sticky: "sticky"
2707
2710
  };
2708
- var Box = React5.forwardRef(
2711
+ var Box = React7.forwardRef(
2709
2712
  ({
2710
2713
  padding,
2711
2714
  paddingX,
@@ -2755,7 +2758,7 @@ var Box = React5.forwardRef(
2755
2758
  onMouseLeave?.(e);
2756
2759
  }, [hoverEvent, eventBus, onMouseLeave]);
2757
2760
  const isClickable = action || onClick;
2758
- return React5.createElement(
2761
+ return React7.createElement(
2759
2762
  Component,
2760
2763
  {
2761
2764
  ref,
@@ -2974,41 +2977,366 @@ var Typography = ({
2974
2977
  );
2975
2978
  };
2976
2979
  Typography.displayName = "Typography";
2977
- var iconAliases = {
2978
- "close": LucideIcons.X,
2979
- "trash": LucideIcons.Trash2,
2980
- "loader": LucideIcons.Loader2,
2981
- "stop": LucideIcons.Square,
2982
- "volume": LucideIcons.Volume2,
2983
- "volume-off": LucideIcons.VolumeX,
2984
- "refresh": LucideIcons.RefreshCw,
2985
- "share": LucideIcons.Share2,
2986
- "sort-asc": LucideIcons.ArrowUpNarrowWide,
2987
- "sort-desc": LucideIcons.ArrowDownNarrowWide
2988
- };
2980
+ var DEFAULT_FAMILY = "lucide";
2981
+ var VALID_FAMILIES = [
2982
+ "lucide",
2983
+ "phosphor-outline",
2984
+ "phosphor-fill",
2985
+ "phosphor-duotone",
2986
+ "tabler",
2987
+ "fa-solid"
2988
+ ];
2989
+ function getCurrentIconFamily() {
2990
+ if (typeof window === "undefined" || typeof document === "undefined") {
2991
+ return DEFAULT_FAMILY;
2992
+ }
2993
+ const raw = getComputedStyle(document.documentElement).getPropertyValue("--icon-family").trim().replace(/^["']|["']$/g, "");
2994
+ return VALID_FAMILIES.includes(raw) ? raw : DEFAULT_FAMILY;
2995
+ }
2996
+ var cachedFamily = null;
2997
+ var listeners = /* @__PURE__ */ new Set();
2998
+ var observer = null;
2999
+ function ensureObserver() {
3000
+ if (typeof window === "undefined" || observer) return;
3001
+ observer = new MutationObserver(() => {
3002
+ const next = getCurrentIconFamily();
3003
+ if (next !== cachedFamily) {
3004
+ cachedFamily = next;
3005
+ listeners.forEach((fn) => fn());
3006
+ }
3007
+ });
3008
+ observer.observe(document.documentElement, {
3009
+ attributes: true,
3010
+ attributeFilter: ["data-theme", "style"]
3011
+ });
3012
+ cachedFamily = getCurrentIconFamily();
3013
+ }
3014
+ function subscribeIconFamily(notify) {
3015
+ ensureObserver();
3016
+ listeners.add(notify);
3017
+ return () => {
3018
+ listeners.delete(notify);
3019
+ };
3020
+ }
3021
+ function getIconFamilySnapshot() {
3022
+ if (cachedFamily !== null) return cachedFamily;
3023
+ cachedFamily = getCurrentIconFamily();
3024
+ return cachedFamily;
3025
+ }
3026
+ function getIconFamilyServerSnapshot() {
3027
+ return DEFAULT_FAMILY;
3028
+ }
3029
+ function useIconFamily() {
3030
+ return useSyncExternalStore(
3031
+ subscribeIconFamily,
3032
+ getIconFamilySnapshot,
3033
+ getIconFamilyServerSnapshot
3034
+ );
3035
+ }
2989
3036
  function kebabToPascal(name) {
2990
3037
  return name.split("-").map((part) => {
2991
3038
  if (/^\d+$/.test(part)) return part;
2992
3039
  return part.charAt(0).toUpperCase() + part.slice(1);
2993
3040
  }).join("");
2994
3041
  }
2995
- var resolvedCache = /* @__PURE__ */ new Map();
2996
- function resolveIcon(name) {
2997
- const cached = resolvedCache.get(name);
2998
- if (cached) return cached;
2999
- const resolved = doResolve(name);
3000
- resolvedCache.set(name, resolved);
3001
- return resolved;
3002
- }
3003
- function doResolve(name) {
3004
- if (iconAliases[name]) return iconAliases[name];
3005
- const pascalName = kebabToPascal(name);
3006
- const directLookup = LucideIcons[pascalName];
3007
- if (directLookup && typeof directLookup === "object") return directLookup;
3008
- const asIs = LucideIcons[name];
3042
+ var lucideAliases = {
3043
+ close: LucideIcons.X,
3044
+ trash: LucideIcons.Trash2,
3045
+ loader: LucideIcons.Loader2,
3046
+ stop: LucideIcons.Square,
3047
+ volume: LucideIcons.Volume2,
3048
+ "volume-off": LucideIcons.VolumeX,
3049
+ refresh: LucideIcons.RefreshCw,
3050
+ share: LucideIcons.Share2,
3051
+ "sort-asc": LucideIcons.ArrowUpNarrowWide,
3052
+ "sort-desc": LucideIcons.ArrowDownNarrowWide
3053
+ };
3054
+ function resolveLucide(name) {
3055
+ if (lucideAliases[name]) return lucideAliases[name];
3056
+ const pascal = kebabToPascal(name);
3057
+ const lucideMap = LucideIcons;
3058
+ const direct = lucideMap[pascal];
3059
+ if (direct && typeof direct === "object") return direct;
3060
+ const asIs = lucideMap[name];
3009
3061
  if (asIs && typeof asIs === "object") return asIs;
3010
3062
  return LucideIcons.HelpCircle;
3011
3063
  }
3064
+ var phosphorAliases = {
3065
+ // lucide name → phosphor PascalCase name
3066
+ search: "MagnifyingGlass",
3067
+ close: "X",
3068
+ loader: "CircleNotch",
3069
+ refresh: "ArrowsClockwise",
3070
+ "sort-asc": "SortAscending",
3071
+ "sort-desc": "SortDescending",
3072
+ "chevron-down": "CaretDown",
3073
+ "chevron-up": "CaretUp",
3074
+ "chevron-left": "CaretLeft",
3075
+ "chevron-right": "CaretRight",
3076
+ "help-circle": "Question",
3077
+ "alert-triangle": "Warning",
3078
+ "alert-circle": "WarningCircle",
3079
+ "check-circle": "CheckCircle",
3080
+ "x-circle": "XCircle",
3081
+ edit: "PencilSimple",
3082
+ pencil: "PencilSimple",
3083
+ trash: "Trash",
3084
+ send: "PaperPlaneRight",
3085
+ external: "ArrowSquareOut",
3086
+ "external-link": "ArrowSquareOut",
3087
+ plus: "Plus",
3088
+ minus: "Minus",
3089
+ x: "X",
3090
+ check: "Check",
3091
+ star: "Star",
3092
+ heart: "Heart",
3093
+ home: "House",
3094
+ user: "User",
3095
+ users: "Users",
3096
+ settings: "Gear",
3097
+ menu: "List",
3098
+ "arrow-up": "ArrowUp",
3099
+ "arrow-down": "ArrowDown",
3100
+ "arrow-left": "ArrowLeft",
3101
+ "arrow-right": "ArrowRight",
3102
+ copy: "Copy",
3103
+ download: "DownloadSimple",
3104
+ upload: "UploadSimple",
3105
+ filter: "Funnel",
3106
+ calendar: "Calendar",
3107
+ clock: "Clock",
3108
+ bell: "Bell",
3109
+ mail: "Envelope",
3110
+ envelope: "Envelope",
3111
+ lock: "Lock",
3112
+ unlock: "LockOpen",
3113
+ eye: "Eye",
3114
+ "eye-off": "EyeSlash",
3115
+ more: "DotsThree",
3116
+ "more-vertical": "DotsThreeVertical",
3117
+ info: "Info",
3118
+ warning: "Warning",
3119
+ error: "WarningCircle"
3120
+ };
3121
+ function resolvePhosphor(name, weight) {
3122
+ const target = phosphorAliases[name] ?? kebabToPascal(name);
3123
+ const map = PhosphorIcons;
3124
+ const PhosphorComp = map[target];
3125
+ if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
3126
+ const Component = PhosphorComp;
3127
+ const Adapter = (props) => /* @__PURE__ */ jsx(
3128
+ Component,
3129
+ {
3130
+ weight,
3131
+ className: props.className,
3132
+ style: props.style,
3133
+ size: props.size ?? "1em"
3134
+ }
3135
+ );
3136
+ Adapter.displayName = `Phosphor.${target}.${weight}`;
3137
+ return Adapter;
3138
+ }
3139
+ var tablerAliases = {
3140
+ // lucide name → tabler suffix (after the `Icon` prefix)
3141
+ search: "Search",
3142
+ close: "X",
3143
+ loader: "Loader2",
3144
+ refresh: "Refresh",
3145
+ "sort-asc": "SortAscending",
3146
+ "sort-desc": "SortDescending",
3147
+ "chevron-down": "ChevronDown",
3148
+ "chevron-up": "ChevronUp",
3149
+ "chevron-left": "ChevronLeft",
3150
+ "chevron-right": "ChevronRight",
3151
+ "help-circle": "HelpCircle",
3152
+ "alert-triangle": "AlertTriangle",
3153
+ "alert-circle": "AlertCircle",
3154
+ "check-circle": "CircleCheck",
3155
+ "x-circle": "CircleX",
3156
+ edit: "Pencil",
3157
+ trash: "Trash",
3158
+ send: "Send",
3159
+ external: "ExternalLink",
3160
+ plus: "Plus",
3161
+ x: "X",
3162
+ check: "Check",
3163
+ star: "Star",
3164
+ heart: "Heart",
3165
+ home: "Home",
3166
+ user: "User",
3167
+ users: "Users",
3168
+ settings: "Settings",
3169
+ menu: "Menu2",
3170
+ copy: "Copy",
3171
+ download: "Download",
3172
+ upload: "Upload",
3173
+ filter: "Filter",
3174
+ calendar: "Calendar",
3175
+ clock: "Clock",
3176
+ bell: "Bell",
3177
+ mail: "Mail",
3178
+ envelope: "Mail",
3179
+ lock: "Lock",
3180
+ unlock: "LockOpen",
3181
+ eye: "Eye",
3182
+ "eye-off": "EyeOff",
3183
+ more: "Dots",
3184
+ "more-vertical": "DotsVertical",
3185
+ info: "InfoCircle"
3186
+ };
3187
+ function resolveTabler(name) {
3188
+ const suffix = tablerAliases[name] ?? kebabToPascal(name);
3189
+ const target = `Icon${suffix}`;
3190
+ const map = TablerIcons;
3191
+ const TablerComp = map[target];
3192
+ if (!TablerComp || typeof TablerComp !== "object") return null;
3193
+ const Component = TablerComp;
3194
+ const Adapter = (props) => /* @__PURE__ */ jsx(
3195
+ Component,
3196
+ {
3197
+ stroke: props.strokeWidth ?? 1.5,
3198
+ className: props.className,
3199
+ style: props.style,
3200
+ size: props.size ?? 24
3201
+ }
3202
+ );
3203
+ Adapter.displayName = `Tabler.${target}`;
3204
+ return Adapter;
3205
+ }
3206
+ var faAliases = {
3207
+ // lucide name → fa-solid suffix (after the `Fa` prefix)
3208
+ search: "Search",
3209
+ close: "Times",
3210
+ x: "Times",
3211
+ loader: "Spinner",
3212
+ refresh: "Sync",
3213
+ "sort-asc": "SortAmountUp",
3214
+ "sort-desc": "SortAmountDown",
3215
+ "chevron-down": "ChevronDown",
3216
+ "chevron-up": "ChevronUp",
3217
+ "chevron-left": "ChevronLeft",
3218
+ "chevron-right": "ChevronRight",
3219
+ "help-circle": "QuestionCircle",
3220
+ "alert-triangle": "ExclamationTriangle",
3221
+ "alert-circle": "ExclamationCircle",
3222
+ "check-circle": "CheckCircle",
3223
+ "x-circle": "TimesCircle",
3224
+ edit: "Edit",
3225
+ pencil: "Pencil",
3226
+ trash: "Trash",
3227
+ send: "PaperPlane",
3228
+ external: "ExternalLinkAlt",
3229
+ plus: "Plus",
3230
+ minus: "Minus",
3231
+ check: "Check",
3232
+ star: "Star",
3233
+ heart: "Heart",
3234
+ home: "Home",
3235
+ user: "User",
3236
+ users: "Users",
3237
+ settings: "Cog",
3238
+ menu: "Bars",
3239
+ "arrow-up": "ArrowUp",
3240
+ "arrow-down": "ArrowDown",
3241
+ "arrow-left": "ArrowLeft",
3242
+ "arrow-right": "ArrowRight",
3243
+ copy: "Copy",
3244
+ download: "Download",
3245
+ upload: "Upload",
3246
+ filter: "Filter",
3247
+ calendar: "Calendar",
3248
+ clock: "Clock",
3249
+ bell: "Bell",
3250
+ mail: "Envelope",
3251
+ envelope: "Envelope",
3252
+ lock: "Lock",
3253
+ unlock: "LockOpen",
3254
+ eye: "Eye",
3255
+ "eye-off": "EyeSlash",
3256
+ more: "EllipsisH",
3257
+ "more-vertical": "EllipsisV",
3258
+ info: "InfoCircle",
3259
+ warning: "ExclamationTriangle"
3260
+ };
3261
+ function resolveFa(name) {
3262
+ const suffix = faAliases[name] ?? kebabToPascal(name);
3263
+ const target = `Fa${suffix}`;
3264
+ const map = FaIcons;
3265
+ const FaComp = map[target];
3266
+ if (!FaComp || typeof FaComp !== "function") return null;
3267
+ const Component = FaComp;
3268
+ const Adapter = (props) => /* @__PURE__ */ jsx(
3269
+ Component,
3270
+ {
3271
+ className: props.className,
3272
+ style: props.style,
3273
+ size: props.size ?? "1em"
3274
+ }
3275
+ );
3276
+ Adapter.displayName = `Fa.${target}`;
3277
+ return Adapter;
3278
+ }
3279
+ var warned = /* @__PURE__ */ new Set();
3280
+ function warnFallback(name, family) {
3281
+ const key = `${family}::${name}`;
3282
+ if (warned.has(key)) return;
3283
+ warned.add(key);
3284
+ if (typeof console !== "undefined") {
3285
+ console.warn(
3286
+ `[iconFamily] No '${name}' mapping in family '${family}'; falling back to lucide. Add an alias in lib/iconFamily.ts.`
3287
+ );
3288
+ }
3289
+ }
3290
+ function makeLucideAdapter(name) {
3291
+ const LucideComp = resolveLucide(name);
3292
+ const Adapter = (props) => /* @__PURE__ */ jsx(
3293
+ LucideComp,
3294
+ {
3295
+ className: props.className,
3296
+ strokeWidth: props.strokeWidth,
3297
+ style: props.style,
3298
+ size: props.size
3299
+ }
3300
+ );
3301
+ Adapter.displayName = `Lucide.${name}`;
3302
+ return Adapter;
3303
+ }
3304
+ function resolveIconForFamily(name, family) {
3305
+ switch (family) {
3306
+ case "lucide":
3307
+ return makeLucideAdapter(name);
3308
+ case "phosphor-outline": {
3309
+ const p = resolvePhosphor(name, "regular");
3310
+ if (p) return p;
3311
+ warnFallback(name, family);
3312
+ return makeLucideAdapter(name);
3313
+ }
3314
+ case "phosphor-fill": {
3315
+ const p = resolvePhosphor(name, "fill");
3316
+ if (p) return p;
3317
+ warnFallback(name, family);
3318
+ return makeLucideAdapter(name);
3319
+ }
3320
+ case "phosphor-duotone": {
3321
+ const p = resolvePhosphor(name, "duotone");
3322
+ if (p) return p;
3323
+ warnFallback(name, family);
3324
+ return makeLucideAdapter(name);
3325
+ }
3326
+ case "tabler": {
3327
+ const t = resolveTabler(name);
3328
+ if (t) return t;
3329
+ warnFallback(name, family);
3330
+ return makeLucideAdapter(name);
3331
+ }
3332
+ case "fa-solid": {
3333
+ const f = resolveFa(name);
3334
+ if (f) return f;
3335
+ warnFallback(name, family);
3336
+ return makeLucideAdapter(name);
3337
+ }
3338
+ }
3339
+ }
3012
3340
  var sizeClasses = {
3013
3341
  xs: "w-3 h-3",
3014
3342
  sm: "w-4 h-4",
@@ -3031,22 +3359,50 @@ var Icon = ({
3031
3359
  strokeWidth,
3032
3360
  style
3033
3361
  }) => {
3034
- const IconComponent = icon ?? (name ? resolveIcon(name) : LucideIcons.HelpCircle);
3362
+ const family = useIconFamily();
3363
+ const RenderedComponent = React7.useMemo(() => {
3364
+ if (icon) return null;
3365
+ return name ? resolveIconForFamily(name, family) : null;
3366
+ }, [icon, name, family]);
3035
3367
  const effectiveStrokeWidth = strokeWidth ?? void 0;
3368
+ const inlineStyle = {
3369
+ ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
3370
+ ...style
3371
+ };
3372
+ const composedClassName = cn(
3373
+ sizeClasses[size],
3374
+ animationClasses[animation],
3375
+ color ? color : "text-current",
3376
+ className
3377
+ );
3378
+ if (icon) {
3379
+ const Direct = icon;
3380
+ return /* @__PURE__ */ jsx(
3381
+ Direct,
3382
+ {
3383
+ className: composedClassName,
3384
+ strokeWidth: effectiveStrokeWidth,
3385
+ style: inlineStyle
3386
+ }
3387
+ );
3388
+ }
3389
+ if (RenderedComponent) {
3390
+ return /* @__PURE__ */ jsx(
3391
+ RenderedComponent,
3392
+ {
3393
+ className: composedClassName,
3394
+ strokeWidth: effectiveStrokeWidth,
3395
+ style: inlineStyle
3396
+ }
3397
+ );
3398
+ }
3399
+ const Fallback = LucideIcons.HelpCircle;
3036
3400
  return /* @__PURE__ */ jsx(
3037
- IconComponent,
3401
+ Fallback,
3038
3402
  {
3039
- className: cn(
3040
- sizeClasses[size],
3041
- animationClasses[animation],
3042
- color ? color : "text-current",
3043
- className
3044
- ),
3403
+ className: composedClassName,
3045
3404
  strokeWidth: effectiveStrokeWidth,
3046
- style: {
3047
- ...effectiveStrokeWidth === void 0 ? { strokeWidth: "var(--icon-stroke-width, 2)" } : {},
3048
- ...style
3049
- }
3405
+ style: inlineStyle
3050
3406
  }
3051
3407
  );
3052
3408
  };
@@ -3114,14 +3470,13 @@ var iconSizeStyles = {
3114
3470
  function resolveIconProp(value, sizeClass) {
3115
3471
  if (!value) return null;
3116
3472
  if (typeof value === "string") {
3117
- const Resolved = resolveIcon(value);
3118
- return Resolved ? /* @__PURE__ */ jsx(Resolved, { className: sizeClass }) : null;
3473
+ return /* @__PURE__ */ jsx(Icon, { name: value, className: sizeClass });
3119
3474
  }
3120
3475
  if (typeof value === "function") {
3121
3476
  const IconComp = value;
3122
3477
  return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
3123
3478
  }
3124
- if (React5.isValidElement(value)) {
3479
+ if (React7.isValidElement(value)) {
3125
3480
  return value;
3126
3481
  }
3127
3482
  if (typeof value === "object" && value !== null && "render" in value) {
@@ -3130,7 +3485,7 @@ function resolveIconProp(value, sizeClass) {
3130
3485
  }
3131
3486
  return value;
3132
3487
  }
3133
- var Button = React5.forwardRef(
3488
+ var Button = React7.forwardRef(
3134
3489
  ({
3135
3490
  className,
3136
3491
  variant = "primary",
@@ -3233,7 +3588,7 @@ var shadowStyles2 = {
3233
3588
  md: "shadow",
3234
3589
  lg: "shadow-elevation-dialog"
3235
3590
  };
3236
- var Card = React5.forwardRef(
3591
+ var Card = React7.forwardRef(
3237
3592
  ({
3238
3593
  className,
3239
3594
  variant = "bordered",
@@ -3269,9 +3624,9 @@ var Card = React5.forwardRef(
3269
3624
  }
3270
3625
  );
3271
3626
  Card.displayName = "Card";
3272
- var CardHeader = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3627
+ var CardHeader = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
3273
3628
  CardHeader.displayName = "CardHeader";
3274
- var CardTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3629
+ var CardTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3275
3630
  "h3",
3276
3631
  {
3277
3632
  ref,
@@ -3284,11 +3639,11 @@ var CardTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__
3284
3639
  }
3285
3640
  ));
3286
3641
  CardTitle.displayName = "CardTitle";
3287
- var CardContent = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3642
+ var CardContent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
3288
3643
  CardContent.displayName = "CardContent";
3289
3644
  var CardBody = CardContent;
3290
3645
  CardBody.displayName = "CardBody";
3291
- var CardFooter = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3646
+ var CardFooter = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3292
3647
  "div",
3293
3648
  {
3294
3649
  ref,
@@ -3367,7 +3722,7 @@ var Divider = ({
3367
3722
  );
3368
3723
  };
3369
3724
  Divider.displayName = "Divider";
3370
- var Input = React5.forwardRef(
3725
+ var Input = React7.forwardRef(
3371
3726
  ({
3372
3727
  className,
3373
3728
  inputType,
@@ -3417,7 +3772,7 @@ var Input = React5.forwardRef(
3417
3772
  ]
3418
3773
  }
3419
3774
  ),
3420
- /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-icon-default w-icon-default" }) })
3775
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-muted-foreground", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", className: "h-icon-default w-icon-default" }) })
3421
3776
  ] });
3422
3777
  }
3423
3778
  if (type === "textarea") {
@@ -3471,7 +3826,7 @@ var Input = React5.forwardRef(
3471
3826
  type: "button",
3472
3827
  onClick: onClear,
3473
3828
  className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground hover:text-foreground",
3474
- children: /* @__PURE__ */ jsx(X, { className: "h-icon-default w-icon-default" })
3829
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", className: "h-icon-default w-icon-default" })
3475
3830
  }
3476
3831
  ),
3477
3832
  rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-muted-foreground", children: rightIcon })
@@ -3635,7 +3990,7 @@ var DocBreadcrumb = ({
3635
3990
  "aria-label": "Breadcrumb",
3636
3991
  children: /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "center", wrap: true, children: items.map((item, idx) => {
3637
3992
  const isLast = idx === items.length - 1;
3638
- return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
3993
+ return /* @__PURE__ */ jsxs(React7.Fragment, { children: [
3639
3994
  idx > 0 && /* @__PURE__ */ jsx(
3640
3995
  Icon,
3641
3996
  {
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Icon family runtime resolver (Layer 1 Iconography axis).
3
+ *
4
+ * Reads the active `--icon-family` CSS variable from the document element and
5
+ * dispatches a canonical icon name (kebab-case, matching lucide's vocabulary)
6
+ * to the equivalent component in the active family. Subscribes to data-theme
7
+ * attribute changes via MutationObserver so a theme switch re-renders icons
8
+ * into the new family without a page reload.
9
+ *
10
+ * Canonical name = lucide name. Per-family alias tables resolve cross-family
11
+ * naming differences (e.g. lucide's `search` is phosphor's `MagnifyingGlass`).
12
+ * For names not mapped in the active family, falls back to lucide and logs a
13
+ * console.warn — preserves semantic over family purity.
14
+ *
15
+ * See `docs/Almadar_Std_Variations.md` §2 and `themes/_contract.md`.
16
+ */
17
+ import React from 'react';
18
+ import type { IconFamily as IconFamilyType } from '@almadar/core';
19
+ export type IconFamily = IconFamilyType;
20
+ /** Adapter props that EVERY family-specific icon component accepts at this layer. */
21
+ export interface RenderedIconProps {
22
+ className?: string;
23
+ strokeWidth?: number;
24
+ size?: number;
25
+ style?: React.CSSProperties;
26
+ }
27
+ /** Read --icon-family from <html> at runtime. Returns 'lucide' on SSR. */
28
+ export declare function getCurrentIconFamily(): IconFamily;
29
+ /** React hook: returns the active icon family, re-renders on theme switch. */
30
+ export declare function useIconFamily(): IconFamily;
31
+ /**
32
+ * Dispatch a canonical icon name to the right family component.
33
+ * Falls back to lucide (with console.warn) when the family has no mapping.
34
+ */
35
+ export declare function resolveIconForFamily(name: string, family: IconFamily): React.ComponentType<RenderedIconProps>;
36
+ /**
37
+ * Resolve a canonical icon name to a family-aware component. The returned
38
+ * component re-renders the icon into the active family's library on theme
39
+ * switch (via useIconFamily's MutationObserver subscription).
40
+ */
41
+ export declare function useResolvedIcon(name: string): React.ComponentType<RenderedIconProps>;