@intlayer/design-system 7.4.0 → 7.5.0-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/dist/esm/components/Avatar/index.mjs +11 -28
  2. package/dist/esm/components/Avatar/index.mjs.map +1 -1
  3. package/dist/esm/components/Badge/index.mjs +1 -1
  4. package/dist/esm/components/Badge/index.mjs.map +1 -1
  5. package/dist/esm/components/Breadcrumb/index.mjs +1 -0
  6. package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
  7. package/dist/esm/components/Button/Button.mjs +20 -15
  8. package/dist/esm/components/Button/Button.mjs.map +1 -1
  9. package/dist/esm/components/Container/index.mjs +7 -4
  10. package/dist/esm/components/Container/index.mjs.map +1 -1
  11. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +2 -4
  12. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
  13. package/dist/esm/components/DropDown/index.mjs +6 -2
  14. package/dist/esm/components/DropDown/index.mjs.map +1 -1
  15. package/dist/esm/components/Form/elements/CheckboxElement.mjs +8 -4
  16. package/dist/esm/components/Form/elements/CheckboxElement.mjs.map +1 -1
  17. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -5
  18. package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
  19. package/dist/esm/components/IDE/CodeBlockClient.mjs +1 -1
  20. package/dist/esm/components/IDE/CodeBlockClient.mjs.map +1 -1
  21. package/dist/esm/components/IDE/CodeBlockShiki.mjs +1 -0
  22. package/dist/esm/components/IDE/CodeBlockShiki.mjs.map +1 -1
  23. package/dist/esm/components/Input/Input.mjs.map +1 -1
  24. package/dist/esm/components/Input/OTPInput.mjs +1 -2
  25. package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
  26. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +225 -0
  27. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -0
  28. package/dist/esm/components/KeyboardShortcut/index.mjs +3 -0
  29. package/dist/esm/components/Link/Link.mjs +123 -93
  30. package/dist/esm/components/Link/Link.mjs.map +1 -1
  31. package/dist/esm/components/Link/index.mjs +2 -2
  32. package/dist/esm/components/Navbar/DesktopNavbar.mjs +1 -1
  33. package/dist/esm/components/Navbar/DesktopNavbar.mjs.map +1 -1
  34. package/dist/esm/components/Pagination/Pagination.mjs +83 -43
  35. package/dist/esm/components/Pagination/Pagination.mjs.map +1 -1
  36. package/dist/esm/components/Popover/static.mjs +3 -6
  37. package/dist/esm/components/Popover/static.mjs.map +1 -1
  38. package/dist/esm/components/SwitchSelector/index.mjs +2 -2
  39. package/dist/esm/components/SwitchSelector/index.mjs.map +1 -1
  40. package/dist/esm/components/Tag/index.mjs +2 -2
  41. package/dist/esm/components/Tag/index.mjs.map +1 -1
  42. package/dist/esm/components/Terminal/Terminal.mjs +4 -1
  43. package/dist/esm/components/Terminal/Terminal.mjs.map +1 -1
  44. package/dist/esm/components/Terminal/terminal.content.mjs +51 -0
  45. package/dist/esm/components/Terminal/terminal.content.mjs.map +1 -0
  46. package/dist/esm/components/index.mjs +3 -2
  47. package/dist/esm/hooks/index.mjs +2 -2
  48. package/dist/esm/hooks/reactQuery.mjs +8 -1
  49. package/dist/esm/hooks/reactQuery.mjs.map +1 -1
  50. package/dist/esm/hooks/useItemSelector.mjs +51 -28
  51. package/dist/esm/hooks/useItemSelector.mjs.map +1 -1
  52. package/dist/esm/libs/auth.mjs +9 -3
  53. package/dist/esm/libs/auth.mjs.map +1 -1
  54. package/dist/types/components/Avatar/index.d.ts.map +1 -1
  55. package/dist/types/components/Badge/index.d.ts.map +1 -1
  56. package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
  57. package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts.map +1 -1
  58. package/dist/types/components/Breadcrumb/index.d.ts.map +1 -1
  59. package/dist/types/components/Button/Button.d.ts +1 -1
  60. package/dist/types/components/Button/Button.d.ts.map +1 -1
  61. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
  62. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
  63. package/dist/types/components/Command/index.d.ts +17 -17
  64. package/dist/types/components/Command/index.d.ts.map +1 -1
  65. package/dist/types/components/Container/index.d.ts +10 -8
  66. package/dist/types/components/Container/index.d.ts.map +1 -1
  67. package/dist/types/components/CopyButton/CopyButton.content.d.ts +3 -3
  68. package/dist/types/components/CopyButton/CopyButton.content.d.ts.map +1 -1
  69. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +25 -25
  70. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts +9 -9
  71. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +33 -33
  72. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/useDictionaryDetailsSchema.content.d.ts +25 -25
  73. package/dist/types/components/DictionaryFieldEditor/DictionaryFieldEditor.d.ts.map +1 -1
  74. package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
  75. package/dist/types/components/DictionaryFieldEditor/SaveForm/saveForm.content.d.ts +33 -33
  76. package/dist/types/components/DictionaryFieldEditor/StructureView/structureView.content.d.ts +9 -9
  77. package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts +7 -7
  78. package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts.map +1 -1
  79. package/dist/types/components/DictionaryFieldEditor/dictionaryFieldEditor.content.d.ts +5 -5
  80. package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
  81. package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts.map +1 -1
  82. package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
  83. package/dist/types/components/Form/FormBase.d.ts +2 -2
  84. package/dist/types/components/Form/FormField.d.ts +2 -2
  85. package/dist/types/components/Form/FormItem.d.ts +2 -2
  86. package/dist/types/components/Form/FormItem.d.ts.map +1 -1
  87. package/dist/types/components/Form/elements/CheckboxElement.d.ts.map +1 -1
  88. package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts +2 -2
  89. package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +2 -2
  90. package/dist/types/components/Form/elements/FormElement.d.ts +2 -2
  91. package/dist/types/components/Form/elements/MultiselectElement.d.ts +2 -2
  92. package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
  93. package/dist/types/components/Form/elements/SelectElement.d.ts +2 -2
  94. package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +2 -2
  95. package/dist/types/components/IDE/CodeBlockShiki.d.ts.map +1 -1
  96. package/dist/types/components/IDE/CodeContext.d.ts +2 -2
  97. package/dist/types/components/IDE/FileTree.d.ts.map +1 -1
  98. package/dist/types/components/IDE/code.content.d.ts +5 -5
  99. package/dist/types/components/IDE/code.content.d.ts.map +1 -1
  100. package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
  101. package/dist/types/components/IDE/copyCode.content.d.ts.map +1 -1
  102. package/dist/types/components/Input/Checkbox.d.ts +3 -3
  103. package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
  104. package/dist/types/components/Input/Input.d.ts +3 -3
  105. package/dist/types/components/Input/Input.d.ts.map +1 -1
  106. package/dist/types/components/Input/OTPInput.d.ts +7 -9
  107. package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
  108. package/dist/types/components/Input/SearchInput.d.ts +2 -2
  109. package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts +90 -0
  110. package/dist/types/components/KeyboardShortcut/KeyboardShortcut.d.ts.map +1 -0
  111. package/dist/types/components/KeyboardShortcut/index.d.ts +2 -0
  112. package/dist/types/components/Link/Link.d.ts +25 -88
  113. package/dist/types/components/Link/Link.d.ts.map +1 -1
  114. package/dist/types/components/Link/index.d.ts +2 -2
  115. package/dist/types/components/Loader/index.content.d.ts +3 -3
  116. package/dist/types/components/Loader/index.content.d.ts.map +1 -1
  117. package/dist/types/components/Loader/spinner.d.ts +2 -2
  118. package/dist/types/components/Loader/spinner.d.ts.map +1 -1
  119. package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts +17 -17
  120. package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts.map +1 -1
  121. package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts +13 -13
  122. package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts.map +1 -1
  123. package/dist/types/components/MaxWidthSmoother/index.d.ts +2 -2
  124. package/dist/types/components/MaxWidthSmoother/index.d.ts.map +1 -1
  125. package/dist/types/components/Navbar/Burger.d.ts +2 -2
  126. package/dist/types/components/Navbar/Burger.d.ts.map +1 -1
  127. package/dist/types/components/Navbar/DesktopNavbar.d.ts +2 -2
  128. package/dist/types/components/Navbar/MobileNavbar.d.ts +2 -2
  129. package/dist/types/components/Navbar/MobileNavbar.d.ts.map +1 -1
  130. package/dist/types/components/Navbar/index.d.ts +2 -2
  131. package/dist/types/components/Navbar/index.d.ts.map +1 -1
  132. package/dist/types/components/Pagination/Pagination.d.ts +3 -3
  133. package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
  134. package/dist/types/components/Pagination/pagination.content.d.ts +11 -11
  135. package/dist/types/components/Popover/static.d.ts +1 -17
  136. package/dist/types/components/Popover/static.d.ts.map +1 -1
  137. package/dist/types/components/Select/Select.d.ts +3 -3
  138. package/dist/types/components/SocialNetworks/index.d.ts +2 -2
  139. package/dist/types/components/SocialNetworks/index.d.ts.map +1 -1
  140. package/dist/types/components/SwitchSelector/index.d.ts +5 -5
  141. package/dist/types/components/SwitchSelector/index.d.ts.map +1 -1
  142. package/dist/types/components/Tab/Tab.d.ts +6 -6
  143. package/dist/types/components/Tab/Tab.d.ts.map +1 -1
  144. package/dist/types/components/Tab/TabContext.d.ts +2 -2
  145. package/dist/types/components/TabSelector/TabSelector.d.ts +4 -4
  146. package/dist/types/components/Table/table.content.d.ts +3 -3
  147. package/dist/types/components/Tag/index.d.ts +2 -2
  148. package/dist/types/components/Tag/index.d.ts.map +1 -1
  149. package/dist/types/components/Terminal/Terminal.d.ts.map +1 -1
  150. package/dist/types/components/Terminal/terminal.content.d.ts +93 -0
  151. package/dist/types/components/Terminal/terminal.content.d.ts.map +1 -0
  152. package/dist/types/components/Toaster/Toast.d.ts +2 -2
  153. package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
  154. package/dist/types/components/Toaster/Toaster.d.ts +2 -2
  155. package/dist/types/components/Toaster/Toaster.d.ts.map +1 -1
  156. package/dist/types/components/index.d.ts +4 -2
  157. package/dist/types/hooks/index.d.ts +2 -2
  158. package/dist/types/hooks/reactQuery.d.ts +2 -1
  159. package/dist/types/hooks/reactQuery.d.ts.map +1 -1
  160. package/dist/types/libs/auth.d.ts +1 -0
  161. package/dist/types/libs/auth.d.ts.map +1 -1
  162. package/package.json +40 -34
@@ -0,0 +1,225 @@
1
+ 'use client';
2
+
3
+ import { cn } from "../../utils/cn.mjs";
4
+ import { useDevice } from "../../hooks/useDevice.mjs";
5
+ import { useEffect, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+
8
+ //#region src/components/KeyboardShortcut/KeyboardShortcut.tsx
9
+ /**
10
+ * Enum for available keyboard keys
11
+ */
12
+ let KeyList = /* @__PURE__ */ function(KeyList$1) {
13
+ KeyList$1["⌘"] = "⌘";
14
+ KeyList$1["Ctrl"] = "Ctrl";
15
+ KeyList$1["Alt"] = "Alt";
16
+ KeyList$1["⌥"] = "⌥";
17
+ KeyList$1["Shift"] = "Shift";
18
+ KeyList$1["Meta"] = "Meta";
19
+ KeyList$1["F"] = "F";
20
+ KeyList$1["K"] = "K";
21
+ KeyList$1["L"] = "L";
22
+ KeyList$1["P"] = "P";
23
+ KeyList$1["S"] = "S";
24
+ KeyList$1["A"] = "A";
25
+ KeyList$1["B"] = "B";
26
+ KeyList$1["C"] = "C";
27
+ KeyList$1["D"] = "D";
28
+ KeyList$1["E"] = "E";
29
+ KeyList$1["G"] = "G";
30
+ KeyList$1["H"] = "H";
31
+ KeyList$1["I"] = "I";
32
+ KeyList$1["J"] = "J";
33
+ KeyList$1["M"] = "M";
34
+ KeyList$1["N"] = "N";
35
+ KeyList$1["O"] = "O";
36
+ KeyList$1["Q"] = "Q";
37
+ KeyList$1["R"] = "R";
38
+ KeyList$1["T"] = "T";
39
+ KeyList$1["U"] = "U";
40
+ KeyList$1["V"] = "V";
41
+ KeyList$1["W"] = "W";
42
+ KeyList$1["X"] = "X";
43
+ KeyList$1["Y"] = "Y";
44
+ KeyList$1["Z"] = "Z";
45
+ KeyList$1["Enter"] = "Enter";
46
+ KeyList$1["Escape"] = "Escape";
47
+ KeyList$1["Backspace"] = "Backspace";
48
+ KeyList$1["Tab"] = "Tab";
49
+ KeyList$1["Space"] = "Space";
50
+ KeyList$1["ArrowUp"] = "ArrowUp";
51
+ KeyList$1["ArrowDown"] = "ArrowDown";
52
+ KeyList$1["ArrowLeft"] = "ArrowLeft";
53
+ KeyList$1["ArrowRight"] = "ArrowRight";
54
+ KeyList$1["↑"] = "↑";
55
+ KeyList$1["↓"] = "↓";
56
+ KeyList$1["←"] = "←";
57
+ KeyList$1["→"] = "→";
58
+ return KeyList$1;
59
+ }({});
60
+ /**
61
+ * Parse keyboard shortcut string into individual keys
62
+ */
63
+ const parseShortcut = (shortcut) => {
64
+ return shortcut.split(" + ").map((key) => key.trim());
65
+ };
66
+ /**
67
+ * Normalize key name for event comparison
68
+ */
69
+ const normalizeKey = (key) => {
70
+ return {
71
+ "⌘": "Meta",
72
+ Ctrl: "Control",
73
+ Control: "Control",
74
+ Alt: "Alt",
75
+ "⌥": "Alt",
76
+ Shift: "Shift",
77
+ Meta: "Meta",
78
+ "↑": "ArrowUp",
79
+ "↓": "ArrowDown",
80
+ "←": "ArrowLeft",
81
+ "→": "ArrowRight",
82
+ ArrowUp: "ArrowUp",
83
+ ArrowDown: "ArrowDown",
84
+ ArrowLeft: "ArrowLeft",
85
+ ArrowRight: "ArrowRight"
86
+ }[key] || key;
87
+ };
88
+ /**
89
+ * Check if the keyboard event matches the shortcut
90
+ */
91
+ const matchesShortcut = (event, keys) => {
92
+ const normalizedKeys = keys.map(normalizeKey);
93
+ const hasModifiers = {
94
+ Meta: normalizedKeys.includes("Meta"),
95
+ Control: normalizedKeys.includes("Control"),
96
+ Alt: normalizedKeys.includes("Alt"),
97
+ Shift: normalizedKeys.includes("Shift")
98
+ };
99
+ if (hasModifiers.Meta !== event.metaKey || hasModifiers.Control !== event.ctrlKey || hasModifiers.Alt !== event.altKey || hasModifiers.Shift !== event.shiftKey) return false;
100
+ const nonModifierKey = keys.find((key) => ![
101
+ "⌘",
102
+ "Ctrl",
103
+ "Control",
104
+ "Alt",
105
+ "⌥",
106
+ "Shift",
107
+ "Meta"
108
+ ].includes(normalizeKey(key)));
109
+ if (!nonModifierKey) return false;
110
+ const normalizedNonModifierKey = normalizeKey(nonModifierKey);
111
+ if (normalizedNonModifierKey.startsWith("Arrow")) return event.key === normalizedNonModifierKey;
112
+ return event.key.toLowerCase() === normalizedNonModifierKey.toLowerCase();
113
+ };
114
+ /**
115
+ * Get display key symbol for better visual representation
116
+ */
117
+ const getDisplayKey = (key) => {
118
+ return {
119
+ ArrowUp: "↑",
120
+ ArrowDown: "↓",
121
+ ArrowLeft: "←",
122
+ ArrowRight: "→"
123
+ }[key] || key;
124
+ };
125
+ /**
126
+ * Get display shortcut based on OS (Mac uses ⌘ and ⌥, others use Ctrl and Alt)
127
+ */
128
+ const getDisplayShortcut = (shortcut, isMac) => {
129
+ let result = shortcut;
130
+ if (isMac) {
131
+ result = result.replace(/Ctrl/g, "⌘");
132
+ result = result.replace(/Alt/g, "⌥");
133
+ } else {
134
+ result = result.replace(/⌘/g, "Ctrl");
135
+ result = result.replace(/⌥/g, "Alt");
136
+ }
137
+ result = result.replace(/ArrowUp/g, "↑");
138
+ result = result.replace(/ArrowDown/g, "↓");
139
+ result = result.replace(/ArrowLeft/g, "←");
140
+ result = result.replace(/ArrowRight/g, "→");
141
+ return result;
142
+ };
143
+ /**
144
+ * KeyboardShortcut Component
145
+ *
146
+ * A reusable component that displays keyboard shortcuts and listens for key combinations.
147
+ * Automatically adapts to Mac (⌘, ⌥) and Windows/Linux (Ctrl, Alt) conventions.
148
+ *
149
+ * @example
150
+ * ```tsx
151
+ * <KeyboardShortcut
152
+ * shortcut="⌘ + F"
153
+ * onTriggered={() => setShowSearch(true)}
154
+ * />
155
+ * ```
156
+ */
157
+ const KeyboardShortcut = ({ shortcut, onTriggered, display = true, className, size = "md" }) => {
158
+ const { isMac } = useDevice();
159
+ const keys = parseShortcut(getDisplayShortcut(shortcut, isMac ?? false));
160
+ const [pressedKeys, setPressedKeys] = useState(/* @__PURE__ */ new Set());
161
+ useEffect(() => {
162
+ const handleKeyDown = (event) => {
163
+ const target = event.target;
164
+ const isInputField = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
165
+ const currentKey = event.key;
166
+ const normalizedEventKeys = /* @__PURE__ */ new Set();
167
+ if (event.metaKey) normalizedEventKeys.add("⌘");
168
+ if (event.ctrlKey) normalizedEventKeys.add("Ctrl");
169
+ if (event.altKey) normalizedEventKeys.add(isMac ? "⌥" : "Alt");
170
+ if (event.shiftKey) normalizedEventKeys.add("Shift");
171
+ if (currentKey.startsWith("Arrow")) {
172
+ normalizedEventKeys.add(currentKey);
173
+ const arrowSymbol = getDisplayKey(currentKey);
174
+ normalizedEventKeys.add(arrowSymbol);
175
+ } else normalizedEventKeys.add(currentKey.toUpperCase());
176
+ setPressedKeys(normalizedEventKeys);
177
+ if (onTriggered && matchesShortcut(event, keys)) {
178
+ if (isInputField) return;
179
+ event.preventDefault();
180
+ onTriggered();
181
+ }
182
+ };
183
+ const handleKeyUp = () => {
184
+ setPressedKeys(/* @__PURE__ */ new Set());
185
+ };
186
+ window.addEventListener("keydown", handleKeyDown);
187
+ window.addEventListener("keyup", handleKeyUp);
188
+ window.addEventListener("blur", handleKeyUp);
189
+ return () => {
190
+ window.removeEventListener("keydown", handleKeyDown);
191
+ window.removeEventListener("keyup", handleKeyUp);
192
+ window.removeEventListener("blur", handleKeyUp);
193
+ };
194
+ }, [keys, onTriggered]);
195
+ if (!display) return null;
196
+ /**
197
+ * Check if a key is currently pressed
198
+ */
199
+ const isKeyPressed = (key) => {
200
+ const upperKey = key.toUpperCase();
201
+ const normalizedKey = normalizeKey(key);
202
+ return pressedKeys.has(key) || pressedKeys.has(upperKey) || pressedKeys.has(normalizedKey) || key === "⌘" && pressedKeys.has("Meta") || key === "Ctrl" && pressedKeys.has("Control") || key === "⌥" && pressedKeys.has("Alt") || key === "Alt" && pressedKeys.has("Alt") || key === "←" && pressedKeys.has("ArrowLeft") || key === "→" && pressedKeys.has("ArrowRight") || key === "↑" && pressedKeys.has("ArrowUp") || key === "↓" && pressedKeys.has("ArrowDown");
203
+ };
204
+ return /* @__PURE__ */ jsx("kbd", {
205
+ className: cn("inline-flex items-center justify-center gap-0.5 p-0.5", "rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl", "font-medium font-sans", "border-1 border-neutral/20 text-neutral", size === "sm" && "text-xs", size === "md" && "text-sm", size === "lg" && "text-base", className),
206
+ children: keys.map((key, index) => {
207
+ const keyId = `${key}-${index}-${shortcut}`;
208
+ const displayKey = getDisplayKey(key);
209
+ return /* @__PURE__ */ jsxs("span", {
210
+ className: "inline-flex items-center",
211
+ children: [index > 0 && /* @__PURE__ */ jsx("span", {
212
+ className: "text-neutral/50",
213
+ children: "+"
214
+ }), /* @__PURE__ */ jsx("span", {
215
+ className: cn("min-w-4 px-0.5", isKeyPressed(key) && "scale-120 font-bold text-text"),
216
+ children: displayKey
217
+ })]
218
+ }, keyId);
219
+ })
220
+ });
221
+ };
222
+
223
+ //#endregion
224
+ export { KeyList, KeyboardShortcut };
225
+ //# sourceMappingURL=KeyboardShortcut.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyboardShortcut.mjs","names":["KeyboardShortcut: FC<KeyboardShortcutProps>"],"sources":["../../../../src/components/KeyboardShortcut/KeyboardShortcut.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, useEffect, useState } from 'react';\nimport { useDevice } from '../../hooks/useDevice';\nimport { cn } from '../../utils/cn';\n\n/**\n * Enum for available keyboard keys\n */\nexport enum KeyList {\n '⌘' = '⌘',\n Ctrl = 'Ctrl',\n Alt = 'Alt',\n '⌥' = '⌥',\n Shift = 'Shift',\n Meta = 'Meta',\n F = 'F',\n K = 'K',\n L = 'L',\n P = 'P',\n S = 'S',\n A = 'A',\n B = 'B',\n C = 'C',\n D = 'D',\n E = 'E',\n G = 'G',\n H = 'H',\n I = 'I',\n J = 'J',\n M = 'M',\n N = 'N',\n O = 'O',\n Q = 'Q',\n R = 'R',\n T = 'T',\n U = 'U',\n V = 'V',\n W = 'W',\n X = 'X',\n Y = 'Y',\n Z = 'Z',\n Enter = 'Enter',\n Escape = 'Escape',\n Backspace = 'Backspace',\n Tab = 'Tab',\n Space = 'Space',\n ArrowUp = 'ArrowUp',\n ArrowDown = 'ArrowDown',\n ArrowLeft = 'ArrowLeft',\n ArrowRight = 'ArrowRight',\n '↑' = '↑',\n '↓' = '↓',\n '←' = '←',\n '→' = '→',\n}\n\n/**\n * Type-safe keyboard shortcut combinations\n * Note: Using string type to avoid union type complexity issues\n * Expected format: \"Key + Key\" (e.g., \"⌘ + F\", \"Ctrl + Shift + K\")\n */\nexport type KeyboardShortcutType = string;\n\nexport type KeyboardShortcutProps = {\n /** The keyboard shortcut combination (e.g., \"⌘ + F\" or \"Ctrl + K\") */\n shortcut: KeyboardShortcutType;\n /** Callback function triggered when the shortcut is pressed */\n onTriggered?: () => void;\n /** Whether to display the shortcut visually (default: true) */\n display?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Size of the keyboard shortcut display */\n size?: 'sm' | 'md' | 'lg';\n};\n\n/**\n * Parse keyboard shortcut string into individual keys\n */\nconst parseShortcut = (shortcut: string): string[] => {\n return shortcut.split(' + ').map((key) => key.trim());\n};\n\n/**\n * Normalize key name for event comparison\n */\nconst normalizeKey = (key: string): string => {\n const keyMap: Record<string, string> = {\n '⌘': 'Meta',\n Ctrl: 'Control',\n Control: 'Control',\n Alt: 'Alt',\n '⌥': 'Alt',\n Shift: 'Shift',\n Meta: 'Meta',\n '↑': 'ArrowUp',\n '↓': 'ArrowDown',\n '←': 'ArrowLeft',\n '→': 'ArrowRight',\n ArrowUp: 'ArrowUp',\n ArrowDown: 'ArrowDown',\n ArrowLeft: 'ArrowLeft',\n ArrowRight: 'ArrowRight',\n };\n\n return keyMap[key] || key;\n};\n\n/**\n * Check if the keyboard event matches the shortcut\n */\nconst matchesShortcut = (event: KeyboardEvent, keys: string[]): boolean => {\n const normalizedKeys = keys.map(normalizeKey);\n const hasModifiers = {\n Meta: normalizedKeys.includes('Meta'),\n Control: normalizedKeys.includes('Control'),\n Alt: normalizedKeys.includes('Alt'),\n Shift: normalizedKeys.includes('Shift'),\n };\n\n // Check if all required modifiers are pressed\n if (\n hasModifiers.Meta !== event.metaKey ||\n hasModifiers.Control !== event.ctrlKey ||\n hasModifiers.Alt !== event.altKey ||\n hasModifiers.Shift !== event.shiftKey\n ) {\n return false;\n }\n\n // Find the non-modifier key\n const nonModifierKey = keys.find(\n (key) =>\n !['⌘', 'Ctrl', 'Control', 'Alt', '⌥', 'Shift', 'Meta'].includes(\n normalizeKey(key)\n )\n );\n\n if (!nonModifierKey) return false;\n\n // Normalize the key for comparison\n const normalizedNonModifierKey = normalizeKey(nonModifierKey);\n\n // Compare the main key\n // For arrow keys, compare directly with event.key\n if (normalizedNonModifierKey.startsWith('Arrow')) {\n return event.key === normalizedNonModifierKey;\n }\n\n // For other keys, compare case-insensitive\n return event.key.toLowerCase() === normalizedNonModifierKey.toLowerCase();\n};\n\n/**\n * Get display key symbol for better visual representation\n */\nconst getDisplayKey = (key: string): string => {\n const displayMap: Record<string, string> = {\n ArrowUp: '↑',\n ArrowDown: '↓',\n ArrowLeft: '←',\n ArrowRight: '→',\n };\n\n return displayMap[key] || key;\n};\n\n/**\n * Get display shortcut based on OS (Mac uses ⌘ and ⌥, others use Ctrl and Alt)\n */\nconst getDisplayShortcut = (shortcut: string, isMac: boolean): string => {\n let result = shortcut;\n\n if (isMac) {\n result = result.replace(/Ctrl/g, '⌘');\n result = result.replace(/Alt/g, '⌥');\n } else {\n result = result.replace(/⌘/g, 'Ctrl');\n result = result.replace(/⌥/g, 'Alt');\n }\n\n // Replace arrow key names with symbols\n result = result.replace(/ArrowUp/g, '↑');\n result = result.replace(/ArrowDown/g, '↓');\n result = result.replace(/ArrowLeft/g, '←');\n result = result.replace(/ArrowRight/g, '→');\n\n return result;\n};\n\n/**\n * KeyboardShortcut Component\n *\n * A reusable component that displays keyboard shortcuts and listens for key combinations.\n * Automatically adapts to Mac (⌘, ⌥) and Windows/Linux (Ctrl, Alt) conventions.\n *\n * @example\n * ```tsx\n * <KeyboardShortcut\n * shortcut=\"⌘ + F\"\n * onTriggered={() => setShowSearch(true)}\n * />\n * ```\n */\nexport const KeyboardShortcut: FC<KeyboardShortcutProps> = ({\n shortcut,\n onTriggered,\n display = true,\n className,\n size = 'md',\n}) => {\n const { isMac } = useDevice();\n const displayShortcut = getDisplayShortcut(shortcut, isMac ?? false);\n const keys = parseShortcut(displayShortcut);\n const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n // Don't trigger shortcuts when typing in input fields\n const target = event.target as HTMLElement;\n const isInputField =\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable;\n\n // Update pressed keys state for visual feedback\n const currentKey = event.key;\n const normalizedEventKeys = new Set<string>();\n\n // Add modifier keys\n if (event.metaKey) normalizedEventKeys.add('⌘');\n if (event.ctrlKey) normalizedEventKeys.add('Ctrl');\n if (event.altKey) normalizedEventKeys.add(isMac ? '⌥' : 'Alt');\n if (event.shiftKey) normalizedEventKeys.add('Shift');\n\n // Add the main key\n if (currentKey.startsWith('Arrow')) {\n // For arrow keys, add both the key name and the symbol\n normalizedEventKeys.add(currentKey);\n const arrowSymbol = getDisplayKey(currentKey);\n normalizedEventKeys.add(arrowSymbol);\n } else {\n normalizedEventKeys.add(currentKey.toUpperCase());\n }\n\n setPressedKeys(normalizedEventKeys);\n\n // Trigger callback if shortcut matches\n if (onTriggered && matchesShortcut(event, keys)) {\n // Don't trigger shortcuts when typing in input fields\n if (isInputField) {\n return;\n }\n event.preventDefault();\n onTriggered();\n }\n };\n\n const handleKeyUp = () => {\n // Clear pressed keys when any key is released\n setPressedKeys(new Set());\n };\n\n window.addEventListener('keydown', handleKeyDown);\n window.addEventListener('keyup', handleKeyUp);\n window.addEventListener('blur', handleKeyUp); // Clear on window blur\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('keyup', handleKeyUp);\n window.removeEventListener('blur', handleKeyUp);\n };\n }, [keys, onTriggered]);\n\n if (!display) return null;\n\n /**\n * Check if a key is currently pressed\n */\n const isKeyPressed = (key: string): boolean => {\n const upperKey = key.toUpperCase();\n const normalizedKey = normalizeKey(key);\n\n return (\n pressedKeys.has(key) ||\n pressedKeys.has(upperKey) ||\n pressedKeys.has(normalizedKey) ||\n // Check for modifier key matches\n (key === '⌘' && pressedKeys.has('Meta')) ||\n (key === 'Ctrl' && pressedKeys.has('Control')) ||\n (key === '⌥' && pressedKeys.has('Alt')) ||\n (key === 'Alt' && pressedKeys.has('Alt')) ||\n // Check for arrow key symbols\n (key === '←' && pressedKeys.has('ArrowLeft')) ||\n (key === '→' && pressedKeys.has('ArrowRight')) ||\n (key === '↑' && pressedKeys.has('ArrowUp')) ||\n (key === '↓' && pressedKeys.has('ArrowDown'))\n );\n };\n\n return (\n <kbd\n className={cn(\n 'inline-flex items-center justify-center gap-0.5 p-0.5',\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n 'font-medium font-sans',\n 'border-1 border-neutral/20 text-neutral',\n size === 'sm' && 'text-xs',\n size === 'md' && 'text-sm',\n size === 'lg' && 'text-base',\n className\n )}\n >\n {keys.map((key, index) => {\n const keyId = `${key}-${index}-${shortcut}`;\n const displayKey = getDisplayKey(key);\n return (\n <span key={keyId} className=\"inline-flex items-center\">\n {index > 0 && <span className=\"text-neutral/50\">+</span>}\n <span\n className={cn(\n 'min-w-4 px-0.5',\n isKeyPressed(key) && 'scale-120 font-bold text-text'\n )}\n >\n {displayKey}\n </span>\n </span>\n );\n })}\n </kbd>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { KeyList, KeyboardShortcut } from "./KeyboardShortcut.mjs";
2
+
3
+ export { KeyList, KeyboardShortcut };
@@ -53,6 +53,26 @@ let LinkColor = /* @__PURE__ */ function(LinkColor$1) {
53
53
  LinkColor$1["CUSTOM"] = "custom";
54
54
  return LinkColor$1;
55
55
  }({});
56
+ /** Available rounded corner sizes for the container */
57
+ let LinkRoundedSize = /* @__PURE__ */ function(LinkRoundedSize$1) {
58
+ LinkRoundedSize$1["NONE"] = "none";
59
+ LinkRoundedSize$1["SM"] = "sm";
60
+ LinkRoundedSize$1["MD"] = "md";
61
+ LinkRoundedSize$1["LG"] = "lg";
62
+ LinkRoundedSize$1["XL"] = "xl";
63
+ LinkRoundedSize$1["TWO_XL"] = "2xl";
64
+ LinkRoundedSize$1["THREE_XL"] = "3xl";
65
+ LinkRoundedSize$1["FULL"] = "full";
66
+ return LinkRoundedSize$1;
67
+ }({});
68
+ let LinkSize = /* @__PURE__ */ function(LinkSize$1) {
69
+ LinkSize$1["SM"] = "sm";
70
+ LinkSize$1["MD"] = "md";
71
+ LinkSize$1["LG"] = "lg";
72
+ LinkSize$1["XL"] = "xl";
73
+ LinkSize$1["CUSTOM"] = "custom";
74
+ return LinkSize$1;
75
+ }({});
56
76
  /**
57
77
  * Underline style options for Link component
58
78
  *
@@ -71,14 +91,24 @@ let LinkUnderlined = /* @__PURE__ */ function(LinkUnderlined$1) {
71
91
  * Class variance authority configuration for Link component styling
72
92
  * Defines the visual appearance based on variant, color, and underline options
73
93
  */
74
- const linkVariants = cva("gap-3 transition focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50", {
94
+ const linkVariants = cva("gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50", {
75
95
  variants: {
76
96
  variant: {
77
97
  [`${LinkVariant.DEFAULT}`]: "h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0 hover:underline",
78
98
  [`${LinkVariant.INVISIBLE_LINK}`]: "h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0",
79
- [`${LinkVariant.BUTTON}`]: "flex min-h-8 items-center justify-center gap-2 whitespace-nowrap rounded-lg bg-current px-6 font-medium text-sm transition *:text-text-opposite focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 max-md:py-2",
80
- [`${LinkVariant.BUTTON_OUTLINED}`]: "flex min-h-8 items-center justify-center gap-2 whitespace-nowrap rounded-lg border-[1.5px] px-6 font-medium text-sm transition hover:bg-current/30 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 max-md:py-2",
81
- [`${LinkVariant.HOVERABLE}`]: "block rounded-lg border-none bg-current/0 transition hover:bg-current/20 aria-[current]:bg-current/5"
99
+ [`${LinkVariant.BUTTON}`]: "relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5",
100
+ [`${LinkVariant.BUTTON_OUTLINED}`]: "relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5",
101
+ [`${LinkVariant.HOVERABLE}`]: "block rounded-lg border-none bg-current/0 hover:bg-current/10 aria-[current]:bg-current/5"
102
+ },
103
+ roundedSize: {
104
+ [`${LinkRoundedSize.NONE}`]: "rounded-none",
105
+ [`${LinkRoundedSize.SM}`]: "rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl",
106
+ [`${LinkRoundedSize.MD}`]: "rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl",
107
+ [`${LinkRoundedSize.LG}`]: "rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl",
108
+ [`${LinkRoundedSize.XL}`]: "rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl",
109
+ [`${LinkRoundedSize.TWO_XL}`]: "rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]",
110
+ [`${LinkRoundedSize.THREE_XL}`]: "rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]",
111
+ [`${LinkRoundedSize.FULL}`]: "rounded-full"
82
112
  },
83
113
  color: {
84
114
  [`${LinkColor.PRIMARY}`]: "text-primary",
@@ -93,16 +123,97 @@ const linkVariants = cva("gap-3 transition focus-visible:outline-hidden disabled
93
123
  [`${LinkColor.SUCCESS}`]: "text-success",
94
124
  [`${LinkColor.CUSTOM}`]: ""
95
125
  },
126
+ size: {
127
+ [`${LinkSize.SM}`]: "text-sm",
128
+ [`${LinkSize.MD}`]: "text-base",
129
+ [`${LinkSize.LG}`]: "text-lg",
130
+ [`${LinkSize.XL}`]: "text-xl",
131
+ [`${LinkSize.CUSTOM}`]: ""
132
+ },
96
133
  underlined: {
97
134
  [LinkUnderlined.DEFAULT]: "",
98
135
  [LinkUnderlined.TRUE]: "underline",
99
136
  [LinkUnderlined.FALSE]: "no-underline"
100
137
  }
101
138
  },
139
+ compoundVariants: [
140
+ {
141
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
142
+ size: LinkSize.SM,
143
+ class: "min-h-7 px-3 max-md:py-1"
144
+ },
145
+ {
146
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
147
+ size: LinkSize.MD,
148
+ class: "min-h-8 px-6 max-md:py-2"
149
+ },
150
+ {
151
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
152
+ size: LinkSize.LG,
153
+ class: "min-h-10 px-8 max-md:py-3"
154
+ },
155
+ {
156
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
157
+ size: LinkSize.XL,
158
+ class: "min-h-11 px-10 max-md:py-4"
159
+ },
160
+ {
161
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
162
+ color: LinkColor.PRIMARY,
163
+ class: "ring-primary/20"
164
+ },
165
+ {
166
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
167
+ color: LinkColor.SECONDARY,
168
+ class: "ring-secondary/20"
169
+ },
170
+ {
171
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
172
+ color: LinkColor.DESTRUCTIVE,
173
+ class: "ring-destructive/20"
174
+ },
175
+ {
176
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
177
+ color: LinkColor.NEUTRAL,
178
+ class: "ring-neutral/20"
179
+ },
180
+ {
181
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
182
+ color: LinkColor.LIGHT,
183
+ class: "ring-white/20"
184
+ },
185
+ {
186
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
187
+ color: LinkColor.DARK,
188
+ class: "ring-neutral-800/20"
189
+ },
190
+ {
191
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
192
+ color: LinkColor.TEXT,
193
+ class: "ring-text/20"
194
+ },
195
+ {
196
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
197
+ color: LinkColor.TEXT_INVERSE,
198
+ class: "ring-text-opposite/20"
199
+ },
200
+ {
201
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
202
+ color: LinkColor.ERROR,
203
+ class: "ring-error/20"
204
+ },
205
+ {
206
+ variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],
207
+ color: LinkColor.SUCCESS,
208
+ class: "ring-success/20"
209
+ }
210
+ ],
102
211
  defaultVariants: {
103
212
  variant: LinkVariant.DEFAULT,
104
213
  color: LinkColor.PRIMARY,
105
- underlined: LinkUnderlined.DEFAULT
214
+ roundedSize: LinkRoundedSize.MD,
215
+ underlined: LinkUnderlined.DEFAULT,
216
+ size: LinkSize.MD
106
217
  }
107
218
  });
108
219
  /**
@@ -113,7 +224,7 @@ const linkVariants = cva("gap-3 transition focus-visible:outline-hidden disabled
113
224
  *
114
225
  * @example
115
226
  * ```tsx
116
- * checkIsExternalLink({ href: 'https://example.com' }) // true
227
+ * checkIsExternalLink({ href: '[https://example.com](https://example.com)' }) // true
117
228
  * checkIsExternalLink({ href: '/internal-page' }) // false
118
229
  * checkIsExternalLink({ href: '/page', isExternalLink: true }) // true
119
230
  * ```
@@ -127,93 +238,10 @@ const checkIsExternalLink = ({ href, isExternalLink: isExternalLinkProp }) => {
127
238
  *
128
239
  * A versatile link component that handles both internal and external navigation
129
240
  * with comprehensive internationalization support and multiple visual variants.
130
- *
131
- * ## Key Features
132
- * - **Multiple Variants**: Default, invisible, button, outlined button, and hoverable styles
133
- * - **Color Themes**: Comprehensive color palette for different contexts and meanings
134
- * - **External Link Detection**: Automatic detection and handling of external URLs
135
- * - **Internationalization**: Built-in support for localized URLs via Intlayer
136
- * - **Security**: Automatic security attributes for external links (noopener, noreferrer)
137
- * - **Accessibility**: Full ARIA support with proper labels and current page indication
138
- * - **Visual Feedback**: Hover effects, underline options, and active states
139
- *
140
- * ## Use Cases
141
- * - Navigation within applications (internal links)
142
- * - External links to other websites with security measures
143
- * - Button-styled links for call-to-action scenarios
144
- * - Subtle hoverable links for navigation menus
145
- * - Multi-language website navigation with automatic URL localization
146
- *
147
- * ## Security Features
148
- * External links automatically receive security attributes:
149
- * - `rel="noopener noreferrer nofollow"` - Prevents security vulnerabilities
150
- * - `target="_blank"` - Opens in new tab/window
151
- * - External link icon indication for user clarity
152
- *
153
- * ## Internationalization
154
- * When used with Intlayer, the component automatically:
155
- * - Localizes internal URLs based on the current or specified locale
156
- * - Sets appropriate `hrefLang` attributes for SEO
157
- * - Maintains proper URL structure for multi-language sites
158
- *
159
- * @component
160
- * @example
161
- * ```tsx
162
- * // Basic internal link
163
- * <Link href="/about" label="Go to about page">
164
- * About Us
165
- * </Link>
166
- *
167
- * // External link with auto-detection
168
- * <Link href="https://example.com" label="Visit external site">
169
- * External Site
170
- * </Link>
171
- *
172
- * // Button-styled link
173
- * <Link
174
- * href="/signup"
175
- * variant={LinkVariant.BUTTON}
176
- * color={LinkColor.PRIMARY}
177
- * label="Sign up for account"
178
- * >
179
- * Get Started
180
- * </Link>
181
- *
182
- * // Localized link
183
- * <Link
184
- * href="/products"
185
- * locale="fr"
186
- * label="Voir les produits"
187
- * >
188
- * Produits
189
- * </Link>
190
- *
191
- * // Active navigation link
192
- * <Link
193
- * href="/dashboard"
194
- * isActive={true}
195
- * variant={LinkVariant.HOVERABLE}
196
- * label="Current page: Dashboard"
197
- * >
198
- * Dashboard
199
- * </Link>
200
- * ```
201
- *
202
- * @param props - Link component props
203
- * @param props.children - Content to display inside the link
204
- * @param props.href - URL or path to navigate to
205
- * @param props.label - Accessible label describing the link's purpose
206
- * @param props.variant - Visual style variant
207
- * @param props.color - Color theme for the link
208
- * @param props.underlined - Underline visibility option
209
- * @param props.isExternalLink - Override external link detection
210
- * @param props.isActive - Whether this link represents the current page
211
- * @param props.locale - Locale for URL internationalization
212
- * @param props.className - Additional CSS classes
213
- * @returns Accessible and internationalized link component
241
+ * ...
214
242
  */
215
243
  const Link = (props) => {
216
- const { variant = LinkVariant.DEFAULT, color = LinkColor.PRIMARY, children, label, className, isActive, underlined, locale, isExternalLink: isExternalLinkProp, isPageSection: isPageSectionProp, href: hrefProp, ...otherProps } = props;
244
+ const { variant = LinkVariant.DEFAULT, color = LinkColor.PRIMARY, roundedSize, children, label, className, isActive, underlined, locale, size, isExternalLink: isExternalLinkProp, isPageSection: isPageSectionProp, href: hrefProp, ...otherProps } = props;
217
245
  const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);
218
246
  const isPageSection = isPageSectionProp ?? hrefProp?.startsWith("#") ?? false;
219
247
  const isChildrenString = typeof children === "string";
@@ -228,12 +256,14 @@ const Link = (props) => {
228
256
  className: cn(linkVariants({
229
257
  variant,
230
258
  color,
259
+ roundedSize,
231
260
  underlined,
261
+ size,
232
262
  className
233
263
  })),
234
264
  ...otherProps,
235
265
  children: [
236
- variant === "button" ? /* @__PURE__ */ jsx("span", { children }) : children,
266
+ children,
237
267
  isExternalLink && isChildrenString && /* @__PURE__ */ jsx(ExternalLink, { className: "ml-2 inline-block size-4" }),
238
268
  isPageSection && /* @__PURE__ */ jsx(MoveRight, { className: "ml-2 inline-block size-4" })
239
269
  ]
@@ -241,5 +271,5 @@ const Link = (props) => {
241
271
  };
242
272
 
243
273
  //#endregion
244
- export { Link, LinkColor, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants };
274
+ export { Link, LinkColor, LinkRoundedSize, LinkSize, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants };
245
275
  //# sourceMappingURL=Link.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Link.mjs","names":["Link: FC<LinkProps>"],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport type { AnchorHTMLAttributes, DetailedHTMLProps, FC } from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Visual style variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkVariant {\n /** Default underlined link with hover effects */\n DEFAULT = 'default',\n /** Link without visible underline or hover effects */\n INVISIBLE_LINK = 'invisible-link',\n /** Button-styled link with solid background */\n BUTTON = 'button',\n /** Button-styled link with outlined border */\n BUTTON_OUTLINED = 'button-outlined',\n /** Link with subtle hover background effect */\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkColor {\n /** Primary brand color */\n PRIMARY = 'primary',\n /** Secondary brand color */\n SECONDARY = 'secondary',\n /** Destructive/danger color for critical actions */\n DESTRUCTIVE = 'destructive',\n /** Neutral/muted color for less prominent links */\n NEUTRAL = 'neutral',\n /** Light color for dark backgrounds */\n LIGHT = 'light',\n /** Dark color for light backgrounds */\n DARK = 'dark',\n /** Default text color */\n TEXT = 'text',\n /** Inverse text color for opposite backgrounds */\n TEXT_INVERSE = 'text-inverse',\n /** Error/red color for error states */\n ERROR = 'error',\n /** Success/green color for positive actions */\n SUCCESS = 'success',\n /** Custom color - no default styling applied */\n CUSTOM = 'custom',\n}\n\n/**\n * Underline style options for Link component\n *\n * @enum {string}\n */\nexport enum LinkUnderlined {\n /** Default underline behavior based on variant */\n DEFAULT = 'default',\n /** Always show underline */\n TRUE = 'true',\n /** Never show underline */\n FALSE = 'false',\n}\n\n/**\n * Class variance authority configuration for Link component styling\n * Defines the visual appearance based on variant, color, and underline options\n */\nexport const linkVariants = cva(\n 'gap-3 transition focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n [`${LinkVariant.DEFAULT}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0 hover:underline',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0',\n [`${LinkVariant.BUTTON}`]:\n 'flex min-h-8 items-center justify-center gap-2 whitespace-nowrap rounded-lg bg-current px-6 font-medium text-sm transition *:text-text-opposite focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 max-md:py-2',\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'flex min-h-8 items-center justify-center gap-2 whitespace-nowrap rounded-lg border-[1.5px] px-6 font-medium text-sm transition hover:bg-current/30 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 max-md:py-2',\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 transition hover:bg-current/20 aria-[current]:bg-current/5',\n },\n color: {\n [`${LinkColor.PRIMARY}`]: 'text-primary',\n [`${LinkColor.SECONDARY}`]: 'text-secondary',\n [`${LinkColor.DESTRUCTIVE}`]: 'text-destructive',\n [`${LinkColor.NEUTRAL}`]: 'text-neutral',\n [`${LinkColor.LIGHT}`]: 'text-white',\n [`${LinkColor.DARK}`]: 'text-neutral-800',\n [`${LinkColor.TEXT}`]: 'text-text',\n [`${LinkColor.TEXT_INVERSE}`]: 'text-text-opposite',\n [`${LinkColor.ERROR}`]: 'text-error',\n [`${LinkColor.SUCCESS}`]: 'text-success',\n [`${LinkColor.CUSTOM}`]: '',\n },\n underlined: {\n [LinkUnderlined.DEFAULT]: '',\n [LinkUnderlined.TRUE]: 'underline',\n [LinkUnderlined.FALSE]: 'no-underline',\n },\n },\n\n defaultVariants: {\n variant: LinkVariant.DEFAULT,\n color: LinkColor.PRIMARY,\n underlined: LinkUnderlined.DEFAULT,\n },\n }\n);\n\n/**\n * Props interface for the Link component\n *\n * @interface LinkProps\n * @extends {DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>}\n * @extends {VariantProps<typeof linkVariants>}\n */\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n /**\n * Accessible label for screen readers (required)\n * Provides context about what the link does or where it leads\n * @example \"Navigate to home page\"\n */\n label: string;\n\n /**\n * Whether this link opens in a new tab/window\n * When true, adds target=\"_blank\" and security attributes\n * Auto-detected for URLs starting with http/https when undefined\n * @default undefined (auto-detect based on href)\n */\n isExternalLink?: boolean;\n\n /**\n * If a link is a page section as '#id'\n * @default false\n */\n isPageSection?: boolean;\n\n /**\n * Whether this link represents the current page/active state\n * Adds aria-current=\"page\" for accessibility\n * @default false\n */\n isActive?: boolean;\n\n /**\n * Locale for internationalized URLs\n * When provided, URLs are automatically localized using Intlayer\n * @example 'fr', 'es', 'en'\n */\n locale?: LocalesValues;\n };\n\n/**\n * Utility function to determine if a link should be treated as external\n *\n * @param props - Link component props containing href and isExternalLink\n * @returns {boolean} True if the link should open externally\n *\n * @example\n * ```tsx\n * checkIsExternalLink({ href: 'https://example.com' }) // true\n * checkIsExternalLink({ href: '/internal-page' }) // false\n * checkIsExternalLink({ href: '/page', isExternalLink: true }) // true\n * ```\n */\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: LinkProps): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\n/**\n * Link Component\n *\n * A versatile link component that handles both internal and external navigation\n * with comprehensive internationalization support and multiple visual variants.\n *\n * ## Key Features\n * - **Multiple Variants**: Default, invisible, button, outlined button, and hoverable styles\n * - **Color Themes**: Comprehensive color palette for different contexts and meanings\n * - **External Link Detection**: Automatic detection and handling of external URLs\n * - **Internationalization**: Built-in support for localized URLs via Intlayer\n * - **Security**: Automatic security attributes for external links (noopener, noreferrer)\n * - **Accessibility**: Full ARIA support with proper labels and current page indication\n * - **Visual Feedback**: Hover effects, underline options, and active states\n *\n * ## Use Cases\n * - Navigation within applications (internal links)\n * - External links to other websites with security measures\n * - Button-styled links for call-to-action scenarios\n * - Subtle hoverable links for navigation menus\n * - Multi-language website navigation with automatic URL localization\n *\n * ## Security Features\n * External links automatically receive security attributes:\n * - `rel=\"noopener noreferrer nofollow\"` - Prevents security vulnerabilities\n * - `target=\"_blank\"` - Opens in new tab/window\n * - External link icon indication for user clarity\n *\n * ## Internationalization\n * When used with Intlayer, the component automatically:\n * - Localizes internal URLs based on the current or specified locale\n * - Sets appropriate `hrefLang` attributes for SEO\n * - Maintains proper URL structure for multi-language sites\n *\n * @component\n * @example\n * ```tsx\n * // Basic internal link\n * <Link href=\"/about\" label=\"Go to about page\">\n * About Us\n * </Link>\n *\n * // External link with auto-detection\n * <Link href=\"https://example.com\" label=\"Visit external site\">\n * External Site\n * </Link>\n *\n * // Button-styled link\n * <Link\n * href=\"/signup\"\n * variant={LinkVariant.BUTTON}\n * color={LinkColor.PRIMARY}\n * label=\"Sign up for account\"\n * >\n * Get Started\n * </Link>\n *\n * // Localized link\n * <Link\n * href=\"/products\"\n * locale=\"fr\"\n * label=\"Voir les produits\"\n * >\n * Produits\n * </Link>\n *\n * // Active navigation link\n * <Link\n * href=\"/dashboard\"\n * isActive={true}\n * variant={LinkVariant.HOVERABLE}\n * label=\"Current page: Dashboard\"\n * >\n * Dashboard\n * </Link>\n * ```\n *\n * @param props - Link component props\n * @param props.children - Content to display inside the link\n * @param props.href - URL or path to navigate to\n * @param props.label - Accessible label describing the link's purpose\n * @param props.variant - Visual style variant\n * @param props.color - Color theme for the link\n * @param props.underlined - Underline visibility option\n * @param props.isExternalLink - Override external link detection\n * @param props.isActive - Whether this link represents the current page\n * @param props.locale - Locale for URL internationalization\n * @param props.className - Additional CSS classes\n * @returns Accessible and internationalized link component\n */\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.PRIMARY,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = typeof children === 'string';\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n linkVariants({\n variant,\n color,\n underlined,\n className,\n })\n )}\n {...otherProps}\n >\n {variant === 'button' ? <span>{children}</span> : children}\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAYA,IAAY,sDAAL;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;;;;;;;AAQF,IAAY,kDAAL;;AAEL;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;;;;;;AAQF,IAAY,4DAAL;;AAEL;;AAEA;;AAEA;;;;;;;AAOF,MAAa,eAAe,IAC1B,kGACA;CACE,UAAU;EACR,SAAS;IACN,GAAG,YAAY,YACd;IACD,GAAG,YAAY,mBACd;IACD,GAAG,YAAY,WACd;IACD,GAAG,YAAY,oBACd;IACD,GAAG,YAAY,cACd;GACH;EACD,OAAO;IACJ,GAAG,UAAU,YAAY;IACzB,GAAG,UAAU,cAAc;IAC3B,GAAG,UAAU,gBAAgB;IAC7B,GAAG,UAAU,YAAY;IACzB,GAAG,UAAU,UAAU;IACvB,GAAG,UAAU,SAAS;IACtB,GAAG,UAAU,SAAS;IACtB,GAAG,UAAU,iBAAiB;IAC9B,GAAG,UAAU,UAAU;IACvB,GAAG,UAAU,YAAY;IACzB,GAAG,UAAU,WAAW;GAC1B;EACD,YAAY;IACT,eAAe,UAAU;IACzB,eAAe,OAAO;IACtB,eAAe,QAAQ;GACzB;EACF;CAED,iBAAiB;EACf,SAAS,YAAY;EACrB,OAAO,UAAU;EACjB,YAAY,eAAe;EAC5B;CACF,CACF;;;;;;;;;;;;;;AA+DD,MAAa,uBAAuB,EAClC,MACA,gBAAgB,yBACQ;CACxB,MAAM,cAAc,OAAO,SAAS,YAAY,KAAK,MAAM,KAAK;AAOhE,QALE,uBAAuB,QACtB,OAAO,uBAAuB,eAC7B,eACA,eAAe,KAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+F/B,MAAaA,QAAuB,UAAU;CAC5C,MAAM,EACJ,UAAU,YAAY,SACtB,QAAQ,UAAU,SAClB,UACA,OACA,WACA,UACA,YACA,QACA,gBAAgB,oBAChB,eAAe,mBACf,MAAM,UACN,GAAG,eACD;CAEJ,MAAM,iBAAiB,sBAAsB,oBAAoB,MAAM;CACvE,MAAM,gBAAgB,qBAAqB,UAAU,WAAW,IAAI,IAAI;CAExE,MAAM,mBAAmB,OAAO,aAAa;CAE7C,MAAM,MAAM,iBAAiB,iCAAiC;CAE9D,MAAM,SAAS,iBAAiB,WAAW;AAO3C,QACE,qBAAC;EACC,MANF,UAAU,YAAY,CAAC,kBAAkB,CAAC,gBACtC,gBAAgB,UAAU,OAAO,GACjC;EAKF,cAAY;EACP;EACG;EACR,gBAAc,WAAW,SAAS;EAClC,WAAW,GACT,aAAa;GACX;GACA;GACA;GACA;GACD,CAAC,CACH;EACD,GAAI;;GAEH,YAAY,WAAW,oBAAC,UAAM,WAAgB,GAAG;GACjD,kBAAkB,oBACjB,oBAAC,gBAAa,WAAU,6BAA6B;GAEtD,iBAAiB,oBAAC,aAAU,WAAU,6BAA6B;;GAClE"}
1
+ {"version":3,"file":"Link.mjs","names":["Link: FC<LinkProps>"],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport type { AnchorHTMLAttributes, DetailedHTMLProps, FC } from 'react';\nimport { cn } from '../../utils/cn';\n\n/**\n * Visual style variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkVariant {\n /** Default underlined link with hover effects */\n DEFAULT = 'default',\n /** Link without visible underline or hover effects */\n INVISIBLE_LINK = 'invisible-link',\n /** Button-styled link with solid background */\n BUTTON = 'button',\n /** Button-styled link with outlined border */\n BUTTON_OUTLINED = 'button-outlined',\n /** Link with subtle hover background effect */\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n *\n * @enum {string}\n */\nexport enum LinkColor {\n /** Primary brand color */\n PRIMARY = 'primary',\n /** Secondary brand color */\n SECONDARY = 'secondary',\n /** Destructive/danger color for critical actions */\n DESTRUCTIVE = 'destructive',\n /** Neutral/muted color for less prominent links */\n NEUTRAL = 'neutral',\n /** Light color for dark backgrounds */\n LIGHT = 'light',\n /** Dark color for light backgrounds */\n DARK = 'dark',\n /** Default text color */\n TEXT = 'text',\n /** Inverse text color for opposite backgrounds */\n TEXT_INVERSE = 'text-inverse',\n /** Error/red color for error states */\n ERROR = 'error',\n /** Success/green color for positive actions */\n SUCCESS = 'success',\n /** Custom color - no default styling applied */\n CUSTOM = 'custom',\n}\n\n/** Available rounded corner sizes for the container */\nexport enum LinkRoundedSize {\n NONE = 'none',\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n TWO_XL = '2xl',\n THREE_XL = '3xl',\n FULL = 'full',\n}\n\nexport enum LinkSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n CUSTOM = 'custom',\n}\n\n/**\n * Underline style options for Link component\n *\n * @enum {string}\n */\nexport enum LinkUnderlined {\n /** Default underline behavior based on variant */\n DEFAULT = 'default',\n /** Always show underline */\n TRUE = 'true',\n /** Never show underline */\n FALSE = 'false',\n}\n\n/**\n * Class variance authority configuration for Link component styling\n * Defines the visual appearance based on variant, color, and underline options\n */\nexport const linkVariants = cva(\n 'gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n [`${LinkVariant.DEFAULT}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0 hover:underline',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-4 hover:bg-current/0',\n\n [`${LinkVariant.BUTTON}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 hover:bg-current/10 aria-[current]:bg-current/5',\n },\n roundedSize: {\n [`${LinkRoundedSize.NONE}`]: 'rounded-none',\n [`${LinkRoundedSize.SM}`]:\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n [`${LinkRoundedSize.MD}`]:\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n [`${LinkRoundedSize.LG}`]:\n 'rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl',\n [`${LinkRoundedSize.XL}`]:\n 'rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl',\n [`${LinkRoundedSize.TWO_XL}`]:\n 'rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]',\n [`${LinkRoundedSize.THREE_XL}`]:\n 'rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]',\n [`${LinkRoundedSize.FULL}`]: 'rounded-full',\n },\n color: {\n [`${LinkColor.PRIMARY}`]: 'text-primary',\n [`${LinkColor.SECONDARY}`]: 'text-secondary',\n [`${LinkColor.DESTRUCTIVE}`]: 'text-destructive',\n [`${LinkColor.NEUTRAL}`]: 'text-neutral',\n [`${LinkColor.LIGHT}`]: 'text-white',\n [`${LinkColor.DARK}`]: 'text-neutral-800',\n [`${LinkColor.TEXT}`]: 'text-text',\n [`${LinkColor.TEXT_INVERSE}`]: 'text-text-opposite',\n [`${LinkColor.ERROR}`]: 'text-error',\n [`${LinkColor.SUCCESS}`]: 'text-success',\n [`${LinkColor.CUSTOM}`]: '',\n },\n size: {\n [`${LinkSize.SM}`]: 'text-sm',\n [`${LinkSize.MD}`]: 'text-base',\n [`${LinkSize.LG}`]: 'text-lg',\n [`${LinkSize.XL}`]: 'text-xl',\n [`${LinkSize.CUSTOM}`]: '',\n },\n underlined: {\n [LinkUnderlined.DEFAULT]: '',\n [LinkUnderlined.TRUE]: 'underline',\n [LinkUnderlined.FALSE]: 'no-underline',\n },\n },\n // Compound variants handle height and padding\n compoundVariants: [\n // Min height and padding for button variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.SM,\n class: 'min-h-7 px-3 max-md:py-1',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.MD,\n class: 'min-h-8 px-6 max-md:py-2',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.LG,\n class: 'min-h-10 px-8 max-md:py-3',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.XL,\n class: 'min-h-11 px-10 max-md:py-4',\n },\n // Ring color variants for button (Chrome bug fix: ring-current/20 doesn't work properly)\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.PRIMARY,\n class: 'ring-primary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SECONDARY,\n class: 'ring-secondary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DESTRUCTIVE,\n class: 'ring-destructive/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.NEUTRAL,\n class: 'ring-neutral/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.LIGHT,\n class: 'ring-white/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DARK,\n class: 'ring-neutral-800/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT,\n class: 'ring-text/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT_INVERSE,\n class: 'ring-text-opposite/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.ERROR,\n class: 'ring-error/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SUCCESS,\n class: 'ring-success/20',\n },\n ],\n\n defaultVariants: {\n variant: LinkVariant.DEFAULT,\n color: LinkColor.PRIMARY,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\n/**\n * Props interface for the Link component\n *\n * @interface LinkProps\n * @extends {DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>}\n * @extends {VariantProps<typeof linkVariants>}\n */\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n /**\n * Accessible label for screen readers (required)\n * Provides context about what the link does or where it leads\n * @example \"Navigate to home page\"\n */\n label: string;\n\n /**\n * Whether this link opens in a new tab/window\n * When true, adds target=\"_blank\" and security attributes\n * Auto-detected for URLs starting with http/https when undefined\n * @default undefined (auto-detect based on href)\n */\n isExternalLink?: boolean;\n\n /**\n * If a link is a page section as '#id'\n * @default false\n */\n isPageSection?: boolean;\n\n /**\n * Whether this link represents the current page/active state\n * Adds aria-current=\"page\" for accessibility\n * @default false\n */\n isActive?: boolean;\n\n /**\n * Locale for internationalized URLs\n * When provided, URLs are automatically localized using Intlayer\n * @example 'fr', 'es', 'en'\n */\n locale?: LocalesValues;\n };\n\n/**\n * Utility function to determine if a link should be treated as external\n *\n * @param props - Link component props containing href and isExternalLink\n * @returns {boolean} True if the link should open externally\n *\n * @example\n * ```tsx\n * checkIsExternalLink({ href: '[https://example.com](https://example.com)' }) // true\n * checkIsExternalLink({ href: '/internal-page' }) // false\n * checkIsExternalLink({ href: '/page', isExternalLink: true }) // true\n * ```\n */\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: LinkProps): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\n/**\n * Link Component\n *\n * A versatile link component that handles both internal and external navigation\n * with comprehensive internationalization support and multiple visual variants.\n * ...\n */\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.PRIMARY,\n roundedSize,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n size,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = typeof children === 'string';\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {children}\n\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { Link, LinkColor, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants } from "./Link.mjs";
1
+ import { Link, LinkColor, LinkRoundedSize, LinkSize, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants } from "./Link.mjs";
2
2
 
3
- export { Link, LinkColor, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants };
3
+ export { Link, LinkColor, LinkRoundedSize, LinkSize, LinkUnderlined, LinkVariant, checkIsExternalLink, linkVariants };
@@ -80,7 +80,7 @@ const DesktopNavbar = ({ logo, sections, rightItems, selectedChoice }) => /* @__
80
80
  logo,
81
81
  /* @__PURE__ */ jsx(TabSelector, {
82
82
  selectedChoice,
83
- className: "ml-[2vw] gap-3 overflow-x-auto text-neutral tracking-wide lg:ml-[5vw] lg:gap-3 xl:ml-[10vw] xl:gap-6",
83
+ className: "ml-[2vw] h-auto gap-3 overflow-x-auto text-neutral tracking-wide lg:ml-[5vw] lg:gap-3 xl:ml-[10vw] xl:gap-6",
84
84
  tabs: sections,
85
85
  hoverable: true,
86
86
  color: TabSelectorColor.TEXT