@particle-academy/react-fancy 6.0.0 → 6.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/badge.cjs +3 -2
  3. package/dist/badge.js +2 -1
  4. package/dist/button.cjs +3 -3
  5. package/dist/button.js +1 -1
  6. package/dist/callout.cjs +2 -2
  7. package/dist/callout.js +1 -1
  8. package/dist/chat-thread.cjs +7 -6
  9. package/dist/chat-thread.js +5 -4
  10. package/dist/{chunk-PACFMPSX.js → chunk-23KQF47X.js} +5 -5
  11. package/dist/{chunk-PACFMPSX.js.map → chunk-23KQF47X.js.map} +1 -1
  12. package/dist/{chunk-GBR4Q6CP.js → chunk-3AA2KGZG.js} +3 -3
  13. package/dist/{chunk-GBR4Q6CP.js.map → chunk-3AA2KGZG.js.map} +1 -1
  14. package/dist/{chunk-WLDDGIGC.js → chunk-4GPH7HOR.js} +11 -3
  15. package/dist/chunk-4GPH7HOR.js.map +1 -0
  16. package/dist/{chunk-LWOA2ET6.js → chunk-B6WTCAGY.js} +3 -3
  17. package/dist/{chunk-LWOA2ET6.js.map → chunk-B6WTCAGY.js.map} +1 -1
  18. package/dist/{chunk-JKH5ODNG.cjs → chunk-CKO2KCUN.cjs} +9 -9
  19. package/dist/{chunk-JKH5ODNG.cjs.map → chunk-CKO2KCUN.cjs.map} +1 -1
  20. package/dist/{chunk-BQFPC5FL.js → chunk-ESCIXKFT.js} +3 -3
  21. package/dist/{chunk-BQFPC5FL.js.map → chunk-ESCIXKFT.js.map} +1 -1
  22. package/dist/{chunk-VZ7IDHUY.js → chunk-F4OYQ2XZ.js} +4 -4
  23. package/dist/{chunk-VZ7IDHUY.js.map → chunk-F4OYQ2XZ.js.map} +1 -1
  24. package/dist/{chunk-ND5SBHGH.cjs → chunk-FKZB27OM.cjs} +6 -6
  25. package/dist/{chunk-ND5SBHGH.cjs.map → chunk-FKZB27OM.cjs.map} +1 -1
  26. package/dist/{chunk-EZA6GWZL.cjs → chunk-GK7IGL7N.cjs} +195 -8
  27. package/dist/chunk-GK7IGL7N.cjs.map +1 -0
  28. package/dist/{chunk-KOECVLC4.js → chunk-GSMD5NK5.js} +3 -3
  29. package/dist/{chunk-KOECVLC4.js.map → chunk-GSMD5NK5.js.map} +1 -1
  30. package/dist/{chunk-ZXGX5RI5.cjs → chunk-I2VAGZXY.cjs} +4 -4
  31. package/dist/{chunk-ZXGX5RI5.cjs.map → chunk-I2VAGZXY.cjs.map} +1 -1
  32. package/dist/{chunk-IA6JKI4P.cjs → chunk-K7JOZQRK.cjs} +15 -15
  33. package/dist/{chunk-IA6JKI4P.cjs.map → chunk-K7JOZQRK.cjs.map} +1 -1
  34. package/dist/{chunk-H2YRZYKK.cjs → chunk-KFA7B6WP.cjs} +4 -4
  35. package/dist/{chunk-H2YRZYKK.cjs.map → chunk-KFA7B6WP.cjs.map} +1 -1
  36. package/dist/{chunk-ZXZJYVWP.js → chunk-KPRSRWNM.js} +3 -3
  37. package/dist/{chunk-ZXZJYVWP.js.map → chunk-KPRSRWNM.js.map} +1 -1
  38. package/dist/{chunk-VNOUXFZ2.cjs → chunk-KSSTFLV2.cjs} +20 -20
  39. package/dist/{chunk-VNOUXFZ2.cjs.map → chunk-KSSTFLV2.cjs.map} +1 -1
  40. package/dist/{chunk-YJHP5FVA.js → chunk-MTDOFZIB.js} +196 -9
  41. package/dist/chunk-MTDOFZIB.js.map +1 -0
  42. package/dist/{chunk-BX6ZVWTO.cjs → chunk-NZHVDWOM.cjs} +11 -3
  43. package/dist/chunk-NZHVDWOM.cjs.map +1 -0
  44. package/dist/chunk-OCHUZ7J3.cjs +60 -0
  45. package/dist/chunk-OCHUZ7J3.cjs.map +1 -0
  46. package/dist/{chunk-BGRVHPGP.cjs → chunk-OUNGGQIS.cjs} +6 -6
  47. package/dist/{chunk-BGRVHPGP.cjs.map → chunk-OUNGGQIS.cjs.map} +1 -1
  48. package/dist/chunk-OZ4QFJ7N.js +58 -0
  49. package/dist/chunk-OZ4QFJ7N.js.map +1 -0
  50. package/dist/{chunk-MOU6O324.cjs → chunk-S53A6JIE.js} +3 -58
  51. package/dist/chunk-S53A6JIE.js.map +1 -0
  52. package/dist/{chunk-X354OVSC.cjs → chunk-SRICSNL4.cjs} +12 -12
  53. package/dist/{chunk-X354OVSC.cjs.map → chunk-SRICSNL4.cjs.map} +1 -1
  54. package/dist/{chunk-3RIBZZLT.js → chunk-TH4JZAMK.js} +5 -5
  55. package/dist/{chunk-3RIBZZLT.js.map → chunk-TH4JZAMK.js.map} +1 -1
  56. package/dist/{chunk-CWWMT57K.js → chunk-WF6AYHOS.js} +4 -4
  57. package/dist/{chunk-CWWMT57K.js.map → chunk-WF6AYHOS.js.map} +1 -1
  58. package/dist/{chunk-LCNHEYIM.cjs → chunk-WNWEC5OU.cjs} +3 -3
  59. package/dist/{chunk-LCNHEYIM.cjs.map → chunk-WNWEC5OU.cjs.map} +1 -1
  60. package/dist/{chunk-6FCQD2KQ.js → chunk-X6LGRB4H.cjs} +7 -55
  61. package/dist/chunk-X6LGRB4H.cjs.map +1 -0
  62. package/dist/content-renderer.cjs +5 -5
  63. package/dist/content-renderer.js +2 -2
  64. package/dist/editor.cjs +5 -5
  65. package/dist/editor.js +3 -3
  66. package/dist/index.cjs +51 -50
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.d.cts +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.js +13 -12
  71. package/dist/index.js.map +1 -1
  72. package/dist/json-editor.cjs +16 -15
  73. package/dist/json-editor.js +5 -4
  74. package/dist/magic-wand.cjs +5 -4
  75. package/dist/magic-wand.js +4 -3
  76. package/dist/prompt-input.cjs +5 -5
  77. package/dist/prompt-input.js +2 -2
  78. package/dist/reason-tag.cjs +3 -3
  79. package/dist/reason-tag.js +2 -2
  80. package/dist/sidebar.cjs +4 -3
  81. package/dist/sidebar.d.cts +49 -4
  82. package/dist/sidebar.d.ts +49 -4
  83. package/dist/sidebar.js +2 -1
  84. package/dist/toast.cjs +5 -4
  85. package/dist/toast.js +3 -2
  86. package/docs/Button.md +8 -0
  87. package/docs/Sidebar.md +75 -1
  88. package/package.json +1 -1
  89. package/dist/chunk-6FCQD2KQ.js.map +0 -1
  90. package/dist/chunk-BX6ZVWTO.cjs.map +0 -1
  91. package/dist/chunk-EZA6GWZL.cjs.map +0 -1
  92. package/dist/chunk-MOU6O324.cjs.map +0 -1
  93. package/dist/chunk-WLDDGIGC.js.map +0 -1
  94. package/dist/chunk-YJHP5FVA.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkND5SBHGH_cjs = require('./chunk-ND5SBHGH.cjs');
3
+ var chunkFKZB27OM_cjs = require('./chunk-FKZB27OM.cjs');
4
4
  require('./chunk-MAZEX4EZ.cjs');
5
5
  require('./chunk-MRZXTL46.cjs');
6
6
  require('./chunk-P53432AK.cjs');
@@ -11,9 +11,10 @@ require('./chunk-L3V3BYVS.cjs');
11
11
  require('./chunk-MKHYENKR.cjs');
12
12
  require('./chunk-TI7D4QDM.cjs');
13
13
  require('./chunk-VBWRH4UW.cjs');
14
- require('./chunk-MOU6O324.cjs');
14
+ require('./chunk-OCHUZ7J3.cjs');
15
+ require('./chunk-X6LGRB4H.cjs');
15
16
  require('./chunk-M5MUGSON.cjs');
16
- require('./chunk-BX6ZVWTO.cjs');
17
+ require('./chunk-NZHVDWOM.cjs');
17
18
  require('./chunk-XCZZVRBY.cjs');
18
19
  require('./chunk-MXWR3T3N.cjs');
19
20
  require('./chunk-ZU5Q77OT.cjs');
@@ -22,7 +23,7 @@ require('./chunk-ZU5Q77OT.cjs');
22
23
 
23
24
  Object.defineProperty(exports, "MagicWand", {
24
25
  enumerable: true,
25
- get: function () { return chunkND5SBHGH_cjs.MagicWand; }
26
+ get: function () { return chunkFKZB27OM_cjs.MagicWand; }
26
27
  });
27
28
  //# sourceMappingURL=magic-wand.cjs.map
28
29
  //# sourceMappingURL=magic-wand.cjs.map
@@ -1,4 +1,4 @@
1
- export { MagicWand } from './chunk-VZ7IDHUY.js';
1
+ export { MagicWand } from './chunk-F4OYQ2XZ.js';
2
2
  import './chunk-UVUBV4VZ.js';
3
3
  import './chunk-KXYMMNNV.js';
4
4
  import './chunk-WX5XYDVN.js';
@@ -9,9 +9,10 @@ import './chunk-NRXK42LO.js';
9
9
  import './chunk-5VMILVWD.js';
10
10
  import './chunk-RBCMKPBX.js';
11
11
  import './chunk-IQ4KQJAO.js';
12
- import './chunk-6FCQD2KQ.js';
12
+ import './chunk-OZ4QFJ7N.js';
13
+ import './chunk-S53A6JIE.js';
13
14
  import './chunk-LQ4ICCN2.js';
14
- import './chunk-WLDDGIGC.js';
15
+ import './chunk-4GPH7HOR.js';
15
16
  import './chunk-45BBNJQD.js';
16
17
  import './chunk-J3A4Z2P7.js';
17
18
  import './chunk-MMW2JGKZ.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkBGRVHPGP_cjs = require('./chunk-BGRVHPGP.cjs');
3
+ var chunkOUNGGQIS_cjs = require('./chunk-OUNGGQIS.cjs');
4
4
  require('./chunk-OASSZI6M.cjs');
5
5
  require('./chunk-I27K6NLX.cjs');
6
6
  require('./chunk-JKD6CFIP.cjs');
@@ -15,7 +15,7 @@ require('./chunk-TI7D4QDM.cjs');
15
15
  require('./chunk-57FQGQJK.cjs');
16
16
  require('./chunk-OUYC6EIL.cjs');
17
17
  require('./chunk-M5MUGSON.cjs');
18
- require('./chunk-BX6ZVWTO.cjs');
18
+ require('./chunk-NZHVDWOM.cjs');
19
19
  require('./chunk-XCZZVRBY.cjs');
20
20
  require('./chunk-MXWR3T3N.cjs');
21
21
  require('./chunk-SNHU2AI4.cjs');
@@ -25,15 +25,15 @@ require('./chunk-ZU5Q77OT.cjs');
25
25
 
26
26
  Object.defineProperty(exports, "PromptInput", {
27
27
  enumerable: true,
28
- get: function () { return chunkBGRVHPGP_cjs.PromptInput; }
28
+ get: function () { return chunkOUNGGQIS_cjs.PromptInput; }
29
29
  });
30
30
  Object.defineProperty(exports, "promptDataUrlToFile", {
31
31
  enumerable: true,
32
- get: function () { return chunkBGRVHPGP_cjs.promptDataUrlToFile; }
32
+ get: function () { return chunkOUNGGQIS_cjs.promptDataUrlToFile; }
33
33
  });
34
34
  Object.defineProperty(exports, "promptFileToDataUrl", {
35
35
  enumerable: true,
36
- get: function () { return chunkBGRVHPGP_cjs.promptFileToDataUrl; }
36
+ get: function () { return chunkOUNGGQIS_cjs.promptFileToDataUrl; }
37
37
  });
38
38
  //# sourceMappingURL=prompt-input.cjs.map
39
39
  //# sourceMappingURL=prompt-input.cjs.map
@@ -1,4 +1,4 @@
1
- export { PromptInput, promptDataUrlToFile, promptFileToDataUrl } from './chunk-LWOA2ET6.js';
1
+ export { PromptInput, promptDataUrlToFile, promptFileToDataUrl } from './chunk-B6WTCAGY.js';
2
2
  import './chunk-GR2WKBER.js';
3
3
  import './chunk-SV5BW3IA.js';
4
4
  import './chunk-J6IQHJET.js';
@@ -13,7 +13,7 @@ import './chunk-RBCMKPBX.js';
13
13
  import './chunk-RGANGU7X.js';
14
14
  import './chunk-YX6FTJ6N.js';
15
15
  import './chunk-LQ4ICCN2.js';
16
- import './chunk-WLDDGIGC.js';
16
+ import './chunk-4GPH7HOR.js';
17
17
  import './chunk-45BBNJQD.js';
18
18
  import './chunk-J3A4Z2P7.js';
19
19
  import './chunk-EDYAXGUM.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkZXGX5RI5_cjs = require('./chunk-ZXGX5RI5.cjs');
3
+ var chunkI2VAGZXY_cjs = require('./chunk-I2VAGZXY.cjs');
4
4
  require('./chunk-MKGWHSNV.cjs');
5
5
  require('./chunk-J2DI6RMR.cjs');
6
6
  require('./chunk-MKHYENKR.cjs');
@@ -8,7 +8,7 @@ require('./chunk-TI7D4QDM.cjs');
8
8
  require('./chunk-57FQGQJK.cjs');
9
9
  require('./chunk-OUYC6EIL.cjs');
10
10
  require('./chunk-M5MUGSON.cjs');
11
- require('./chunk-BX6ZVWTO.cjs');
11
+ require('./chunk-NZHVDWOM.cjs');
12
12
  require('./chunk-XCZZVRBY.cjs');
13
13
  require('./chunk-MXWR3T3N.cjs');
14
14
  require('./chunk-ZU5Q77OT.cjs');
@@ -17,7 +17,7 @@ require('./chunk-ZU5Q77OT.cjs');
17
17
 
18
18
  Object.defineProperty(exports, "ReasonTag", {
19
19
  enumerable: true,
20
- get: function () { return chunkZXGX5RI5_cjs.ReasonTag; }
20
+ get: function () { return chunkI2VAGZXY_cjs.ReasonTag; }
21
21
  });
22
22
  //# sourceMappingURL=reason-tag.cjs.map
23
23
  //# sourceMappingURL=reason-tag.cjs.map
@@ -1,4 +1,4 @@
1
- export { ReasonTag } from './chunk-KOECVLC4.js';
1
+ export { ReasonTag } from './chunk-GSMD5NK5.js';
2
2
  import './chunk-QTS4Q2NK.js';
3
3
  import './chunk-MQ6VGG62.js';
4
4
  import './chunk-5VMILVWD.js';
@@ -6,7 +6,7 @@ import './chunk-RBCMKPBX.js';
6
6
  import './chunk-RGANGU7X.js';
7
7
  import './chunk-YX6FTJ6N.js';
8
8
  import './chunk-LQ4ICCN2.js';
9
- import './chunk-WLDDGIGC.js';
9
+ import './chunk-4GPH7HOR.js';
10
10
  import './chunk-45BBNJQD.js';
11
11
  import './chunk-J3A4Z2P7.js';
12
12
  import './chunk-MMW2JGKZ.js';
package/dist/sidebar.cjs CHANGED
@@ -1,12 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkEZA6GWZL_cjs = require('./chunk-EZA6GWZL.cjs');
3
+ var chunkGK7IGL7N_cjs = require('./chunk-GK7IGL7N.cjs');
4
4
  require('./chunk-A2JUTNE6.cjs');
5
5
  require('./chunk-T6YELZPJ.cjs');
6
6
  require('./chunk-4GOOSZEK.cjs');
7
7
  require('./chunk-TXTRTTG7.cjs');
8
8
  require('./chunk-FQZE5N2N.cjs');
9
9
  require('./chunk-J2DI6RMR.cjs');
10
+ require('./chunk-X6LGRB4H.cjs');
10
11
  require('./chunk-57FQGQJK.cjs');
11
12
  require('./chunk-OUYC6EIL.cjs');
12
13
  require('./chunk-SNHU2AI4.cjs');
@@ -16,11 +17,11 @@ require('./chunk-ZU5Q77OT.cjs');
16
17
 
17
18
  Object.defineProperty(exports, "Sidebar", {
18
19
  enumerable: true,
19
- get: function () { return chunkEZA6GWZL_cjs.Sidebar; }
20
+ get: function () { return chunkGK7IGL7N_cjs.Sidebar; }
20
21
  });
21
22
  Object.defineProperty(exports, "useSidebar", {
22
23
  enumerable: true,
23
- get: function () { return chunkEZA6GWZL_cjs.useSidebar; }
24
+ get: function () { return chunkGK7IGL7N_cjs.useSidebar; }
24
25
  });
25
26
  //# sourceMappingURL=sidebar.cjs.map
26
27
  //# sourceMappingURL=sidebar.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { N as NavigableProps } from './types-DJI492iY.cjs';
3
+ import { N as NavigableProps, C as Color } from './types-DJI492iY.cjs';
4
4
 
5
5
  type SidebarCollapseMode = "icons" | "letters";
6
6
  interface SidebarProps {
@@ -29,14 +29,57 @@ interface SidebarProps {
29
29
  * @default "icons"
30
30
  */
31
31
  collapseMode?: SidebarCollapseMode;
32
+ /**
33
+ * Wrap the children in `<nav aria-label={navLabel}>`, so the items form a
34
+ * navigation landmark. The root stays an `<aside>`; the `<nav>` sits inside
35
+ * it and takes over the column layout. Omitted (or empty), no `<nav>` is
36
+ * rendered and the markup is exactly what it was before this prop existed.
37
+ */
38
+ navLabel?: string;
39
+ /**
40
+ * Arrow-key movement between items with a roving tabindex: the rail becomes
41
+ * ONE tab stop (the active item, else the first enabled one), and
42
+ * ArrowUp / ArrowDown / Home / End move focus within it. Disabled items and
43
+ * items inside a closed `Sidebar.Submenu` are skipped; a submenu's trigger
44
+ * is part of the sequence. Keys pressed in an input, textarea, select or
45
+ * contenteditable inside the sidebar are never intercepted, and
46
+ * `Sidebar.Toggle` keeps its own tab stop.
47
+ *
48
+ * Opt-in because it changes Tab order: without it every item is its own
49
+ * tab stop, as before.
50
+ * @default false
51
+ */
52
+ keyboardNav?: boolean;
32
53
  className?: string;
33
54
  }
55
+ /** Colour of a {@link SidebarItemProps.dot}. `dot={true}` is red. */
56
+ type SidebarDotColor = Color;
34
57
  interface SidebarItemProps extends NavigableProps {
35
58
  children: ReactNode;
36
59
  icon?: ReactNode;
37
60
  active?: boolean;
38
61
  disabled?: boolean;
39
62
  badge?: ReactNode;
63
+ /**
64
+ * Also render `badge` when the sidebar is collapsed, as an overlay at the
65
+ * corner of the icon (or of the letters). Off by default: a collapsed rail
66
+ * has never shown badges, and a wide badge ("Beta") over a 20px icon is not
67
+ * something to switch on for every existing consumer. Best for short counts.
68
+ * Handle: `data-react-fancy-sidebar-badge`.
69
+ */
70
+ collapsedBadge?: boolean;
71
+ /**
72
+ * A small attention dot at the icon's corner (unread, warning, "needs
73
+ * you"), shown expanded AND collapsed. `true` is red; pass any Badge colour
74
+ * for another. Purely visual: pair it with `dotLabel`. Handle:
75
+ * `data-react-fancy-sidebar-dot`, with `data-color`.
76
+ */
77
+ dot?: boolean | SidebarDotColor;
78
+ /**
79
+ * Screen-reader text for the dot ("3 unread"), rendered visually hidden and
80
+ * appended to the item's accessible name. Ignored without `dot`.
81
+ */
82
+ dotLabel?: string;
40
83
  onClick?: () => void;
41
84
  className?: string;
42
85
  }
@@ -59,9 +102,11 @@ interface SidebarContextValue {
59
102
  collapsed: boolean;
60
103
  collapseMode: SidebarCollapseMode;
61
104
  setCollapsed: (collapsed: boolean) => void;
105
+ /** Whether the root has `keyboardNav` on. */
106
+ keyboardNav?: boolean;
62
107
  }
63
108
 
64
- declare function SidebarItem({ children, href, as: As, icon, active, disabled, badge, onClick, className, ...rest }: SidebarItemProps): react.JSX.Element;
109
+ declare function SidebarItem({ children, href, as: As, icon, active, disabled, badge, collapsedBadge, dot, dotLabel, onClick, className, ...rest }: SidebarItemProps): react.JSX.Element;
65
110
  declare namespace SidebarItem {
66
111
  var displayName: string;
67
112
  }
@@ -81,7 +126,7 @@ declare namespace SidebarToggle {
81
126
  var displayName: string;
82
127
  }
83
128
 
84
- declare function SidebarRoot({ children, collapsed: controlledCollapsed, defaultCollapsed, onCollapsedChange, collapseMode, embedded, className, }: SidebarProps): react.JSX.Element;
129
+ declare function SidebarRoot({ children, collapsed: controlledCollapsed, defaultCollapsed, onCollapsedChange, collapseMode, embedded, navLabel, keyboardNav, className, }: SidebarProps): react.JSX.Element;
85
130
  declare const Sidebar: typeof SidebarRoot & {
86
131
  Item: typeof SidebarItem;
87
132
  Group: typeof SidebarGroup;
@@ -91,4 +136,4 @@ declare const Sidebar: typeof SidebarRoot & {
91
136
 
92
137
  declare function useSidebar(): SidebarContextValue;
93
138
 
94
- export { Sidebar, type SidebarCollapseMode, type SidebarContextValue, type SidebarGroupProps, type SidebarItemProps, type SidebarProps, type SidebarSubmenuProps, type SidebarToggleProps, useSidebar };
139
+ export { Sidebar, type SidebarCollapseMode, type SidebarContextValue, type SidebarDotColor, type SidebarGroupProps, type SidebarItemProps, type SidebarProps, type SidebarSubmenuProps, type SidebarToggleProps, useSidebar };
package/dist/sidebar.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { N as NavigableProps } from './types-DJI492iY.js';
3
+ import { N as NavigableProps, C as Color } from './types-DJI492iY.js';
4
4
 
5
5
  type SidebarCollapseMode = "icons" | "letters";
6
6
  interface SidebarProps {
@@ -29,14 +29,57 @@ interface SidebarProps {
29
29
  * @default "icons"
30
30
  */
31
31
  collapseMode?: SidebarCollapseMode;
32
+ /**
33
+ * Wrap the children in `<nav aria-label={navLabel}>`, so the items form a
34
+ * navigation landmark. The root stays an `<aside>`; the `<nav>` sits inside
35
+ * it and takes over the column layout. Omitted (or empty), no `<nav>` is
36
+ * rendered and the markup is exactly what it was before this prop existed.
37
+ */
38
+ navLabel?: string;
39
+ /**
40
+ * Arrow-key movement between items with a roving tabindex: the rail becomes
41
+ * ONE tab stop (the active item, else the first enabled one), and
42
+ * ArrowUp / ArrowDown / Home / End move focus within it. Disabled items and
43
+ * items inside a closed `Sidebar.Submenu` are skipped; a submenu's trigger
44
+ * is part of the sequence. Keys pressed in an input, textarea, select or
45
+ * contenteditable inside the sidebar are never intercepted, and
46
+ * `Sidebar.Toggle` keeps its own tab stop.
47
+ *
48
+ * Opt-in because it changes Tab order: without it every item is its own
49
+ * tab stop, as before.
50
+ * @default false
51
+ */
52
+ keyboardNav?: boolean;
32
53
  className?: string;
33
54
  }
55
+ /** Colour of a {@link SidebarItemProps.dot}. `dot={true}` is red. */
56
+ type SidebarDotColor = Color;
34
57
  interface SidebarItemProps extends NavigableProps {
35
58
  children: ReactNode;
36
59
  icon?: ReactNode;
37
60
  active?: boolean;
38
61
  disabled?: boolean;
39
62
  badge?: ReactNode;
63
+ /**
64
+ * Also render `badge` when the sidebar is collapsed, as an overlay at the
65
+ * corner of the icon (or of the letters). Off by default: a collapsed rail
66
+ * has never shown badges, and a wide badge ("Beta") over a 20px icon is not
67
+ * something to switch on for every existing consumer. Best for short counts.
68
+ * Handle: `data-react-fancy-sidebar-badge`.
69
+ */
70
+ collapsedBadge?: boolean;
71
+ /**
72
+ * A small attention dot at the icon's corner (unread, warning, "needs
73
+ * you"), shown expanded AND collapsed. `true` is red; pass any Badge colour
74
+ * for another. Purely visual: pair it with `dotLabel`. Handle:
75
+ * `data-react-fancy-sidebar-dot`, with `data-color`.
76
+ */
77
+ dot?: boolean | SidebarDotColor;
78
+ /**
79
+ * Screen-reader text for the dot ("3 unread"), rendered visually hidden and
80
+ * appended to the item's accessible name. Ignored without `dot`.
81
+ */
82
+ dotLabel?: string;
40
83
  onClick?: () => void;
41
84
  className?: string;
42
85
  }
@@ -59,9 +102,11 @@ interface SidebarContextValue {
59
102
  collapsed: boolean;
60
103
  collapseMode: SidebarCollapseMode;
61
104
  setCollapsed: (collapsed: boolean) => void;
105
+ /** Whether the root has `keyboardNav` on. */
106
+ keyboardNav?: boolean;
62
107
  }
63
108
 
64
- declare function SidebarItem({ children, href, as: As, icon, active, disabled, badge, onClick, className, ...rest }: SidebarItemProps): react.JSX.Element;
109
+ declare function SidebarItem({ children, href, as: As, icon, active, disabled, badge, collapsedBadge, dot, dotLabel, onClick, className, ...rest }: SidebarItemProps): react.JSX.Element;
65
110
  declare namespace SidebarItem {
66
111
  var displayName: string;
67
112
  }
@@ -81,7 +126,7 @@ declare namespace SidebarToggle {
81
126
  var displayName: string;
82
127
  }
83
128
 
84
- declare function SidebarRoot({ children, collapsed: controlledCollapsed, defaultCollapsed, onCollapsedChange, collapseMode, embedded, className, }: SidebarProps): react.JSX.Element;
129
+ declare function SidebarRoot({ children, collapsed: controlledCollapsed, defaultCollapsed, onCollapsedChange, collapseMode, embedded, navLabel, keyboardNav, className, }: SidebarProps): react.JSX.Element;
85
130
  declare const Sidebar: typeof SidebarRoot & {
86
131
  Item: typeof SidebarItem;
87
132
  Group: typeof SidebarGroup;
@@ -91,4 +136,4 @@ declare const Sidebar: typeof SidebarRoot & {
91
136
 
92
137
  declare function useSidebar(): SidebarContextValue;
93
138
 
94
- export { Sidebar, type SidebarCollapseMode, type SidebarContextValue, type SidebarGroupProps, type SidebarItemProps, type SidebarProps, type SidebarSubmenuProps, type SidebarToggleProps, useSidebar };
139
+ export { Sidebar, type SidebarCollapseMode, type SidebarContextValue, type SidebarDotColor, type SidebarGroupProps, type SidebarItemProps, type SidebarProps, type SidebarSubmenuProps, type SidebarToggleProps, useSidebar };
package/dist/sidebar.js CHANGED
@@ -1,10 +1,11 @@
1
- export { Sidebar, useSidebar } from './chunk-YJHP5FVA.js';
1
+ export { Sidebar, useSidebar } from './chunk-MTDOFZIB.js';
2
2
  import './chunk-2BXMMVQS.js';
3
3
  import './chunk-CPY7NHXM.js';
4
4
  import './chunk-ZQ3VXRUY.js';
5
5
  import './chunk-5U2DZ7AV.js';
6
6
  import './chunk-3K2CEAI7.js';
7
7
  import './chunk-MQ6VGG62.js';
8
+ import './chunk-S53A6JIE.js';
8
9
  import './chunk-RGANGU7X.js';
9
10
  import './chunk-YX6FTJ6N.js';
10
11
  import './chunk-EDYAXGUM.js';
package/dist/toast.cjs CHANGED
@@ -1,10 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkH2YRZYKK_cjs = require('./chunk-H2YRZYKK.cjs');
3
+ var chunkKFA7B6WP_cjs = require('./chunk-KFA7B6WP.cjs');
4
4
  require('./chunk-MKHYENKR.cjs');
5
5
  require('./chunk-TI7D4QDM.cjs');
6
6
  require('./chunk-VBWRH4UW.cjs');
7
- require('./chunk-MOU6O324.cjs');
7
+ require('./chunk-OCHUZ7J3.cjs');
8
+ require('./chunk-X6LGRB4H.cjs');
8
9
  require('./chunk-SNHU2AI4.cjs');
9
10
  require('./chunk-ZU5Q77OT.cjs');
10
11
 
@@ -12,11 +13,11 @@ require('./chunk-ZU5Q77OT.cjs');
12
13
 
13
14
  Object.defineProperty(exports, "Toast", {
14
15
  enumerable: true,
15
- get: function () { return chunkH2YRZYKK_cjs.Toast; }
16
+ get: function () { return chunkKFA7B6WP_cjs.Toast; }
16
17
  });
17
18
  Object.defineProperty(exports, "useToast", {
18
19
  enumerable: true,
19
- get: function () { return chunkH2YRZYKK_cjs.useToast; }
20
+ get: function () { return chunkKFA7B6WP_cjs.useToast; }
20
21
  });
21
22
  //# sourceMappingURL=toast.cjs.map
22
23
  //# sourceMappingURL=toast.cjs.map
package/dist/toast.js CHANGED
@@ -1,8 +1,9 @@
1
- export { Toast, useToast } from './chunk-BQFPC5FL.js';
1
+ export { Toast, useToast } from './chunk-ESCIXKFT.js';
2
2
  import './chunk-5VMILVWD.js';
3
3
  import './chunk-RBCMKPBX.js';
4
4
  import './chunk-IQ4KQJAO.js';
5
- import './chunk-6FCQD2KQ.js';
5
+ import './chunk-OZ4QFJ7N.js';
6
+ import './chunk-S53A6JIE.js';
6
7
  import './chunk-EDYAXGUM.js';
7
8
  import './chunk-MMW2JGKZ.js';
8
9
  //# sourceMappingURL=toast.js.map
package/docs/Button.md CHANGED
@@ -102,3 +102,11 @@ should submit says so:
102
102
  <Button variant="ghost" color="red" icon="trash-2">Delete</Button>
103
103
  <Button variant="ghost" icon="download">Export</Button>
104
104
  ```
105
+
106
+ ## Focus ring
107
+
108
+ The ring shows on `:focus-visible` only, so it appears when someone reaches the
109
+ Button by keyboard and not after a mouse click. It uses the focus token
110
+ (`--fancy-focus`, blue-500 by default; `--fancy-focus-dark`, blue-400, in dark
111
+ mode) and is offset against the surface token, so dark mode gets no white gap.
112
+ Override it with `focus-visible:ring-*` classes in `className`.
package/docs/Sidebar.md CHANGED
@@ -34,6 +34,9 @@ import { Sidebar, Icon } from "@particle-academy/react-fancy";
34
34
  | defaultCollapsed | `boolean` | `false` | Default collapsed state (uncontrolled) |
35
35
  | onCollapsedChange | `(collapsed: boolean) => void` | - | Callback when collapsed state changes |
36
36
  | collapseMode | `"icons" \| "letters"` | `"icons"` | How items display when collapsed: icons only, or first 3 letters |
37
+ | embedded | `boolean` | `false` | Drop the app-shell chrome (right border, background, fixed `w-60`) for a sidebar inside a card, panel or drawer |
38
+ | navLabel | `string` | - | Wrap the children in `<nav aria-label={navLabel}>` so the items form a navigation landmark. Omitted, no `<nav>` is rendered |
39
+ | keyboardNav | `boolean` | `false` | ArrowUp / ArrowDown / Home / End between items, with a roving tabindex (the rail becomes one tab stop). See [Keyboard navigation](#keyboard-navigation) |
37
40
  | className | `string` | - | Additional CSS classes |
38
41
 
39
42
  ### Sidebar.Item
@@ -45,7 +48,10 @@ import { Sidebar, Icon } from "@particle-academy/react-fancy";
45
48
  | icon | `ReactNode` | - | Leading icon |
46
49
  | active | `boolean` | - | Active state highlight |
47
50
  | disabled | `boolean` | - | Disable the item |
48
- | badge | `ReactNode` | - | Trailing badge element |
51
+ | badge | `ReactNode` | - | Trailing badge element (expanded only, unless `collapsedBadge`) |
52
+ | collapsedBadge | `boolean` | `false` | Also show `badge` on a collapsed rail, as an overlay at the icon's corner. Best for short counts |
53
+ | dot | `boolean \| Color` | - | Attention dot at the icon's corner, shown expanded and collapsed. `true` is red; any Badge colour otherwise |
54
+ | dotLabel | `string` | - | Screen-reader text for the dot ("3 unread"), visually hidden and added to the item's accessible name |
49
55
  | onClick | `() => void` | - | Click handler |
50
56
  | className | `string` | - | Additional CSS classes |
51
57
 
@@ -94,6 +100,74 @@ const [collapsed, setCollapsed] = useState(false);
94
100
  - `"icons"` (default) — only the icon is shown when collapsed; falls back to the first 3 letters if no icon is provided
95
101
  - `"letters"` — the first 3 letters of the label are always shown
96
102
 
103
+ ## Attention marks on a compact rail
104
+
105
+ A collapsed rail shows only icons, so `badge` is hidden there by default. Use
106
+ `dot` for an unread, warning or "needs you" mark: it renders at the icon's
107
+ corner in both modes. A dot is only colour, so give it a `dotLabel` for screen
108
+ readers.
109
+
110
+ ```tsx
111
+ <Sidebar collapsed navLabel="Main">
112
+ <Sidebar.Item icon={<Icon name="inbox" size="sm" />} dot dotLabel="3 unread">
113
+ Inbox
114
+ </Sidebar.Item>
115
+ <Sidebar.Item icon={<Icon name="triangle-alert" size="sm" />} dot="amber" dotLabel="needs you">
116
+ Deploys
117
+ </Sidebar.Item>
118
+ <Sidebar.Item
119
+ icon={<Icon name="message-square" size="sm" />}
120
+ badge={<Badge size="sm" color="blue" variant="solid">12</Badge>}
121
+ collapsedBadge
122
+ >
123
+ Messages
124
+ </Sidebar.Item>
125
+ </Sidebar>
126
+ ```
127
+
128
+ - The collapsed item is still named by its label (`title` and a visually
129
+ hidden copy of the label), so the dot label or a badge count never replaces
130
+ the name: a screen reader hears "Inbox 3 unread".
131
+ - With both `dot` and `collapsedBadge` on a collapsed item, the badge takes the
132
+ top corner and the dot moves to the bottom one (`data-position="bottom"`).
133
+ - Handles: `data-react-fancy-sidebar-dot` (with `data-color` and
134
+ `data-position`), `data-react-fancy-sidebar-dot-label`,
135
+ `data-react-fancy-sidebar-badge` for the collapsed badge overlay.
136
+
137
+ ## Navigation landmark
138
+
139
+ `Sidebar` renders an `<aside>`. Pass `navLabel` to wrap its children in a
140
+ labelled `<nav>`, so the items appear in a screen reader's landmark list:
141
+
142
+ ```tsx
143
+ <Sidebar navLabel="Main">…</Sidebar>
144
+ ```
145
+
146
+ The `<nav>` (`data-react-fancy-sidebar-nav`) takes over the column layout and
147
+ fills the rail, so a footer pushed down with `mt-auto` still reaches the
148
+ bottom. Without `navLabel` the markup is unchanged.
149
+
150
+ ## Keyboard navigation
151
+
152
+ `keyboardNav` turns the rail into one tab stop with a roving tabindex:
153
+
154
+ - **Tab** lands on the active item (the one with `active`), or the first
155
+ enabled item when none is active. `Sidebar.Toggle` keeps its own tab stop.
156
+ - **ArrowDown / ArrowUp** move to the next / previous item; **Home / End** to
157
+ the first / last. No wrap at the ends.
158
+ - Disabled items are skipped. An open `Sidebar.Submenu`'s trigger and its items
159
+ are in the sequence; a closed submenu's items are skipped (its trigger gets
160
+ `aria-expanded`). Enter / Space on a trigger opens it as usual.
161
+ - Keys pressed in an input, textarea, select or contenteditable inside the
162
+ sidebar are never intercepted, nor are arrows with a modifier key.
163
+
164
+ It is opt-in because it changes Tab order: without it, every item is its own
165
+ tab stop, exactly as before.
166
+
167
+ ```tsx
168
+ <Sidebar keyboardNav navLabel="Main">…</Sidebar>
169
+ ```
170
+
97
171
  ## useSidebar Hook
98
172
 
99
173
  Access collapsed state from any child component:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "6.0.0",
3
+ "version": "6.1.0",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Badge/Badge.colors.ts","../src/components/Badge/Badge.tsx"],"names":[],"mappings":";;;;;AAMO,IAAM,UAAA,GAAoC;AAAA;AAAA;AAAA,EAG/C,KAAA,EAAO,8BAAA;AAAA,EACP,KAAA,EAAO,2CAAA;AAAA,EACP,IAAA,EAAM,yCAAA;AAAA,EACN,IAAA,EAAM,yCAAA;AAAA,EACN,OAAA,EAAS,+CAAA;AAAA,EACT,KAAA,EAAO,2CAAA;AAAA,EACP,GAAA,EAAK,uCAAA;AAAA,EACL,MAAA,EAAQ,6CAAA;AAAA,EACR,KAAA,EAAO,mEAAA;AAAA,EACP,MAAA,EAAQ,uEAAA;AAAA,EACR,IAAA,EAAM,+DAAA;AAAA,EACN,KAAA,EAAO,2CAAA;AAAA,EACP,OAAA,EAAS,+CAAA;AAAA,EACT,IAAA,EAAM,yCAAA;AAAA,EACN,IAAA,EAAM,yCAAA;AAAA,EACN,GAAA,EAAK,uCAAA;AAAA,EACL,IAAA,EAAM,yCAAA;AAAA,EACN,MAAA,EAAQ,6CAAA;AAAA,EACR,MAAA,EAAQ,6CAAA;AAAA,EACR,MAAA,EAAQ,6CAAA;AAAA,EACR,OAAA,EAAS,+CAAA;AAAA,EACT,IAAA,EAAM,yCAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEO,IAAM,YAAA,GAAsC;AAAA;AAAA;AAAA,EAGjD,KAAA,EAAO,mCAAA;AAAA,EACP,KAAA,EAAO,kFAAA;AAAA,EACP,IAAA,EAAM,8EAAA;AAAA,EACN,IAAA,EAAM,8EAAA;AAAA,EACN,OAAA,EAAS,0FAAA;AAAA,EACT,KAAA,EAAO,kFAAA;AAAA,EACP,GAAA,EAAK,0EAAA;AAAA,EACL,MAAA,EAAQ,sFAAA;AAAA,EACR,KAAA,EAAO,kFAAA;AAAA,EACP,MAAA,EAAQ,sFAAA;AAAA,EACR,IAAA,EAAM,8EAAA;AAAA,EACN,KAAA,EAAO,kFAAA;AAAA,EACP,OAAA,EAAS,0FAAA;AAAA,EACT,IAAA,EAAM,8EAAA;AAAA,EACN,IAAA,EAAM,8EAAA;AAAA,EACN,GAAA,EAAK,0EAAA;AAAA,EACL,IAAA,EAAM,8EAAA;AAAA,EACN,MAAA,EAAQ,sFAAA;AAAA,EACR,MAAA,EAAQ,sFAAA;AAAA,EACR,MAAA,EAAQ,sFAAA;AAAA,EACR,OAAA,EAAS,0FAAA;AAAA,EACT,IAAA,EAAM,8EAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEO,IAAM,SAAA,GAAmC;AAAA;AAAA;AAAA,EAG9C,KAAA,EAAO,wBAAA;AAAA,EACP,KAAA,EAAO,sEAAA;AAAA,EACP,IAAA,EAAM,kEAAA;AAAA,EACN,IAAA,EAAM,kEAAA;AAAA,EACN,OAAA,EAAS,8EAAA;AAAA,EACT,KAAA,EAAO,sEAAA;AAAA,EACP,GAAA,EAAK,8DAAA;AAAA,EACL,MAAA,EAAQ,0EAAA;AAAA,EACR,KAAA,EAAO,sEAAA;AAAA,EACP,MAAA,EAAQ,0EAAA;AAAA,EACR,IAAA,EAAM,kEAAA;AAAA,EACN,KAAA,EAAO,sEAAA;AAAA,EACP,OAAA,EAAS,8EAAA;AAAA,EACT,IAAA,EAAM,kEAAA;AAAA,EACN,IAAA,EAAM,kEAAA;AAAA,EACN,GAAA,EAAK,8DAAA;AAAA,EACL,IAAA,EAAM,kEAAA;AAAA,EACN,MAAA,EAAQ,0EAAA;AAAA,EACR,MAAA,EAAQ,0EAAA;AAAA,EACR,MAAA,EAAQ,0EAAA;AAAA,EACR,OAAA,EAAS,8EAAA;AAAA,EACT,IAAA,EAAM,kEAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEO,IAAM,QAAA,GAAkC;AAAA;AAAA;AAAA,EAG7C,KAAA,EAAO,UAAA;AAAA,EACP,KAAA,EAAO,cAAA;AAAA,EACP,IAAA,EAAM,aAAA;AAAA,EACN,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS,gBAAA;AAAA,EACT,KAAA,EAAO,cAAA;AAAA,EACP,GAAA,EAAK,YAAA;AAAA,EACL,MAAA,EAAQ,eAAA;AAAA,EACR,KAAA,EAAO,cAAA;AAAA,EACP,MAAA,EAAQ,eAAA;AAAA,EACR,IAAA,EAAM,aAAA;AAAA,EACN,KAAA,EAAO,cAAA;AAAA,EACP,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM,aAAA;AAAA,EACN,IAAA,EAAM,aAAA;AAAA,EACN,GAAA,EAAK,YAAA;AAAA,EACL,IAAA,EAAM,aAAA;AAAA,EACN,MAAA,EAAQ,eAAA;AAAA,EACR,MAAA,EAAQ,eAAA;AAAA,EACR,MAAA,EAAQ,eAAA;AAAA,EACR,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM,aAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AC3GA,IAAM,UAAA,GAAqD;AAAA,EACzD,KAAA,EAAO,UAAA;AAAA,EACP,OAAA,EAAS,YAAA;AAAA,EACT,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,WAAA,GAAyC;AAAA,EAC7C,EAAA,EAAI,uBAAA;AAAA,EACJ,EAAA,EAAI,qBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEO,IAAM,KAAA,GAAQ,UAAA;AAAA,EACnB,CACE;AAAA,IACE,KAAA,GAAQ,MAAA;AAAA,IACR,OAAA,GAAU,MAAA;AAAA,IACV,IAAA,GAAO,IAAA;AAAA,IACP,GAAA,GAAM,KAAA;AAAA,IACN,SAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,uBACE,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,wBAAA,EAAuB,EAAA;AAAA,QACvB,SAAA,EAAW,EAAA;AAAA,UACT,2DAAA;AAAA,UACA,YAAY,IAAI,CAAA;AAAA,UAChB,UAAA,CAAW,OAAO,CAAA,CAAE,KAAK,CAAA;AAAA,UACzB;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,GAAA,oBACC,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,EAAA;AAAA,gBACT,uCAAA;AAAA,gBACA,SAAS,KAAK;AAAA;AAChB;AAAA,WACF;AAAA,UAED;AAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AACF;AAEA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-6FCQD2KQ.js","sourcesContent":["// AUTO-GENERATED by scripts/gen-badge-colors — do not edit by hand.\n// Literal Tailwind class strings for every color in the v4 palette so the\n// scanner can detect them in the published dist (template-built names are\n// invisible to Tailwind's JIT). Regenerate after changing the palette.\nimport type { Color } from \"../../utils/types\";\n\nexport const badgeSolid: Record<Color, string> = {\n // The host's colour, from CSS variables -- no dark: variant, because a\n // host that themes per mode scopes the variables themselves.\n brand: \"bg-brand text-brand-contrast\",\n slate: \"bg-slate-600 text-white dark:bg-slate-500\",\n gray: \"bg-gray-600 text-white dark:bg-gray-500\",\n zinc: \"bg-zinc-600 text-white dark:bg-zinc-500\",\n neutral: \"bg-neutral-600 text-white dark:bg-neutral-500\",\n stone: \"bg-stone-600 text-white dark:bg-stone-500\",\n red: \"bg-red-600 text-white dark:bg-red-500\",\n orange: \"bg-orange-600 text-white dark:bg-orange-500\",\n amber: \"bg-amber-400 text-amber-950 dark:bg-amber-300 dark:text-amber-950\",\n yellow: \"bg-yellow-400 text-yellow-950 dark:bg-yellow-300 dark:text-yellow-950\",\n lime: \"bg-lime-400 text-lime-950 dark:bg-lime-300 dark:text-lime-950\",\n green: \"bg-green-600 text-white dark:bg-green-500\",\n emerald: \"bg-emerald-600 text-white dark:bg-emerald-500\",\n teal: \"bg-teal-600 text-white dark:bg-teal-500\",\n cyan: \"bg-cyan-600 text-white dark:bg-cyan-500\",\n sky: \"bg-sky-600 text-white dark:bg-sky-500\",\n blue: \"bg-blue-600 text-white dark:bg-blue-500\",\n indigo: \"bg-indigo-600 text-white dark:bg-indigo-500\",\n violet: \"bg-violet-600 text-white dark:bg-violet-500\",\n purple: \"bg-purple-600 text-white dark:bg-purple-500\",\n fuchsia: \"bg-fuchsia-600 text-white dark:bg-fuchsia-500\",\n pink: \"bg-pink-600 text-white dark:bg-pink-500\",\n rose: \"bg-rose-600 text-white dark:bg-rose-500\",\n};\n\nexport const badgeOutline: Record<Color, string> = {\n // The host's colour, from CSS variables -- no dark: variant, because a\n // host that themes per mode scopes the variables themselves.\n brand: \"border border-brand/40 text-brand\",\n slate: \"border border-slate-300 text-slate-700 dark:border-slate-600 dark:text-slate-300\",\n gray: \"border border-gray-300 text-gray-700 dark:border-gray-600 dark:text-gray-300\",\n zinc: \"border border-zinc-300 text-zinc-700 dark:border-zinc-600 dark:text-zinc-300\",\n neutral: \"border border-neutral-300 text-neutral-700 dark:border-neutral-600 dark:text-neutral-300\",\n stone: \"border border-stone-300 text-stone-700 dark:border-stone-600 dark:text-stone-300\",\n red: \"border border-red-300 text-red-700 dark:border-red-600 dark:text-red-300\",\n orange: \"border border-orange-300 text-orange-700 dark:border-orange-600 dark:text-orange-300\",\n amber: \"border border-amber-300 text-amber-700 dark:border-amber-600 dark:text-amber-300\",\n yellow: \"border border-yellow-300 text-yellow-700 dark:border-yellow-600 dark:text-yellow-300\",\n lime: \"border border-lime-300 text-lime-700 dark:border-lime-600 dark:text-lime-300\",\n green: \"border border-green-300 text-green-700 dark:border-green-600 dark:text-green-300\",\n emerald: \"border border-emerald-300 text-emerald-700 dark:border-emerald-600 dark:text-emerald-300\",\n teal: \"border border-teal-300 text-teal-700 dark:border-teal-600 dark:text-teal-300\",\n cyan: \"border border-cyan-300 text-cyan-700 dark:border-cyan-600 dark:text-cyan-300\",\n sky: \"border border-sky-300 text-sky-700 dark:border-sky-600 dark:text-sky-300\",\n blue: \"border border-blue-300 text-blue-700 dark:border-blue-600 dark:text-blue-300\",\n indigo: \"border border-indigo-300 text-indigo-700 dark:border-indigo-600 dark:text-indigo-300\",\n violet: \"border border-violet-300 text-violet-700 dark:border-violet-600 dark:text-violet-300\",\n purple: \"border border-purple-300 text-purple-700 dark:border-purple-600 dark:text-purple-300\",\n fuchsia: \"border border-fuchsia-300 text-fuchsia-700 dark:border-fuchsia-600 dark:text-fuchsia-300\",\n pink: \"border border-pink-300 text-pink-700 dark:border-pink-600 dark:text-pink-300\",\n rose: \"border border-rose-300 text-rose-700 dark:border-rose-600 dark:text-rose-300\",\n};\n\nexport const badgeSoft: Record<Color, string> = {\n // The host's colour, from CSS variables -- no dark: variant, because a\n // host that themes per mode scopes the variables themselves.\n brand: \"bg-brand/10 text-brand\",\n slate: \"bg-slate-100 text-slate-700 dark:bg-slate-900/30 dark:text-slate-300\",\n gray: \"bg-gray-100 text-gray-700 dark:bg-gray-900/30 dark:text-gray-300\",\n zinc: \"bg-zinc-100 text-zinc-700 dark:bg-zinc-900/30 dark:text-zinc-300\",\n neutral: \"bg-neutral-100 text-neutral-700 dark:bg-neutral-900/30 dark:text-neutral-300\",\n stone: \"bg-stone-100 text-stone-700 dark:bg-stone-900/30 dark:text-stone-300\",\n red: \"bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300\",\n orange: \"bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300\",\n amber: \"bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300\",\n yellow: \"bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300\",\n lime: \"bg-lime-100 text-lime-700 dark:bg-lime-900/30 dark:text-lime-300\",\n green: \"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300\",\n emerald: \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300\",\n teal: \"bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-300\",\n cyan: \"bg-cyan-100 text-cyan-700 dark:bg-cyan-900/30 dark:text-cyan-300\",\n sky: \"bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300\",\n blue: \"bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300\",\n indigo: \"bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300\",\n violet: \"bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300\",\n purple: \"bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300\",\n fuchsia: \"bg-fuchsia-100 text-fuchsia-700 dark:bg-fuchsia-900/30 dark:text-fuchsia-300\",\n pink: \"bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-300\",\n rose: \"bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-300\",\n};\n\nexport const badgeDot: Record<Color, string> = {\n // The host's colour, from CSS variables -- no dark: variant, because a\n // host that themes per mode scopes the variables themselves.\n brand: \"bg-brand\",\n slate: \"bg-slate-500\",\n gray: \"bg-gray-500\",\n zinc: \"bg-zinc-500\",\n neutral: \"bg-neutral-500\",\n stone: \"bg-stone-500\",\n red: \"bg-red-500\",\n orange: \"bg-orange-500\",\n amber: \"bg-amber-500\",\n yellow: \"bg-yellow-500\",\n lime: \"bg-lime-500\",\n green: \"bg-green-500\",\n emerald: \"bg-emerald-500\",\n teal: \"bg-teal-500\",\n cyan: \"bg-cyan-500\",\n sky: \"bg-sky-500\",\n blue: \"bg-blue-500\",\n indigo: \"bg-indigo-500\",\n violet: \"bg-violet-500\",\n purple: \"bg-purple-500\",\n fuchsia: \"bg-fuchsia-500\",\n pink: \"bg-pink-500\",\n rose: \"bg-rose-500\",\n};\n","import { forwardRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { BadgeProps } from \"./Badge.types\";\nimport { badgeSolid, badgeOutline, badgeSoft, badgeDot } from \"./Badge.colors\";\n\ntype BadgeVariant = NonNullable<BadgeProps[\"variant\"]>;\ntype BadgeSize = NonNullable<BadgeProps[\"size\"]>;\n\n// Full Tailwind v4 palette — see Badge.colors.ts (generated literal class maps).\nconst variantMap: Record<BadgeVariant, typeof badgeSoft> = {\n solid: badgeSolid,\n outline: badgeOutline,\n soft: badgeSoft,\n};\n\nconst sizeClasses: Record<BadgeSize, string> = {\n sm: \"text-xs px-1.5 py-0.5\",\n md: \"text-sm px-2 py-0.5\",\n lg: \"text-base px-2.5 py-1\",\n};\n\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n color = \"zinc\",\n variant = \"soft\",\n size = \"md\",\n dot = false,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n return (\n <span\n ref={ref}\n data-react-fancy-badge=\"\"\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full font-medium\",\n sizeClasses[size],\n variantMap[variant][color],\n className,\n )}\n {...props}\n >\n {dot && (\n <span\n className={cn(\n \"inline-block h-1.5 w-1.5 rounded-full\",\n badgeDot[color],\n )}\n />\n )}\n {children}\n </span>\n );\n },\n);\n\nBadge.displayName = \"Badge\";\n"]}