twintrinsic 0.0.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 (212) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +150 -0
  3. package/dist/App/App.svelte +54 -0
  4. package/dist/App/App.svelte.d.ts +65 -0
  5. package/dist/Section.svelte +25 -0
  6. package/dist/Section.svelte.d.ts +34 -0
  7. package/dist/actions/clickOutside.d.ts +9 -0
  8. package/dist/actions/clickOutside.js +19 -0
  9. package/dist/actions/index.d.ts +1 -0
  10. package/dist/actions/index.js +1 -0
  11. package/dist/components/Accordion/Accordion.svelte +75 -0
  12. package/dist/components/Accordion/Accordion.svelte.d.ts +39 -0
  13. package/dist/components/Accordion/AccordionItem.svelte +150 -0
  14. package/dist/components/Accordion/AccordionItem.svelte.d.ts +30 -0
  15. package/dist/components/App/App.story.md +8 -0
  16. package/dist/components/App/App.story.svelte +170 -0
  17. package/dist/components/App/App.story.svelte.d.ts +22 -0
  18. package/dist/components/App/App.svelte +77 -0
  19. package/dist/components/App/App.svelte.d.ts +66 -0
  20. package/dist/components/App/Split.svelte +346 -0
  21. package/dist/components/App/Split.svelte.d.ts +54 -0
  22. package/dist/components/App/index.d.ts +2 -0
  23. package/dist/components/App/index.js +3 -0
  24. package/dist/components/AppHeader/AppHeader.svelte +439 -0
  25. package/dist/components/AppHeader/AppHeader.svelte.d.ts +24 -0
  26. package/dist/components/Avatar/Avatar.svelte +300 -0
  27. package/dist/components/Avatar/Avatar.svelte.d.ts +48 -0
  28. package/dist/components/Avatar/AvatarGroup.svelte +185 -0
  29. package/dist/components/Avatar/AvatarGroup.svelte.d.ts +46 -0
  30. package/dist/components/Badge/Badge.svelte +186 -0
  31. package/dist/components/Badge/Badge.svelte.d.ts +51 -0
  32. package/dist/components/BottomBar/BottomBar.svelte +146 -0
  33. package/dist/components/BottomBar/BottomBar.svelte.d.ts +38 -0
  34. package/dist/components/Breadcrumb/Breadcrumb.svelte +77 -0
  35. package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +42 -0
  36. package/dist/components/Breadcrumb/BreadcrumbItem.svelte +171 -0
  37. package/dist/components/Breadcrumb/BreadcrumbItem.svelte.d.ts +38 -0
  38. package/dist/components/Button/Button.svelte +252 -0
  39. package/dist/components/Button/Button.svelte.d.ts +80 -0
  40. package/dist/components/Button/ButtonGroup.svelte +127 -0
  41. package/dist/components/Button/ButtonGroup.svelte.d.ts +44 -0
  42. package/dist/components/Card/Card.svelte +152 -0
  43. package/dist/components/Card/Card.svelte.d.ts +55 -0
  44. package/dist/components/Carousel/Carousel.svelte +461 -0
  45. package/dist/components/Carousel/Carousel.svelte.d.ts +79 -0
  46. package/dist/components/Carousel/CarouselItem.svelte +149 -0
  47. package/dist/components/Carousel/CarouselItem.svelte.d.ts +35 -0
  48. package/dist/components/Chip/Chip.svelte +288 -0
  49. package/dist/components/Chip/Chip.svelte.d.ts +71 -0
  50. package/dist/components/Chip/ChipGroup.svelte +190 -0
  51. package/dist/components/Chip/ChipGroup.svelte.d.ts +71 -0
  52. package/dist/components/CodeBlock/CodeBlock.svelte +356 -0
  53. package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +44 -0
  54. package/dist/components/CodeBlock/index.d.ts +1 -0
  55. package/dist/components/CodeBlock/index.js +1 -0
  56. package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte +145 -0
  57. package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte.d.ts +44 -0
  58. package/dist/components/CodeEditor/CodeEditor.svelte +229 -0
  59. package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +23 -0
  60. package/dist/components/Combobox/Combobox.svelte +279 -0
  61. package/dist/components/Combobox/Combobox.svelte.d.ts +34 -0
  62. package/dist/components/Container/Container.svelte +45 -0
  63. package/dist/components/Container/Container.svelte.d.ts +36 -0
  64. package/dist/components/DataTable/DataTable.svelte +879 -0
  65. package/dist/components/DataTable/DataTable.svelte.d.ts +102 -0
  66. package/dist/components/Form/AutoComplete.svelte +357 -0
  67. package/dist/components/Form/AutoComplete.svelte.d.ts +73 -0
  68. package/dist/components/Form/Calendar.svelte +429 -0
  69. package/dist/components/Form/Calendar.svelte.d.ts +53 -0
  70. package/dist/components/Form/Checkbox.svelte +196 -0
  71. package/dist/components/Form/Checkbox.svelte.d.ts +50 -0
  72. package/dist/components/Form/ColorPicker.svelte +396 -0
  73. package/dist/components/Form/ColorPicker.svelte.d.ts +43 -0
  74. package/dist/components/Form/Combobox.svelte +645 -0
  75. package/dist/components/Form/Combobox.svelte.d.ts +93 -0
  76. package/dist/components/Form/Dropdown.svelte +773 -0
  77. package/dist/components/Form/Dropdown.svelte.d.ts +81 -0
  78. package/dist/components/Form/FileUpload.svelte +796 -0
  79. package/dist/components/Form/FileUpload.svelte.d.ts +78 -0
  80. package/dist/components/Form/FloatLabel.svelte +245 -0
  81. package/dist/components/Form/FloatLabel.svelte.d.ts +44 -0
  82. package/dist/components/Form/Form.svelte +281 -0
  83. package/dist/components/Form/Form.svelte.d.ts +54 -0
  84. package/dist/components/Form/FormField.svelte +218 -0
  85. package/dist/components/Form/FormField.svelte.d.ts +47 -0
  86. package/dist/components/Form/Input.svelte +340 -0
  87. package/dist/components/Form/Input.svelte.d.ts +79 -0
  88. package/dist/components/Form/InputSwitch.svelte +189 -0
  89. package/dist/components/Form/InputSwitch.svelte.d.ts +46 -0
  90. package/dist/components/Form/InvalidState.svelte +97 -0
  91. package/dist/components/Form/InvalidState.svelte.d.ts +37 -0
  92. package/dist/components/Form/Knob.svelte +537 -0
  93. package/dist/components/Form/Knob.svelte.d.ts +78 -0
  94. package/dist/components/Form/ListInput.svelte +469 -0
  95. package/dist/components/Form/ListInput.svelte.d.ts +70 -0
  96. package/dist/components/Form/Listbox.svelte +513 -0
  97. package/dist/components/Form/Listbox.svelte.d.ts +74 -0
  98. package/dist/components/Form/NumberInput.svelte +452 -0
  99. package/dist/components/Form/NumberInput.svelte.d.ts +82 -0
  100. package/dist/components/Form/Radio.svelte +192 -0
  101. package/dist/components/Form/Radio.svelte.d.ts +53 -0
  102. package/dist/components/Form/RadioGroup.svelte +155 -0
  103. package/dist/components/Form/RadioGroup.svelte.d.ts +48 -0
  104. package/dist/components/Form/Rating.svelte +380 -0
  105. package/dist/components/Form/Rating.svelte.d.ts +64 -0
  106. package/dist/components/Form/Select.svelte +436 -0
  107. package/dist/components/Form/Select.svelte.d.ts +49 -0
  108. package/dist/components/Form/SelectGroup.svelte +34 -0
  109. package/dist/components/Form/SelectGroup.svelte.d.ts +33 -0
  110. package/dist/components/Form/Slider.svelte +622 -0
  111. package/dist/components/Form/Slider.svelte.d.ts +73 -0
  112. package/dist/components/Form/Switch.svelte +192 -0
  113. package/dist/components/Form/Switch.svelte.d.ts +46 -0
  114. package/dist/components/Form/TextInput.svelte +274 -0
  115. package/dist/components/Form/TextInput.svelte.d.ts +74 -0
  116. package/dist/components/Form/Textarea.svelte +207 -0
  117. package/dist/components/Form/Textarea.svelte.d.ts +62 -0
  118. package/dist/components/Icon/Icon.svelte +140 -0
  119. package/dist/components/Icon/Icon.svelte.d.ts +25 -0
  120. package/dist/components/Icon/index.d.ts +1 -0
  121. package/dist/components/Icon/index.js +1 -0
  122. package/dist/components/Lazy/Lazy.svelte +158 -0
  123. package/dist/components/Lazy/Lazy.svelte.d.ts +42 -0
  124. package/dist/components/Masonry/Masonry.svelte +299 -0
  125. package/dist/components/Masonry/Masonry.svelte.d.ts +55 -0
  126. package/dist/components/Menu/Menu/Menu.svelte +65 -0
  127. package/dist/components/Menu/Menu/Menu.svelte.d.ts +17 -0
  128. package/dist/components/Menu/Menu/MenuItem.svelte +90 -0
  129. package/dist/components/Menu/Menu/MenuItem.svelte.d.ts +27 -0
  130. package/dist/components/Modal/Modal.svelte +334 -0
  131. package/dist/components/Modal/Modal.svelte.d.ts +55 -0
  132. package/dist/components/Panel/Card.svelte +141 -0
  133. package/dist/components/Panel/Card.svelte.d.ts +52 -0
  134. package/dist/components/Panel/Hero/Hero.story.md +9 -0
  135. package/dist/components/Panel/Hero/Hero.story.svelte +49 -0
  136. package/dist/components/Panel/Hero/Hero.story.svelte.d.ts +21 -0
  137. package/dist/components/Panel/Hero/Hero.svelte +24 -0
  138. package/dist/components/Panel/Hero/Hero.svelte.d.ts +32 -0
  139. package/dist/components/Panel/LazyPanel.svelte +110 -0
  140. package/dist/components/Panel/LazyPanel.svelte.d.ts +46 -0
  141. package/dist/components/Panel/Panel.svelte +205 -0
  142. package/dist/components/Panel/Panel.svelte.d.ts +23 -0
  143. package/dist/components/Progress/Progress.svelte +220 -0
  144. package/dist/components/Progress/Progress.svelte.d.ts +61 -0
  145. package/dist/components/Separator/Separator.svelte +109 -0
  146. package/dist/components/Separator/Separator.svelte.d.ts +35 -0
  147. package/dist/components/Sidebar/Sidebar.svelte +213 -0
  148. package/dist/components/Sidebar/Sidebar.svelte.d.ts +60 -0
  149. package/dist/components/Skeleton/Skeleton.svelte +170 -0
  150. package/dist/components/Skeleton/Skeleton.svelte.d.ts +48 -0
  151. package/dist/components/Stepper/Stepper.svelte +111 -0
  152. package/dist/components/Stepper/Stepper.svelte.d.ts +54 -0
  153. package/dist/components/Stepper/StepperStep.svelte +369 -0
  154. package/dist/components/Stepper/StepperStep.svelte.d.ts +63 -0
  155. package/dist/components/Table/Table.svelte +167 -0
  156. package/dist/components/Table/Table.svelte.d.ts +56 -0
  157. package/dist/components/Table/TableBody.svelte +41 -0
  158. package/dist/components/Table/TableBody.svelte.d.ts +33 -0
  159. package/dist/components/Table/TableCell.svelte +76 -0
  160. package/dist/components/Table/TableCell.svelte.d.ts +36 -0
  161. package/dist/components/Table/TableHead.svelte +41 -0
  162. package/dist/components/Table/TableHead.svelte.d.ts +32 -0
  163. package/dist/components/Table/TableHeader.svelte +148 -0
  164. package/dist/components/Table/TableHeader.svelte.d.ts +42 -0
  165. package/dist/components/Table/TableRow.svelte +99 -0
  166. package/dist/components/Table/TableRow.svelte.d.ts +40 -0
  167. package/dist/components/Tabs/Tab.svelte +145 -0
  168. package/dist/components/Tabs/Tab.svelte.d.ts +36 -0
  169. package/dist/components/Tabs/TabList.svelte +60 -0
  170. package/dist/components/Tabs/TabList.svelte.d.ts +32 -0
  171. package/dist/components/Tabs/TabPanel.svelte +118 -0
  172. package/dist/components/Tabs/TabPanel.svelte.d.ts +38 -0
  173. package/dist/components/Tabs/Tabs.svelte +287 -0
  174. package/dist/components/Tabs/Tabs.svelte.d.ts +50 -0
  175. package/dist/components/Tag/Tag.svelte +260 -0
  176. package/dist/components/Tag/Tag.svelte.d.ts +54 -0
  177. package/dist/components/Tag/TagGroup.svelte +147 -0
  178. package/dist/components/Tag/TagGroup.svelte.d.ts +62 -0
  179. package/dist/components/ThemeToggle/ThemeToggle.svelte +93 -0
  180. package/dist/components/ThemeToggle/ThemeToggle.svelte.d.ts +12 -0
  181. package/dist/components/Timeline/Timeline.svelte +144 -0
  182. package/dist/components/Timeline/Timeline.svelte.d.ts +48 -0
  183. package/dist/components/Timeline/TimelineItem.svelte +391 -0
  184. package/dist/components/Timeline/TimelineItem.svelte.d.ts +63 -0
  185. package/dist/components/Toast/Toast.svelte +313 -0
  186. package/dist/components/Toast/Toast.svelte.d.ts +44 -0
  187. package/dist/components/Toast/toastStore.d.ts +40 -0
  188. package/dist/components/Toast/toastStore.js +293 -0
  189. package/dist/components/Tooltip/Tooltip.svelte +282 -0
  190. package/dist/components/Tooltip/Tooltip.svelte.d.ts +55 -0
  191. package/dist/components/Tree/Tree.svelte +129 -0
  192. package/dist/components/Tree/Tree.svelte.d.ts +61 -0
  193. package/dist/components/Tree/TreeNode.svelte +332 -0
  194. package/dist/components/Tree/TreeNode.svelte.d.ts +55 -0
  195. package/dist/components/icons/TwintrinsicLogo.svelte +73 -0
  196. package/dist/components/icons/TwintrinsicLogo.svelte.d.ts +17 -0
  197. package/dist/components/icons/twintrinsic-source.svg +73 -0
  198. package/dist/components/icons/twintrinsic.svg +38 -0
  199. package/dist/docs/EventsTable.svelte +86 -0
  200. package/dist/docs/EventsTable.svelte.d.ts +27 -0
  201. package/dist/docs/PropsTable.svelte +103 -0
  202. package/dist/docs/PropsTable.svelte.d.ts +28 -0
  203. package/dist/docs/index.d.ts +2 -0
  204. package/dist/docs/index.js +2 -0
  205. package/dist/helpers/detectLanguage.d.ts +6 -0
  206. package/dist/helpers/detectLanguage.js +60 -0
  207. package/dist/helpers/index.d.ts +1 -0
  208. package/dist/helpers/index.js +1 -0
  209. package/dist/index.d.ts +86 -0
  210. package/dist/index.js +94 -0
  211. package/dist/twintrinsic.css +347 -0
  212. package/package.json +98 -0
@@ -0,0 +1,145 @@
1
+ <script>
2
+ import { highlightElement } from '@speed-highlight/core';
3
+ import { detectLanguage } from '@speed-highlight/core/detect';
4
+ import { onDestroy, onMount } from 'svelte';
5
+
6
+ const {
7
+ /** @type {string} - The language for syntax highlighting */
8
+ language = '',
9
+ /** @type {string} - Additional CSS classes */
10
+ class: className = '',
11
+ /** @type {boolean} - Whether to show rendering time */
12
+ showRenderTime = false,
13
+ } = $props();
14
+
15
+ // className is used in the template below
16
+
17
+ let code = $state('');
18
+ let copied = $state(false);
19
+ let copyTimeout = $state();
20
+ let codeElement = $state();
21
+ let renderTime = $state(0);
22
+
23
+ onMount(() => {
24
+ if (!codeElement) return;
25
+
26
+ code = codeElement.textContent || '';
27
+
28
+ const detectedLang = language || detectLanguage(code);
29
+
30
+ codeElement.className = `shj-lang-${detectedLang}`;
31
+
32
+ if (showRenderTime) {
33
+ const startTime = performance.now();
34
+ highlightElement(codeElement, detectedLang);
35
+ const endTime = performance.now();
36
+ renderTime = Math.round((endTime - startTime) * 100) / 100;
37
+ } else {
38
+ highlightElement(codeElement, detectedLang);
39
+ }
40
+ });
41
+
42
+ onDestroy(() => {
43
+ if (copyTimeout) {
44
+ clearTimeout(copyTimeout);
45
+ }
46
+ });
47
+
48
+ /**
49
+ * Copy code to clipboard
50
+ */
51
+ async function copyCode() {
52
+ if (copied) return;
53
+
54
+ try {
55
+ await navigator.clipboard.writeText(code);
56
+ copied = true;
57
+
58
+ copyTimeout = setTimeout(() => {
59
+ copied = false;
60
+ }, 2000);
61
+ } catch (error) {
62
+ console.error('Failed to copy code:', error);
63
+ }
64
+ }
65
+ </script>
66
+
67
+ <div class="code-block-speed {className}">
68
+ <div class="code-header">
69
+ <div class="code-header-left">
70
+ {#if language}
71
+ <div class="code-language">{language}</div>
72
+ {/if}
73
+ {#if showRenderTime && renderTime > 0}
74
+ <div class="code-render-time">{renderTime}ms</div>
75
+ {/if}
76
+ </div>
77
+ <button
78
+ type="button"
79
+ class="code-copy"
80
+ onclick={copyCode}
81
+ aria-label={copied ? 'Copied!' : 'Copy code'}
82
+ >
83
+ {#if copied}
84
+ <svg viewBox="0 0 24 24" width="16" height="16">
85
+ <path
86
+ fill="currentColor"
87
+ d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
88
+ />
89
+ </svg>
90
+ <span>Copied!</span>
91
+ {:else}
92
+ <svg viewBox="0 0 24 24" width="16" height="16">
93
+ <path
94
+ fill="currentColor"
95
+ d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"
96
+ />
97
+ </svg>
98
+ <span>Copy</span>
99
+ {/if}
100
+ </button>
101
+ </div>
102
+
103
+ <pre class="code-pre"><code bind:this={codeElement}><slot /></code></pre>
104
+ </div>
105
+
106
+ <style>
107
+ @reference '../../twintrinsic.css';
108
+
109
+ .code-block-speed {
110
+ @apply relative my-4 rounded-lg overflow-hidden;
111
+ @apply bg-surface border border-border;
112
+ }
113
+
114
+ .code-header {
115
+ @apply flex items-center justify-between px-4 py-2;
116
+ @apply bg-surface border-b border-border;
117
+ }
118
+
119
+ .code-header-left {
120
+ @apply flex items-center gap-3;
121
+ }
122
+
123
+ .code-language {
124
+ @apply text-xs font-mono text-muted;
125
+ }
126
+
127
+ .code-render-time {
128
+ @apply text-xs font-mono text-primary-600 dark:text-primary-400;
129
+ @apply px-2 py-1 rounded bg-primary-50 dark:bg-primary-900;
130
+ }
131
+
132
+ .code-copy {
133
+ @apply flex items-center gap-2 px-2 py-1;
134
+ @apply text-xs font-medium text-muted;
135
+ @apply rounded hover:bg-hover;
136
+ @apply transition-colors duration-150;
137
+ @apply focus:outline-none focus:ring-2 focus:ring-primary/50;
138
+ }
139
+
140
+ .code-pre {
141
+ @apply m-0 p-4 overflow-x-auto;
142
+ @apply font-mono text-sm;
143
+ @apply bg-surface dark:bg-surface;
144
+ }
145
+ </style>
@@ -0,0 +1,44 @@
1
+ export default CodeBlockSpeed;
2
+ type CodeBlockSpeed = SvelteComponent<$$__sveltets_2_PropsWithChildren<$$ComponentProps, {
3
+ default: {};
4
+ }>, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {
7
+ default: {};
8
+ }> & {
9
+ $$bindings?: "" | undefined;
10
+ };
11
+ declare const CodeBlockSpeed: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
12
+ language?: string;
13
+ class?: string;
14
+ showRenderTime?: boolean;
15
+ }, {
16
+ default: {};
17
+ }>, {
18
+ [evt: string]: CustomEvent<any>;
19
+ }, {
20
+ default: {};
21
+ }, {}, "">;
22
+ type $$ComponentProps = {
23
+ language?: string;
24
+ class?: string;
25
+ showRenderTime?: boolean;
26
+ };
27
+ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
28
+ default: any;
29
+ } ? Props extends Record<string, never> ? any : {
30
+ children?: any;
31
+ } : {});
32
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
33
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
34
+ $$bindings?: Bindings;
35
+ } & Exports;
36
+ (internal: unknown, props: Props & {
37
+ $$events?: Events;
38
+ $$slots?: Slots;
39
+ }): Exports & {
40
+ $set?: any;
41
+ $on?: any;
42
+ };
43
+ z_$$bindings?: Bindings;
44
+ }
@@ -0,0 +1,229 @@
1
+ <script>
2
+ import { EditorState } from '@codemirror/state';
3
+ import { EditorView } from '@codemirror/view';
4
+ import { onMount } from 'svelte';
5
+
6
+ const {
7
+ /** @type {string} - Initial code content */
8
+ code = '',
9
+ /** @type {string} - Language to use for syntax highlighting */
10
+ language = 'javascript',
11
+ /** @type {string} - Theme name to apply */
12
+ theme = 'light',
13
+ /** @type {string[]} - Array of extension URLs to load dynamically */
14
+ extensions = [],
15
+ /** @type {'jsdelivr' | 'esm.sh' | 'unpkg'} - CDN source for loading extensions */
16
+ cdnSource = 'esm.sh',
17
+ /** @type {(event: CustomEvent<string>) => void | undefined} - Callback when code changes */
18
+ onchange = undefined,
19
+ /** @type {string} - Height of the editor */
20
+ height = '400px',
21
+ } = $props();
22
+
23
+ /** @type {HTMLDivElement | undefined} */
24
+ let container;
25
+ /** @type {any} */
26
+ let view;
27
+
28
+ /**
29
+ * Constructs the CDN URL for loading a package
30
+ * @param {string} packageName - Package name
31
+ * @param {string} version - Package version
32
+ * @returns {string} CDN URL
33
+ */
34
+ function getCdnUrl(packageName, version = 'latest') {
35
+ switch (cdnSource) {
36
+ case 'jsdelivr':
37
+ return `https://cdn.jsdelivr.net/npm/${packageName}@${version}/+esm`;
38
+ case 'unpkg':
39
+ return `https://unpkg.com/${packageName}@${version}?module`;
40
+ case 'esm.sh':
41
+ default:
42
+ return `https://esm.sh/${packageName}@${version}`;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Dynamically loads an extension from a CDN
48
+ * @param {string} extensionUrl - URL to load extension from
49
+ * @returns {Promise<any|null>} Loaded extension or null
50
+ */
51
+ async function loadExtension(extensionUrl) {
52
+ try {
53
+ const module = await import(/* @vite-ignore */ extensionUrl);
54
+ const ext = module.default || Object.values(module)[0];
55
+ return ext;
56
+ } catch (error) {
57
+ console.error(`Failed to load extension from ${extensionUrl}:`, error);
58
+ return null;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Loads language support dynamically
64
+ * @param {string} lang - Language name
65
+ * @returns {Promise<any|null>} Language extension or null
66
+ */
67
+ async function loadLanguageSupport(lang) {
68
+ /** @type {Record<string, string>} */
69
+ const languageMap = {
70
+ javascript: '@codemirror/lang-javascript',
71
+ typescript: '@codemirror/lang-javascript',
72
+ python: '@codemirror/lang-python',
73
+ html: '@codemirror/lang-html',
74
+ css: '@codemirror/lang-css',
75
+ json: '@codemirror/lang-json',
76
+ xml: '@codemirror/lang-xml',
77
+ markdown: '@codemirror/lang-markdown',
78
+ sql: '@codemirror/lang-sql',
79
+ java: '@codemirror/lang-java',
80
+ cpp: '@codemirror/lang-cpp',
81
+ rust: '@codemirror/lang-rust',
82
+ go: '@codemirror/lang-go',
83
+ php: '@codemirror/lang-php',
84
+ vue: '@codemirror/lang-vue',
85
+ svelte: '@codemirror/lang-svelte',
86
+ };
87
+
88
+ const packageName = languageMap[lang.toLowerCase()];
89
+ if (!packageName) {
90
+ console.warn(`Language support for ${lang} not available`);
91
+ return null;
92
+ }
93
+
94
+ try {
95
+ const url = getCdnUrl(packageName);
96
+ const module = await import(/* @vite-ignore */ url);
97
+ const langFn = module[lang.toLowerCase()] || module.default;
98
+ return langFn?.() || null;
99
+ } catch (error) {
100
+ console.error(`Failed to load language support for ${lang}:`, error);
101
+ return null;
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Loads theme dynamically
107
+ * @param {string} themeName - Theme name
108
+ * @returns {Promise<any|null>} Theme extension or null
109
+ */
110
+ async function loadTheme(themeName) {
111
+ /** @type {Record<string, string>} */
112
+ const themeMap = {
113
+ 'one-dark': '@codemirror/theme-one-dark',
114
+ 'dracula': '@codemirror/theme-dracula',
115
+ 'material-dark': '@codemirror/theme-material-dark',
116
+ 'nord': '@codemirror/theme-nord',
117
+ 'solarized-light': '@codemirror/theme-solarized-light',
118
+ 'solarized-dark': '@codemirror/theme-solarized-dark',
119
+ 'sublime': '@codemirror/theme-sublime',
120
+ 'ayu-light': '@codemirror/theme-ayu-light',
121
+ 'ayu-dark': '@codemirror/theme-ayu-dark',
122
+ };
123
+
124
+ const packageName = themeMap[themeName.toLowerCase()];
125
+ if (!packageName) {
126
+ console.warn(`Theme ${themeName} not available`);
127
+ return null;
128
+ }
129
+
130
+ try {
131
+ const url = getCdnUrl(packageName);
132
+ const module = await import(/* @vite-ignore */ url);
133
+ const themeFn = module[themeName.toLowerCase().replace(/-/g, '')] || module.default;
134
+ return themeFn || null;
135
+ } catch (error) {
136
+ console.error(`Failed to load theme ${themeName}:`, error);
137
+ return null;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Initializes the editor with all extensions
143
+ */
144
+ async function initializeEditor() {
145
+ const exts = [];
146
+
147
+ const langExt = await loadLanguageSupport(language);
148
+ if (langExt) exts.push(langExt);
149
+
150
+ if (theme !== 'light') {
151
+ const themeExt = await loadTheme(theme);
152
+ if (themeExt) exts.push(themeExt);
153
+ }
154
+
155
+ for (const extUrl of extensions) {
156
+ const ext = await loadExtension(extUrl);
157
+ if (ext) exts.push(ext);
158
+ }
159
+
160
+ exts.push(EditorView.lineNumbers());
161
+ exts.push(EditorView.highlightActiveLineGutter());
162
+ exts.push(EditorView.foldGutter());
163
+
164
+ const state = EditorState.create({
165
+ doc: code,
166
+ extensions: exts,
167
+ });
168
+
169
+ view = new EditorView({
170
+ state,
171
+ parent: container,
172
+ dispatch: (/** @type {any} */ tr) => {
173
+ view.update([tr]);
174
+ if (tr.docChanged) {
175
+ const newCode = tr.newDoc.toString();
176
+ onchange?.(new CustomEvent('change', { detail: newCode }));
177
+ }
178
+ },
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Updates the code content
184
+ * @param {string} newCode - New code to set
185
+ */
186
+ function setCode(newCode) {
187
+ if (view) {
188
+ const changes = {
189
+ from: 0,
190
+ to: view.state.doc.length,
191
+ insert: newCode,
192
+ };
193
+ view.dispatch({ changes });
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Gets the current code content
199
+ * @returns {string} Current code
200
+ */
201
+ function getCode() {
202
+ return view?.state.doc.toString() || code;
203
+ }
204
+
205
+ onMount(() => {
206
+ initializeEditor();
207
+
208
+ return () => {
209
+ if (view) {
210
+ view.destroy();
211
+ }
212
+ };
213
+ });
214
+ </script>
215
+
216
+ <div
217
+ bind:this={container}
218
+ class="code-editor-wrapper"
219
+ style="height: {height}; overflow: hidden; border: 1px solid var(--color-border, #e5e7eb);"
220
+ ></div>
221
+
222
+ <style>
223
+ @reference "../../twintrinsic.css";
224
+
225
+ .code-editor-wrapper {
226
+ font-family: 'Fira Code', 'Courier New', monospace;
227
+ font-size: 14px;
228
+ }
229
+ </style>
@@ -0,0 +1,23 @@
1
+ export default CodeEditor;
2
+ type CodeEditor = {
3
+ $on?(type: string, callback: (e: any) => void): () => void;
4
+ $set?(props: Partial<$$ComponentProps>): void;
5
+ };
6
+ declare const CodeEditor: import("svelte").Component<{
7
+ code?: string;
8
+ language?: string;
9
+ theme?: string;
10
+ extensions?: any[];
11
+ cdnSource?: string;
12
+ onchange?: any;
13
+ height?: string;
14
+ }, {}, "">;
15
+ type $$ComponentProps = {
16
+ code?: string;
17
+ language?: string;
18
+ theme?: string;
19
+ extensions?: any[];
20
+ cdnSource?: string;
21
+ onchange?: any;
22
+ height?: string;
23
+ };
@@ -0,0 +1,279 @@
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte"
3
+
4
+ const {
5
+ class: className = "",
6
+ id = crypto.randomUUID(),
7
+ name,
8
+ options = [],
9
+ value = null,
10
+ placeholder = "Select an option",
11
+ optionLabel = "label",
12
+ optionValue = "value",
13
+ disabled = false,
14
+ searchable = false,
15
+ clearable = false,
16
+ ariaLabel,
17
+ children,
18
+ } = $props()
19
+
20
+ const dispatch = createEventDispatcher()
21
+
22
+ let isOpen = $state(false)
23
+ let searchValue = $state("")
24
+ let highlightedIndex = $state(-1)
25
+ let selectedValue = $state(null)
26
+ let inputElement
27
+
28
+ $effect(() => {
29
+ selectedValue = value
30
+ })
31
+
32
+ const getOptionLabel = (option) => {
33
+ if (typeof option === "object" && option !== null) {
34
+ return option[optionLabel]
35
+ }
36
+ return option
37
+ }
38
+
39
+ const getOptionValue = (option) => {
40
+ if (typeof option === "object" && option !== null) {
41
+ return option[optionValue]
42
+ }
43
+ return option
44
+ }
45
+
46
+ const filteredOptions = $derived.by(() => {
47
+ if (!searchable || !searchValue) {
48
+ return options
49
+ }
50
+ return options.filter((option) =>
51
+ getOptionLabel(option).toLowerCase().includes(searchValue.toLowerCase())
52
+ )
53
+ })
54
+
55
+ const handleInputFocus = () => {
56
+ isOpen = true
57
+ }
58
+
59
+ const handleInputBlur = (e) => {
60
+ if (!e.relatedTarget?.closest(".combobox-dropdown")) {
61
+ isOpen = false
62
+ }
63
+ }
64
+
65
+ const handleInputChange = (e) => {
66
+ if (searchable) {
67
+ searchValue = e.target.value
68
+ }
69
+ }
70
+
71
+ const handleOptionClick = (option) => {
72
+ const newValue = getOptionValue(option)
73
+ selectedValue = newValue
74
+ isOpen = false
75
+ searchValue = ""
76
+ dispatch("change", { value: newValue, option })
77
+ }
78
+
79
+ const handleClear = (e) => {
80
+ e.stopPropagation()
81
+ selectedValue = null
82
+ searchValue = ""
83
+ dispatch("change", { value: null, option: null })
84
+ inputElement?.focus()
85
+ }
86
+
87
+ const handleKeydown = (e) => {
88
+ if (!isOpen) {
89
+ if (e.key === "Enter" || e.key === " ") {
90
+ e.preventDefault()
91
+ isOpen = true
92
+ }
93
+ return
94
+ }
95
+
96
+ switch (e.key) {
97
+ case "ArrowDown":
98
+ e.preventDefault()
99
+ highlightedIndex = Math.min(highlightedIndex + 1, filteredOptions.length - 1)
100
+ break
101
+ case "ArrowUp":
102
+ e.preventDefault()
103
+ highlightedIndex = Math.max(highlightedIndex - 1, -1)
104
+ break
105
+ case "Enter":
106
+ e.preventDefault()
107
+ if (highlightedIndex >= 0) {
108
+ handleOptionClick(filteredOptions[highlightedIndex])
109
+ }
110
+ break
111
+ case "Escape":
112
+ e.preventDefault()
113
+ isOpen = false
114
+ break
115
+ }
116
+ }
117
+
118
+ const selectedLabel = $derived.by(() => {
119
+ if (selectedValue === null || selectedValue === undefined) {
120
+ return placeholder
121
+ }
122
+ const selected = options.find((opt) => getOptionValue(opt) === selectedValue)
123
+ return selected ? getOptionLabel(selected) : placeholder
124
+ })
125
+ </script>
126
+
127
+ <style>
128
+ @reference '$lib/twintrinsic.css';
129
+
130
+ .combobox-wrapper {
131
+ position: relative;
132
+ display: inline-block;
133
+ width: 100%;
134
+ }
135
+
136
+ .combobox-input {
137
+ width: 100%;
138
+ padding: 0.5rem 0.75rem;
139
+ border: 1px solid var(--color-border);
140
+ border-radius: 0.375rem;
141
+ background-color: var(--color-background);
142
+ color: var(--color-text);
143
+ font-size: 1rem;
144
+ transition: all 0.2s ease;
145
+ }
146
+
147
+ .combobox-input:focus {
148
+ outline: none;
149
+ border-color: var(--color-primary);
150
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
151
+ }
152
+
153
+ .combobox-input:disabled {
154
+ background-color: var(--color-disabled);
155
+ cursor: not-allowed;
156
+ opacity: 0.5;
157
+ }
158
+
159
+ .combobox-input-wrapper {
160
+ position: relative;
161
+ display: flex;
162
+ align-items: center;
163
+ }
164
+
165
+ .combobox-clear {
166
+ position: absolute;
167
+ right: 0.5rem;
168
+ background: none;
169
+ border: none;
170
+ cursor: pointer;
171
+ padding: 0.25rem;
172
+ color: var(--color-text-secondary);
173
+ transition: color 0.2s ease;
174
+ }
175
+
176
+ .combobox-clear:hover {
177
+ color: var(--color-text);
178
+ }
179
+
180
+ .combobox-dropdown {
181
+ position: absolute;
182
+ top: 100%;
183
+ left: 0;
184
+ right: 0;
185
+ margin-top: 0.25rem;
186
+ background-color: var(--color-background);
187
+ border: 1px solid var(--color-border);
188
+ border-radius: 0.375rem;
189
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
190
+ max-height: 300px;
191
+ overflow-y: auto;
192
+ z-index: 10;
193
+ }
194
+
195
+ .combobox-option {
196
+ padding: 0.5rem 0.75rem;
197
+ cursor: pointer;
198
+ transition: background-color 0.2s ease;
199
+ }
200
+
201
+ .combobox-option:hover,
202
+ .combobox-option.highlighted {
203
+ background-color: var(--color-hover);
204
+ }
205
+
206
+ .combobox-option.selected {
207
+ background-color: var(--color-primary);
208
+ color: white;
209
+ }
210
+
211
+ .combobox-empty {
212
+ padding: 1rem;
213
+ text-align: center;
214
+ color: var(--color-text-secondary);
215
+ }
216
+ </style>
217
+
218
+ <div class="combobox-wrapper {className}" {id}>
219
+ <div class="combobox-input-wrapper">
220
+ <input
221
+ bind:this={inputElement}
222
+ type="text"
223
+ class="combobox-input"
224
+ {placeholder}
225
+ {disabled}
226
+ value={searchable ? searchValue : selectedLabel}
227
+ on:focus={handleInputFocus}
228
+ on:blur={handleInputBlur}
229
+ on:change={handleInputChange}
230
+ on:keydown={handleKeydown}
231
+ aria-label={ariaLabel}
232
+ aria-description={ariaDescription}
233
+ aria-haspopup="listbox"
234
+ aria-expanded={isOpen}
235
+ {name}
236
+ />
237
+ {#if clearable && value !== null && value !== undefined}
238
+ <button
239
+ class="combobox-clear"
240
+ on:click={handleClear}
241
+ aria-label="Clear selection"
242
+ tabindex="-1"
243
+ >
244
+
245
+ </button>
246
+ {/if}
247
+ </div>
248
+
249
+ {#if isOpen && filteredOptions.length > 0}
250
+ <div class="combobox-dropdown" bind:this={dropdownElement} role="listbox">
251
+ {#each filteredOptions as option, index}
252
+ <div
253
+ class="combobox-option"
254
+ class:highlighted={index === highlightedIndex}
255
+ class:selected={getOptionValue(option) === value}
256
+ on:click={() => handleOptionClick(option)}
257
+ on:keydown={(e) => {
258
+ if (e.key === "Enter") {
259
+ handleOptionClick(option)
260
+ }
261
+ }}
262
+ role="option"
263
+ aria-selected={getOptionValue(option) === value}
264
+ tabindex="-1"
265
+ >
266
+ {#if children}
267
+ {@render children(option)}
268
+ {:else}
269
+ {getOptionLabel(option)}
270
+ {/if}
271
+ </div>
272
+ {/each}
273
+ </div>
274
+ {:else if isOpen}
275
+ <div class="combobox-dropdown">
276
+ <div class="combobox-empty">No options available</div>
277
+ </div>
278
+ {/if}
279
+ </div>