@almadar/ui 4.3.1 → 4.4.1

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.
@@ -7147,7 +7147,8 @@ var init_AnimatedCounter = __esm({
7147
7147
  suffix,
7148
7148
  className
7149
7149
  }) => {
7150
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
7150
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
7151
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
7151
7152
  const [displayValue, setDisplayValue] = React126.useState(value);
7152
7153
  const previousValueRef = React126.useRef(value);
7153
7154
  const animationFrameRef = React126.useRef(null);
@@ -46317,18 +46318,24 @@ function renderContainedPortal(slot, content, onDismiss) {
46317
46318
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
46318
46319
  onClick: (e) => e.stopPropagation(),
46319
46320
  children: [
46320
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
46321
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
46321
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
46322
+ "flex items-center p-4",
46323
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
46324
+ ), children: [
46325
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
46322
46326
  /* @__PURE__ */ jsxRuntime.jsx(
46323
46327
  Box,
46324
46328
  {
46325
46329
  as: "button",
46326
46330
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
46327
46331
  onClick: onDismiss,
46332
+ "data-event": "CLOSE",
46333
+ "data-testid": "action-CLOSE",
46334
+ "aria-label": "Close modal",
46328
46335
  children: "\u2715"
46329
46336
  }
46330
46337
  )
46331
- ] }) : null,
46338
+ ] }),
46332
46339
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
46333
46340
  ]
46334
46341
  }
@@ -46353,18 +46360,24 @@ function renderContainedPortal(slot, content, onDismiss) {
46353
46360
  ),
46354
46361
  onClick: (e) => e.stopPropagation(),
46355
46362
  children: [
46356
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
46357
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
46363
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
46364
+ "flex items-center p-4",
46365
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
46366
+ ), children: [
46367
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
46358
46368
  /* @__PURE__ */ jsxRuntime.jsx(
46359
46369
  Box,
46360
46370
  {
46361
46371
  as: "button",
46362
46372
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
46363
46373
  onClick: onDismiss,
46374
+ "data-event": "CLOSE",
46375
+ "data-testid": "action-CLOSE",
46376
+ "aria-label": "Close drawer",
46364
46377
  children: "\u2715"
46365
46378
  }
46366
46379
  )
46367
- ] }) : null,
46380
+ ] }),
46368
46381
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4", children: slotContent })
46369
46382
  ]
46370
46383
  }
@@ -46408,6 +46421,7 @@ function UISlotComponent({
46408
46421
  sourceTrait
46409
46422
  }) {
46410
46423
  const { slots, clear } = useUISlots();
46424
+ const eventBus = useEventBus();
46411
46425
  const suspenseConfig = React126.useContext(SuspenseConfigContext);
46412
46426
  const contained = React126.useContext(SlotContainedContext);
46413
46427
  const content = slots[slot];
@@ -46454,6 +46468,10 @@ function UISlotComponent({
46454
46468
  return null;
46455
46469
  }
46456
46470
  const handleDismiss = () => {
46471
+ if (slot === "modal" || slot === "drawer") {
46472
+ eventBus.emit("UI:CLOSE");
46473
+ eventBus.emit("UI:CANCEL");
46474
+ }
46457
46475
  clear(slot);
46458
46476
  };
46459
46477
  if (portal) {
@@ -46503,7 +46521,8 @@ function getOrCreatePortalRoot() {
46503
46521
  }
46504
46522
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
46505
46523
  const [portalRoot, setPortalRoot] = React126.useState(null);
46506
- const eventBus = useUISlots();
46524
+ const slotsBus = useUISlots();
46525
+ const eventBus = useEventBus();
46507
46526
  React126.useEffect(() => {
46508
46527
  setPortalRoot(getOrCreatePortalRoot());
46509
46528
  }, []);
@@ -46511,7 +46530,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
46511
46530
  if (portalRoot) getOrCreatePortalRoot();
46512
46531
  });
46513
46532
  const handleDismiss = () => {
46514
- eventBus.clear(slot);
46533
+ if (slot === "modal" || slot === "drawer") {
46534
+ eventBus.emit("UI:CLOSE");
46535
+ eventBus.emit("UI:CANCEL");
46536
+ }
46537
+ slotsBus.clear(slot);
46515
46538
  };
46516
46539
  if (!portalRoot) return null;
46517
46540
  const slotId = `slot-${slot}`;
@@ -46859,6 +46882,7 @@ var init_UISlotRenderer = __esm({
46859
46882
  init_Toast();
46860
46883
  init_Box();
46861
46884
  init_Typography();
46885
+ init_useEventBus();
46862
46886
  init_cn();
46863
46887
  init_ErrorBoundary();
46864
46888
  init_Skeleton();
package/dist/avl/index.js CHANGED
@@ -7101,7 +7101,8 @@ var init_AnimatedCounter = __esm({
7101
7101
  suffix,
7102
7102
  className
7103
7103
  }) => {
7104
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
7104
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
7105
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
7105
7106
  const [displayValue, setDisplayValue] = useState(value);
7106
7107
  const previousValueRef = useRef(value);
7107
7108
  const animationFrameRef = useRef(null);
@@ -46271,18 +46272,24 @@ function renderContainedPortal(slot, content, onDismiss) {
46271
46272
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
46272
46273
  onClick: (e) => e.stopPropagation(),
46273
46274
  children: [
46274
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
46275
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
46275
+ /* @__PURE__ */ jsxs(Box, { className: cn(
46276
+ "flex items-center p-4",
46277
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
46278
+ ), children: [
46279
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
46276
46280
  /* @__PURE__ */ jsx(
46277
46281
  Box,
46278
46282
  {
46279
46283
  as: "button",
46280
46284
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
46281
46285
  onClick: onDismiss,
46286
+ "data-event": "CLOSE",
46287
+ "data-testid": "action-CLOSE",
46288
+ "aria-label": "Close modal",
46282
46289
  children: "\u2715"
46283
46290
  }
46284
46291
  )
46285
- ] }) : null,
46292
+ ] }),
46286
46293
  /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
46287
46294
  ]
46288
46295
  }
@@ -46307,18 +46314,24 @@ function renderContainedPortal(slot, content, onDismiss) {
46307
46314
  ),
46308
46315
  onClick: (e) => e.stopPropagation(),
46309
46316
  children: [
46310
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
46311
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
46317
+ /* @__PURE__ */ jsxs(Box, { className: cn(
46318
+ "flex items-center p-4",
46319
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
46320
+ ), children: [
46321
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
46312
46322
  /* @__PURE__ */ jsx(
46313
46323
  Box,
46314
46324
  {
46315
46325
  as: "button",
46316
46326
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
46317
46327
  onClick: onDismiss,
46328
+ "data-event": "CLOSE",
46329
+ "data-testid": "action-CLOSE",
46330
+ "aria-label": "Close drawer",
46318
46331
  children: "\u2715"
46319
46332
  }
46320
46333
  )
46321
- ] }) : null,
46334
+ ] }),
46322
46335
  /* @__PURE__ */ jsx(Box, { className: "p-4", children: slotContent })
46323
46336
  ]
46324
46337
  }
@@ -46362,6 +46375,7 @@ function UISlotComponent({
46362
46375
  sourceTrait
46363
46376
  }) {
46364
46377
  const { slots, clear } = useUISlots();
46378
+ const eventBus = useEventBus();
46365
46379
  const suspenseConfig = useContext(SuspenseConfigContext);
46366
46380
  const contained = useContext(SlotContainedContext);
46367
46381
  const content = slots[slot];
@@ -46408,6 +46422,10 @@ function UISlotComponent({
46408
46422
  return null;
46409
46423
  }
46410
46424
  const handleDismiss = () => {
46425
+ if (slot === "modal" || slot === "drawer") {
46426
+ eventBus.emit("UI:CLOSE");
46427
+ eventBus.emit("UI:CANCEL");
46428
+ }
46411
46429
  clear(slot);
46412
46430
  };
46413
46431
  if (portal) {
@@ -46457,7 +46475,8 @@ function getOrCreatePortalRoot() {
46457
46475
  }
46458
46476
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
46459
46477
  const [portalRoot, setPortalRoot] = useState(null);
46460
- const eventBus = useUISlots();
46478
+ const slotsBus = useUISlots();
46479
+ const eventBus = useEventBus();
46461
46480
  useEffect(() => {
46462
46481
  setPortalRoot(getOrCreatePortalRoot());
46463
46482
  }, []);
@@ -46465,7 +46484,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
46465
46484
  if (portalRoot) getOrCreatePortalRoot();
46466
46485
  });
46467
46486
  const handleDismiss = () => {
46468
- eventBus.clear(slot);
46487
+ if (slot === "modal" || slot === "drawer") {
46488
+ eventBus.emit("UI:CLOSE");
46489
+ eventBus.emit("UI:CANCEL");
46490
+ }
46491
+ slotsBus.clear(slot);
46469
46492
  };
46470
46493
  if (!portalRoot) return null;
46471
46494
  const slotId = `slot-${slot}`;
@@ -46813,6 +46836,7 @@ var init_UISlotRenderer = __esm({
46813
46836
  init_Toast();
46814
46837
  init_Box();
46815
46838
  init_Typography();
46839
+ init_useEventBus();
46816
46840
  init_cn();
46817
46841
  init_ErrorBoundary();
46818
46842
  init_Skeleton();
@@ -6,8 +6,8 @@
6
6
  */
7
7
  import React from "react";
8
8
  export interface AnimatedCounterProps {
9
- /** The target number to animate to */
10
- value: number;
9
+ /** The target value to animate to. Strings are parsed numerically (e.g. "500", "99.9"). */
10
+ value: number | string;
11
11
  /** Animation duration in milliseconds */
12
12
  duration?: number;
13
13
  /** Text to display before the number */
@@ -3178,7 +3178,8 @@ var init_AnimatedCounter = __esm({
3178
3178
  suffix,
3179
3179
  className
3180
3180
  }) => {
3181
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
3181
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
3182
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
3182
3183
  const [displayValue, setDisplayValue] = React110.useState(value);
3183
3184
  const previousValueRef = React110.useRef(value);
3184
3185
  const animationFrameRef = React110.useRef(null);
@@ -37163,18 +37164,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37163
37164
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37164
37165
  onClick: (e) => e.stopPropagation(),
37165
37166
  children: [
37166
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37167
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37167
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn(
37168
+ "flex items-center p-4",
37169
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37170
+ ), children: [
37171
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37168
37172
  /* @__PURE__ */ jsxRuntime.jsx(
37169
37173
  exports.Box,
37170
37174
  {
37171
37175
  as: "button",
37172
37176
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37173
37177
  onClick: onDismiss,
37178
+ "data-event": "CLOSE",
37179
+ "data-testid": "action-CLOSE",
37180
+ "aria-label": "Close modal",
37174
37181
  children: "\u2715"
37175
37182
  }
37176
37183
  )
37177
- ] }) : null,
37184
+ ] }),
37178
37185
  /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37179
37186
  ]
37180
37187
  }
@@ -37199,18 +37206,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37199
37206
  ),
37200
37207
  onClick: (e) => e.stopPropagation(),
37201
37208
  children: [
37202
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37203
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37209
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn(
37210
+ "flex items-center p-4",
37211
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37212
+ ), children: [
37213
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37204
37214
  /* @__PURE__ */ jsxRuntime.jsx(
37205
37215
  exports.Box,
37206
37216
  {
37207
37217
  as: "button",
37208
37218
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37209
37219
  onClick: onDismiss,
37220
+ "data-event": "CLOSE",
37221
+ "data-testid": "action-CLOSE",
37222
+ "aria-label": "Close drawer",
37210
37223
  children: "\u2715"
37211
37224
  }
37212
37225
  )
37213
- ] }) : null,
37226
+ ] }),
37214
37227
  /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "p-4", children: slotContent })
37215
37228
  ]
37216
37229
  }
@@ -37254,6 +37267,7 @@ function UISlotComponent({
37254
37267
  sourceTrait
37255
37268
  }) {
37256
37269
  const { slots, clear } = context.useUISlots();
37270
+ const eventBus = useEventBus();
37257
37271
  const suspenseConfig = React110.useContext(SuspenseConfigContext);
37258
37272
  const contained = React110.useContext(SlotContainedContext);
37259
37273
  const content = slots[slot];
@@ -37300,6 +37314,10 @@ function UISlotComponent({
37300
37314
  return null;
37301
37315
  }
37302
37316
  const handleDismiss = () => {
37317
+ if (slot === "modal" || slot === "drawer") {
37318
+ eventBus.emit("UI:CLOSE");
37319
+ eventBus.emit("UI:CANCEL");
37320
+ }
37303
37321
  clear(slot);
37304
37322
  };
37305
37323
  if (portal) {
@@ -37349,7 +37367,8 @@ function getOrCreatePortalRoot() {
37349
37367
  }
37350
37368
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37351
37369
  const [portalRoot, setPortalRoot] = React110.useState(null);
37352
- const eventBus = context.useUISlots();
37370
+ const slotsBus = context.useUISlots();
37371
+ const eventBus = useEventBus();
37353
37372
  React110.useEffect(() => {
37354
37373
  setPortalRoot(getOrCreatePortalRoot());
37355
37374
  }, []);
@@ -37357,7 +37376,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37357
37376
  if (portalRoot) getOrCreatePortalRoot();
37358
37377
  });
37359
37378
  const handleDismiss = () => {
37360
- eventBus.clear(slot);
37379
+ if (slot === "modal" || slot === "drawer") {
37380
+ eventBus.emit("UI:CLOSE");
37381
+ eventBus.emit("UI:CANCEL");
37382
+ }
37383
+ slotsBus.clear(slot);
37361
37384
  };
37362
37385
  if (!portalRoot) return null;
37363
37386
  const slotId = `slot-${slot}`;
@@ -37704,6 +37727,7 @@ var init_UISlotRenderer = __esm({
37704
37727
  init_Toast();
37705
37728
  init_Box();
37706
37729
  init_Typography();
37730
+ init_useEventBus();
37707
37731
  init_cn();
37708
37732
  init_ErrorBoundary();
37709
37733
  init_Skeleton();
@@ -3133,7 +3133,8 @@ var init_AnimatedCounter = __esm({
3133
3133
  suffix,
3134
3134
  className
3135
3135
  }) => {
3136
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
3136
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
3137
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
3137
3138
  const [displayValue, setDisplayValue] = useState(value);
3138
3139
  const previousValueRef = useRef(value);
3139
3140
  const animationFrameRef = useRef(null);
@@ -37118,18 +37119,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37118
37119
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37119
37120
  onClick: (e) => e.stopPropagation(),
37120
37121
  children: [
37121
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37122
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37122
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37123
+ "flex items-center p-4",
37124
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37125
+ ), children: [
37126
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37123
37127
  /* @__PURE__ */ jsx(
37124
37128
  Box,
37125
37129
  {
37126
37130
  as: "button",
37127
37131
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37128
37132
  onClick: onDismiss,
37133
+ "data-event": "CLOSE",
37134
+ "data-testid": "action-CLOSE",
37135
+ "aria-label": "Close modal",
37129
37136
  children: "\u2715"
37130
37137
  }
37131
37138
  )
37132
- ] }) : null,
37139
+ ] }),
37133
37140
  /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37134
37141
  ]
37135
37142
  }
@@ -37154,18 +37161,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37154
37161
  ),
37155
37162
  onClick: (e) => e.stopPropagation(),
37156
37163
  children: [
37157
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37158
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37164
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37165
+ "flex items-center p-4",
37166
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37167
+ ), children: [
37168
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37159
37169
  /* @__PURE__ */ jsx(
37160
37170
  Box,
37161
37171
  {
37162
37172
  as: "button",
37163
37173
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37164
37174
  onClick: onDismiss,
37175
+ "data-event": "CLOSE",
37176
+ "data-testid": "action-CLOSE",
37177
+ "aria-label": "Close drawer",
37165
37178
  children: "\u2715"
37166
37179
  }
37167
37180
  )
37168
- ] }) : null,
37181
+ ] }),
37169
37182
  /* @__PURE__ */ jsx(Box, { className: "p-4", children: slotContent })
37170
37183
  ]
37171
37184
  }
@@ -37209,6 +37222,7 @@ function UISlotComponent({
37209
37222
  sourceTrait
37210
37223
  }) {
37211
37224
  const { slots, clear } = useUISlots();
37225
+ const eventBus = useEventBus();
37212
37226
  const suspenseConfig = useContext(SuspenseConfigContext);
37213
37227
  const contained = useContext(SlotContainedContext);
37214
37228
  const content = slots[slot];
@@ -37255,6 +37269,10 @@ function UISlotComponent({
37255
37269
  return null;
37256
37270
  }
37257
37271
  const handleDismiss = () => {
37272
+ if (slot === "modal" || slot === "drawer") {
37273
+ eventBus.emit("UI:CLOSE");
37274
+ eventBus.emit("UI:CANCEL");
37275
+ }
37258
37276
  clear(slot);
37259
37277
  };
37260
37278
  if (portal) {
@@ -37304,7 +37322,8 @@ function getOrCreatePortalRoot() {
37304
37322
  }
37305
37323
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37306
37324
  const [portalRoot, setPortalRoot] = useState(null);
37307
- const eventBus = useUISlots();
37325
+ const slotsBus = useUISlots();
37326
+ const eventBus = useEventBus();
37308
37327
  useEffect(() => {
37309
37328
  setPortalRoot(getOrCreatePortalRoot());
37310
37329
  }, []);
@@ -37312,7 +37331,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37312
37331
  if (portalRoot) getOrCreatePortalRoot();
37313
37332
  });
37314
37333
  const handleDismiss = () => {
37315
- eventBus.clear(slot);
37334
+ if (slot === "modal" || slot === "drawer") {
37335
+ eventBus.emit("UI:CLOSE");
37336
+ eventBus.emit("UI:CANCEL");
37337
+ }
37338
+ slotsBus.clear(slot);
37316
37339
  };
37317
37340
  if (!portalRoot) return null;
37318
37341
  const slotId = `slot-${slot}`;
@@ -37659,6 +37682,7 @@ var init_UISlotRenderer = __esm({
37659
37682
  init_Toast();
37660
37683
  init_Box();
37661
37684
  init_Typography();
37685
+ init_useEventBus();
37662
37686
  init_cn();
37663
37687
  init_ErrorBoundary();
37664
37688
  init_Skeleton();
@@ -6,8 +6,8 @@
6
6
  */
7
7
  import React from 'react';
8
8
  export interface AnimatedCounterProps {
9
- /** Target value to count to (e.g. "500+", "99.9%", "3x") */
10
- value: string;
9
+ /** Target value to count to. Strings allow display formats (e.g. "500+", "99.9%", "3x"); numbers are coerced. */
10
+ value: string | number;
11
11
  /** Label displayed below the number */
12
12
  label: string;
13
13
  /** Animation duration in ms */
@@ -4641,7 +4641,7 @@ var PullQuote = ({
4641
4641
  };
4642
4642
  PullQuote.displayName = "PullQuote";
4643
4643
  function parseValue(value) {
4644
- if (!value) return { num: 0, prefix: "", suffix: "", decimals: 0 };
4644
+ if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
4645
4645
  const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
4646
4646
  if (!match) {
4647
4647
  return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
@@ -4668,7 +4668,7 @@ var AnimatedCounter = ({
4668
4668
  const animate = React5.useCallback(() => {
4669
4669
  const { num, prefix, suffix, decimals } = parseValue(value);
4670
4670
  if (num === 0) {
4671
- setDisplayValue(value);
4671
+ setDisplayValue(String(value));
4672
4672
  return;
4673
4673
  }
4674
4674
  const startTime = performance.now();
@@ -4681,7 +4681,7 @@ var AnimatedCounter = ({
4681
4681
  if (progress < 1) {
4682
4682
  requestAnimationFrame(tick);
4683
4683
  } else {
4684
- setDisplayValue(value);
4684
+ setDisplayValue(String(value));
4685
4685
  }
4686
4686
  };
4687
4687
  requestAnimationFrame(tick);
@@ -822,8 +822,8 @@ declare const PullQuote: React.FC<PullQuoteProps>;
822
822
  */
823
823
 
824
824
  interface AnimatedCounterProps {
825
- /** Target value to count to (e.g. "500+", "99.9%", "3x") */
826
- value: string;
825
+ /** Target value to count to. Strings allow display formats (e.g. "500+", "99.9%", "3x"); numbers are coerced. */
826
+ value: string | number;
827
827
  /** Label displayed below the number */
828
828
  label: string;
829
829
  /** Animation duration in ms */
@@ -4617,7 +4617,7 @@ var PullQuote = ({
4617
4617
  };
4618
4618
  PullQuote.displayName = "PullQuote";
4619
4619
  function parseValue(value) {
4620
- if (!value) return { num: 0, prefix: "", suffix: "", decimals: 0 };
4620
+ if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
4621
4621
  const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
4622
4622
  if (!match) {
4623
4623
  return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
@@ -4644,7 +4644,7 @@ var AnimatedCounter = ({
4644
4644
  const animate = useCallback(() => {
4645
4645
  const { num, prefix, suffix, decimals } = parseValue(value);
4646
4646
  if (num === 0) {
4647
- setDisplayValue(value);
4647
+ setDisplayValue(String(value));
4648
4648
  return;
4649
4649
  }
4650
4650
  const startTime = performance.now();
@@ -4657,7 +4657,7 @@ var AnimatedCounter = ({
4657
4657
  if (progress < 1) {
4658
4658
  requestAnimationFrame(tick);
4659
4659
  } else {
4660
- setDisplayValue(value);
4660
+ setDisplayValue(String(value));
4661
4661
  }
4662
4662
  };
4663
4663
  requestAnimationFrame(tick);
@@ -3681,7 +3681,8 @@ var init_AnimatedCounter = __esm({
3681
3681
  suffix,
3682
3682
  className
3683
3683
  }) => {
3684
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
3684
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
3685
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
3685
3686
  const [displayValue, setDisplayValue] = React115.useState(value);
3686
3687
  const previousValueRef = React115.useRef(value);
3687
3688
  const animationFrameRef = React115.useRef(null);
@@ -37672,18 +37673,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37672
37673
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37673
37674
  onClick: (e) => e.stopPropagation(),
37674
37675
  children: [
37675
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37676
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37676
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
37677
+ "flex items-center p-4",
37678
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37679
+ ), children: [
37680
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37677
37681
  /* @__PURE__ */ jsxRuntime.jsx(
37678
37682
  Box,
37679
37683
  {
37680
37684
  as: "button",
37681
37685
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37682
37686
  onClick: onDismiss,
37687
+ "data-event": "CLOSE",
37688
+ "data-testid": "action-CLOSE",
37689
+ "aria-label": "Close modal",
37683
37690
  children: "\u2715"
37684
37691
  }
37685
37692
  )
37686
- ] }) : null,
37693
+ ] }),
37687
37694
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37688
37695
  ]
37689
37696
  }
@@ -37708,18 +37715,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37708
37715
  ),
37709
37716
  onClick: (e) => e.stopPropagation(),
37710
37717
  children: [
37711
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37712
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37718
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
37719
+ "flex items-center p-4",
37720
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37721
+ ), children: [
37722
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37713
37723
  /* @__PURE__ */ jsxRuntime.jsx(
37714
37724
  Box,
37715
37725
  {
37716
37726
  as: "button",
37717
37727
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37718
37728
  onClick: onDismiss,
37729
+ "data-event": "CLOSE",
37730
+ "data-testid": "action-CLOSE",
37731
+ "aria-label": "Close drawer",
37719
37732
  children: "\u2715"
37720
37733
  }
37721
37734
  )
37722
- ] }) : null,
37735
+ ] }),
37723
37736
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4", children: slotContent })
37724
37737
  ]
37725
37738
  }
@@ -37763,6 +37776,7 @@ function UISlotComponent({
37763
37776
  sourceTrait
37764
37777
  }) {
37765
37778
  const { slots, clear } = context.useUISlots();
37779
+ const eventBus = useEventBus();
37766
37780
  const suspenseConfig = React115.useContext(SuspenseConfigContext);
37767
37781
  const contained = React115.useContext(SlotContainedContext);
37768
37782
  const content = slots[slot];
@@ -37809,6 +37823,10 @@ function UISlotComponent({
37809
37823
  return null;
37810
37824
  }
37811
37825
  const handleDismiss = () => {
37826
+ if (slot === "modal" || slot === "drawer") {
37827
+ eventBus.emit("UI:CLOSE");
37828
+ eventBus.emit("UI:CANCEL");
37829
+ }
37812
37830
  clear(slot);
37813
37831
  };
37814
37832
  if (portal) {
@@ -37858,7 +37876,8 @@ function getOrCreatePortalRoot() {
37858
37876
  }
37859
37877
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37860
37878
  const [portalRoot, setPortalRoot] = React115.useState(null);
37861
- const eventBus = context.useUISlots();
37879
+ const slotsBus = context.useUISlots();
37880
+ const eventBus = useEventBus();
37862
37881
  React115.useEffect(() => {
37863
37882
  setPortalRoot(getOrCreatePortalRoot());
37864
37883
  }, []);
@@ -37866,7 +37885,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37866
37885
  if (portalRoot) getOrCreatePortalRoot();
37867
37886
  });
37868
37887
  const handleDismiss = () => {
37869
- eventBus.clear(slot);
37888
+ if (slot === "modal" || slot === "drawer") {
37889
+ eventBus.emit("UI:CLOSE");
37890
+ eventBus.emit("UI:CANCEL");
37891
+ }
37892
+ slotsBus.clear(slot);
37870
37893
  };
37871
37894
  if (!portalRoot) return null;
37872
37895
  const slotId = `slot-${slot}`;
@@ -38213,6 +38236,7 @@ var init_UISlotRenderer = __esm({
38213
38236
  init_Toast();
38214
38237
  init_Box();
38215
38238
  init_Typography();
38239
+ init_useEventBus();
38216
38240
  init_cn();
38217
38241
  init_ErrorBoundary();
38218
38242
  init_Skeleton();
@@ -3636,7 +3636,8 @@ var init_AnimatedCounter = __esm({
3636
3636
  suffix,
3637
3637
  className
3638
3638
  }) => {
3639
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
3639
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
3640
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
3640
3641
  const [displayValue, setDisplayValue] = useState(value);
3641
3642
  const previousValueRef = useRef(value);
3642
3643
  const animationFrameRef = useRef(null);
@@ -37627,18 +37628,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37627
37628
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37628
37629
  onClick: (e) => e.stopPropagation(),
37629
37630
  children: [
37630
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37631
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37631
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37632
+ "flex items-center p-4",
37633
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37634
+ ), children: [
37635
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37632
37636
  /* @__PURE__ */ jsx(
37633
37637
  Box,
37634
37638
  {
37635
37639
  as: "button",
37636
37640
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37637
37641
  onClick: onDismiss,
37642
+ "data-event": "CLOSE",
37643
+ "data-testid": "action-CLOSE",
37644
+ "aria-label": "Close modal",
37638
37645
  children: "\u2715"
37639
37646
  }
37640
37647
  )
37641
- ] }) : null,
37648
+ ] }),
37642
37649
  /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37643
37650
  ]
37644
37651
  }
@@ -37663,18 +37670,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37663
37670
  ),
37664
37671
  onClick: (e) => e.stopPropagation(),
37665
37672
  children: [
37666
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37667
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37673
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37674
+ "flex items-center p-4",
37675
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37676
+ ), children: [
37677
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37668
37678
  /* @__PURE__ */ jsx(
37669
37679
  Box,
37670
37680
  {
37671
37681
  as: "button",
37672
37682
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37673
37683
  onClick: onDismiss,
37684
+ "data-event": "CLOSE",
37685
+ "data-testid": "action-CLOSE",
37686
+ "aria-label": "Close drawer",
37674
37687
  children: "\u2715"
37675
37688
  }
37676
37689
  )
37677
- ] }) : null,
37690
+ ] }),
37678
37691
  /* @__PURE__ */ jsx(Box, { className: "p-4", children: slotContent })
37679
37692
  ]
37680
37693
  }
@@ -37718,6 +37731,7 @@ function UISlotComponent({
37718
37731
  sourceTrait
37719
37732
  }) {
37720
37733
  const { slots, clear } = useUISlots();
37734
+ const eventBus = useEventBus();
37721
37735
  const suspenseConfig = useContext(SuspenseConfigContext);
37722
37736
  const contained = useContext(SlotContainedContext);
37723
37737
  const content = slots[slot];
@@ -37764,6 +37778,10 @@ function UISlotComponent({
37764
37778
  return null;
37765
37779
  }
37766
37780
  const handleDismiss = () => {
37781
+ if (slot === "modal" || slot === "drawer") {
37782
+ eventBus.emit("UI:CLOSE");
37783
+ eventBus.emit("UI:CANCEL");
37784
+ }
37767
37785
  clear(slot);
37768
37786
  };
37769
37787
  if (portal) {
@@ -37813,7 +37831,8 @@ function getOrCreatePortalRoot() {
37813
37831
  }
37814
37832
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37815
37833
  const [portalRoot, setPortalRoot] = useState(null);
37816
- const eventBus = useUISlots();
37834
+ const slotsBus = useUISlots();
37835
+ const eventBus = useEventBus();
37817
37836
  useEffect(() => {
37818
37837
  setPortalRoot(getOrCreatePortalRoot());
37819
37838
  }, []);
@@ -37821,7 +37840,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37821
37840
  if (portalRoot) getOrCreatePortalRoot();
37822
37841
  });
37823
37842
  const handleDismiss = () => {
37824
- eventBus.clear(slot);
37843
+ if (slot === "modal" || slot === "drawer") {
37844
+ eventBus.emit("UI:CLOSE");
37845
+ eventBus.emit("UI:CANCEL");
37846
+ }
37847
+ slotsBus.clear(slot);
37825
37848
  };
37826
37849
  if (!portalRoot) return null;
37827
37850
  const slotId = `slot-${slot}`;
@@ -38168,6 +38191,7 @@ var init_UISlotRenderer = __esm({
38168
38191
  init_Toast();
38169
38192
  init_Box();
38170
38193
  init_Typography();
38194
+ init_useEventBus();
38171
38195
  init_cn();
38172
38196
  init_ErrorBoundary();
38173
38197
  init_Skeleton();
@@ -4349,7 +4349,8 @@ var init_AnimatedCounter = __esm({
4349
4349
  suffix,
4350
4350
  className
4351
4351
  }) => {
4352
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
4352
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
4353
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
4353
4354
  const [displayValue, setDisplayValue] = React115.useState(value);
4354
4355
  const previousValueRef = React115.useRef(value);
4355
4356
  const animationFrameRef = React115.useRef(null);
@@ -37258,18 +37259,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37258
37259
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37259
37260
  onClick: (e) => e.stopPropagation(),
37260
37261
  children: [
37261
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37262
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37262
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
37263
+ "flex items-center p-4",
37264
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37265
+ ), children: [
37266
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37263
37267
  /* @__PURE__ */ jsxRuntime.jsx(
37264
37268
  Box,
37265
37269
  {
37266
37270
  as: "button",
37267
37271
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37268
37272
  onClick: onDismiss,
37273
+ "data-event": "CLOSE",
37274
+ "data-testid": "action-CLOSE",
37275
+ "aria-label": "Close modal",
37269
37276
  children: "\u2715"
37270
37277
  }
37271
37278
  )
37272
- ] }) : null,
37279
+ ] }),
37273
37280
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37274
37281
  ]
37275
37282
  }
@@ -37294,18 +37301,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37294
37301
  ),
37295
37302
  onClick: (e) => e.stopPropagation(),
37296
37303
  children: [
37297
- content.props.title ? /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37298
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37304
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn(
37305
+ "flex items-center p-4",
37306
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37307
+ ), children: [
37308
+ content.props.title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37299
37309
  /* @__PURE__ */ jsxRuntime.jsx(
37300
37310
  Box,
37301
37311
  {
37302
37312
  as: "button",
37303
37313
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37304
37314
  onClick: onDismiss,
37315
+ "data-event": "CLOSE",
37316
+ "data-testid": "action-CLOSE",
37317
+ "aria-label": "Close drawer",
37305
37318
  children: "\u2715"
37306
37319
  }
37307
37320
  )
37308
- ] }) : null,
37321
+ ] }),
37309
37322
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4", children: slotContent })
37310
37323
  ]
37311
37324
  }
@@ -37349,6 +37362,7 @@ function UISlotComponent({
37349
37362
  sourceTrait
37350
37363
  }) {
37351
37364
  const { slots, clear } = context.useUISlots();
37365
+ const eventBus = useEventBus();
37352
37366
  const suspenseConfig = React115.useContext(SuspenseConfigContext);
37353
37367
  const contained = React115.useContext(SlotContainedContext);
37354
37368
  const content = slots[slot];
@@ -37395,6 +37409,10 @@ function UISlotComponent({
37395
37409
  return null;
37396
37410
  }
37397
37411
  const handleDismiss = () => {
37412
+ if (slot === "modal" || slot === "drawer") {
37413
+ eventBus.emit("UI:CLOSE");
37414
+ eventBus.emit("UI:CANCEL");
37415
+ }
37398
37416
  clear(slot);
37399
37417
  };
37400
37418
  if (portal) {
@@ -37444,7 +37462,8 @@ function getOrCreatePortalRoot() {
37444
37462
  }
37445
37463
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37446
37464
  const [portalRoot, setPortalRoot] = React115.useState(null);
37447
- const eventBus = context.useUISlots();
37465
+ const slotsBus = context.useUISlots();
37466
+ const eventBus = useEventBus();
37448
37467
  React115.useEffect(() => {
37449
37468
  setPortalRoot(getOrCreatePortalRoot());
37450
37469
  }, []);
@@ -37452,7 +37471,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37452
37471
  if (portalRoot) getOrCreatePortalRoot();
37453
37472
  });
37454
37473
  const handleDismiss = () => {
37455
- eventBus.clear(slot);
37474
+ if (slot === "modal" || slot === "drawer") {
37475
+ eventBus.emit("UI:CLOSE");
37476
+ eventBus.emit("UI:CANCEL");
37477
+ }
37478
+ slotsBus.clear(slot);
37456
37479
  };
37457
37480
  if (!portalRoot) return null;
37458
37481
  const slotId = `slot-${slot}`;
@@ -37799,6 +37822,7 @@ var init_UISlotRenderer = __esm({
37799
37822
  init_Toast();
37800
37823
  init_Box();
37801
37824
  init_Typography();
37825
+ init_useEventBus();
37802
37826
  init_cn();
37803
37827
  init_ErrorBoundary();
37804
37828
  init_Skeleton();
@@ -4304,7 +4304,8 @@ var init_AnimatedCounter = __esm({
4304
4304
  suffix,
4305
4305
  className
4306
4306
  }) => {
4307
- const value = typeof rawValue === "number" && !Number.isNaN(rawValue) ? rawValue : 0;
4307
+ const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
4308
+ const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
4308
4309
  const [displayValue, setDisplayValue] = useState(value);
4309
4310
  const previousValueRef = useRef(value);
4310
4311
  const animationFrameRef = useRef(null);
@@ -37213,18 +37214,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37213
37214
  style: { minWidth: "520px", maxWidth: "700px", maxHeight: "80%" },
37214
37215
  onClick: (e) => e.stopPropagation(),
37215
37216
  children: [
37216
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37217
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37217
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37218
+ "flex items-center p-4",
37219
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37220
+ ), children: [
37221
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37218
37222
  /* @__PURE__ */ jsx(
37219
37223
  Box,
37220
37224
  {
37221
37225
  as: "button",
37222
37226
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37223
37227
  onClick: onDismiss,
37228
+ "data-event": "CLOSE",
37229
+ "data-testid": "action-CLOSE",
37230
+ "aria-label": "Close modal",
37224
37231
  children: "\u2715"
37225
37232
  }
37226
37233
  )
37227
- ] }) : null,
37234
+ ] }),
37228
37235
  /* @__PURE__ */ jsx(Box, { className: "flex-1 overflow-auto p-4", children: slotContent })
37229
37236
  ]
37230
37237
  }
@@ -37249,18 +37256,24 @@ function renderContainedPortal(slot, content, onDismiss) {
37249
37256
  ),
37250
37257
  onClick: (e) => e.stopPropagation(),
37251
37258
  children: [
37252
- content.props.title ? /* @__PURE__ */ jsxs(Box, { className: "flex items-center justify-between p-4 border-b border-border", children: [
37253
- /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }),
37259
+ /* @__PURE__ */ jsxs(Box, { className: cn(
37260
+ "flex items-center p-4",
37261
+ content.props.title ? "justify-between border-b border-border" : "justify-end"
37262
+ ), children: [
37263
+ content.props.title ? /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-semibold", children: String(content.props.title) }) : null,
37254
37264
  /* @__PURE__ */ jsx(
37255
37265
  Box,
37256
37266
  {
37257
37267
  as: "button",
37258
37268
  className: "text-muted-foreground hover:text-foreground cursor-pointer",
37259
37269
  onClick: onDismiss,
37270
+ "data-event": "CLOSE",
37271
+ "data-testid": "action-CLOSE",
37272
+ "aria-label": "Close drawer",
37260
37273
  children: "\u2715"
37261
37274
  }
37262
37275
  )
37263
- ] }) : null,
37276
+ ] }),
37264
37277
  /* @__PURE__ */ jsx(Box, { className: "p-4", children: slotContent })
37265
37278
  ]
37266
37279
  }
@@ -37304,6 +37317,7 @@ function UISlotComponent({
37304
37317
  sourceTrait
37305
37318
  }) {
37306
37319
  const { slots, clear } = useUISlots();
37320
+ const eventBus = useEventBus();
37307
37321
  const suspenseConfig = useContext(SuspenseConfigContext);
37308
37322
  const contained = useContext(SlotContainedContext);
37309
37323
  const content = slots[slot];
@@ -37350,6 +37364,10 @@ function UISlotComponent({
37350
37364
  return null;
37351
37365
  }
37352
37366
  const handleDismiss = () => {
37367
+ if (slot === "modal" || slot === "drawer") {
37368
+ eventBus.emit("UI:CLOSE");
37369
+ eventBus.emit("UI:CANCEL");
37370
+ }
37353
37371
  clear(slot);
37354
37372
  };
37355
37373
  if (portal) {
@@ -37399,7 +37417,8 @@ function getOrCreatePortalRoot() {
37399
37417
  }
37400
37418
  function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37401
37419
  const [portalRoot, setPortalRoot] = useState(null);
37402
- const eventBus = useUISlots();
37420
+ const slotsBus = useUISlots();
37421
+ const eventBus = useEventBus();
37403
37422
  useEffect(() => {
37404
37423
  setPortalRoot(getOrCreatePortalRoot());
37405
37424
  }, []);
@@ -37407,7 +37426,11 @@ function CompiledPortal({ slot, className, pattern, sourceTrait, children }) {
37407
37426
  if (portalRoot) getOrCreatePortalRoot();
37408
37427
  });
37409
37428
  const handleDismiss = () => {
37410
- eventBus.clear(slot);
37429
+ if (slot === "modal" || slot === "drawer") {
37430
+ eventBus.emit("UI:CLOSE");
37431
+ eventBus.emit("UI:CANCEL");
37432
+ }
37433
+ slotsBus.clear(slot);
37411
37434
  };
37412
37435
  if (!portalRoot) return null;
37413
37436
  const slotId = `slot-${slot}`;
@@ -37754,6 +37777,7 @@ var init_UISlotRenderer = __esm({
37754
37777
  init_Toast();
37755
37778
  init_Box();
37756
37779
  init_Typography();
37780
+ init_useEventBus();
37757
37781
  init_cn();
37758
37782
  init_ErrorBoundary();
37759
37783
  init_Skeleton();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.3.1",
3
+ "version": "4.4.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",