@particle-academy/react-fancy 6.9.0 → 6.11.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 (148) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -0
  3. package/dist/autocomplete.cjs +3 -3
  4. package/dist/autocomplete.js +2 -2
  5. package/dist/{chunk-ZUJVGHFW.js → chunk-24RWB7Q3.js} +3 -3
  6. package/dist/{chunk-ZUJVGHFW.js.map → chunk-24RWB7Q3.js.map} +1 -1
  7. package/dist/{chunk-GEQKNV7E.js → chunk-26GRLVCQ.js} +17 -13
  8. package/dist/chunk-26GRLVCQ.js.map +1 -0
  9. package/dist/{chunk-GODJVIIO.js → chunk-3W6BKQVZ.js} +4 -4
  10. package/dist/{chunk-GODJVIIO.js.map → chunk-3W6BKQVZ.js.map} +1 -1
  11. package/dist/{chunk-AZ5DWOQY.cjs → chunk-6B43ARGW.cjs} +4 -4
  12. package/dist/{chunk-AZ5DWOQY.cjs.map → chunk-6B43ARGW.cjs.map} +1 -1
  13. package/dist/{chunk-Q62RDKRA.cjs → chunk-7N7XVBH7.cjs} +6 -6
  14. package/dist/{chunk-Q62RDKRA.cjs.map → chunk-7N7XVBH7.cjs.map} +1 -1
  15. package/dist/{chunk-VGUAIFGE.js → chunk-C2VGO375.js} +3 -3
  16. package/dist/{chunk-VGUAIFGE.js.map → chunk-C2VGO375.js.map} +1 -1
  17. package/dist/{chunk-H7OTLGRD.cjs → chunk-DQWAG7YY.cjs} +4 -4
  18. package/dist/{chunk-H7OTLGRD.cjs.map → chunk-DQWAG7YY.cjs.map} +1 -1
  19. package/dist/{chunk-3KJN3GTB.cjs → chunk-EDIB6V6Y.cjs} +4 -4
  20. package/dist/{chunk-3KJN3GTB.cjs.map → chunk-EDIB6V6Y.cjs.map} +1 -1
  21. package/dist/{chunk-G5MDMQVQ.cjs → chunk-EEFU5BVM.cjs} +6 -6
  22. package/dist/{chunk-G5MDMQVQ.cjs.map → chunk-EEFU5BVM.cjs.map} +1 -1
  23. package/dist/{chunk-IYG436ZY.js → chunk-EW2N52FD.js} +3 -3
  24. package/dist/{chunk-IYG436ZY.js.map → chunk-EW2N52FD.js.map} +1 -1
  25. package/dist/{chunk-RSB2P3JK.js → chunk-FECD3WKN.js} +3 -3
  26. package/dist/{chunk-RSB2P3JK.js.map → chunk-FECD3WKN.js.map} +1 -1
  27. package/dist/{chunk-6RXEWM3V.js → chunk-FNHKZMMI.js} +3 -3
  28. package/dist/{chunk-6RXEWM3V.js.map → chunk-FNHKZMMI.js.map} +1 -1
  29. package/dist/{chunk-M5ER3Y5I.cjs → chunk-FR3V5IAJ.cjs} +4 -4
  30. package/dist/{chunk-M5ER3Y5I.cjs.map → chunk-FR3V5IAJ.cjs.map} +1 -1
  31. package/dist/{chunk-DXLPBLNC.cjs → chunk-FSLEFL4U.cjs} +4 -4
  32. package/dist/{chunk-DXLPBLNC.cjs.map → chunk-FSLEFL4U.cjs.map} +1 -1
  33. package/dist/{chunk-FQCLJZZS.js → chunk-FX37P4KR.js} +3 -3
  34. package/dist/{chunk-FQCLJZZS.js.map → chunk-FX37P4KR.js.map} +1 -1
  35. package/dist/{chunk-HANQYZW2.cjs → chunk-GB2EGMVQ.cjs} +16 -12
  36. package/dist/chunk-GB2EGMVQ.cjs.map +1 -0
  37. package/dist/{chunk-DW2PHLOA.js → chunk-H5LJFN7D.js} +3 -3
  38. package/dist/{chunk-DW2PHLOA.js.map → chunk-H5LJFN7D.js.map} +1 -1
  39. package/dist/{chunk-F3U4AVGF.js → chunk-HCIEXBEB.js} +3 -3
  40. package/dist/{chunk-F3U4AVGF.js.map → chunk-HCIEXBEB.js.map} +1 -1
  41. package/dist/{chunk-QAM6N3VG.cjs → chunk-HEGM5LMZ.cjs} +4 -4
  42. package/dist/{chunk-QAM6N3VG.cjs.map → chunk-HEGM5LMZ.cjs.map} +1 -1
  43. package/dist/chunk-HHCVBIMM.js +21 -0
  44. package/dist/chunk-HHCVBIMM.js.map +1 -0
  45. package/dist/{chunk-KAKKZDCE.js → chunk-J57JSHDC.js} +3 -3
  46. package/dist/{chunk-KAKKZDCE.js.map → chunk-J57JSHDC.js.map} +1 -1
  47. package/dist/{chunk-ZBXJDQXN.js → chunk-JJYMRV62.js} +17 -13
  48. package/dist/chunk-JJYMRV62.js.map +1 -0
  49. package/dist/{chunk-6BCXGP2T.js → chunk-JN5DHZ6I.js} +3 -3
  50. package/dist/{chunk-6BCXGP2T.js.map → chunk-JN5DHZ6I.js.map} +1 -1
  51. package/dist/{chunk-R6O6SLXK.js → chunk-LG2O26CG.js} +13 -8
  52. package/dist/chunk-LG2O26CG.js.map +1 -0
  53. package/dist/chunk-LJCQI6ZS.js +1212 -0
  54. package/dist/chunk-LJCQI6ZS.js.map +1 -0
  55. package/dist/{chunk-JV2HEOCB.cjs → chunk-MAY4NMRI.cjs} +4 -4
  56. package/dist/{chunk-JV2HEOCB.cjs.map → chunk-MAY4NMRI.cjs.map} +1 -1
  57. package/dist/{chunk-BQENLOEV.js → chunk-MD7HUHJB.js} +4 -4
  58. package/dist/{chunk-BQENLOEV.js.map → chunk-MD7HUHJB.js.map} +1 -1
  59. package/dist/{chunk-5U2DZ7AV.js → chunk-MUV7OK3W.js} +8 -6
  60. package/dist/chunk-MUV7OK3W.js.map +1 -0
  61. package/dist/{chunk-EC4ZYZNK.cjs → chunk-NFUKNVB7.cjs} +13 -8
  62. package/dist/chunk-NFUKNVB7.cjs.map +1 -0
  63. package/dist/{chunk-QUZOGRZS.js → chunk-OE4AIUAN.js} +3 -3
  64. package/dist/{chunk-QUZOGRZS.js.map → chunk-OE4AIUAN.js.map} +1 -1
  65. package/dist/chunk-OP7A4SZZ.cjs +1216 -0
  66. package/dist/chunk-OP7A4SZZ.cjs.map +1 -0
  67. package/dist/{chunk-YBBBX5H2.cjs → chunk-OUPHLIXV.cjs} +11 -11
  68. package/dist/{chunk-YBBBX5H2.cjs.map → chunk-OUPHLIXV.cjs.map} +1 -1
  69. package/dist/{chunk-XGGAAG74.cjs → chunk-QQKWI7QP.cjs} +7 -3
  70. package/dist/chunk-QQKWI7QP.cjs.map +1 -0
  71. package/dist/{chunk-XT4WBBCD.cjs → chunk-R4SANV3G.cjs} +11 -11
  72. package/dist/{chunk-XT4WBBCD.cjs.map → chunk-R4SANV3G.cjs.map} +1 -1
  73. package/dist/chunk-RE3PMG47.cjs +23 -0
  74. package/dist/chunk-RE3PMG47.cjs.map +1 -0
  75. package/dist/{chunk-GJWNZMJT.js → chunk-RUEDMYBF.js} +7 -3
  76. package/dist/chunk-RUEDMYBF.js.map +1 -0
  77. package/dist/{chunk-UORN3Z7R.cjs → chunk-TBLKVTJC.cjs} +6 -6
  78. package/dist/{chunk-UORN3Z7R.cjs.map → chunk-TBLKVTJC.cjs.map} +1 -1
  79. package/dist/{chunk-7NRG77U5.cjs → chunk-TXQT6S4D.cjs} +16 -12
  80. package/dist/chunk-TXQT6S4D.cjs.map +1 -0
  81. package/dist/{chunk-TXTRTTG7.cjs → chunk-UOG3O3KP.cjs} +8 -6
  82. package/dist/chunk-UOG3O3KP.cjs.map +1 -0
  83. package/dist/{chunk-L5NDZEL6.cjs → chunk-ZFXCZ2QO.cjs} +9 -9
  84. package/dist/{chunk-L5NDZEL6.cjs.map → chunk-ZFXCZ2QO.cjs.map} +1 -1
  85. package/dist/command.cjs +5 -4
  86. package/dist/command.js +3 -2
  87. package/dist/composer.cjs +6 -6
  88. package/dist/composer.js +4 -4
  89. package/dist/drawer.cjs +5 -4
  90. package/dist/drawer.d.cts +8 -1
  91. package/dist/drawer.d.ts +8 -1
  92. package/dist/drawer.js +3 -2
  93. package/dist/dropdown.cjs +4 -4
  94. package/dist/dropdown.js +2 -2
  95. package/dist/editor.cjs +2 -2
  96. package/dist/editor.js +2 -2
  97. package/dist/index.cjs +111 -97
  98. package/dist/index.cjs.map +1 -1
  99. package/dist/index.d.cts +13 -1
  100. package/dist/index.d.ts +13 -1
  101. package/dist/index.js +27 -25
  102. package/dist/index.js.map +1 -1
  103. package/dist/input.cjs +5 -5
  104. package/dist/input.js +4 -4
  105. package/dist/inputs.cjs +19 -19
  106. package/dist/inputs.js +8 -8
  107. package/dist/json-editor.cjs +17 -17
  108. package/dist/json-editor.js +6 -6
  109. package/dist/mobile-menu.cjs +2 -2
  110. package/dist/mobile-menu.js +2 -2
  111. package/dist/modal.cjs +5 -4
  112. package/dist/modal.d.cts +11 -1
  113. package/dist/modal.d.ts +11 -1
  114. package/dist/modal.js +3 -2
  115. package/dist/number-field.cjs +6 -6
  116. package/dist/number-field.js +5 -5
  117. package/dist/paste-pills.cjs +16 -16
  118. package/dist/paste-pills.js +3 -3
  119. package/dist/phone-input.cjs +39 -0
  120. package/dist/phone-input.cjs.map +1 -0
  121. package/dist/phone-input.d.cts +139 -0
  122. package/dist/phone-input.d.ts +139 -0
  123. package/dist/phone-input.js +22 -0
  124. package/dist/phone-input.js.map +1 -0
  125. package/dist/popover.cjs +4 -4
  126. package/dist/popover.js +2 -2
  127. package/dist/prompt-input.cjs +8 -8
  128. package/dist/prompt-input.js +5 -5
  129. package/dist/reason-tag.cjs +4 -4
  130. package/dist/reason-tag.js +3 -3
  131. package/dist/select.cjs +3 -3
  132. package/dist/select.js +2 -2
  133. package/dist/sidebar.cjs +6 -6
  134. package/dist/sidebar.js +4 -4
  135. package/dist/tooltip.cjs +3 -3
  136. package/dist/tooltip.js +2 -2
  137. package/docs/PhoneInput.md +104 -0
  138. package/package.json +11 -1
  139. package/dist/chunk-5U2DZ7AV.js.map +0 -1
  140. package/dist/chunk-7NRG77U5.cjs.map +0 -1
  141. package/dist/chunk-EC4ZYZNK.cjs.map +0 -1
  142. package/dist/chunk-GEQKNV7E.js.map +0 -1
  143. package/dist/chunk-GJWNZMJT.js.map +0 -1
  144. package/dist/chunk-HANQYZW2.cjs.map +0 -1
  145. package/dist/chunk-R6O6SLXK.js.map +0 -1
  146. package/dist/chunk-TXTRTTG7.cjs.map +0 -1
  147. package/dist/chunk-XGGAAG74.cjs.map +0 -1
  148. package/dist/chunk-ZBXJDQXN.js.map +0 -1
package/dist/sidebar.js CHANGED
@@ -1,13 +1,13 @@
1
- export { Sidebar, useSidebar } from './chunk-FQCLJZZS.js';
2
- import './chunk-QUZOGRZS.js';
1
+ export { Sidebar, useSidebar } from './chunk-FX37P4KR.js';
2
+ import './chunk-OE4AIUAN.js';
3
3
  import './chunk-SV5BW3IA.js';
4
4
  import './chunk-2BXMMVQS.js';
5
5
  import './chunk-CPY7NHXM.js';
6
6
  import './chunk-ZQ3VXRUY.js';
7
- import './chunk-5U2DZ7AV.js';
7
+ import './chunk-MUV7OK3W.js';
8
8
  import './chunk-3K2CEAI7.js';
9
9
  import './chunk-5VMILVWD.js';
10
- import './chunk-GJWNZMJT.js';
10
+ import './chunk-RUEDMYBF.js';
11
11
  import './chunk-US5R36TQ.js';
12
12
  import './chunk-RBCMKPBX.js';
13
13
  import './chunk-S53A6JIE.js';
package/dist/tooltip.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkAZ5DWOQY_cjs = require('./chunk-AZ5DWOQY.cjs');
3
+ var chunk6B43ARGW_cjs = require('./chunk-6B43ARGW.cjs');
4
4
  require('./chunk-I27K6NLX.cjs');
5
5
  require('./chunk-MKHYENKR.cjs');
6
- require('./chunk-XGGAAG74.cjs');
6
+ require('./chunk-QQKWI7QP.cjs');
7
7
  require('./chunk-36IC3NDN.cjs');
8
8
  require('./chunk-TI7D4QDM.cjs');
9
9
  require('./chunk-OUYC6EIL.cjs');
@@ -13,7 +13,7 @@ require('./chunk-ZU5Q77OT.cjs');
13
13
 
14
14
  Object.defineProperty(exports, "Tooltip", {
15
15
  enumerable: true,
16
- get: function () { return chunkAZ5DWOQY_cjs.Tooltip; }
16
+ get: function () { return chunk6B43ARGW_cjs.Tooltip; }
17
17
  });
18
18
  //# sourceMappingURL=tooltip.cjs.map
19
19
  //# sourceMappingURL=tooltip.cjs.map
package/dist/tooltip.js CHANGED
@@ -1,7 +1,7 @@
1
- export { Tooltip } from './chunk-QUZOGRZS.js';
1
+ export { Tooltip } from './chunk-OE4AIUAN.js';
2
2
  import './chunk-SV5BW3IA.js';
3
3
  import './chunk-5VMILVWD.js';
4
- import './chunk-GJWNZMJT.js';
4
+ import './chunk-RUEDMYBF.js';
5
5
  import './chunk-US5R36TQ.js';
6
6
  import './chunk-RBCMKPBX.js';
7
7
  import './chunk-YX6FTJ6N.js';
@@ -0,0 +1,104 @@
1
+ # PhoneInput
2
+
3
+ A country picker and a number field whose value is an E.164 number (`+95945123456`) or `null`. Blank is `null`, half-typed text is `null` with a reason, and pasting a full international number picks its country.
4
+
5
+ It is a **light** phone field: a first-party table of dial codes and national-number lengths, and no phone-number library or data. **The length check is a sanity check, not validation.** It catches a number that is plainly too short or too long for its country; it does not know which ranges are allocated, whether a number is mobile, or whether anyone holds it. Validate on your server (Twilio Lookup, for example) before you rely on a number.
6
+
7
+ **`detail.valid` means plausible, not valid.** Real per-country lengths apply only to the rows whose lengths were checked against a cited plan: Benin, Côte d'Ivoire, Colombia, Gabon, Kazakhstan, Lithuania, Myanmar, Saint Helena and Mayotte (`PHONE_COUNTRIES[i].lengthVerified`). Every other country accepts 4 to 15 digits including its dial code, the widest E.164 allows, so there the check is digits, a known dial code and the E.164 maximum. That is deliberate: a range that is too tight would refuse a real person's number and block their form, while a wrong number accepted here is caught by your server.
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { PhoneInput } from "@particle-academy/react-fancy";
13
+ // or the subpath
14
+ import { PhoneInput } from "@particle-academy/react-fancy/phone-input";
15
+ ```
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ const [phone, setPhone] = useState<string | null>(null);
21
+
22
+ <PhoneInput label="Mobile number" value={phone} onValueChange={setPhone} defaultCountry="MM" />
23
+ ```
24
+
25
+ ## Props
26
+
27
+ | Prop | Type | Default | Description |
28
+ |------|------|---------|-------------|
29
+ | `value` | `string \| null` | - | The number in E.164, or `null` |
30
+ | `defaultValue` | `string \| null` | `null` | Starting value when uncontrolled |
31
+ | `onValueChange` | `(value: string \| null, detail: PhoneInputDetail) => void` | - | Called when the value or the reading of it changes |
32
+ | `label` | `string` | required | Visible label for the number |
33
+ | `defaultCountry` | `string` | - | ISO 3166-1 alpha-2 selected at first. Also the tie-break for a shared dial code |
34
+ | `countries` | `string[]` | every country, by name | Restrict the picker to these ISO codes, in this order |
35
+ | `locale` | `string` | the browser's | BCP 47 locale for country names. Pass it when you render on the server, or the names can differ between server and browser |
36
+ | `description` | `string` | - | Help text, tied to the number with `aria-describedby` |
37
+ | `error` | `string` | - | Your own message, shown instead of the built-in one |
38
+ | `messages` | `PhoneInputMessages` | English | Every piece of text the component shows, for a host working in another language |
39
+ | `name` | `string` | - | Posts the E.164 (or `""`) through a hidden input, never the text on screen |
40
+ | `required`, `disabled`, `placeholder`, `autoFocus`, `id`, `form`, `className`, `onBlur` | | | As usual. `id` is the number input's |
41
+
42
+ ## What `detail` reports
43
+
44
+ ```ts
45
+ {
46
+ country: "MM", // ISO code the number was read in, or null
47
+ dialCode: "95", // or null
48
+ nationalNumber: "945123456", // digits only, no trunk prefix
49
+ valid: true,
50
+ reason: null, // "too_short" | "too_long" | "invalid_chars" | "unknown_country" | null
51
+ approximate: false, // true when the dial code is shared and country is a guess
52
+ }
53
+ ```
54
+
55
+ ## What it does with what you type
56
+
57
+ | Typed (country MM) | `value` | `reason` |
58
+ |---|---|---|
59
+ | (blank) | `null` | `null`: blank is not an error. Use `required` |
60
+ | `09 45` | `null` | `too_short` |
61
+ | `09 4512 3456` | `+95945123456` | `null`. The trunk prefix 0 is dropped |
62
+ | `+959 4512 3456`, `00959 4512 3456`, `+95 (9) 4512-3456` | `+95945123456` | `null`. The country follows the dial code |
63
+ | `+44 (0)20 7946 0958` | `+442079460958` | `null`. A `(0)` inside an international number is dropped |
64
+ | `09 45ab` | `null` | `invalid_chars`. Letters are never read past |
65
+ | `+999 1234` | `null` | `unknown_country` |
66
+ | `4512 3456` with no country chosen | `null` | `unknown_country` |
67
+
68
+ Digits in Arabic-Indic, Persian, Devanagari, Bengali, Thai, Myanmar and fullwidth forms are read as digits, and the invisible direction marks a right-to-left page wraps around copied text are ignored. Only `+` and `00` start an international number: other international prefixes (`011` in North America, `010` in Japan) are not recognised.
69
+
70
+ **Partial input.** Nothing below a country's shortest length is ever emitted, so in a verified fixed-length plan (Colombia, Côte d'Ivoire) a half-typed number is always `null`. In an unverified row the shortest length is 4 digits, so a half-typed number of 4 digits or more is emitted. Where a plan has numbers of different lengths (Myanmar runs 7 to 10 digits), a prefix of a long number can itself be a valid length, and is emitted: a length check cannot tell "still typing" from "done". Use `detail` and your server for that.
71
+
72
+ **When messages show.** `invalid_chars` and `too_long` show at once, because typing more cannot fix them. `too_short` and `unknown_country` show when focus leaves the field, and clear while you type again. The message is the readable sentence for the reason, in `messages` if you pass them; `{country}` is replaced with the country's name. Every reason also reaches `setCustomValidity`, so a native form submit is blocked while the number is not whole.
73
+
74
+ ## Shared dial codes
75
+
76
+ `+1` (the North American Numbering Plan), `+7`, `+39`, `+44`, `+47`, `+61`, `+212`, `+262`, `+358`, `+590` and `+599` belong to more than one country. The country is chosen in this order, and **is approximate** (`detail.approximate` is `true`):
77
+
78
+ 1. The number's leading digits, where a short first-party table knows them: Canadian and Caribbean area codes under `+1`, Kazakhstan's `6` and `7` under `+7`, the Crown Dependencies' fixed-line codes under `+44`, Svalbard, Cocos and Christmas Islands, Mayotte, Aland, Vatican City and the Caribbean Netherlands.
79
+ 2. The selected country (or `defaultCountry`), if it shares the code.
80
+ 3. The main country for the code: `+1` is the United States, `+7` Russia, `+44` the United Kingdom.
81
+
82
+ The E.164 is exact whichever country is chosen; only `detail.country` and the flag can be wrong, for instance for a ported number. A new Canadian area code reads as the United States until it is added to the table.
83
+
84
+ ## Country picker
85
+
86
+ A button showing the flag and dial code, named for assistive tech as "Country: Myanmar (+95)". It opens a searchable list: type a name in the page's language, an ISO code (`mm`) or a dial code (`+95`). ArrowDown / ArrowUp move through the list, PageDown / PageUp by ten, Enter picks (the first match if nothing is highlighted), Escape closes and returns to the button, and Tab returns to the number. ArrowDown on the closed button opens it. Picking a country while the number starts with `+` re-reads it as a national number in that country.
87
+
88
+ Names come from `Intl.DisplayNames` in `locale`. Flags are Unicode regional-indicator letters, not images: Windows does not draw them as flags and shows the two letters instead, which is still the country code.
89
+
90
+ ## Right-to-left
91
+
92
+ The number input has `dir="ltr"`, so the `+` and the digits keep their order inside a right-to-left page, isolated from the text around them, and the digits align to the page's inline start (the right, in RTL). Chromium already lays a `type="tel"` input out left-to-right; the attribute is what isolates it, and is the part the HTML standard specifies rather than a browser default. Only Chromium was checked. The dial codes in the picker and list are isolated left-to-right too. The label, the picker and the list follow the page: under `dir="rtl"` the picker sits on the right. Arrow keys inside the number move the caret the way they point.
93
+
94
+ ## Accessibility
95
+
96
+ A visible label is required. The description and the message are tied to the number with `aria-describedby`, `aria-invalid` is set while a message shows, and the message is announced politely. The picker, its search box and the list each have an accessible name, the list uses `aria-activedescendant`, and every target is at least 44 by 44 CSS pixels. The message and description text measured 8.4:1 and 10.4:1 against the default white surface in Chromium; check your own theme, and dark mode, against 7:1.
97
+
98
+ ## Agents
99
+
100
+ The component is controlled, so an agent writes `value` as an E.164 string and the text and picker follow: the input shows the national number and the picker its country. `detail` is plain JSON. Handles: `[data-react-fancy-phone-input]` (with `data-country`, `data-valid` and `data-reason`), `-country`, `-number`, `-error`, `-search`, `-listbox` and `-option` (VALUE is the ISO code). `parsePhone(text, { country, countries })` is exported, so an agent or a server-side render can read a number the same way the field does, and `PHONE_COUNTRIES` is the table itself.
101
+
102
+ ## Data
103
+
104
+ `src/components/PhoneInput/phone-countries.ts` holds one row per country: ISO code, dial code, shortest and longest national number, trunk prefixes and a `VERIFIED` / `UNVERIFIED` status, each with its source in a comment. Dial codes come from the ITU-T E.164 list of assigned country codes. A `VERIFIED` row's length was checked against the country's numbering plan as cited in its comment. An `UNVERIFIED` row's length is the E.164 maximum, and its comment keeps the range that was transcribed from memory. To verify one: check it against the plan, put the range in, mark it `VERIFIED`, and cite the source. A test holds every unverified row at the E.164 maximum, so a narrowed range without a status change fails the build.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/react-fancy",
3
- "version": "6.9.0",
3
+ "version": "6.11.0",
4
4
  "description": "React UI component library for Human+ UX — controlled, agent-bridgeable primitives",
5
5
  "repository": {
6
6
  "type": "git",
@@ -693,6 +693,16 @@
693
693
  "default": "./dist/pdf-viewer.cjs"
694
694
  }
695
695
  },
696
+ "./phone-input": {
697
+ "import": {
698
+ "types": "./dist/phone-input.d.ts",
699
+ "default": "./dist/phone-input.js"
700
+ },
701
+ "require": {
702
+ "types": "./dist/phone-input.d.cts",
703
+ "default": "./dist/phone-input.cjs"
704
+ }
705
+ },
696
706
  "./pillbox": {
697
707
  "import": {
698
708
  "types": "./dist/pillbox.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-focus-trap.ts"],"names":[],"mappings":";;;AAEA,IAAM,kBAAA,GAAqB;AAAA,EACzB,SAAA;AAAA,EACA,wBAAA;AAAA,EACA,uBAAA;AAAA,EACA,0BAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,IAAI,CAAA;AAEJ,SAAS,YAAA,CACd,GAAA,EACA,OAAA,GAAmB,IAAA,EACb;AACN,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,MAAM,KAAK,GAAA,CAAI,OAAA;AACf,IAAA,IAAI,CAAC,EAAA,EAAI;AAET,IAAA,MAAM,oBAAoB,QAAA,CAAS,aAAA;AAEnC,IAAA,MAAM,aAAa,MACjB,KAAA,CAAM,KAAK,EAAA,CAAG,gBAAA,CAA8B,kBAAkB,CAAC,CAAA;AAGjE,IAAA,MAAM,KAAA,GAAQ,UAAA,EAAW,CAAE,CAAC,CAAA;AAC5B,IAAA,KAAA,EAAO,KAAA,EAAM;AAEb,IAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAyB;AACzC,MAAA,IAAI,KAAA,CAAM,QAAQ,KAAA,EAAO;AAEzB,MAAA,MAAM,QAAQ,UAAA,EAAW;AACzB,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAExB,MAAA,MAAM,SAAA,GAAY,MAAM,CAAC,CAAA;AACzB,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AAEvC,MAAA,IAAI,MAAM,QAAA,EAAU;AAClB,QAAA,IAAI,QAAA,CAAS,kBAAkB,SAAA,EAAW;AACxC,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,QAAA,CAAS,KAAA,EAAM;AAAA,QACjB;AAAA,MACF,CAAA,MAAO;AACL,QAAA,IAAI,QAAA,CAAS,kBAAkB,QAAA,EAAU;AACvC,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,SAAA,CAAU,KAAA,EAAM;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,gBAAA,CAAiB,WAAW,QAAQ,CAAA;AAEvC,IAAA,OAAO,MAAM;AACX,MAAA,EAAA,CAAG,mBAAA,CAAoB,WAAW,QAAQ,CAAA;AAC1C,MAAA,iBAAA,EAAmB,KAAA,EAAM;AAAA,IAC3B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAA,EAAK,OAAO,CAAC,CAAA;AACnB","file":"chunk-5U2DZ7AV.js","sourcesContent":["import { useEffect, type RefObject } from \"react\";\n\nconst FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\nexport function useFocusTrap(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean = true,\n): void {\n useEffect(() => {\n if (!enabled) return;\n\n const el = ref.current;\n if (!el) return;\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n\n const focusables = () =>\n Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n\n // Focus first focusable element\n const first = focusables()[0];\n first?.focus();\n\n const listener = (event: KeyboardEvent) => {\n if (event.key !== \"Tab\") return;\n\n const items = focusables();\n if (items.length === 0) return;\n\n const firstItem = items[0];\n const lastItem = items[items.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstItem) {\n event.preventDefault();\n lastItem.focus();\n }\n } else {\n if (document.activeElement === lastItem) {\n event.preventDefault();\n firstItem.focus();\n }\n }\n };\n\n el.addEventListener(\"keydown\", listener);\n\n return () => {\n el.removeEventListener(\"keydown\", listener);\n previouslyFocused?.focus();\n };\n }, [ref, enabled]);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Drawer/Drawer.context.ts","../src/components/Drawer/DrawerHeader.tsx","../src/components/Drawer/DrawerBody.tsx","../src/components/Drawer/DrawerFooter.tsx","../src/components/Drawer/DrawerContainer.tsx","../src/components/Drawer/Drawer.tsx"],"names":["createContext","useContext","jsxs","cn","jsx","X","useRef","useCallback","useEscapeKey","useFocusTrap","useEffect","useAnimation","useMemo","Portal"],"mappings":"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","file":"chunk-7NRG77U5.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { DrawerContextValue } from \"./Drawer.types\";\n\nexport const DrawerContext = createContext<DrawerContextValue | null>(null);\n\nexport function useDrawer(): DrawerContextValue {\n const ctx = useContext(DrawerContext);\n if (!ctx) {\n throw new Error(\"Drawer compound components must be used within <Drawer>\");\n }\n return ctx;\n}\n","import { X } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useDrawer } from \"./Drawer.context\";\nimport type { DrawerHeaderProps } from \"./Drawer.types\";\n\nexport function DrawerHeader({ children, closable = true, className }: DrawerHeaderProps) {\n const { close } = useDrawer();\n\n return (\n <div\n data-react-fancy-drawer-header=\"\"\n className={cn(\n \"flex shrink-0 items-center justify-between border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 py-3 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n <div className=\"text-sm font-semibold text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{children}</div>\n {closable ? (\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-lg p-1 text-zinc-400 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:text-zinc-600 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:hover:text-zinc-300\"\n aria-label=\"Close\"\n >\n <X size={18} />\n </button>\n ) : null}\n </div>\n );\n}\n\nDrawerHeader.displayName = \"DrawerHeader\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerBodyProps } from \"./Drawer.types\";\n\nexport function DrawerBody({ children, className }: DrawerBodyProps) {\n return (\n <div\n data-react-fancy-drawer-body=\"\"\n className={cn(\"min-h-0 flex-1 overflow-auto px-4 py-3 text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\", className)}\n >\n {children}\n </div>\n );\n}\n\nDrawerBody.displayName = \"DrawerBody\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerFooterProps } from \"./Drawer.types\";\n\nexport function DrawerFooter({ children, className }: DrawerFooterProps) {\n return (\n <div\n data-react-fancy-drawer-footer=\"\"\n className={cn(\n \"flex shrink-0 items-center justify-end gap-2 border-t border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 py-3 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nDrawerFooter.displayName = \"DrawerFooter\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerContainerProps } from \"./Drawer.types\";\n\n/**\n * The anchor for `<Drawer attach=\"container\">`.\n *\n * A container-attached drawer positions itself `absolute`, which resolves\n * against the nearest *positioned* ancestor — so without `relative` somewhere\n * above it, the drawer silently escapes to the viewport and looks like it\n * ignored `attach` entirely. This wrapper supplies `relative` + `overflow-hidden`\n * so the panel slides within the box rather than out of it.\n *\n * <Drawer.Container className=\"h-80 rounded-xl border\">\n * <YourContent />\n * <Drawer attach=\"container\" side=\"bottom\" open={open} onClose={close}>\n * <Drawer.Body>Filters</Drawer.Body>\n * </Drawer>\n * </Drawer.Container>\n *\n * Any element works as long as it is positioned — this is the shortcut, not a\n * requirement. Wrapping a Card, a layout pane, or a prompt-input shell in\n * `relative overflow-hidden` does the same job.\n */\nexport function DrawerContainer({ children, className, ...rest }: DrawerContainerProps) {\n return (\n <div\n data-react-fancy-drawer-container=\"\"\n {...rest}\n className={cn(\"relative overflow-hidden\", className)}\n >\n {children}\n </div>\n );\n}\n\nDrawerContainer.displayName = \"DrawerContainer\";\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { DrawerContext } from \"./Drawer.context\";\nimport { DrawerHeader } from \"./DrawerHeader\";\nimport { DrawerBody } from \"./DrawerBody\";\nimport { DrawerFooter } from \"./DrawerFooter\";\nimport { DrawerContainer } from \"./DrawerContainer\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport type { DrawerProps, DrawerSide } from \"./Drawer.types\";\n\n/**\n * `size` addresses the drawer's own axis: width on the horizontal edges,\n * height on the vertical ones. Keeping one scale across both means `size=\"lg\"`\n * does not have to be re-learned when a drawer moves from the side to the\n * bottom.\n */\nconst WIDTH = {\n sm: \"w-64\",\n md: \"w-80\",\n lg: \"w-96\",\n xl: \"w-[32rem]\",\n full: \"w-full\",\n} as const;\n\nconst HEIGHT = {\n sm: \"h-32\",\n md: \"h-64\",\n lg: \"h-96\",\n xl: \"h-[32rem]\",\n full: \"h-full\",\n} as const;\n\nconst ANCHOR: Record<DrawerSide, string> = {\n start: \"inset-y-0 start-0\",\n end: \"inset-y-0 end-0\",\n left: \"inset-y-0 left-0\",\n right: \"inset-y-0 right-0\",\n top: \"inset-x-0 top-0\",\n bottom: \"inset-x-0 bottom-0\",\n};\n\nconst ENTER: Record<DrawerSide, string> = {\n start: \"fancy-slide-in-start\",\n end: \"fancy-slide-in-end\",\n left: \"fancy-slide-in-left\",\n right: \"fancy-slide-in-right\",\n top: \"fancy-slide-in-top\",\n bottom: \"fancy-slide-in-bottom\",\n};\n\nconst EXIT: Record<DrawerSide, string> = {\n start: \"fancy-slide-out-start\",\n end: \"fancy-slide-out-end\",\n left: \"fancy-slide-out-left\",\n right: \"fancy-slide-out-right\",\n top: \"fancy-slide-out-top\",\n bottom: \"fancy-slide-out-bottom\",\n};\n\n/** The panel's edge shadow reads as depth away from the anchored edge. */\nconst EDGE: Record<DrawerSide, string> = {\n start: \"border-e\",\n end: \"border-s\",\n left: \"border-r\",\n right: \"border-l\",\n top: \"border-b\",\n bottom: \"border-t\",\n};\n\nfunction DrawerRoot({\n children,\n open,\n onClose,\n side = \"end\",\n size = \"md\",\n attach = \"viewport\",\n backdrop = true,\n dismissOnBackdrop = true,\n dismissOnEscape = true,\n className,\n ...rest\n}: DrawerProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const horizontal = side !== \"top\" && side !== \"bottom\";\n const isViewport = attach === \"viewport\";\n\n const close = useCallback(() => onClose(), [onClose]);\n useEscapeKey(close, open && dismissOnEscape);\n\n // A container-attached drawer is a panel, not a dialog — trapping focus in it\n // would strand keyboard users inside a Card. Only the viewport form is modal.\n useFocusTrap(panelRef, open && isViewport);\n\n useEffect(() => {\n if (!open || !isViewport) return;\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }, [open, isViewport]);\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: ENTER[side],\n exitClass: EXIT[side],\n });\n\n const ctx = useMemo(() => ({ open, close, side }), [open, close, side]);\n\n if (!mounted) return null;\n\n const frame = (\n <div\n data-react-fancy-drawer-frame=\"\"\n className={cn(isViewport ? \"fixed inset-0 z-50\" : \"absolute inset-0 z-20\", !backdrop && \"pointer-events-none\")}\n >\n {backdrop ? (\n <div\n data-react-fancy-drawer-backdrop=\"\"\n className={cn(\n \"absolute inset-0 bg-black/40 transition-opacity\",\n isViewport && \"backdrop-blur-sm\",\n open ? \"opacity-100\" : \"opacity-0\",\n )}\n onClick={dismissOnBackdrop ? close : undefined}\n aria-hidden=\"true\"\n />\n ) : null}\n\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current = node;\n }}\n data-react-fancy-drawer=\"\"\n data-side={side}\n role=\"dialog\"\n aria-modal={isViewport || undefined}\n {...rest}\n className={cn(\n \"pointer-events-auto absolute flex flex-col border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n ANCHOR[side],\n EDGE[side],\n horizontal ? WIDTH[size] : HEIGHT[size],\n // Cross-axis fills the anchor; the main axis is capped so a viewport\n // drawer can never grow past the screen on a small device.\n horizontal ? \"h-full\" : \"w-full\",\n isViewport && (horizontal ? \"max-w-[90vw]\" : \"max-h-[90vh]\"),\n !isViewport && (horizontal ? \"max-w-full\" : \"max-h-full\"),\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n );\n\n return (\n <DrawerContext.Provider value={ctx}>\n {isViewport ? <Portal>{frame}</Portal> : frame}\n </DrawerContext.Provider>\n );\n}\n\nexport const Drawer = Object.assign(DrawerRoot, {\n Header: DrawerHeader,\n Body: DrawerBody,\n Footer: DrawerFooter,\n Container: DrawerContainer,\n});\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Command/Command.context.ts","../src/components/Command/CommandInput.tsx","../src/components/Command/CommandList.tsx","../src/components/Command/CommandItem.tsx","../src/components/Command/CommandGroup.tsx","../src/components/Command/CommandEmpty.tsx","../src/components/Command/Command.tsx"],"names":["createContext","useContext","jsxs","jsx","Search","cn","useId","useControllableState","useState","useRef","useCallback","useEscapeKey","useFocusTrap","useEffect","isImeComposing","useLayoutEffect","useAnimation","useMemo","Portal"],"mappings":";;;;;;;;;;;;;AAGO,IAAM,cAAA,GAAiBA,oBAA0C,IAAI,CAAA;AAErE,SAAS,UAAA,GAAkC;AAChD,EAAA,MAAM,GAAA,GAAMC,iBAAW,cAAc,CAAA;AACrC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;ACRO,SAAS,YAAA,CAAa;AAAA,EAC3B,WAAA,GAAc,6BAAA;AAAA,EACd;AACF,CAAA,EAAsB;AACpB,EAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAU,MAAA,KAAW,UAAA,EAAW;AAE/C,EAAA,uBACEC,eAAA,CAAC,KAAA,EAAA,EAAI,gCAAA,EAA+B,EAAA,EAAG,WAAU,6JAAA,EAC/C,QAAA,EAAA;AAAA,oBAAAC,cAAA,CAACC,kBAAA,EAAA,EAAO,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,wBAAA,EAAyB,CAAA;AAAA,oBACrDD,cAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,MAAA;AAAA,QAGL,IAAA,EAAK,UAAA;AAAA,QACL,eAAA,EAAc,MAAA;AAAA,QACd,eAAA,EAAe,MAAA;AAAA,QACf,mBAAA,EAAkB,MAAA;AAAA,QAClB,KAAA,EAAO,KAAA;AAAA,QACP,UAAU,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,QACxC,WAAA;AAAA,QACA,SAAA,EAAWE,oBAAA;AAAA,UACT,gFAAA;AAAA,UACA;AAAA,SACF;AAAA,QACA,SAAA,EAAS;AAAA;AAAA;AACX,GAAA,EACF,CAAA;AAEJ;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA;AC/BpB,SAAS,WAAA,CAAY,EAAE,QAAA,EAAU,SAAA,EAAU,EAAqB;AACrE,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,UAAA,EAAW;AAE9B,EAAA,uBACEF,cAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI,MAAA;AAAA,MACJ,+BAAA,EAA8B,EAAA;AAAA,MAC9B,IAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAWE,oBAAA,CAAG,8BAAA,EAAgC,SAAS,CAAA;AAAA,MAEtD;AAAA;AAAA,GACH;AAEJ;AAEA,WAAA,CAAY,WAAA,GAAc,aAAA;ACdnB,SAAS,WAAA,CAAY;AAAA,EAC1B,QAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,YAAA,EAAc,cAAA,KAAmB,UAAA,EAAW;AAElE,EAAA,MAAM,KAAKC,WAAA,EAAM;AAGjB,EAAA,MAAM,IAAA,GAAO,KAAA,KAAU,OAAO,QAAA,KAAa,WAAW,QAAA,GAAW,EAAA,CAAA;AACjE,EAAA,IAAI,YAAA,IAAgB,KAAA,IAAS,CAAC,IAAA,CAAK,WAAA,GAAc,QAAA,CAAS,KAAA,CAAM,WAAA,EAAa,CAAA,EAAG;AAC9E,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACEH,cAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,EAAA;AAAA,MACA,+BAAA,EAA8B,EAAA;AAAA,MAC9B,IAAA,EAAK,QAAA;AAAA,MACL,IAAA,EAAK,QAAA;AAAA,MAGL,eAAA,EAAe,KAAA;AAAA,MAEf,QAAA,EAAU,EAAA;AAAA,MACV,YAAA,EAAc,CAAC,CAAA,KAAM;AACnB,QAAA,MAAM,UAAU,CAAA,CAAE,aAAA,CACf,QAAQ,4BAA4B,CAAA,EACnC,iBAAiB,iBAAiB,CAAA;AACtC,QAAA,IAAI,OAAA,iBAAwB,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAA,CAAE,aAAa,CAAC,CAAA;AAAA,MAC1E,CAAA;AAAA,MACA,SAAA,EAAWE,oBAAA;AAAA,QACT,oFAAA;AAAA,QACA,2aAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,SAAS,MAAM;AACb,QAAA,QAAA,IAAW;AACX,QAAA,KAAA,EAAM;AAAA,MACR,CAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;AAEA,WAAA,CAAY,WAAA,GAAc,aAAA;AClDnB,SAAS,YAAA,CAAa;AAAA,EAC3B,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAsB;AACpB,EAAA,uBACEH,eAAAA,CAAC,KAAA,EAAA,EAAI,gCAAA,EAA+B,EAAA,EAAG,IAAA,EAAK,OAAA,EAAQ,SAAA,EAAWG,oBAAA,CAAG,MAAA,EAAQ,SAAS,CAAA,EAChF,QAAA,EAAA;AAAA,IAAA,OAAA,oBACCF,cAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDACZ,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,IAED;AAAA,GAAA,EACH,CAAA;AAEJ;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA;ACjBpB,SAAS,YAAA,CAAa;AAAA,EAC3B,QAAA,GAAW,mBAAA;AAAA,EACX;AACF,CAAA,EAAsB;AACpB,EAAA,uBACEA,cAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,gCAAA,EAA+B,EAAA;AAAA,MAC/B,SAAA,EAAWE,oBAAA;AAAA,QACT,0JAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA;ACI3B,SAAS,WAAA,CAAY;AAAA,EACnB,QAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,IAAA;AAAA,EACf,KAAA,EAAO,eAAA;AAAA,EACP;AACF,CAAA,EAAiB;AACf,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,IAAIE,sCAAA,CAAqB,eAAA,EAAiB,IAAI,aAAa,CAAA;AACjF,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIC,eAAS,EAAE,CAAA;AACjD,EAAA,MAAM,QAAA,GAAWC,aAAuB,IAAI,CAAA;AAC5C,EAAA,MAAM,SAASH,WAAAA,EAAM;AAErB,EAAA,MAAM,KAAA,GAAQI,kBAAY,MAAM;AAC9B,IAAA,OAAA,EAAQ;AACR,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,cAAA,CAAe,EAAE,CAAA;AAAA,EACnB,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAAC,8BAAA,CAAa,OAAO,IAAI,CAAA;AACxB,EAAAC,8BAAA,CAAa,UAAU,IAAI,CAAA;AAG3B,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,QAAA,GAAW,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,QAAA;AACrC,MAAA,QAAA,CAAS,IAAA,CAAK,MAAM,QAAA,GAAW,QAAA;AAC/B,MAAA,OAAO,MAAM;AACX,QAAA,QAAA,CAAS,IAAA,CAAK,MAAM,QAAA,GAAW,QAAA;AAAA,MACjC,CAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAWT,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AAEX,IAAA,MAAM,aAAA,GAAgB,CAAC,CAAA,KAAqB;AAC1C,MAAA,MAAM,KAAA,GAAQ,SAAS,OAAA,EAAS,gBAAA;AAAA,QAC9B;AAAA,OACF;AACA,MAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAEpB,MAAA,IAAI,CAAA,CAAE,QAAQ,WAAA,EAAa;AACzB,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,cAAA,CAAe,cAAc,KAAA,CAAM,MAAA,GAAS,CAAA,GAAI,WAAA,GAAc,IAAI,CAAC,CAAA;AAAA,MACrE,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,SAAA,EAAW;AAC9B,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,cAAA,CAAe,cAAc,CAAA,GAAI,WAAA,GAAc,CAAA,GAAI,KAAA,CAAM,SAAS,CAAC,CAAA;AAAA,MACrE,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,OAAA,EAAS;AAC5B,QAAA,IAAIC,gCAAA,CAAe,CAAC,CAAA,EAAG;AAGvB,QAAA,IAAK,CAAA,CAAE,MAAA,EAA+B,YAAA,CAAa,MAAM,MAAM,QAAA,EAAU;AACzE,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,WAAW,CAAA,IAAK,MAAM,CAAC,CAAA;AAC1C,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAClD,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,aAAa,CAAA;AAAA,EACpE,CAAA,EAAG,CAAC,IAAA,EAAM,WAAW,CAAC,CAAA;AAOtB,EAAAC,qBAAA,CAAgB,MAAM;AACpB,IAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,IAAA,MAAM,QAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,gBAAA,CAA8B,iBAAiB,CAAC,CAAA;AAC/E,IAAA,MAAM,MAAA,GAAS,MAAM,WAAW,CAAA;AAChC,IAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtB,MAAA,MAAM,KAAK,IAAA,KAAS,MAAA;AACpB,MAAA,IAAA,CAAK,YAAA,CAAa,eAAA,EAAiB,EAAA,GAAK,MAAA,GAAS,OAAO,CAAA;AACxD,MAAA,IAAI,EAAA,EAAI,IAAA,CAAK,YAAA,CAAa,aAAA,EAAe,EAAE,CAAA;AAAA,WACtC,IAAA,CAAK,gBAAgB,aAAa,CAAA;AAAA,IACzC,CAAC,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,aAAA,CAAgC,wCAAwC,CAAA;AAC5F,IAAA,IAAI,QAAQ,EAAA,EAAI,KAAA,EAAO,YAAA,CAAa,uBAAA,EAAyB,OAAO,EAAE,CAAA;AAAA,SACjE,KAAA,EAAO,gBAAgB,uBAAuB,CAAA;AACnD,IAAA,MAAA,EAAQ,cAAA,GAAiB,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA;AAAA,EAC/C,CAAC,CAAA;AAGD,EAAA,MAAM,WAAA,GAAcL,iBAAA;AAAA,IAClB,CAAC,IAAA,KAAiB;AAChB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,cAAA,CAAe,EAAE,CAAA;AAAA,IACnB,CAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,WAAW,GAAA,EAAK,OAAA,KAAYM,8BAAA,CAAa;AAAA,IACnE,IAAA;AAAA,IACA,UAAA,EAAY,gBAAA;AAAA,IACZ,SAAA,EAAW;AAAA,GACZ,CAAA;AAED,EAAA,MAAM,GAAA,GAAMC,aAAA;AAAA,IACV,OAAO;AAAA,MACL,IAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAA,EAAU,WAAA;AAAA,MACV,WAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,IAAA,EAAM,KAAA,EAAO,OAAO,WAAA,EAAa,WAAA,EAAa,cAAc,MAAM;AAAA,GACrE;AAEA,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,uBACEd,cAAAA,CAAC,cAAA,CAAe,QAAA,EAAf,EAAwB,KAAA,EAAO,GAAA,EAC9B,QAAA,kBAAAA,cAAAA,CAACe,wBAAA,EAAA,EACC,QAAA,kBAAAhB,eAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,8DAAA,EACb,QAAA,EAAA;AAAA,oBAAAC,cAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,+CAAA;AAAA,QACV,OAAA,EAAS,KAAA;AAAA,QACT,aAAA,EAAY;AAAA;AAAA,KACd;AAAA,oBACAA,cAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,CAAC,IAAA,KAAS;AACb,UAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,UAAC,QAAuD,OAAA,GACtD,IAAA;AAAA,QACJ,CAAA;AAAA,QACA,0BAAA,EAAyB,EAAA;AAAA,QACzB,SAAA,EAAWE,oBAAA;AAAA,UACT,uTAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACF;AAAA,QAEC;AAAA;AAAA;AACH,GAAA,EACF,GACF,CAAA,EACF,CAAA;AAEJ;AAEO,IAAM,OAAA,GAAU,MAAA,CAAO,MAAA,CAAO,WAAA,EAAa;AAAA,EAChD,KAAA,EAAO,YAAA;AAAA,EACP,IAAA,EAAM,WAAA;AAAA,EACN,IAAA,EAAM,WAAA;AAAA,EACN,KAAA,EAAO,YAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAC","file":"chunk-EC4ZYZNK.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { CommandContextValue } from \"./Command.types\";\n\nexport const CommandContext = createContext<CommandContextValue | null>(null);\n\nexport function useCommand(): CommandContextValue {\n const ctx = useContext(CommandContext);\n if (!ctx) {\n throw new Error(\n \"Command compound components must be used within <Command>\",\n );\n }\n return ctx;\n}\n","import { Search } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandInputProps } from \"./Command.types\";\n\nexport function CommandInput({\n placeholder = \"Type a command or search...\",\n className,\n}: CommandInputProps) {\n const { query, setQuery, listId } = useCommand();\n\n return (\n <div data-react-fancy-command-input=\"\" className=\"flex items-center border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\">\n <Search size={16} className=\"shrink-0 text-zinc-400\" />\n <input\n type=\"text\"\n // A combobox: focus stays here while the arrows move the active option,\n // which Command announces through aria-activedescendant.\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={placeholder}\n className={cn(\n \"flex-1 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-zinc-400\",\n className,\n )}\n autoFocus\n />\n </div>\n );\n}\n\nCommandInput.displayName = \"CommandInput\";\n","import { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandListProps } from \"./Command.types\";\n\nexport function CommandList({ children, className }: CommandListProps) {\n const { listId } = useCommand();\n\n return (\n <div\n id={listId}\n data-react-fancy-command-list=\"\"\n role=\"listbox\"\n className={cn(\"max-h-72 overflow-y-auto p-2\", className)}\n >\n {children}\n </div>\n );\n}\n\nCommandList.displayName = \"CommandList\";\n","import { useId } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandItemProps } from \"./Command.types\";\n\nexport function CommandItem({\n children,\n value,\n onSelect,\n className,\n}: CommandItemProps) {\n const { query, close, shouldFilter, setActiveIndex } = useCommand();\n // Called before the filter's early return, so the hook order never changes.\n const id = useId();\n\n // Filter by query — unless the caller filters for itself (`shouldFilter={false}`).\n const text = value ?? (typeof children === \"string\" ? children : \"\");\n if (shouldFilter && query && !text.toLowerCase().includes(query.toLowerCase())) {\n return null;\n }\n\n return (\n <button\n id={id}\n data-react-fancy-command-item=\"\"\n type=\"button\"\n role=\"option\"\n // Marked active by Command itself (aria-selected + data-active), since an\n // item cannot know its own position among the rendered options.\n aria-selected={false}\n // Keyboard focus stays in the input; the items are reached with the arrows.\n tabIndex={-1}\n onMouseEnter={(e) => {\n const options = e.currentTarget\n .closest(\"[data-react-fancy-command]\")\n ?.querySelectorAll('[role=\"option\"]');\n if (options) setActiveIndex(Array.from(options).indexOf(e.currentTarget));\n }}\n className={cn(\n \"flex w-full items-center rounded-lg px-3 py-2 text-start text-sm transition-colors\",\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] data-[active]:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:data-[active]:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n className,\n )}\n onClick={() => {\n onSelect?.();\n close();\n }}\n >\n {children}\n </button>\n );\n}\n\nCommandItem.displayName = \"CommandItem\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandGroupProps } from \"./Command.types\";\n\nexport function CommandGroup({\n children,\n heading,\n className,\n}: CommandGroupProps) {\n return (\n <div data-react-fancy-command-group=\"\" role=\"group\" className={cn(\"py-1\", className)}>\n {heading && (\n <div className=\"px-3 py-1.5 text-xs font-medium text-zinc-400\">\n {heading}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nCommandGroup.displayName = \"CommandGroup\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandEmptyProps } from \"./Command.types\";\n\nexport function CommandEmpty({\n children = \"No results found.\",\n className,\n}: CommandEmptyProps) {\n return (\n <div\n data-react-fancy-command-empty=\"\"\n className={cn(\n \"py-6 text-center text-sm text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nCommandEmpty.displayName = \"CommandEmpty\";\n","import {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { isImeComposing } from \"../../utils/ime\";\nimport { Portal } from \"../Portal\";\nimport { CommandContext } from \"./Command.context\";\nimport { CommandInput } from \"./CommandInput\";\nimport { CommandList } from \"./CommandList\";\nimport { CommandItem } from \"./CommandItem\";\nimport { CommandGroup } from \"./CommandGroup\";\nimport { CommandEmpty } from \"./CommandEmpty\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport type { CommandProps } from \"./Command.types\";\n\nfunction CommandRoot({\n children,\n open,\n onClose,\n className,\n shouldFilter = true,\n query: controlledQuery,\n onQueryChange,\n}: CommandProps) {\n const [query, setQuery] = useControllableState(controlledQuery, \"\", onQueryChange);\n const [activeIndex, setActiveIndex] = useState(-1);\n const panelRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n\n const close = useCallback(() => {\n onClose();\n setQuery(\"\");\n setActiveIndex(-1);\n }, [onClose]);\n\n useEscapeKey(close, open);\n useFocusTrap(panelRef, open);\n\n // Cmd+K global shortcut is handled by the consumer\n useEffect(() => {\n if (open) {\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }\n }, [open]);\n\n /*\n * Keyboard navigation, as a combobox: the arrows move the ACTIVE item while\n * focus stays in the input (announced through aria-activedescendant), and\n * Enter picks the active item — or the first visible one when none is active.\n *\n * Focus used to move onto the items, and Enter was handled nowhere, so typing\n * a query and pressing Enter did nothing: only a focused item took Enter, as a\n * native click. Found by Genie 2's real-window test.\n */\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const items = panelRef.current?.querySelectorAll<HTMLElement>(\n '[role=\"option\"]',\n );\n if (!items?.length) return;\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex(activeIndex < items.length - 1 ? activeIndex + 1 : 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex(activeIndex > 0 ? activeIndex - 1 : items.length - 1);\n } else if (e.key === \"Enter\") {\n if (isImeComposing(e)) return;\n // A focused item takes Enter natively, as a click; picking here as well\n // would select it twice.\n if ((e.target as HTMLElement | null)?.getAttribute(\"role\") === \"option\") return;\n const pick = items[activeIndex] ?? items[0];\n e.preventDefault();\n pick.click();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, activeIndex]);\n\n /*\n * Mark the active item and point the input at it. Done on the DOM after each\n * render because an item cannot know its own index — that is its position\n * among the options currently rendered, which filtering changes.\n */\n useLayoutEffect(() => {\n const panel = panelRef.current;\n if (!panel) return;\n\n const items = Array.from(panel.querySelectorAll<HTMLElement>('[role=\"option\"]'));\n const active = items[activeIndex];\n items.forEach((item) => {\n const on = item === active;\n item.setAttribute(\"aria-selected\", on ? \"true\" : \"false\");\n if (on) item.setAttribute(\"data-active\", \"\");\n else item.removeAttribute(\"data-active\");\n });\n\n const input = panel.querySelector<HTMLInputElement>(\"[data-react-fancy-command-input] input\");\n if (active?.id) input?.setAttribute(\"aria-activedescendant\", active.id);\n else input?.removeAttribute(\"aria-activedescendant\");\n active?.scrollIntoView?.({ block: \"nearest\" });\n });\n\n // A new query is a new list: nothing in it is active yet, so Enter picks the first match.\n const changeQuery = useCallback(\n (next: string) => {\n setQuery(next);\n setActiveIndex(-1);\n },\n [setQuery],\n );\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: \"fancy-slide-up\",\n exitClass: \"fancy-fade-out\",\n });\n\n const ctx = useMemo(\n () => ({\n open,\n close,\n query,\n setQuery: changeQuery,\n activeIndex,\n setActiveIndex,\n shouldFilter,\n listId,\n }),\n [open, close, query, changeQuery, activeIndex, shouldFilter, listId],\n );\n\n if (!mounted) return null;\n\n return (\n <CommandContext.Provider value={ctx}>\n <Portal>\n <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[20vh]\">\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }}\n data-react-fancy-command=\"\"\n className={cn(\n \"relative w-full max-w-lg overflow-hidden rounded-2xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-2xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n </Portal>\n </CommandContext.Provider>\n );\n}\n\nexport const Command = Object.assign(CommandRoot, {\n Input: CommandInput,\n List: CommandList,\n Item: CommandItem,\n Group: CommandGroup,\n Empty: CommandEmpty,\n});\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Modal/Modal.context.ts","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/ModalFooter.tsx","../src/components/Modal/Modal.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-GEQKNV7E.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ModalContextValue } from \"./Modal.types\";\n\nexport const ModalContext = createContext<ModalContextValue | null>(null);\n\nexport function useModal(): ModalContextValue {\n const ctx = useContext(ModalContext);\n if (!ctx) {\n throw new Error(\"Modal compound components must be used within <Modal>\");\n }\n return ctx;\n}\n","import { X } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useModal } from \"./Modal.context\";\nimport type { ModalHeaderProps } from \"./Modal.types\";\n\nexport function ModalHeader({ children, className }: ModalHeaderProps) {\n const { close } = useModal();\n\n return (\n <div\n data-react-fancy-modal-header=\"\"\n className={cn(\n \"flex items-center justify-between border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-6 py-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n <div className=\"text-lg font-semibold text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{children}</div>\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-lg p-1 text-zinc-400 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:text-zinc-600 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:hover:text-zinc-300\"\n aria-label=\"Close\"\n >\n <X size={20} />\n </button>\n </div>\n );\n}\n\nModalHeader.displayName = \"ModalHeader\";\n","import { cn } from \"../../utils/cn\";\nimport type { ModalBodyProps } from \"./Modal.types\";\n\nexport function ModalBody({ children, className }: ModalBodyProps) {\n return (\n // `min-h-0` is load-bearing, not decoration. A flex child defaults to\n // `min-height: auto`, which refuses to shrink below its content — so\n // `flex-1` alone would push the panel through its own max-height and the\n // scrollbar would never appear. This is what permits the overflow that\n // `overflow-y-auto` then handles.\n <div data-react-fancy-modal-body=\"\" className={cn(\"min-h-0 flex-1 overflow-y-auto px-6 py-4 text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\", className)}>\n {children}\n </div>\n );\n}\n\nModalBody.displayName = \"ModalBody\";\n","import { cn } from \"../../utils/cn\";\nimport type { ModalFooterProps } from \"./Modal.types\";\n\nexport function ModalFooter({ children, className }: ModalFooterProps) {\n return (\n <div\n data-react-fancy-modal-footer=\"\"\n className={cn(\n \"flex items-center justify-end gap-3 border-t border-[color:var(--fancy-border,var(--color-zinc-200))] px-6 py-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nModalFooter.displayName = \"ModalFooter\";\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ModalContext } from \"./Modal.context\";\nimport { ModalHeader } from \"./ModalHeader\";\nimport { ModalBody } from \"./ModalBody\";\nimport { ModalFooter } from \"./ModalFooter\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport type { ModalProps } from \"./Modal.types\";\n\n/**\n * Every size is capped against the VIEWPORT, not just the width.\n *\n * Only `full` used to carry a max-height. The other four were width-constrained\n * and vertically unbounded, so a modal with long content simply grew past the\n * bottom of the screen and the rest became unreachable — no scrollbar, because\n * there was no overflow to scroll: the box got taller instead.\n *\n * `ModalBody` already had `flex-1 overflow-y-auto` and the panel already had\n * `overflow-hidden`. The scrolling machinery was complete and inert, waiting on\n * the one constraint that makes it engage.\n *\n * `dvh` over `vh` deliberately: on mobile browsers `100vh` is the tallest the\n * viewport ever gets, ignoring the address bar, so a `vh`-capped modal still\n * runs under the chrome on exactly the devices with least room. `dvh` tracks\n * the visible height. The `vh` fallback is listed first for any engine that\n * does not know `dvh` yet — an unknown unit drops the declaration, so ordering\n * is what keeps the old behaviour rather than none.\n */\nconst VIEWPORT_CAP = \"max-h-[calc(100vh-2rem)] max-h-[calc(100dvh-2rem)]\";\n\nconst SIZE_MAP = {\n sm: `max-w-sm ${VIEWPORT_CAP}`,\n md: `max-w-lg ${VIEWPORT_CAP}`,\n lg: `max-w-2xl ${VIEWPORT_CAP}`,\n xl: `max-w-4xl ${VIEWPORT_CAP}`,\n full: `max-w-[calc(100vw-2rem)] ${VIEWPORT_CAP}`,\n} as const;\n\nfunction ModalRoot({\n children,\n open,\n onClose,\n size = \"md\",\n className,\n ...rest\n}: ModalProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n\n const close = useCallback(() => onClose(), [onClose]);\n useEscapeKey(close, open);\n useFocusTrap(panelRef, open);\n\n // Body scroll lock\n useEffect(() => {\n if (open) {\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }\n }, [open]);\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: \"fancy-slide-up\",\n exitClass: \"fancy-fade-out\",\n });\n\n const ctx = useMemo(() => ({ open, close }), [open, close]);\n\n if (!mounted) return null;\n\n return (\n <ModalContext.Provider value={ctx}>\n <Portal>\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n {/* Panel */}\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }}\n data-react-fancy-modal=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n {...rest}\n className={cn(\n \"relative flex w-full flex-col overflow-hidden rounded-2xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n SIZE_MAP[size],\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n </Portal>\n </ModalContext.Provider>\n );\n}\n\nexport const Modal = Object.assign(ModalRoot, {\n Header: ModalHeader,\n Body: ModalBody,\n Footer: ModalFooter,\n});\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-floating-position.ts"],"names":[],"mappings":"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","file":"chunk-GJWNZMJT.js","sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from \"react\";\nimport type { Placement } from \"../utils/types\";\nimport { directionOf, type Direction } from \"../utils/direction\";\n\ninterface FloatingPosition {\n x: number;\n y: number;\n placement: Placement;\n /**\n * The anchor's writing direction. Put it on the floating element as `dir`:\n * a floating element is portalled to `<body>`, so without it a `dir` set on\n * a wrapper (rather than on `<html>`) would not reach the popup.\n */\n dir: Direction;\n}\n\ninterface UseFloatingPositionOptions {\n placement?: Placement;\n offset?: number;\n enabled?: boolean;\n}\n\nfunction getPosition(\n anchor: DOMRect,\n floating: DOMRect,\n placement: Placement,\n offset: number,\n dir: Direction = \"ltr\",\n): FloatingPosition {\n let x = 0;\n let y = 0;\n const base = placement.split(\"-\")[0] as \"top\" | \"bottom\" | \"left\" | \"right\";\n const align = placement.split(\"-\")[1] as \"start\" | \"end\" | undefined;\n\n switch (base) {\n case \"top\":\n x = anchor.left + anchor.width / 2 - floating.width / 2;\n y = anchor.top - floating.height - offset;\n break;\n case \"bottom\":\n x = anchor.left + anchor.width / 2 - floating.width / 2;\n y = anchor.bottom + offset;\n break;\n case \"left\":\n x = anchor.left - floating.width - offset;\n y = anchor.top + anchor.height / 2 - floating.height / 2;\n break;\n case \"right\":\n x = anchor.right + offset;\n y = anchor.top + anchor.height / 2 - floating.height / 2;\n break;\n }\n\n // `start` / `end` are LOGICAL: `bottom-start` lines the popup up with the\n // anchor's inline-start edge, which is its RIGHT edge in RTL. The base side\n // (`left` / `right`) stays physical, as the names say.\n if (base === \"top\" || base === \"bottom\") {\n const startEdge = dir === \"rtl\" ? anchor.right - floating.width : anchor.left;\n const endEdge = dir === \"rtl\" ? anchor.left : anchor.right - floating.width;\n if (align === \"start\") x = startEdge;\n else if (align === \"end\") x = endEdge;\n }\n\n if (base === \"left\" || base === \"right\") {\n if (align === \"start\") y = anchor.top;\n else if (align === \"end\") y = anchor.bottom - floating.height;\n }\n\n // Viewport clamping\n let finalPlacement = placement;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n if (base === \"bottom\" && y + floating.height > vh) {\n y = anchor.top - floating.height - offset;\n finalPlacement = placement.replace(\"bottom\", \"top\") as Placement;\n } else if (base === \"top\" && y < 0) {\n y = anchor.bottom + offset;\n finalPlacement = placement.replace(\"top\", \"bottom\") as Placement;\n }\n\n x = Math.max(4, Math.min(x, vw - floating.width - 4));\n y = Math.max(4, Math.min(y, vh - floating.height - 4));\n\n return { x, y, placement: finalPlacement, dir };\n}\n\nexport function useFloatingPosition(\n anchorRef: RefObject<HTMLElement | null>,\n floatingRef: RefObject<HTMLElement | null>,\n options: UseFloatingPositionOptions = {},\n): FloatingPosition {\n const { placement = \"bottom\", offset = 8, enabled = true } = options;\n const [position, setPosition] = useState<FloatingPosition>({\n x: -9999,\n y: -9999,\n placement,\n dir: \"ltr\",\n });\n\n const update = useCallback(() => {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const anchorRect = anchor.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n const next = getPosition(anchorRect, floatingRect, placement, offset, directionOf(anchor));\n // Bail out when nothing changed so this can run after every commit\n // (below) without causing an infinite render loop.\n setPosition((prev) =>\n prev.x === next.x && prev.y === next.y && prev.placement === next.placement && prev.dir === next.dir\n ? prev\n : next,\n );\n }, [anchorRef, floatingRef, placement, offset]);\n\n // Re-measure after every commit while open.\n //\n // The floating element mounts a frame or two AFTER `enabled` flips — its\n // render is gated behind a state flip (e.g. useAnimation's `mounted`), so at\n // the moment `enabled` turns true the floating ref is still null and a single\n // measurement no-ops, leaving the popover parked at its off-screen sentinel.\n //\n // A passive effect with no deps runs after *every* commit — including the one\n // that finally mounts the floating element — and, crucially, keeps running in\n // hidden/background tabs where `requestAnimationFrame` is paused. The bail-out\n // in `update` makes the steady-state calls free, so this both fixes the\n // late-mount race and survives tab-visibility throttling.\n useEffect(() => {\n if (enabled) update();\n });\n\n // …but the per-commit effect ISN'T enough when the floating element mounts\n // through a <Portal> whose own mount gate (SSR-safe; renders nothing until its\n // useEffect runs) attaches the node WITHOUT re-rendering this hook's component.\n // Then no commit happens here, the measurement never runs, and the popover\n // stays parked at its off-screen sentinel until an unrelated scroll/resize\n // fires `update()` — the \"menu only appears after I scroll\" bug. Poll with rAF\n // until the node is actually in the DOM, measure it, then keep it observed for\n // size changes (async content / lazily-loaded icons).\n useEffect(() => {\n if (!enabled) return;\n let raf = 0;\n let ro: ResizeObserver | null = null;\n const tick = () => {\n const el = floatingRef.current;\n if (el) {\n update();\n if (typeof ResizeObserver !== \"undefined\") {\n ro = new ResizeObserver(() => update());\n ro.observe(el);\n }\n } else {\n raf = requestAnimationFrame(tick);\n }\n };\n raf = requestAnimationFrame(tick);\n return () => {\n cancelAnimationFrame(raf);\n ro?.disconnect();\n };\n }, [enabled, update, floatingRef]);\n\n // Park off-screen when closed so the next open re-measures from scratch.\n useEffect(() => {\n if (!enabled) {\n setPosition((prev) =>\n prev.x === -9999 ? prev : { x: -9999, y: -9999, placement, dir: prev.dir },\n );\n }\n }, [enabled, placement]);\n\n // Reposition on scroll/resize while open.\n useEffect(() => {\n if (!enabled) return;\n\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [update, enabled]);\n\n return position;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Modal/Modal.context.ts","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/ModalFooter.tsx","../src/components/Modal/Modal.tsx"],"names":["createContext","useContext","jsxs","cn","jsx","X","useRef","useCallback","useEscapeKey","useFocusTrap","useEffect","useAnimation","useMemo","Portal"],"mappings":"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","file":"chunk-HANQYZW2.cjs","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { ModalContextValue } from \"./Modal.types\";\n\nexport const ModalContext = createContext<ModalContextValue | null>(null);\n\nexport function useModal(): ModalContextValue {\n const ctx = useContext(ModalContext);\n if (!ctx) {\n throw new Error(\"Modal compound components must be used within <Modal>\");\n }\n return ctx;\n}\n","import { X } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useModal } from \"./Modal.context\";\nimport type { ModalHeaderProps } from \"./Modal.types\";\n\nexport function ModalHeader({ children, className }: ModalHeaderProps) {\n const { close } = useModal();\n\n return (\n <div\n data-react-fancy-modal-header=\"\"\n className={cn(\n \"flex items-center justify-between border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-6 py-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n <div className=\"text-lg font-semibold text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{children}</div>\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-lg p-1 text-zinc-400 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:text-zinc-600 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:hover:text-zinc-300\"\n aria-label=\"Close\"\n >\n <X size={20} />\n </button>\n </div>\n );\n}\n\nModalHeader.displayName = \"ModalHeader\";\n","import { cn } from \"../../utils/cn\";\nimport type { ModalBodyProps } from \"./Modal.types\";\n\nexport function ModalBody({ children, className }: ModalBodyProps) {\n return (\n // `min-h-0` is load-bearing, not decoration. A flex child defaults to\n // `min-height: auto`, which refuses to shrink below its content — so\n // `flex-1` alone would push the panel through its own max-height and the\n // scrollbar would never appear. This is what permits the overflow that\n // `overflow-y-auto` then handles.\n <div data-react-fancy-modal-body=\"\" className={cn(\"min-h-0 flex-1 overflow-y-auto px-6 py-4 text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\", className)}>\n {children}\n </div>\n );\n}\n\nModalBody.displayName = \"ModalBody\";\n","import { cn } from \"../../utils/cn\";\nimport type { ModalFooterProps } from \"./Modal.types\";\n\nexport function ModalFooter({ children, className }: ModalFooterProps) {\n return (\n <div\n data-react-fancy-modal-footer=\"\"\n className={cn(\n \"flex items-center justify-end gap-3 border-t border-[color:var(--fancy-border,var(--color-zinc-200))] px-6 py-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nModalFooter.displayName = \"ModalFooter\";\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { ModalContext } from \"./Modal.context\";\nimport { ModalHeader } from \"./ModalHeader\";\nimport { ModalBody } from \"./ModalBody\";\nimport { ModalFooter } from \"./ModalFooter\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport type { ModalProps } from \"./Modal.types\";\n\n/**\n * Every size is capped against the VIEWPORT, not just the width.\n *\n * Only `full` used to carry a max-height. The other four were width-constrained\n * and vertically unbounded, so a modal with long content simply grew past the\n * bottom of the screen and the rest became unreachable — no scrollbar, because\n * there was no overflow to scroll: the box got taller instead.\n *\n * `ModalBody` already had `flex-1 overflow-y-auto` and the panel already had\n * `overflow-hidden`. The scrolling machinery was complete and inert, waiting on\n * the one constraint that makes it engage.\n *\n * `dvh` over `vh` deliberately: on mobile browsers `100vh` is the tallest the\n * viewport ever gets, ignoring the address bar, so a `vh`-capped modal still\n * runs under the chrome on exactly the devices with least room. `dvh` tracks\n * the visible height. The `vh` fallback is listed first for any engine that\n * does not know `dvh` yet — an unknown unit drops the declaration, so ordering\n * is what keeps the old behaviour rather than none.\n */\nconst VIEWPORT_CAP = \"max-h-[calc(100vh-2rem)] max-h-[calc(100dvh-2rem)]\";\n\nconst SIZE_MAP = {\n sm: `max-w-sm ${VIEWPORT_CAP}`,\n md: `max-w-lg ${VIEWPORT_CAP}`,\n lg: `max-w-2xl ${VIEWPORT_CAP}`,\n xl: `max-w-4xl ${VIEWPORT_CAP}`,\n full: `max-w-[calc(100vw-2rem)] ${VIEWPORT_CAP}`,\n} as const;\n\nfunction ModalRoot({\n children,\n open,\n onClose,\n size = \"md\",\n className,\n ...rest\n}: ModalProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n\n const close = useCallback(() => onClose(), [onClose]);\n useEscapeKey(close, open);\n useFocusTrap(panelRef, open);\n\n // Body scroll lock\n useEffect(() => {\n if (open) {\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }\n }, [open]);\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: \"fancy-slide-up\",\n exitClass: \"fancy-fade-out\",\n });\n\n const ctx = useMemo(() => ({ open, close }), [open, close]);\n\n if (!mounted) return null;\n\n return (\n <ModalContext.Provider value={ctx}>\n <Portal>\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n {/* Panel */}\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }}\n data-react-fancy-modal=\"\"\n role=\"dialog\"\n aria-modal=\"true\"\n {...rest}\n className={cn(\n \"relative flex w-full flex-col overflow-hidden rounded-2xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n SIZE_MAP[size],\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n </Portal>\n </ModalContext.Provider>\n );\n}\n\nexport const Modal = Object.assign(ModalRoot, {\n Header: ModalHeader,\n Body: ModalBody,\n Footer: ModalFooter,\n});\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Command/Command.context.ts","../src/components/Command/CommandInput.tsx","../src/components/Command/CommandList.tsx","../src/components/Command/CommandItem.tsx","../src/components/Command/CommandGroup.tsx","../src/components/Command/CommandEmpty.tsx","../src/components/Command/Command.tsx"],"names":["jsx","jsxs","useId"],"mappings":"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","file":"chunk-R6O6SLXK.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { CommandContextValue } from \"./Command.types\";\n\nexport const CommandContext = createContext<CommandContextValue | null>(null);\n\nexport function useCommand(): CommandContextValue {\n const ctx = useContext(CommandContext);\n if (!ctx) {\n throw new Error(\n \"Command compound components must be used within <Command>\",\n );\n }\n return ctx;\n}\n","import { Search } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandInputProps } from \"./Command.types\";\n\nexport function CommandInput({\n placeholder = \"Type a command or search...\",\n className,\n}: CommandInputProps) {\n const { query, setQuery, listId } = useCommand();\n\n return (\n <div data-react-fancy-command-input=\"\" className=\"flex items-center border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\">\n <Search size={16} className=\"shrink-0 text-zinc-400\" />\n <input\n type=\"text\"\n // A combobox: focus stays here while the arrows move the active option,\n // which Command announces through aria-activedescendant.\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={placeholder}\n className={cn(\n \"flex-1 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-zinc-400\",\n className,\n )}\n autoFocus\n />\n </div>\n );\n}\n\nCommandInput.displayName = \"CommandInput\";\n","import { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandListProps } from \"./Command.types\";\n\nexport function CommandList({ children, className }: CommandListProps) {\n const { listId } = useCommand();\n\n return (\n <div\n id={listId}\n data-react-fancy-command-list=\"\"\n role=\"listbox\"\n className={cn(\"max-h-72 overflow-y-auto p-2\", className)}\n >\n {children}\n </div>\n );\n}\n\nCommandList.displayName = \"CommandList\";\n","import { useId } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandItemProps } from \"./Command.types\";\n\nexport function CommandItem({\n children,\n value,\n onSelect,\n className,\n}: CommandItemProps) {\n const { query, close, shouldFilter, setActiveIndex } = useCommand();\n // Called before the filter's early return, so the hook order never changes.\n const id = useId();\n\n // Filter by query — unless the caller filters for itself (`shouldFilter={false}`).\n const text = value ?? (typeof children === \"string\" ? children : \"\");\n if (shouldFilter && query && !text.toLowerCase().includes(query.toLowerCase())) {\n return null;\n }\n\n return (\n <button\n id={id}\n data-react-fancy-command-item=\"\"\n type=\"button\"\n role=\"option\"\n // Marked active by Command itself (aria-selected + data-active), since an\n // item cannot know its own position among the rendered options.\n aria-selected={false}\n // Keyboard focus stays in the input; the items are reached with the arrows.\n tabIndex={-1}\n onMouseEnter={(e) => {\n const options = e.currentTarget\n .closest(\"[data-react-fancy-command]\")\n ?.querySelectorAll('[role=\"option\"]');\n if (options) setActiveIndex(Array.from(options).indexOf(e.currentTarget));\n }}\n className={cn(\n \"flex w-full items-center rounded-lg px-3 py-2 text-start text-sm transition-colors\",\n \"text-[color:var(--fancy-text-soft,var(--color-zinc-700))] hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] data-[active]:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))] dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:data-[active]:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\",\n className,\n )}\n onClick={() => {\n onSelect?.();\n close();\n }}\n >\n {children}\n </button>\n );\n}\n\nCommandItem.displayName = \"CommandItem\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandGroupProps } from \"./Command.types\";\n\nexport function CommandGroup({\n children,\n heading,\n className,\n}: CommandGroupProps) {\n return (\n <div data-react-fancy-command-group=\"\" role=\"group\" className={cn(\"py-1\", className)}>\n {heading && (\n <div className=\"px-3 py-1.5 text-xs font-medium text-zinc-400\">\n {heading}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nCommandGroup.displayName = \"CommandGroup\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandEmptyProps } from \"./Command.types\";\n\nexport function CommandEmpty({\n children = \"No results found.\",\n className,\n}: CommandEmptyProps) {\n return (\n <div\n data-react-fancy-command-empty=\"\"\n className={cn(\n \"py-6 text-center text-sm text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nCommandEmpty.displayName = \"CommandEmpty\";\n","import {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { isImeComposing } from \"../../utils/ime\";\nimport { Portal } from \"../Portal\";\nimport { CommandContext } from \"./Command.context\";\nimport { CommandInput } from \"./CommandInput\";\nimport { CommandList } from \"./CommandList\";\nimport { CommandItem } from \"./CommandItem\";\nimport { CommandGroup } from \"./CommandGroup\";\nimport { CommandEmpty } from \"./CommandEmpty\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport type { CommandProps } from \"./Command.types\";\n\nfunction CommandRoot({\n children,\n open,\n onClose,\n className,\n shouldFilter = true,\n query: controlledQuery,\n onQueryChange,\n}: CommandProps) {\n const [query, setQuery] = useControllableState(controlledQuery, \"\", onQueryChange);\n const [activeIndex, setActiveIndex] = useState(-1);\n const panelRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n\n const close = useCallback(() => {\n onClose();\n setQuery(\"\");\n setActiveIndex(-1);\n }, [onClose]);\n\n useEscapeKey(close, open);\n useFocusTrap(panelRef, open);\n\n // Cmd+K global shortcut is handled by the consumer\n useEffect(() => {\n if (open) {\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }\n }, [open]);\n\n /*\n * Keyboard navigation, as a combobox: the arrows move the ACTIVE item while\n * focus stays in the input (announced through aria-activedescendant), and\n * Enter picks the active item — or the first visible one when none is active.\n *\n * Focus used to move onto the items, and Enter was handled nowhere, so typing\n * a query and pressing Enter did nothing: only a focused item took Enter, as a\n * native click. Found by Genie 2's real-window test.\n */\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const items = panelRef.current?.querySelectorAll<HTMLElement>(\n '[role=\"option\"]',\n );\n if (!items?.length) return;\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex(activeIndex < items.length - 1 ? activeIndex + 1 : 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex(activeIndex > 0 ? activeIndex - 1 : items.length - 1);\n } else if (e.key === \"Enter\") {\n if (isImeComposing(e)) return;\n // A focused item takes Enter natively, as a click; picking here as well\n // would select it twice.\n if ((e.target as HTMLElement | null)?.getAttribute(\"role\") === \"option\") return;\n const pick = items[activeIndex] ?? items[0];\n e.preventDefault();\n pick.click();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, activeIndex]);\n\n /*\n * Mark the active item and point the input at it. Done on the DOM after each\n * render because an item cannot know its own index — that is its position\n * among the options currently rendered, which filtering changes.\n */\n useLayoutEffect(() => {\n const panel = panelRef.current;\n if (!panel) return;\n\n const items = Array.from(panel.querySelectorAll<HTMLElement>('[role=\"option\"]'));\n const active = items[activeIndex];\n items.forEach((item) => {\n const on = item === active;\n item.setAttribute(\"aria-selected\", on ? \"true\" : \"false\");\n if (on) item.setAttribute(\"data-active\", \"\");\n else item.removeAttribute(\"data-active\");\n });\n\n const input = panel.querySelector<HTMLInputElement>(\"[data-react-fancy-command-input] input\");\n if (active?.id) input?.setAttribute(\"aria-activedescendant\", active.id);\n else input?.removeAttribute(\"aria-activedescendant\");\n active?.scrollIntoView?.({ block: \"nearest\" });\n });\n\n // A new query is a new list: nothing in it is active yet, so Enter picks the first match.\n const changeQuery = useCallback(\n (next: string) => {\n setQuery(next);\n setActiveIndex(-1);\n },\n [setQuery],\n );\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: \"fancy-slide-up\",\n exitClass: \"fancy-fade-out\",\n });\n\n const ctx = useMemo(\n () => ({\n open,\n close,\n query,\n setQuery: changeQuery,\n activeIndex,\n setActiveIndex,\n shouldFilter,\n listId,\n }),\n [open, close, query, changeQuery, activeIndex, shouldFilter, listId],\n );\n\n if (!mounted) return null;\n\n return (\n <CommandContext.Provider value={ctx}>\n <Portal>\n <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[20vh]\">\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }}\n data-react-fancy-command=\"\"\n className={cn(\n \"relative w-full max-w-lg overflow-hidden rounded-2xl border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-2xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n </Portal>\n </CommandContext.Provider>\n );\n}\n\nexport const Command = Object.assign(CommandRoot, {\n Input: CommandInput,\n List: CommandList,\n Item: CommandItem,\n Group: CommandGroup,\n Empty: CommandEmpty,\n});\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-focus-trap.ts"],"names":["useEffect"],"mappings":";;;;;AAEA,IAAM,kBAAA,GAAqB;AAAA,EACzB,SAAA;AAAA,EACA,wBAAA;AAAA,EACA,uBAAA;AAAA,EACA,0BAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,IAAI,CAAA;AAEJ,SAAS,YAAA,CACd,GAAA,EACA,OAAA,GAAmB,IAAA,EACb;AACN,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,MAAM,KAAK,GAAA,CAAI,OAAA;AACf,IAAA,IAAI,CAAC,EAAA,EAAI;AAET,IAAA,MAAM,oBAAoB,QAAA,CAAS,aAAA;AAEnC,IAAA,MAAM,aAAa,MACjB,KAAA,CAAM,KAAK,EAAA,CAAG,gBAAA,CAA8B,kBAAkB,CAAC,CAAA;AAGjE,IAAA,MAAM,KAAA,GAAQ,UAAA,EAAW,CAAE,CAAC,CAAA;AAC5B,IAAA,KAAA,EAAO,KAAA,EAAM;AAEb,IAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAyB;AACzC,MAAA,IAAI,KAAA,CAAM,QAAQ,KAAA,EAAO;AAEzB,MAAA,MAAM,QAAQ,UAAA,EAAW;AACzB,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAExB,MAAA,MAAM,SAAA,GAAY,MAAM,CAAC,CAAA;AACzB,MAAA,MAAM,QAAA,GAAW,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AAEvC,MAAA,IAAI,MAAM,QAAA,EAAU;AAClB,QAAA,IAAI,QAAA,CAAS,kBAAkB,SAAA,EAAW;AACxC,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,QAAA,CAAS,KAAA,EAAM;AAAA,QACjB;AAAA,MACF,CAAA,MAAO;AACL,QAAA,IAAI,QAAA,CAAS,kBAAkB,QAAA,EAAU;AACvC,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,SAAA,CAAU,KAAA,EAAM;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,EAAA,CAAG,gBAAA,CAAiB,WAAW,QAAQ,CAAA;AAEvC,IAAA,OAAO,MAAM;AACX,MAAA,EAAA,CAAG,mBAAA,CAAoB,WAAW,QAAQ,CAAA;AAC1C,MAAA,iBAAA,EAAmB,KAAA,EAAM;AAAA,IAC3B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,GAAA,EAAK,OAAO,CAAC,CAAA;AACnB","file":"chunk-TXTRTTG7.cjs","sourcesContent":["import { useEffect, type RefObject } from \"react\";\n\nconst FOCUSABLE_SELECTOR = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\nexport function useFocusTrap(\n ref: RefObject<HTMLElement | null>,\n enabled: boolean = true,\n): void {\n useEffect(() => {\n if (!enabled) return;\n\n const el = ref.current;\n if (!el) return;\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n\n const focusables = () =>\n Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));\n\n // Focus first focusable element\n const first = focusables()[0];\n first?.focus();\n\n const listener = (event: KeyboardEvent) => {\n if (event.key !== \"Tab\") return;\n\n const items = focusables();\n if (items.length === 0) return;\n\n const firstItem = items[0];\n const lastItem = items[items.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstItem) {\n event.preventDefault();\n lastItem.focus();\n }\n } else {\n if (document.activeElement === lastItem) {\n event.preventDefault();\n firstItem.focus();\n }\n }\n };\n\n el.addEventListener(\"keydown\", listener);\n\n return () => {\n el.removeEventListener(\"keydown\", listener);\n previouslyFocused?.focus();\n };\n }, [ref, enabled]);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-floating-position.ts"],"names":["useState","useCallback","directionOf","useEffect"],"mappings":"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","file":"chunk-XGGAAG74.cjs","sourcesContent":["import { useCallback, useEffect, useState, type RefObject } from \"react\";\nimport type { Placement } from \"../utils/types\";\nimport { directionOf, type Direction } from \"../utils/direction\";\n\ninterface FloatingPosition {\n x: number;\n y: number;\n placement: Placement;\n /**\n * The anchor's writing direction. Put it on the floating element as `dir`:\n * a floating element is portalled to `<body>`, so without it a `dir` set on\n * a wrapper (rather than on `<html>`) would not reach the popup.\n */\n dir: Direction;\n}\n\ninterface UseFloatingPositionOptions {\n placement?: Placement;\n offset?: number;\n enabled?: boolean;\n}\n\nfunction getPosition(\n anchor: DOMRect,\n floating: DOMRect,\n placement: Placement,\n offset: number,\n dir: Direction = \"ltr\",\n): FloatingPosition {\n let x = 0;\n let y = 0;\n const base = placement.split(\"-\")[0] as \"top\" | \"bottom\" | \"left\" | \"right\";\n const align = placement.split(\"-\")[1] as \"start\" | \"end\" | undefined;\n\n switch (base) {\n case \"top\":\n x = anchor.left + anchor.width / 2 - floating.width / 2;\n y = anchor.top - floating.height - offset;\n break;\n case \"bottom\":\n x = anchor.left + anchor.width / 2 - floating.width / 2;\n y = anchor.bottom + offset;\n break;\n case \"left\":\n x = anchor.left - floating.width - offset;\n y = anchor.top + anchor.height / 2 - floating.height / 2;\n break;\n case \"right\":\n x = anchor.right + offset;\n y = anchor.top + anchor.height / 2 - floating.height / 2;\n break;\n }\n\n // `start` / `end` are LOGICAL: `bottom-start` lines the popup up with the\n // anchor's inline-start edge, which is its RIGHT edge in RTL. The base side\n // (`left` / `right`) stays physical, as the names say.\n if (base === \"top\" || base === \"bottom\") {\n const startEdge = dir === \"rtl\" ? anchor.right - floating.width : anchor.left;\n const endEdge = dir === \"rtl\" ? anchor.left : anchor.right - floating.width;\n if (align === \"start\") x = startEdge;\n else if (align === \"end\") x = endEdge;\n }\n\n if (base === \"left\" || base === \"right\") {\n if (align === \"start\") y = anchor.top;\n else if (align === \"end\") y = anchor.bottom - floating.height;\n }\n\n // Viewport clamping\n let finalPlacement = placement;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n if (base === \"bottom\" && y + floating.height > vh) {\n y = anchor.top - floating.height - offset;\n finalPlacement = placement.replace(\"bottom\", \"top\") as Placement;\n } else if (base === \"top\" && y < 0) {\n y = anchor.bottom + offset;\n finalPlacement = placement.replace(\"top\", \"bottom\") as Placement;\n }\n\n x = Math.max(4, Math.min(x, vw - floating.width - 4));\n y = Math.max(4, Math.min(y, vh - floating.height - 4));\n\n return { x, y, placement: finalPlacement, dir };\n}\n\nexport function useFloatingPosition(\n anchorRef: RefObject<HTMLElement | null>,\n floatingRef: RefObject<HTMLElement | null>,\n options: UseFloatingPositionOptions = {},\n): FloatingPosition {\n const { placement = \"bottom\", offset = 8, enabled = true } = options;\n const [position, setPosition] = useState<FloatingPosition>({\n x: -9999,\n y: -9999,\n placement,\n dir: \"ltr\",\n });\n\n const update = useCallback(() => {\n const anchor = anchorRef.current;\n const floating = floatingRef.current;\n if (!anchor || !floating) return;\n\n const anchorRect = anchor.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n const next = getPosition(anchorRect, floatingRect, placement, offset, directionOf(anchor));\n // Bail out when nothing changed so this can run after every commit\n // (below) without causing an infinite render loop.\n setPosition((prev) =>\n prev.x === next.x && prev.y === next.y && prev.placement === next.placement && prev.dir === next.dir\n ? prev\n : next,\n );\n }, [anchorRef, floatingRef, placement, offset]);\n\n // Re-measure after every commit while open.\n //\n // The floating element mounts a frame or two AFTER `enabled` flips — its\n // render is gated behind a state flip (e.g. useAnimation's `mounted`), so at\n // the moment `enabled` turns true the floating ref is still null and a single\n // measurement no-ops, leaving the popover parked at its off-screen sentinel.\n //\n // A passive effect with no deps runs after *every* commit — including the one\n // that finally mounts the floating element — and, crucially, keeps running in\n // hidden/background tabs where `requestAnimationFrame` is paused. The bail-out\n // in `update` makes the steady-state calls free, so this both fixes the\n // late-mount race and survives tab-visibility throttling.\n useEffect(() => {\n if (enabled) update();\n });\n\n // …but the per-commit effect ISN'T enough when the floating element mounts\n // through a <Portal> whose own mount gate (SSR-safe; renders nothing until its\n // useEffect runs) attaches the node WITHOUT re-rendering this hook's component.\n // Then no commit happens here, the measurement never runs, and the popover\n // stays parked at its off-screen sentinel until an unrelated scroll/resize\n // fires `update()` — the \"menu only appears after I scroll\" bug. Poll with rAF\n // until the node is actually in the DOM, measure it, then keep it observed for\n // size changes (async content / lazily-loaded icons).\n useEffect(() => {\n if (!enabled) return;\n let raf = 0;\n let ro: ResizeObserver | null = null;\n const tick = () => {\n const el = floatingRef.current;\n if (el) {\n update();\n if (typeof ResizeObserver !== \"undefined\") {\n ro = new ResizeObserver(() => update());\n ro.observe(el);\n }\n } else {\n raf = requestAnimationFrame(tick);\n }\n };\n raf = requestAnimationFrame(tick);\n return () => {\n cancelAnimationFrame(raf);\n ro?.disconnect();\n };\n }, [enabled, update, floatingRef]);\n\n // Park off-screen when closed so the next open re-measures from scratch.\n useEffect(() => {\n if (!enabled) {\n setPosition((prev) =>\n prev.x === -9999 ? prev : { x: -9999, y: -9999, placement, dir: prev.dir },\n );\n }\n }, [enabled, placement]);\n\n // Reposition on scroll/resize while open.\n useEffect(() => {\n if (!enabled) return;\n\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [update, enabled]);\n\n return position;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Drawer/Drawer.context.ts","../src/components/Drawer/DrawerHeader.tsx","../src/components/Drawer/DrawerBody.tsx","../src/components/Drawer/DrawerFooter.tsx","../src/components/Drawer/DrawerContainer.tsx","../src/components/Drawer/Drawer.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-ZBXJDQXN.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { DrawerContextValue } from \"./Drawer.types\";\n\nexport const DrawerContext = createContext<DrawerContextValue | null>(null);\n\nexport function useDrawer(): DrawerContextValue {\n const ctx = useContext(DrawerContext);\n if (!ctx) {\n throw new Error(\"Drawer compound components must be used within <Drawer>\");\n }\n return ctx;\n}\n","import { X } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useDrawer } from \"./Drawer.context\";\nimport type { DrawerHeaderProps } from \"./Drawer.types\";\n\nexport function DrawerHeader({ children, closable = true, className }: DrawerHeaderProps) {\n const { close } = useDrawer();\n\n return (\n <div\n data-react-fancy-drawer-header=\"\"\n className={cn(\n \"flex shrink-0 items-center justify-between border-b border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 py-3 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n <div className=\"text-sm font-semibold text-[color:var(--fancy-text,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-dark,var(--color-zinc-100))]\">{children}</div>\n {closable ? (\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-lg p-1 text-zinc-400 transition-colors hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] hover:text-zinc-600 dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))] dark:hover:text-zinc-300\"\n aria-label=\"Close\"\n >\n <X size={18} />\n </button>\n ) : null}\n </div>\n );\n}\n\nDrawerHeader.displayName = \"DrawerHeader\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerBodyProps } from \"./Drawer.types\";\n\nexport function DrawerBody({ children, className }: DrawerBodyProps) {\n return (\n <div\n data-react-fancy-drawer-body=\"\"\n className={cn(\"min-h-0 flex-1 overflow-auto px-4 py-3 text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\", className)}\n >\n {children}\n </div>\n );\n}\n\nDrawerBody.displayName = \"DrawerBody\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerFooterProps } from \"./Drawer.types\";\n\nexport function DrawerFooter({ children, className }: DrawerFooterProps) {\n return (\n <div\n data-react-fancy-drawer-footer=\"\"\n className={cn(\n \"flex shrink-0 items-center justify-end gap-2 border-t border-[color:var(--fancy-border,var(--color-zinc-200))] px-4 py-3 dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nDrawerFooter.displayName = \"DrawerFooter\";\n","import { cn } from \"../../utils/cn\";\nimport type { DrawerContainerProps } from \"./Drawer.types\";\n\n/**\n * The anchor for `<Drawer attach=\"container\">`.\n *\n * A container-attached drawer positions itself `absolute`, which resolves\n * against the nearest *positioned* ancestor — so without `relative` somewhere\n * above it, the drawer silently escapes to the viewport and looks like it\n * ignored `attach` entirely. This wrapper supplies `relative` + `overflow-hidden`\n * so the panel slides within the box rather than out of it.\n *\n * <Drawer.Container className=\"h-80 rounded-xl border\">\n * <YourContent />\n * <Drawer attach=\"container\" side=\"bottom\" open={open} onClose={close}>\n * <Drawer.Body>Filters</Drawer.Body>\n * </Drawer>\n * </Drawer.Container>\n *\n * Any element works as long as it is positioned — this is the shortcut, not a\n * requirement. Wrapping a Card, a layout pane, or a prompt-input shell in\n * `relative overflow-hidden` does the same job.\n */\nexport function DrawerContainer({ children, className, ...rest }: DrawerContainerProps) {\n return (\n <div\n data-react-fancy-drawer-container=\"\"\n {...rest}\n className={cn(\"relative overflow-hidden\", className)}\n >\n {children}\n </div>\n );\n}\n\nDrawerContainer.displayName = \"DrawerContainer\";\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { DrawerContext } from \"./Drawer.context\";\nimport { DrawerHeader } from \"./DrawerHeader\";\nimport { DrawerBody } from \"./DrawerBody\";\nimport { DrawerFooter } from \"./DrawerFooter\";\nimport { DrawerContainer } from \"./DrawerContainer\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport type { DrawerProps, DrawerSide } from \"./Drawer.types\";\n\n/**\n * `size` addresses the drawer's own axis: width on the horizontal edges,\n * height on the vertical ones. Keeping one scale across both means `size=\"lg\"`\n * does not have to be re-learned when a drawer moves from the side to the\n * bottom.\n */\nconst WIDTH = {\n sm: \"w-64\",\n md: \"w-80\",\n lg: \"w-96\",\n xl: \"w-[32rem]\",\n full: \"w-full\",\n} as const;\n\nconst HEIGHT = {\n sm: \"h-32\",\n md: \"h-64\",\n lg: \"h-96\",\n xl: \"h-[32rem]\",\n full: \"h-full\",\n} as const;\n\nconst ANCHOR: Record<DrawerSide, string> = {\n start: \"inset-y-0 start-0\",\n end: \"inset-y-0 end-0\",\n left: \"inset-y-0 left-0\",\n right: \"inset-y-0 right-0\",\n top: \"inset-x-0 top-0\",\n bottom: \"inset-x-0 bottom-0\",\n};\n\nconst ENTER: Record<DrawerSide, string> = {\n start: \"fancy-slide-in-start\",\n end: \"fancy-slide-in-end\",\n left: \"fancy-slide-in-left\",\n right: \"fancy-slide-in-right\",\n top: \"fancy-slide-in-top\",\n bottom: \"fancy-slide-in-bottom\",\n};\n\nconst EXIT: Record<DrawerSide, string> = {\n start: \"fancy-slide-out-start\",\n end: \"fancy-slide-out-end\",\n left: \"fancy-slide-out-left\",\n right: \"fancy-slide-out-right\",\n top: \"fancy-slide-out-top\",\n bottom: \"fancy-slide-out-bottom\",\n};\n\n/** The panel's edge shadow reads as depth away from the anchored edge. */\nconst EDGE: Record<DrawerSide, string> = {\n start: \"border-e\",\n end: \"border-s\",\n left: \"border-r\",\n right: \"border-l\",\n top: \"border-b\",\n bottom: \"border-t\",\n};\n\nfunction DrawerRoot({\n children,\n open,\n onClose,\n side = \"end\",\n size = \"md\",\n attach = \"viewport\",\n backdrop = true,\n dismissOnBackdrop = true,\n dismissOnEscape = true,\n className,\n ...rest\n}: DrawerProps) {\n const panelRef = useRef<HTMLDivElement>(null);\n const horizontal = side !== \"top\" && side !== \"bottom\";\n const isViewport = attach === \"viewport\";\n\n const close = useCallback(() => onClose(), [onClose]);\n useEscapeKey(close, open && dismissOnEscape);\n\n // A container-attached drawer is a panel, not a dialog — trapping focus in it\n // would strand keyboard users inside a Card. Only the viewport form is modal.\n useFocusTrap(panelRef, open && isViewport);\n\n useEffect(() => {\n if (!open || !isViewport) return;\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }, [open, isViewport]);\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: ENTER[side],\n exitClass: EXIT[side],\n });\n\n const ctx = useMemo(() => ({ open, close, side }), [open, close, side]);\n\n if (!mounted) return null;\n\n const frame = (\n <div\n data-react-fancy-drawer-frame=\"\"\n className={cn(isViewport ? \"fixed inset-0 z-50\" : \"absolute inset-0 z-20\", !backdrop && \"pointer-events-none\")}\n >\n {backdrop ? (\n <div\n data-react-fancy-drawer-backdrop=\"\"\n className={cn(\n \"absolute inset-0 bg-black/40 transition-opacity\",\n isViewport && \"backdrop-blur-sm\",\n open ? \"opacity-100\" : \"opacity-0\",\n )}\n onClick={dismissOnBackdrop ? close : undefined}\n aria-hidden=\"true\"\n />\n ) : null}\n\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current = node;\n }}\n data-react-fancy-drawer=\"\"\n data-side={side}\n role=\"dialog\"\n aria-modal={isViewport || undefined}\n {...rest}\n className={cn(\n \"pointer-events-auto absolute flex flex-col border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] shadow-xl dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n ANCHOR[side],\n EDGE[side],\n horizontal ? WIDTH[size] : HEIGHT[size],\n // Cross-axis fills the anchor; the main axis is capped so a viewport\n // drawer can never grow past the screen on a small device.\n horizontal ? \"h-full\" : \"w-full\",\n isViewport && (horizontal ? \"max-w-[90vw]\" : \"max-h-[90vh]\"),\n !isViewport && (horizontal ? \"max-w-full\" : \"max-h-full\"),\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n );\n\n return (\n <DrawerContext.Provider value={ctx}>\n {isViewport ? <Portal>{frame}</Portal> : frame}\n </DrawerContext.Provider>\n );\n}\n\nexport const Drawer = Object.assign(DrawerRoot, {\n Header: DrawerHeader,\n Body: DrawerBody,\n Footer: DrawerFooter,\n Container: DrawerContainer,\n});\n"]}