components-svelte 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/dist/components/Search.svelte +320 -0
  4. package/dist/components/Search.svelte.d.ts +31 -0
  5. package/dist/components/SearchButton.svelte +82 -0
  6. package/dist/components/SearchButton.svelte.d.ts +13 -0
  7. package/dist/components/SearchProvider.svelte +87 -0
  8. package/dist/components/SearchProvider.svelte.d.ts +17 -0
  9. package/dist/components/accordion/Accordion.svelte +150 -0
  10. package/dist/components/accordion/Accordion.svelte.d.ts +25 -0
  11. package/dist/components/accordion/AccordionCover.svelte +68 -0
  12. package/dist/components/accordion/AccordionCover.svelte.d.ts +13 -0
  13. package/dist/components/accordion/AccordionGroup.svelte +23 -0
  14. package/dist/components/accordion/AccordionGroup.svelte.d.ts +8 -0
  15. package/dist/components/accordion/accordion-url-utils.d.ts +4 -0
  16. package/dist/components/accordion/accordion-url-utils.js +48 -0
  17. package/dist/components/accordion/index.d.ts +29 -0
  18. package/dist/components/accordion/index.js +6 -0
  19. package/dist/components/badge/Badge.svelte +152 -0
  20. package/dist/components/badge/Badge.svelte.d.ts +23 -0
  21. package/dist/components/badge/index.d.ts +1 -0
  22. package/dist/components/badge/index.js +2 -0
  23. package/dist/components/callout/Callout.svelte +317 -0
  24. package/dist/components/callout/Callout.svelte.d.ts +17 -0
  25. package/dist/components/callout/Check.svelte +9 -0
  26. package/dist/components/callout/Check.svelte.d.ts +4 -0
  27. package/dist/components/callout/Danger.svelte +9 -0
  28. package/dist/components/callout/Danger.svelte.d.ts +4 -0
  29. package/dist/components/callout/Info.svelte +9 -0
  30. package/dist/components/callout/Info.svelte.d.ts +4 -0
  31. package/dist/components/callout/Note.svelte +9 -0
  32. package/dist/components/callout/Note.svelte.d.ts +4 -0
  33. package/dist/components/callout/Tip.svelte +9 -0
  34. package/dist/components/callout/Tip.svelte.d.ts +4 -0
  35. package/dist/components/callout/Warning.svelte +9 -0
  36. package/dist/components/callout/Warning.svelte.d.ts +4 -0
  37. package/dist/components/callout/index.d.ts +8 -0
  38. package/dist/components/callout/index.js +8 -0
  39. package/dist/components/card/Card.svelte +172 -0
  40. package/dist/components/card/Card.svelte.d.ts +21 -0
  41. package/dist/components/card/index.d.ts +3 -0
  42. package/dist/components/card/index.js +2 -0
  43. package/dist/components/code-block/BaseCodeBlock.svelte +249 -0
  44. package/dist/components/code-block/BaseCodeBlock.svelte.d.ts +10 -0
  45. package/dist/components/code-block/CodeBlock.svelte +185 -0
  46. package/dist/components/code-block/CodeBlock.svelte.d.ts +5 -0
  47. package/dist/components/code-block/CodeFooter.svelte +34 -0
  48. package/dist/components/code-block/CodeFooter.svelte.d.ts +8 -0
  49. package/dist/components/code-block/CodeHeader.svelte +52 -0
  50. package/dist/components/code-block/CodeHeader.svelte.d.ts +11 -0
  51. package/dist/components/code-block/CopyToClipboardButton.svelte +124 -0
  52. package/dist/components/code-block/CopyToClipboardButton.svelte.d.ts +4 -0
  53. package/dist/components/code-block/index.d.ts +10 -0
  54. package/dist/components/code-block/index.js +5 -0
  55. package/dist/components/code-block/types.d.ts +85 -0
  56. package/dist/components/code-block/types.js +1 -0
  57. package/dist/components/code-group/CodeGroup.svelte +327 -0
  58. package/dist/components/code-group/CodeGroup.svelte.d.ts +24 -0
  59. package/dist/components/code-group/CodeGroupSelect.svelte +170 -0
  60. package/dist/components/code-group/CodeGroupSelect.svelte.d.ts +25 -0
  61. package/dist/components/code-group/CodeSelectDropdown.svelte +74 -0
  62. package/dist/components/code-group/CodeSelectDropdown.svelte.d.ts +9 -0
  63. package/dist/components/code-group/LanguageDropdown.svelte +134 -0
  64. package/dist/components/code-group/LanguageDropdown.svelte.d.ts +11 -0
  65. package/dist/components/code-group/LanguageIcon.svelte +24 -0
  66. package/dist/components/code-group/LanguageIcon.svelte.d.ts +8 -0
  67. package/dist/components/code-group/context.d.ts +14 -0
  68. package/dist/components/code-group/context.js +2 -0
  69. package/dist/components/code-group/index.d.ts +8 -0
  70. package/dist/components/code-group/index.js +4 -0
  71. package/dist/components/color/Color.svelte +34 -0
  72. package/dist/components/color/Color.svelte.d.ts +10 -0
  73. package/dist/components/color/ColorItem.svelte +140 -0
  74. package/dist/components/color/ColorItem.svelte.d.ts +10 -0
  75. package/dist/components/color/ColorRow.svelte +27 -0
  76. package/dist/components/color/ColorRow.svelte.d.ts +8 -0
  77. package/dist/components/color/index.d.ts +1 -0
  78. package/dist/components/color/index.js +8 -0
  79. package/dist/components/columns/Box.svelte +15 -0
  80. package/dist/components/columns/Box.svelte.d.ts +7 -0
  81. package/dist/components/columns/Columns.svelte +31 -0
  82. package/dist/components/columns/Columns.svelte.d.ts +10 -0
  83. package/dist/components/columns/constants.d.ts +5 -0
  84. package/dist/components/columns/constants.js +3 -0
  85. package/dist/components/columns/index.d.ts +5 -0
  86. package/dist/components/columns/index.js +3 -0
  87. package/dist/components/expandable/Expandable.svelte +182 -0
  88. package/dist/components/expandable/Expandable.svelte.d.ts +22 -0
  89. package/dist/components/expandable/index.d.ts +3 -0
  90. package/dist/components/expandable/index.js +2 -0
  91. package/dist/components/frame/Frame.svelte +118 -0
  92. package/dist/components/frame/Frame.svelte.d.ts +15 -0
  93. package/dist/components/frame/index.d.ts +3 -0
  94. package/dist/components/frame/index.js +2 -0
  95. package/dist/components/icon/Icon.svelte +129 -0
  96. package/dist/components/icon/Icon.svelte.d.ts +18 -0
  97. package/dist/components/icon/index.d.ts +2 -0
  98. package/dist/components/icon/index.js +1 -0
  99. package/dist/components/index.d.ts +22 -0
  100. package/dist/components/index.js +22 -0
  101. package/dist/components/mermaid/Mermaid.svelte +181 -0
  102. package/dist/components/mermaid/Mermaid.svelte.d.ts +11 -0
  103. package/dist/components/mermaid/ZoomControls.svelte +74 -0
  104. package/dist/components/mermaid/ZoomControls.svelte.d.ts +12 -0
  105. package/dist/components/mermaid/index.d.ts +7 -0
  106. package/dist/components/mermaid/index.js +4 -0
  107. package/dist/components/mermaid/use-pan-zoom.svelte.d.ts +11 -0
  108. package/dist/components/mermaid/use-pan-zoom.svelte.js +41 -0
  109. package/dist/components/panel/Panel.svelte +27 -0
  110. package/dist/components/panel/Panel.svelte.d.ts +9 -0
  111. package/dist/components/panel/index.d.ts +3 -0
  112. package/dist/components/panel/index.js +2 -0
  113. package/dist/components/property/DeprecatedPill.svelte +16 -0
  114. package/dist/components/property/DeprecatedPill.svelte.d.ts +6 -0
  115. package/dist/components/property/InfoPill.svelte +32 -0
  116. package/dist/components/property/InfoPill.svelte.d.ts +10 -0
  117. package/dist/components/property/ParamHead.svelte +188 -0
  118. package/dist/components/property/ParamHead.svelte.d.ts +22 -0
  119. package/dist/components/property/Property.svelte +123 -0
  120. package/dist/components/property/Property.svelte.d.ts +24 -0
  121. package/dist/components/property/RequiredPill.svelte +16 -0
  122. package/dist/components/property/RequiredPill.svelte.d.ts +6 -0
  123. package/dist/components/property/index.d.ts +11 -0
  124. package/dist/components/property/index.js +6 -0
  125. package/dist/components/search/index.d.ts +7 -0
  126. package/dist/components/search/index.js +4 -0
  127. package/dist/components/search/use-search.d.ts +9 -0
  128. package/dist/components/search/use-search.js +6 -0
  129. package/dist/components/steps/Step.svelte +314 -0
  130. package/dist/components/steps/Step.svelte.d.ts +26 -0
  131. package/dist/components/steps/Steps.svelte +51 -0
  132. package/dist/components/steps/Steps.svelte.d.ts +11 -0
  133. package/dist/components/steps/constants.d.ts +4 -0
  134. package/dist/components/steps/constants.js +2 -0
  135. package/dist/components/steps/context.d.ts +10 -0
  136. package/dist/components/steps/context.js +2 -0
  137. package/dist/components/steps/index.d.ts +32 -0
  138. package/dist/components/steps/index.js +6 -0
  139. package/dist/components/tabs/Tabs.svelte +254 -0
  140. package/dist/components/tabs/Tabs.svelte.d.ts +16 -0
  141. package/dist/components/tabs/TabsItem.svelte +56 -0
  142. package/dist/components/tabs/TabsItem.svelte.d.ts +15 -0
  143. package/dist/components/tabs/context.d.ts +20 -0
  144. package/dist/components/tabs/context.js +2 -0
  145. package/dist/components/tabs/index.d.ts +27 -0
  146. package/dist/components/tabs/index.js +5 -0
  147. package/dist/components/tile/Tile.svelte +124 -0
  148. package/dist/components/tile/Tile.svelte.d.ts +12 -0
  149. package/dist/components/tile/index.d.ts +2 -0
  150. package/dist/components/tile/index.js +1 -0
  151. package/dist/components/tooltip/Tooltip.svelte +170 -0
  152. package/dist/components/tooltip/Tooltip.svelte.d.ts +23 -0
  153. package/dist/components/tooltip/index.d.ts +2 -0
  154. package/dist/components/tooltip/index.js +1 -0
  155. package/dist/components/tree/Tree.svelte +226 -0
  156. package/dist/components/tree/Tree.svelte.d.ts +9 -0
  157. package/dist/components/tree/TreeFile.svelte +44 -0
  158. package/dist/components/tree/TreeFile.svelte.d.ts +6 -0
  159. package/dist/components/tree/TreeFolder.svelte +107 -0
  160. package/dist/components/tree/TreeFolder.svelte.d.ts +10 -0
  161. package/dist/components/tree/context.d.ts +3 -0
  162. package/dist/components/tree/context.js +7 -0
  163. package/dist/components/tree/index.d.ts +10 -0
  164. package/dist/components/tree/index.js +9 -0
  165. package/dist/components/tree/tree-level-context.d.ts +8 -0
  166. package/dist/components/tree/tree-level-context.js +7 -0
  167. package/dist/components/tree/use-tree-level.d.ts +3 -0
  168. package/dist/components/tree/use-tree-level.js +5 -0
  169. package/dist/components/tree/utils.d.ts +9 -0
  170. package/dist/components/tree/utils.js +86 -0
  171. package/dist/components/update/Update.svelte +210 -0
  172. package/dist/components/update/Update.svelte.d.ts +34 -0
  173. package/dist/components/update/index.d.ts +4 -0
  174. package/dist/components/update/index.js +3 -0
  175. package/dist/components/view/View.svelte +52 -0
  176. package/dist/components/view/View.svelte.d.ts +14 -0
  177. package/dist/components/view/index.d.ts +3 -0
  178. package/dist/components/view/index.js +2 -0
  179. package/dist/constants/brands.d.ts +2 -0
  180. package/dist/constants/brands.js +4 -0
  181. package/dist/constants/index.d.ts +6 -0
  182. package/dist/constants/index.js +6 -0
  183. package/dist/constants/selectors.d.ts +125 -0
  184. package/dist/constants/selectors.js +125 -0
  185. package/dist/hooks/index.d.ts +8 -0
  186. package/dist/hooks/index.js +6 -0
  187. package/dist/hooks/use-expandable-memory.svelte.d.ts +6 -0
  188. package/dist/hooks/use-expandable-memory.svelte.js +89 -0
  189. package/dist/hooks/use-expandable.svelte.d.ts +15 -0
  190. package/dist/hooks/use-expandable.svelte.js +53 -0
  191. package/dist/hooks/use-get-shiki-highlighted-html.svelte.d.ts +8 -0
  192. package/dist/hooks/use-get-shiki-highlighted-html.svelte.js +36 -0
  193. package/dist/hooks/use-has-hover.d.ts +2 -0
  194. package/dist/hooks/use-has-hover.js +10 -0
  195. package/dist/hooks/use-is-dark-theme.svelte.d.ts +3 -0
  196. package/dist/hooks/use-is-dark-theme.svelte.js +25 -0
  197. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  198. package/dist/hooks/use-isomorphic-layout-effect.js +6 -0
  199. package/dist/index.d.ts +2 -0
  200. package/dist/index.js +2 -0
  201. package/dist/styles.css +2 -0
  202. package/dist/utils/cn.d.ts +3 -0
  203. package/dist/utils/cn.js +7 -0
  204. package/dist/utils/copy-to-clipboard.d.ts +4 -0
  205. package/dist/utils/copy-to-clipboard.js +50 -0
  206. package/dist/utils/dedent.d.ts +1 -0
  207. package/dist/utils/dedent.js +125 -0
  208. package/dist/utils/enhance-video-props.d.ts +4 -0
  209. package/dist/utils/enhance-video-props.js +25 -0
  210. package/dist/utils/get-node-text.d.ts +2 -0
  211. package/dist/utils/get-node-text.js +26 -0
  212. package/dist/utils/icon-utils.d.ts +18 -0
  213. package/dist/utils/icon-utils.js +30 -0
  214. package/dist/utils/is-absolute-url.d.ts +4 -0
  215. package/dist/utils/is-absolute-url.js +11 -0
  216. package/dist/utils/is-remote-url.d.ts +2 -0
  217. package/dist/utils/is-remote-url.js +12 -0
  218. package/dist/utils/make-marker-ids-unique.d.ts +2 -0
  219. package/dist/utils/make-marker-ids-unique.js +36 -0
  220. package/dist/utils/shiki/code-styling.d.ts +13 -0
  221. package/dist/utils/shiki/code-styling.js +1 -0
  222. package/dist/utils/shiki/constants.d.ts +21 -0
  223. package/dist/utils/shiki/constants.js +116 -0
  224. package/dist/utils/shiki/get-code-styling.d.ts +9 -0
  225. package/dist/utils/shiki/get-code-styling.js +38 -0
  226. package/dist/utils/shiki/get-shiki-background-colors.d.ts +20 -0
  227. package/dist/utils/shiki/get-shiki-background-colors.js +56 -0
  228. package/dist/utils/shiki/index.d.ts +30 -0
  229. package/dist/utils/shiki/index.js +209 -0
  230. package/dist/utils/shiki/lib.d.ts +4 -0
  231. package/dist/utils/shiki/lib.js +49 -0
  232. package/dist/utils/shiki/shiki-themes.d.ts +2 -0
  233. package/dist/utils/shiki/shiki-themes.js +64 -0
  234. package/dist/utils/shiki/snippet-presets.d.ts +27 -0
  235. package/dist/utils/shiki/snippet-presets.js +44 -0
  236. package/dist/utils/shiki/worker-client.d.ts +9 -0
  237. package/dist/utils/shiki/worker-client.js +22 -0
  238. package/dist/utils/shiki/worker.d.ts +1 -0
  239. package/dist/utils/shiki/worker.js +134 -0
  240. package/dist/utils/slugify.d.ts +2 -0
  241. package/dist/utils/slugify.js +9 -0
  242. package/package.json +100 -0
@@ -0,0 +1,32 @@
1
+ import Step from "./Step.svelte";
2
+ declare const Steps: import("svelte").Component<{
3
+ children?: import("svelte").Snippet;
4
+ titleSize?: import("./constants").StepTitleSize;
5
+ class?: string;
6
+ className?: string;
7
+ }, {}, ""> & {
8
+ Item: import("svelte").Component<{
9
+ icon?: string | import("svelte").Snippet;
10
+ stepNumber?: number | `${number}`;
11
+ iconType?: import("../../utils/icon-utils").IconType;
12
+ iconLibrary?: import("../../utils/icon-utils").IconLibrary;
13
+ title: string | import("svelte").Snippet;
14
+ children?: string | import("svelte").Snippet;
15
+ titleSize?: import("./constants").StepTitleSize;
16
+ class?: string;
17
+ className?: string;
18
+ isLast?: boolean;
19
+ id?: string;
20
+ noAnchor?: boolean;
21
+ scrollElementIntoView?: (id: string) => void;
22
+ onCopyAnchorLink?: (id: string | undefined) => void;
23
+ onRegisterHeading?: (id: string, rect: DOMRect) => void;
24
+ onUnregisterHeading?: (id: string) => void;
25
+ _hasContext?: boolean;
26
+ }, {}, "">;
27
+ };
28
+ export type { StepTitleSize } from "./constants";
29
+ export { STEP_TITLE_SIZES } from "./constants";
30
+ export type { default as StepProps } from "./Step.svelte";
31
+ export type { default as StepsProps } from "./Steps.svelte";
32
+ export { Step, Steps };
@@ -0,0 +1,6 @@
1
+ import Step from "./Step.svelte";
2
+ import StepsRoot from "./Steps.svelte";
3
+ // Preserve the React compound-component export for JavaScript consumers.
4
+ const Steps = Object.assign(StepsRoot, { Item: Step });
5
+ export { STEP_TITLE_SIZES } from "./constants";
6
+ export { Step, Steps };
@@ -0,0 +1,254 @@
1
+ <script module lang="ts">
2
+ let nextTabsId = 0;
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import { setContext } from "svelte";
7
+ import type { Snippet } from "svelte";
8
+ import Icon from "../icon/Icon.svelte";
9
+ import { Classes } from "../../constants/selectors";
10
+ import { cn } from "../../utils/cn";
11
+ import type { IconLibrary, IconType } from "../../utils/icon-utils";
12
+ import { TABS_CONTEXT, type TabsContext, type TabsItemRecord } from "./context";
13
+
14
+ const DEFAULT_TAB_TITLE = "Tab Title";
15
+
16
+ type TabsProps = {
17
+ children?: Snippet;
18
+ defaultTabIndex?: number;
19
+ onTabChange?: (tabIndex: number) => void;
20
+ class?: string;
21
+ className?: string;
22
+ borderBottom?: boolean;
23
+ ariaLabel?: string;
24
+ panelsRef?: { current: HTMLDivElement | null };
25
+ };
26
+
27
+ let {
28
+ children,
29
+ defaultTabIndex = 0,
30
+ onTabChange,
31
+ class: classAttribute,
32
+ className,
33
+ borderBottom,
34
+ ariaLabel,
35
+ panelsRef,
36
+ }: TabsProps = $props();
37
+
38
+ const uniqueId = `tabs-${++nextTabsId}`;
39
+
40
+ let items = $state<TabsItemRecord[]>([]);
41
+ // Svelte state captures defaultTabIndex only during the initial mount, matching the original behavior.
42
+ // svelte-ignore state_referenced_locally
43
+ let activeTabIndex = $state(Math.max(0, defaultTabIndex));
44
+ let tabRefs = $state<(HTMLLIElement | null)[]>([]);
45
+ let panelsElement = $state<HTMLDivElement | null>(null);
46
+
47
+ function register(item: TabsItemRecord) {
48
+ const existingIndex = items.findIndex((existing) => existing.id === item.id);
49
+ if (existingIndex === -1) {
50
+ items = [...items, item];
51
+ } else {
52
+ const nextItems = [...items];
53
+ nextItems[existingIndex] = item;
54
+ items = nextItems;
55
+ }
56
+ }
57
+
58
+ function unregister(id: symbol) {
59
+ items = items.filter((item) => item.id !== id);
60
+ }
61
+
62
+ const tabsContext: TabsContext = { register, unregister };
63
+ setContext(TABS_CONTEXT, tabsContext);
64
+
65
+ function slugify(value: string): string {
66
+ return value
67
+ .toLowerCase()
68
+ .trim()
69
+ .replace(/[^\w\s-]/g, "")
70
+ .replace(/[\s_-]+/g, "-")
71
+ .replace(/^-+|-+$/g, "");
72
+ }
73
+
74
+ let tabIds = $derived(
75
+ items.map((item, index) => {
76
+ if (item.customId) {
77
+ return item.customId;
78
+ }
79
+
80
+ const tabTitle = item.title ?? DEFAULT_TAB_TITLE;
81
+ return `${uniqueId}-${slugify(tabTitle)}-${index}`;
82
+ })
83
+ );
84
+
85
+ let selectedIndex = $derived(
86
+ items.length > 0
87
+ ? Math.max(0, Math.min(Number(activeTabIndex), items.length - 1))
88
+ : 0
89
+ );
90
+
91
+ $effect(() => {
92
+ if (items.length > 0 && activeTabIndex >= items.length) {
93
+ activeTabIndex = items.length - 1;
94
+ }
95
+ });
96
+
97
+ $effect(() => {
98
+ if (panelsRef) {
99
+ panelsRef.current = panelsElement;
100
+ }
101
+ });
102
+
103
+ function handleTabClick(index: number) {
104
+ if (index === activeTabIndex) {
105
+ return;
106
+ }
107
+
108
+ activeTabIndex = index;
109
+ onTabChange?.(index);
110
+ }
111
+
112
+ function focusTab(index: number) {
113
+ setTimeout(() => {
114
+ tabRefs[index]?.focus();
115
+ }, 0);
116
+ }
117
+
118
+ function handleKeyDown(event: KeyboardEvent, currentIndex: number) {
119
+ const tabCount = items.length;
120
+ if (tabCount === 0) {
121
+ return;
122
+ }
123
+
124
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
125
+ event.preventDefault();
126
+ const newIndex =
127
+ event.key === "ArrowLeft"
128
+ ? (currentIndex - 1 + tabCount) % tabCount
129
+ : (currentIndex + 1) % tabCount;
130
+ handleTabClick(newIndex);
131
+ focusTab(newIndex);
132
+ } else if (event.key === "Enter" || event.key === " ") {
133
+ event.preventDefault();
134
+ handleTabClick(currentIndex);
135
+ } else if (event.key === "Home") {
136
+ event.preventDefault();
137
+ handleTabClick(0);
138
+ focusTab(0);
139
+ } else if (event.key === "End") {
140
+ event.preventDefault();
141
+ const lastIndex = tabCount - 1;
142
+ handleTabClick(lastIndex);
143
+ focusTab(lastIndex);
144
+ }
145
+ }
146
+
147
+ let rootClass = $derived(
148
+ cn(
149
+ Classes.Tabs,
150
+ "tabs tab-container",
151
+ borderBottom && "border-stone-200 border-b pb-6 dark:border-stone-700",
152
+ classAttribute ?? className
153
+ )
154
+ );
155
+ </script>
156
+
157
+ <!--
158
+ Mint app integration:
159
+ - Wrap with a tab-state helper for URL hash sync, tab sync across components, and localStorage persistence
160
+ - The tab-state helper provides activeIndex and setActiveIndex for hash, sync, and persistence updates
161
+ - Connect onTabChange to setActiveIndex for full integration
162
+ - Pass panelsRef and use it to implement findInPanels for DOM-based navigation
163
+ - The component renders role="tabpanel" and aria-controls attributes used by DOM-based tab navigation
164
+ -->
165
+
166
+ {#if children}
167
+ <div aria-hidden="true" class="hidden">{@render children()}</div>
168
+ {/if}
169
+
170
+ {#if items.length > 0}
171
+ <div class={rootClass}>
172
+ <!-- Svelte keeps the tablist on the semantic ul used by the original component. -->
173
+ <ul
174
+ aria-label={ariaLabel ?? "Tabs"}
175
+ class="not-prose mb-6 flex min-w-full flex-none gap-x-6 overflow-auto border-stone-200 border-b pb-px dark:border-stone-700"
176
+ data-component-part="tabs-list"
177
+ role="tablist"
178
+ >
179
+ {#each items as item, index (item.id)}
180
+ {@const title = item.title ?? DEFAULT_TAB_TITLE}
181
+ {@const isActive = index === selectedIndex}
182
+ <!-- The original component uses the li as the complete tab control; keep that DOM contract. -->
183
+ <!-- svelte-ignore a11y_no_noninteractive_element_to_interactive_role -->
184
+ <li
185
+ bind:this={tabRefs[index]}
186
+ aria-controls={`panel-${tabIds[index]}`}
187
+ aria-selected={isActive}
188
+ class="cursor-pointer"
189
+ data-child-heading-ids={item.childHeadingIds}
190
+ data-child-tab-ids={item.childTabIds}
191
+ data-component-part="tab"
192
+ data-tab-index={index}
193
+ id={tabIds[index]}
194
+ onclick={(event) => {
195
+ event.stopPropagation();
196
+ handleTabClick(index);
197
+ }}
198
+ onkeydown={(event) => handleKeyDown(event, index)}
199
+ role="tab"
200
+ tabindex={isActive ? 0 : -1}
201
+ >
202
+ <div
203
+ class={cn(
204
+ "-mb-px flex max-w-max items-center gap-1.5 whitespace-nowrap border-b pt-3 pb-2.5 font-semibold text-sm leading-6",
205
+ isActive
206
+ ? "border-current text-primary dark:text-primary-light"
207
+ : "border-transparent text-stone-900 hover:border-stone-300 dark:text-stone-200 dark:hover:border-stone-700"
208
+ )}
209
+ data-active={isActive}
210
+ data-component-part="tab-button"
211
+ data-testid={`tab-${title}`}
212
+ >
213
+ {#if item.icon}
214
+ <Icon
215
+ class={cn(
216
+ "size-4 shrink-0",
217
+ isActive
218
+ ? "bg-primary dark:bg-primary-light"
219
+ : "bg-stone-900 dark:bg-stone-200",
220
+ Classes.TabIcon
221
+ )}
222
+ icon={item.icon}
223
+ iconLibrary={item.iconLibrary}
224
+ iconType={item.iconType}
225
+ overrideColor={true}
226
+ />
227
+ {/if}
228
+ {title}
229
+ </div>
230
+ </li>
231
+ {/each}
232
+ </ul>
233
+ <div bind:this={panelsElement} data-component-part="tabs-panels">
234
+ {#each items as item, index (item.id)}
235
+ {@const isActive = index === selectedIndex}
236
+ <div
237
+ aria-hidden={!isActive}
238
+ aria-labelledby={tabIds[index]}
239
+ class={cn("prose dark:prose-invert overflow-x-auto", !isActive && "hidden")}
240
+ data-component-part="tab-content"
241
+ id={`panel-${tabIds[index]}`}
242
+ role="tabpanel"
243
+ tabindex={isActive ? 0 : -1}
244
+ >
245
+ {#if typeof item.children === "string"}
246
+ {item.children}
247
+ {:else if item.children}
248
+ {@render item.children()}
249
+ {/if}
250
+ </div>
251
+ {/each}
252
+ </div>
253
+ </div>
254
+ {/if}
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from "svelte";
2
+ type TabsProps = {
3
+ children?: Snippet;
4
+ defaultTabIndex?: number;
5
+ onTabChange?: (tabIndex: number) => void;
6
+ class?: string;
7
+ className?: string;
8
+ borderBottom?: boolean;
9
+ ariaLabel?: string;
10
+ panelsRef?: {
11
+ current: HTMLDivElement | null;
12
+ };
13
+ };
14
+ declare const Tabs: import("svelte").Component<TabsProps, {}, "">;
15
+ type Tabs = ReturnType<typeof Tabs>;
16
+ export default Tabs;
@@ -0,0 +1,56 @@
1
+ <script lang="ts">
2
+ import { getContext, untrack } from "svelte";
3
+ import type { Snippet } from "svelte";
4
+ import type { IconLibrary, IconType } from "../../utils/icon-utils";
5
+ import { TABS_CONTEXT, type TabsContext } from "./context";
6
+
7
+ type TabsItemProps = {
8
+ id?: string;
9
+ title: string;
10
+ icon?: string;
11
+ iconType?: IconType;
12
+ iconLibrary?: IconLibrary;
13
+ children?: string | Snippet;
14
+ "data-child-tab-ids"?: string;
15
+ "data-child-heading-ids"?: string;
16
+ };
17
+
18
+ let {
19
+ id: customId,
20
+ title,
21
+ icon,
22
+ iconType,
23
+ iconLibrary,
24
+ children,
25
+ "data-child-tab-ids": childTabIds,
26
+ "data-child-heading-ids": childHeadingIds,
27
+ }: TabsItemProps = $props();
28
+
29
+ const tabsContext = getContext<TabsContext | undefined>(TABS_CONTEXT);
30
+ const itemId = Symbol("tabs-item");
31
+
32
+ // TabsItem is intentionally markup-free, preserving the original fragment-only item.
33
+ $effect(() => {
34
+ if (!tabsContext) {
35
+ return;
36
+ }
37
+
38
+ const item = {
39
+ id: itemId,
40
+ customId,
41
+ title,
42
+ icon,
43
+ iconType,
44
+ iconLibrary,
45
+ children,
46
+ childTabIds,
47
+ childHeadingIds,
48
+ };
49
+
50
+ // Track item prop changes, but never subscribe this effect to the parent's
51
+ // reactive items array while registration mutates it.
52
+ untrack(() => tabsContext.register(item));
53
+
54
+ return () => untrack(() => tabsContext.unregister(itemId));
55
+ });
56
+ </script>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { IconLibrary, IconType } from "../../utils/icon-utils";
3
+ type TabsItemProps = {
4
+ id?: string;
5
+ title: string;
6
+ icon?: string;
7
+ iconType?: IconType;
8
+ iconLibrary?: IconLibrary;
9
+ children?: string | Snippet;
10
+ "data-child-tab-ids"?: string;
11
+ "data-child-heading-ids"?: string;
12
+ };
13
+ declare const TabsItem: import("svelte").Component<TabsItemProps, {}, "">;
14
+ type TabsItem = ReturnType<typeof TabsItem>;
15
+ export default TabsItem;
@@ -0,0 +1,20 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { IconLibrary, IconType } from "../../utils/icon-utils";
3
+ type TabsItemRecord = {
4
+ id: symbol;
5
+ customId?: string;
6
+ title: string;
7
+ icon?: string;
8
+ iconType?: IconType;
9
+ iconLibrary?: IconLibrary;
10
+ children?: string | Snippet;
11
+ childTabIds?: string;
12
+ childHeadingIds?: string;
13
+ };
14
+ type TabsContext = {
15
+ register: (item: TabsItemRecord) => void;
16
+ unregister: (id: symbol) => void;
17
+ };
18
+ declare const TABS_CONTEXT: unique symbol;
19
+ export type { TabsContext, TabsItemRecord };
20
+ export { TABS_CONTEXT };
@@ -0,0 +1,2 @@
1
+ const TABS_CONTEXT = Symbol("tabs-context");
2
+ export { TABS_CONTEXT };
@@ -0,0 +1,27 @@
1
+ import TabsItem from "./TabsItem.svelte";
2
+ declare const Tabs: import("svelte").Component<{
3
+ children?: import("svelte").Snippet;
4
+ defaultTabIndex?: number;
5
+ onTabChange?: (tabIndex: number) => void;
6
+ class?: string;
7
+ className?: string;
8
+ borderBottom?: boolean;
9
+ ariaLabel?: string;
10
+ panelsRef?: {
11
+ current: HTMLDivElement | null;
12
+ };
13
+ }, {}, ""> & {
14
+ Item: import("svelte").Component<{
15
+ id?: string;
16
+ title: string;
17
+ icon?: string;
18
+ iconType?: import("../../utils/icon-utils").IconType;
19
+ iconLibrary?: import("../../utils/icon-utils").IconLibrary;
20
+ children?: string | import("svelte").Snippet;
21
+ "data-child-tab-ids"?: string;
22
+ "data-child-heading-ids"?: string;
23
+ }, {}, "">;
24
+ };
25
+ export type { default as TabsProps } from "./Tabs.svelte";
26
+ export type { default as TabsItemProps } from "./TabsItem.svelte";
27
+ export { Tabs, TabsItem };
@@ -0,0 +1,5 @@
1
+ import TabsItem from "./TabsItem.svelte";
2
+ import TabsRoot from "./Tabs.svelte";
3
+ // Preserve the React compound-component export for JavaScript consumers.
4
+ const Tabs = Object.assign(TabsRoot, { Item: TabsItem });
5
+ export { Tabs, TabsItem };
@@ -0,0 +1,124 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import { Classes } from "../../constants/selectors";
4
+ import { cn } from "../../utils/cn";
5
+ import { isRemoteUrl } from "../../utils/is-remote-url";
6
+
7
+ const SIZE = 24;
8
+ const PLUS_SIZE = 10;
9
+ const CENTER = SIZE / 2;
10
+
11
+ const createPlusPattern = (color: string) => {
12
+ const svg = `
13
+ <svg width="${SIZE}" height="${SIZE}" xmlns="http://www.w3.org/2000/svg">
14
+ <g opacity="0.5">
15
+ <line x1="${CENTER}" y1="${CENTER - PLUS_SIZE / 2}" x2="${CENTER}" y2="${CENTER + PLUS_SIZE / 2}"
16
+ stroke="${color}" stroke-width="1" stroke-linecap="round"/>
17
+ <line x1="${CENTER - PLUS_SIZE / 2}" y1="${CENTER}" x2="${CENTER + PLUS_SIZE / 2}" y2="${CENTER}"
18
+ stroke="${color}" stroke-width="1" stroke-linecap="round"/>
19
+ </g>
20
+ </svg>
21
+ `;
22
+
23
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
24
+ };
25
+
26
+ const LIGHT_PATTERN = createPlusPattern("#F0F0F0");
27
+ const DARK_PATTERN = createPlusPattern("#232323");
28
+ const BG_SIZE = `${SIZE}px ${SIZE}px`;
29
+
30
+ export type TileProps = {
31
+ href: string;
32
+ children?: string | Snippet;
33
+ title?: string;
34
+ description?: string;
35
+ class?: string;
36
+ className?: string;
37
+ };
38
+
39
+ let {
40
+ href,
41
+ children,
42
+ title,
43
+ description,
44
+ class: classAttribute,
45
+ className,
46
+ }: TileProps = $props();
47
+
48
+ let tileClass = $derived(
49
+ cn(
50
+ Classes.Tile,
51
+ "group not-prose flex w-full min-w-0 cursor-pointer flex-col items-center justify-center gap-1",
52
+ className ?? classAttribute
53
+ )
54
+ );
55
+ let isExternalLink = $derived(isRemoteUrl(href));
56
+ let hasText = $derived(!!title || !!description);
57
+ const backgroundPatternClasses = cn(
58
+ "pointer-events-none size-full select-none bg-center bg-repeat-round [grid-area:1/1]",
59
+ "after:absolute after:left-0 after:h-full after:w-[7px] after:bg-stone-50 after:content-[''] dark:after:bg-stone-900",
60
+ "before:absolute before:right-0 before:h-full before:w-[7px] before:bg-stone-50 before:content-[''] dark:before:bg-stone-900"
61
+ );
62
+ </script>
63
+
64
+ <!-- Svelte keeps the React anchor as the root so the complete tile remains clickable. -->
65
+ <a
66
+ class={tileClass}
67
+ href={href}
68
+ rel={isExternalLink ? "noreferrer" : undefined}
69
+ target={isExternalLink ? "_blank" : undefined}
70
+ >
71
+ <div
72
+ class="relative grid h-[170px] w-full place-items-center overflow-hidden rounded-2xl bg-stone-50 py-1 dark:bg-stone-900"
73
+ data-component-part="tile-children-container"
74
+ >
75
+ <div
76
+ aria-hidden="true"
77
+ class={cn(backgroundPatternClasses, "block dark:hidden")}
78
+ data-component-part="tile-background-light"
79
+ style={`background-image:url("${LIGHT_PATTERN}");background-size:${BG_SIZE}`}
80
+ ></div>
81
+ <div
82
+ aria-hidden="true"
83
+ class={cn(backgroundPatternClasses, "hidden dark:block")}
84
+ data-component-part="tile-background-dark"
85
+ style={`background-image:url("${DARK_PATTERN}");background-size:${BG_SIZE}`}
86
+ ></div>
87
+ <div
88
+ class="flex size-full items-center justify-center p-8 [grid-area:1/1] [&_svg]:h-auto [&_svg]:max-h-full [&_svg]:w-auto [&_svg]:max-w-full"
89
+ data-component-part="tile-children-inner-container"
90
+ >
91
+ {#if typeof children === "string"}
92
+ {children}
93
+ {:else if children}
94
+ {@render children()}
95
+ {/if}
96
+ </div>
97
+ </div>
98
+
99
+ {#if hasText}
100
+ <div
101
+ class="flex w-full min-w-0 flex-col items-center justify-center gap-1 p-2"
102
+ data-component-part="tile-text-container"
103
+ >
104
+ {#if title}
105
+ <p
106
+ class="m-0 max-w-full truncate font-medium text-base text-stone-900 tracking-[-0.2px] dark:text-stone-200"
107
+ data-component-part="tile-title"
108
+ title={title}
109
+ >
110
+ {title}
111
+ </p>
112
+ {/if}
113
+ {#if description}
114
+ <p
115
+ class="m-0 max-w-full truncate font-normal text-sm text-stone-600 tracking-[-0.1px] dark:text-stone-400"
116
+ data-component-part="tile-description"
117
+ title={description}
118
+ >
119
+ {description}
120
+ </p>
121
+ {/if}
122
+ </div>
123
+ {/if}
124
+ </a>
@@ -0,0 +1,12 @@
1
+ import type { Snippet } from "svelte";
2
+ export type TileProps = {
3
+ href: string;
4
+ children?: string | Snippet;
5
+ title?: string;
6
+ description?: string;
7
+ class?: string;
8
+ className?: string;
9
+ };
10
+ declare const Tile: import("svelte").Component<TileProps, {}, "">;
11
+ type Tile = ReturnType<typeof Tile>;
12
+ export default Tile;
@@ -0,0 +1,2 @@
1
+ export type { TileProps } from "./Tile.svelte";
2
+ export { default as Tile } from "./Tile.svelte";
@@ -0,0 +1 @@
1
+ export { default as Tile } from "./Tile.svelte";