@almadar/ui 4.56.4 → 4.57.2

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.
@@ -3251,7 +3251,7 @@ var sizeStyles3 = {
3251
3251
  lg: "px-3 py-1.5 text-base"
3252
3252
  };
3253
3253
  var Badge = React6__default.default.forwardRef(
3254
- ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
3254
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
3255
3255
  const iconSizes = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
3256
3256
  const resolvedIcon = typeof icon === "string" ? (() => {
3257
3257
  const I = resolveIcon(icon);
@@ -3265,12 +3265,31 @@ var Badge = React6__default.default.forwardRef(
3265
3265
  "inline-flex items-center gap-1 font-bold rounded-sm",
3266
3266
  variantStyles3[variant],
3267
3267
  sizeStyles3[size],
3268
+ onRemove && "pr-1",
3268
3269
  className
3269
3270
  ),
3270
3271
  ...props,
3271
3272
  children: [
3272
3273
  resolvedIcon,
3273
- children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
3274
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label),
3275
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
3276
+ "button",
3277
+ {
3278
+ type: "button",
3279
+ "aria-label": removeLabel ?? "Remove",
3280
+ onClick: (e) => {
3281
+ e.stopPropagation();
3282
+ onRemove();
3283
+ },
3284
+ className: cn(
3285
+ "inline-flex items-center justify-center rounded-sm",
3286
+ "hover:bg-foreground/10 focus:outline-none focus:ring-1 focus:ring-ring",
3287
+ "transition-colors",
3288
+ size === "sm" ? "w-4 h-4 ml-0.5" : size === "md" ? "w-5 h-5 ml-1" : "w-6 h-6 ml-1"
3289
+ ),
3290
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: iconSizes[size] })
3291
+ }
3292
+ ) : null
3274
3293
  ]
3275
3294
  }
3276
3295
  );
@@ -203,6 +203,13 @@ interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
203
203
  label?: string | number;
204
204
  /** Icon name (Lucide icon string) or React node */
205
205
  icon?: React.ReactNode;
206
+ /** When set, renders a small X button on the right of the badge that
207
+ * invokes this handler — turns the badge into a removable chip.
208
+ * Used by the TagInput molecule and other "list of removable values"
209
+ * surfaces. */
210
+ onRemove?: () => void;
211
+ /** Accessible label for the remove button. Defaults to "Remove". */
212
+ removeLabel?: string;
206
213
  }
207
214
  declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
208
215
 
@@ -2,7 +2,7 @@ import React6, { createContext, useCallback, useState, useRef, useEffect, useCon
2
2
  import { createLogger } from '@almadar/logger';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
  import * as LucideIcons from 'lucide-react';
5
- import { Loader2, Check, User } from 'lucide-react';
5
+ import { Loader2, X, Check, User } from 'lucide-react';
6
6
 
7
7
  // node_modules/clsx/dist/clsx.mjs
8
8
  function r(e) {
@@ -3227,7 +3227,7 @@ var sizeStyles3 = {
3227
3227
  lg: "px-3 py-1.5 text-base"
3228
3228
  };
3229
3229
  var Badge = React6.forwardRef(
3230
- ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
3230
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
3231
3231
  const iconSizes = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
3232
3232
  const resolvedIcon = typeof icon === "string" ? (() => {
3233
3233
  const I = resolveIcon(icon);
@@ -3241,12 +3241,31 @@ var Badge = React6.forwardRef(
3241
3241
  "inline-flex items-center gap-1 font-bold rounded-sm",
3242
3242
  variantStyles3[variant],
3243
3243
  sizeStyles3[size],
3244
+ onRemove && "pr-1",
3244
3245
  className
3245
3246
  ),
3246
3247
  ...props,
3247
3248
  children: [
3248
3249
  resolvedIcon,
3249
- children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
3250
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label),
3251
+ onRemove ? /* @__PURE__ */ jsx(
3252
+ "button",
3253
+ {
3254
+ type: "button",
3255
+ "aria-label": removeLabel ?? "Remove",
3256
+ onClick: (e) => {
3257
+ e.stopPropagation();
3258
+ onRemove();
3259
+ },
3260
+ className: cn(
3261
+ "inline-flex items-center justify-center rounded-sm",
3262
+ "hover:bg-foreground/10 focus:outline-none focus:ring-1 focus:ring-ring",
3263
+ "transition-colors",
3264
+ size === "sm" ? "w-4 h-4 ml-0.5" : size === "md" ? "w-5 h-5 ml-1" : "w-6 h-6 ml-1"
3265
+ ),
3266
+ children: /* @__PURE__ */ jsx(X, { className: iconSizes[size] })
3267
+ }
3268
+ ) : null
3250
3269
  ]
3251
3270
  }
3252
3271
  );
@@ -1617,7 +1617,7 @@ var init_Badge = __esm({
1617
1617
  lg: "px-3 py-1.5 text-base"
1618
1618
  };
1619
1619
  Badge = React84__namespace.default.forwardRef(
1620
- ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
1620
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
1621
1621
  const iconSizes3 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
1622
1622
  const resolvedIcon = typeof icon === "string" ? (() => {
1623
1623
  const I = resolveIcon(icon);
@@ -1631,12 +1631,31 @@ var init_Badge = __esm({
1631
1631
  "inline-flex items-center gap-1 font-bold rounded-sm",
1632
1632
  variantStyles3[variant],
1633
1633
  sizeStyles3[size],
1634
+ onRemove && "pr-1",
1634
1635
  className
1635
1636
  ),
1636
1637
  ...props,
1637
1638
  children: [
1638
1639
  resolvedIcon,
1639
- children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
1640
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label),
1641
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
1642
+ "button",
1643
+ {
1644
+ type: "button",
1645
+ "aria-label": removeLabel ?? "Remove",
1646
+ onClick: (e) => {
1647
+ e.stopPropagation();
1648
+ onRemove();
1649
+ },
1650
+ className: cn(
1651
+ "inline-flex items-center justify-center rounded-sm",
1652
+ "hover:bg-foreground/10 focus:outline-none focus:ring-1 focus:ring-ring",
1653
+ "transition-colors",
1654
+ size === "sm" ? "w-4 h-4 ml-0.5" : size === "md" ? "w-5 h-5 ml-1" : "w-6 h-6 ml-1"
1655
+ ),
1656
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: iconSizes3[size] })
1657
+ }
1658
+ ) : null
1640
1659
  ]
1641
1660
  }
1642
1661
  );
@@ -9438,7 +9457,7 @@ var init_MapView = __esm({
9438
9457
  shadowSize: [41, 41]
9439
9458
  });
9440
9459
  L.Marker.prototype.options.icon = defaultIcon;
9441
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState97 } = React84__namespace.default;
9460
+ const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback113, useState: useState98 } = React84__namespace.default;
9442
9461
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9443
9462
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9444
9463
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9483,8 +9502,8 @@ var init_MapView = __esm({
9483
9502
  showAttribution = true
9484
9503
  }) {
9485
9504
  const eventBus = useEventBus2();
9486
- const [clickedPosition, setClickedPosition] = useState97(null);
9487
- const handleMapClick = useCallback112((lat, lng) => {
9505
+ const [clickedPosition, setClickedPosition] = useState98(null);
9506
+ const handleMapClick = useCallback113((lat, lng) => {
9488
9507
  if (showClickedPin) {
9489
9508
  setClickedPosition({ lat, lng });
9490
9509
  }
@@ -9493,7 +9512,7 @@ var init_MapView = __esm({
9493
9512
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9494
9513
  }
9495
9514
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9496
- const handleMarkerClick = useCallback112((marker) => {
9515
+ const handleMarkerClick = useCallback113((marker) => {
9497
9516
  onMarkerClick?.(marker);
9498
9517
  if (markerClickEvent) {
9499
9518
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -29697,6 +29716,98 @@ var init_TagCloud = __esm({
29697
29716
  TagCloud.displayName = "TagCloud";
29698
29717
  }
29699
29718
  });
29719
+ var TagInput;
29720
+ var init_TagInput = __esm({
29721
+ "components/molecules/TagInput.tsx"() {
29722
+ "use client";
29723
+ init_cn();
29724
+ init_useEventBus();
29725
+ init_Input();
29726
+ init_Badge();
29727
+ init_Stack();
29728
+ init_Typography();
29729
+ TagInput = ({
29730
+ value,
29731
+ onChange,
29732
+ placeholder,
29733
+ disabled = false,
29734
+ variant = "default",
29735
+ unique = true,
29736
+ helperText,
29737
+ className,
29738
+ addEvent,
29739
+ removeEvent
29740
+ }) => {
29741
+ const eventBus = useEventBus();
29742
+ const [draft, setDraft] = React84.useState("");
29743
+ const commit = React84.useCallback(() => {
29744
+ const tag = draft.trim();
29745
+ if (!tag) return;
29746
+ if (unique && value.includes(tag)) {
29747
+ setDraft("");
29748
+ return;
29749
+ }
29750
+ const next = [...value, tag];
29751
+ onChange?.(next);
29752
+ if (addEvent) {
29753
+ eventBus.emit(`UI:${addEvent}`, { tag, value: next });
29754
+ }
29755
+ setDraft("");
29756
+ }, [draft, value, onChange, unique, addEvent, eventBus]);
29757
+ const removeAt = React84.useCallback(
29758
+ (index) => {
29759
+ if (disabled) return;
29760
+ const tag = value[index];
29761
+ const next = value.slice();
29762
+ next.splice(index, 1);
29763
+ onChange?.(next);
29764
+ if (removeEvent) {
29765
+ eventBus.emit(`UI:${removeEvent}`, { tag, index, value: next });
29766
+ }
29767
+ },
29768
+ [value, onChange, disabled, removeEvent, eventBus]
29769
+ );
29770
+ const handleKeyDown = React84.useCallback(
29771
+ (e) => {
29772
+ if (disabled) return;
29773
+ if (e.key === "Enter") {
29774
+ e.preventDefault();
29775
+ commit();
29776
+ } else if (e.key === "Backspace" && draft.length === 0 && value.length > 0) {
29777
+ e.preventDefault();
29778
+ removeAt(value.length - 1);
29779
+ }
29780
+ },
29781
+ [commit, draft.length, value, removeAt, disabled]
29782
+ );
29783
+ return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: cn("w-full", className), children: [
29784
+ value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", className: "flex-wrap", children: value.map((tag, index) => /* @__PURE__ */ jsxRuntime.jsx(
29785
+ Badge,
29786
+ {
29787
+ variant,
29788
+ size: "sm",
29789
+ onRemove: disabled ? void 0 : () => removeAt(index),
29790
+ removeLabel: `Remove ${tag}`,
29791
+ children: tag
29792
+ },
29793
+ `${tag}-${index}`
29794
+ )) }) : null,
29795
+ /* @__PURE__ */ jsxRuntime.jsx(
29796
+ Input,
29797
+ {
29798
+ value: draft,
29799
+ placeholder: placeholder ?? "Type and press Enter\u2026",
29800
+ disabled,
29801
+ onChange: (e) => setDraft(e.target.value),
29802
+ onKeyDown: handleKeyDown
29803
+ }
29804
+ ),
29805
+ helperText ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: helperText }) : null
29806
+ ] });
29807
+ };
29808
+ TagInput.displayName = "TagInput";
29809
+ }
29810
+ });
29700
29811
  var ShowcaseCard;
29701
29812
  var init_ShowcaseCard = __esm({
29702
29813
  "components/molecules/ShowcaseCard.tsx"() {
@@ -33315,6 +33426,75 @@ var init_GradientDivider = __esm({
33315
33426
  GradientDivider.displayName = "GradientDivider";
33316
33427
  }
33317
33428
  });
33429
+ var MarketingFooter;
33430
+ var init_MarketingFooter = __esm({
33431
+ "components/molecules/MarketingFooter.tsx"() {
33432
+ "use client";
33433
+ init_cn();
33434
+ init_Box();
33435
+ init_Stack();
33436
+ init_Typography();
33437
+ MarketingFooter = ({
33438
+ columns,
33439
+ copyright,
33440
+ logo,
33441
+ className
33442
+ }) => {
33443
+ return /* @__PURE__ */ jsxRuntime.jsx(
33444
+ Box,
33445
+ {
33446
+ as: "footer",
33447
+ className: cn(
33448
+ "bg-surface",
33449
+ "border-t border-border",
33450
+ "pt-12 pb-8 px-4",
33451
+ className
33452
+ ),
33453
+ children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
33454
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "lg", align: "start", className: "flex-wrap w-full justify-between", children: [
33455
+ logo && /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className: "min-w-[140px] mb-4", children: logo.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: logo.href, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: logo.src, alt: logo.alt, className: "h-8 w-auto" }) }) : /* @__PURE__ */ jsxRuntime.jsx("img", { src: logo.src, alt: logo.alt, className: "h-8 w-auto" }) }),
33456
+ columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: "min-w-[140px] mb-4", children: [
33457
+ /* @__PURE__ */ jsxRuntime.jsx(
33458
+ Typography,
33459
+ {
33460
+ variant: "body2",
33461
+ className: "font-semibold text-foreground mb-1",
33462
+ children: col.title
33463
+ }
33464
+ ),
33465
+ col.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
33466
+ "a",
33467
+ {
33468
+ href: item.href,
33469
+ className: cn(
33470
+ "text-sm no-underline",
33471
+ "text-foreground/60",
33472
+ "hover:text-accent",
33473
+ "transition-colors duration-150"
33474
+ ),
33475
+ target: item.href.startsWith("http") ? "_blank" : void 0,
33476
+ rel: item.href.startsWith("http") ? "noopener noreferrer" : void 0,
33477
+ children: item.label
33478
+ },
33479
+ item.label
33480
+ ))
33481
+ ] }, col.title))
33482
+ ] }),
33483
+ copyright && /* @__PURE__ */ jsxRuntime.jsx(
33484
+ Typography,
33485
+ {
33486
+ variant: "caption",
33487
+ className: "text-foreground/30 text-center w-full pt-6",
33488
+ children: copyright
33489
+ }
33490
+ )
33491
+ ] })
33492
+ }
33493
+ );
33494
+ };
33495
+ MarketingFooter.displayName = "MarketingFooter";
33496
+ }
33497
+ });
33318
33498
  var PullQuote;
33319
33499
  var init_PullQuote = __esm({
33320
33500
  "components/molecules/PullQuote.tsx"() {
@@ -45051,6 +45231,7 @@ var init_component_registry_generated = __esm({
45051
45231
  init_List();
45052
45232
  init_LoadingState();
45053
45233
  init_MarkdownContent();
45234
+ init_MarketingFooter();
45054
45235
  init_MasterDetail();
45055
45236
  init_MasterDetailLayout();
45056
45237
  init_MatrixQuestion();
@@ -45150,6 +45331,7 @@ var init_component_registry_generated = __esm({
45150
45331
  init_Table();
45151
45332
  init_Tabs();
45152
45333
  init_TagCloud();
45334
+ init_TagInput();
45153
45335
  init_TeamCard();
45154
45336
  init_TeamOrganism();
45155
45337
  init_TextHighlight();
@@ -45350,6 +45532,7 @@ var init_component_registry_generated = __esm({
45350
45532
  "MapView": MapViewPattern,
45351
45533
  "MapViewPattern": MapViewPattern,
45352
45534
  "MarkdownContent": MarkdownContent,
45535
+ "MarketingFooter": MarketingFooter,
45353
45536
  "MasterDetail": MasterDetail,
45354
45537
  "MasterDetailLayout": MasterDetailLayout,
45355
45538
  "MatrixQuestion": MatrixQuestion,
@@ -45465,6 +45648,7 @@ var init_component_registry_generated = __esm({
45465
45648
  "Table": Table,
45466
45649
  "Tabs": Tabs,
45467
45650
  "TagCloud": TagCloud,
45651
+ "TagInput": TagInput,
45468
45652
  "TeamCard": TeamCard,
45469
45653
  "TeamOrganism": TeamOrganism,
45470
45654
  "TextHighlight": TextHighlight,
@@ -1571,7 +1571,7 @@ var init_Badge = __esm({
1571
1571
  lg: "px-3 py-1.5 text-base"
1572
1572
  };
1573
1573
  Badge = React84__default.forwardRef(
1574
- ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
1574
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, onRemove, removeLabel, ...props }, ref) => {
1575
1575
  const iconSizes3 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
1576
1576
  const resolvedIcon = typeof icon === "string" ? (() => {
1577
1577
  const I = resolveIcon(icon);
@@ -1585,12 +1585,31 @@ var init_Badge = __esm({
1585
1585
  "inline-flex items-center gap-1 font-bold rounded-sm",
1586
1586
  variantStyles3[variant],
1587
1587
  sizeStyles3[size],
1588
+ onRemove && "pr-1",
1588
1589
  className
1589
1590
  ),
1590
1591
  ...props,
1591
1592
  children: [
1592
1593
  resolvedIcon,
1593
- children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
1594
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label),
1595
+ onRemove ? /* @__PURE__ */ jsx(
1596
+ "button",
1597
+ {
1598
+ type: "button",
1599
+ "aria-label": removeLabel ?? "Remove",
1600
+ onClick: (e) => {
1601
+ e.stopPropagation();
1602
+ onRemove();
1603
+ },
1604
+ className: cn(
1605
+ "inline-flex items-center justify-center rounded-sm",
1606
+ "hover:bg-foreground/10 focus:outline-none focus:ring-1 focus:ring-ring",
1607
+ "transition-colors",
1608
+ size === "sm" ? "w-4 h-4 ml-0.5" : size === "md" ? "w-5 h-5 ml-1" : "w-6 h-6 ml-1"
1609
+ ),
1610
+ children: /* @__PURE__ */ jsx(X, { className: iconSizes3[size] })
1611
+ }
1612
+ ) : null
1594
1613
  ]
1595
1614
  }
1596
1615
  );
@@ -9392,7 +9411,7 @@ var init_MapView = __esm({
9392
9411
  shadowSize: [41, 41]
9393
9412
  });
9394
9413
  L.Marker.prototype.options.icon = defaultIcon;
9395
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState97 } = React84__default;
9414
+ const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback113, useState: useState98 } = React84__default;
9396
9415
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9397
9416
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9398
9417
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9437,8 +9456,8 @@ var init_MapView = __esm({
9437
9456
  showAttribution = true
9438
9457
  }) {
9439
9458
  const eventBus = useEventBus2();
9440
- const [clickedPosition, setClickedPosition] = useState97(null);
9441
- const handleMapClick = useCallback112((lat, lng) => {
9459
+ const [clickedPosition, setClickedPosition] = useState98(null);
9460
+ const handleMapClick = useCallback113((lat, lng) => {
9442
9461
  if (showClickedPin) {
9443
9462
  setClickedPosition({ lat, lng });
9444
9463
  }
@@ -9447,7 +9466,7 @@ var init_MapView = __esm({
9447
9466
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9448
9467
  }
9449
9468
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9450
- const handleMarkerClick = useCallback112((marker) => {
9469
+ const handleMarkerClick = useCallback113((marker) => {
9451
9470
  onMarkerClick?.(marker);
9452
9471
  if (markerClickEvent) {
9453
9472
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -29651,6 +29670,98 @@ var init_TagCloud = __esm({
29651
29670
  TagCloud.displayName = "TagCloud";
29652
29671
  }
29653
29672
  });
29673
+ var TagInput;
29674
+ var init_TagInput = __esm({
29675
+ "components/molecules/TagInput.tsx"() {
29676
+ "use client";
29677
+ init_cn();
29678
+ init_useEventBus();
29679
+ init_Input();
29680
+ init_Badge();
29681
+ init_Stack();
29682
+ init_Typography();
29683
+ TagInput = ({
29684
+ value,
29685
+ onChange,
29686
+ placeholder,
29687
+ disabled = false,
29688
+ variant = "default",
29689
+ unique = true,
29690
+ helperText,
29691
+ className,
29692
+ addEvent,
29693
+ removeEvent
29694
+ }) => {
29695
+ const eventBus = useEventBus();
29696
+ const [draft, setDraft] = useState("");
29697
+ const commit = useCallback(() => {
29698
+ const tag = draft.trim();
29699
+ if (!tag) return;
29700
+ if (unique && value.includes(tag)) {
29701
+ setDraft("");
29702
+ return;
29703
+ }
29704
+ const next = [...value, tag];
29705
+ onChange?.(next);
29706
+ if (addEvent) {
29707
+ eventBus.emit(`UI:${addEvent}`, { tag, value: next });
29708
+ }
29709
+ setDraft("");
29710
+ }, [draft, value, onChange, unique, addEvent, eventBus]);
29711
+ const removeAt = useCallback(
29712
+ (index) => {
29713
+ if (disabled) return;
29714
+ const tag = value[index];
29715
+ const next = value.slice();
29716
+ next.splice(index, 1);
29717
+ onChange?.(next);
29718
+ if (removeEvent) {
29719
+ eventBus.emit(`UI:${removeEvent}`, { tag, index, value: next });
29720
+ }
29721
+ },
29722
+ [value, onChange, disabled, removeEvent, eventBus]
29723
+ );
29724
+ const handleKeyDown = useCallback(
29725
+ (e) => {
29726
+ if (disabled) return;
29727
+ if (e.key === "Enter") {
29728
+ e.preventDefault();
29729
+ commit();
29730
+ } else if (e.key === "Backspace" && draft.length === 0 && value.length > 0) {
29731
+ e.preventDefault();
29732
+ removeAt(value.length - 1);
29733
+ }
29734
+ },
29735
+ [commit, draft.length, value, removeAt, disabled]
29736
+ );
29737
+ return /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: cn("w-full", className), children: [
29738
+ value.length > 0 ? /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: value.map((tag, index) => /* @__PURE__ */ jsx(
29739
+ Badge,
29740
+ {
29741
+ variant,
29742
+ size: "sm",
29743
+ onRemove: disabled ? void 0 : () => removeAt(index),
29744
+ removeLabel: `Remove ${tag}`,
29745
+ children: tag
29746
+ },
29747
+ `${tag}-${index}`
29748
+ )) }) : null,
29749
+ /* @__PURE__ */ jsx(
29750
+ Input,
29751
+ {
29752
+ value: draft,
29753
+ placeholder: placeholder ?? "Type and press Enter\u2026",
29754
+ disabled,
29755
+ onChange: (e) => setDraft(e.target.value),
29756
+ onKeyDown: handleKeyDown
29757
+ }
29758
+ ),
29759
+ helperText ? /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: helperText }) : null
29760
+ ] });
29761
+ };
29762
+ TagInput.displayName = "TagInput";
29763
+ }
29764
+ });
29654
29765
  var ShowcaseCard;
29655
29766
  var init_ShowcaseCard = __esm({
29656
29767
  "components/molecules/ShowcaseCard.tsx"() {
@@ -33269,6 +33380,75 @@ var init_GradientDivider = __esm({
33269
33380
  GradientDivider.displayName = "GradientDivider";
33270
33381
  }
33271
33382
  });
33383
+ var MarketingFooter;
33384
+ var init_MarketingFooter = __esm({
33385
+ "components/molecules/MarketingFooter.tsx"() {
33386
+ "use client";
33387
+ init_cn();
33388
+ init_Box();
33389
+ init_Stack();
33390
+ init_Typography();
33391
+ MarketingFooter = ({
33392
+ columns,
33393
+ copyright,
33394
+ logo,
33395
+ className
33396
+ }) => {
33397
+ return /* @__PURE__ */ jsx(
33398
+ Box,
33399
+ {
33400
+ as: "footer",
33401
+ className: cn(
33402
+ "bg-surface",
33403
+ "border-t border-border",
33404
+ "pt-12 pb-8 px-4",
33405
+ className
33406
+ ),
33407
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
33408
+ /* @__PURE__ */ jsxs(HStack, { gap: "lg", align: "start", className: "flex-wrap w-full justify-between", children: [
33409
+ logo && /* @__PURE__ */ jsx(VStack, { gap: "sm", className: "min-w-[140px] mb-4", children: logo.href ? /* @__PURE__ */ jsx("a", { href: logo.href, children: /* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-8 w-auto" }) }) : /* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-8 w-auto" }) }),
33410
+ columns.map((col) => /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "min-w-[140px] mb-4", children: [
33411
+ /* @__PURE__ */ jsx(
33412
+ Typography,
33413
+ {
33414
+ variant: "body2",
33415
+ className: "font-semibold text-foreground mb-1",
33416
+ children: col.title
33417
+ }
33418
+ ),
33419
+ col.items.map((item) => /* @__PURE__ */ jsx(
33420
+ "a",
33421
+ {
33422
+ href: item.href,
33423
+ className: cn(
33424
+ "text-sm no-underline",
33425
+ "text-foreground/60",
33426
+ "hover:text-accent",
33427
+ "transition-colors duration-150"
33428
+ ),
33429
+ target: item.href.startsWith("http") ? "_blank" : void 0,
33430
+ rel: item.href.startsWith("http") ? "noopener noreferrer" : void 0,
33431
+ children: item.label
33432
+ },
33433
+ item.label
33434
+ ))
33435
+ ] }, col.title))
33436
+ ] }),
33437
+ copyright && /* @__PURE__ */ jsx(
33438
+ Typography,
33439
+ {
33440
+ variant: "caption",
33441
+ className: "text-foreground/30 text-center w-full pt-6",
33442
+ children: copyright
33443
+ }
33444
+ )
33445
+ ] })
33446
+ }
33447
+ );
33448
+ };
33449
+ MarketingFooter.displayName = "MarketingFooter";
33450
+ }
33451
+ });
33272
33452
  var PullQuote;
33273
33453
  var init_PullQuote = __esm({
33274
33454
  "components/molecules/PullQuote.tsx"() {
@@ -45005,6 +45185,7 @@ var init_component_registry_generated = __esm({
45005
45185
  init_List();
45006
45186
  init_LoadingState();
45007
45187
  init_MarkdownContent();
45188
+ init_MarketingFooter();
45008
45189
  init_MasterDetail();
45009
45190
  init_MasterDetailLayout();
45010
45191
  init_MatrixQuestion();
@@ -45104,6 +45285,7 @@ var init_component_registry_generated = __esm({
45104
45285
  init_Table();
45105
45286
  init_Tabs();
45106
45287
  init_TagCloud();
45288
+ init_TagInput();
45107
45289
  init_TeamCard();
45108
45290
  init_TeamOrganism();
45109
45291
  init_TextHighlight();
@@ -45304,6 +45486,7 @@ var init_component_registry_generated = __esm({
45304
45486
  "MapView": MapViewPattern,
45305
45487
  "MapViewPattern": MapViewPattern,
45306
45488
  "MarkdownContent": MarkdownContent,
45489
+ "MarketingFooter": MarketingFooter,
45307
45490
  "MasterDetail": MasterDetail,
45308
45491
  "MasterDetailLayout": MasterDetailLayout,
45309
45492
  "MatrixQuestion": MatrixQuestion,
@@ -45419,6 +45602,7 @@ var init_component_registry_generated = __esm({
45419
45602
  "Table": Table,
45420
45603
  "Tabs": Tabs,
45421
45604
  "TagCloud": TagCloud,
45605
+ "TagInput": TagInput,
45422
45606
  "TeamCard": TeamCard,
45423
45607
  "TeamOrganism": TeamOrganism,
45424
45608
  "TextHighlight": TextHighlight,