@fuzdev/fuz_code 0.45.1 → 0.46.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.
- package/README.md +1 -0
- package/dist/Code.svelte +2 -2
- package/dist/Code.svelte.d.ts +2 -2
- package/dist/CodeHighlight.svelte +18 -54
- package/dist/CodeHighlight.svelte.d.ts +4 -4
- package/dist/CodeHighlight.svelte.d.ts.map +1 -1
- package/dist/CodeTextarea.svelte +149 -0
- package/dist/CodeTextarea.svelte.d.ts +43 -0
- package/dist/CodeTextarea.svelte.d.ts.map +1 -0
- package/dist/grammar_markdown.js +3 -3
- package/dist/grammar_markup.d.ts +8 -7
- package/dist/grammar_markup.d.ts.map +1 -1
- package/dist/grammar_markup.js +8 -7
- package/dist/highlight_manager.d.ts +21 -7
- package/dist/highlight_manager.d.ts.map +1 -1
- package/dist/highlight_manager.js +130 -74
- package/dist/range_highlighting.svelte.d.ts +39 -0
- package/dist/range_highlighting.svelte.d.ts.map +1 -0
- package/dist/range_highlighting.svelte.js +57 -0
- package/dist/svelte_preprocess_fuz_code.d.ts +4 -4
- package/dist/svelte_preprocess_fuz_code.d.ts.map +1 -1
- package/dist/svelte_preprocess_fuz_code.js +3 -3
- package/dist/syntax_styler.d.ts +40 -32
- package/dist/syntax_styler.d.ts.map +1 -1
- package/dist/syntax_styler.js +81 -49
- package/dist/syntax_token.d.ts +4 -4
- package/dist/syntax_token.js +2 -2
- package/dist/tokenize_syntax.d.ts +2 -4
- package/dist/tokenize_syntax.d.ts.map +1 -1
- package/dist/tokenize_syntax.js +2 -4
- package/package.json +27 -29
- package/src/lib/grammar_markdown.ts +3 -3
- package/src/lib/grammar_markup.ts +8 -7
- package/src/lib/highlight_manager.ts +154 -84
- package/src/lib/range_highlighting.svelte.ts +100 -0
- package/src/lib/svelte_preprocess_fuz_code.ts +6 -6
- package/src/lib/syntax_styler.ts +98 -53
- package/src/lib/syntax_token.ts +4 -4
- package/src/lib/tokenize_syntax.ts +2 -4
package/README.md
CHANGED
package/dist/Code.svelte
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
*/
|
|
56
56
|
lang?: string | null;
|
|
57
57
|
/**
|
|
58
|
-
* Optional custom
|
|
58
|
+
* Optional custom `SyntaxGrammar` object for syntax tokenization.
|
|
59
59
|
*
|
|
60
60
|
* **When to use:**
|
|
61
61
|
* - To provide a custom language definition not registered in `syntax_styler.langs`
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
*/
|
|
101
101
|
nomargin?: boolean;
|
|
102
102
|
/**
|
|
103
|
-
* Custom SyntaxStyler instance to use for highlighting.
|
|
103
|
+
* Custom `SyntaxStyler` instance to use for highlighting.
|
|
104
104
|
* Allows using a different styler with custom grammars or configuration.
|
|
105
105
|
*
|
|
106
106
|
* @default syntax_styler_global
|
package/dist/Code.svelte.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ type $$ComponentProps = SvelteHTMLElements['code'] & ({
|
|
|
35
35
|
*/
|
|
36
36
|
lang?: string | null;
|
|
37
37
|
/**
|
|
38
|
-
* Optional custom
|
|
38
|
+
* Optional custom `SyntaxGrammar` object for syntax tokenization.
|
|
39
39
|
*
|
|
40
40
|
* **When to use:**
|
|
41
41
|
* - To provide a custom language definition not registered in `syntax_styler.langs`
|
|
@@ -80,7 +80,7 @@ type $$ComponentProps = SvelteHTMLElements['code'] & ({
|
|
|
80
80
|
*/
|
|
81
81
|
nomargin?: boolean;
|
|
82
82
|
/**
|
|
83
|
-
* Custom SyntaxStyler instance to use for highlighting.
|
|
83
|
+
* Custom `SyntaxStyler` instance to use for highlighting.
|
|
84
84
|
* Allows using a different styler with custom grammars or configuration.
|
|
85
85
|
*
|
|
86
86
|
* @default syntax_styler_global
|
|
@@ -3,21 +3,16 @@
|
|
|
3
3
|
* Uses the CSS Custom Highlight API when available --
|
|
4
4
|
* https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API
|
|
5
5
|
*
|
|
6
|
-
* Requires importing theme_highlight.css instead of theme.css
|
|
6
|
+
* Requires importing `theme_highlight.css` instead of `theme.css`.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
import {DEV} from 'esm-env';
|
|
9
|
+
import type {Snippet} from 'svelte';
|
|
11
10
|
import type {SvelteHTMLElements} from 'svelte/elements';
|
|
12
11
|
|
|
13
12
|
import {syntax_styler_global} from './syntax_styler_global.js';
|
|
14
13
|
import type {SyntaxStyler, SyntaxGrammar} from './syntax_styler.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
HighlightManager,
|
|
18
|
-
supports_css_highlight_api,
|
|
19
|
-
type HighlightMode,
|
|
20
|
-
} from './highlight_manager.js';
|
|
14
|
+
import {supports_css_highlight_api, type HighlightMode} from './highlight_manager.js';
|
|
15
|
+
import {create_range_highlighting} from './range_highlighting.svelte.js';
|
|
21
16
|
|
|
22
17
|
const {
|
|
23
18
|
content,
|
|
@@ -65,7 +60,7 @@
|
|
|
65
60
|
*/
|
|
66
61
|
mode?: HighlightMode;
|
|
67
62
|
/**
|
|
68
|
-
* Optional custom
|
|
63
|
+
* Optional custom `SyntaxGrammar` object for syntax tokenization.
|
|
69
64
|
*
|
|
70
65
|
* **When to use:**
|
|
71
66
|
* - To provide a custom language definition not registered in `syntax_styler.langs`
|
|
@@ -103,7 +98,7 @@
|
|
|
103
98
|
*/
|
|
104
99
|
wrap?: boolean;
|
|
105
100
|
/**
|
|
106
|
-
* Custom SyntaxStyler instance to use for highlighting.
|
|
101
|
+
* Custom `SyntaxStyler` instance to use for highlighting.
|
|
107
102
|
* Allows using a different styler with custom grammars or configuration.
|
|
108
103
|
*
|
|
109
104
|
* @default syntax_styler_global
|
|
@@ -117,62 +112,31 @@
|
|
|
117
112
|
children?: Snippet<[markup: string]>;
|
|
118
113
|
} = $props();
|
|
119
114
|
|
|
120
|
-
let code_element: HTMLElement | undefined = $state();
|
|
115
|
+
let code_element: HTMLElement | undefined = $state.raw();
|
|
121
116
|
|
|
122
117
|
const supports_ranges = supports_css_highlight_api();
|
|
123
118
|
|
|
124
|
-
const highlight_manager = supports_ranges ? new HighlightManager() : null;
|
|
125
|
-
|
|
126
119
|
const use_ranges = $derived(supports_ranges && (mode === 'ranges' || mode === 'auto'));
|
|
127
120
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// eslint-disable-next-line no-console
|
|
138
|
-
console.error(
|
|
139
|
-
`[CodeHighlight] Language "${lang}" is not supported and no custom grammar provided. ` +
|
|
140
|
-
`Highlighting disabled. Supported: ${langs}`,
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
121
|
+
const rh = create_range_highlighting({
|
|
122
|
+
element: () => code_element,
|
|
123
|
+
text: () => content,
|
|
124
|
+
enabled: () => use_ranges,
|
|
125
|
+
lang: () => lang,
|
|
126
|
+
grammar: () => grammar,
|
|
127
|
+
syntax_styler: () => syntax_styler,
|
|
128
|
+
dev_label: 'CodeHighlight',
|
|
129
|
+
});
|
|
145
130
|
|
|
146
131
|
// Generate HTML markup for syntax highlighting in non-range mode
|
|
147
132
|
const html_content = $derived.by(() => {
|
|
148
|
-
if (use_ranges || !content || highlighting_disabled) {
|
|
133
|
+
if (use_ranges || !content || rh.highlighting_disabled) {
|
|
149
134
|
return '';
|
|
150
135
|
}
|
|
151
136
|
|
|
152
137
|
return syntax_styler.stylize(content, lang!, grammar); // ! is safe bc of the `highlighting_disabled` calculation
|
|
153
138
|
});
|
|
154
139
|
|
|
155
|
-
// Apply highlights for range mode
|
|
156
|
-
if (highlight_manager) {
|
|
157
|
-
$effect(() => {
|
|
158
|
-
if (!code_element || !content || !use_ranges || highlighting_disabled) {
|
|
159
|
-
highlight_manager.clear_element_ranges();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Get tokens from syntax styler
|
|
164
|
-
const tokens = tokenize_syntax(content, grammar || syntax_styler.get_lang(lang!)); // ! is safe bc of the `highlighting_disabled` calculation
|
|
165
|
-
|
|
166
|
-
// Apply highlights
|
|
167
|
-
highlight_manager.highlight_from_syntax_tokens(code_element, tokens);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
onDestroy(() => {
|
|
172
|
-
highlight_manager?.destroy();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// TODO use intersect attachment from fuz_ui to optimize ranges
|
|
176
140
|
// TODO do syntax styling at compile-time in the normal case, and don't import these at runtime
|
|
177
141
|
// TODO @html making me nervous
|
|
178
142
|
</script>
|
|
@@ -182,7 +146,7 @@
|
|
|
182
146
|
<code {...rest} class:inline class:wrap data-lang={lang} bind:this={code_element}
|
|
183
147
|
>{#if use_ranges && children}{@render children(
|
|
184
148
|
content,
|
|
185
|
-
)}{:else if use_ranges || highlighting_disabled}{content}{:else if children}{@render children(
|
|
149
|
+
)}{:else if use_ranges || rh.highlighting_disabled}{content}{:else if children}{@render children(
|
|
186
150
|
html_content,
|
|
187
151
|
)}{:else}{@html html_content}{/if}</code
|
|
188
152
|
>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Uses the CSS Custom Highlight API when available --
|
|
3
3
|
* https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API
|
|
4
4
|
*
|
|
5
|
-
* Requires importing theme_highlight.css instead of theme.css
|
|
5
|
+
* Requires importing `theme_highlight.css` instead of `theme.css`.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import type { Snippet } from 'svelte';
|
|
8
8
|
import type { SvelteHTMLElements } from 'svelte/elements';
|
|
9
9
|
import type { SyntaxStyler, SyntaxGrammar } from './syntax_styler.js';
|
|
10
10
|
import { type HighlightMode } from './highlight_manager.js';
|
|
@@ -44,7 +44,7 @@ type $$ComponentProps = SvelteHTMLElements['code'] & {
|
|
|
44
44
|
*/
|
|
45
45
|
mode?: HighlightMode;
|
|
46
46
|
/**
|
|
47
|
-
* Optional custom
|
|
47
|
+
* Optional custom `SyntaxGrammar` object for syntax tokenization.
|
|
48
48
|
*
|
|
49
49
|
* **When to use:**
|
|
50
50
|
* - To provide a custom language definition not registered in `syntax_styler.langs`
|
|
@@ -82,7 +82,7 @@ type $$ComponentProps = SvelteHTMLElements['code'] & {
|
|
|
82
82
|
*/
|
|
83
83
|
wrap?: boolean;
|
|
84
84
|
/**
|
|
85
|
-
* Custom SyntaxStyler instance to use for highlighting.
|
|
85
|
+
* Custom `SyntaxStyler` instance to use for highlighting.
|
|
86
86
|
* Allows using a different styler with custom grammars or configuration.
|
|
87
87
|
*
|
|
88
88
|
* @default syntax_styler_global
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeHighlight.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/CodeHighlight.svelte"],"names":[],"mappings":"AAGA;;;;;OAKI;AACJ,OAAO,
|
|
1
|
+
{"version":3,"file":"CodeHighlight.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/CodeHighlight.svelte"],"names":[],"mappings":"AAGA;;;;;OAKI;AACJ,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAC,YAAY,EAAE,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAA6B,KAAK,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrF,KAAK,gBAAgB,GAAI,kBAAkB,CAAC,MAAM,CAAC,GAAG;IACrD,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACrC,CAAC;AAiEH,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* A `<textarea>` with live syntax highlighting via the CSS Custom Highlight API.
|
|
4
|
+
*
|
|
5
|
+
* The text is rendered twice: an editable, visually-transparent `<textarea>`
|
|
6
|
+
* on top, and a backdrop `<pre>` mirror underneath whose text node receives
|
|
7
|
+
* the highlight ranges. The two share identical box metrics so characters line
|
|
8
|
+
* up exactly, and the backdrop is scroll-synced to the textarea.
|
|
9
|
+
*
|
|
10
|
+
* **Minimal by design**: this is a highlighted input, not a full editor. It
|
|
11
|
+
* does not provide line numbers, tab-to-indent, auto-resize, or undo handling
|
|
12
|
+
* — compose those on top via the spread `...rest` props and `bind:value`.
|
|
13
|
+
*
|
|
14
|
+
* **Experimental** — the Highlight API has limited browser support and cannot
|
|
15
|
+
* render font-weight/font-style. Requires importing `theme_highlight.css`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type {SvelteHTMLElements} from 'svelte/elements';
|
|
19
|
+
|
|
20
|
+
import {syntax_styler_global} from './syntax_styler_global.js';
|
|
21
|
+
import type {SyntaxStyler, SyntaxGrammar} from './syntax_styler.js';
|
|
22
|
+
import {create_range_highlighting} from './range_highlighting.svelte.js';
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
value = $bindable(''),
|
|
26
|
+
lang = 'svelte',
|
|
27
|
+
grammar,
|
|
28
|
+
syntax_styler = syntax_styler_global,
|
|
29
|
+
wrapper_attrs,
|
|
30
|
+
...rest
|
|
31
|
+
}: SvelteHTMLElements['textarea'] & {
|
|
32
|
+
/** The editable source code. Bindable. */
|
|
33
|
+
value?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Language identifier (e.g. 'ts', 'css', 'svelte'). `null` disables
|
|
36
|
+
* highlighting; `undefined` falls back to the default ('svelte').
|
|
37
|
+
*/
|
|
38
|
+
lang?: string | null;
|
|
39
|
+
/** Optional custom grammar; takes precedence over `lang` for tokenization. */
|
|
40
|
+
grammar?: SyntaxGrammar | undefined;
|
|
41
|
+
/** Custom `SyntaxStyler` instance (defaults to the global one). */
|
|
42
|
+
syntax_styler?: SyntaxStyler;
|
|
43
|
+
/**
|
|
44
|
+
* Attributes for the wrapper `<div>` — the layout box that the textarea
|
|
45
|
+
* fills and `resize` grows. Use it for sizing/layout classes, `style`,
|
|
46
|
+
* `id`, or container-level handlers. Its `class` is merged with the
|
|
47
|
+
* internal `code_textarea` class; `data-lang` stays component-controlled.
|
|
48
|
+
* (`...rest` spreads onto the `<textarea>`; the backdrop `<pre>` is
|
|
49
|
+
* internal and intentionally not exposed.)
|
|
50
|
+
*/
|
|
51
|
+
wrapper_attrs?: SvelteHTMLElements['div'];
|
|
52
|
+
} = $props();
|
|
53
|
+
|
|
54
|
+
// the backdrop <pre> holds the text node that gets highlighted *and* is the
|
|
55
|
+
// scroll container kept in sync with the textarea
|
|
56
|
+
let backdrop: HTMLElement | undefined = $state.raw();
|
|
57
|
+
let textarea: HTMLTextAreaElement | undefined = $state.raw();
|
|
58
|
+
|
|
59
|
+
// A trailing newline keeps the backdrop's last line aligned with the textarea:
|
|
60
|
+
// a textarea shows an empty final line after a trailing "\n", which a <pre>
|
|
61
|
+
// would otherwise collapse. Rendered as a single expression -> one text node,
|
|
62
|
+
// and tokenized as-is so range positions match the text node exactly.
|
|
63
|
+
const display_text = $derived(value + '\n');
|
|
64
|
+
|
|
65
|
+
create_range_highlighting({
|
|
66
|
+
element: () => backdrop,
|
|
67
|
+
text: () => display_text,
|
|
68
|
+
lang: () => lang,
|
|
69
|
+
grammar: () => grammar,
|
|
70
|
+
syntax_styler: () => syntax_styler,
|
|
71
|
+
dev_label: 'CodeTextarea',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// keep the (overflow-hidden) backdrop aligned with the textarea's scroll position
|
|
75
|
+
const sync_scroll = () => {
|
|
76
|
+
if (!backdrop || !textarea) return;
|
|
77
|
+
backdrop.scrollTop = textarea.scrollTop;
|
|
78
|
+
backdrop.scrollLeft = textarea.scrollLeft;
|
|
79
|
+
};
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<div {...wrapper_attrs} class={['code_textarea', wrapper_attrs?.class]} data-lang={lang}>
|
|
83
|
+
<pre class="code_textarea_backdrop" aria-hidden="true" bind:this={backdrop}>{display_text}</pre>
|
|
84
|
+
<textarea
|
|
85
|
+
bind:this={textarea}
|
|
86
|
+
spellcheck="false"
|
|
87
|
+
{...rest}
|
|
88
|
+
bind:value
|
|
89
|
+
onscroll={(e) => {
|
|
90
|
+
sync_scroll();
|
|
91
|
+
rest.onscroll?.(e); // preserve a consumer-supplied handler
|
|
92
|
+
}}
|
|
93
|
+
></textarea>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
.code_textarea {
|
|
98
|
+
position: relative;
|
|
99
|
+
width: 100%;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* metrics shared by both layers so characters align exactly */
|
|
103
|
+
.code_textarea_backdrop,
|
|
104
|
+
.code_textarea textarea {
|
|
105
|
+
margin: 0;
|
|
106
|
+
box-sizing: border-box;
|
|
107
|
+
width: 100%;
|
|
108
|
+
padding: var(--space_xs3) var(--space_xs);
|
|
109
|
+
border: 1px solid transparent;
|
|
110
|
+
border-radius: var(--radius_xs, 2px);
|
|
111
|
+
font-family: var(--font_family_mono, monospace);
|
|
112
|
+
font-size: var(--font_size_sm, 0.9rem);
|
|
113
|
+
line-height: var(--line_height_md, 1.5);
|
|
114
|
+
letter-spacing: inherit;
|
|
115
|
+
tab-size: 2;
|
|
116
|
+
white-space: pre-wrap;
|
|
117
|
+
overflow-wrap: break-word;
|
|
118
|
+
overflow: auto;
|
|
119
|
+
/* reserve gutter on both layers so the textarea's scrollbar doesn't shrink
|
|
120
|
+
its wrap width relative to the backdrop, which would drift highlights */
|
|
121
|
+
scrollbar-gutter: stable;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* the backdrop is taken out of flow so the in-flow textarea (its `rows`/resize)
|
|
125
|
+
defines the box; `inset: 0` makes the backdrop fill and clip to that box,
|
|
126
|
+
scrolled programmatically to match the textarea */
|
|
127
|
+
.code_textarea_backdrop {
|
|
128
|
+
position: absolute;
|
|
129
|
+
inset: 0;
|
|
130
|
+
pointer-events: none;
|
|
131
|
+
user-select: none;
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
color: var(--text_color, currentColor);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.code_textarea textarea {
|
|
137
|
+
/* sits above the backdrop so the caret and selection are visible; the
|
|
138
|
+
textarea is the only in-flow layer, so it sizes the container */
|
|
139
|
+
position: relative;
|
|
140
|
+
z-index: 1;
|
|
141
|
+
display: block;
|
|
142
|
+
background-color: transparent;
|
|
143
|
+
/* the textarea's own text is invisible; the backdrop shows through */
|
|
144
|
+
color: transparent;
|
|
145
|
+
caret-color: var(--text_color, currentColor);
|
|
146
|
+
border-color: var(--border_color, currentColor);
|
|
147
|
+
resize: vertical;
|
|
148
|
+
}
|
|
149
|
+
</style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `<textarea>` with live syntax highlighting via the CSS Custom Highlight API.
|
|
3
|
+
*
|
|
4
|
+
* The text is rendered twice: an editable, visually-transparent `<textarea>`
|
|
5
|
+
* on top, and a backdrop `<pre>` mirror underneath whose text node receives
|
|
6
|
+
* the highlight ranges. The two share identical box metrics so characters line
|
|
7
|
+
* up exactly, and the backdrop is scroll-synced to the textarea.
|
|
8
|
+
*
|
|
9
|
+
* **Minimal by design**: this is a highlighted input, not a full editor. It
|
|
10
|
+
* does not provide line numbers, tab-to-indent, auto-resize, or undo handling
|
|
11
|
+
* — compose those on top via the spread `...rest` props and `bind:value`.
|
|
12
|
+
*
|
|
13
|
+
* **Experimental** — the Highlight API has limited browser support and cannot
|
|
14
|
+
* render font-weight/font-style. Requires importing `theme_highlight.css`.
|
|
15
|
+
*/
|
|
16
|
+
import type { SvelteHTMLElements } from 'svelte/elements';
|
|
17
|
+
import type { SyntaxStyler, SyntaxGrammar } from './syntax_styler.js';
|
|
18
|
+
type $$ComponentProps = SvelteHTMLElements['textarea'] & {
|
|
19
|
+
/** The editable source code. Bindable. */
|
|
20
|
+
value?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Language identifier (e.g. 'ts', 'css', 'svelte'). `null` disables
|
|
23
|
+
* highlighting; `undefined` falls back to the default ('svelte').
|
|
24
|
+
*/
|
|
25
|
+
lang?: string | null;
|
|
26
|
+
/** Optional custom grammar; takes precedence over `lang` for tokenization. */
|
|
27
|
+
grammar?: SyntaxGrammar | undefined;
|
|
28
|
+
/** Custom `SyntaxStyler` instance (defaults to the global one). */
|
|
29
|
+
syntax_styler?: SyntaxStyler;
|
|
30
|
+
/**
|
|
31
|
+
* Attributes for the wrapper `<div>` — the layout box that the textarea
|
|
32
|
+
* fills and `resize` grows. Use it for sizing/layout classes, `style`,
|
|
33
|
+
* `id`, or container-level handlers. Its `class` is merged with the
|
|
34
|
+
* internal `code_textarea` class; `data-lang` stays component-controlled.
|
|
35
|
+
* (`...rest` spreads onto the `<textarea>`; the backdrop `<pre>` is
|
|
36
|
+
* internal and intentionally not exposed.)
|
|
37
|
+
*/
|
|
38
|
+
wrapper_attrs?: SvelteHTMLElements['div'];
|
|
39
|
+
};
|
|
40
|
+
declare const CodeTextarea: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
41
|
+
type CodeTextarea = ReturnType<typeof CodeTextarea>;
|
|
42
|
+
export default CodeTextarea;
|
|
43
|
+
//# sourceMappingURL=CodeTextarea.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeTextarea.svelte.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/CodeTextarea.svelte"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;OAcI;AACJ,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAC,YAAY,EAAE,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAGnE,KAAK,gBAAgB,GAAI,kBAAkB,CAAC,UAAU,CAAC,GAAG;IACzD,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACpC,mEAAmE;IACnE,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC;CAC1C,CAAC;AA2DH,QAAA,MAAM,YAAY,2DAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
package/dist/grammar_markdown.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Helper to create fenced code block pattern for a language
|
|
2
|
+
* Helper to create fenced code block pattern for a language.
|
|
3
3
|
*/
|
|
4
4
|
const create_fence_pattern = (backticks, aliases, lang_id, syntax_styler) => {
|
|
5
5
|
const aliases_pattern = aliases.join('|');
|
|
@@ -21,7 +21,7 @@ const create_fence_pattern = (backticks, aliases, lang_id, syntax_styler) => {
|
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
|
-
* Helper to create catch-all fence pattern (unknown languages)
|
|
24
|
+
* Helper to create catch-all fence pattern (unknown languages).
|
|
25
25
|
*/
|
|
26
26
|
const create_catchall_fence = (backticks) => {
|
|
27
27
|
const pattern = new RegExp(`^${backticks}[^\\n\\r]*(?:\\r?\\n|\\r)[\\s\\S]*?^${backticks}$`, 'm');
|
|
@@ -38,7 +38,7 @@ const create_catchall_fence = (backticks) => {
|
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
|
-
* Helper to create md self-reference placeholder pattern
|
|
41
|
+
* Helper to create md self-reference placeholder pattern.
|
|
42
42
|
*/
|
|
43
43
|
const create_md_placeholder = (backticks) => {
|
|
44
44
|
const pattern = new RegExp(`^${backticks}(?:md|markdown)[^\\n\\r]*(?:\\r?\\n|\\r)[\\s\\S]*?^${backticks}$`, 'm');
|
package/dist/grammar_markup.d.ts
CHANGED
|
@@ -13,19 +13,20 @@ export declare const add_grammar_markup: AddSyntaxGrammar;
|
|
|
13
13
|
*
|
|
14
14
|
* An example of an inlined language is CSS with `<style>` tags.
|
|
15
15
|
*
|
|
16
|
-
* @param
|
|
17
|
-
* case insensitive
|
|
18
|
-
* @param lang -
|
|
16
|
+
* @param syntax_styler - the `SyntaxStyler` instance to modify
|
|
17
|
+
* @param tag_name - the name of the tag that contains the inlined language, treated as case insensitive
|
|
18
|
+
* @param lang - the language key
|
|
19
|
+
* @param inside_lang - the language to insert into, defaults to `'markup'`
|
|
19
20
|
*/
|
|
20
21
|
export declare const grammar_markup_add_inlined: (syntax_styler: SyntaxStyler, tag_name: string, lang: string, inside_lang?: string) => void;
|
|
21
22
|
/**
|
|
22
|
-
* Adds
|
|
23
|
+
* Adds a pattern to style languages embedded in HTML attributes.
|
|
23
24
|
*
|
|
24
25
|
* An example of an inlined language is CSS with `style` attributes.
|
|
25
26
|
*
|
|
26
|
-
* @param
|
|
27
|
-
* case insensitive
|
|
28
|
-
* @param lang -
|
|
27
|
+
* @param syntax_styler - the `SyntaxStyler` instance to modify
|
|
28
|
+
* @param attr_name - the name of the attribute that contains the inlined language, treated as case insensitive
|
|
29
|
+
* @param lang - the language key
|
|
29
30
|
*/
|
|
30
31
|
export declare const grammar_markup_add_attribute: (syntax_styler: SyntaxStyler, attr_name: string, lang: string) => void;
|
|
31
32
|
//# sourceMappingURL=grammar_markup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grammar_markup.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/grammar_markup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBA6EhC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"grammar_markup.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/grammar_markup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBA6EhC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,GACtC,eAAe,YAAY,EAC3B,UAAU,MAAM,EAChB,MAAM,MAAM,EACZ,oBAAsB,KACpB,IAmCF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GACxC,eAAe,YAAY,EAC3B,WAAW,MAAM,EACjB,MAAM,MAAM,KACV,IAiEF,CAAC"}
|
package/dist/grammar_markup.js
CHANGED
|
@@ -86,9 +86,10 @@ export const add_grammar_markup = (syntax_styler) => {
|
|
|
86
86
|
*
|
|
87
87
|
* An example of an inlined language is CSS with `<style>` tags.
|
|
88
88
|
*
|
|
89
|
-
* @param
|
|
90
|
-
* case insensitive
|
|
91
|
-
* @param lang -
|
|
89
|
+
* @param syntax_styler - the `SyntaxStyler` instance to modify
|
|
90
|
+
* @param tag_name - the name of the tag that contains the inlined language, treated as case insensitive
|
|
91
|
+
* @param lang - the language key
|
|
92
|
+
* @param inside_lang - the language to insert into, defaults to `'markup'`
|
|
92
93
|
*/
|
|
93
94
|
export const grammar_markup_add_inlined = (syntax_styler, tag_name, lang, inside_lang = 'markup') => {
|
|
94
95
|
const lang_key = 'lang_' + lang;
|
|
@@ -120,13 +121,13 @@ export const grammar_markup_add_inlined = (syntax_styler, tag_name, lang, inside
|
|
|
120
121
|
});
|
|
121
122
|
};
|
|
122
123
|
/**
|
|
123
|
-
* Adds
|
|
124
|
+
* Adds a pattern to style languages embedded in HTML attributes.
|
|
124
125
|
*
|
|
125
126
|
* An example of an inlined language is CSS with `style` attributes.
|
|
126
127
|
*
|
|
127
|
-
* @param
|
|
128
|
-
* case insensitive
|
|
129
|
-
* @param lang -
|
|
128
|
+
* @param syntax_styler - the `SyntaxStyler` instance to modify
|
|
129
|
+
* @param attr_name - the name of the attribute that contains the inlined language, treated as case insensitive
|
|
130
|
+
* @param lang - the language key
|
|
130
131
|
*/
|
|
131
132
|
export const grammar_markup_add_attribute = (syntax_styler, attr_name, lang) => {
|
|
132
133
|
// After normalization, grammar.tag is an array of SyntaxGrammarToken
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { SyntaxTokenStream } from './syntax_token.js';
|
|
2
2
|
export type HighlightMode = 'auto' | 'ranges' | 'html';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Checks for CSS Highlights API support.
|
|
5
5
|
*/
|
|
6
6
|
export declare const supports_css_highlight_api: () => boolean;
|
|
7
7
|
/**
|
|
8
|
-
* Manages CSS Custom Highlight API ranges for a single element.
|
|
9
|
-
* Tracks ranges per element and only removes its own ranges when clearing
|
|
8
|
+
* Manages CSS Custom Highlight API ranges for a single element's text node.
|
|
9
|
+
* Tracks ranges per element and only removes its own ranges when clearing,
|
|
10
|
+
* cooperating with other managers that share the global `CSS.highlights` registry.
|
|
10
11
|
*
|
|
11
|
-
* **Experimental** — limited browser support. Use `Code` for production
|
|
12
|
+
* **Experimental** — limited browser support. Use `Code.svelte` for production
|
|
13
|
+
* block code; this powers the experimental `CodeHighlight` and `CodeTextarea`.
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```ts
|
|
@@ -18,14 +20,26 @@ export declare const supports_css_highlight_api: () => boolean;
|
|
|
18
20
|
*/
|
|
19
21
|
export declare class HighlightManager {
|
|
20
22
|
#private;
|
|
21
|
-
|
|
23
|
+
/**
|
|
24
|
+
* This manager's ranges, keyed by prefixed highlight name (e.g. `token_keyword`).
|
|
25
|
+
* A single range object may be shared across several names (a token type plus
|
|
26
|
+
* its aliases), since one range can belong to multiple `Highlight` sets.
|
|
27
|
+
*/
|
|
28
|
+
element_ranges: Map<string, Array<AbstractRange>>;
|
|
22
29
|
constructor();
|
|
23
30
|
/**
|
|
24
|
-
*
|
|
31
|
+
* Highlights `element`'s text node from a `SyntaxTokenStream` produced by
|
|
32
|
+
* `tokenize_syntax`. Clears this manager's previous ranges first.
|
|
33
|
+
*
|
|
34
|
+
* In production this never throws on a tokenizer/DOM mismatch: out-of-bounds
|
|
35
|
+
* tokens are clamped and a missing text node is a no-op. In DEV the same
|
|
36
|
+
* conditions throw loudly to surface grammar bugs.
|
|
25
37
|
*/
|
|
26
38
|
highlight_from_syntax_tokens(element: Element, tokens: SyntaxTokenStream): void;
|
|
27
39
|
/**
|
|
28
|
-
*
|
|
40
|
+
* Clears only this manager's ranges from the shared highlights. Defensive:
|
|
41
|
+
* a highlight may already be gone (e.g. another manager removed the last
|
|
42
|
+
* range, or HMR reset the registry), which is a valid state, not an error.
|
|
29
43
|
*/
|
|
30
44
|
clear_element_ranges(): void;
|
|
31
45
|
destroy(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"highlight_manager.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/highlight_manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"highlight_manager.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/highlight_manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAGzD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,0BAA0B,QAAO,OACS,CAAC;AA6CxD;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB;;IAC5B;;;;OAIG;IACH,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;;IAYlD;;;;;;;OAOG;IACH,4BAA4B,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAqE/E;;;;OAIG;IACH,oBAAoB,IAAI,IAAI;IAiB5B,OAAO,IAAI,IAAI;CAwEf"}
|