@fusion.dev/helix 0.169.0 → 0.171.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/custom-elements.json +952 -51
- package/dist/chat/root/chat-root.css.js +1 -1
- package/dist/code-block/root/code-block-root.css.js +11 -3
- package/dist/data-table/root/data-table-root.css.js +3 -1
- package/dist/data-table/root/data-table-root.d.ts +6 -3
- package/dist/filter-input/root/filter-input-root.css.js +2 -1
- package/dist/filter-input/root/filter-input-root.d.ts +1 -0
- package/dist/filter-input/root/filter-input-root.js +3 -0
- package/dist/sandbox/frame.d.ts +9 -1
- package/dist/sandbox/frame.js +6 -2
- package/dist/sandbox/preview/sandbox-preview.d.ts +16 -0
- package/dist/sandbox/preview/sandbox-preview.js +7 -4
- package/dist/sandbox/source/sandbox-source.css.js +1 -1
- package/dist/sandbox/source/sandbox-source.d.ts +45 -5
- package/dist/sandbox/source/sandbox-source.js +85 -7
- package/lint.json +1 -1
- package/package.json +6 -6
- package/types/jsx.d.ts +464 -86
- package/types/vue.d.ts +112 -18
- package/types/words.d.ts +6 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createSheet } from '@fusion.dev/helix-core';
|
|
2
2
|
export const styles = createSheet(`:host {display: grid;grid-template-rows: auto minmax(0, 1fr) auto auto auto;max-block-size: var(--chat-max-block-size, none);min-block-size: 0;}[part="header"] {grid-row: 1;}[part="log"] {grid-row: 2;}[part="resume"] {grid-row: 3;}[part="status"] {grid-row: 4;}[part="composer"] {grid-row: 5;}[part="log"] {display: flex;flex-direction: column;scrollbar-color: var(--chat-scrollbar-thumb-color, var(--helix-scrollbar-thumb-color))
|
|
3
|
-
var(--chat-scrollbar-track-color, var(--helix-scrollbar-track-color));scrollbar-width: thin;gap: var(--chat-gap, var(--helix-space-md));overflow-y: auto;padding-block: var(--helix-space-md);padding-inline: var(--chat-padding-inline, var(--helix-space-md));justify-content: safe flex-end;}[part="log"]:hover {scrollbar-color: var(--chat-scrollbar-thumb-hover-color, var(--helix-scrollbar-thumb-hover-color))
|
|
3
|
+
var(--chat-scrollbar-track-color, var(--helix-scrollbar-track-color));scrollbar-width: thin;gap: var(--chat-gap, var(--helix-space-md));overflow-y: auto;padding-block: var(--helix-space-md);padding-inline: var(--chat-padding-inline, var(--helix-space-md));justify-content: safe flex-end;}[part="log"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}[part="log"]:hover {scrollbar-color: var(--chat-scrollbar-thumb-hover-color, var(--helix-scrollbar-thumb-hover-color))
|
|
4
4
|
var(--chat-scrollbar-track-color, var(--helix-scrollbar-track-color));}[part="header"][hidden],
|
|
5
5
|
[part="resume"][hidden],
|
|
6
6
|
[part="composer"][hidden] {display: none;}[part="status"][data-empty] {padding-block: 0;}[part="header"] {--helix-size-tag: var(--helix-size-tag-sm);align-items: center;border-block-end: var(--helix-border-thin) solid var(--chat-rule, var(--helix-color-border));display: flex;gap: var(--helix-space-sm);justify-content: space-between;min-block-size: var(--helix-size-control);padding-block: var(--helix-space-2xs);padding-inline: var(--chat-padding-inline, var(--helix-space-md));}[part="header"] > [part="actions"] {--helix-size-control: var(--helix-size-control-sm);--helix-size-control-loose: calc(var(--helix-size-control) * 1.2);--helix-size-control-tight: calc(var(--helix-size-control) * 0.8);--helix-size-icon: var(--helix-size-icon-sm);--helix-size-icon-loose: calc(var(--helix-size-icon) * 1.2);--helix-size-icon-tight: calc(var(--helix-size-icon) * 0.8);align-items: center;display: flex;flex: 0 0 auto;gap: var(--helix-space-2xs);}[part="header"] > [part="actions"][hidden] {display: none;}[part="resume"] {display: grid;justify-items: center;margin-block-start: calc(var(--helix-space-xl) * -1);pointer-events: none;position: relative;}[part="resume"] > * {pointer-events: auto;}[part="resume"] slot::slotted(*) {border: var(--chat-resume-border-width, var(--helix-border-floating)) solid
|
|
@@ -3,14 +3,22 @@ export const styles = createSheet(`:host {--_code-block-size: var(--code-block-f
|
|
|
3
3
|
> :is([part="actions"], [part="wrap-toggle"])
|
|
4
4
|
~ :is([part="copy"], [part="wrap-toggle"]) {margin-inline-start: var(--helix-space-none);}[part="wrap-toggle"] {all: unset;box-sizing: border-box;border-radius: var(--helix-radii-sm);color: var(--code-block-label-color, var(--helix-color-foreground-muted));cursor: pointer;font-family: var(--helix-font-sans);font-size: var(--helix-text-xs);font-weight: var(--helix-weight-medium);margin-inline-start: auto;padding-block: var(--helix-space-2xs);padding-inline: var(--helix-space-xs);}[part="wrap-toggle"]:hover,
|
|
5
5
|
[part="wrap-toggle"][aria-pressed="true"] {color: var(--helix-color-foreground);}[part="wrap-toggle"][aria-pressed="true"] {background-color: color-mix(in oklab, var(--helix-color-foreground) 8%, transparent);}[part="wrap-toggle"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: var(--helix-size-focus-offset);}[part="frame"] > [part="copy"] {font-size: var(--_code-block-size);inset-block-start: var(--_code-block-copy-inset);inset-inline-end: var(--_code-block-copy-inset);line-height: var(--_code-block-leading);position: absolute;}[part="block"] {backdrop-filter: var(--code-block-backdrop, none);background-color: var(--code-block-background-color, var(--helix-color-background));border: var(--helix-border-thin) solid var(--code-block-border-color, var(--helix-color-border));border-radius: var(--code-block-radius, var(--helix-radii-lg));margin: var(--helix-space-none);overflow-x: auto;padding-block: var(--helix-space-sm);padding-inline: var(--helix-space-md);}:host(:not([diff], [no-copy])) [part="frame"]:not([part="header"] + *) > [part="block"] {padding-inline-end: var(--_code-block-gutter);}[part="header"] + [part="frame"] [part="block"] {border-block-start-width: var(--helix-space-none);border-start-end-radius: var(--helix-radii-none);border-start-start-radius: var(--helix-radii-none);}[part="files"] {backdrop-filter: var(--code-block-backdrop, none);background-color: var(--code-block-header-background-color, var(--helix-color-surface-raised));border: var(--helix-border-thin) solid var(--code-block-border-color, var(--helix-color-border));border-block-end-width: var(--helix-space-none);border-start-end-radius: var(--code-block-radius, var(--helix-radii-lg));border-start-start-radius: var(--code-block-radius, var(--helix-radii-lg));display: flex;overflow-x: auto;padding-inline: var(--helix-space-xs);}[part="file-tab"] {background-color: transparent;border: none;border-block-end: var(--helix-border-thick) solid transparent;color: var(--code-block-label-color, var(--helix-color-foreground-muted));cursor: pointer;font-family: var(--helix-font-sans);font-size: var(--helix-text-xs);font-weight: var(--helix-weight-medium);padding-block: var(--helix-space-xs);padding-inline: var(--helix-space-sm);white-space: nowrap;}[part="file-tab"]:hover,
|
|
6
|
-
[part="file-tab"][aria-selected="true"] {color: var(--helix-color-foreground);}[part="file-tab"][aria-selected="true"] {border-block-end-color: var(--helix-color-accent);}[part="file-tab"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}:host(:state(tabbed)) :is([part="header"], [part="block"]) {border-start-end-radius: var(--helix-radii-none);border-start-start-radius: var(--helix-radii-none);}[part="code"] {color: var(--code-block-color, var(--helix-color-foreground));font-family: var(--_code-block-face);font-size: var(--_code-block-size);line-height: var(--_code-block-leading);}:host(:not([diff])) [part="code"] {display: block;isolation: isolate;max-block-size: var(--code-block-max-block-size, none);overflow-x: auto;position: relative;}:host(:state(expanded)) [part="code"] {max-block-size: none;}[part="expand"] {all: unset;box-sizing: border-box;border-radius: var(--helix-radii-sm);color: var(--code-block-expand-color, var(--helix-color-foreground-muted));cursor: pointer;font-size: var(--helix-text-sm);padding: var(--helix-space-xs);}[part="expand"]:hover {color: var(--helix-color-foreground);}[part="expand"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: var(--helix-size-focus-offset);}[part="block"]:focus-visible,
|
|
6
|
+
[part="file-tab"][aria-selected="true"] {color: var(--helix-color-foreground);}[part="file-tab"][aria-selected="true"] {border-block-end-color: var(--helix-color-accent);}[part="file-tab"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}:host(:state(tabbed)) :is([part="header"], [part="block"]) {border-start-end-radius: var(--helix-radii-none);border-start-start-radius: var(--helix-radii-none);}[part="code"] {color: var(--code-block-color, var(--helix-color-foreground));font-family: var(--_code-block-face);font-size: var(--_code-block-size);line-height: var(--_code-block-leading);}:host(:not([diff])) [part="code"] {display: block;isolation: isolate;max-block-size: var(--code-block-max-block-size, none);overflow-x: auto;position: relative;}:host(:state(expanded)) [part="code"] {max-block-size: none;}[part="expand"] {all: unset;box-sizing: border-box;border-radius: var(--helix-radii-sm);color: var(--code-block-expand-color, var(--helix-color-foreground-muted));cursor: pointer;font-size: var(--helix-text-sm);padding: var(--helix-space-xs);}::slotted([slot="expand-icon"]) {margin-inline-end: var(--helix-space-xs);vertical-align: middle;}[part="expand"]:hover {color: var(--helix-color-foreground);}[part="expand"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: var(--helix-size-focus-offset);}[part="block"]:focus-visible,
|
|
7
7
|
[part="code"]:focus-visible,
|
|
8
8
|
[part="old"]:focus-visible,
|
|
9
|
-
[part="new"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}:host([wrap]:not([diff])) [part="code"] {overflow-wrap: anywhere;white-space: pre-wrap;}[part
|
|
9
|
+
[part="new"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}:host([wrap]:not([diff])) [part="code"] {overflow-wrap: anywhere;white-space: pre-wrap;}[part~="mark"] {background-color: var(
|
|
10
10
|
--code-block-mark-color,
|
|
11
11
|
color-mix(in oklab, var(--helix-color-primary) 12%, transparent)
|
|
12
12
|
);block-size: var(--code-block-mark-size, 0);border-inline-start: var(--helix-border-thick) solid
|
|
13
|
-
var(--code-block-mark-edge-color, var(--helix-color-primary));box-sizing: border-box;inline-size: max(100%, var(--code-block-mark-inline-size, 100%));inset-block-start: var(--code-block-mark-start, 0);inset-inline-start: 0;pointer-events: none;position: absolute;z-index: var(--helix-layer-beneath);}
|
|
13
|
+
var(--code-block-mark-edge-color, var(--helix-color-primary));box-sizing: border-box;inline-size: max(100%, var(--code-block-mark-inline-size, 100%));inset-block-start: var(--code-block-mark-start, 0);inset-inline-start: 0;pointer-events: none;position: absolute;z-index: var(--helix-layer-beneath);}[part~="mark-added"] {background-color: color-mix(
|
|
14
|
+
in oklab,
|
|
15
|
+
var(--code-block-added-color, var(--helix-color-success)) 14%,
|
|
16
|
+
transparent
|
|
17
|
+
);border-inline-start-color: var(--code-block-added-color, var(--helix-color-success));}[part~="mark-removed"] {background-color: color-mix(
|
|
18
|
+
in oklab,
|
|
19
|
+
var(--code-block-removed-color, var(--helix-color-danger)) 14%,
|
|
20
|
+
transparent
|
|
21
|
+
);border-inline-start-color: var(--code-block-removed-color, var(--helix-color-danger));}:host([line-numbers]:not([diff])) [part="block"] {column-gap: var(--helix-space-md);display: grid;grid-template-columns: auto minmax(0, 1fr);}[part="gutter"] {color: var(--code-block-gutter-color, var(--helix-color-foreground-subtle));font-family: var(--_code-block-face);font-size: var(--_code-block-size);font-variant-numeric: tabular-nums;line-height: var(--_code-block-leading);text-align: end;user-select: none;}:host([diff]) {gap: var(--helix-space-md);}:host([diff]) [part="file"] {container-type: inline-size;display: flex;flex-direction: column;}:host([diff]) [part="block"],
|
|
14
22
|
[part="old"],
|
|
15
23
|
[part="new"] {backdrop-filter: var(--code-block-backdrop, none);background-color: var(--code-block-background-color, var(--helix-color-background));border: var(--helix-border-thin) solid var(--code-block-border-color, var(--helix-color-border));border-radius: var(--code-block-radius, var(--helix-radii-lg));margin: var(--helix-space-none);min-inline-size: 0;overflow-x: auto;padding-block: var(--helix-space-none) var(--helix-space-sm);padding-inline: var(--helix-space-none);}:host([diff]:not([no-copy]))
|
|
16
24
|
[part="frame"]:not([part="header"] + *)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createSheet } from '@fusion.dev/helix-core';
|
|
2
|
-
export const styles = createSheet(`:host {display: block;}[part="
|
|
2
|
+
export const styles = createSheet(`:host {display: block;}[part="toolbar"],
|
|
3
|
+
[part="table"],
|
|
4
|
+
[part="footer"] {grid-column: 1 / -1;}[part="table"] {display: grid;grid-template-columns: var(--data-table-columns, var(--data-table-template, minmax(0, 1fr)));inline-size: 100%;overflow-x: auto;}[part="table"] {--_data-table-fade: to right;animation: data-table-edges linear both;animation-timeline: scroll(self inline);mask-image: linear-gradient(
|
|
3
5
|
var(--_data-table-fade),
|
|
4
6
|
transparent,
|
|
5
7
|
#000 var(--_data-table-fade-start, 0rem),
|
|
@@ -19,15 +19,18 @@ import '../../table/index.js';
|
|
|
19
19
|
* without `paginated` and with either `mode`, so a page or a chunk from a
|
|
20
20
|
* server can be windowed.
|
|
21
21
|
*
|
|
22
|
-
* **
|
|
23
|
-
*
|
|
22
|
+
* **Write the first page as rows, so the served HTML carries the values.**
|
|
23
|
+
* Write it under the columns as `helix-table-row` and `helix-table-cell`
|
|
24
|
+
* elements. `@fusion.dev/helix-styles/helix.css` lays them out as the table
|
|
25
|
+
* draws them before it upgrades, and the table shows them until `rows` holds a
|
|
26
|
+
* row.
|
|
24
27
|
*
|
|
25
28
|
* @since 0.1.0
|
|
26
29
|
* @status stable
|
|
27
30
|
* @category data
|
|
28
31
|
* @documentation https://fusion.dev/helix/components/data-table
|
|
29
32
|
*
|
|
30
|
-
* @slot - The columns, as `TableColumn` elements.
|
|
33
|
+
* @slot - The columns, as `TableColumn` elements, and the first page served as `TableRow` elements, which show until `rows` holds a row.
|
|
31
34
|
* @slot empty - Content shown when there are no rows to show and none are loading, such as a picture and a link. Falls back to `empty-text`, which the live region still says.
|
|
32
35
|
* @slot error - Content shown while `error-text` is set, such as a button that tries again. Falls back to `error-text`, which the live region still says.
|
|
33
36
|
* @slot footer - Content below the grid. It replaces the built-in pagination.
|
|
@@ -5,4 +5,5 @@ border-color var(--helix-duration-fast) var(--helix-easing-standard),
|
|
|
5
5
|
background-color var(--helix-duration-fast) var(--helix-easing-standard);}::slotted([slot="tags"]) {flex: 0 0 auto;max-inline-size: 100%;}[part="control"] {flex: 1 1 var(--filter-input-control-size, 6ch);}[part="lead"] {align-items: center;align-self: stretch;border-inline-end: var(--helix-border-thin) solid
|
|
6
6
|
var(--filter-input-lead-border-color, var(--helix-color-border));display: flex;margin-block: calc(var(--helix-space-2xs) * -1);margin-inline-start: calc(var(--helix-space-xs) * -1);padding-inline: var(--helix-space-2xs);}[part="lead"][hidden] {display: none;}[part="lead"],
|
|
7
7
|
slot[name="end"] {--button-size: var(--filter-input-action-size, var(--helix-size-tag));--icon-button-size: var(--filter-input-action-size, var(--helix-size-tag));--button-padding-inline: var(--filter-input-action-padding-inline, var(--helix-space-xs));}slot[name="start"]::slotted(*),
|
|
8
|
-
slot[name="end"]::slotted(*) {color: var(--helix-color-foreground-subtle);flex: 0 0 auto;}[part="clear"] {--icon-size: 0.85em;all: unset;align-items: center;align-self: center;border-radius: var(--helix-radii-sm);box-sizing: border-box;color: var(--filter-input-clear-color, var(--helix-color-foreground-subtle));cursor: pointer;display: flex;flex: 0 0 auto;justify-content: center;min-block-size: var(--helix-size-icon-loose);min-inline-size: var(--helix-size-icon-loose);transition: color var(--helix-duration-fast) var(--helix-easing-standard);}[part="clear"]:hover {background-color: color-mix(in oklab, currentcolor 12%, transparent);color: var(--filter-input-clear-color-hover, var(--helix-color-foreground));}[part="clear"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: var(--helix-size-focus-offset);}:host(:disabled) [part="field"] {cursor: not-allowed;opacity: 0.5;}@media print {:host {print-color-adjust: exact;}}[part="surface"] {--_floating-border-color: var(--filter-input-border-color, var(--helix-color-border));--_floating-border-width: var(--filter-input-border-width, var(--helix-border-floating));--_floating-shadow: var(--filter-input-shadow, var(--helix-shadow-floating));box-sizing: border-box;inline-size: var(--filter-input-panel-size, var(--floating-anchor-inline-size, 100%));max-block-size: var(--floating-available-block-size, 20rem);min-inline-size: max-content;overflow-y: auto;padding-block: var(--helix-space-2xs);padding-inline: var(--helix-space-none);position: absolute;}
|
|
8
|
+
slot[name="end"]::slotted(*) {color: var(--helix-color-foreground-subtle);flex: 0 0 auto;}[part="clear"] {--icon-size: 0.85em;all: unset;align-items: center;align-self: center;border-radius: var(--helix-radii-sm);box-sizing: border-box;color: var(--filter-input-clear-color, var(--helix-color-foreground-subtle));cursor: pointer;display: flex;flex: 0 0 auto;justify-content: center;min-block-size: var(--helix-size-icon-loose);min-inline-size: var(--helix-size-icon-loose);transition: color var(--helix-duration-fast) var(--helix-easing-standard);}[part="clear"]:hover {background-color: color-mix(in oklab, currentcolor 12%, transparent);color: var(--filter-input-clear-color-hover, var(--helix-color-foreground));}[part="clear"]:focus-visible {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: var(--helix-size-focus-offset);}:host(:disabled) [part="field"] {cursor: not-allowed;opacity: 0.5;}@media print {:host {print-color-adjust: exact;}}[part="surface"] {--_floating-border-color: var(--filter-input-border-color, var(--helix-color-border));--_floating-border-width: var(--filter-input-border-width, var(--helix-border-floating));--_floating-shadow: var(--filter-input-shadow, var(--helix-shadow-floating));box-sizing: border-box;inline-size: var(--filter-input-panel-size, var(--floating-anchor-inline-size, 100%));max-block-size: var(--floating-available-block-size, 20rem);min-inline-size: max-content;overflow-y: auto;padding-block: var(--helix-space-2xs);padding-inline: var(--helix-space-none);position: absolute;}[part="empty"],
|
|
9
|
+
[part="loading"] {--_collection-inset-block: var(--helix-space-xs);--_collection-inset-inline: var(--helix-space-xs);}`);
|
|
@@ -46,6 +46,7 @@ import '../../option/index.js';
|
|
|
46
46
|
* @cssproperty --filter-input-size - The height of the empty field. The field grows from this height.
|
|
47
47
|
*/
|
|
48
48
|
export declare class HelixFilterInput extends HelixHeadlessFilterInput {
|
|
49
|
+
static tier: string;
|
|
49
50
|
static styles: CSSResultGroup;
|
|
50
51
|
}
|
|
51
52
|
declare global {
|
|
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { customElement } from '@fusion.dev/helix-core';
|
|
8
8
|
import { HelixHeadlessFilterInput } from '@fusion.dev/helix-headless/filter-input';
|
|
9
9
|
import '../../option/index.js';
|
|
10
|
+
import { styles as collectionStateStyles } from '../../shared/collection/state.css.js';
|
|
10
11
|
import { styles as fieldStyles } from '../../shared/field/field.css.js';
|
|
11
12
|
import { styles as fieldFrameStyles } from '../../shared/field/field-frame.css.js';
|
|
12
13
|
import { styles as fieldStackedStyles } from '../../shared/field/field-stacked.css.js';
|
|
@@ -17,6 +18,7 @@ import { styles as liveStyles } from '../../shared/live/live.css.js';
|
|
|
17
18
|
import { styles as tagRowStyles } from '../../shared/tags/tags.css.js';
|
|
18
19
|
import { styles } from './filter-input-root.css.js';
|
|
19
20
|
let HelixFilterInput = class HelixFilterInput extends HelixHeadlessFilterInput {
|
|
21
|
+
static { this.tier = 'helix-'; }
|
|
20
22
|
static { this.styles = [
|
|
21
23
|
liveStyles,
|
|
22
24
|
glyphStyles,
|
|
@@ -26,6 +28,7 @@ let HelixFilterInput = class HelixFilterInput extends HelixHeadlessFilterInput {
|
|
|
26
28
|
tagRowStyles,
|
|
27
29
|
floatingPanelStyles,
|
|
28
30
|
floatingEntranceStyles,
|
|
31
|
+
collectionStateStyles,
|
|
29
32
|
styles,
|
|
30
33
|
]; }
|
|
31
34
|
};
|
package/dist/sandbox/frame.d.ts
CHANGED
|
@@ -69,4 +69,12 @@ export declare const servePreview: (options?: ServePreviewOptions) => (() => voi
|
|
|
69
69
|
* a sandbox's `js` pane adds to its `html` pane.
|
|
70
70
|
*/
|
|
71
71
|
export declare const withScript: (source: string, script: string) => string;
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
|
+
* The built-in document, with an import map for `imports` where there are any.
|
|
74
|
+
*
|
|
75
|
+
* **The map comes first in the head**, because a browser reads an import map
|
|
76
|
+
* only before the first module it loads, and the example's scripts are
|
|
77
|
+
* modules. `</` is escaped in the map as in the script, so a URL cannot close
|
|
78
|
+
* the element early.
|
|
79
|
+
*/
|
|
80
|
+
export declare const defaultFrame: (imports?: Readonly<Record<string, string>>) => string;
|
package/dist/sandbox/frame.js
CHANGED
|
@@ -169,10 +169,14 @@ export const servePreview = (options = {}) => serveWith(TOOLS, options);
|
|
|
169
169
|
let builtIn;
|
|
170
170
|
export const withScript = (source, script) => script === '' ? source : `${source}<script type="module">${script}${SCRIPT_END}`;
|
|
171
171
|
const SCRIPT_END = ['<', 'script>'].join('/');
|
|
172
|
-
export const defaultFrame = () => {
|
|
172
|
+
export const defaultFrame = (imports) => {
|
|
173
173
|
if (builtIn === undefined) {
|
|
174
174
|
const script = `(${serveWith})({drawn:${drawn},isRender:${isRender},layoutRules:${JSON.stringify(LAYOUT_RULES)},loggedText:${loggedText},runScripts:${runScripts},withoutStylesheets:${withoutStylesheets}})`;
|
|
175
175
|
builtIn = `<!doctype html><html><head><meta charset="utf-8"><meta content="width=device-width" name="viewport"><style>:root{color-scheme:light dark;font-family:system-ui,sans-serif}body{margin:0}</style></head><body><div id="preview-root"></div><script>${script.replaceAll('</', '<\\/')}${SCRIPT_END}</body></html>`;
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
if (!imports || Object.keys(imports).length === 0) {
|
|
178
|
+
return builtIn;
|
|
179
|
+
}
|
|
180
|
+
const map = JSON.stringify({ imports }).replaceAll('</', '<\\/');
|
|
181
|
+
return builtIn.replace('<head>', `<head><script type="importmap">${map}${SCRIPT_END}`);
|
|
178
182
|
};
|
|
@@ -54,6 +54,15 @@ export type PreviewMessage = PreviewConsole | PreviewPress | PreviewReady | Prev
|
|
|
54
54
|
* `servePreview` does. It defines no element, so an example that uses Helix
|
|
55
55
|
* components needs a `src` that imports them.
|
|
56
56
|
*
|
|
57
|
+
* **`imports` lets an example import packages by name** in the built-in
|
|
58
|
+
* document, as an import map: each name maps to the address of an ES module,
|
|
59
|
+
* such as `{"canvas-confetti": "https://esm.sh/canvas-confetti@1.9.3"}`, and
|
|
60
|
+
* `import confetti from 'canvas-confetti'` in the `js` pane then loads it. A
|
|
61
|
+
* CDN that serves npm packages as modules, such as esm.sh or jsDelivr's
|
|
62
|
+
* `+esm`, gives every package an address. A new map loads the document again,
|
|
63
|
+
* since a browser reads one only as a document starts. A `src` document
|
|
64
|
+
* declares its own.
|
|
65
|
+
*
|
|
57
66
|
* **Examples render in a frame**, so an example's styles and scripts do not
|
|
58
67
|
* affect the page around the sandbox, and `position: fixed` stays inside the
|
|
59
68
|
* pane. The frame starts empty, with its own stylesheets and its own custom
|
|
@@ -134,6 +143,13 @@ export declare class HelixSandboxPreview extends HelixElement {
|
|
|
134
143
|
* `colorMode` has to be sent rather than set.
|
|
135
144
|
*/
|
|
136
145
|
direction?: 'rtl';
|
|
146
|
+
/**
|
|
147
|
+
* The packages an example can import by name in the built-in document,
|
|
148
|
+
* each mapped to the address of an ES module, as an import map's `imports`.
|
|
149
|
+
* Set it as JSON in the attribute or as an object. Not read where `src` is
|
|
150
|
+
* set.
|
|
151
|
+
*/
|
|
152
|
+
imports?: Record<string, string>;
|
|
137
153
|
/**
|
|
138
154
|
* The frame's name, read by screen readers.
|
|
139
155
|
*/
|
|
@@ -106,7 +106,7 @@ let HelixSandboxPreview = class HelixSandboxPreview extends HelixElement {
|
|
|
106
106
|
frame.title = this.label;
|
|
107
107
|
frame.style.cssText = 'block-size: 100vh; border: none; display: block; inline-size: 100vw';
|
|
108
108
|
if (this.src === '') {
|
|
109
|
-
frame.srcdoc = defaultFrame();
|
|
109
|
+
frame.srcdoc = defaultFrame(this.imports);
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
112
112
|
frame.src = this.frame?.src || this.src;
|
|
@@ -132,7 +132,7 @@ frame.onload = () => frame.contentWindow.postMessage(${JSON.stringify(this.messa
|
|
|
132
132
|
}
|
|
133
133
|
this.unready();
|
|
134
134
|
if (this.src === '') {
|
|
135
|
-
frame.srcdoc = defaultFrame();
|
|
135
|
+
frame.srcdoc = defaultFrame(this.imports);
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
frame.src = this.src;
|
|
@@ -146,7 +146,7 @@ frame.onload = () => frame.contentWindow.postMessage(${JSON.stringify(this.messa
|
|
|
146
146
|
}
|
|
147
147
|
updated(changed) {
|
|
148
148
|
super.updated(changed);
|
|
149
|
-
if (changed.has('src')) {
|
|
149
|
+
if (changed.has('src') || (changed.has('imports') && this.src === '')) {
|
|
150
150
|
this.unready();
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
@@ -174,7 +174,7 @@ frame.onload = () => frame.contentWindow.postMessage(${JSON.stringify(this.messa
|
|
|
174
174
|
part="frame"
|
|
175
175
|
@load=${this.handleFrameLoad}
|
|
176
176
|
src=${this.src || nothing}
|
|
177
|
-
srcdoc=${this.src === '' ? defaultFrame() : nothing}
|
|
177
|
+
srcdoc=${this.src === '' ? defaultFrame(this.imports) : nothing}
|
|
178
178
|
title=${this.label}
|
|
179
179
|
allow="clipboard-write *; fullscreen *"
|
|
180
180
|
sandbox=${SANDBOX}
|
|
@@ -191,6 +191,9 @@ __decorate([
|
|
|
191
191
|
__decorate([
|
|
192
192
|
property()
|
|
193
193
|
], HelixSandboxPreview.prototype, "direction", void 0);
|
|
194
|
+
__decorate([
|
|
195
|
+
property({ type: Object })
|
|
196
|
+
], HelixSandboxPreview.prototype, "imports", void 0);
|
|
194
197
|
__decorate([
|
|
195
198
|
words,
|
|
196
199
|
property()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { createSheet } from '@fusion.dev/helix-core';
|
|
2
2
|
export const styles = createSheet(`:host {display: block;block-size: 100%;}[part="highlight"],
|
|
3
3
|
[part="source"] {border: none;color: var(--helix-color-foreground-muted);font-family: var(--helix-font-mono);font-size: max(var(--helix-text-field-min), var(--helix-text-xs));inline-size: 100%;line-height: var(--helix-leading-normal);min-block-size: var(--sandbox-source-min-block-size, 12rem);padding: var(--helix-space-sm);tab-size: 2;}[part="source"] {background-color: var(--sandbox-source-background-color, var(--helix-color-background));block-size: 100%;display: block;resize: none;}[part="source"]:focus-visible {background-color: var(--helix-color-surface);outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}[part="field"] {background-color: var(--sandbox-source-background-color, var(--helix-color-background));block-size: 100%;display: grid;grid-template-rows: minmax(max-content, auto);overflow: auto;}[part="field"]:focus-within {background-color: var(--helix-color-surface);}[part="field"]:has(> [part="source"]:focus-visible) {outline: var(--helix-size-focus-ring) solid var(--helix-color-focus-ring);outline-offset: calc(var(--helix-size-focus-offset) * -1);}[part="field"] > [part] {grid-area: 1 / 1;letter-spacing: normal;margin: 0;overflow-wrap: break-word;white-space: pre-wrap;}[part="field"] > [part="source"],
|
|
4
|
-
[part="field"] > [part="source"]:focus-visible {-webkit-text-fill-color: transparent;align-self: stretch;background-color: transparent;block-size: auto;caret-color: var(--helix-color-foreground);color: transparent;outline: none;overflow: hidden;}[data-kind="callable"] {color: var(--sandbox-source-callable-color, var(--helix-color-syntax-callable));}[data-kind="comment"] {color: var(--sandbox-source-comment-color, var(--helix-color-syntax-comment));}[data-kind="constant"] {color: var(--sandbox-source-constant-color, var(--helix-color-syntax-constant));}[data-kind="invalid"] {color: var(--sandbox-source-invalid-color, var(--helix-color-syntax-invalid));}[data-kind="keyword"] {color: var(--sandbox-source-keyword-color, var(--helix-color-syntax-keyword));}[data-kind="name"] {color: var(--sandbox-source-name-color, var(--helix-color-syntax-name));}[data-kind="string"] {color: var(--sandbox-source-string-color, var(--helix-color-syntax-string));}[data-kind="tag"] {color: var(--sandbox-source-tag-color, var(--helix-color-syntax-tag));}`);
|
|
4
|
+
[part="field"] > [part="source"]:focus-visible {-webkit-text-fill-color: transparent;align-self: stretch;background-color: transparent;block-size: auto;caret-color: var(--helix-color-foreground);color: transparent;outline: none;overflow: hidden;}:host([line-numbers]) [part="field"] > [part] {padding-inline-start: calc(var(--helix-space-sm) * 3 + var(--_sandbox-source-gutter, 1ch));}:host([line-numbers]) [part="highlight"] {counter-reset: line;}[part="line"] {counter-increment: line;display: block;min-block-size: 1lh;position: relative;}[part="line"]::before {color: var(--sandbox-source-line-number-color, var(--helix-color-foreground-subtle));content: counter(line);inset-inline-end: calc(100% + var(--helix-space-sm) * 2);position: absolute;text-align: end;}[data-kind="callable"] {color: var(--sandbox-source-callable-color, var(--helix-color-syntax-callable));}[data-kind="comment"] {color: var(--sandbox-source-comment-color, var(--helix-color-syntax-comment));}[data-kind="constant"] {color: var(--sandbox-source-constant-color, var(--helix-color-syntax-constant));}[data-kind="invalid"] {color: var(--sandbox-source-invalid-color, var(--helix-color-syntax-invalid));}[data-kind="keyword"] {color: var(--sandbox-source-keyword-color, var(--helix-color-syntax-keyword));}[data-kind="name"] {color: var(--sandbox-source-name-color, var(--helix-color-syntax-name));}[data-kind="string"] {color: var(--sandbox-source-string-color, var(--helix-color-syntax-string));}[data-kind="tag"] {color: var(--sandbox-source-tag-color, var(--helix-color-syntax-tag));}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import type { CSSResultGroup, TemplateResult } from 'lit';
|
|
2
|
+
import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit';
|
|
3
3
|
import { type SandboxTokenizer } from '../tokens.js';
|
|
4
4
|
/**
|
|
5
5
|
* @summary An editable source pane for a sandbox preview.
|
|
@@ -24,6 +24,18 @@ import { type SandboxTokenizer } from '../tokens.js';
|
|
|
24
24
|
* that throws leaves the source drawn plain and the field editable, and the
|
|
25
25
|
* error is reported to the page as an uncaught one.
|
|
26
26
|
*
|
|
27
|
+
* **`line-numbers` numbers each line** in a gutter beside the source. A line
|
|
28
|
+
* that wraps keeps one number. The numbers are drawn, and hidden from screen
|
|
29
|
+
* readers, which read the field.
|
|
30
|
+
*
|
|
31
|
+
* Enter keeps the indentation of the line it breaks, and the new line is
|
|
32
|
+
* undone with the next undo as typing is.
|
|
33
|
+
*
|
|
34
|
+
* **The source can be written inside the pane** where `value` is not set: its
|
|
35
|
+
* text, or the markup of a `<template>` it holds, without the indentation the
|
|
36
|
+
* page gave it. Markup goes in a template so the page does not render it or
|
|
37
|
+
* run its scripts. Text inside the pane is read once, when it connects.
|
|
38
|
+
*
|
|
27
39
|
* @since 0.1.0
|
|
28
40
|
* @status stable
|
|
29
41
|
* @aliases Editor, Code pane
|
|
@@ -33,8 +45,9 @@ import { type SandboxTokenizer } from '../tokens.js';
|
|
|
33
45
|
* @event {HelixCaretEvent} helix-caret - Fired when the cursor moves.
|
|
34
46
|
* @event {HelixEditEvent} helix-edit - Fired after the source was edited, with the new source.
|
|
35
47
|
*
|
|
36
|
-
* @csspart field - The box that scrolls the field and its colors together, under `tokenize`.
|
|
37
|
-
* @csspart highlight - The colored copy of the source drawn under the field, under `tokenize`.
|
|
48
|
+
* @csspart field - The box that scrolls the field and its colors together, under `tokenize` or `line-numbers`.
|
|
49
|
+
* @csspart highlight - The colored copy of the source drawn under the field, under `tokenize` or `line-numbers`.
|
|
50
|
+
* @csspart line - One line of that copy, under `line-numbers`, numbered in the gutter by its `::before`.
|
|
38
51
|
* @csspart source - The editable region.
|
|
39
52
|
* @csspart token - One run of the source that has a kind, under `tokenize`.
|
|
40
53
|
*
|
|
@@ -44,6 +57,7 @@ import { type SandboxTokenizer } from '../tokens.js';
|
|
|
44
57
|
* @cssproperty --sandbox-source-constant-color - Color of a `constant` run, under `tokenize`. Defaults to `--helix-color-syntax-constant`.
|
|
45
58
|
* @cssproperty --sandbox-source-invalid-color - Color of an `invalid` run, under `tokenize`. Defaults to `--helix-color-syntax-invalid`.
|
|
46
59
|
* @cssproperty --sandbox-source-keyword-color - Color of a `keyword` run, under `tokenize`. Defaults to `--helix-color-syntax-keyword`.
|
|
60
|
+
* @cssproperty --sandbox-source-line-number-color - Color of the line numbers, under `line-numbers`. Defaults to `--helix-color-foreground-subtle`.
|
|
47
61
|
* @cssproperty --sandbox-source-min-block-size - Minimum height of the pane.
|
|
48
62
|
* @cssproperty --sandbox-source-name-color - Color of a `name` run, under `tokenize`. Defaults to `--helix-color-syntax-name`.
|
|
49
63
|
* @cssproperty --sandbox-source-string-color - Color of a `string` run, under `tokenize`. Defaults to `--helix-color-syntax-string`.
|
|
@@ -74,6 +88,10 @@ export declare class HelixSandboxSource extends HelixElement {
|
|
|
74
88
|
* holds several panes. Empty puts the pane's `name` on the tab.
|
|
75
89
|
*/
|
|
76
90
|
label: string;
|
|
91
|
+
/**
|
|
92
|
+
* Whether each line of the source is numbered, in a gutter beside it.
|
|
93
|
+
*/
|
|
94
|
+
lineNumbers: boolean;
|
|
77
95
|
/**
|
|
78
96
|
* Which source this pane holds. Every `helix-before-edit` event includes it.
|
|
79
97
|
*
|
|
@@ -107,6 +125,22 @@ export declare class HelixSandboxSource extends HelixElement {
|
|
|
107
125
|
value: string;
|
|
108
126
|
/** Set by Escape, so the next Tab leaves the field. */
|
|
109
127
|
private escaped;
|
|
128
|
+
/** Whether the source written inside the pane has been read. */
|
|
129
|
+
private read;
|
|
130
|
+
/**
|
|
131
|
+
* Takes the source written inside the pane where `value` is not set: a
|
|
132
|
+
* template's markup, or else the text. Client only, like every read of the
|
|
133
|
+
* light DOM, and once there is something to read.
|
|
134
|
+
*
|
|
135
|
+
* **As it connects, and again before its first render.** A pane that
|
|
136
|
+
* upgrades after the parser is done holds its text as it connects, which is
|
|
137
|
+
* before a sandbox around it reads `value` to seed its preview. A parser that
|
|
138
|
+
* connects the pane before its children, as one with the element already
|
|
139
|
+
* defined does, leaves the text for the render.
|
|
140
|
+
*/
|
|
141
|
+
private readWritten;
|
|
142
|
+
connectedCallback(): void;
|
|
143
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
110
144
|
/**
|
|
111
145
|
* Reports where the cursor is, for a status bar to read.
|
|
112
146
|
*
|
|
@@ -145,7 +179,13 @@ export declare class HelixSandboxSource extends HelixElement {
|
|
|
145
179
|
private edit;
|
|
146
180
|
private readonly handleKeydown;
|
|
147
181
|
/**
|
|
148
|
-
*
|
|
182
|
+
* Breaks the line with the indentation it has, where it has some. A line at
|
|
183
|
+
* the margin is left to the platform's own Enter.
|
|
184
|
+
*/
|
|
185
|
+
private breakLine;
|
|
186
|
+
/**
|
|
187
|
+
* Writes text at the caret, as typing would: the two spaces Tab inserts,
|
|
188
|
+
* and the indentation Enter keeps.
|
|
149
189
|
*
|
|
150
190
|
* **Through `insertText`, so undo takes the indent back.** Assigning
|
|
151
191
|
* `field.value` empties the textarea's undo history: a reader who typed,
|
|
@@ -155,7 +195,7 @@ export declare class HelixSandboxSource extends HelixElement {
|
|
|
155
195
|
* into whatever has focus, so it is used only while the field has it. Where it
|
|
156
196
|
* is not supported, the field is written directly.
|
|
157
197
|
*/
|
|
158
|
-
private
|
|
198
|
+
private insert;
|
|
159
199
|
protected render(): TemplateResult;
|
|
160
200
|
/** The field itself and its description, which is the whole pane without `tokenize`. */
|
|
161
201
|
private renderField;
|
|
@@ -10,6 +10,30 @@ import { property } from 'lit/decorators.js';
|
|
|
10
10
|
import { drawnRuns } from '../tokens.js';
|
|
11
11
|
import { styles } from './sandbox-source.css.js';
|
|
12
12
|
const MODIFIERS = new Set(['Alt', 'AltGraph', 'Control', 'Meta', 'Shift']);
|
|
13
|
+
const dedent = (text) => {
|
|
14
|
+
const lines = text
|
|
15
|
+
.replace(/^(?:[ \t]*\n)+/, '')
|
|
16
|
+
.trimEnd()
|
|
17
|
+
.split('\n');
|
|
18
|
+
const shared = Math.min(...lines
|
|
19
|
+
.filter((line) => line.trim() !== '')
|
|
20
|
+
.map((line) => /^[ \t]*/.exec(line)?.[0].length ?? 0));
|
|
21
|
+
return Number.isFinite(shared) ? lines.map((line) => line.slice(shared)).join('\n') : '';
|
|
22
|
+
};
|
|
23
|
+
const linesOf = (runs) => {
|
|
24
|
+
const lines = [[]];
|
|
25
|
+
for (const { kind, text } of runs) {
|
|
26
|
+
text.split('\n').forEach((piece, at) => {
|
|
27
|
+
if (at > 0) {
|
|
28
|
+
lines.push([]);
|
|
29
|
+
}
|
|
30
|
+
if (piece !== '') {
|
|
31
|
+
lines.at(-1)?.push(kind ? { kind, text: piece } : { text: piece });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return lines;
|
|
36
|
+
};
|
|
13
37
|
let HelixSandboxSource = class HelixSandboxSource extends HelixElement {
|
|
14
38
|
constructor() {
|
|
15
39
|
super(...arguments);
|
|
@@ -17,10 +41,12 @@ let HelixSandboxSource = class HelixSandboxSource extends HelixElement {
|
|
|
17
41
|
this.fieldNameLabel = '{field}, {name}';
|
|
18
42
|
this.keysDescription = 'Tab inserts two spaces. To leave, press Escape and then Tab, or press Shift+Tab to go back.';
|
|
19
43
|
this.label = '';
|
|
44
|
+
this.lineNumbers = false;
|
|
20
45
|
this.name = 'html';
|
|
21
46
|
this.tabIndents = true;
|
|
22
47
|
this.value = '';
|
|
23
48
|
this.escaped = false;
|
|
49
|
+
this.read = false;
|
|
24
50
|
this.reportCaret = (event) => {
|
|
25
51
|
const field = event.target;
|
|
26
52
|
const at = field.selectionStart ?? 0;
|
|
@@ -43,15 +69,46 @@ let HelixSandboxSource = class HelixSandboxSource extends HelixElement {
|
|
|
43
69
|
if (MODIFIERS.has(event.key)) {
|
|
44
70
|
return;
|
|
45
71
|
}
|
|
72
|
+
if (event.key === 'Enter' &&
|
|
73
|
+
!event.isComposing &&
|
|
74
|
+
!(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)) {
|
|
75
|
+
this.escaped = false;
|
|
76
|
+
this.breakLine(event);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
46
79
|
if (event.key !== 'Tab' || event.shiftKey || !this.tabIndents || this.escaped) {
|
|
47
80
|
this.escaped = false;
|
|
48
81
|
return;
|
|
49
82
|
}
|
|
50
83
|
event.preventDefault();
|
|
51
|
-
this.
|
|
84
|
+
this.insert(event.target, ' ');
|
|
52
85
|
};
|
|
53
86
|
}
|
|
54
87
|
static { this.words = 'helix-sandbox-source'; }
|
|
88
|
+
readWritten() {
|
|
89
|
+
if (this.read ||
|
|
90
|
+
this.children === undefined ||
|
|
91
|
+
this.hasAttribute('value') ||
|
|
92
|
+
this.value !== '') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const template = this.querySelector(':scope > template');
|
|
96
|
+
const written = dedent(template ? template.innerHTML : (this.textContent ?? ''));
|
|
97
|
+
if (written !== '') {
|
|
98
|
+
this.read = true;
|
|
99
|
+
this.value = written;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
connectedCallback() {
|
|
103
|
+
super.connectedCallback();
|
|
104
|
+
this.readWritten();
|
|
105
|
+
}
|
|
106
|
+
willUpdate(changed) {
|
|
107
|
+
super.willUpdate(changed);
|
|
108
|
+
if (!this.hasUpdated) {
|
|
109
|
+
this.readWritten();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
55
112
|
edit(field, next) {
|
|
56
113
|
const request = new HelixBeforeEditEvent({ value: next });
|
|
57
114
|
const accepted = this.dispatchEvent(request);
|
|
@@ -63,32 +120,50 @@ let HelixSandboxSource = class HelixSandboxSource extends HelixElement {
|
|
|
63
120
|
this.dispatchEvent(new HelixEditEvent({ value: next }));
|
|
64
121
|
}
|
|
65
122
|
}
|
|
66
|
-
|
|
123
|
+
breakLine(event) {
|
|
124
|
+
const field = event.target;
|
|
125
|
+
const at = field.selectionStart ?? 0;
|
|
126
|
+
const start = field.value.lastIndexOf('\n', at - 1) + 1;
|
|
127
|
+
const indent = /^[ \t]*/.exec(field.value.slice(start, at))?.[0] ?? '';
|
|
128
|
+
if (indent !== '') {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
this.insert(field, `\n${indent}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
insert(field, text) {
|
|
67
134
|
const { ownerDocument } = field;
|
|
68
135
|
const focused = field.getRootNode().activeElement === field;
|
|
69
136
|
if (focused &&
|
|
70
137
|
typeof ownerDocument.execCommand === 'function' &&
|
|
71
|
-
ownerDocument.execCommand('insertText', false,
|
|
138
|
+
ownerDocument.execCommand('insertText', false, text)) {
|
|
72
139
|
return;
|
|
73
140
|
}
|
|
74
|
-
field.setRangeText(
|
|
141
|
+
field.setRangeText(text, field.selectionStart, field.selectionEnd, 'end');
|
|
75
142
|
this.edit(field, field.value);
|
|
76
143
|
}
|
|
77
144
|
render() {
|
|
78
145
|
const field = this.renderField();
|
|
79
|
-
if (!this.tokenize) {
|
|
146
|
+
if (!this.tokenize && !this.lineNumbers) {
|
|
80
147
|
return field;
|
|
81
148
|
}
|
|
82
149
|
let given = [];
|
|
83
150
|
try {
|
|
84
|
-
given = this.tokenize(this.value, this.name);
|
|
151
|
+
given = this.tokenize?.(this.value, this.name) ?? [];
|
|
85
152
|
}
|
|
86
153
|
catch (error) {
|
|
87
154
|
globalThis.reportError?.(error);
|
|
88
155
|
}
|
|
89
156
|
const runs = drawnRuns(this.value, given);
|
|
157
|
+
const draw = (some) => some.map(({ kind, text }) => kind ? html `<span part="token" data-kind=${kind}>${text}</span>` : text);
|
|
158
|
+
if (this.lineNumbers) {
|
|
159
|
+
const lines = linesOf(runs);
|
|
160
|
+
return html `<div part="field" style="--_sandbox-source-gutter: ${String(lines.length).length}ch">
|
|
161
|
+
<pre part="highlight" aria-hidden="true">${lines.map((line) => html `<span part="line">${draw(line)}</span>`)}</pre>
|
|
162
|
+
${field}
|
|
163
|
+
</div>`;
|
|
164
|
+
}
|
|
90
165
|
return html `<div part="field">
|
|
91
|
-
<pre part="highlight" aria-hidden="true">${runs
|
|
166
|
+
<pre part="highlight" aria-hidden="true">${draw(runs)}${'\n'}</pre>
|
|
92
167
|
${field}
|
|
93
168
|
</div>`;
|
|
94
169
|
}
|
|
@@ -126,6 +201,9 @@ __decorate([
|
|
|
126
201
|
__decorate([
|
|
127
202
|
property()
|
|
128
203
|
], HelixSandboxSource.prototype, "label", void 0);
|
|
204
|
+
__decorate([
|
|
205
|
+
property({ attribute: 'line-numbers', reflect: true, type: Boolean })
|
|
206
|
+
], HelixSandboxSource.prototype, "lineNumbers", void 0);
|
|
129
207
|
__decorate([
|
|
130
208
|
property()
|
|
131
209
|
], HelixSandboxSource.prototype, "name", void 0);
|