@placeholderco/placeholder-ui 2.1.1 → 2.2.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 (80) hide show
  1. package/dist/editors/CodeMirror.svelte +295 -297
  2. package/dist/editors/tiptap/LinkActionMenu.svelte +6 -1
  3. package/dist/editors/tiptap/extensions/Alert.js +17 -17
  4. package/dist/editors/tiptap/extensions/Div.js +19 -19
  5. package/dist/editors/tiptap/extensions/Span.js +14 -14
  6. package/dist/editors/tiptap/toolbar/AlertButton.svelte +254 -253
  7. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +11 -11
  8. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +11 -11
  9. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +11 -11
  10. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +11 -11
  11. package/dist/editors/tiptap/toolbar/BoldButton.svelte +11 -11
  12. package/dist/editors/tiptap/toolbar/BulletListButton.svelte +11 -11
  13. package/dist/editors/tiptap/toolbar/CodeButton.svelte +11 -11
  14. package/dist/editors/tiptap/toolbar/ColorButton.svelte +265 -265
  15. package/dist/editors/tiptap/toolbar/DocumentButton.svelte +51 -51
  16. package/dist/editors/tiptap/toolbar/HeadingButton.svelte +21 -21
  17. package/dist/editors/tiptap/toolbar/HtmlButton.svelte +48 -52
  18. package/dist/editors/tiptap/toolbar/ImageButton.svelte +35 -39
  19. package/dist/editors/tiptap/toolbar/ItalicButton.svelte +11 -11
  20. package/dist/editors/tiptap/toolbar/LinkButton.svelte +249 -249
  21. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +11 -11
  22. package/dist/editors/tiptap/toolbar/RedoButton.svelte +11 -11
  23. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +11 -11
  24. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +11 -11
  25. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +11 -11
  26. package/dist/editors/tiptap/toolbar/TableButton.svelte +231 -224
  27. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +59 -65
  28. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +11 -11
  29. package/dist/editors/tiptap/toolbar/UndoButton.svelte +11 -11
  30. package/dist/form/Autocomplete.svelte +24 -22
  31. package/dist/form/AutocompleteMulti.svelte +24 -22
  32. package/dist/form/Checkbox.svelte +4 -4
  33. package/dist/form/Chips.svelte +15 -7
  34. package/dist/form/ColorPicker.svelte +5 -20
  35. package/dist/form/ComboBox.svelte +4 -4
  36. package/dist/form/ComboBoxItemBuilder.svelte +14 -32
  37. package/dist/form/ComboBoxMulti.svelte +7 -3
  38. package/dist/form/CronBuilder.svelte +32 -110
  39. package/dist/form/DatePicker.svelte +9 -28
  40. package/dist/form/DateRangePicker.svelte +46 -36
  41. package/dist/form/DateTimePicker.svelte +11 -30
  42. package/dist/form/Number.svelte +1 -3
  43. package/dist/form/RadioGroup.svelte +1 -3
  44. package/dist/form/Select.svelte +25 -28
  45. package/dist/form/SelectMulti.svelte +36 -38
  46. package/dist/form/StringArrayBuilder.svelte +1 -3
  47. package/dist/form/TextArea.svelte +5 -6
  48. package/dist/form/Textbox.svelte +10 -4
  49. package/dist/form/TimePicker.svelte +10 -4
  50. package/dist/icon/Icon.svelte +5 -1
  51. package/dist/index.d.ts +147 -146
  52. package/dist/index.js +78 -77
  53. package/dist/layout/CustomNavbar.svelte +1 -1
  54. package/dist/layout/NavbarItemDisplay.svelte +1 -1
  55. package/dist/layout/NavbarItemView.svelte +3 -1
  56. package/dist/layout/Sidenav.svelte +1 -1
  57. package/dist/models/ComboBoxItem.d.ts +4 -4
  58. package/dist/models/NotifyModel.js +0 -1
  59. package/dist/theme.svelte.d.ts +1 -1
  60. package/dist/theme.svelte.js +46 -22
  61. package/dist/ui/Accordion.svelte +1 -3
  62. package/dist/ui/Badge.svelte +4 -5
  63. package/dist/ui/Button.svelte +7 -1
  64. package/dist/ui/ContextMenu.svelte +5 -11
  65. package/dist/ui/Dialog.svelte +16 -3
  66. package/dist/ui/Dialog.svelte.d.ts +7 -1
  67. package/dist/ui/Dropdown.svelte +21 -10
  68. package/dist/ui/MultiSortable.svelte +1 -3
  69. package/dist/ui/Pagination.svelte +2 -2
  70. package/dist/ui/Popover.svelte +16 -37
  71. package/dist/ui/ProgressBar.svelte +1 -4
  72. package/dist/ui/ThemeSwitcher.svelte +2 -1
  73. package/dist/ui/Tooltip.svelte +1 -37
  74. package/dist/util/DateFunctions.js +1 -1
  75. package/dist/util/Floating.d.ts +70 -0
  76. package/dist/util/Floating.js +321 -0
  77. package/dist/util/NavigateTo.js +2 -2
  78. package/dist/util/Transitions.d.ts +1 -1
  79. package/dist/util/Transitions.js +1 -1
  80. package/package.json +1 -1
@@ -1,306 +1,304 @@
1
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
- }
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(theme === 'auto' ? themeState.isDarkMode : theme === 'dark');
119
+
120
+ const getLanguageExtension = (lang: string) => {
121
+ switch (lang) {
122
+ case 'javascript':
123
+ case 'typescript':
124
+ return javascript();
125
+ case 'html':
126
+ return html();
127
+ case 'css':
128
+ return css();
129
+ case 'json':
130
+ return json();
131
+ case 'markdown':
132
+ return markdown();
133
+ default:
134
+ return javascript();
135
+ }
136
+ };
137
+
138
+ onMount(() => {
139
+ if (!editorContainer) return;
140
+
141
+ const extensions = [
142
+ gutterCompartment.of(getGutterExtension(lineNumbers)),
143
+ baseSetup,
144
+ getLanguageExtension(language),
145
+ EditorView.lineWrapping,
146
+ themeCompartment.of(isDark ? oneDark : [])
147
+ ];
148
+
149
+ if (readOnly) {
150
+ extensions.push(EditorState.readOnly.of(true));
151
+ }
152
+
153
+ // Always add update listener to sync bindable value
154
+ extensions.push(
155
+ EditorView.updateListener.of((update) => {
156
+ if (update.docChanged) {
157
+ const newValue = update.state.doc.toString();
158
+ value = newValue;
159
+ if (onChange) {
160
+ onChange(newValue);
161
+ }
162
+ }
163
+ })
164
+ );
165
+
166
+ const startState = EditorState.create({
167
+ doc: value,
168
+ extensions
169
+ });
170
+
171
+ view = new EditorView({
172
+ state: startState,
173
+ parent: editorContainer
174
+ });
175
+ });
176
+
177
+ onDestroy(() => {
178
+ view?.destroy();
179
+ clearTimeout(copiedTimeout);
180
+ });
181
+
182
+ async function copyToClipboard() {
183
+ const text = view?.state.doc.toString() ?? value;
184
+
185
+ try {
186
+ await navigator.clipboard.writeText(text);
187
+ copied = true;
188
+ clearTimeout(copiedTimeout);
189
+ copiedTimeout = setTimeout(() => (copied = false), 2000);
190
+ onCopy?.(text);
191
+ } catch (err) {
192
+ console.error('CodeMirror: failed to copy to clipboard', err);
193
+ }
194
+ }
195
+
196
+ // Watch for theme changes and reconfigure
197
+ $effect(() => {
198
+ if (!view) return;
199
+
200
+ view.dispatch({
201
+ effects: themeCompartment.reconfigure(isDark ? oneDark : [])
202
+ });
203
+ });
204
+
205
+ // Watch for lineNumbers changes and reconfigure the gutter
206
+ $effect(() => {
207
+ if (!view) return;
208
+
209
+ view.dispatch({
210
+ effects: gutterCompartment.reconfigure(getGutterExtension(lineNumbers))
211
+ });
212
+ });
213
+
214
+ // Watch for external value changes and update editor
215
+ $effect(() => {
216
+ if (!view) return;
217
+
218
+ const currentValue = view.state.doc.toString();
219
+ if (value !== currentValue) {
220
+ view.dispatch({
221
+ changes: { from: 0, to: currentValue.length, insert: value }
222
+ });
223
+ }
224
+ });
225
+
226
+ // Public API methods
227
+ export function getValue(): string {
228
+ return view?.state.doc.toString() || '';
229
+ }
230
+
231
+ export function setValue(newValue: string) {
232
+ if (!view) return;
233
+ view.dispatch({
234
+ changes: { from: 0, to: view.state.doc.length, insert: newValue }
235
+ });
236
+ }
237
+
238
+ export function getView(): EditorView | null {
239
+ return view;
240
+ }
241
+
242
+ export function focus() {
243
+ view?.focus();
244
+ }
247
245
  </script>
248
246
 
249
247
  <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>
248
+ {#if copyButton}
249
+ <div class="codemirror-copy" class:copied class:dark={isDark}>
250
+ <ActionIcon
251
+ svg={copied ? iconCheck : iconCopy}
252
+ size="16px"
253
+ tooltip={copied ? 'Copied' : 'Copy to clipboard'}
254
+ ariaLabel={copied ? 'Copied to clipboard' : 'Copy to clipboard'}
255
+ onclick={copyToClipboard}
256
+ />
257
+ </div>
258
+ {/if}
259
+ <div class="codemirror-wrapper" bind:this={editorContainer}></div>
262
260
  </div>
263
261
 
264
262
  <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
263
+ .codemirror-container {
264
+ position: relative;
265
+ width: 100%;
266
+ border: 1px solid var(--border-color, #ddd);
267
+ border-radius: 6px;
268
+ overflow: hidden;
269
+ background: var(--input-bg-color);
270
+ }
271
+
272
+ /* The ActionIcon supplies the button chrome; this only places it and gives it
275
273
  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
- }
274
+ .codemirror-copy {
275
+ position: absolute;
276
+ top: 6px;
277
+ right: 6px;
278
+ z-index: 2;
279
+ display: inline-flex;
280
+ border-radius: 6px;
281
+ opacity: 0.65;
282
+ transition: opacity 0.15s ease;
283
+ }
284
+
285
+ .codemirror-container:hover .codemirror-copy,
286
+ .codemirror-copy:hover,
287
+ .codemirror-copy:focus-within,
288
+ .codemirror-copy.copied {
289
+ opacity: 1;
290
+ }
291
+
292
+ .codemirror-wrapper {
293
+ width: 100%;
294
+ height: 100%;
295
+ }
296
+
297
+ .codemirror-wrapper :global(.cm-editor) {
298
+ height: 100%;
299
+ }
300
+
301
+ .codemirror-wrapper :global(.cm-scroller) {
302
+ overflow: auto;
303
+ }
306
304
  </style>
@@ -163,7 +163,12 @@
163
163
  <button class="link-icon-button" onclick={startEditing} title="Edit link" type="button">
164
164
  <Icon svg={iconEdit} size="16px" />
165
165
  </button>
166
- <button class="link-icon-button danger" onclick={removeLink} title="Remove link" type="button">
166
+ <button
167
+ class="link-icon-button danger"
168
+ onclick={removeLink}
169
+ title="Remove link"
170
+ type="button"
171
+ >
167
172
  <Icon svg={iconTrash} size="16px" />
168
173
  </button>
169
174
  {/if}