svelte-multiselect 11.5.2 → 11.6.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.
package/dist/Nav.svelte CHANGED
@@ -1,12 +1,14 @@
1
1
  <script lang="ts">import { click_outside, tooltip } from './attachments';
2
2
  import Icon from './Icon.svelte';
3
+ import { get_uuid } from './utils';
3
4
  let { routes = [], children, item, link, menu_props, link_props, page, labels, tooltips, tooltip_options, breakpoint = 767, onnavigate, onopen, onclose, ...rest } = $props();
4
5
  let is_open = $state(false);
5
6
  let hovered_dropdown = $state(null);
7
+ let pinned_dropdown = $state(null);
6
8
  let focused_item_index = $state(-1);
7
9
  let is_touch_device = $state(false);
8
10
  let is_mobile = $state(false);
9
- const panel_id = `nav-menu-${crypto.randomUUID()}`;
11
+ const panel_id = `nav-menu-${get_uuid()}`;
10
12
  // Track previous is_open state for callbacks
11
13
  let prev_is_open = $state(false);
12
14
  // Detect touch device and handle responsive breakpoint
@@ -35,19 +37,37 @@ $effect(() => {
35
37
  function close_menus() {
36
38
  is_open = false;
37
39
  hovered_dropdown = null;
40
+ pinned_dropdown = null;
38
41
  focused_item_index = -1;
39
42
  }
40
43
  function toggle_dropdown(href, focus_first = false) {
41
- const is_opening = hovered_dropdown !== href;
42
- hovered_dropdown = hovered_dropdown === href ? null : href;
44
+ const is_opening = pinned_dropdown !== href;
45
+ pinned_dropdown = is_opening ? href : null;
46
+ hovered_dropdown = is_opening ? href : null;
43
47
  focused_item_index = is_opening && focus_first ? 0 : -1;
44
48
  // Focus management for keyboard users
45
49
  if (is_opening && focus_first) {
46
50
  setTimeout(() => {
47
- document.querySelector(`.dropdown[data-href="${href}"] [role="menuitem"]`)?.focus();
51
+ document
52
+ .querySelector(`.dropdown[data-href="${CSS.escape(href)}"] [role="menuitem"]`)
53
+ ?.focus();
48
54
  }, 0);
49
55
  }
50
56
  }
57
+ function handle_dropdown_mouseenter(href) {
58
+ if (is_touch_device)
59
+ return;
60
+ const is_this_pinned = pinned_dropdown === href;
61
+ if (pinned_dropdown && !is_this_pinned)
62
+ pinned_dropdown = null;
63
+ hovered_dropdown = href;
64
+ }
65
+ function handle_dropdown_focusin(href) {
66
+ const is_this_pinned = pinned_dropdown === href;
67
+ if (pinned_dropdown && !is_this_pinned)
68
+ pinned_dropdown = null;
69
+ hovered_dropdown = href;
70
+ }
51
71
  function onkeydown(event) {
52
72
  if (event.key === `Escape`)
53
73
  close_menus();
@@ -59,15 +79,18 @@ function handle_dropdown_keydown(event, href, sub_routes) {
59
79
  toggle_dropdown(href, true);
60
80
  return;
61
81
  }
82
+ // Check if dropdown is open (either via hover or pinned)
83
+ const is_open = hovered_dropdown === href || pinned_dropdown === href;
62
84
  // Arrow key navigation within open dropdown
63
- if (hovered_dropdown === href && (key === `ArrowDown` || key === `ArrowUp`)) {
85
+ if (is_open && (key === `ArrowDown` || key === `ArrowUp`)) {
64
86
  event.preventDefault();
65
87
  const direction = key === `ArrowDown` ? 1 : -1;
66
88
  focused_item_index = Math.max(0, Math.min(sub_routes.length - 1, focused_item_index + direction));
67
- document.querySelectorAll(`.dropdown[data-href="${href}"] [role="menuitem"]`)?.[focused_item_index]?.focus();
89
+ document
90
+ .querySelectorAll(`.dropdown[data-href="${CSS.escape(href)}"] [role="menuitem"]`)?.[focused_item_index]?.focus();
68
91
  }
69
92
  // Open dropdown with ArrowDown when closed
70
- if (hovered_dropdown !== href && key === `ArrowDown`) {
93
+ if (!is_open && key === `ArrowDown`) {
71
94
  event.preventDefault();
72
95
  toggle_dropdown(href, true);
73
96
  }
@@ -76,7 +99,9 @@ function handle_dropdown_item_keydown(event, href) {
76
99
  if (event.key === `Escape`) {
77
100
  event.preventDefault();
78
101
  close_menus();
79
- document.querySelector(`.dropdown[data-href="${href}"] [data-dropdown-toggle]`)?.focus();
102
+ document
103
+ .querySelector(`.dropdown[data-href="${href}"] [data-dropdown-toggle]`)
104
+ ?.focus();
80
105
  }
81
106
  }
82
107
  function is_current(path) {
@@ -195,7 +220,7 @@ function get_external_attrs(route) {
195
220
  <button
196
221
  class="burger"
197
222
  type="button"
198
- onclick={() => is_open = !is_open}
223
+ onclick={() => (is_open = !is_open)}
199
224
  aria-label="Toggle navigation menu"
200
225
  aria-expanded={is_open}
201
226
  aria-controls={panel_id}
@@ -222,7 +247,7 @@ function get_external_attrs(route) {
222
247
  ? route
223
248
  : Array.isArray(route)
224
249
  ? route[0]
225
- : route.href ?? `sep-${route_idx}`
250
+ : (route.href ?? `sep-${route_idx}`)
226
251
  }`)
227
252
  }
228
253
  {@const parsed_route = parse_route(route)}
@@ -240,7 +265,11 @@ function get_external_attrs(route) {
240
265
  <!-- Dropdown menu item -->
241
266
  {@const child_is_active = is_child_current(sub_routes)}
242
267
  {@const parent_page_exists = sub_routes.includes(parsed_route.href)}
243
- {@const filtered_sub_routes = sub_routes.filter((r) => r !== parsed_route.href)}
268
+ {@const filtered_sub_routes = sub_routes.filter(
269
+ (r) => r !== parsed_route.href,
270
+ )}
271
+ {@const is_pinned = pinned_dropdown === parsed_route.href}
272
+ {@const dropdown_open = hovered_dropdown === parsed_route.href || is_pinned}
244
273
  <div
245
274
  class="dropdown"
246
275
  class:active={child_is_active}
@@ -248,13 +277,15 @@ function get_external_attrs(route) {
248
277
  data-href={parsed_route.href}
249
278
  role="group"
250
279
  aria-current={child_is_active ? `true` : undefined}
251
- onmouseenter={() => !is_touch_device && (hovered_dropdown = parsed_route.href)}
252
- onmouseleave={() => !is_touch_device && (hovered_dropdown = null)}
253
- onfocusin={() => (hovered_dropdown = parsed_route.href)}
280
+ onmouseenter={() => handle_dropdown_mouseenter(parsed_route.href)}
281
+ onmouseleave={() => {
282
+ if (!is_touch_device && !is_pinned) hovered_dropdown = null
283
+ }}
284
+ onfocusin={() => handle_dropdown_focusin(parsed_route.href)}
254
285
  onfocusout={(event) => {
255
286
  const next = event.relatedTarget as Node | null
256
287
  if (!next || !(event.currentTarget as HTMLElement).contains(next)) {
257
- hovered_dropdown = null
288
+ if (!is_pinned) hovered_dropdown = null
258
289
  }
259
290
  }}
260
291
  >
@@ -287,9 +318,11 @@ function get_external_attrs(route) {
287
318
  {/if}
288
319
  <button
289
320
  type="button"
321
+ class="dropdown-toggle"
322
+ class:open={dropdown_open}
290
323
  data-dropdown-toggle
291
324
  aria-label="Toggle {formatted.label} submenu"
292
- aria-expanded={hovered_dropdown === parsed_route.href}
325
+ aria-expanded={dropdown_open}
293
326
  aria-haspopup="true"
294
327
  onclick={() => toggle_dropdown(parsed_route.href, false)}
295
328
  onkeydown={(event) =>
@@ -299,24 +332,15 @@ function get_external_attrs(route) {
299
332
  filtered_sub_routes,
300
333
  )}
301
334
  >
302
- <Icon
303
- icon="ChevronExpand"
304
- style="width: 0.8em; height: 0.8em"
305
- />
335
+ <Icon icon="ChevronDown" style="width: 0.7em; height: 0.7em" />
306
336
  </button>
307
337
  </div>
308
338
  <div
309
- class:visible={hovered_dropdown === parsed_route.href}
339
+ class:visible={dropdown_open}
310
340
  role="menu"
311
341
  tabindex="-1"
312
- onmouseenter={() => !is_touch_device && (hovered_dropdown = parsed_route.href)}
313
- onmouseleave={() => !is_touch_device && (hovered_dropdown = null)}
314
- onfocusin={() => (hovered_dropdown = parsed_route.href)}
315
- onfocusout={(event) => {
316
- const next = event.relatedTarget as Node | null
317
- if (!next || !(event.currentTarget as HTMLElement).contains(next)) {
318
- hovered_dropdown = null
319
- }
342
+ onmouseenter={() => {
343
+ if (!is_touch_device) hovered_dropdown = parsed_route.href
320
344
  }}
321
345
  >
322
346
  {#each filtered_sub_routes as child_href (child_href)}
@@ -384,7 +408,10 @@ function get_external_attrs(route) {
384
408
  margin: -0.75em auto 1.25em;
385
409
  --nav-border-radius: 6pt;
386
410
  --nav-surface-bg: light-dark(#fafafa, #1a1a1a);
387
- --nav-surface-border: light-dark(rgba(128, 128, 128, 0.25), rgba(200, 200, 200, 0.2));
411
+ --nav-surface-border: light-dark(
412
+ rgba(128, 128, 128, 0.25),
413
+ rgba(200, 200, 200, 0.2)
414
+ );
388
415
  --nav-surface-shadow: light-dark(
389
416
  0 2px 8px rgba(0, 0, 0, 0.15),
390
417
  0 4px 12px rgba(0, 0, 0, 0.5)
@@ -398,17 +425,21 @@ function get_external_attrs(route) {
398
425
  flex-wrap: wrap;
399
426
  padding: 0.5em;
400
427
  }
401
- .menu > span,
428
+ .menu > span {
429
+ display: flex;
430
+ align-items: center;
431
+ border-radius: var(--nav-border-radius);
432
+ background-color: var(--nav-link-bg);
433
+ transition: background-color 0.2s;
434
+ }
435
+ .menu > span:hover {
436
+ background-color: var(--nav-link-bg-hover, rgba(0, 0, 0, 0.1));
437
+ }
402
438
  .menu > span > a {
403
439
  line-height: 1.3;
404
- padding: 1pt 5pt;
405
- border-radius: var(--nav-border-radius);
440
+ padding: var(--nav-item-padding);
406
441
  text-decoration: none;
407
442
  color: inherit;
408
- transition: background-color 0.2s;
409
- }
410
- .menu > span > a:hover {
411
- background-color: var(--nav-link-bg-hover);
412
443
  }
413
444
  .menu > span > a[aria-current='page'] {
414
445
  color: var(--nav-link-active-color);
@@ -450,24 +481,23 @@ function get_external_attrs(route) {
450
481
  content: '';
451
482
  position: absolute;
452
483
  top: 100%;
453
- left: 0;
454
- right: 0;
455
- height: var(--nav-dropdown-margin, 3pt);
484
+ left: -5pt;
485
+ right: -5pt;
486
+ height: calc(var(--nav-dropdown-margin, 2pt) + 5pt);
456
487
  }
457
488
  .dropdown > div:first-child {
458
489
  display: flex;
459
490
  align-items: center;
460
- gap: 0;
461
491
  border-radius: var(--nav-border-radius);
492
+ background-color: var(--nav-link-bg);
462
493
  transition: background-color 0.2s;
463
494
  }
464
495
  .dropdown > div:first-child:hover {
465
- background-color: var(--nav-link-bg-hover);
496
+ background-color: var(--nav-link-bg-hover, rgba(0, 0, 0, 0.1));
466
497
  }
467
- .dropdown > div:first-child > a,
468
- .dropdown > div:first-child > span {
498
+ .dropdown > div:first-child > a, .dropdown > div:first-child > span {
469
499
  line-height: 1.3;
470
- padding: 1pt 5pt;
500
+ padding: var(--nav-item-padding);
471
501
  text-decoration: none;
472
502
  color: inherit;
473
503
  border-radius: var(--nav-border-radius) 0 0 var(--nav-border-radius);
@@ -476,7 +506,7 @@ function get_external_attrs(route) {
476
506
  color: var(--nav-link-active-color);
477
507
  }
478
508
  .dropdown > div:first-child > button {
479
- padding: 1pt 3pt;
509
+ padding: 2pt 4pt;
480
510
  border: none;
481
511
  background: transparent;
482
512
  color: inherit;
@@ -486,40 +516,49 @@ function get_external_attrs(route) {
486
516
  justify-content: center;
487
517
  border-radius: 0 var(--nav-border-radius) var(--nav-border-radius) 0;
488
518
  outline-offset: -1px;
519
+ opacity: 0.6;
520
+ transition: opacity 0.15s, transform 0.2s ease;
521
+ }
522
+ .dropdown > div:first-child > button:hover {
523
+ opacity: 1;
524
+ }
525
+ .dropdown > div:first-child > button.open {
526
+ opacity: 1;
527
+ transform: rotate(180deg);
489
528
  }
490
529
  .dropdown > div:first-child > button:focus-visible {
491
530
  outline: 2px solid currentColor;
492
531
  outline-offset: -2px;
532
+ opacity: 1;
493
533
  }
494
534
  .dropdown > div:last-child {
495
535
  position: absolute;
496
536
  top: 100%;
497
537
  left: 0;
498
- margin: var(--nav-dropdown-margin, 3pt 0 0 0);
538
+ margin: var(--nav-dropdown-margin, 2pt) 0 0 0;
499
539
  min-width: max-content;
500
540
  background-color: var(--nav-dropdown-bg, var(--nav-surface-bg));
501
541
  border: 1px solid var(--nav-dropdown-border-color, var(--nav-surface-border));
502
542
  border-radius: var(--nav-border-radius, 6pt);
503
543
  box-shadow: var(--nav-dropdown-shadow, var(--nav-surface-shadow));
504
- padding: var(--nav-dropdown-padding, 2pt 3pt);
544
+ padding: var(--nav-dropdown-padding, 3pt 0);
505
545
  display: none;
506
546
  flex-direction: column;
507
- gap: var(--nav-dropdown-gap, 5pt);
508
547
  z-index: var(--nav-dropdown-z-index, 100);
509
548
  }
510
549
  .dropdown > div:last-child.visible {
511
550
  display: flex;
512
551
  }
513
552
  .dropdown > div:last-child a {
514
- padding: var(--nav-dropdown-link-padding, 1pt 4pt);
515
- border-radius: var(--nav-border-radius);
553
+ padding: var(--nav-dropdown-link-padding, 2pt 6pt);
516
554
  text-decoration: none;
517
555
  color: inherit;
518
556
  white-space: nowrap;
519
- transition: background-color 0.2s;
557
+ font-size: 0.92em;
558
+ transition: background-color 0.15s;
520
559
  }
521
560
  .dropdown > div:last-child a:hover {
522
- background-color: var(--nav-link-bg-hover);
561
+ background-color: var(--nav-link-bg-hover, rgba(0, 0, 0, 0.1));
523
562
  }
524
563
  .dropdown > div:last-child a[aria-current='page'] {
525
564
  color: var(--nav-link-active-color);
@@ -610,15 +649,29 @@ function get_external_attrs(route) {
610
649
  nav.mobile .dropdown > div:first-child > button {
611
650
  padding: 4pt 8pt;
612
651
  border-radius: var(--nav-border-radius);
652
+ opacity: 0.6;
653
+ }
654
+ nav.mobile .dropdown > div:first-child > button.open {
655
+ opacity: 1;
613
656
  }
614
657
  nav.mobile .dropdown > div:last-child {
615
658
  position: static;
616
659
  border: none;
617
660
  box-shadow: none;
618
- margin-top: 0.25em;
619
- padding: 0 0 0 1em;
661
+ margin-top: 2pt;
662
+ padding: 0;
620
663
  background-color: transparent;
621
664
  }
665
+ nav.mobile .dropdown > div:last-child a {
666
+ padding: 4pt 8pt 4pt 6pt;
667
+ margin-left: 8pt;
668
+ border-left: 2px solid transparent;
669
+ font-size: 0.9em;
670
+ }
671
+ nav.mobile .dropdown > div:last-child a:hover,
672
+ nav.mobile .dropdown > div:last-child a[aria-current='page'] {
673
+ border-left-color: var(--nav-link-active-color, currentColor);
674
+ }
622
675
  /* Mobile right-aligned items stack normally */
623
676
  nav.mobile .menu > .align-right,
624
677
  nav.mobile .menu > .dropdown.align-right {
@@ -1,7 +1,7 @@
1
1
  import type { Page } from '@sveltejs/kit';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import { type TooltipOptions } from './attachments';
4
+ import type { TooltipOptions } from './attachments';
5
5
  import type { NavRoute, NavRouteObject } from './types';
6
6
  interface ItemSnippetParams {
7
7
  route: NavRouteObject;
@@ -1,4 +1,6 @@
1
1
  import { type Attachment } from 'svelte/attachments';
2
+ import { get_uuid } from './utils';
3
+ export { get_uuid };
2
4
  declare global {
3
5
  interface CSS {
4
6
  highlights: HighlightRegistry;
@@ -1,4 +1,7 @@
1
1
  import {} from 'svelte/attachments';
2
+ import { get_uuid } from './utils';
3
+ // Re-export get_uuid for backwards compatibility
4
+ export { get_uuid };
2
5
  // Svelte 5 attachment factory to make an element draggable
3
6
  // @param options - Configuration options for dragging behavior
4
7
  // @returns Attachment function that sets up dragging on an element
@@ -440,7 +443,7 @@ export const tooltip = (options = {}) => (node) => {
440
443
  const placement = options.placement || `bottom`;
441
444
  tooltip_el.setAttribute(`data-placement`, placement);
442
445
  // Accessibility: link tooltip to trigger element
443
- const tooltip_id = `tooltip-${crypto.randomUUID()}`;
446
+ const tooltip_id = `tooltip-${get_uuid()}`;
444
447
  tooltip_el.id = tooltip_id;
445
448
  tooltip_el.setAttribute(`role`, `tooltip`);
446
449
  element.setAttribute(`aria-describedby`, tooltip_id);
@@ -6,8 +6,8 @@
6
6
  // Avoid matching inside src={...} attributes by requiring these specific contexts
7
7
  // Note: [^>]* for attributes won't match if an attribute value contains > (e.g., data-foo="a>b")
8
8
  // This edge case is rare in practice and would require significantly more complex parsing
9
- const heading_regex_line_start = /^(\s*)<(h[2-6])([^>]*)>([\s\S]*?)<\/\2>/gim;
10
- const heading_regex_after_tag = /(>)(\s*)<(h[2-6])([^>]*)>([\s\S]*?)<\/\3>/gi;
9
+ const heading_regex_line_start = /^(\s*)<(h[1-6])([^>]*)>([\s\S]*?)<\/\2>/gim;
10
+ const heading_regex_after_tag = /(>)(\s*)<(h[1-6])([^>]*)>([\s\S]*?)<\/\3>/gi;
11
11
  // Remove Svelte expressions handling nested braces (e.g., {fn({a: 1})})
12
12
  // Treats unmatched } as literal text to avoid dropping content
13
13
  function strip_svelte_expressions(str) {
@@ -94,25 +94,19 @@ function add_anchor_to_heading(heading, icon_svg = link_svg) {
94
94
  export const heading_anchors = (options = {}) => (node) => {
95
95
  if (typeof document === `undefined`)
96
96
  return;
97
- const selector = options.selector ?? `h2, h3, h4, h5, h6`;
97
+ // :scope refers to the element on which querySelectorAll is called
98
+ // This works whether the attachment is on <main> or a parent element
99
+ const selector = options.selector ??
100
+ `:scope > :is(h1, h2, h3, h4, h5, h6), :scope > * > :is(h1, h2, h3, h4, h5, h6)`;
98
101
  const icon_svg = options.icon_svg ?? link_svg;
99
102
  // Process existing headings
100
103
  for (const heading of Array.from(node.querySelectorAll(selector))) {
101
104
  add_anchor_to_heading(heading, icon_svg);
102
105
  }
103
- // Watch for new headings
104
- const observer = new MutationObserver((mutations) => {
105
- for (const { addedNodes } of mutations) {
106
- for (const added of Array.from(addedNodes)) {
107
- if (added.nodeType !== Node.ELEMENT_NODE)
108
- continue;
109
- const el = added;
110
- if (el.matches?.(selector))
111
- add_anchor_to_heading(el, icon_svg);
112
- for (const hdn of Array.from(el.querySelectorAll(selector))) {
113
- add_anchor_to_heading(hdn, icon_svg);
114
- }
115
- }
106
+ // Watch for new headings - requery the container to respect nesting depth constraints
107
+ const observer = new MutationObserver(() => {
108
+ for (const heading of Array.from(node.querySelectorAll(selector))) {
109
+ add_anchor_to_heading(heading, icon_svg);
116
110
  }
117
111
  });
118
112
  observer.observe(node, { childList: true, subtree: true });
@@ -0,0 +1,62 @@
1
+ // Starry-night highlighter for mdsvex
2
+ import { createStarryNight } from '@wooorm/starry-night';
3
+ import source_css from '@wooorm/starry-night/source.css';
4
+ import source_js from '@wooorm/starry-night/source.js';
5
+ import source_json from '@wooorm/starry-night/source.json';
6
+ import source_shell from '@wooorm/starry-night/source.shell';
7
+ import source_svelte from '@wooorm/starry-night/source.svelte';
8
+ import source_ts from '@wooorm/starry-night/source.ts';
9
+ import text_html_basic from '@wooorm/starry-night/text.html.basic';
10
+ // Escape HTML special characters in text content (not for attribute values)
11
+ const escape_html_text = (str) => str.replace(/&/g, `&amp;`).replace(/</g, `&lt;`).replace(/>/g, `&gt;`);
12
+ // Convert HAST to HTML string (simplified - only handles what starry-night outputs)
13
+ export const hast_to_html = (node) => {
14
+ if (node.type === `text`)
15
+ return escape_html_text(node.value);
16
+ if (node.type === `root`)
17
+ return node.children?.map(hast_to_html).join(``) ?? ``;
18
+ const { tagName, properties, children } = node;
19
+ const cls = properties?.className?.join(` `);
20
+ const attrs = cls ? ` class="${cls}"` : ``;
21
+ const inner = children?.map(hast_to_html).join(``) ?? ``;
22
+ return `<${tagName}${attrs}>${inner}</${tagName}>`;
23
+ };
24
+ // Shared starry-night instance (grammars loaded once at build time)
25
+ export const starry_night = await createStarryNight([
26
+ source_svelte,
27
+ source_js,
28
+ source_ts,
29
+ source_css,
30
+ source_json,
31
+ source_shell,
32
+ text_html_basic,
33
+ ]);
34
+ // Map code fence language to starry-night grammar scope
35
+ export const LANG_TO_SCOPE = {
36
+ svelte: `source.svelte`,
37
+ html: `text.html.basic`,
38
+ ts: `source.ts`,
39
+ typescript: `source.ts`,
40
+ js: `source.js`,
41
+ javascript: `source.js`,
42
+ css: `source.css`,
43
+ json: `source.json`,
44
+ shell: `source.shell`,
45
+ bash: `source.shell`,
46
+ sh: `source.shell`,
47
+ };
48
+ // Escape characters that would be interpreted as Svelte template syntax
49
+ const escape_svelte = (html) => html.replace(/\{/g, `&#123;`).replace(/\}/g, `&#125;`);
50
+ // mdsvex highlighter function
51
+ export function starry_night_highlighter(code, lang) {
52
+ const lang_key = lang?.toLowerCase();
53
+ const scope = lang_key ? LANG_TO_SCOPE[lang_key] : undefined;
54
+ if (!scope) {
55
+ // Return escaped code if language not supported
56
+ const escaped = escape_svelte(escape_html_text(code));
57
+ return `<pre class="highlight"><code>${escaped}</code></pre>`;
58
+ }
59
+ const tree = starry_night.highlight(code, scope);
60
+ const html = escape_svelte(hast_to_html(tree));
61
+ return `<pre class="highlight highlight-${lang_key}"><code>${html}</code></pre>`;
62
+ }
@@ -0,0 +1,7 @@
1
+ export { starry_night_highlighter } from './highlighter.js';
2
+ export { default as mdsvex_transform, EXAMPLE_COMPONENT_PREFIX, EXAMPLE_MODULE_PREFIX, } from './mdsvex-transform.js';
3
+ export { default as vite_plugin } from './vite-plugin.js';
4
+ import { sveltePreprocess as _sveltePreprocess } from 'svelte-preprocess';
5
+ type SveltePreprocessOptions = Parameters<typeof _sveltePreprocess>[0];
6
+ type PreprocessorGroup = ReturnType<typeof _sveltePreprocess>;
7
+ export declare function sveltePreprocess(opts?: SveltePreprocessOptions): PreprocessorGroup;
@@ -0,0 +1,23 @@
1
+ // Live examples - transforms ```svelte example code blocks into rendered components
2
+ // with syntax highlighting and live preview
3
+ export { starry_night_highlighter } from './highlighter.js';
4
+ export { default as mdsvex_transform, EXAMPLE_COMPONENT_PREFIX, EXAMPLE_MODULE_PREFIX, } from './mdsvex-transform.js';
5
+ export { default as vite_plugin } from './vite-plugin.js';
6
+ import { sveltePreprocess as _sveltePreprocess } from 'svelte-preprocess';
7
+ // Wrap sveltePreprocess to skip markdown files - otherwise it transpiles code inside
8
+ // markdown code fences, losing whitespace formatting
9
+ const is_markdown = (filename) => /\.(md|mdx|svx)$/.test(filename ?? ``);
10
+ export function sveltePreprocess(opts) {
11
+ const base = _sveltePreprocess(opts);
12
+ return {
13
+ markup: async (args) => is_markdown(args.filename)
14
+ ? { code: args.content }
15
+ : (await base.markup?.(args)) ?? { code: args.content },
16
+ script: async (args) => is_markdown(args.filename)
17
+ ? { code: args.content }
18
+ : (await base.script?.(args)) ?? { code: args.content },
19
+ style: async (args) => is_markdown(args.filename)
20
+ ? { code: args.content }
21
+ : (await base.style?.(args)) ?? { code: args.content },
22
+ };
23
+ }
@@ -0,0 +1,32 @@
1
+ export declare const EXAMPLE_MODULE_PREFIX = "___live_example___";
2
+ export declare const EXAMPLE_COMPONENT_PREFIX = "LiveExample___";
3
+ interface RemarkMeta {
4
+ Wrapper?: string | [string, string];
5
+ filename?: string;
6
+ csr?: boolean;
7
+ example?: boolean;
8
+ hideScript?: boolean;
9
+ hideStyle?: boolean;
10
+ [key: string]: unknown;
11
+ }
12
+ interface RemarkOptions {
13
+ defaults?: Partial<RemarkMeta>;
14
+ }
15
+ interface RemarkTree {
16
+ type: string;
17
+ children: RemarkNode[];
18
+ }
19
+ interface RemarkNode {
20
+ type: string;
21
+ lang?: string;
22
+ meta?: string;
23
+ value?: string;
24
+ children?: RemarkNode[];
25
+ }
26
+ interface RemarkFile {
27
+ filename: string;
28
+ cwd: string;
29
+ }
30
+ type RemarkTransformer = (tree: RemarkTree, file: RemarkFile) => void;
31
+ declare function remark(options?: RemarkOptions): RemarkTransformer;
32
+ export default remark;