@sveltejs/vite-plugin-svelte 7.1.4 → 7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/vite-plugin-svelte",
3
- "version": "7.1.4",
3
+ "version": "7.2.0",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "src",
@@ -11,6 +11,7 @@ export const defaultInspectorOptions = {
11
11
  navKeys: { parent: 'ArrowUp', child: 'ArrowDown', next: 'ArrowRight', prev: 'ArrowLeft' },
12
12
  escapeKeys: ['Backspace', 'Escape'],
13
13
  openKey: 'Enter',
14
+ openMenuKey: ' ',
14
15
  holdMode: true,
15
16
  showToggleButton: 'active',
16
17
  toggleButtonPos: 'top-right',
@@ -9,6 +9,7 @@
9
9
  const escape_keys = options.escapeKeys?.map((k) => k.toLowerCase());
10
10
  const nav_keys = Object.values(options.navKeys).map((k) => k?.toLowerCase());
11
11
  const open_key = options.openKey?.toLowerCase();
12
+ const open_menu_key = options.openMenuKey?.toLowerCase();
12
13
 
13
14
  let enabled = $state(false);
14
15
  let has_opened = $state(false);
@@ -25,15 +26,16 @@
25
26
  .trim()
26
27
  )}`;
27
28
 
28
- // location of code in file
29
- let file_loc = $state();
30
- // cursor pos and width for file_loc overlay positioning
29
+ // overlay positioning
31
30
  let x = $state(),
32
31
  y = $state(),
33
- w = $state();
32
+ w = $state(),
33
+ h = $state();
34
34
 
35
35
  let active_el = $state();
36
36
 
37
+ let menu = $state(null);
38
+
37
39
  let hold_start_ts = $state();
38
40
 
39
41
  let show_toggle = $derived(
@@ -41,6 +43,7 @@
41
43
  );
42
44
 
43
45
  function mousemove(e) {
46
+ if (menu) return;
44
47
  x = e.x;
45
48
  y = e.y;
46
49
  }
@@ -102,6 +105,7 @@
102
105
  }
103
106
 
104
107
  function mouseover({ target }) {
108
+ if (menu) return;
105
109
  const el = find_selectable_parent(target, true);
106
110
  activate(el, false);
107
111
  }
@@ -115,12 +119,7 @@
115
119
  el.classList.add('svelte-inspector-active-target');
116
120
  }
117
121
  }
118
- if (el) {
119
- const { file, line, column } = el.__svelte_meta.loc;
120
- file_loc = `${file}:${line + 1}:${column + 1}`;
121
- } else {
122
- file_loc = null;
123
- }
122
+
124
123
  active_el = el;
125
124
  if (set_bubble_pos) {
126
125
  const pos = el.getBoundingClientRect();
@@ -130,13 +129,63 @@
130
129
  }
131
130
 
132
131
  function open_editor(e) {
133
- if (file_loc) {
132
+ if (menu) return;
133
+
134
+ if (active_el) {
134
135
  stop(e);
135
- fetch(`${options.__internal.base}/__open-in-editor?file=${encodeURIComponent(file_loc)}`);
136
- has_opened = true;
137
- if (options.holdMode && is_holding()) {
138
- disable();
136
+ send(active_el.__svelte_meta.loc);
137
+ }
138
+ }
139
+
140
+ function get_stack(target) {
141
+ const el = find_selectable_parent(target, true);
142
+ const meta = el?.__svelte_meta;
143
+
144
+ const stack = [
145
+ {
146
+ file: meta.loc.file,
147
+ line: meta.loc.line,
148
+ column: meta.loc.column,
149
+ tag: el.tagName.toLowerCase()
139
150
  }
151
+ ];
152
+
153
+ let entry = meta;
154
+ while ((entry = entry.parent)) {
155
+ if (entry.type !== 'component') continue;
156
+ if (/(^|\/)(node_modules|\.svelte-kit)\//.test(entry.file)) continue;
157
+
158
+ stack.push({
159
+ file: entry.file,
160
+ line: entry.line,
161
+ column: entry.column,
162
+ tag: entry.componentTag
163
+ });
164
+ }
165
+
166
+ return stack;
167
+ }
168
+
169
+ function on_contextmenu(e) {
170
+ e.preventDefault();
171
+
172
+ active_el ??= find_selectable_parent(e.target);
173
+ if (!active_el) return;
174
+
175
+ stop(e);
176
+ menu = { x: e.clientX, y: e.clientY, stack: get_stack(active_el) };
177
+ }
178
+
179
+ function send(loc) {
180
+ fetch(
181
+ `${options.__internal.base}/__open-in-editor?file=${encodeURIComponent(
182
+ `${loc.file}:${loc.line}:${loc.column + 1}`
183
+ )}`
184
+ );
185
+ has_opened = true;
186
+ menu = null;
187
+ if (options.holdMode && is_holding()) {
188
+ disable();
140
189
  }
141
190
  }
142
191
 
@@ -172,6 +221,10 @@
172
221
  return open_key && is_active(open_key, e);
173
222
  }
174
223
 
224
+ function is_open_menu(e) {
225
+ return open_menu_key && is_active(open_menu_key, e);
226
+ }
227
+
175
228
  function is_holding() {
176
229
  return hold_start_ts && Date.now() - hold_start_ts > 250;
177
230
  }
@@ -200,6 +253,8 @@
200
253
  }
201
254
  } else if (is_open(e)) {
202
255
  open_editor(e);
256
+ } else if (is_open_menu(e)) {
257
+ on_contextmenu(e);
203
258
  } else if (is_holding() || is_escape(e)) {
204
259
  // is_holding() checks for unhandled additional key pressed
205
260
  // while holding the toggle keys, which is possibly another
@@ -236,6 +291,7 @@
236
291
  l('mousemove', mousemove);
237
292
  l('mouseover', mouseover);
238
293
  l('click', open_editor, true);
294
+ l('contextmenu', on_contextmenu, true);
239
295
  }
240
296
 
241
297
  function enable() {
@@ -277,6 +333,7 @@
277
333
  enabled = false;
278
334
  has_opened = false;
279
335
  hold_start_ts = null;
336
+ menu = null;
280
337
  const b = document.body;
281
338
  listeners(b, enabled);
282
339
  if (options.customStyles) {
@@ -332,6 +389,15 @@
332
389
  });
333
390
  </script>
334
391
 
392
+ <svelte:window
393
+ onclick={disable}
394
+ onkeydown={(e) => {
395
+ if (e.key === 'Escape') {
396
+ disable();
397
+ }
398
+ }}
399
+ />
400
+
335
401
  {#if show_toggle}
336
402
  <button
337
403
  id="svelte-inspector-toggle"
@@ -344,18 +410,57 @@
344
410
  aria-label={`${enabled ? 'disable' : 'enable'} svelte-inspector`}
345
411
  ></button>
346
412
  {/if}
347
- {#if enabled && active_el && file_loc}
348
- {@const loc = active_el.__svelte_meta.loc}
413
+
414
+ {#if enabled && (menu || active_el)}
349
415
  <div
350
416
  id="svelte-inspector-overlay"
351
417
  style:left="{Math.min(x + 3, document.documentElement.clientWidth - w - 10)}px"
352
- style:top="{document.documentElement.clientHeight < y + 50 ? y - 30 : y + 30}px"
418
+ style:top="{document.documentElement.clientHeight < y + h + 40 ? y - h - 10 : y + 30}px"
353
419
  bind:offsetWidth={w}
420
+ bind:offsetHeight={h}
354
421
  >
355
- &lt;{active_el.tagName.toLowerCase()}&gt;&nbsp;{file_loc}
356
- </div>
357
- <div id="svelte-inspector-announcer" aria-live="assertive" aria-atomic="true">
358
- {active_el.tagName.toLowerCase()} in file {loc.file} on line {loc.line} column {loc.column}
422
+ {#if menu}
423
+ <button aria-label="close" class="svelte-inspector-button" {@attach (node) => node.focus()}>
424
+ <span>close</span>
425
+ <svg
426
+ xmlns="http://www.w3.org/2000/svg"
427
+ role="img"
428
+ width="1em"
429
+ height="1em"
430
+ viewBox="0 0 24 24"
431
+ stroke-width="2"
432
+ stroke-linecap="round"
433
+ stroke-linejoin="round"><path d="M18 6 6 18" /><path d="m6 6 12 12" /></svg
434
+ >
435
+ </button>
436
+
437
+ <hr />
438
+
439
+ <ul class="svelte-inspector-grid">
440
+ {#each menu.stack as item, i (item.file + item.line + i)}
441
+ <li>
442
+ <button type="button" class="svelte-inspector-menu-row" onclick={() => send(item)}>
443
+ <span class="svelte-inspector-tag">&lt;{item.tag}&gt;</span>
444
+ <span class="svelte-inspector-file">{item.file}:{item.line}</span>
445
+ </button>
446
+ </li>
447
+ {/each}
448
+ </ul>
449
+ {:else}
450
+ {@const loc = active_el.__svelte_meta.loc}
451
+
452
+ <div class="svelte-inspector-grid">
453
+ <div class="svelte-inspector-menu-row">
454
+ <span class="svelte-inspector-tag">&lt;{active_el.tagName.toLowerCase()}&gt;</span>
455
+ <span class="svelte-inspector-file">{loc.file}:{loc.line}</span>
456
+ </div>
457
+ </div>
458
+
459
+ <div id="svelte-inspector-announcer" aria-live="assertive" aria-atomic="true">
460
+ {active_el.tagName.toLowerCase()} in file {loc.file} on line {loc.line} column {loc.column +
461
+ 1}
462
+ </div>
463
+ {/if}
359
464
  </div>
360
465
  {/if}
361
466
 
@@ -370,18 +475,35 @@
370
475
  direction: ltr;
371
476
  }
372
477
 
478
+ *:not(svg *) {
479
+ all: unset;
480
+ box-sizing: border-box;
481
+ }
482
+
373
483
  #svelte-inspector-overlay {
374
484
  position: fixed;
375
- background-color: rgba(0, 0, 0, 0.8);
376
- color: #fff;
377
- padding: 2px 4px;
378
- border-radius: 5px;
485
+ padding: 2px;
486
+ margin: 0;
487
+ border-radius: 2px;
488
+ filter: drop-shadow(2px 2px 4px rgb(0 0 0 / 0.1));
489
+ font-family: ui-monospace, 'SF Mono', Menlo, monospace;
490
+ font-size: 12px;
491
+ line-height: 1.4;
379
492
  z-index: 999999;
380
- pointer-events: none;
493
+ background-color: #fff;
494
+ color: #222;
495
+ cursor: auto;
496
+ user-select: none;
497
+ }
498
+
499
+ .svelte-inspector-grid {
500
+ display: grid;
501
+ grid-template-columns: max-content 1fr;
502
+ column-gap: 8px;
503
+ /* row-gap: 4px; */
381
504
  }
382
505
 
383
506
  #svelte-inspector-toggle {
384
- all: unset;
385
507
  border: 1px solid #ff3e00;
386
508
  border-radius: 8px;
387
509
  position: fixed;
@@ -411,4 +533,83 @@
411
533
  #svelte-inspector-toggle:hover {
412
534
  background-color: #facece;
413
535
  }
536
+
537
+ .svelte-inspector-tag {
538
+ white-space: nowrap;
539
+ font-weight: 600;
540
+ }
541
+
542
+ .svelte-inspector-file {
543
+ overflow: hidden;
544
+ text-overflow: ellipsis;
545
+ white-space: nowrap;
546
+ color: #444;
547
+ }
548
+
549
+ ul {
550
+ max-width: 480px;
551
+ list-style: none;
552
+ margin: 0;
553
+ padding: 0;
554
+ display: contents;
555
+
556
+ li {
557
+ display: contents;
558
+ }
559
+ }
560
+
561
+ button {
562
+ background: transparent;
563
+ border: none;
564
+ color: inherit;
565
+ pointer-events: all;
566
+ font: inherit;
567
+ align-items: center;
568
+ cursor: pointer;
569
+
570
+ &:focus-visible {
571
+ outline: 2px solid #ff3e00;
572
+ }
573
+
574
+ &:hover,
575
+ &:focus-visible {
576
+ background-color: rgb(0 0 0 / 0.05);
577
+ }
578
+ }
579
+
580
+ hr {
581
+ margin: 2px;
582
+ background: rgb(0 0 0 / 0.05);
583
+ border: none;
584
+ height: 1px;
585
+ width: 100%;
586
+ display: block;
587
+ }
588
+
589
+ svg path {
590
+ stroke: currentColor;
591
+ }
592
+
593
+ .svelte-inspector-button {
594
+ display: flex;
595
+ justify-content: space-between;
596
+ width: 100%;
597
+ padding: 4px 8px;
598
+ }
599
+
600
+ .svelte-inspector-menu-row {
601
+ display: grid;
602
+ grid-column: 1 / 3;
603
+ grid-template-columns: subgrid;
604
+ box-sizing: border-box;
605
+ align-items: baseline;
606
+ width: 100%;
607
+ padding: 4px 8px;
608
+ cursor: pointer;
609
+
610
+ &:hover,
611
+ &:focus-visible {
612
+ background-color: rgb(0 0 0 / 0.05);
613
+ }
614
+ }
414
615
  </style>
package/src/public.d.ts CHANGED
@@ -228,6 +228,13 @@ export interface InspectorOptions {
228
228
  */
229
229
  openKey?: string;
230
230
 
231
+ /**
232
+ * define key to open the context menu for the currently selected dom node
233
+ *
234
+ * @default ' '
235
+ */
236
+ openMenuKey?: string;
237
+
231
238
  /**
232
239
  * define keys to close the inspector
233
240
  * @default ['Backspace', 'Escape']
package/types/index.d.ts CHANGED
@@ -228,6 +228,13 @@ declare module '@sveltejs/vite-plugin-svelte' {
228
228
  */
229
229
  openKey?: string;
230
230
 
231
+ /**
232
+ * define key to open the context menu for the currently selected dom node
233
+ *
234
+ * @default ' '
235
+ */
236
+ openMenuKey?: string;
237
+
231
238
  /**
232
239
  * define keys to close the inspector
233
240
  * @default ['Backspace', 'Escape']
@@ -27,6 +27,6 @@
27
27
  null,
28
28
  null
29
29
  ],
30
- "mappings": ";;;aAGYA,OAAOA;;WAETC,mBAAmBA;;;;;;;;;;;kBAWZC,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgFbC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAiDnBC,mBAAmBA;;;;;;;;;;;;;;;;WAgBnBC,oBAAoBA;;;;;;;;;;;;;;;MAezBC,SAASA;;kBAEGC,qBAAqBA;;;;;;;;;;;;;;kBAcrBC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCzKjBC,MAAMA;iBCGNC,cAAcA;iBCARC,gBAAgBA",
30
+ "mappings": ";;;aAGYA,OAAOA;;WAETC,mBAAmBA;;;;;;;;;;;kBAWZC,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgFbC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAiDnBC,mBAAmBA;;;;;;;;;;;;;;;;WAgBnBC,oBAAoBA;;;;;;;;;;;;;;;MAezBC,SAASA;;kBAEGC,qBAAqBA;;;;;;;;;;;;;;kBAcrBC,gBAAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCzKjBC,MAAMA;iBCGNC,cAAcA;iBCARC,gBAAgBA",
31
31
  "ignoreList": []
32
32
  }