@lvce-editor/component-state-worker 0.1.1 → 0.3.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/README.md +19 -0
- package/dist/componentStateWorkerMain.js +127 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,3 +5,22 @@ Inspect and edit live LVCE Editor component state as JSON.
|
|
|
5
5
|
The worker provides the component-state grid view and the
|
|
6
6
|
`live-component-state:///<uid>.json` filesystem implementation used by LVCE
|
|
7
7
|
Editor.
|
|
8
|
+
|
|
9
|
+
## Development
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm ci
|
|
13
|
+
npm run dev
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Open `http://localhost:3000`, then run `Developer: Open Component State` from
|
|
17
|
+
the command palette. Select an editable component to open its live state as a
|
|
18
|
+
JSON file. Saving that file applies the new state to the running component.
|
|
19
|
+
|
|
20
|
+
Run the browser tests headlessly with:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm run build
|
|
24
|
+
npm run build:static
|
|
25
|
+
npm run e2e:headless
|
|
26
|
+
```
|
|
@@ -54,6 +54,49 @@ class VError extends Error {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
class AssertionError extends Error {
|
|
58
|
+
constructor(message) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = 'AssertionError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const Object$1 = 1;
|
|
64
|
+
const Number$1 = 2;
|
|
65
|
+
const Array$1 = 3;
|
|
66
|
+
const String$1 = 4;
|
|
67
|
+
const Boolean = 5;
|
|
68
|
+
const Function = 6;
|
|
69
|
+
const Null = 7;
|
|
70
|
+
const Unknown = 8;
|
|
71
|
+
const getType = value => {
|
|
72
|
+
switch (typeof value) {
|
|
73
|
+
case 'number':
|
|
74
|
+
return Number$1;
|
|
75
|
+
case 'function':
|
|
76
|
+
return Function;
|
|
77
|
+
case 'string':
|
|
78
|
+
return String$1;
|
|
79
|
+
case 'object':
|
|
80
|
+
if (value === null) {
|
|
81
|
+
return Null;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
return Array$1;
|
|
85
|
+
}
|
|
86
|
+
return Object$1;
|
|
87
|
+
case 'boolean':
|
|
88
|
+
return Boolean;
|
|
89
|
+
default:
|
|
90
|
+
return Unknown;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const object = value => {
|
|
94
|
+
const type = getType(value);
|
|
95
|
+
if (type !== Object$1) {
|
|
96
|
+
throw new AssertionError('expected value to be of type object');
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
57
100
|
const isMessagePort = value => {
|
|
58
101
|
return value && value instanceof MessagePort;
|
|
59
102
|
};
|
|
@@ -967,6 +1010,9 @@ const {
|
|
|
967
1010
|
invoke,
|
|
968
1011
|
set: set$1
|
|
969
1012
|
} = create$2(RendererWorker);
|
|
1013
|
+
const getComponents = async () => {
|
|
1014
|
+
return invoke('ComponentState.getComponents');
|
|
1015
|
+
};
|
|
970
1016
|
|
|
971
1017
|
const toCommandId = key => {
|
|
972
1018
|
const dotIndex = key.indexOf('.');
|
|
@@ -1249,12 +1295,20 @@ const create = (uid, x, y, width, height) => {
|
|
|
1249
1295
|
set(uid, state, state);
|
|
1250
1296
|
};
|
|
1251
1297
|
|
|
1298
|
+
const cardGap = 8;
|
|
1299
|
+
const cardMinWidth = 180;
|
|
1300
|
+
const viewHorizontalPadding = 32;
|
|
1301
|
+
const getColumnCount = width => {
|
|
1302
|
+
const availableWidth = Math.max(0, width - viewHorizontalPadding);
|
|
1303
|
+
return Math.max(1, Math.floor((availableWidth + cardGap) / (cardMinWidth + cardGap)));
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1252
1306
|
const diff2 = uid => {
|
|
1253
1307
|
const {
|
|
1254
1308
|
oldState,
|
|
1255
1309
|
scheduledState
|
|
1256
1310
|
} = get(uid);
|
|
1257
|
-
return oldState.components === scheduledState.components && oldState.loaded === scheduledState.loaded ? [] : [1];
|
|
1311
|
+
return oldState.components === scheduledState.components && oldState.loaded === scheduledState.loaded && getColumnCount(oldState.width) === getColumnCount(scheduledState.width) ? [] : [1];
|
|
1258
1312
|
};
|
|
1259
1313
|
|
|
1260
1314
|
const pattern = /^live-component-state:\/\/\/(\d+)\.json$/;
|
|
@@ -1267,11 +1321,6 @@ const getUid = uri => {
|
|
|
1267
1321
|
};
|
|
1268
1322
|
const toUri = uid => `live-component-state:///${uid}.json`;
|
|
1269
1323
|
|
|
1270
|
-
const assertObject = value => {
|
|
1271
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1272
|
-
throw new TypeError('Component state must be a JSON object');
|
|
1273
|
-
}
|
|
1274
|
-
};
|
|
1275
1324
|
const readFile = async uri => {
|
|
1276
1325
|
const uid = getUid(uri);
|
|
1277
1326
|
const state = await invoke('ComponentState.getState', uid);
|
|
@@ -1280,11 +1329,11 @@ const readFile = async uri => {
|
|
|
1280
1329
|
const writeFile = async (uri, content) => {
|
|
1281
1330
|
const uid = getUid(uri);
|
|
1282
1331
|
const state = JSON.parse(content);
|
|
1283
|
-
|
|
1332
|
+
object(state);
|
|
1284
1333
|
await invoke('ComponentState.setState', uid, state);
|
|
1285
1334
|
};
|
|
1286
1335
|
const readDirWithFileTypes = async () => {
|
|
1287
|
-
const components = await
|
|
1336
|
+
const components = await getComponents();
|
|
1288
1337
|
return components.filter(component => component.editable).map(component => ({
|
|
1289
1338
|
name: `${component.uid}.json`,
|
|
1290
1339
|
type: File
|
|
@@ -1293,7 +1342,7 @@ const readDirWithFileTypes = async () => {
|
|
|
1293
1342
|
const isReadonly = () => false;
|
|
1294
1343
|
const exists = async uri => {
|
|
1295
1344
|
const uid = getUid(uri);
|
|
1296
|
-
const components = await
|
|
1345
|
+
const components = await getComponents();
|
|
1297
1346
|
return components.some(component => component.uid === uid && component.editable);
|
|
1298
1347
|
};
|
|
1299
1348
|
|
|
@@ -1303,7 +1352,7 @@ const handleClick = async (state, uid) => {
|
|
|
1303
1352
|
};
|
|
1304
1353
|
|
|
1305
1354
|
const loadContent = async state => {
|
|
1306
|
-
const components = await
|
|
1355
|
+
const components = await getComponents();
|
|
1307
1356
|
return {
|
|
1308
1357
|
...state,
|
|
1309
1358
|
components,
|
|
@@ -1319,48 +1368,81 @@ const text = data => {
|
|
|
1319
1368
|
};
|
|
1320
1369
|
};
|
|
1321
1370
|
|
|
1371
|
+
const Card = 'ComponentStateCard';
|
|
1372
|
+
const CardStatus = 'ComponentStateCardStatus';
|
|
1373
|
+
const CardTitle = 'ComponentStateCardTitle';
|
|
1374
|
+
const CardUid = 'ComponentStateCardUid';
|
|
1375
|
+
const Description = 'ComponentStateDescription';
|
|
1376
|
+
const Heading = 'ComponentStateHeading';
|
|
1377
|
+
const Row = 'ComponentStateRow';
|
|
1378
|
+
const Rows = 'ComponentStateRows';
|
|
1379
|
+
const View = 'ComponentStateView';
|
|
1380
|
+
|
|
1381
|
+
const HandleClick = 1;
|
|
1382
|
+
|
|
1383
|
+
const titleNode = {
|
|
1384
|
+
childCount: 1,
|
|
1385
|
+
className: CardTitle,
|
|
1386
|
+
type: Strong
|
|
1387
|
+
};
|
|
1388
|
+
const uidNode = {
|
|
1389
|
+
childCount: 1,
|
|
1390
|
+
className: CardUid,
|
|
1391
|
+
type: Span
|
|
1392
|
+
};
|
|
1393
|
+
const statusNode = {
|
|
1394
|
+
childCount: 1,
|
|
1395
|
+
className: CardStatus,
|
|
1396
|
+
type: Span
|
|
1397
|
+
};
|
|
1322
1398
|
const getCard = component => {
|
|
1323
1399
|
const status = component.editable ? 'Open JSON state' : 'State API unavailable';
|
|
1324
1400
|
return [{
|
|
1325
1401
|
childCount: 3,
|
|
1326
|
-
className:
|
|
1402
|
+
className: Card,
|
|
1327
1403
|
'data-uid': String(component.uid),
|
|
1328
1404
|
disabled: !component.editable,
|
|
1329
|
-
onClick:
|
|
1405
|
+
onClick: HandleClick,
|
|
1330
1406
|
type: Button
|
|
1331
|
-
}, {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1407
|
+
}, titleNode, text(component.moduleId), uidNode, text(`uid ${component.uid}`), statusNode, text(status)];
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
const viewNode = {
|
|
1411
|
+
childCount: 3,
|
|
1412
|
+
className: View,
|
|
1413
|
+
type: Div
|
|
1414
|
+
};
|
|
1415
|
+
const headingNode = {
|
|
1416
|
+
childCount: 1,
|
|
1417
|
+
className: Heading,
|
|
1418
|
+
type: H2
|
|
1419
|
+
};
|
|
1420
|
+
const descriptionNode = {
|
|
1421
|
+
childCount: 1,
|
|
1422
|
+
className: Description,
|
|
1423
|
+
type: Div
|
|
1424
|
+
};
|
|
1425
|
+
const getRows = (components, columnCount) => {
|
|
1426
|
+
const rows = [];
|
|
1427
|
+
for (let index = 0; index < components.length; index += columnCount) {
|
|
1428
|
+
const row = components.slice(index, index + columnCount);
|
|
1429
|
+
rows.push({
|
|
1430
|
+
childCount: row.length,
|
|
1431
|
+
className: Row,
|
|
1432
|
+
type: Div
|
|
1433
|
+
}, ...row.flatMap(getCard));
|
|
1434
|
+
}
|
|
1435
|
+
return rows;
|
|
1436
|
+
};
|
|
1437
|
+
const getComponentStateVirtualDom = (components, loaded, width) => {
|
|
1346
1438
|
const description = loaded ? `${components.length} live components` : 'Loading live components…';
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
childCount: 1,
|
|
1353
|
-
className: 'ComponentStateHeading',
|
|
1354
|
-
type: H2
|
|
1355
|
-
}, text('Live Component State'), {
|
|
1356
|
-
childCount: 1,
|
|
1357
|
-
className: 'ComponentStateDescription',
|
|
1358
|
-
type: Div
|
|
1359
|
-
}, text(description), {
|
|
1360
|
-
childCount: components.length,
|
|
1361
|
-
className: 'ComponentStateGrid',
|
|
1439
|
+
const columnCount = getColumnCount(width);
|
|
1440
|
+
const rowCount = Math.ceil(components.length / columnCount);
|
|
1441
|
+
return [viewNode, headingNode, text('Live Component State'), descriptionNode, text(description), {
|
|
1442
|
+
childCount: rowCount,
|
|
1443
|
+
className: Rows,
|
|
1362
1444
|
type: Div
|
|
1363
|
-
}, ...components
|
|
1445
|
+
}, ...getRows(components, columnCount)];
|
|
1364
1446
|
};
|
|
1365
1447
|
|
|
1366
1448
|
const render2 = (uid, diffResult) => {
|
|
@@ -1371,11 +1453,11 @@ const render2 = (uid, diffResult) => {
|
|
|
1371
1453
|
if (diffResult.length === 0) {
|
|
1372
1454
|
return [];
|
|
1373
1455
|
}
|
|
1374
|
-
return [[SetDom2, uid, getComponentStateVirtualDom(newState.components, newState.loaded)]];
|
|
1456
|
+
return [[SetDom2, uid, getComponentStateVirtualDom(newState.components, newState.loaded, newState.width)]];
|
|
1375
1457
|
};
|
|
1376
1458
|
|
|
1377
1459
|
const renderEventListeners = () => [{
|
|
1378
|
-
name:
|
|
1460
|
+
name: HandleClick,
|
|
1379
1461
|
params: ['handleClick', 'event.currentTarget.dataset.uid'],
|
|
1380
1462
|
preventDefault: true
|
|
1381
1463
|
}];
|