tosijs-ui 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/iife.js +70 -60
- package/dist/iife.js.map +42 -42
- package/dist/index.js +15 -37
- package/dist/index.js.map +39 -39
- package/dist/version.d.ts +1 -1
- package/package.json +2 -2
- package/dist/ab-test.js +0 -116
- package/dist/babylon-3d.js +0 -292
- package/dist/bodymovin-player.js +0 -172
- package/dist/bp-loader.js +0 -26
- package/dist/carousel.js +0 -308
- package/dist/code-editor.js +0 -102
- package/dist/color-input.js +0 -112
- package/dist/data-table.js +0 -774
- package/dist/drag-and-drop.js +0 -386
- package/dist/editable-rect.js +0 -450
- package/dist/filter-builder.js +0 -468
- package/dist/float.js +0 -170
- package/dist/form.js +0 -466
- package/dist/gamepad.js +0 -115
- package/dist/icon-data.js +0 -308
- package/dist/icon-types.js +0 -1
- package/dist/icons.js +0 -374
- package/dist/index-iife.js +0 -4
- package/dist/live-example.js +0 -611
- package/dist/localize.js +0 -381
- package/dist/make-sorter.js +0 -119
- package/dist/make-sorter.test.d.ts +0 -1
- package/dist/make-sorter.test.js +0 -48
- package/dist/mapbox.js +0 -161
- package/dist/markdown-viewer.js +0 -173
- package/dist/match-shortcut.js +0 -13
- package/dist/match-shortcut.test.d.ts +0 -1
- package/dist/match-shortcut.test.js +0 -194
- package/dist/menu.js +0 -614
- package/dist/notifications.js +0 -308
- package/dist/password-strength.js +0 -302
- package/dist/playwright.config.d.ts +0 -9
- package/dist/playwright.config.js +0 -73
- package/dist/pop-float.js +0 -231
- package/dist/rating.js +0 -192
- package/dist/rich-text.js +0 -296
- package/dist/segmented.js +0 -298
- package/dist/select.js +0 -427
- package/dist/side-nav.js +0 -106
- package/dist/size-break.js +0 -118
- package/dist/sizer.js +0 -92
- package/dist/src/ab-test.d.ts +0 -14
- package/dist/src/babylon-3d.d.ts +0 -53
- package/dist/src/bodymovin-player.d.ts +0 -32
- package/dist/src/bp-loader.d.ts +0 -0
- package/dist/src/carousel.d.ts +0 -113
- package/dist/src/code-editor.d.ts +0 -27
- package/dist/src/color-input.d.ts +0 -41
- package/dist/src/data-table.d.ts +0 -79
- package/dist/src/drag-and-drop.d.ts +0 -2
- package/dist/src/editable-rect.d.ts +0 -97
- package/dist/src/filter-builder.d.ts +0 -64
- package/dist/src/float.d.ts +0 -18
- package/dist/src/form.d.ts +0 -68
- package/dist/src/gamepad.d.ts +0 -34
- package/dist/src/icon-data.d.ts +0 -309
- package/dist/src/icon-types.d.ts +0 -7
- package/dist/src/icons.d.ts +0 -17
- package/dist/src/index.d.ts +0 -37
- package/dist/src/live-example.d.ts +0 -51
- package/dist/src/localize.d.ts +0 -30
- package/dist/src/make-sorter.d.ts +0 -3
- package/dist/src/mapbox.d.ts +0 -24
- package/dist/src/markdown-viewer.d.ts +0 -15
- package/dist/src/match-shortcut.d.ts +0 -9
- package/dist/src/menu.d.ts +0 -60
- package/dist/src/notifications.d.ts +0 -106
- package/dist/src/password-strength.d.ts +0 -35
- package/dist/src/pop-float.d.ts +0 -10
- package/dist/src/rating.d.ts +0 -62
- package/dist/src/rich-text.d.ts +0 -28
- package/dist/src/segmented.d.ts +0 -80
- package/dist/src/select.d.ts +0 -43
- package/dist/src/side-nav.d.ts +0 -36
- package/dist/src/size-break.d.ts +0 -18
- package/dist/src/sizer.d.ts +0 -34
- package/dist/src/tab-selector.d.ts +0 -91
- package/dist/src/tag-list.d.ts +0 -37
- package/dist/src/track-drag.d.ts +0 -5
- package/dist/src/version.d.ts +0 -1
- package/dist/src/via-tag.d.ts +0 -2
- package/dist/tab-selector.js +0 -326
- package/dist/tag-list.js +0 -375
- package/dist/track-drag.js +0 -143
- package/dist/version.js +0 -1
- package/dist/via-tag.js +0 -102
package/dist/live-example.js
DELETED
|
@@ -1,611 +0,0 @@
|
|
|
1
|
-
/*#
|
|
2
|
-
# example
|
|
3
|
-
|
|
4
|
-
`<xin-example>` makes it easy to insert interactive code examples in a web page. It
|
|
5
|
-
started life as a super lightweight, easier-to-embed implementation of
|
|
6
|
-
[b8rjs's fiddle component](https://b8rjs.com)—which I dearly missed—but now the student
|
|
7
|
-
is, by far, the master. And it's still super lightweight.
|
|
8
|
-
|
|
9
|
-
*You're probably looking at it right now.*
|
|
10
|
-
|
|
11
|
-
```js
|
|
12
|
-
// this code executes in an async function body
|
|
13
|
-
// it has xinjs, xinjsui, and preview (the preview div) available as local variables
|
|
14
|
-
const { div } = xinjs.elements
|
|
15
|
-
preview.append(div({class: 'example'}, 'fiddle de dee!'))
|
|
16
|
-
preview.append('Try editing some code and hitting refresh…')
|
|
17
|
-
```
|
|
18
|
-
```html
|
|
19
|
-
<h2>Example</h2>
|
|
20
|
-
```
|
|
21
|
-
```css
|
|
22
|
-
.preview {
|
|
23
|
-
padding: 0 var(--spacing);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.example {
|
|
27
|
-
animation: throb ease-in-out 1s infinite alternate;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@keyframes throb {
|
|
31
|
-
from { color: blue }
|
|
32
|
-
to { color: red }
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
You can also create a live-example from HTML. And if you add the `persist-to-dom`
|
|
37
|
-
attribute, it will persist your code to the DOM.
|
|
38
|
-
|
|
39
|
-
<xin-example persist-to-dom>
|
|
40
|
-
<pre class="language-html">
|
|
41
|
-
<h1 class="make-it-red">Pure HTML!</h1>
|
|
42
|
-
<button>Click Me!</button>
|
|
43
|
-
</pre>
|
|
44
|
-
<pre class="language-js">
|
|
45
|
-
preview.querySelector('button').addEventListener('click', () => {
|
|
46
|
-
alert('you clicked?')
|
|
47
|
-
})
|
|
48
|
-
</pre>
|
|
49
|
-
<pre class="language-css">
|
|
50
|
-
.make-it-red {
|
|
51
|
-
color: red;
|
|
52
|
-
}
|
|
53
|
-
</pre>
|
|
54
|
-
</xin-example>
|
|
55
|
-
|
|
56
|
-
You can simply wrap it around a sequence of code blocks in the DOM with the
|
|
57
|
-
languages (js, html, css) as annotations or you can directly set the `js`, `html`,
|
|
58
|
-
and `css` properties.
|
|
59
|
-
|
|
60
|
-
## Code-Editor
|
|
61
|
-
|
|
62
|
-
The **code-editor** is actually the same component spawned in a new window using
|
|
63
|
-
a couple of clever tricks, the most important of which is leveraging
|
|
64
|
-
[StorageEvent](https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent).
|
|
65
|
-
|
|
66
|
-
This functionality was originally added to make working in XR easier, but it turned
|
|
67
|
-
out that it's just better than the earlier way of doing things.
|
|
68
|
-
|
|
69
|
-
It actually uses just one `localStorage` item to handle any number of code-editors,
|
|
70
|
-
and cleans up after itself when you close the example (including closing stray
|
|
71
|
-
windows.
|
|
72
|
-
|
|
73
|
-
> **To Do** a little refactoring and tweaking to split the the editor off as a
|
|
74
|
-
completely separate component that can be used for other things, and make the
|
|
75
|
-
example itself lighter-weight.
|
|
76
|
-
|
|
77
|
-
## context
|
|
78
|
-
|
|
79
|
-
A `<xin-example>` can be given a `context` object {[key: string]: any}, which is the
|
|
80
|
-
set of values available in the javascript's execution context (it is wrapped in an
|
|
81
|
-
async function and passed those values). By default, that context comprises `preview`
|
|
82
|
-
(the `<div>` in which the example is rendered), `xinjs` (`* from xinjs`),
|
|
83
|
-
and `xinjsui` (`* from xinjsui`).
|
|
84
|
-
|
|
85
|
-
The `LiveExample` class provides the static `insertExamples(element: HTMLElement)`
|
|
86
|
-
function that will replace any sequence of
|
|
87
|
-
`pre code[class="language-html"],pre code[class="language-js"],pre code[class="language-css"]`
|
|
88
|
-
elements with a `<xin-example>` instance.
|
|
89
|
-
*/
|
|
90
|
-
import { Component, elements } from 'xinjs';
|
|
91
|
-
import { codeEditor, CodeEditor } from './code-editor';
|
|
92
|
-
import { tabSelector } from './tab-selector';
|
|
93
|
-
import { icons } from './icons';
|
|
94
|
-
import { popMenu } from './menu';
|
|
95
|
-
const { div, xinSlot, style, button, h4, pre } = elements;
|
|
96
|
-
const AsyncFunction = (async () => {
|
|
97
|
-
/* do not care */
|
|
98
|
-
}).constructor;
|
|
99
|
-
export class LiveExample extends Component {
|
|
100
|
-
persistToDom = false;
|
|
101
|
-
prettier = false;
|
|
102
|
-
prefix = 'lx';
|
|
103
|
-
storageKey = 'live-example-payload';
|
|
104
|
-
context = {};
|
|
105
|
-
uuid = crypto.randomUUID();
|
|
106
|
-
remoteId = '';
|
|
107
|
-
// FIXME workarounds for StorageEvent issue on Quest
|
|
108
|
-
lastUpdate = 0;
|
|
109
|
-
interval;
|
|
110
|
-
static insertExamples(element, context = {}) {
|
|
111
|
-
const sources = [
|
|
112
|
-
...element.querySelectorAll('.language-html,.language-js,.language-css'),
|
|
113
|
-
]
|
|
114
|
-
.filter((element) => !element.closest(LiveExample.tagName))
|
|
115
|
-
.map((code) => ({
|
|
116
|
-
block: code.parentElement,
|
|
117
|
-
language: code.classList[0].split('-').pop(),
|
|
118
|
-
code: code.innerText,
|
|
119
|
-
}));
|
|
120
|
-
for (let index = 0; index < sources.length; index += 1) {
|
|
121
|
-
const exampleSources = [sources[index]];
|
|
122
|
-
while (index < sources.length - 1 &&
|
|
123
|
-
sources[index].block.nextElementSibling === sources[index + 1].block) {
|
|
124
|
-
exampleSources.push(sources[index + 1]);
|
|
125
|
-
index += 1;
|
|
126
|
-
}
|
|
127
|
-
const example = liveExample({ context });
|
|
128
|
-
exampleSources[0].block.parentElement.insertBefore(example, exampleSources[0].block);
|
|
129
|
-
exampleSources.forEach((source) => {
|
|
130
|
-
switch (source.language) {
|
|
131
|
-
case 'js':
|
|
132
|
-
example.js = source.code;
|
|
133
|
-
break;
|
|
134
|
-
case 'html':
|
|
135
|
-
example.html = source.code;
|
|
136
|
-
break;
|
|
137
|
-
case 'css':
|
|
138
|
-
example.css = source.code;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
source.block.remove();
|
|
142
|
-
});
|
|
143
|
-
example.showDefaultTab();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
constructor() {
|
|
147
|
-
super();
|
|
148
|
-
this.initAttributes('persistToDom', 'prettier');
|
|
149
|
-
}
|
|
150
|
-
get activeTab() {
|
|
151
|
-
const { editors } = this.parts;
|
|
152
|
-
return [...editors.children].find((elt) => elt.getAttribute('hidden') === null);
|
|
153
|
-
}
|
|
154
|
-
getEditorValue(which) {
|
|
155
|
-
return this.parts[which].value;
|
|
156
|
-
}
|
|
157
|
-
setEditorValue(which, code) {
|
|
158
|
-
const codeEditor = this.parts[which];
|
|
159
|
-
codeEditor.value = code;
|
|
160
|
-
}
|
|
161
|
-
get css() {
|
|
162
|
-
return this.getEditorValue('css');
|
|
163
|
-
}
|
|
164
|
-
set css(code) {
|
|
165
|
-
this.setEditorValue('css', code);
|
|
166
|
-
}
|
|
167
|
-
get html() {
|
|
168
|
-
return this.getEditorValue('html');
|
|
169
|
-
}
|
|
170
|
-
set html(code) {
|
|
171
|
-
this.setEditorValue('html', code);
|
|
172
|
-
}
|
|
173
|
-
get js() {
|
|
174
|
-
return this.getEditorValue('js');
|
|
175
|
-
}
|
|
176
|
-
set js(code) {
|
|
177
|
-
this.setEditorValue('js', code);
|
|
178
|
-
}
|
|
179
|
-
updateUndo = () => {
|
|
180
|
-
const { activeTab } = this;
|
|
181
|
-
const { undo, redo } = this.parts;
|
|
182
|
-
if (activeTab instanceof CodeEditor && activeTab.editor !== undefined) {
|
|
183
|
-
const undoManager = activeTab.editor.session.getUndoManager();
|
|
184
|
-
undo.disabled = !undoManager.hasUndo();
|
|
185
|
-
redo.disabled = !undoManager.hasRedo();
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
undo.disabled = true;
|
|
189
|
-
redo.disabled = true;
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
undo = () => {
|
|
193
|
-
const { activeTab } = this;
|
|
194
|
-
if (activeTab instanceof CodeEditor) {
|
|
195
|
-
activeTab.editor.undo();
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
redo = () => {
|
|
199
|
-
const { activeTab } = this;
|
|
200
|
-
if (activeTab instanceof CodeEditor) {
|
|
201
|
-
activeTab.editor.redo();
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
get isMaximized() {
|
|
205
|
-
return this.classList.contains('-maximize');
|
|
206
|
-
}
|
|
207
|
-
flipLayout = () => {
|
|
208
|
-
this.classList.toggle('-vertical');
|
|
209
|
-
};
|
|
210
|
-
exampleMenu = () => {
|
|
211
|
-
popMenu({
|
|
212
|
-
target: this.parts.exampleWidgets,
|
|
213
|
-
width: 'auto',
|
|
214
|
-
menuItems: [
|
|
215
|
-
{
|
|
216
|
-
icon: 'edit2',
|
|
217
|
-
caption: 'view/edit code',
|
|
218
|
-
action: this.showCode,
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
icon: 'edit',
|
|
222
|
-
caption: 'view/edit code in a new window',
|
|
223
|
-
action: this.openEditorWindow,
|
|
224
|
-
},
|
|
225
|
-
null,
|
|
226
|
-
{
|
|
227
|
-
icon: this.isMaximized ? 'minimize' : 'maximize',
|
|
228
|
-
caption: this.isMaximized ? 'restore preview' : 'maximize preview',
|
|
229
|
-
action: this.toggleMaximize,
|
|
230
|
-
},
|
|
231
|
-
],
|
|
232
|
-
});
|
|
233
|
-
};
|
|
234
|
-
content = () => [
|
|
235
|
-
div({ part: 'example' }, style({ part: 'style' }), button({
|
|
236
|
-
title: 'example menu',
|
|
237
|
-
part: 'exampleWidgets',
|
|
238
|
-
onClick: this.exampleMenu,
|
|
239
|
-
}, icons.code())),
|
|
240
|
-
div({
|
|
241
|
-
class: 'code-editors',
|
|
242
|
-
part: 'codeEditors',
|
|
243
|
-
hidden: true,
|
|
244
|
-
}, h4('Code'), button({
|
|
245
|
-
title: 'close code',
|
|
246
|
-
class: 'transparent close-button',
|
|
247
|
-
onClick: this.closeCode,
|
|
248
|
-
}, icons.x()), tabSelector({
|
|
249
|
-
part: 'editors',
|
|
250
|
-
onChange: this.updateUndo,
|
|
251
|
-
}, codeEditor({
|
|
252
|
-
name: 'js',
|
|
253
|
-
mode: 'javascript',
|
|
254
|
-
part: 'js',
|
|
255
|
-
}), codeEditor({ name: 'html', mode: 'html', part: 'html' }), codeEditor({ name: 'css', mode: 'css', part: 'css' }), div({
|
|
256
|
-
slot: 'after-tabs',
|
|
257
|
-
class: 'row',
|
|
258
|
-
}, button({
|
|
259
|
-
title: 'undo',
|
|
260
|
-
part: 'undo',
|
|
261
|
-
class: 'transparent',
|
|
262
|
-
onClick: this.undo,
|
|
263
|
-
}, icons.cornerUpLeft()), button({
|
|
264
|
-
title: 'redo',
|
|
265
|
-
part: 'redo',
|
|
266
|
-
class: 'transparent',
|
|
267
|
-
onClick: this.redo,
|
|
268
|
-
}, icons.cornerUpRight()), button({
|
|
269
|
-
title: 'flip direction',
|
|
270
|
-
class: 'transparent',
|
|
271
|
-
onClick: this.flipLayout,
|
|
272
|
-
}, icons.columns({ class: 'layout-indicator' })), button({
|
|
273
|
-
title: 'copy as markdown',
|
|
274
|
-
class: 'transparent',
|
|
275
|
-
onClick: this.copy,
|
|
276
|
-
}, icons.copy()), button({
|
|
277
|
-
title: 'reload',
|
|
278
|
-
class: 'transparent',
|
|
279
|
-
onClick: this.refreshRemote,
|
|
280
|
-
}, icons.refreshCw())))),
|
|
281
|
-
xinSlot({ part: 'sources', hidden: true }),
|
|
282
|
-
];
|
|
283
|
-
connectedCallback() {
|
|
284
|
-
super.connectedCallback();
|
|
285
|
-
const { sources } = this.parts;
|
|
286
|
-
this.initFromElements([...sources.children]);
|
|
287
|
-
addEventListener('storage', this.remoteChange);
|
|
288
|
-
// FIXME workaround for Quest 3
|
|
289
|
-
this.interval = setInterval(this.remoteChange, 500);
|
|
290
|
-
this.undoInterval = setInterval(this.updateUndo, 250);
|
|
291
|
-
}
|
|
292
|
-
disconnectedCallback() {
|
|
293
|
-
super.disconnectedCallback();
|
|
294
|
-
const { storageKey, remoteKey } = this;
|
|
295
|
-
// FIXME workaround for Quest 3
|
|
296
|
-
clearInterval(this.interval);
|
|
297
|
-
clearInterval(this.undoInterval);
|
|
298
|
-
localStorage.setItem(storageKey, JSON.stringify({
|
|
299
|
-
remoteKey,
|
|
300
|
-
sentAt: Date.now(),
|
|
301
|
-
close: true,
|
|
302
|
-
}));
|
|
303
|
-
}
|
|
304
|
-
copy = () => {
|
|
305
|
-
const js = this.js !== '' ? '```js\n' + this.js.trim() + '\n```\n' : '';
|
|
306
|
-
const html = this.html !== '' ? '```html\n' + this.html.trim() + '\n```\n' : '';
|
|
307
|
-
const css = this.css !== '' ? '```css\n' + this.css.trim() + '\n```\n' : '';
|
|
308
|
-
navigator.clipboard.writeText(js + html + css);
|
|
309
|
-
};
|
|
310
|
-
toggleMaximize = () => {
|
|
311
|
-
this.classList.toggle('-maximize');
|
|
312
|
-
};
|
|
313
|
-
get remoteKey() {
|
|
314
|
-
return this.remoteId !== ''
|
|
315
|
-
? this.prefix + '-' + this.remoteId
|
|
316
|
-
: this.prefix + '-' + this.uuid;
|
|
317
|
-
}
|
|
318
|
-
remoteChange = (event) => {
|
|
319
|
-
const data = localStorage.getItem(this.storageKey);
|
|
320
|
-
if (event instanceof StorageEvent && event.key !== this.storageKey) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (data === null) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
const { remoteKey, sentAt, css, html, js, close } = JSON.parse(data);
|
|
327
|
-
// FIXME workaround for Quest
|
|
328
|
-
if (sentAt <= this.lastUpdate) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
if (remoteKey !== this.remoteKey) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
if (close === true) {
|
|
335
|
-
window.close();
|
|
336
|
-
}
|
|
337
|
-
console.log('received new code', sentAt, this.lastUpdate);
|
|
338
|
-
this.lastUpdate = sentAt;
|
|
339
|
-
this.css = css;
|
|
340
|
-
this.html = html;
|
|
341
|
-
this.js = js;
|
|
342
|
-
this.refresh();
|
|
343
|
-
};
|
|
344
|
-
showCode = () => {
|
|
345
|
-
this.classList.add('-maximize');
|
|
346
|
-
this.classList.toggle('-vertical', this.offsetHeight > this.offsetWidth);
|
|
347
|
-
this.parts.codeEditors.hidden = false;
|
|
348
|
-
};
|
|
349
|
-
closeCode = () => {
|
|
350
|
-
if (this.remoteId !== '') {
|
|
351
|
-
window.close();
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
this.classList.remove('-maximize');
|
|
355
|
-
this.parts.codeEditors.hidden = true;
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
openEditorWindow = () => {
|
|
359
|
-
const { storageKey, remoteKey, css, html, js, uuid, prefix } = this;
|
|
360
|
-
const href = location.href.split('?')[0] + `?${prefix}=${uuid}`;
|
|
361
|
-
localStorage.setItem(storageKey, JSON.stringify({
|
|
362
|
-
remoteKey,
|
|
363
|
-
sentAt: Date.now(),
|
|
364
|
-
css,
|
|
365
|
-
html,
|
|
366
|
-
js,
|
|
367
|
-
}));
|
|
368
|
-
window.open(href);
|
|
369
|
-
};
|
|
370
|
-
refreshRemote = () => {
|
|
371
|
-
const { remoteKey, css, html, js } = this;
|
|
372
|
-
localStorage.setItem(this.storageKey, JSON.stringify({ remoteKey, sentAt: Date.now(), css, html, js }));
|
|
373
|
-
};
|
|
374
|
-
updateSources = () => {
|
|
375
|
-
if (this.persistToDom) {
|
|
376
|
-
const { sources } = this.parts;
|
|
377
|
-
sources.innerText = '';
|
|
378
|
-
for (const language of ['js', 'css', 'html']) {
|
|
379
|
-
if (this[language]) {
|
|
380
|
-
sources.append(pre({ class: `language-${language}`, innerHTML: this[language] }));
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
/*
|
|
384
|
-
let sourceHTML = []
|
|
385
|
-
if (this.html)
|
|
386
|
-
sourceHTML.push(`<pre class="language-html">${this.html}</pre>`)
|
|
387
|
-
if (this.css)
|
|
388
|
-
sourceHTML.push(`<pre class="language-css">${this.css}</pre>`)
|
|
389
|
-
if (this.js) sourceHTML.push(`<pre class="language-js">${this.js}</pre>`)
|
|
390
|
-
sources.innerHTML = sourceHTML.join('\n')
|
|
391
|
-
*/
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
refresh = () => {
|
|
395
|
-
if (this.remoteId !== '') {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
const { example, style } = this.parts;
|
|
399
|
-
const preview = div({ class: 'preview' });
|
|
400
|
-
preview.innerHTML = this.html;
|
|
401
|
-
style.innerText = this.css;
|
|
402
|
-
const oldPreview = example.querySelector('.preview');
|
|
403
|
-
if (oldPreview) {
|
|
404
|
-
oldPreview.replaceWith(preview);
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
example.insertBefore(preview, this.parts.exampleWidgets);
|
|
408
|
-
}
|
|
409
|
-
const context = { preview, ...this.context };
|
|
410
|
-
try {
|
|
411
|
-
// @ts-expect-error ts is wrong and it makes me so mad
|
|
412
|
-
const func = new AsyncFunction(...Object.keys(context), this.js);
|
|
413
|
-
func(...Object.values(context)).catch((err) => console.error(err));
|
|
414
|
-
if (this.persistToDom) {
|
|
415
|
-
this.updateSources();
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
catch (e) {
|
|
419
|
-
console.error(e);
|
|
420
|
-
window.alert(`Error: ${e}, the console may have more information…`);
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
initFromElements(elements) {
|
|
424
|
-
for (const element of elements) {
|
|
425
|
-
element.hidden = true;
|
|
426
|
-
const [mode, ...lines] = element.innerHTML.split('\n');
|
|
427
|
-
if (['js', 'html', 'css'].includes(mode)) {
|
|
428
|
-
const minIndex = lines
|
|
429
|
-
.filter((line) => line.trim() !== '')
|
|
430
|
-
.map((line) => line.match(/^\s*/)[0].length)
|
|
431
|
-
.sort()[0];
|
|
432
|
-
const source = (minIndex > 0 ? lines.map((line) => line.substring(minIndex)) : lines).join('\n');
|
|
433
|
-
this.parts[mode].value = source;
|
|
434
|
-
}
|
|
435
|
-
else {
|
|
436
|
-
const language = ['js', 'html', 'css'].find((language) => element.matches(`.language-${language}`));
|
|
437
|
-
if (language) {
|
|
438
|
-
;
|
|
439
|
-
this.parts[language].value =
|
|
440
|
-
language === 'html' ? element.innerHTML : element.innerText;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
showDefaultTab() {
|
|
446
|
-
const { editors } = this.parts;
|
|
447
|
-
if (this.js !== '') {
|
|
448
|
-
editors.value = 0;
|
|
449
|
-
}
|
|
450
|
-
else if (this.html !== '') {
|
|
451
|
-
editors.value = 1;
|
|
452
|
-
}
|
|
453
|
-
else if (this.css !== '') {
|
|
454
|
-
editors.value = 2;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
render() {
|
|
458
|
-
super.render();
|
|
459
|
-
if (this.remoteId !== '') {
|
|
460
|
-
const data = localStorage.getItem(this.storageKey);
|
|
461
|
-
if (data !== null) {
|
|
462
|
-
const { remoteKey, sentAt, css, html, js } = JSON.parse(data);
|
|
463
|
-
if (this.remoteKey !== remoteKey) {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
this.lastUpdate = sentAt;
|
|
467
|
-
this.css = css;
|
|
468
|
-
this.html = html;
|
|
469
|
-
this.js = js;
|
|
470
|
-
this.parts.example.hidden = true;
|
|
471
|
-
this.parts.codeEditors.hidden = false;
|
|
472
|
-
this.classList.add('-maximize');
|
|
473
|
-
this.updateUndo();
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
this.refresh();
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
export const liveExample = LiveExample.elementCreator({
|
|
482
|
-
tag: 'xin-example',
|
|
483
|
-
styleSpec: {
|
|
484
|
-
':host': {
|
|
485
|
-
'--xin-example-height': '320px',
|
|
486
|
-
'--code-editors-bar-bg': '#777',
|
|
487
|
-
'--code-editors-bar-color': '#fff',
|
|
488
|
-
'--widget-bg': '#fff8',
|
|
489
|
-
'--widget-color': '#000',
|
|
490
|
-
position: 'relative',
|
|
491
|
-
display: 'flex',
|
|
492
|
-
height: 'var(--xin-example-height)',
|
|
493
|
-
background: 'var(--background)',
|
|
494
|
-
boxSizing: 'border-box',
|
|
495
|
-
},
|
|
496
|
-
':host.-maximize': {
|
|
497
|
-
position: 'fixed',
|
|
498
|
-
left: '0',
|
|
499
|
-
top: '0',
|
|
500
|
-
height: '100vh',
|
|
501
|
-
width: '100vw',
|
|
502
|
-
margin: '0 !important',
|
|
503
|
-
},
|
|
504
|
-
'.-maximize': {
|
|
505
|
-
zIndex: 101,
|
|
506
|
-
},
|
|
507
|
-
':host.-vertical': {
|
|
508
|
-
flexDirection: 'column',
|
|
509
|
-
},
|
|
510
|
-
':host .layout-indicator': {
|
|
511
|
-
transition: '0.5s ease-out',
|
|
512
|
-
transform: 'rotateZ(270deg)',
|
|
513
|
-
},
|
|
514
|
-
':host.-vertical .layout-indicator': {
|
|
515
|
-
transform: 'rotateZ(180deg)',
|
|
516
|
-
},
|
|
517
|
-
':host.-maximize .hide-if-maximized, :host:not(.-maximize) .show-if-maximized': {
|
|
518
|
-
display: 'none',
|
|
519
|
-
},
|
|
520
|
-
':host [part="example"]': {
|
|
521
|
-
flex: '1 1 50%',
|
|
522
|
-
height: '100%',
|
|
523
|
-
position: 'relative',
|
|
524
|
-
overflowX: 'auto',
|
|
525
|
-
},
|
|
526
|
-
':host .preview': {
|
|
527
|
-
height: '100%',
|
|
528
|
-
position: 'relative',
|
|
529
|
-
overflow: 'hidden',
|
|
530
|
-
boxShadow: 'inset 0 0 0 2px #8883',
|
|
531
|
-
},
|
|
532
|
-
':host [part="editors"]': {
|
|
533
|
-
flex: '1 1 200px',
|
|
534
|
-
height: '100%',
|
|
535
|
-
position: 'relative',
|
|
536
|
-
},
|
|
537
|
-
':host [part="exampleWidgets"]': {
|
|
538
|
-
position: 'absolute',
|
|
539
|
-
left: '5px',
|
|
540
|
-
bottom: '5px',
|
|
541
|
-
'--widget-color': 'var(--brand-color)',
|
|
542
|
-
borderRadius: '5px',
|
|
543
|
-
width: '44px',
|
|
544
|
-
height: '44px',
|
|
545
|
-
lineHeight: '44px',
|
|
546
|
-
zIndex: '100',
|
|
547
|
-
},
|
|
548
|
-
':host [part="exampleWidgets"] svg': {
|
|
549
|
-
stroke: 'var(--widget-color)',
|
|
550
|
-
},
|
|
551
|
-
':host .code-editors': {
|
|
552
|
-
overflow: 'hidden',
|
|
553
|
-
background: 'white',
|
|
554
|
-
position: 'relative',
|
|
555
|
-
top: '0',
|
|
556
|
-
right: '0',
|
|
557
|
-
flex: '1 1 50%',
|
|
558
|
-
height: '100%',
|
|
559
|
-
flexDirection: 'column',
|
|
560
|
-
zIndex: '10',
|
|
561
|
-
},
|
|
562
|
-
':host .code-editors:not([hidden])': {
|
|
563
|
-
display: 'flex',
|
|
564
|
-
},
|
|
565
|
-
':host .code-editors > h4': {
|
|
566
|
-
padding: '5px',
|
|
567
|
-
margin: '0',
|
|
568
|
-
textAlign: 'center',
|
|
569
|
-
background: 'var(--code-editors-bar-bg)',
|
|
570
|
-
color: 'var(--code-editors-bar-color)',
|
|
571
|
-
cursor: 'move',
|
|
572
|
-
},
|
|
573
|
-
':host .close-button': {
|
|
574
|
-
position: 'absolute',
|
|
575
|
-
top: '0',
|
|
576
|
-
right: '0',
|
|
577
|
-
color: 'var(--code-editors-bar-color)',
|
|
578
|
-
},
|
|
579
|
-
':host button.transparent, :host .sizer': {
|
|
580
|
-
width: '32px',
|
|
581
|
-
height: '32px',
|
|
582
|
-
lineHeight: '32px',
|
|
583
|
-
textAlign: 'center',
|
|
584
|
-
padding: '0',
|
|
585
|
-
margin: '0',
|
|
586
|
-
},
|
|
587
|
-
':host .sizer': {
|
|
588
|
-
cursor: 'nwse-resize',
|
|
589
|
-
},
|
|
590
|
-
},
|
|
591
|
-
});
|
|
592
|
-
export function makeExamplesLive(element) {
|
|
593
|
-
const preElements = [...element.querySelectorAll('pre')].filter((pre) => ['js', 'html', 'css', 'json'].includes(pre.innerText.split('\n')[0]));
|
|
594
|
-
for (let i = 0; i < preElements.length; i++) {
|
|
595
|
-
const parts = [preElements[i]];
|
|
596
|
-
while (preElements[i].nextElementSibling === preElements[i + 1]) {
|
|
597
|
-
parts.push(preElements[i + 1]);
|
|
598
|
-
i += 1;
|
|
599
|
-
}
|
|
600
|
-
const example = liveExample();
|
|
601
|
-
element.insertBefore(example, parts[0]);
|
|
602
|
-
example.initFromElements(parts);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
const params = new URL(window.location.href).searchParams;
|
|
606
|
-
const remoteId = params.get('lx');
|
|
607
|
-
if (remoteId) {
|
|
608
|
-
document.title += ' [code editor]';
|
|
609
|
-
document.body.textContent = '';
|
|
610
|
-
document.body.append(liveExample({ remoteId }));
|
|
611
|
-
}
|