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,10 @@
1
+ export type { BaseCodeBlockProps } from "./BaseCodeBlock.svelte";
2
+ export { default as BaseCodeBlock } from "./BaseCodeBlock.svelte";
3
+ export type { CodeBlockProps } from "./CodeBlock.svelte";
4
+ export { default as CodeBlock } from "./CodeBlock.svelte";
5
+ export type { CopyToClipboardButtonProps } from "./types";
6
+ export { default as CopyToClipboardButton } from "./CopyToClipboardButton.svelte";
7
+ export type { CodeFooterProps } from "./CodeFooter.svelte";
8
+ export { default as CodeFooter } from "./CodeFooter.svelte";
9
+ export type { CodeHeaderProps } from "./CodeHeader.svelte";
10
+ export { default as CodeHeader } from "./CodeHeader.svelte";
@@ -0,0 +1,5 @@
1
+ export { default as BaseCodeBlock } from "./BaseCodeBlock.svelte";
2
+ export { default as CodeBlock } from "./CodeBlock.svelte";
3
+ export { default as CopyToClipboardButton } from "./CopyToClipboardButton.svelte";
4
+ export { default as CodeFooter } from "./CodeFooter.svelte";
5
+ export { default as CodeHeader } from "./CodeHeader.svelte";
@@ -0,0 +1,85 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLButtonAttributes } from "svelte/elements";
3
+ import type { CodeBlockTheme, CodeStyling } from "../../utils/shiki/code-styling";
4
+ type CopyToClipboardButtonProps = {
5
+ textToCopy: string;
6
+ onCopied?: (result: "success" | "error", textToCopy?: string) => void;
7
+ class?: string;
8
+ showTooltip?: boolean;
9
+ codeBlockTheme?: CodeBlockTheme;
10
+ copyButtonAriaLabel?: string;
11
+ tooltipCopyText?: string;
12
+ tooltipCopiedText?: string;
13
+ } & Omit<HTMLButtonAttributes, "class">;
14
+ type CodeBlockProps = {
15
+ language?: string;
16
+ filename?: string;
17
+ icon?: string;
18
+ lang?: string;
19
+ class?: string;
20
+ /**
21
+ * Whether to show line numbers.
22
+ */
23
+ lines?: boolean;
24
+ /**
25
+ * Whether to wrap the code block.
26
+ */
27
+ wrap?: boolean;
28
+ /**
29
+ * Whether to expand the code block.
30
+ */
31
+ expandable?: boolean;
32
+ /**
33
+ * The lines to highlight. it's a stringified array of numbers.
34
+ * Example: "[1,3,4,5]"
35
+ */
36
+ highlight?: string;
37
+ /**
38
+ * The lines to focus on. it's a stringified array of numbers.
39
+ * Example: "[1,3,4,5]"
40
+ */
41
+ focus?: string;
42
+ /**
43
+ * Internal prop to set the number of lines in the code block.
44
+ * Users should not set this prop.
45
+ */
46
+ numberOfLines?: number;
47
+ /**
48
+ * Prop to hide the ask ai button
49
+ */
50
+ hideAskAiButton?: boolean;
51
+ /**
52
+ * Prop to set the small text size
53
+ */
54
+ isSmallText?: boolean;
55
+ /**
56
+ * Pass in from CodeSnippetFeedbackProvider
57
+ */
58
+ feedbackModalOpen?: boolean;
59
+ /**
60
+ * Pass in from CodeSnippetFeedbackProvider
61
+ */
62
+ anchorRef?: {
63
+ current: HTMLDivElement | null;
64
+ };
65
+ /**
66
+ * Prop to set the code block theme (code block UI theme)
67
+ */
68
+ codeBlockTheme?: CodeBlockTheme;
69
+ /**
70
+ * Prop to set the code block theme object (syntax highlighting theme)
71
+ */
72
+ codeBlockThemeObject?: CodeStyling;
73
+ /**
74
+ * Pass in AskAiCodeBlockButton component
75
+ */
76
+ askAiButton?: Snippet;
77
+ /**
78
+ * Pass in CodeSnippetFeedbackButton component
79
+ */
80
+ feedbackButton?: Snippet;
81
+ children?: Snippet;
82
+ copyButtonProps?: Omit<CopyToClipboardButtonProps, "textToCopy">;
83
+ ref?: HTMLDivElement;
84
+ };
85
+ export type { CodeBlockProps, CopyToClipboardButtonProps };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,327 @@
1
+ <script lang="ts">
2
+ import { getContext, setContext } from "svelte";
3
+ import { Classes } from "../../constants/selectors";
4
+ import { cn } from "../../utils/cn";
5
+ import { getCodeString } from "../../utils/shiki/lib";
6
+ import { Icon as ComponentIcon } from "../icon";
7
+ import BaseCodeBlock from "../code-block/BaseCodeBlock.svelte";
8
+ import CopyToClipboardButton from "../code-block/CopyToClipboardButton.svelte";
9
+ import type { CopyToClipboardButtonProps } from "../code-block/types";
10
+ import type { CodeBlockTheme, CodeStyling } from "../../utils/shiki/code-styling";
11
+ import LanguageDropdown from "./LanguageDropdown.svelte";
12
+ import {
13
+ CODE_GROUP_CONTEXT,
14
+ type CodeGroupChild,
15
+ type CodeGroupContext,
16
+ } from "./context";
17
+
18
+ type CodeGroupProps = {
19
+ dropdown?: boolean;
20
+ isSmallText?: boolean;
21
+ children?: import("svelte").Snippet;
22
+ noMargins?: boolean;
23
+ feedbackModalOpen?: boolean;
24
+ anchorRef?: { current: HTMLDivElement | null };
25
+ codeBlockTheme?: CodeBlockTheme;
26
+ codeBlockThemeObject?: CodeStyling;
27
+ initialSelectedTab?: number;
28
+ onSelectedTabChange?: (index: number) => void;
29
+ askAiButton?: import("svelte").Snippet;
30
+ feedbackButton?: import("svelte").Snippet;
31
+ class?: string;
32
+ copyButtonProps?: CopyToClipboardButtonProps;
33
+ };
34
+
35
+ let {
36
+ children,
37
+ isSmallText,
38
+ class: className,
39
+ noMargins,
40
+ dropdown,
41
+ feedbackModalOpen,
42
+ anchorRef,
43
+ codeBlockTheme = "system",
44
+ codeBlockThemeObject,
45
+ initialSelectedTab = 0,
46
+ onSelectedTabChange,
47
+ askAiButton,
48
+ feedbackButton,
49
+ copyButtonProps,
50
+ }: CodeGroupProps = $props();
51
+
52
+ let childArr = $state<CodeGroupChild[]>([]);
53
+ let selectedTab = $state(0);
54
+ let hasInitialisedSelection = false;
55
+ let tabBarRef = $state<HTMLDivElement>();
56
+ let rootRef = $state<HTMLDivElement>();
57
+
58
+ function register(child: CodeGroupChild) {
59
+ const existingIndex = childArr.findIndex((item) => item.id === child.id);
60
+ if (existingIndex === -1) {
61
+ childArr = [...childArr, child];
62
+ } else {
63
+ const nextChildren = [...childArr];
64
+ nextChildren[existingIndex] = child;
65
+ childArr = nextChildren;
66
+ }
67
+ }
68
+
69
+ function unregister(id: symbol) {
70
+ childArr = childArr.filter((child) => child.id !== id);
71
+ }
72
+
73
+ const codeGroupContext: CodeGroupContext = { register, unregister };
74
+ setContext(CODE_GROUP_CONTEXT, codeGroupContext);
75
+
76
+ $effect(() => {
77
+ if (!hasInitialisedSelection) {
78
+ selectedTab = initialSelectedTab;
79
+ hasInitialisedSelection = true;
80
+ }
81
+ });
82
+
83
+ let selectedIndex = $derived(
84
+ Math.min(
85
+ Math.max(0, Number(selectedTab)),
86
+ Math.max(0, childArr.length - 1)
87
+ )
88
+ );
89
+ let selectedChild = $derived(childArr[selectedIndex]);
90
+ let groupClass = $derived(
91
+ cn(
92
+ Classes.CodeGroup,
93
+ "not-prose relative mt-5 mb-8 flex flex-col overflow-hidden rounded-2xl border border-stone-950/10 p-0.5 dark:border-white/10",
94
+ noMargins && "my-0",
95
+ codeBlockTheme === "system" &&
96
+ "dark:codeblock-dark codeblock-light bg-stone-50 text-stone-950 dark:bg-white/5 dark:text-stone-50",
97
+ codeBlockTheme === "dark" &&
98
+ "codeblock-dark border-transparent bg-codeblock text-stone-50 dark:bg-white/5",
99
+ feedbackModalOpen && "border border-primary dark:border-primary-light",
100
+ className
101
+ )
102
+ );
103
+
104
+ $effect(() => {
105
+ if (anchorRef && rootRef) {
106
+ anchorRef.current = rootRef;
107
+ }
108
+ });
109
+
110
+ function focusTab(index: number) {
111
+ requestAnimationFrame(() => {
112
+ tabBarRef
113
+ ?.querySelector<HTMLElement>(`[data-tab-index="${index}"]`)
114
+ ?.focus();
115
+ });
116
+ }
117
+
118
+ function handleValueChange(value: number, restoreFocus = true) {
119
+ if (childArr.length === 0) {
120
+ return;
121
+ }
122
+
123
+ const index = Math.min(Math.max(0, value), childArr.length - 1);
124
+ const wasFocusOnTab =
125
+ typeof document !== "undefined" &&
126
+ document.activeElement?.getAttribute("role") === "tab";
127
+
128
+ // Important to clear hash to avoid collisions with tab groups
129
+ if (typeof window !== "undefined" && window.location.hash) {
130
+ window.history.replaceState(
131
+ null,
132
+ "",
133
+ window.location.pathname + window.location.search
134
+ );
135
+ }
136
+
137
+ selectedTab = index;
138
+ onSelectedTabChange?.(index);
139
+
140
+ if ((restoreFocus && wasFocusOnTab) || restoreFocus === true) {
141
+ focusTab(index);
142
+ }
143
+ }
144
+
145
+ function handleTabKeydown(event: KeyboardEvent, index: number) {
146
+ let nextIndex: number | undefined;
147
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
148
+ nextIndex = (index + 1) % childArr.length;
149
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
150
+ nextIndex = (index - 1 + childArr.length) % childArr.length;
151
+ } else if (event.key === "Home") {
152
+ nextIndex = 0;
153
+ } else if (event.key === "End") {
154
+ nextIndex = childArr.length - 1;
155
+ }
156
+
157
+ if (nextIndex !== undefined) {
158
+ event.preventDefault();
159
+ handleValueChange(nextIndex);
160
+ }
161
+ }
162
+ </script>
163
+
164
+ {#if children}
165
+ <div aria-hidden="true" class="hidden">{@render children()}</div>
166
+ {/if}
167
+
168
+ {#if childArr.length > 0}
169
+ <div bind:this={rootRef} class={groupClass} data-value={selectedIndex}>
170
+ <div
171
+ class={cn(
172
+ "relative flex items-center justify-between gap-2",
173
+ dropdown ? "px-2.5" : "pr-2.5"
174
+ )}
175
+ data-component-part="code-group-tab-bar"
176
+ bind:this={tabBarRef}
177
+ >
178
+ {#if dropdown}
179
+ <div class="flex min-w-0 items-center gap-1.5 font-medium text-xs">
180
+ {#if selectedChild?.icon}
181
+ <ComponentIcon
182
+ class={cn("size-3.5 bg-stone-500 dark:bg-stone-400", Classes.CodeBlockIcon)}
183
+ icon={selectedChild.icon}
184
+ iconType="regular"
185
+ overrideColor
186
+ />
187
+ {/if}
188
+ <span
189
+ class={cn(
190
+ "truncate",
191
+ codeBlockTheme === "system" && "text-stone-950 dark:text-stone-50",
192
+ codeBlockTheme === "dark" && "text-stone-50"
193
+ )}
194
+ >{selectedChild?.filename}</span>
195
+ </div>
196
+ {:else}
197
+ <div
198
+ class={cn(
199
+ "flex w-0 flex-1 gap-1 overflow-x-auto overflow-y-hidden rounded-tl-xl text-xs leading-6",
200
+ codeBlockTheme === "system"
201
+ ? "scrollbar-code-system"
202
+ : "scrollbar-code-dark"
203
+ )}
204
+ role="tablist"
205
+ aria-label="Code examples"
206
+ >
207
+ {#each childArr as child, index (child.id)}
208
+ <button
209
+ class={cn(
210
+ "group relative my-1 mb-1.5 ml-0! flex items-center gap-1.5 whitespace-nowrap font-medium outline-0 first:ml-2.5! focus-visible:outline-2",
211
+ selectedIndex === index &&
212
+ codeBlockTheme === "system" &&
213
+ "text-primary dark:text-primary-light",
214
+ selectedIndex === index &&
215
+ codeBlockTheme === "dark" &&
216
+ "text-primary-light",
217
+ selectedIndex !== index &&
218
+ codeBlockTheme === "system" &&
219
+ "text-stone-500 dark:text-stone-400",
220
+ selectedIndex !== index &&
221
+ codeBlockTheme === "dark" &&
222
+ "text-stone-400"
223
+ )}
224
+ type="button"
225
+ role="tab"
226
+ aria-selected={selectedIndex === index}
227
+ aria-controls={`code-group-panel-${index}`}
228
+ id={`code-group-tab-${index}`}
229
+ tabindex={selectedIndex === index ? 0 : -1}
230
+ data-tab-index={index}
231
+ onclick={() => handleValueChange(index)}
232
+ onkeydown={(event) => handleTabKeydown(event, index)}
233
+ >
234
+ <div
235
+ class={cn(
236
+ "z-10 flex items-center gap-1.5 rounded-lg px-1.5 focus:outline-none",
237
+ childArr.length > 1 &&
238
+ codeBlockTheme === "system" &&
239
+ "group-hover:bg-stone-200/50 group-hover:text-primary dark:group-hover:bg-stone-700/70 dark:group-hover:text-primary-light",
240
+ childArr.length > 1 &&
241
+ codeBlockTheme === "dark" &&
242
+ "group-hover:bg-stone-700/70 group-hover:text-primary-light"
243
+ )}
244
+ >
245
+ {#if child.icon}
246
+ <ComponentIcon
247
+ class={cn(
248
+ "h-3.5 w-3.5 bg-stone-500 dark:bg-stone-400",
249
+ codeBlockTheme === "system"
250
+ ? "group-hover:bg-primary dark:group-hover:bg-primary-light"
251
+ : "group-hover:bg-stone-700/70 group-hover:text-primary-light",
252
+ Classes.CodeBlockIcon
253
+ )}
254
+ color={selectedIndex === index ? "currentColor" : undefined}
255
+ icon={child.icon}
256
+ iconType="regular"
257
+ overrideColor
258
+ />
259
+ {/if}
260
+ {child.filename}
261
+ </div>
262
+ {#if selectedIndex === index}
263
+ <div class="absolute right-0 -bottom-1.5 left-0 h-0.5 rounded-full bg-primary dark:bg-primary-light"></div>
264
+ {/if}
265
+ </button>
266
+ {/each}
267
+ </div>
268
+ {/if}
269
+
270
+ <div class="flex shrink-0 items-center justify-end gap-1.5">
271
+ {#if dropdown}
272
+ <LanguageDropdown
273
+ codeBlockTheme={codeBlockTheme}
274
+ languages={childArr.map((child) => child.language || "")}
275
+ selectedLanguage={selectedChild?.language || ""}
276
+ setSelectedLanguage={(_language, index) => handleValueChange(index, false)}
277
+ />
278
+ {/if}
279
+ {#if feedbackButton}{@render feedbackButton()}{/if}
280
+ <CopyToClipboardButton
281
+ codeBlockTheme={codeBlockTheme}
282
+ textToCopy={getCodeString(selectedChild?.codeString, selectedChild?.class, true)}
283
+ {...(copyButtonProps as Omit<CopyToClipboardButtonProps, "textToCopy">)}
284
+ />
285
+ {#if askAiButton}{@render askAiButton()}{/if}
286
+ </div>
287
+ </div>
288
+
289
+ <div class="flex flex-1 overflow-hidden">
290
+ {#each childArr as child, index (child.id)}
291
+ <div
292
+ class="relative h-full max-h-full w-full min-w-full max-w-full"
293
+ id={`code-group-panel-${index}`}
294
+ role="tabpanel"
295
+ aria-labelledby={index === selectedIndex ? `code-group-tab-${index}` : undefined}
296
+ tabindex={-1}
297
+ hidden={index !== selectedIndex}
298
+ >
299
+ <BaseCodeBlock
300
+ class={child.class}
301
+ codeBlockTheme={codeBlockTheme}
302
+ codeBlockThemeObject={codeBlockThemeObject ?? codeBlockTheme}
303
+ codeString={child.codeString}
304
+ expandable={child.expandable && index === selectedIndex}
305
+ filename={child.filename}
306
+ focus={child.focus}
307
+ highlight={child.highlight}
308
+ isParentCodeGroup={true}
309
+ isSmallText={isSmallText}
310
+ lang={child.lang}
311
+ language={child.language}
312
+ lines={child.lines}
313
+ numberOfLines={child.numberOfLines}
314
+ shouldHighlight={index === selectedIndex}
315
+ wrap={child.wrap}
316
+ >
317
+ {#if child.children}{@render child.children()}{/if}
318
+ </BaseCodeBlock>
319
+ </div>
320
+ {/each}
321
+ </div>
322
+ </div>
323
+ {/if}
324
+
325
+ <script lang="ts" module>
326
+ export type { CodeGroupProps };
327
+ </script>
@@ -0,0 +1,24 @@
1
+ export type { CodeGroupProps };
2
+ import type { CopyToClipboardButtonProps } from "../code-block/types";
3
+ import type { CodeBlockTheme, CodeStyling } from "../../utils/shiki/code-styling";
4
+ type CodeGroupProps = {
5
+ dropdown?: boolean;
6
+ isSmallText?: boolean;
7
+ children?: import("svelte").Snippet;
8
+ noMargins?: boolean;
9
+ feedbackModalOpen?: boolean;
10
+ anchorRef?: {
11
+ current: HTMLDivElement | null;
12
+ };
13
+ codeBlockTheme?: CodeBlockTheme;
14
+ codeBlockThemeObject?: CodeStyling;
15
+ initialSelectedTab?: number;
16
+ onSelectedTabChange?: (index: number) => void;
17
+ askAiButton?: import("svelte").Snippet;
18
+ feedbackButton?: import("svelte").Snippet;
19
+ class?: string;
20
+ copyButtonProps?: CopyToClipboardButtonProps;
21
+ };
22
+ declare const CodeGroup: import("svelte").Component<CodeGroupProps, {}, "">;
23
+ type CodeGroup = ReturnType<typeof CodeGroup>;
24
+ export default CodeGroup;
@@ -0,0 +1,170 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+ import { cn } from "../../utils/cn";
4
+ import type { CodeBlockTheme, CodeStyling } from "../../utils/shiki/code-styling";
5
+ import BaseCodeBlock from "../code-block/BaseCodeBlock.svelte";
6
+ import CopyToClipboardButton from "../code-block/CopyToClipboardButton.svelte";
7
+ import type { CopyToClipboardButtonProps } from "../code-block/types";
8
+ import CodeSelectDropdown from "./CodeSelectDropdown.svelte";
9
+
10
+ const DEFAULT_CODE_SNIPPET_ARIA_LABEL = "Code snippet";
11
+
12
+ type ExampleCodeSnippet = {
13
+ filename: string;
14
+ code: string;
15
+ language: string;
16
+ audioUrl?: string;
17
+ };
18
+
19
+ type CodeGroupSelectProps = {
20
+ snippets: Record<string, Record<string, ExampleCodeSnippet>>;
21
+ class?: string;
22
+ syncedLabel?: string;
23
+ setSyncedLabel?: (label: string) => void;
24
+ setSelectedExampleIndex?: (index: number) => void;
25
+ askAiButton?: Snippet;
26
+ codeBlockTheme?: CodeBlockTheme;
27
+ codeBlockThemeObject?: CodeStyling;
28
+ codeSnippetAriaLabel?: string;
29
+ copyButtonProps?: CopyToClipboardButtonProps;
30
+ };
31
+
32
+ let {
33
+ snippets,
34
+ class: className,
35
+ syncedLabel,
36
+ setSyncedLabel,
37
+ setSelectedExampleIndex,
38
+ askAiButton,
39
+ codeBlockTheme = "system",
40
+ codeBlockThemeObject,
41
+ codeSnippetAriaLabel = DEFAULT_CODE_SNIPPET_ARIA_LABEL,
42
+ copyButtonProps,
43
+ }: CodeGroupSelectProps = $props();
44
+
45
+ let groups = $derived(Object.keys(snippets));
46
+ let selectedGroup = $state<string | undefined>();
47
+ let selectedOption = $state<string | undefined>();
48
+
49
+ let safeSelectedGroup = $derived(
50
+ selectedGroup && groups.includes(selectedGroup) ? selectedGroup : groups[0]
51
+ );
52
+ let groupSnippets = $derived(
53
+ safeSelectedGroup !== undefined ? snippets[safeSelectedGroup] : undefined
54
+ );
55
+ let options = $derived(
56
+ groupSnippets ? Object.keys(groupSnippets) : undefined
57
+ );
58
+ let safeSelectedOption = $derived(
59
+ selectedOption && options?.includes(selectedOption)
60
+ ? selectedOption
61
+ : options?.[0]
62
+ );
63
+ let snippet = $derived(
64
+ groupSnippets !== undefined && safeSelectedOption !== undefined
65
+ ? groupSnippets[safeSelectedOption]
66
+ : undefined
67
+ );
68
+
69
+ function handleGroupSelect(group: string) {
70
+ selectedGroup = group;
71
+ const newOptions = snippets[group] ? Object.keys(snippets[group]) : [];
72
+ const firstOption = newOptions[0];
73
+
74
+ if (firstOption !== undefined) {
75
+ selectedOption = firstOption;
76
+ setSelectedExampleIndex?.(0);
77
+ if (firstOption !== syncedLabel) {
78
+ setSyncedLabel?.(firstOption);
79
+ }
80
+ }
81
+ }
82
+
83
+ function handleOptionSelect(option: string) {
84
+ selectedOption = option;
85
+ const index = options?.indexOf(option) ?? -1;
86
+ setSelectedExampleIndex?.(index === -1 ? 0 : index);
87
+ if (option !== syncedLabel) {
88
+ setSyncedLabel?.(option);
89
+ }
90
+ }
91
+
92
+ $effect(() => {
93
+ if (
94
+ syncedLabel &&
95
+ syncedLabel !== safeSelectedOption &&
96
+ options?.includes(syncedLabel)
97
+ ) {
98
+ selectedOption = syncedLabel;
99
+ const index = options?.indexOf(syncedLabel) ?? -1;
100
+ setSelectedExampleIndex?.(index === -1 ? 0 : index);
101
+ }
102
+ });
103
+ </script>
104
+
105
+ <div
106
+ class={cn(
107
+ "not-prose relative flex min-w-full max-w-full flex-col overflow-hidden rounded-2xl p-0.5 text-xs leading-6",
108
+ "border border-gray-950/10 bg-gray-50 dark:border-white/10 dark:bg-white/5",
109
+ className
110
+ )}
111
+ data-testid="code-group-select"
112
+ >
113
+ <div class="flex w-full justify-between rounded-t-2xl text-xs leading-6">
114
+ <CodeSelectDropdown
115
+ options={groups}
116
+ selectedOption={safeSelectedGroup}
117
+ setSelectedOption={handleGroupSelect}
118
+ />
119
+ <div class="flex overflow-hidden">
120
+ {#if options}
121
+ <CodeSelectDropdown
122
+ options={options}
123
+ selectedOption={safeSelectedOption}
124
+ setSelectedOption={handleOptionSelect}
125
+ />
126
+ {/if}
127
+ <div
128
+ class="flex items-center gap-1.5 pr-2.5"
129
+ data-testid="code-group-select-copy-button"
130
+ >
131
+ <CopyToClipboardButton
132
+ codeBlockTheme={codeBlockTheme}
133
+ textToCopy={snippet?.code ?? ""}
134
+ {...(copyButtonProps as Omit<CopyToClipboardButtonProps, "textToCopy">)}
135
+ />
136
+ {#if askAiButton}{@render askAiButton()}{/if}
137
+ </div>
138
+ </div>
139
+ </div>
140
+
141
+ <section
142
+ aria-label={codeSnippetAriaLabel}
143
+ class="flex flex-1 overflow-hidden"
144
+ >
145
+ <div class="relative h-full max-h-full w-full min-w-full max-w-full">
146
+ {#if snippet?.audioUrl}
147
+ <div class="p-4">
148
+ <audio class="w-full" controls src={snippet.audioUrl}>
149
+ <track kind="captions" />
150
+ </audio>
151
+ </div>
152
+ {:else}
153
+ <BaseCodeBlock
154
+ codeBlockTheme={codeBlockTheme}
155
+ codeBlockThemeObject={codeBlockThemeObject ?? codeBlockTheme}
156
+ codeString={snippet?.code ?? ""}
157
+ isParentCodeGroup={true}
158
+ isSmallText={true}
159
+ language={snippet?.language}
160
+ >
161
+ {#snippet children()}{snippet?.code ?? ""}{/snippet}
162
+ </BaseCodeBlock>
163
+ {/if}
164
+ </div>
165
+ </section>
166
+ </div>
167
+
168
+ <script lang="ts" module>
169
+ export type { CodeGroupSelectProps, ExampleCodeSnippet };
170
+ </script>
@@ -0,0 +1,25 @@
1
+ export type { CodeGroupSelectProps, ExampleCodeSnippet };
2
+ import type { Snippet } from "svelte";
3
+ import type { CodeBlockTheme, CodeStyling } from "../../utils/shiki/code-styling";
4
+ import type { CopyToClipboardButtonProps } from "../code-block/types";
5
+ type ExampleCodeSnippet = {
6
+ filename: string;
7
+ code: string;
8
+ language: string;
9
+ audioUrl?: string;
10
+ };
11
+ type CodeGroupSelectProps = {
12
+ snippets: Record<string, Record<string, ExampleCodeSnippet>>;
13
+ class?: string;
14
+ syncedLabel?: string;
15
+ setSyncedLabel?: (label: string) => void;
16
+ setSelectedExampleIndex?: (index: number) => void;
17
+ askAiButton?: Snippet;
18
+ codeBlockTheme?: CodeBlockTheme;
19
+ codeBlockThemeObject?: CodeStyling;
20
+ codeSnippetAriaLabel?: string;
21
+ copyButtonProps?: CopyToClipboardButtonProps;
22
+ };
23
+ declare const CodeGroupSelect: import("svelte").Component<CodeGroupSelectProps, {}, "">;
24
+ type CodeGroupSelect = ReturnType<typeof CodeGroupSelect>;
25
+ export default CodeGroupSelect;