@placeholderco/placeholder-ui 1.0.12 → 2.0.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 (276) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +134 -130
  3. package/dist/app.css +178 -0
  4. package/dist/bootstrap.min.css +3600 -0
  5. package/dist/cards/GitCard.svelte +115 -0
  6. package/dist/cards/GitCard.svelte.d.ts +22 -0
  7. package/dist/display/Avatar.svelte +29 -17
  8. package/dist/display/Avatar.svelte.d.ts +12 -2
  9. package/dist/display/LinkCollection.svelte +40 -18
  10. package/dist/display/LinkCollection.svelte.d.ts +9 -2
  11. package/dist/display/Paper.svelte +31 -19
  12. package/dist/display/Paper.svelte.d.ts +12 -3
  13. package/dist/display/alert/Alert.svelte +129 -0
  14. package/dist/display/alert/Alert.svelte.d.ts +15 -0
  15. package/dist/display/alert/AlertVariant.d.ts +1 -0
  16. package/dist/display/alert/AlertVariant.js +1 -0
  17. package/dist/display/filetree/FileTree.svelte +259 -0
  18. package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
  19. package/dist/display/filetree/FileTreeItem.svelte +396 -0
  20. package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
  21. package/dist/display/filetree/FileTreeNode.d.ts +46 -0
  22. package/dist/display/filetree/FileTreeNode.js +115 -0
  23. package/dist/display/filetree/index.d.ts +5 -0
  24. package/dist/display/filetree/index.js +3 -0
  25. package/dist/editors/CodeMirror.svelte +306 -0
  26. package/dist/editors/CodeMirror.svelte.d.ts +31 -0
  27. package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
  28. package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
  29. package/dist/editors/tiptap/TipTap.svelte +856 -0
  30. package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
  31. package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
  32. package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
  33. package/dist/editors/tiptap/collaboration.d.ts +55 -0
  34. package/dist/editors/tiptap/collaboration.js +1 -0
  35. package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
  36. package/dist/editors/tiptap/extensions/Alert.js +72 -0
  37. package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
  38. package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
  39. package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
  40. package/dist/editors/tiptap/extensions/Div.js +89 -0
  41. package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
  42. package/dist/editors/tiptap/extensions/Span.js +56 -0
  43. package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
  44. package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
  45. package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
  46. package/dist/editors/tiptap/extensions/index.d.ts +7 -0
  47. package/dist/editors/tiptap/extensions/index.js +5 -0
  48. package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
  49. package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
  50. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
  51. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
  52. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
  53. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
  54. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
  55. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
  56. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
  57. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
  58. package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
  59. package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
  60. package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
  61. package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
  62. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
  63. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
  64. package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
  65. package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
  66. package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
  67. package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
  68. package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
  69. package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
  70. package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
  71. package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
  72. package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
  73. package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
  74. package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
  75. package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
  76. package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
  77. package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
  78. package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
  79. package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
  80. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
  81. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
  82. package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
  83. package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
  84. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
  85. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
  86. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
  87. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
  88. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
  89. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
  90. package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
  91. package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
  92. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
  93. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
  94. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
  95. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
  96. package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
  97. package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
  98. package/dist/form/Autocomplete.svelte +86 -135
  99. package/dist/form/Autocomplete.svelte.d.ts +6 -8
  100. package/dist/form/AutocompleteMulti.svelte +385 -227
  101. package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
  102. package/dist/form/Checkbox.svelte +59 -54
  103. package/dist/form/Checkbox.svelte.d.ts +14 -5
  104. package/dist/form/Chips.svelte +29 -13
  105. package/dist/form/Chips.svelte.d.ts +16 -2
  106. package/dist/form/ComboBox.svelte +30 -20
  107. package/dist/form/ComboBox.svelte.d.ts +1 -1
  108. package/dist/form/ComboBoxItemBuilder.svelte +161 -188
  109. package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
  110. package/dist/form/ComboBoxMulti.svelte +38 -24
  111. package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
  112. package/dist/form/CronBuilder.svelte +84 -67
  113. package/dist/form/CronBuilder.svelte.d.ts +16 -3
  114. package/dist/form/DatePicker.svelte +148 -195
  115. package/dist/form/DateRangePicker.svelte +101 -98
  116. package/dist/form/DateTimePicker.svelte +167 -208
  117. package/dist/form/DateTimePicker.svelte.d.ts +10 -2
  118. package/dist/form/FormGroup.svelte +33 -10
  119. package/dist/form/FormGroup.svelte.d.ts +12 -2
  120. package/dist/form/Number.svelte +70 -47
  121. package/dist/form/Number.svelte.d.ts +36 -6
  122. package/dist/form/Radio.svelte +18 -18
  123. package/dist/form/RadioGroup.svelte +23 -12
  124. package/dist/form/RadioGroup.svelte.d.ts +13 -2
  125. package/dist/form/SegmentedControl.svelte +76 -56
  126. package/dist/form/SegmentedControl.svelte.d.ts +9 -4
  127. package/dist/form/Select.svelte +150 -233
  128. package/dist/form/Select.svelte.d.ts +29 -5
  129. package/dist/form/SelectMulti.svelte +163 -277
  130. package/dist/form/SelectMulti.svelte.d.ts +36 -7
  131. package/dist/form/Slider.svelte +183 -269
  132. package/dist/form/Slider.svelte.d.ts +32 -17
  133. package/dist/form/StringArrayBuilder.svelte +249 -0
  134. package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
  135. package/dist/form/Switch.svelte +164 -106
  136. package/dist/form/Switch.svelte.d.ts +22 -3
  137. package/dist/form/TextArea.svelte +49 -29
  138. package/dist/form/TextArea.svelte.d.ts +23 -3
  139. package/dist/form/Textbox.svelte +69 -68
  140. package/dist/form/Textbox.svelte.d.ts +32 -4
  141. package/dist/form/TimePicker.svelte +42 -47
  142. package/dist/form/TimePicker.svelte.d.ts +12 -2
  143. package/dist/form/comboBoxCore.svelte.d.ts +99 -0
  144. package/dist/form/comboBoxCore.svelte.js +243 -0
  145. package/dist/icon/Icon.svelte +8 -3
  146. package/dist/icon/Icon.svelte.d.ts +8 -3
  147. package/dist/icon/file-type-bmp.svg +1 -0
  148. package/dist/icon/file-type-csv.svg +1 -0
  149. package/dist/icon/file-type-doc.svg +1 -0
  150. package/dist/icon/file-type-docx.svg +1 -0
  151. package/dist/icon/file-type-jpg.svg +1 -0
  152. package/dist/icon/file-type-pdf.svg +1 -0
  153. package/dist/icon/file-type-png.svg +1 -0
  154. package/dist/icon/file-type-ppt.svg +1 -0
  155. package/dist/icon/file-type-svg.svg +1 -0
  156. package/dist/icon/file-type-txt.svg +1 -0
  157. package/dist/icon/file-type-xls.svg +1 -0
  158. package/dist/icon/file-type-zip.svg +1 -0
  159. package/dist/icon/index.d.ts +166 -151
  160. package/dist/icon/index.js +166 -152
  161. package/dist/icon/logo-placeholder.svg +6 -0
  162. package/dist/icon/source-code.svg +1 -0
  163. package/dist/icon/sun-moon.svg +1 -0
  164. package/dist/icon/table.svg +6 -0
  165. package/dist/index.d.ts +87 -26
  166. package/dist/index.js +25 -28
  167. package/dist/layout/AppShell.svelte +12 -162
  168. package/dist/layout/AppShell.svelte.d.ts +6 -27
  169. package/dist/layout/CustomNavbar.svelte +9 -7
  170. package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
  171. package/dist/layout/Navbar.svelte +161 -129
  172. package/dist/layout/Navbar.svelte.d.ts +29 -15
  173. package/dist/layout/NavbarItemDisplay.svelte +2 -2
  174. package/dist/layout/NavbarItemView.svelte +182 -0
  175. package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
  176. package/dist/layout/Sidenav.svelte +280 -341
  177. package/dist/layout/Sidenav.svelte.d.ts +36 -4
  178. package/dist/models/ComboBoxItem.d.ts +2 -0
  179. package/dist/models/Employee.d.ts +53 -0
  180. package/dist/models/Employee.js +23 -0
  181. package/dist/models/Hyperlink.d.ts +3 -1
  182. package/dist/models/LinkCollectionItem.d.ts +3 -1
  183. package/dist/models/NavbarItem.d.ts +6 -2
  184. package/dist/theme.svelte.d.ts +0 -1
  185. package/dist/theme.svelte.js +46 -58
  186. package/dist/ui/Accordion.svelte +81 -242
  187. package/dist/ui/Accordion.svelte.d.ts +37 -14
  188. package/dist/ui/AccordionItem.svelte +303 -0
  189. package/dist/ui/AccordionItem.svelte.d.ts +21 -0
  190. package/dist/ui/ActionIcon.svelte +25 -21
  191. package/dist/ui/ActionIcon.svelte.d.ts +15 -2
  192. package/dist/ui/Badge.svelte +163 -171
  193. package/dist/ui/Badge.svelte.d.ts +13 -5
  194. package/dist/ui/Button.svelte +178 -205
  195. package/dist/ui/Button.svelte.d.ts +19 -2
  196. package/dist/ui/ButtonVariant.d.ts +15 -1
  197. package/dist/ui/ContextMenu.svelte +146 -0
  198. package/dist/ui/ContextMenu.svelte.d.ts +37 -0
  199. package/dist/ui/ContextMenuList.svelte +188 -0
  200. package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
  201. package/dist/ui/Dialog.svelte +183 -111
  202. package/dist/ui/Dialog.svelte.d.ts +21 -4
  203. package/dist/ui/Drawer.svelte +237 -184
  204. package/dist/ui/Drawer.svelte.d.ts +20 -2
  205. package/dist/ui/Dropdown.svelte +24 -14
  206. package/dist/ui/Dropdown.svelte.d.ts +11 -2
  207. package/dist/ui/Dropzone.svelte +159 -57
  208. package/dist/ui/Dropzone.svelte.d.ts +29 -2
  209. package/dist/ui/Link.svelte +12 -4
  210. package/dist/ui/Link.svelte.d.ts +8 -2
  211. package/dist/ui/Loader.svelte +23 -18
  212. package/dist/ui/Loader.svelte.d.ts +5 -2
  213. package/dist/ui/Logo.svelte +37 -0
  214. package/dist/ui/Logo.svelte.d.ts +16 -0
  215. package/dist/ui/MultiSortable.svelte +287 -0
  216. package/dist/ui/MultiSortable.svelte.d.ts +50 -0
  217. package/dist/ui/Pagination.svelte +15 -9
  218. package/dist/ui/Pagination.svelte.d.ts +6 -2
  219. package/dist/ui/Popover.svelte +43 -65
  220. package/dist/ui/Popover.svelte.d.ts +14 -5
  221. package/dist/ui/ProgressBar.svelte +28 -30
  222. package/dist/ui/ProgressBarVariant.d.ts +7 -1
  223. package/dist/ui/SegmentedControl.svelte +0 -0
  224. package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
  225. package/dist/ui/Sortable.svelte +163 -0
  226. package/dist/ui/Sortable.svelte.d.ts +47 -0
  227. package/dist/ui/Table.svelte +383 -80
  228. package/dist/ui/Table.svelte.d.ts +43 -2
  229. package/dist/ui/Tabs.svelte +22 -18
  230. package/dist/ui/Tabs.svelte.d.ts +6 -2
  231. package/dist/ui/ThemeSwitcher.svelte +26 -7
  232. package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
  233. package/dist/ui/Tooltip.svelte +312 -180
  234. package/dist/ui/Tooltip.svelte.d.ts +4 -3
  235. package/dist/uiTheme.svelte.d.ts +86 -0
  236. package/dist/uiTheme.svelte.js +214 -0
  237. package/dist/util/DateFunctions.js +1 -1
  238. package/dist/util/DragDrop.d.ts +50 -0
  239. package/dist/util/DragDrop.js +154 -0
  240. package/dist/util/NavigateTo.js +2 -2
  241. package/dist/util/dayjs.d.ts +4 -0
  242. package/dist/util/dayjs.js +15 -0
  243. package/package.json +66 -26
  244. package/dist/display/Alert.svelte +0 -179
  245. package/dist/display/Alert.svelte.d.ts +0 -13
  246. package/dist/form/FileInput.svelte +0 -235
  247. package/dist/form/FileInput.svelte.d.ts +0 -23
  248. package/dist/form/PasswordInput.svelte +0 -253
  249. package/dist/form/PasswordInput.svelte.d.ts +0 -34
  250. package/dist/form/Rating.svelte +0 -235
  251. package/dist/form/Rating.svelte.d.ts +0 -21
  252. package/dist/styles/components.css +0 -199
  253. package/dist/styles/dark.css +0 -146
  254. package/dist/styles/index.css +0 -116
  255. package/dist/styles/reset.css +0 -110
  256. package/dist/styles/semantic.css +0 -86
  257. package/dist/styles/tokens.css +0 -203
  258. package/dist/styles/utilities.css +0 -523
  259. package/dist/ui/Breadcrumbs.svelte +0 -131
  260. package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
  261. package/dist/ui/LoadingOverlay.svelte +0 -53
  262. package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
  263. package/dist/ui/Progress.svelte +0 -191
  264. package/dist/ui/Progress.svelte.d.ts +0 -15
  265. package/dist/ui/RingProgress.svelte +0 -141
  266. package/dist/ui/RingProgress.svelte.d.ts +0 -18
  267. package/dist/ui/Skeleton.svelte +0 -85
  268. package/dist/ui/Skeleton.svelte.d.ts +0 -12
  269. package/dist/ui/Stepper.svelte +0 -355
  270. package/dist/ui/Stepper.svelte.d.ts +0 -24
  271. package/dist/ui/Timeline.svelte +0 -225
  272. package/dist/ui/Timeline.svelte.d.ts +0 -23
  273. /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
  274. /package/dist/{actions → util}/ClickOutside.js +0 -0
  275. /package/dist/{transitions → util}/Transitions.d.ts +0 -0
  276. /package/dist/{transitions → util}/Transitions.js +0 -0
@@ -0,0 +1,306 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte'
3
+ import {
4
+ EditorView,
5
+ lineNumbers as lineNumbersGutter,
6
+ highlightActiveLineGutter,
7
+ highlightSpecialChars,
8
+ drawSelection,
9
+ dropCursor,
10
+ rectangularSelection,
11
+ crosshairCursor,
12
+ highlightActiveLine,
13
+ keymap
14
+ } from '@codemirror/view'
15
+ import { EditorState, Compartment } from '@codemirror/state'
16
+ import {
17
+ foldGutter,
18
+ foldKeymap,
19
+ indentOnInput,
20
+ syntaxHighlighting,
21
+ defaultHighlightStyle,
22
+ bracketMatching
23
+ } from '@codemirror/language'
24
+ import { history, defaultKeymap, historyKeymap } from '@codemirror/commands'
25
+ import { highlightSelectionMatches, searchKeymap } from '@codemirror/search'
26
+ import {
27
+ closeBrackets,
28
+ closeBracketsKeymap,
29
+ autocompletion,
30
+ completionKeymap
31
+ } from '@codemirror/autocomplete'
32
+ import { lintKeymap } from '@codemirror/lint'
33
+ import { javascript } from '@codemirror/lang-javascript'
34
+ import { html } from '@codemirror/lang-html'
35
+ import { css } from '@codemirror/lang-css'
36
+ import { json } from '@codemirror/lang-json'
37
+ import { markdown } from '@codemirror/lang-markdown'
38
+ import { oneDark } from '@codemirror/theme-one-dark'
39
+ import { themeState } from '../theme.svelte.js'
40
+ import ActionIcon from '../ui/ActionIcon.svelte'
41
+ import { iconCopy, iconCheck } from '../icon/index.js'
42
+
43
+ export interface CodeMirrorProps {
44
+ /** Editor content value (bindable) */
45
+ value?: string
46
+ /** Programming language for syntax highlighting */
47
+ language?: 'javascript' | 'html' | 'css' | 'json' | 'typescript' | 'markdown'
48
+ /** Color theme for the editor (defaults to app theme) */
49
+ theme?: 'light' | 'dark' | 'auto'
50
+ /** Disable editing */
51
+ readOnly?: boolean
52
+ /** Show line numbers in the gutter */
53
+ lineNumbers?: boolean
54
+ /** Show a button that copies the editor contents to the clipboard */
55
+ copyButton?: boolean
56
+ /** Additional CSS classes */
57
+ class?: string
58
+ /** Height of the editor */
59
+ height?: string
60
+ /** Callback when content changes */
61
+ onChange?: (value: string) => void
62
+ /** Callback after the contents are copied to the clipboard */
63
+ onCopy?: (value: string) => void
64
+ }
65
+
66
+ let {
67
+ value = $bindable(''),
68
+ language = 'javascript',
69
+ theme = 'auto',
70
+ readOnly = false,
71
+ lineNumbers = true,
72
+ copyButton = false,
73
+ class: className = '',
74
+ height = '500px',
75
+ onChange,
76
+ onCopy
77
+ }: CodeMirrorProps = $props()
78
+
79
+ let editorContainer: HTMLDivElement | undefined = $state()
80
+ let view: EditorView | null = $state(null)
81
+ let themeCompartment = new Compartment()
82
+ let gutterCompartment = new Compartment()
83
+ let copied = $state(false)
84
+ let copiedTimeout: ReturnType<typeof setTimeout>
85
+
86
+ // basicSetup minus the gutters, which we swap in via a compartment so the
87
+ // `lineNumbers` prop can be toggled after the editor is created.
88
+ const baseSetup = [
89
+ highlightSpecialChars(),
90
+ history(),
91
+ drawSelection(),
92
+ dropCursor(),
93
+ EditorState.allowMultipleSelections.of(true),
94
+ indentOnInput(),
95
+ syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
96
+ bracketMatching(),
97
+ closeBrackets(),
98
+ autocompletion(),
99
+ rectangularSelection(),
100
+ crosshairCursor(),
101
+ highlightActiveLine(),
102
+ highlightSelectionMatches(),
103
+ keymap.of([
104
+ ...closeBracketsKeymap,
105
+ ...defaultKeymap,
106
+ ...searchKeymap,
107
+ ...historyKeymap,
108
+ ...foldKeymap,
109
+ ...completionKeymap,
110
+ ...lintKeymap
111
+ ])
112
+ ]
113
+
114
+ const getGutterExtension = (show: boolean) =>
115
+ show ? [lineNumbersGutter(), highlightActiveLineGutter(), foldGutter()] : []
116
+
117
+ // Derive effective dark mode from prop or app theme
118
+ let isDark = $derived(
119
+ theme === 'auto' ? themeState.isDarkMode : theme === 'dark'
120
+ )
121
+
122
+ const getLanguageExtension = (lang: string) => {
123
+ switch (lang) {
124
+ case 'javascript':
125
+ case 'typescript':
126
+ return javascript()
127
+ case 'html':
128
+ return html()
129
+ case 'css':
130
+ return css()
131
+ case 'json':
132
+ return json()
133
+ case 'markdown':
134
+ return markdown()
135
+ default:
136
+ return javascript()
137
+ }
138
+ }
139
+
140
+ onMount(() => {
141
+ if (!editorContainer) return
142
+
143
+ const extensions = [
144
+ gutterCompartment.of(getGutterExtension(lineNumbers)),
145
+ baseSetup,
146
+ getLanguageExtension(language),
147
+ EditorView.lineWrapping,
148
+ themeCompartment.of(isDark ? oneDark : [])
149
+ ]
150
+
151
+ if (readOnly) {
152
+ extensions.push(EditorState.readOnly.of(true))
153
+ }
154
+
155
+ // Always add update listener to sync bindable value
156
+ extensions.push(
157
+ EditorView.updateListener.of((update) => {
158
+ if (update.docChanged) {
159
+ const newValue = update.state.doc.toString()
160
+ value = newValue
161
+ if (onChange) {
162
+ onChange(newValue)
163
+ }
164
+ }
165
+ })
166
+ )
167
+
168
+ const startState = EditorState.create({
169
+ doc: value,
170
+ extensions
171
+ })
172
+
173
+ view = new EditorView({
174
+ state: startState,
175
+ parent: editorContainer
176
+ })
177
+ })
178
+
179
+ onDestroy(() => {
180
+ view?.destroy()
181
+ clearTimeout(copiedTimeout)
182
+ })
183
+
184
+ async function copyToClipboard() {
185
+ const text = view?.state.doc.toString() ?? value
186
+
187
+ try {
188
+ await navigator.clipboard.writeText(text)
189
+ copied = true
190
+ clearTimeout(copiedTimeout)
191
+ copiedTimeout = setTimeout(() => (copied = false), 2000)
192
+ onCopy?.(text)
193
+ } catch (err) {
194
+ console.error('CodeMirror: failed to copy to clipboard', err)
195
+ }
196
+ }
197
+
198
+ // Watch for theme changes and reconfigure
199
+ $effect(() => {
200
+ if (!view) return
201
+
202
+ view.dispatch({
203
+ effects: themeCompartment.reconfigure(isDark ? oneDark : [])
204
+ })
205
+ })
206
+
207
+ // Watch for lineNumbers changes and reconfigure the gutter
208
+ $effect(() => {
209
+ if (!view) return
210
+
211
+ view.dispatch({
212
+ effects: gutterCompartment.reconfigure(getGutterExtension(lineNumbers))
213
+ })
214
+ })
215
+
216
+ // Watch for external value changes and update editor
217
+ $effect(() => {
218
+ if (!view) return
219
+
220
+ const currentValue = view.state.doc.toString()
221
+ if (value !== currentValue) {
222
+ view.dispatch({
223
+ changes: { from: 0, to: currentValue.length, insert: value }
224
+ })
225
+ }
226
+ })
227
+
228
+ // Public API methods
229
+ export function getValue(): string {
230
+ return view?.state.doc.toString() || ''
231
+ }
232
+
233
+ export function setValue(newValue: string) {
234
+ if (!view) return
235
+ view.dispatch({
236
+ changes: { from: 0, to: view.state.doc.length, insert: newValue }
237
+ })
238
+ }
239
+
240
+ export function getView(): EditorView | null {
241
+ return view
242
+ }
243
+
244
+ export function focus() {
245
+ view?.focus()
246
+ }
247
+ </script>
248
+
249
+ <div class="codemirror-container {className}" style="height: {height}">
250
+ {#if copyButton}
251
+ <div class="codemirror-copy" class:copied class:dark={isDark}>
252
+ <ActionIcon
253
+ svg={copied ? iconCheck : iconCopy}
254
+ size="16px"
255
+ tooltip={copied ? 'Copied' : 'Copy to clipboard'}
256
+ ariaLabel={copied ? 'Copied to clipboard' : 'Copy to clipboard'}
257
+ onclick={copyToClipboard}
258
+ />
259
+ </div>
260
+ {/if}
261
+ <div class="codemirror-wrapper" bind:this={editorContainer}></div>
262
+ </div>
263
+
264
+ <style>
265
+ .codemirror-container {
266
+ position: relative;
267
+ width: 100%;
268
+ border: 1px solid var(--border-color, #ddd);
269
+ border-radius: 6px;
270
+ overflow: hidden;
271
+ background: var(--input-bg-color);
272
+ }
273
+
274
+ /* The ActionIcon supplies the button chrome; this only places it and gives it
275
+ an opaque backing so it stays readable over the code underneath. */
276
+ .codemirror-copy {
277
+ position: absolute;
278
+ top: 6px;
279
+ right: 6px;
280
+ z-index: 2;
281
+ display: inline-flex;
282
+ border-radius: 6px;
283
+ opacity: 0.65;
284
+ transition: opacity 0.15s ease;
285
+ }
286
+
287
+ .codemirror-container:hover .codemirror-copy,
288
+ .codemirror-copy:hover,
289
+ .codemirror-copy:focus-within,
290
+ .codemirror-copy.copied {
291
+ opacity: 1;
292
+ }
293
+
294
+ .codemirror-wrapper {
295
+ width: 100%;
296
+ height: 100%;
297
+ }
298
+
299
+ .codemirror-wrapper :global(.cm-editor) {
300
+ height: 100%;
301
+ }
302
+
303
+ .codemirror-wrapper :global(.cm-scroller) {
304
+ overflow: auto;
305
+ }
306
+ </style>
@@ -0,0 +1,31 @@
1
+ import { EditorView } from '@codemirror/view';
2
+ export interface CodeMirrorProps {
3
+ /** Editor content value (bindable) */
4
+ value?: string;
5
+ /** Programming language for syntax highlighting */
6
+ language?: 'javascript' | 'html' | 'css' | 'json' | 'typescript' | 'markdown';
7
+ /** Color theme for the editor (defaults to app theme) */
8
+ theme?: 'light' | 'dark' | 'auto';
9
+ /** Disable editing */
10
+ readOnly?: boolean;
11
+ /** Show line numbers in the gutter */
12
+ lineNumbers?: boolean;
13
+ /** Show a button that copies the editor contents to the clipboard */
14
+ copyButton?: boolean;
15
+ /** Additional CSS classes */
16
+ class?: string;
17
+ /** Height of the editor */
18
+ height?: string;
19
+ /** Callback when content changes */
20
+ onChange?: (value: string) => void;
21
+ /** Callback after the contents are copied to the clipboard */
22
+ onCopy?: (value: string) => void;
23
+ }
24
+ declare const CodeMirror: import("svelte").Component<CodeMirrorProps, {
25
+ getValue: () => string;
26
+ setValue: (newValue: string) => void;
27
+ getView: () => EditorView | null;
28
+ focus: () => void;
29
+ }, "value">;
30
+ type CodeMirror = ReturnType<typeof CodeMirror>;
31
+ export default CodeMirror;
@@ -0,0 +1,307 @@
1
+ <script lang="ts">
2
+ import type { Editor } from '@tiptap/core';
3
+ import { onMount } from 'svelte';
4
+ import {
5
+ Icon,
6
+ iconCheck,
7
+ iconEdit,
8
+ iconExternalLink,
9
+ iconTrash,
10
+ iconX
11
+ } from '../../icon/index.js';
12
+
13
+ interface Props {
14
+ editor: Editor;
15
+ editable?: boolean;
16
+ }
17
+
18
+ let { editor, editable = true }: Props = $props();
19
+
20
+ let href = $state('');
21
+ let target = $state<string | null>(null);
22
+ let isEditing = $state(false);
23
+ let draftHref = $state('');
24
+ let draftOpenInNewTab = $state(false);
25
+ let linkInputElement: HTMLInputElement | undefined = $state();
26
+
27
+ function refreshLinkState() {
28
+ const attrs = editor.getAttributes('link') as {
29
+ href?: string;
30
+ target?: string | null;
31
+ };
32
+
33
+ href = attrs.href || '';
34
+ target = attrs.target || null;
35
+
36
+ if (!isEditing) {
37
+ draftHref = href;
38
+ draftOpenInNewTab = target === '_blank';
39
+ }
40
+ }
41
+
42
+ function openLink() {
43
+ if (!href) return;
44
+
45
+ const linkTarget = target || '_self';
46
+ const openedWindow = window.open(
47
+ href,
48
+ linkTarget,
49
+ linkTarget === '_blank' ? 'noopener,noreferrer' : undefined
50
+ );
51
+
52
+ if (openedWindow && linkTarget === '_blank') {
53
+ openedWindow.opener = null;
54
+ }
55
+ }
56
+
57
+ function startEditing() {
58
+ if (!editable) return;
59
+
60
+ draftHref = href;
61
+ draftOpenInNewTab = target === '_blank';
62
+ isEditing = true;
63
+
64
+ setTimeout(() => {
65
+ linkInputElement?.focus();
66
+ linkInputElement?.select();
67
+ }, 0);
68
+ }
69
+
70
+ function applyLink() {
71
+ if (!editable) return;
72
+
73
+ const nextHref = draftHref.trim();
74
+
75
+ if (!nextHref) {
76
+ removeLink();
77
+ return;
78
+ }
79
+
80
+ editor
81
+ .chain()
82
+ .focus()
83
+ .extendMarkRange('link')
84
+ .setLink({
85
+ href: nextHref,
86
+ target: draftOpenInNewTab ? '_blank' : null,
87
+ rel: draftOpenInNewTab ? 'noopener noreferrer' : null
88
+ })
89
+ .run();
90
+
91
+ isEditing = false;
92
+ refreshLinkState();
93
+ }
94
+
95
+ function cancelEditing() {
96
+ isEditing = false;
97
+ refreshLinkState();
98
+ editor.commands.focus();
99
+ }
100
+
101
+ function removeLink() {
102
+ if (!editable) return;
103
+
104
+ editor.chain().focus().extendMarkRange('link').unsetLink().run();
105
+ isEditing = false;
106
+ refreshLinkState();
107
+ }
108
+
109
+ function handleEditKeydown(event: KeyboardEvent) {
110
+ if (event.key === 'Enter') {
111
+ event.preventDefault();
112
+ applyLink();
113
+ }
114
+
115
+ if (event.key === 'Escape') {
116
+ event.preventDefault();
117
+ cancelEditing();
118
+ }
119
+ }
120
+
121
+ onMount(() => {
122
+ refreshLinkState();
123
+ editor.on('selectionUpdate', refreshLinkState);
124
+ editor.on('transaction', refreshLinkState);
125
+
126
+ return () => {
127
+ editor.off('selectionUpdate', refreshLinkState);
128
+ editor.off('transaction', refreshLinkState);
129
+ };
130
+ });
131
+ </script>
132
+
133
+ <div class="link-action-menu">
134
+ {#if isEditing && editable}
135
+ <div class="link-edit-row">
136
+ <input
137
+ bind:this={linkInputElement}
138
+ bind:value={draftHref}
139
+ class="link-input"
140
+ onkeydown={handleEditKeydown}
141
+ placeholder="Enter URL"
142
+ type="text"
143
+ />
144
+ <button class="link-icon-button primary" onclick={applyLink} title="Apply" type="button">
145
+ <Icon svg={iconCheck} size="16px" />
146
+ </button>
147
+ <button class="link-icon-button" onclick={cancelEditing} title="Cancel" type="button">
148
+ <Icon svg={iconX} size="16px" />
149
+ </button>
150
+ </div>
151
+ <label class="link-checkbox-label">
152
+ <input bind:checked={draftOpenInNewTab} class="link-checkbox" type="checkbox" />
153
+ <span>Open in new tab</span>
154
+ </label>
155
+ {:else}
156
+ <button class="link-url" onclick={openLink} title={href} type="button">
157
+ {href}
158
+ </button>
159
+ <button class="link-icon-button primary" onclick={openLink} title="Open link" type="button">
160
+ <Icon svg={iconExternalLink} size="16px" />
161
+ </button>
162
+ {#if editable}
163
+ <button class="link-icon-button" onclick={startEditing} title="Edit link" type="button">
164
+ <Icon svg={iconEdit} size="16px" />
165
+ </button>
166
+ <button class="link-icon-button danger" onclick={removeLink} title="Remove link" type="button">
167
+ <Icon svg={iconTrash} size="16px" />
168
+ </button>
169
+ {/if}
170
+ {/if}
171
+ </div>
172
+
173
+ <style>
174
+ .link-action-menu {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: 6px;
178
+ max-width: min(560px, calc(100vw - 32px));
179
+ padding: 6px;
180
+ border: 1px solid var(--border-color);
181
+ border-radius: 6px;
182
+ background: var(--paper-title-bg);
183
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
184
+ color: var(--text-color);
185
+ font-family: var(--ui-font-family);
186
+ }
187
+
188
+ :global(.dark) .link-action-menu {
189
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
190
+ }
191
+
192
+ .link-url {
193
+ min-width: 0;
194
+ max-width: 320px;
195
+ padding: 5px 8px;
196
+ overflow: hidden;
197
+ border: 1px solid var(--border-color);
198
+ border-radius: 4px;
199
+ background: var(--paper-body-bg);
200
+ color: var(--ui-tertiary-dark);
201
+ cursor: pointer;
202
+ font: inherit;
203
+ font-size: 13px;
204
+ text-overflow: ellipsis;
205
+ white-space: nowrap;
206
+ }
207
+
208
+ :global(.dark) .link-url {
209
+ color: var(--ui-tertiary);
210
+ }
211
+
212
+ .link-edit-row {
213
+ display: flex;
214
+ align-items: center;
215
+ gap: 4px;
216
+ min-width: min(360px, calc(100vw - 80px));
217
+ }
218
+
219
+ .link-input {
220
+ flex: 1;
221
+ min-width: 0;
222
+ padding: 6px 10px;
223
+ border: 1px solid var(--border-color);
224
+ border-radius: 4px;
225
+ background: var(--paper-body-bg);
226
+ color: var(--text-color);
227
+ font: inherit;
228
+ font-size: 14px;
229
+ outline: none;
230
+ }
231
+
232
+ .link-input:focus {
233
+ border-color: var(--ui-primary);
234
+ box-shadow: 0 0 0 2px rgba(var(--ui-primary-rgbc), 0.1);
235
+ }
236
+
237
+ :global(.dark) .link-input:focus {
238
+ border-color: var(--ui-accent);
239
+ box-shadow: 0 0 0 2px rgba(var(--ui-accent-rgbc), 0.1);
240
+ }
241
+
242
+ .link-icon-button {
243
+ display: inline-flex;
244
+ align-items: center;
245
+ justify-content: center;
246
+ width: 28px;
247
+ height: 28px;
248
+ padding: 0;
249
+ border: none;
250
+ border-radius: 4px;
251
+ background: transparent;
252
+ color: var(--text-color);
253
+ cursor: pointer;
254
+ transition:
255
+ background 0.15s ease,
256
+ color 0.15s ease;
257
+ }
258
+
259
+ .link-icon-button:hover {
260
+ background: rgba(var(--ui-primary-rgbc), 0.1);
261
+ color: var(--ui-primary);
262
+ }
263
+
264
+ :global(.dark) .link-icon-button:hover {
265
+ background: rgba(var(--ui-accent-rgbc), 0.1);
266
+ color: var(--ui-accent);
267
+ }
268
+
269
+ .link-icon-button.primary {
270
+ background: var(--ui-primary);
271
+ color: white;
272
+ }
273
+
274
+ .link-icon-button.primary:hover {
275
+ background: var(--ui-tertiary-dark);
276
+ color: white;
277
+ }
278
+
279
+ :global(.dark) .link-icon-button.primary {
280
+ background: var(--ui-accent);
281
+ color: var(--ui-primary);
282
+ }
283
+
284
+ .link-icon-button.danger:hover {
285
+ background: rgba(var(--bs-danger-rgb), 0.12);
286
+ color: var(--bs-danger);
287
+ }
288
+
289
+ .link-checkbox-label {
290
+ display: flex;
291
+ align-items: center;
292
+ gap: 6px;
293
+ font-size: 13px;
294
+ white-space: nowrap;
295
+ }
296
+
297
+ .link-checkbox {
298
+ width: 16px;
299
+ height: 16px;
300
+ cursor: pointer;
301
+ accent-color: var(--ui-primary);
302
+ }
303
+
304
+ :global(.dark) .link-checkbox {
305
+ accent-color: var(--ui-accent);
306
+ }
307
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { Editor } from '@tiptap/core';
2
+ interface Props {
3
+ editor: Editor;
4
+ editable?: boolean;
5
+ }
6
+ declare const LinkActionMenu: import("svelte").Component<Props, {}, "">;
7
+ type LinkActionMenu = ReturnType<typeof LinkActionMenu>;
8
+ export default LinkActionMenu;