@openpresentation/opf-editor 0.30.0 → 0.31.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/element.d.ts +5 -2
- package/dist/styles.css +13 -6
- package/dist/styles.layered.css +407 -278
- package/dist/toolbar.d.ts +23 -13
- package/dist/toolbar.js +12 -4
- package/dist/workspace.d.ts +15 -2
- package/dist/workspace.js +18 -5
- package/package.json +7 -7
package/dist/element.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export interface OpfEditorElementDefaults {
|
|
|
38
38
|
/**
|
|
39
39
|
* `<opf-editor>`: the editor in one tag. The editor mounts in a `div` inside the element (light DOM), once the element is connected and the
|
|
40
40
|
* page has parsed its content, and is destroyed one microtask after the element leaves the document (unless it came back: a move in the DOM
|
|
41
|
-
* keeps the editor). Attributes `layout`, `toolbar`, `readonly`, `theme`, `density`, `slide` and `
|
|
41
|
+
* keeps the editor). Attributes `layout`, `toolbar`, `readonly`, `theme`, `density`, `slide`, `src` and `fonts` are observed; see docs/web-component.md.
|
|
42
42
|
*/
|
|
43
43
|
export interface OpfEditorElement extends HTMLElement {
|
|
44
44
|
/** The editor handle once it is created, else `null` (before mount, after removal, or when it could not be created). */
|
|
@@ -53,7 +53,10 @@ export interface OpfEditorElement extends HTMLElement {
|
|
|
53
53
|
document: unknown;
|
|
54
54
|
/** More `createOpfEditor` options. Read when the editor mounts; setting a different object on a mounted element remounts it, keeping the document. */
|
|
55
55
|
options: Partial<OpfEditorOptions>;
|
|
56
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* A fonts handle (or what `OpfEditorFontsOption` allows), or the URL of a font root. Default: `defineOpfEditorElement`'s, then `options.fonts`, then
|
|
58
|
+
* the `fonts` attribute (a font root; observed: changing it remounts the editor). Setting a different value on a mounted element remounts it.
|
|
59
|
+
*/
|
|
57
60
|
fonts: OpfEditorFontsOption | string | undefined;
|
|
58
61
|
catalogs: readonly Catalog[] | undefined;
|
|
59
62
|
/** The attributes as properties. `readOnly` is the `readonly` attribute. */
|
package/dist/styles.css
CHANGED
|
@@ -7531,6 +7531,11 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7531
7531
|
gap: 4px;
|
|
7532
7532
|
padding: 0 12px 8px;
|
|
7533
7533
|
}
|
|
7534
|
+
/* CE-30: the slide row is no wider than the editor; the thumbnail strip scrolls inside it (a narrow box, a phone). */
|
|
7535
|
+
.opf-ws-dock > .opf-ws-navigator,
|
|
7536
|
+
.opf-ws-dock > .opf-ws-thumbnails {
|
|
7537
|
+
max-width: 100%;
|
|
7538
|
+
}
|
|
7534
7539
|
.opf-ws-status {
|
|
7535
7540
|
flex: none;
|
|
7536
7541
|
margin: 0;
|
|
@@ -7618,27 +7623,29 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7618
7623
|
flex: 1 1 0;
|
|
7619
7624
|
min-height: 0;
|
|
7620
7625
|
}
|
|
7621
|
-
/* A phone: the parts stack, the source above the slide, the side panel below.
|
|
7626
|
+
/* A phone: the parts stack, the source above the slide, the side panel below. CE-30: only in the layouts that have several parts to stack;
|
|
7627
|
+
`embed`, `viewer` and `canvas` are the slide alone and fit it to their box at any width (a stage of 40vh made a short embed overflow).
|
|
7628
|
+
`:where()` keeps the specificity of the plain class. */
|
|
7622
7629
|
@media (max-width: 760px) {
|
|
7623
|
-
.opf-ws-body {
|
|
7630
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-body {
|
|
7624
7631
|
flex-direction: column;
|
|
7625
7632
|
overflow: auto;
|
|
7626
7633
|
}
|
|
7627
|
-
.opf-ws-source {
|
|
7634
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-source {
|
|
7628
7635
|
flex: none;
|
|
7629
7636
|
min-width: 0;
|
|
7630
7637
|
height: 40vh;
|
|
7631
7638
|
border-right: 0;
|
|
7632
7639
|
border-bottom: 1px solid var(--opf-ui-border);
|
|
7633
7640
|
}
|
|
7634
|
-
.opf-ws-main {
|
|
7641
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-main {
|
|
7635
7642
|
flex: none;
|
|
7636
7643
|
}
|
|
7637
|
-
.opf-ws-stage {
|
|
7644
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-stage {
|
|
7638
7645
|
flex: none;
|
|
7639
7646
|
min-height: 40vh;
|
|
7640
7647
|
}
|
|
7641
|
-
.opf-ws-side {
|
|
7648
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-side {
|
|
7642
7649
|
flex: none;
|
|
7643
7650
|
border-left: 0;
|
|
7644
7651
|
border-top: 1px solid var(--opf-ui-border);
|
package/dist/styles.layered.css
CHANGED
|
@@ -4038,38 +4038,17 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4038
4038
|
/* ---------------------------------------------------------------- JSON editor (CodeMirror, opf-json / opf-code) */
|
|
4039
4039
|
/* The editor ships no CSS of its own. Put it in an `.opf-ui`, `.opf-json` or `.opf-code` element (or the component that holds it) to get this look. */
|
|
4040
4040
|
|
|
4041
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-editor {
|
|
4042
|
-
font: 12.5px/1.65 var(--opf-ui-mono);
|
|
4043
|
-
color: var(--opf-ui-fg);
|
|
4044
|
-
background: var(--opf-ui-code-bg);
|
|
4045
|
-
border: 1px solid var(--opf-ui-code-border);
|
|
4046
|
-
border-radius: var(--opf-ui-radius-md);
|
|
4047
|
-
}
|
|
4048
4041
|
|
|
4049
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-editor.cm-focused {
|
|
4050
|
-
outline: 2px solid var(--opf-ui-ring);
|
|
4051
|
-
outline-offset: 2px;
|
|
4052
|
-
}
|
|
4053
4042
|
|
|
4054
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-scroller,
|
|
4055
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-content {
|
|
4056
|
-
font-family: var(--opf-ui-mono);
|
|
4057
|
-
}
|
|
4058
4043
|
|
|
4059
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-content {
|
|
4060
|
-
caret-color: var(--opf-ui-fg);
|
|
4061
|
-
}
|
|
4062
4044
|
|
|
4063
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-cursor,
|
|
4064
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-dropCursor {
|
|
4065
|
-
border-left-color: var(--opf-ui-fg);
|
|
4066
|
-
}
|
|
4067
4045
|
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4046
|
+
|
|
4047
|
+
|
|
4048
|
+
|
|
4049
|
+
|
|
4050
|
+
|
|
4051
|
+
|
|
4073
4052
|
|
|
4074
4053
|
/* A wrapped line continues under its own indentation (src/source-wrap.js, VS Code's wrappingIndent "indent"): `opf-hang-<n>` says how many
|
|
4075
4054
|
columns, the first line keeps its place (a negative text-indent of the same width) and every continuation line starts n columns in.
|
|
@@ -4077,66 +4056,52 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4077
4056
|
from the measured width, because a percentage here makes style and layout of every line very slow (replacing the text of an 848-line
|
|
4078
4057
|
document took 8.5 s instead of 0.56 s). Text inside an inline widget does not inherit the negative indent. `--opf-line-start` is the line's own
|
|
4079
4058
|
left padding (the source pane sets it to 2px). */
|
|
4080
|
-
.cm-line.opf-hang-0 { --opf-hang: 0; }
|
|
4081
|
-
.cm-line.opf-hang-1 { --opf-hang: 1; }
|
|
4082
|
-
.cm-line.opf-hang-2 { --opf-hang: 2; }
|
|
4083
|
-
.cm-line.opf-hang-3 { --opf-hang: 3; }
|
|
4084
|
-
.cm-line.opf-hang-4 { --opf-hang: 4; }
|
|
4085
|
-
.cm-line.opf-hang-5 { --opf-hang: 5; }
|
|
4086
|
-
.cm-line.opf-hang-6 { --opf-hang: 6; }
|
|
4087
|
-
.cm-line.opf-hang-7 { --opf-hang: 7; }
|
|
4088
|
-
.cm-line.opf-hang-8 { --opf-hang: 8; }
|
|
4089
|
-
.cm-line.opf-hang-9 { --opf-hang: 9; }
|
|
4090
|
-
.cm-line.opf-hang-10 { --opf-hang: 10; }
|
|
4091
|
-
.cm-line.opf-hang-11 { --opf-hang: 11; }
|
|
4092
|
-
.cm-line.opf-hang-12 { --opf-hang: 12; }
|
|
4093
|
-
.cm-line.opf-hang-13 { --opf-hang: 13; }
|
|
4094
|
-
.cm-line.opf-hang-14 { --opf-hang: 14; }
|
|
4095
|
-
.cm-line.opf-hang-15 { --opf-hang: 15; }
|
|
4096
|
-
.cm-line.opf-hang-16 { --opf-hang: 16; }
|
|
4097
|
-
.cm-line.opf-hang-17 { --opf-hang: 17; }
|
|
4098
|
-
.cm-line.opf-hang-18 { --opf-hang: 18; }
|
|
4099
|
-
.cm-line.opf-hang-19 { --opf-hang: 19; }
|
|
4100
|
-
.cm-line.opf-hang-20 { --opf-hang: 20; }
|
|
4101
|
-
.cm-line.opf-hang-21 { --opf-hang: 21; }
|
|
4102
|
-
.cm-line.opf-hang-22 { --opf-hang: 22; }
|
|
4103
|
-
.cm-line.opf-hang-23 { --opf-hang: 23; }
|
|
4104
|
-
.cm-line.opf-hang-24 { --opf-hang: 24; }
|
|
4105
|
-
.cm-line.opf-hang-25 { --opf-hang: 25; }
|
|
4106
|
-
.cm-line.opf-hang-26 { --opf-hang: 26; }
|
|
4107
|
-
.cm-line.opf-hang-27 { --opf-hang: 27; }
|
|
4108
|
-
.cm-line.opf-hang-28 { --opf-hang: 28; }
|
|
4109
|
-
.cm-line.opf-hang-29 { --opf-hang: 29; }
|
|
4110
|
-
.cm-line.opf-hang-30 { --opf-hang: 30; }
|
|
4111
|
-
.cm-line.opf-hang-31 { --opf-hang: 31; }
|
|
4112
|
-
.cm-line.opf-hang-32 { --opf-hang: 32; }
|
|
4113
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-line {
|
|
4114
|
-
padding-left: calc(var(--opf-line-start, 6px) + var(--opf-hang, 0) * 1ch);
|
|
4115
|
-
text-indent: calc(-1 * var(--opf-hang, 0) * 1ch);
|
|
4116
|
-
}
|
|
4117
4059
|
|
|
4118
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-line > * {
|
|
4119
|
-
text-indent: 0;
|
|
4120
|
-
}
|
|
4121
4060
|
|
|
4122
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-activeLine,
|
|
4123
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-line.is-hover {
|
|
4124
|
-
background: color-mix(in srgb, var(--opf-ui-accent) 8%, transparent);
|
|
4125
|
-
}
|
|
4126
4061
|
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4062
|
+
|
|
4063
|
+
|
|
4064
|
+
|
|
4065
|
+
|
|
4066
|
+
|
|
4067
|
+
|
|
4068
|
+
|
|
4069
|
+
|
|
4070
|
+
|
|
4071
|
+
|
|
4072
|
+
|
|
4073
|
+
|
|
4074
|
+
|
|
4075
|
+
|
|
4076
|
+
|
|
4077
|
+
|
|
4078
|
+
|
|
4079
|
+
|
|
4080
|
+
|
|
4081
|
+
|
|
4082
|
+
|
|
4083
|
+
|
|
4084
|
+
|
|
4085
|
+
|
|
4086
|
+
|
|
4087
|
+
|
|
4088
|
+
|
|
4089
|
+
|
|
4090
|
+
|
|
4091
|
+
|
|
4092
|
+
|
|
4093
|
+
|
|
4094
|
+
|
|
4095
|
+
|
|
4096
|
+
|
|
4097
|
+
|
|
4098
|
+
|
|
4131
4099
|
|
|
4132
4100
|
/* The selection is a layer behind the text, so the text keeps its own colors: the tint is light enough that every token color (test/selection-contrast-browser.mjs
|
|
4133
4101
|
measures each) keeps 4.5:1 against it, focused or not, in the light and the dark scheme. The focused rule of CodeMirror's base theme
|
|
4134
4102
|
(`&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground`, `#d7d4f0` for light and `#233` for dark) has five classes, so
|
|
4135
4103
|
the second selector has six and wins whichever stylesheet loads last; src/source-color-scheme.js flags the view dark so the rest of the base theme follows. */
|
|
4136
|
-
|
|
4137
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground {
|
|
4138
|
-
background: color-mix(in srgb, var(--opf-ui-accent) 16%, transparent);
|
|
4139
|
-
}
|
|
4104
|
+
|
|
4140
4105
|
|
|
4141
4106
|
/* A selection that is not drawn by CodeMirror (the handoff prompt, the data grid's text areas, the numbering preview) uses the browser's own, and a browser's
|
|
4142
4107
|
default highlight is not made for our surfaces: the same tint, with the text color the surface already has, is 4.5:1 or better in both schemes. */
|
|
@@ -4148,15 +4113,9 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4148
4113
|
|
|
4149
4114
|
/* The other occurrences of the selected word: a 16% tint, so the lightest code text on it (a key in the dark scheme) keeps 4.5:1 (25% gave 4.2:1);
|
|
4150
4115
|
the underline marks them at a glance. test/selection-contrast-browser.mjs measures it in both schemes. */
|
|
4151
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-selectionMatch {
|
|
4152
|
-
background: color-mix(in srgb, var(--opf-ui-warn) 16%, transparent);
|
|
4153
|
-
box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--opf-ui-warn) 70%, transparent);
|
|
4154
|
-
}
|
|
4155
4116
|
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
outline: 1px solid var(--opf-ui-accent);
|
|
4159
|
-
}
|
|
4117
|
+
|
|
4118
|
+
|
|
4160
4119
|
|
|
4161
4120
|
:is(.opf-ui, .opf-json, .opf-code) .tok-key {
|
|
4162
4121
|
color: var(--opf-ui-accent-strong);
|
|
@@ -4180,79 +4139,27 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4180
4139
|
border-radius: var(--opf-ui-radius-sm);
|
|
4181
4140
|
}
|
|
4182
4141
|
|
|
4183
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-panels {
|
|
4184
|
-
color: var(--opf-ui-fg);
|
|
4185
|
-
background: var(--opf-ui-surface);
|
|
4186
|
-
border-color: var(--opf-ui-border);
|
|
4187
|
-
font-family: var(--opf-ui-font);
|
|
4188
|
-
}
|
|
4189
4142
|
|
|
4190
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-panels input,
|
|
4191
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-panels button {
|
|
4192
|
-
font: 12px var(--opf-ui-font);
|
|
4193
|
-
color: var(--opf-ui-fg);
|
|
4194
|
-
background: var(--opf-ui-surface);
|
|
4195
|
-
border: 1px solid var(--opf-ui-border);
|
|
4196
|
-
border-radius: var(--opf-ui-radius-sm);
|
|
4197
|
-
}
|
|
4198
4143
|
|
|
4199
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-tooltip {
|
|
4200
|
-
color: var(--opf-ui-fg);
|
|
4201
|
-
background: var(--opf-ui-surface);
|
|
4202
|
-
border: 1px solid var(--opf-ui-border);
|
|
4203
|
-
border-radius: var(--opf-ui-radius-md);
|
|
4204
|
-
box-shadow: var(--opf-ui-shadow-pop);
|
|
4205
|
-
}
|
|
4206
4144
|
|
|
4207
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul {
|
|
4208
|
-
font-family: var(--opf-ui-mono);
|
|
4209
|
-
font-size: 12px;
|
|
4210
|
-
}
|
|
4211
4145
|
|
|
4212
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li {
|
|
4213
|
-
padding: 2px 8px;
|
|
4214
|
-
color: var(--opf-ui-fg);
|
|
4215
|
-
}
|
|
4216
4146
|
|
|
4217
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] {
|
|
4218
|
-
color: var(--opf-ui-accent-fg);
|
|
4219
|
-
background: var(--opf-ui-accent);
|
|
4220
|
-
}
|
|
4221
4147
|
|
|
4222
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionDetail {
|
|
4223
|
-
margin-left: 12px;
|
|
4224
|
-
font-family: var(--opf-ui-font);
|
|
4225
|
-
font-style: normal;
|
|
4226
|
-
color: var(--opf-ui-muted-fg);
|
|
4227
|
-
}
|
|
4228
4148
|
|
|
4229
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionDetail {
|
|
4230
|
-
color: inherit;
|
|
4231
|
-
opacity: 0.85;
|
|
4232
|
-
}
|
|
4233
4149
|
|
|
4234
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete > .opf-completion-footer {
|
|
4235
|
-
padding: 4px 8px;
|
|
4236
|
-
font: 12px/1.4 var(--opf-ui-font);
|
|
4237
|
-
color: var(--opf-ui-muted-fg);
|
|
4238
|
-
border-top: 1px solid var(--opf-ui-border);
|
|
4239
|
-
}
|
|
4240
4150
|
|
|
4241
|
-
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionMatchedText {
|
|
4242
|
-
font-weight: 600;
|
|
4243
|
-
text-decoration: none;
|
|
4244
|
-
}
|
|
4245
4151
|
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4152
|
+
|
|
4153
|
+
|
|
4154
|
+
|
|
4155
|
+
|
|
4156
|
+
|
|
4157
|
+
|
|
4158
|
+
|
|
4159
|
+
|
|
4160
|
+
|
|
4161
|
+
|
|
4162
|
+
|
|
4256
4163
|
|
|
4257
4164
|
/* The live region next to the code: read by screen readers, never seen. */
|
|
4258
4165
|
.opf-source-live {
|
|
@@ -4268,16 +4175,7 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4268
4175
|
}
|
|
4269
4176
|
|
|
4270
4177
|
/* The documentation cards: beside the selected suggestion and over a key or a value. */
|
|
4271
|
-
|
|
4272
|
-
.opf-source-code .cm-tooltip .opf-doc {
|
|
4273
|
-
display: flex;
|
|
4274
|
-
flex-direction: column;
|
|
4275
|
-
gap: 4px;
|
|
4276
|
-
max-width: 340px;
|
|
4277
|
-
padding: 2px 0;
|
|
4278
|
-
font: 12px/1.45 var(--opf-ui-font);
|
|
4279
|
-
white-space: normal;
|
|
4280
|
-
}
|
|
4178
|
+
|
|
4281
4179
|
.opf-doc-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
|
|
4282
4180
|
.opf-doc-title { font-family: var(--opf-ui-mono); font-weight: 600; }
|
|
4283
4181
|
.opf-doc-type { color: var(--opf-ui-muted-fg); }
|
|
@@ -4289,18 +4187,18 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4289
4187
|
.opf-doc-more { color: var(--opf-ui-muted-fg); font-size: 11px; }
|
|
4290
4188
|
|
|
4291
4189
|
/* A problem's tooltip and the quick fix list. */
|
|
4292
|
-
|
|
4190
|
+
|
|
4293
4191
|
.opf-problem-next { color: var(--opf-ui-muted-fg); }
|
|
4294
|
-
|
|
4295
|
-
|
|
4192
|
+
|
|
4193
|
+
|
|
4296
4194
|
.opf-problem-hint { color: var(--opf-ui-muted-fg); font-size: 11px; }
|
|
4297
|
-
|
|
4195
|
+
|
|
4298
4196
|
.opf-fix { padding: 3px 8px; border-radius: var(--opf-ui-radius-sm); white-space: nowrap; }
|
|
4299
4197
|
.opf-fix[aria-selected="true"] { background: var(--opf-ui-accent); color: var(--opf-ui-accent-fg); }
|
|
4300
|
-
|
|
4198
|
+
|
|
4301
4199
|
|
|
4302
4200
|
/* The shape hint (Cmd/Ctrl+Shift+Space): the fields of the object around the caret, each set, next or optional. The state is a word and a mark, not only a color. */
|
|
4303
|
-
|
|
4201
|
+
|
|
4304
4202
|
.opf-hint-head { display: flex; justify-content: space-between; gap: 24px; padding: 2px 12px 5px; border-bottom: 1px solid var(--opf-ui-border); }
|
|
4305
4203
|
.opf-hint-title { font: 600 12px var(--opf-ui-mono); }
|
|
4306
4204
|
.opf-hint-aside { color: var(--opf-ui-muted-fg); font-size: 11.5px; white-space: nowrap; }
|
|
@@ -4315,20 +4213,14 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
4315
4213
|
.opf-hint-row[data-state="next"] .opf-hint-state { color: var(--opf-ui-accent-strong); font-weight: 600; }
|
|
4316
4214
|
.opf-hint-row[data-state="next"] .opf-hint-state::before { content: "\25B6\00a0"; }
|
|
4317
4215
|
/* No animation either way; the rule is explicit so a later one cannot add motion for someone who asked for less. */
|
|
4318
|
-
|
|
4319
|
-
.cm-tooltip.opf-hint, .cm-tooltip.opf-hint * { animation: none !important; transition: none !important; }
|
|
4320
|
-
}
|
|
4216
|
+
|
|
4321
4217
|
|
|
4322
4218
|
/* Ctrl+Space with the list open hides the documentation panel (and shows it again). */
|
|
4323
|
-
.cm-editor.opf-docs-off .cm-completionInfo { display: none; }
|
|
4324
4219
|
|
|
4325
|
-
:is(.opf-ui, .opf-json, .opf-code) .cm-diagnostic-error {
|
|
4326
|
-
border-left-color: var(--opf-ui-danger);
|
|
4327
|
-
}
|
|
4328
4220
|
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4221
|
+
|
|
4222
|
+
|
|
4223
|
+
|
|
4332
4224
|
|
|
4333
4225
|
/* The field-options popover. Its inline style uses system colors; color-scheme follows the theme, and these keep it on the tokens. */
|
|
4334
4226
|
:is(.opf-ui, .opf-json, .opf-code) .json-field-menu {
|
|
@@ -5058,18 +4950,18 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
5058
4950
|
/* Code */
|
|
5059
4951
|
.opf-source-code { position: relative; flex: 1; min-height: 0; overflow: hidden; display: flex; }
|
|
5060
4952
|
/* The pane frame draws the edge: the editor inside it has no border or radius of its own (panels.css gives a standalone editor both). */
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
/* The selection color is the shared one in panels.css (JSON editor section). */
|
|
5071
|
-
|
|
5072
|
-
.opf-source-code .tok-key { color: var(--opf-ui-accent-strong); }
|
|
4953
|
+
|
|
4954
|
+
|
|
4955
|
+
|
|
4956
|
+
|
|
4957
|
+
|
|
4958
|
+
|
|
4959
|
+
|
|
4960
|
+
|
|
4961
|
+
|
|
4962
|
+
/* The selection color is the shared one in panels.css (JSON editor section). */
|
|
4963
|
+
|
|
4964
|
+
.opf-source-code .tok-key { color: var(--opf-ui-accent-strong); }
|
|
5073
4965
|
.opf-source-code .tok-str { color: var(--opf-ui-fg); }
|
|
5074
4966
|
.opf-source-code .tok-num { color: var(--opf-ui-warn); }
|
|
5075
4967
|
.opf-source-code .tok-punct,
|
|
@@ -5079,7 +4971,7 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
5079
4971
|
.opf-source-code .tok-head { color: var(--opf-ui-accent-strong); font-weight: 600; }
|
|
5080
4972
|
.opf-source-code .tok-comment { font-style: italic; }
|
|
5081
4973
|
.opf-source-code .code-key.is-active { background: color-mix(in srgb, var(--opf-ui-accent) 10%, transparent); border-radius: var(--opf-ui-radius-sm); }
|
|
5082
|
-
|
|
4974
|
+
|
|
5083
4975
|
/* CE-17: decorations a host draws (setDecorations) and the flash of revealPath; the host styles any other kind as .opf-source-decoration-<kind>. */
|
|
5084
4976
|
.opf-source-code .opf-source-decoration { background: color-mix(in srgb, var(--opf-ui-accent) 16%, transparent); border-radius: var(--opf-ui-radius-sm); }
|
|
5085
4977
|
.opf-source-code .opf-source-decoration-error { background: color-mix(in srgb, var(--opf-ui-danger) 18%, transparent); }
|
|
@@ -5087,12 +4979,12 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
5087
4979
|
.opf-source-code .opf-source-decoration-info { background: color-mix(in srgb, var(--opf-ui-accent) 10%, transparent); }
|
|
5088
4980
|
.opf-source-code .opf-source-decoration-added { background: color-mix(in srgb, var(--opf-ui-success) 20%, transparent); }
|
|
5089
4981
|
.opf-source-code .opf-source-decoration-changed { background: color-mix(in srgb, var(--opf-ui-warn) 14%, transparent); }
|
|
5090
|
-
|
|
4982
|
+
|
|
5091
4983
|
@keyframes opf-source-flash { from { background: color-mix(in srgb, var(--opf-ui-accent) 32%, transparent); } to { background: transparent; } }
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
4984
|
+
|
|
4985
|
+
|
|
4986
|
+
|
|
4987
|
+
|
|
5096
4988
|
|
|
5097
4989
|
/* Findings under the code */
|
|
5098
4990
|
.opf-source-findings {
|
|
@@ -5230,16 +5122,14 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
5230
5122
|
.opf-source-confirm-accept { font-weight: 600; }
|
|
5231
5123
|
|
|
5232
5124
|
/* Fold gutter (src/source-folding.js) */
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
@media (prefers-reduced-motion: reduce) { .opf-source-code .cm-foldGutter .opf-fold-marker { transition: none; } }
|
|
5242
|
-
@media (forced-colors: active) { .opf-source-code .cm-foldGutter .opf-fold-marker { opacity: 1; } }
|
|
5125
|
+
|
|
5126
|
+
|
|
5127
|
+
|
|
5128
|
+
|
|
5129
|
+
|
|
5130
|
+
|
|
5131
|
+
|
|
5132
|
+
|
|
5243
5133
|
|
|
5244
5134
|
/* Outline panel (opt-in `outline` option) */
|
|
5245
5135
|
.opf-source-body { display: flex; flex: 1; min-height: 0; min-width: 0; }
|
|
@@ -5258,16 +5148,13 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
5258
5148
|
|
|
5259
5149
|
/* Forced colors (Windows high contrast): the selection of a list is an outline and a problem keeps its underline and a different shape per severity. */
|
|
5260
5150
|
@media (forced-colors: active) {
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
.opf-source-code .cm-lintRange-info { text-decoration: underline dotted CanvasText; }
|
|
5151
|
+
|
|
5152
|
+
|
|
5153
|
+
|
|
5154
|
+
|
|
5266
5155
|
.opf-source-finding { border: 1px solid CanvasText; }
|
|
5267
5156
|
}
|
|
5268
|
-
|
|
5269
|
-
.cm-tooltip, .cm-tooltip * { animation: none !important; transition: none !important; }
|
|
5270
|
-
}
|
|
5157
|
+
|
|
5271
5158
|
|
|
5272
5159
|
/* studio.css */
|
|
5273
5160
|
/* CE-20: the Studio (`createOpfEditor(el, { layout: "studio" | "playground" })`). Only --opf-ui-* tokens. The arrangement follows data
|
|
@@ -7122,67 +7009,20 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7122
7009
|
}
|
|
7123
7010
|
|
|
7124
7011
|
/* ---- CodeMirror's lists and panels (completions, problems, quick fixes, search) ---------------------------------------------- */
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
}
|
|
7132
|
-
:root :is(.opf-ui, .opf-source, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionLabel {
|
|
7133
|
-
min-width: 0;
|
|
7134
|
-
overflow: hidden;
|
|
7135
|
-
text-overflow: ellipsis;
|
|
7136
|
-
}
|
|
7137
|
-
.cm-tooltip .opf-fix {
|
|
7138
|
-
display: flex;
|
|
7139
|
-
align-items: center;
|
|
7140
|
-
min-height: 44px;
|
|
7141
|
-
padding: 3px 12px;
|
|
7142
|
-
}
|
|
7143
|
-
.cm-tooltip-lint .cm-diagnosticAction {
|
|
7144
|
-
min-height: 44px;
|
|
7145
|
-
padding: 0 14px;
|
|
7146
|
-
}
|
|
7147
|
-
:root .cm-panels .cm-panel.cm-search :is(input, button, label) {
|
|
7148
|
-
min-height: 44px;
|
|
7149
|
-
}
|
|
7150
|
-
:root .cm-panels .cm-panel.cm-search :is(input[type="text"], input:not([type])) {
|
|
7151
|
-
font-size: 16px;
|
|
7152
|
-
}
|
|
7012
|
+
|
|
7013
|
+
|
|
7014
|
+
|
|
7015
|
+
|
|
7016
|
+
|
|
7017
|
+
|
|
7153
7018
|
/* The find and replace fields take a row of their own each, the buttons and options wrap beneath, the close button stays in the corner. */
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
:root .cm-panels .cm-panel.cm-search br {
|
|
7162
|
-
display: none;
|
|
7163
|
-
}
|
|
7164
|
-
:root .cm-panels .cm-panel.cm-search input[type="text"],
|
|
7165
|
-
:root .cm-panels .cm-panel.cm-search input:not([type]) {
|
|
7166
|
-
flex: 1 1 100%;
|
|
7167
|
-
min-width: 0;
|
|
7168
|
-
margin: 0;
|
|
7169
|
-
}
|
|
7170
|
-
:root .cm-panels .cm-panel.cm-search button,
|
|
7171
|
-
:root .cm-panels .cm-panel.cm-search label {
|
|
7172
|
-
margin: 0;
|
|
7173
|
-
}
|
|
7174
|
-
:root .cm-panels .cm-panel.cm-search label {
|
|
7175
|
-
display: inline-flex;
|
|
7176
|
-
align-items: center;
|
|
7177
|
-
gap: 6px;
|
|
7178
|
-
}
|
|
7179
|
-
:root .cm-panels .cm-panel.cm-search button {
|
|
7180
|
-
min-width: 44px;
|
|
7181
|
-
}
|
|
7182
|
-
:root .cm-panels .cm-panel.cm-search button[name="close"] {
|
|
7183
|
-
top: 0;
|
|
7184
|
-
right: 4px;
|
|
7185
|
-
}
|
|
7019
|
+
|
|
7020
|
+
|
|
7021
|
+
|
|
7022
|
+
|
|
7023
|
+
|
|
7024
|
+
|
|
7025
|
+
|
|
7186
7026
|
|
|
7187
7027
|
/* ---- menus, dialogs and the compact controls of the panels --------------------------------------------------------------------- */
|
|
7188
7028
|
.opf-export .opf-export-close {
|
|
@@ -7532,6 +7372,11 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7532
7372
|
gap: 4px;
|
|
7533
7373
|
padding: 0 12px 8px;
|
|
7534
7374
|
}
|
|
7375
|
+
/* CE-30: the slide row is no wider than the editor; the thumbnail strip scrolls inside it (a narrow box, a phone). */
|
|
7376
|
+
.opf-ws-dock > .opf-ws-navigator,
|
|
7377
|
+
.opf-ws-dock > .opf-ws-thumbnails {
|
|
7378
|
+
max-width: 100%;
|
|
7379
|
+
}
|
|
7535
7380
|
.opf-ws-status {
|
|
7536
7381
|
flex: none;
|
|
7537
7382
|
margin: 0;
|
|
@@ -7619,27 +7464,29 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7619
7464
|
flex: 1 1 0;
|
|
7620
7465
|
min-height: 0;
|
|
7621
7466
|
}
|
|
7622
|
-
/* A phone: the parts stack, the source above the slide, the side panel below.
|
|
7467
|
+
/* A phone: the parts stack, the source above the slide, the side panel below. CE-30: only in the layouts that have several parts to stack;
|
|
7468
|
+
`embed`, `viewer` and `canvas` are the slide alone and fit it to their box at any width (a stage of 40vh made a short embed overflow).
|
|
7469
|
+
`:where()` keeps the specificity of the plain class. */
|
|
7623
7470
|
@media (max-width: 760px) {
|
|
7624
|
-
.opf-ws-body {
|
|
7471
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-body {
|
|
7625
7472
|
flex-direction: column;
|
|
7626
7473
|
overflow: auto;
|
|
7627
7474
|
}
|
|
7628
|
-
.opf-ws-source {
|
|
7475
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-source {
|
|
7629
7476
|
flex: none;
|
|
7630
7477
|
min-width: 0;
|
|
7631
7478
|
height: 40vh;
|
|
7632
7479
|
border-right: 0;
|
|
7633
7480
|
border-bottom: 1px solid var(--opf-ui-border);
|
|
7634
7481
|
}
|
|
7635
|
-
.opf-ws-main {
|
|
7482
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-main {
|
|
7636
7483
|
flex: none;
|
|
7637
7484
|
}
|
|
7638
|
-
.opf-ws-stage {
|
|
7485
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-stage {
|
|
7639
7486
|
flex: none;
|
|
7640
7487
|
min-height: 40vh;
|
|
7641
7488
|
}
|
|
7642
|
-
.opf-ws-side {
|
|
7489
|
+
:where(.opf-workspace:not([data-opf-layout="embed"], [data-opf-layout="viewer"], [data-opf-layout="canvas"])) .opf-ws-side {
|
|
7643
7490
|
flex: none;
|
|
7644
7491
|
border-left: 0;
|
|
7645
7492
|
border-top: 1px solid var(--opf-ui-border);
|
|
@@ -7651,3 +7498,285 @@ input.opf-lx-input[data-field="max"] { font-family: var(--opf-ui-mono); font-siz
|
|
|
7651
7498
|
}
|
|
7652
7499
|
}
|
|
7653
7500
|
}
|
|
7501
|
+
|
|
7502
|
+
/* Outside the layer: the rules for CodeMirror's elements, which CodeMirror's own unlayered theme would otherwise beat. */
|
|
7503
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-editor {
|
|
7504
|
+
font: 12.5px/1.65 var(--opf-ui-mono);
|
|
7505
|
+
color: var(--opf-ui-fg);
|
|
7506
|
+
background: var(--opf-ui-code-bg);
|
|
7507
|
+
border: 1px solid var(--opf-ui-code-border);
|
|
7508
|
+
border-radius: var(--opf-ui-radius-md);
|
|
7509
|
+
}
|
|
7510
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-editor.cm-focused {
|
|
7511
|
+
outline: 2px solid var(--opf-ui-ring);
|
|
7512
|
+
outline-offset: 2px;
|
|
7513
|
+
}
|
|
7514
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-scroller,
|
|
7515
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-content {
|
|
7516
|
+
font-family: var(--opf-ui-mono);
|
|
7517
|
+
}
|
|
7518
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-content {
|
|
7519
|
+
caret-color: var(--opf-ui-fg);
|
|
7520
|
+
}
|
|
7521
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-cursor,
|
|
7522
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-dropCursor {
|
|
7523
|
+
border-left-color: var(--opf-ui-fg);
|
|
7524
|
+
}
|
|
7525
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-gutters {
|
|
7526
|
+
color: var(--opf-ui-muted-fg);
|
|
7527
|
+
background: var(--opf-ui-code-bg);
|
|
7528
|
+
border-right: 1px solid var(--opf-ui-code-border);
|
|
7529
|
+
}
|
|
7530
|
+
.cm-line.opf-hang-0 { --opf-hang: 0; }
|
|
7531
|
+
.cm-line.opf-hang-1 { --opf-hang: 1; }
|
|
7532
|
+
.cm-line.opf-hang-2 { --opf-hang: 2; }
|
|
7533
|
+
.cm-line.opf-hang-3 { --opf-hang: 3; }
|
|
7534
|
+
.cm-line.opf-hang-4 { --opf-hang: 4; }
|
|
7535
|
+
.cm-line.opf-hang-5 { --opf-hang: 5; }
|
|
7536
|
+
.cm-line.opf-hang-6 { --opf-hang: 6; }
|
|
7537
|
+
.cm-line.opf-hang-7 { --opf-hang: 7; }
|
|
7538
|
+
.cm-line.opf-hang-8 { --opf-hang: 8; }
|
|
7539
|
+
.cm-line.opf-hang-9 { --opf-hang: 9; }
|
|
7540
|
+
.cm-line.opf-hang-10 { --opf-hang: 10; }
|
|
7541
|
+
.cm-line.opf-hang-11 { --opf-hang: 11; }
|
|
7542
|
+
.cm-line.opf-hang-12 { --opf-hang: 12; }
|
|
7543
|
+
.cm-line.opf-hang-13 { --opf-hang: 13; }
|
|
7544
|
+
.cm-line.opf-hang-14 { --opf-hang: 14; }
|
|
7545
|
+
.cm-line.opf-hang-15 { --opf-hang: 15; }
|
|
7546
|
+
.cm-line.opf-hang-16 { --opf-hang: 16; }
|
|
7547
|
+
.cm-line.opf-hang-17 { --opf-hang: 17; }
|
|
7548
|
+
.cm-line.opf-hang-18 { --opf-hang: 18; }
|
|
7549
|
+
.cm-line.opf-hang-19 { --opf-hang: 19; }
|
|
7550
|
+
.cm-line.opf-hang-20 { --opf-hang: 20; }
|
|
7551
|
+
.cm-line.opf-hang-21 { --opf-hang: 21; }
|
|
7552
|
+
.cm-line.opf-hang-22 { --opf-hang: 22; }
|
|
7553
|
+
.cm-line.opf-hang-23 { --opf-hang: 23; }
|
|
7554
|
+
.cm-line.opf-hang-24 { --opf-hang: 24; }
|
|
7555
|
+
.cm-line.opf-hang-25 { --opf-hang: 25; }
|
|
7556
|
+
.cm-line.opf-hang-26 { --opf-hang: 26; }
|
|
7557
|
+
.cm-line.opf-hang-27 { --opf-hang: 27; }
|
|
7558
|
+
.cm-line.opf-hang-28 { --opf-hang: 28; }
|
|
7559
|
+
.cm-line.opf-hang-29 { --opf-hang: 29; }
|
|
7560
|
+
.cm-line.opf-hang-30 { --opf-hang: 30; }
|
|
7561
|
+
.cm-line.opf-hang-31 { --opf-hang: 31; }
|
|
7562
|
+
.cm-line.opf-hang-32 { --opf-hang: 32; }
|
|
7563
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-line {
|
|
7564
|
+
padding-left: calc(var(--opf-line-start, 6px) + var(--opf-hang, 0) * 1ch);
|
|
7565
|
+
text-indent: calc(-1 * var(--opf-hang, 0) * 1ch);
|
|
7566
|
+
}
|
|
7567
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-line > * {
|
|
7568
|
+
text-indent: 0;
|
|
7569
|
+
}
|
|
7570
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-activeLine,
|
|
7571
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-line.is-hover {
|
|
7572
|
+
background: color-mix(in srgb, var(--opf-ui-accent) 8%, transparent);
|
|
7573
|
+
}
|
|
7574
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-activeLineGutter {
|
|
7575
|
+
color: var(--opf-ui-fg);
|
|
7576
|
+
background: color-mix(in srgb, var(--opf-ui-accent) 8%, transparent);
|
|
7577
|
+
}
|
|
7578
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-editor .cm-selectionLayer .cm-selectionBackground,
|
|
7579
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground {
|
|
7580
|
+
background: color-mix(in srgb, var(--opf-ui-accent) 16%, transparent);
|
|
7581
|
+
}
|
|
7582
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-selectionMatch {
|
|
7583
|
+
background: color-mix(in srgb, var(--opf-ui-warn) 16%, transparent);
|
|
7584
|
+
box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--opf-ui-warn) 70%, transparent);
|
|
7585
|
+
}
|
|
7586
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-matchingBracket {
|
|
7587
|
+
background: color-mix(in srgb, var(--opf-ui-accent) 16%, transparent);
|
|
7588
|
+
outline: 1px solid var(--opf-ui-accent);
|
|
7589
|
+
}
|
|
7590
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-panels {
|
|
7591
|
+
color: var(--opf-ui-fg);
|
|
7592
|
+
background: var(--opf-ui-surface);
|
|
7593
|
+
border-color: var(--opf-ui-border);
|
|
7594
|
+
font-family: var(--opf-ui-font);
|
|
7595
|
+
}
|
|
7596
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-panels input,
|
|
7597
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-panels button {
|
|
7598
|
+
font: 12px var(--opf-ui-font);
|
|
7599
|
+
color: var(--opf-ui-fg);
|
|
7600
|
+
background: var(--opf-ui-surface);
|
|
7601
|
+
border: 1px solid var(--opf-ui-border);
|
|
7602
|
+
border-radius: var(--opf-ui-radius-sm);
|
|
7603
|
+
}
|
|
7604
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-tooltip {
|
|
7605
|
+
color: var(--opf-ui-fg);
|
|
7606
|
+
background: var(--opf-ui-surface);
|
|
7607
|
+
border: 1px solid var(--opf-ui-border);
|
|
7608
|
+
border-radius: var(--opf-ui-radius-md);
|
|
7609
|
+
box-shadow: var(--opf-ui-shadow-pop);
|
|
7610
|
+
}
|
|
7611
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul {
|
|
7612
|
+
font-family: var(--opf-ui-mono);
|
|
7613
|
+
font-size: 12px;
|
|
7614
|
+
}
|
|
7615
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li {
|
|
7616
|
+
padding: 2px 8px;
|
|
7617
|
+
color: var(--opf-ui-fg);
|
|
7618
|
+
}
|
|
7619
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] {
|
|
7620
|
+
color: var(--opf-ui-accent-fg);
|
|
7621
|
+
background: var(--opf-ui-accent);
|
|
7622
|
+
}
|
|
7623
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionDetail {
|
|
7624
|
+
margin-left: 12px;
|
|
7625
|
+
font-family: var(--opf-ui-font);
|
|
7626
|
+
font-style: normal;
|
|
7627
|
+
color: var(--opf-ui-muted-fg);
|
|
7628
|
+
}
|
|
7629
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionDetail {
|
|
7630
|
+
color: inherit;
|
|
7631
|
+
opacity: 0.85;
|
|
7632
|
+
}
|
|
7633
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete > .opf-completion-footer {
|
|
7634
|
+
padding: 4px 8px;
|
|
7635
|
+
font: 12px/1.4 var(--opf-ui-font);
|
|
7636
|
+
color: var(--opf-ui-muted-fg);
|
|
7637
|
+
border-top: 1px solid var(--opf-ui-border);
|
|
7638
|
+
}
|
|
7639
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionMatchedText {
|
|
7640
|
+
font-weight: 600;
|
|
7641
|
+
text-decoration: none;
|
|
7642
|
+
}
|
|
7643
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip .cm-completionInfo {
|
|
7644
|
+
max-width: 280px;
|
|
7645
|
+
padding: 6px 8px;
|
|
7646
|
+
font: 12px/1.45 var(--opf-ui-font);
|
|
7647
|
+
white-space: pre-wrap;
|
|
7648
|
+
color: var(--opf-ui-fg);
|
|
7649
|
+
background: var(--opf-ui-surface);
|
|
7650
|
+
border: 1px solid var(--opf-ui-border);
|
|
7651
|
+
border-radius: var(--opf-ui-radius-md);
|
|
7652
|
+
}
|
|
7653
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-tooltip .opf-doc,
|
|
7654
|
+
.opf-source-code .cm-tooltip .opf-doc {
|
|
7655
|
+
display: flex;
|
|
7656
|
+
flex-direction: column;
|
|
7657
|
+
gap: 4px;
|
|
7658
|
+
max-width: 340px;
|
|
7659
|
+
padding: 2px 0;
|
|
7660
|
+
font: 12px/1.45 var(--opf-ui-font);
|
|
7661
|
+
white-space: normal;
|
|
7662
|
+
}
|
|
7663
|
+
.cm-tooltip-lint .opf-problem { display: flex; flex-direction: column; gap: 2px; max-width: 360px; white-space: normal; }
|
|
7664
|
+
.cm-tooltip-lint .cm-diagnosticAction { margin: 4px 6px 0 0; padding: 1px 8px; border: 1px solid var(--opf-ui-border); border-radius: var(--opf-ui-radius-sm); background: var(--opf-ui-muted); color: var(--opf-ui-fg); font: 12px var(--opf-ui-font); cursor: pointer; }
|
|
7665
|
+
.cm-tooltip-lint .cm-diagnosticSource { color: var(--opf-ui-muted-fg); }
|
|
7666
|
+
.cm-tooltip .opf-fixes { display: flex; flex-direction: column; min-width: 180px; padding: 3px; font: 12px var(--opf-ui-font); }
|
|
7667
|
+
:root :is(.opf-ui, .opf-json, .opf-code) .cm-tooltip .cm-completionInfo { white-space: normal; }
|
|
7668
|
+
.cm-tooltip.opf-hint { display: flex; flex-direction: column; min-width: 22em; max-width: 38em; padding: 4px 0; font: 12.5px var(--opf-ui-font); white-space: normal; }
|
|
7669
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7670
|
+
.cm-tooltip.opf-hint, .cm-tooltip.opf-hint * { animation: none !important; transition: none !important; }
|
|
7671
|
+
}
|
|
7672
|
+
.cm-editor.opf-docs-off .cm-completionInfo { display: none; }
|
|
7673
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-diagnostic-error {
|
|
7674
|
+
border-left-color: var(--opf-ui-danger);
|
|
7675
|
+
}
|
|
7676
|
+
:is(.opf-ui, .opf-json, .opf-code) .cm-diagnostic-warning {
|
|
7677
|
+
border-left-color: var(--opf-ui-warn);
|
|
7678
|
+
}
|
|
7679
|
+
.opf-source-code > .cm-editor { flex: 1; min-width: 0; height: 100%; background: transparent; color: var(--opf-ui-fg); border: 0; border-radius: 0; }
|
|
7680
|
+
.opf-source-code .cm-editor.cm-focused { outline: none; }
|
|
7681
|
+
.opf-source-code .cm-scroller { overflow: auto; font: 400 13.5px/22px var(--opf-ui-mono); }
|
|
7682
|
+
.opf-source[data-density="touch"] .opf-source-code .cm-scroller { font-size: 13px; line-height: 21px; }
|
|
7683
|
+
.opf-source-code .cm-content { padding: 16px 16px 16px 4px; caret-color: var(--opf-ui-fg); }
|
|
7684
|
+
.opf-source-code .cm-line { --opf-line-start: 2px; padding-top: 0; padding-right: 2px; padding-bottom: 0; }
|
|
7685
|
+
.opf-source-code .cm-gutters { border: 0; background: transparent; color: var(--opf-ui-muted-fg); }
|
|
7686
|
+
.opf-source-code .cm-lineNumbers .cm-gutterElement { min-width: 30px; padding: 0 12px 0 0; text-align: right; font-size: 11px; }
|
|
7687
|
+
.opf-source-code .cm-activeLine { background: transparent; }
|
|
7688
|
+
.opf-source-code .cm-cursor { border-left-color: var(--opf-ui-fg); }
|
|
7689
|
+
.opf-source-code .cm-line.is-hover { background: color-mix(in srgb, var(--opf-ui-accent) 6%, transparent); }
|
|
7690
|
+
.opf-source-code .cm-line.opf-source-flash { animation: opf-source-flash 1.2s ease-out; }
|
|
7691
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7692
|
+
.opf-source-code .cm-line.opf-source-flash { animation: none; background: color-mix(in srgb, var(--opf-ui-accent) 20%, transparent); }
|
|
7693
|
+
}
|
|
7694
|
+
.opf-source-code .cm-panels { background: var(--opf-ui-surface); color: var(--opf-ui-fg); border-color: var(--opf-ui-border); }
|
|
7695
|
+
.opf-source-code .cm-tooltip { background: var(--opf-ui-surface); border: 1px solid var(--opf-ui-border); border-radius: var(--opf-ui-radius); color: var(--opf-ui-fg); }
|
|
7696
|
+
.opf-source-code .cm-lintRange-error { background-image: none; text-decoration: underline wavy var(--opf-ui-danger); }
|
|
7697
|
+
.opf-source-code .cm-foldGutter { width: 16px; }
|
|
7698
|
+
.opf-source-code .cm-foldGutter .cm-gutterElement { display: flex; align-items: center; justify-content: center; padding: 0; cursor: pointer; }
|
|
7699
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 100%; color: var(--opf-ui-muted-fg); opacity: 0; transition: opacity var(--opf-ui-ease); }
|
|
7700
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker.is-folded,
|
|
7701
|
+
.opf-source-code:hover .cm-foldGutter .opf-fold-marker,
|
|
7702
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker:hover { opacity: 1; }
|
|
7703
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker:hover { color: var(--opf-ui-fg); }
|
|
7704
|
+
.opf-source-code .cm-foldPlaceholder { border: 0; background: var(--opf-ui-muted); color: var(--opf-ui-muted-fg); border-radius: var(--opf-ui-radius-sm); padding: 0 5px; margin: 0 2px; cursor: pointer; }
|
|
7705
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7706
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker { transition: none; }
|
|
7707
|
+
}
|
|
7708
|
+
@media (forced-colors: active) {
|
|
7709
|
+
.opf-source-code .cm-foldGutter .opf-fold-marker { opacity: 1; }
|
|
7710
|
+
}
|
|
7711
|
+
@media (forced-colors: active) {
|
|
7712
|
+
.opf-source-code .cm-tooltip-autocomplete > ul > li[aria-selected],
|
|
7713
|
+
.cm-tooltip .opf-fix[aria-selected="true"] { outline: 2px solid Highlight; outline-offset: -2px; forced-color-adjust: none; background: Canvas; color: CanvasText; }
|
|
7714
|
+
.opf-source-code .cm-lintRange-error { text-decoration: underline wavy CanvasText; }
|
|
7715
|
+
.opf-source-code .cm-lintRange-warning { text-decoration: underline dashed CanvasText; }
|
|
7716
|
+
.opf-source-code .cm-lintRange-info { text-decoration: underline dotted CanvasText; }
|
|
7717
|
+
}
|
|
7718
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7719
|
+
.cm-tooltip, .cm-tooltip * { animation: none !important; transition: none !important; }
|
|
7720
|
+
}
|
|
7721
|
+
@media (pointer: coarse) {
|
|
7722
|
+
:root :is(.opf-ui, .opf-source, .opf-json, .opf-code) .cm-tooltip.cm-tooltip-autocomplete > ul > li {
|
|
7723
|
+
display: flex;
|
|
7724
|
+
align-items: center;
|
|
7725
|
+
gap: 4px;
|
|
7726
|
+
min-height: 44px;
|
|
7727
|
+
padding: 2px 12px;
|
|
7728
|
+
}
|
|
7729
|
+
:root :is(.opf-ui, .opf-source, .opf-json, .opf-code) .cm-tooltip-autocomplete .cm-completionLabel {
|
|
7730
|
+
min-width: 0;
|
|
7731
|
+
overflow: hidden;
|
|
7732
|
+
text-overflow: ellipsis;
|
|
7733
|
+
}
|
|
7734
|
+
.cm-tooltip .opf-fix {
|
|
7735
|
+
display: flex;
|
|
7736
|
+
align-items: center;
|
|
7737
|
+
min-height: 44px;
|
|
7738
|
+
padding: 3px 12px;
|
|
7739
|
+
}
|
|
7740
|
+
.cm-tooltip-lint .cm-diagnosticAction {
|
|
7741
|
+
min-height: 44px;
|
|
7742
|
+
padding: 0 14px;
|
|
7743
|
+
}
|
|
7744
|
+
:root .cm-panels .cm-panel.cm-search :is(input, button, label) {
|
|
7745
|
+
min-height: 44px;
|
|
7746
|
+
}
|
|
7747
|
+
:root .cm-panels .cm-panel.cm-search :is(input[type="text"], input:not([type])) {
|
|
7748
|
+
font-size: 16px;
|
|
7749
|
+
}
|
|
7750
|
+
:root .cm-panels .cm-panel.cm-search {
|
|
7751
|
+
display: flex;
|
|
7752
|
+
flex-wrap: wrap;
|
|
7753
|
+
align-items: center;
|
|
7754
|
+
gap: 6px;
|
|
7755
|
+
padding: 6px 52px 6px 8px;
|
|
7756
|
+
}
|
|
7757
|
+
:root .cm-panels .cm-panel.cm-search br {
|
|
7758
|
+
display: none;
|
|
7759
|
+
}
|
|
7760
|
+
:root .cm-panels .cm-panel.cm-search input[type="text"],
|
|
7761
|
+
:root .cm-panels .cm-panel.cm-search input:not([type]) {
|
|
7762
|
+
flex: 1 1 100%;
|
|
7763
|
+
min-width: 0;
|
|
7764
|
+
margin: 0;
|
|
7765
|
+
}
|
|
7766
|
+
:root .cm-panels .cm-panel.cm-search button,
|
|
7767
|
+
:root .cm-panels .cm-panel.cm-search label {
|
|
7768
|
+
margin: 0;
|
|
7769
|
+
}
|
|
7770
|
+
:root .cm-panels .cm-panel.cm-search label {
|
|
7771
|
+
display: inline-flex;
|
|
7772
|
+
align-items: center;
|
|
7773
|
+
gap: 6px;
|
|
7774
|
+
}
|
|
7775
|
+
:root .cm-panels .cm-panel.cm-search button {
|
|
7776
|
+
min-width: 44px;
|
|
7777
|
+
}
|
|
7778
|
+
:root .cm-panels .cm-panel.cm-search button[name="close"] {
|
|
7779
|
+
top: 0;
|
|
7780
|
+
right: 4px;
|
|
7781
|
+
}
|
|
7782
|
+
}
|
package/dist/toolbar.d.ts
CHANGED
|
@@ -26,11 +26,21 @@ export type ToolbarItemName =
|
|
|
26
26
|
| "spacer"
|
|
27
27
|
| "|";
|
|
28
28
|
|
|
29
|
-
/** An item
|
|
30
|
-
export type
|
|
29
|
+
/** An item name, or the name of a host's own item. */
|
|
30
|
+
export type ToolbarItemId = ToolbarItemName | (string & {});
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* An item by name, or with its own priority (higher stays visible longer) and whether it may move into the more menu. A host's own item is
|
|
34
|
+
* `{ id, priority }` with a name that is not one of the above (lowercase letters, digits and dashes): its slot starts empty, the host fills it
|
|
35
|
+
* (`slot(id)`) and registers what it offers in the more menu with `mount(id, part)`. A bare unknown name throws, so a misspelt item is caught.
|
|
36
|
+
*/
|
|
37
|
+
export type ToolbarItemSpec =
|
|
38
|
+
| ToolbarItemName
|
|
39
|
+
| { id: ToolbarItemName; priority?: number; collapsible?: boolean }
|
|
40
|
+
| { id: string; priority: number; collapsible?: boolean };
|
|
31
41
|
|
|
32
42
|
export interface ToolbarItem {
|
|
33
|
-
id:
|
|
43
|
+
id: ToolbarItemId;
|
|
34
44
|
priority: number;
|
|
35
45
|
collapsible: boolean;
|
|
36
46
|
}
|
|
@@ -38,7 +48,7 @@ export interface ToolbarItem {
|
|
|
38
48
|
/** The defaults of every item: `more` and `title` stay (the title shrinks instead), `spacer` and `|` are layout. */
|
|
39
49
|
export declare const TOOLBAR_ITEMS: Readonly<Record<ToolbarItemName, Readonly<{ priority: number; collapsible: boolean }>>>;
|
|
40
50
|
|
|
41
|
-
/** The items with their priorities. Throws on a name that is not an item, and on a named item given twice (`spacer` and `|` may repeat). */
|
|
51
|
+
/** The items with their priorities. Throws on a name that is not an item (or a host item), and on a named item given twice (`spacer` and `|` may repeat). */
|
|
42
52
|
export declare function normalizeToolbarItems(items: readonly ToolbarItemSpec[]): ToolbarItem[];
|
|
43
53
|
|
|
44
54
|
/** One entry of the more menu. `pressed` makes it a checkbox item (`aria-checked`); a `disabled` item is listed but does not run. */
|
|
@@ -65,7 +75,7 @@ export interface ToolbarOptions {
|
|
|
65
75
|
/** Replace the ⋯ glyph: `more` (`.opf-tb-more-icon`). See `OpfIcon`. */
|
|
66
76
|
icons?: OpfIcons<"more">;
|
|
67
77
|
/** The set of collapsed items changed. */
|
|
68
|
-
onCollapse?(detail: { collapsed:
|
|
78
|
+
onCollapse?(detail: { collapsed: ToolbarItemId[] }): void;
|
|
69
79
|
/** A part's `menuItems()` or an item's `run()` threw. */
|
|
70
80
|
onError?(error: unknown): void;
|
|
71
81
|
}
|
|
@@ -74,20 +84,20 @@ export interface Toolbar {
|
|
|
74
84
|
/** The row (`.opf-tb`), appended to the container. */
|
|
75
85
|
readonly element: HTMLElement;
|
|
76
86
|
readonly items: ToolbarItem[];
|
|
77
|
-
/** One element per named item (`data-opf-toolbar-item`), in bar order. Mount a part in it, then `mount(name, part)`. */
|
|
78
|
-
readonly slots: Partial<Record<
|
|
79
|
-
slot(name:
|
|
87
|
+
/** One element per named item (`data-opf-toolbar-item`), in bar order, host items included. Mount a part in it, then `mount(name, part)`. */
|
|
88
|
+
readonly slots: Partial<Record<ToolbarItemId, HTMLElement>>;
|
|
89
|
+
slot(name: ToolbarItemId): HTMLElement | undefined;
|
|
80
90
|
/** The items in the more menu now, in bar order. */
|
|
81
|
-
readonly collapsed:
|
|
91
|
+
readonly collapsed: ToolbarItemId[];
|
|
82
92
|
readonly menuOpen: boolean;
|
|
83
93
|
/** Change an item's priority or whether it collapses; false for an item that is not in the bar (or `more`, `spacer`, `|`). */
|
|
84
|
-
setItem(name:
|
|
94
|
+
setItem(name: ToolbarItemId, change: { priority?: number; collapsible?: boolean }): boolean;
|
|
85
95
|
/** Register the part mounted in a slot, for its menu items. Returns the function that unregisters it. */
|
|
86
|
-
mount(name:
|
|
96
|
+
mount(name: ToolbarItemId, part: ToolbarPart): () => void;
|
|
87
97
|
/** What the more menu would list now, one group per collapsed part. */
|
|
88
|
-
menuItems(): { id:
|
|
98
|
+
menuItems(): { id: ToolbarItemId; items: ToolbarMenuItem[] }[];
|
|
89
99
|
/** Fit the row now (it also fits itself on the next frame after a resize). Returns the collapsed items. */
|
|
90
|
-
update():
|
|
100
|
+
update(): ToolbarItemId[];
|
|
91
101
|
/** Open the more menu and focus its first (or last) item. False when there is nothing to list. */
|
|
92
102
|
openMenu(which?: "first" | "last"): boolean;
|
|
93
103
|
closeMenu(options?: { restoreFocus?: boolean }): void;
|
package/dist/toolbar.js
CHANGED
|
@@ -31,10 +31,16 @@ export const TOOLBAR_ITEMS = Object.freeze({
|
|
|
31
31
|
});
|
|
32
32
|
const REPEATABLE = new Set(["spacer", "|"]);
|
|
33
33
|
const LABELS = Object.freeze({ more: "More", menu: "More actions" });
|
|
34
|
+
// A host's own item: `{ id, priority }` with a name of its own (lowercase letters, digits and dashes). Its slot starts empty; the host fills it and
|
|
35
|
+
// registers what it offers in ⋯ with `mount(id, part)`, like any item. A bare unknown name still throws, so a misspelt item is caught.
|
|
36
|
+
const HOST_ITEM = /^[a-z][a-z0-9-]*$/;
|
|
37
|
+
|
|
38
|
+
const isHostItem = (id) => typeof id === "string" && !Object.hasOwn(TOOLBAR_ITEMS, id) && HOST_ITEM.test(id);
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Turn the `items` option (names, or `{ id, priority, collapsible }`) into the list the toolbar builds, with each item's priority and whether
|
|
37
|
-
* it collapses. Throws on a name that is not an item
|
|
42
|
+
* it collapses. Throws on a name that is not an item (a host's own item is `{ id, priority }` with a name of its own) and on a named item given
|
|
43
|
+
* twice (`spacer` and `|` may repeat).
|
|
38
44
|
*/
|
|
39
45
|
export function normalizeToolbarItems(items) {
|
|
40
46
|
if (!Array.isArray(items)) throw new TypeError("toolbar items must be an array of item names or { id, priority } objects.");
|
|
@@ -42,8 +48,9 @@ export function normalizeToolbarItems(items) {
|
|
|
42
48
|
return items.map((item, index) => {
|
|
43
49
|
const spec = typeof item === "string" ? { id: item } : item;
|
|
44
50
|
if (!spec || typeof spec !== "object" || typeof spec.id !== "string") throw new TypeError(`toolbar item ${index} must be an item name or { id, priority }.`);
|
|
45
|
-
const
|
|
46
|
-
|
|
51
|
+
const host = typeof item === "object" && spec.priority !== undefined && isHostItem(spec.id);
|
|
52
|
+
const known = host ? { priority: spec.priority, collapsible: true } : Object.hasOwn(TOOLBAR_ITEMS, spec.id) ? TOOLBAR_ITEMS[spec.id] : undefined;
|
|
53
|
+
if (!known) throw new RangeError(`"${spec.id}" is not a toolbar item (${Object.keys(TOOLBAR_ITEMS).join(", ")}; an item of your own is { id, priority }).`);
|
|
47
54
|
if (!REPEATABLE.has(spec.id)) {
|
|
48
55
|
if (seen.has(spec.id)) throw new RangeError(`the toolbar item "${spec.id}" is given twice.`);
|
|
49
56
|
seen.add(spec.id);
|
|
@@ -274,7 +281,8 @@ export function createToolbar(container, options = {}) {
|
|
|
274
281
|
}
|
|
275
282
|
const before = collapsed.join(",");
|
|
276
283
|
bar.setAttribute("data-measuring", "");
|
|
277
|
-
|
|
284
|
+
// Every item shows again first, one made non-collapsible (`setItem`) while it was in ⋯ included.
|
|
285
|
+
for (const entry of entries) setCollapsed(entry, false);
|
|
278
286
|
if (moreEntry) moreEntry.element.hidden = true;
|
|
279
287
|
syncDividers();
|
|
280
288
|
const next = [];
|
package/dist/workspace.d.ts
CHANGED
|
@@ -274,6 +274,15 @@ export interface OpfEditorSourceOptions {
|
|
|
274
274
|
onDownload?(file: SourceFile): void | Promise<void>;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/** CE-30: `variables` as an object: the canvas draws `{{variables}}` resolved, as with `"resolved"`. */
|
|
278
|
+
export interface OpfEditorVariablesOptions {
|
|
279
|
+
/**
|
|
280
|
+
* Called when a press on the slide lands on text that has no field of its own (a value the deck generates), in place of focusing the editor's
|
|
281
|
+
* source pane: focus your own code editor. A throw is reported as an `error` event.
|
|
282
|
+
*/
|
|
283
|
+
focusSource?(): void;
|
|
284
|
+
}
|
|
285
|
+
|
|
277
286
|
export interface OpfEditorOptions {
|
|
278
287
|
/** The document to edit: an OPF object, or its JSON text (then the pane keeps its spelling). Creates the session. */
|
|
279
288
|
document?: unknown;
|
|
@@ -289,8 +298,12 @@ export interface OpfEditorOptions {
|
|
|
289
298
|
imageResolver?: ToSvgOptions["imageResolver"];
|
|
290
299
|
/** Stores an uploaded image yourself and returns its reference (see `@openpresentation/opf-editor/assets`). Used by the design controls. */
|
|
291
300
|
onAddAsset?: DesignControlsOptions["onAddAsset"];
|
|
292
|
-
/**
|
|
293
|
-
|
|
301
|
+
/**
|
|
302
|
+
* `"authored"` (default): the canvas shows `{{variables}}` as written. `"resolved"`: filled in, except in a template deck; a press on filled-in text
|
|
303
|
+
* opens its properties form, and a press on text without a field of its own (a generated value) focuses the source pane. CE-30: an object is
|
|
304
|
+
* `"resolved"` too, and its `focusSource` is called instead of focusing the source pane: for a host with its own code editor beside the slide.
|
|
305
|
+
*/
|
|
306
|
+
variables?: "authored" | "resolved" | OpfEditorVariablesOptions;
|
|
294
307
|
|
|
295
308
|
/**
|
|
296
309
|
* `"full"` (default), `"canvas"`, `"embed"` (CE-28) or `"source"`: the editor builds the arrangement (ignored when `slots` names a part; slots for the
|
package/dist/workspace.js
CHANGED
|
@@ -164,10 +164,11 @@ function resolveParts(options, layout, slots, asked = []) {
|
|
|
164
164
|
}
|
|
165
165
|
// The slide is the editor; a source-only layout has none.
|
|
166
166
|
parts.canvas = layout === "source" ? false : panels.canvas !== false;
|
|
167
|
-
// CE-28 wave 2: an item the toolbar lists brings the part it shows: Export in the viewer,
|
|
168
|
-
// has none, so the pill has counts) wherever it is listed.
|
|
167
|
+
// CE-28 wave 2: an item the toolbar lists brings the part it shows: Export in the viewer, Present (CE-30: also where the host arranges the
|
|
168
|
+
// parts with `slots`), and Review (run without its panel where the layout has none, so the pill has counts) wherever it is listed.
|
|
169
169
|
const listed = (id) => asked.some((item) => item.id === id) || Boolean(slots[itemSlot(id)]);
|
|
170
170
|
if (panels.export === undefined && listed("export")) parts.export = true;
|
|
171
|
+
if (panels.present === undefined && listed("present")) parts.present = true;
|
|
171
172
|
if (panels.review === undefined && listed("review") && !parts.review) {
|
|
172
173
|
parts.review = true;
|
|
173
174
|
// A layout without a Review panel gets none: the review runs headless for the pill.
|
|
@@ -203,7 +204,9 @@ function resolveToolbar(options, layout, parts, views, given, items) {
|
|
|
203
204
|
spacer: true,
|
|
204
205
|
"|": true,
|
|
205
206
|
};
|
|
206
|
-
|
|
207
|
+
// A host's own item (`{ id, priority }` with a name of its own) is always built: its slot is the host's to fill (`editor.toolbar.slot(id)`).
|
|
208
|
+
const host = (id) => !Object.hasOwn(TOOLBAR_ITEMS, id);
|
|
209
|
+
return items.filter((item) => !RESERVED_ITEMS.has(item.id) && (host(item.id) || available[item.id]) && !(ITEM_SLOT_NAMES.has(item.id) && given[itemSlot(item.id)]));
|
|
207
210
|
}
|
|
208
211
|
|
|
209
212
|
/**
|
|
@@ -422,7 +425,10 @@ export function createOpfEditor(element, options = {}) {
|
|
|
422
425
|
}
|
|
423
426
|
let frameSize = { width: 0, height: 0 };
|
|
424
427
|
const draftMemory = createSourceMemory();
|
|
425
|
-
|
|
428
|
+
// CE-30: `variables: { focusSource }` is "resolved" with the host's own code editor: a press on text without a field of its own focuses that.
|
|
429
|
+
const variablesObject = options.variables !== null && typeof options.variables === "object" ? options.variables : undefined;
|
|
430
|
+
const variablesMode = options.variables === "resolved" || variablesObject ? "resolved" : "authored";
|
|
431
|
+
if (variablesObject && variablesObject.focusSource !== undefined && typeof variablesObject.focusSource !== "function") throw new TypeError("variables.focusSource must be a function.");
|
|
426
432
|
const fitMode = studioLayout ? false : options.fit === undefined ? (layout === "slots" ? false : "contain") : options.fit;
|
|
427
433
|
|
|
428
434
|
const say = (message) => {
|
|
@@ -944,7 +950,14 @@ export function createOpfEditor(element, options = {}) {
|
|
|
944
950
|
cleanups.push(
|
|
945
951
|
installCanvasVariableEditing(slots.canvas, ui, canvas, {
|
|
946
952
|
resolved: () => !authoredTemplate,
|
|
947
|
-
focusSource: () =>
|
|
953
|
+
focusSource: () => {
|
|
954
|
+
if (!variablesObject?.focusSource) return pane?.editor?.api?.focus?.();
|
|
955
|
+
try {
|
|
956
|
+
variablesObject.focusSource();
|
|
957
|
+
} catch (error) {
|
|
958
|
+
report(error);
|
|
959
|
+
}
|
|
960
|
+
},
|
|
948
961
|
}),
|
|
949
962
|
);
|
|
950
963
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpresentation/opf-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "Embeddable local OPF editor primitives built on the deterministic renderer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -348,12 +348,12 @@
|
|
|
348
348
|
"@lezer/highlight": "^1.2.5",
|
|
349
349
|
"jsonc-parser": "3.3.1",
|
|
350
350
|
"yaml": "^2.9.1",
|
|
351
|
-
"@openpresentation/opf": "^0.
|
|
351
|
+
"@openpresentation/opf": "^0.31.0"
|
|
352
352
|
},
|
|
353
353
|
"peerDependencies": {
|
|
354
354
|
"react": ">=18",
|
|
355
355
|
"react-dom": ">=18",
|
|
356
|
-
"@openpresentation/opf-render": "^0.
|
|
356
|
+
"@openpresentation/opf-render": "^0.31.0"
|
|
357
357
|
},
|
|
358
358
|
"peerDependenciesMeta": {
|
|
359
359
|
"@openpresentation/opf-render": {
|
|
@@ -422,9 +422,9 @@
|
|
|
422
422
|
"react-dom": "19.3.1",
|
|
423
423
|
"react-18": "npm:react@18.3.1",
|
|
424
424
|
"react-dom-18": "npm:react-dom@18.3.1",
|
|
425
|
-
"@openpresentation/
|
|
426
|
-
"@openpresentation/
|
|
427
|
-
"@openpresentation/opf-render": "0.
|
|
425
|
+
"@openpresentation/opf-pptx": "0.31.0",
|
|
426
|
+
"@openpresentation/gallery": "0.31.0",
|
|
427
|
+
"@openpresentation/opf-render": "0.31.0"
|
|
428
428
|
},
|
|
429
429
|
"scripts": {
|
|
430
430
|
"build": "node scripts/build.mjs",
|
|
@@ -479,5 +479,5 @@
|
|
|
479
479
|
"test:workspace-react-browser": "node test/workspace-react-browser.mjs",
|
|
480
480
|
"test:element-browser": "node test/element-browser.mjs"
|
|
481
481
|
},
|
|
482
|
-
"gitHead": "
|
|
482
|
+
"gitHead": "d68561fad7b2b319cd7cdb8d7e75fefdd1dffa4c"
|
|
483
483
|
}
|