@westopp/windo 0.1.0 → 0.1.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 +5 -2
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -17
- package/dist/index.d.ts +64 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/cli/index.ts +1 -1
- package/src/client/App.tsx +82 -3
- package/src/client/Canvas.tsx +8 -3
- package/src/client/Inspector.tsx +37 -0
- package/src/client/Sidebar.tsx +13 -3
- package/src/client/TagFilter.tsx +125 -0
- package/src/client/bridge.ts +24 -0
- package/src/client/chrome.css +317 -52
- package/src/client/internal-types.ts +24 -0
- package/src/define-config.ts +12 -8
- package/src/index.ts +2 -0
- package/src/preview/ctx.ts +8 -1
- package/src/preview/index.ts +155 -10
- package/src/preview/render.tsx +5 -3
- package/src/protocol.ts +6 -0
- package/src/types.ts +43 -12
- package/src/descriptor.test.ts +0 -59
package/src/client/chrome.css
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
--accent-text: #ffffff;
|
|
22
22
|
--accent-soft: color-mix(in srgb, var(--accent) 8%, transparent);
|
|
23
23
|
--danger: #c0443c;
|
|
24
|
+
--success: #3c7a4a;
|
|
25
|
+
--warn: #99661c;
|
|
26
|
+
--deprecated: #a8433a;
|
|
24
27
|
--surface: #ffffff;
|
|
25
28
|
--shadow: 0 1px 2px rgba(16, 16, 18, 0.04), 0 8px 24px rgba(16, 16, 18, 0.06);
|
|
26
29
|
--mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
@@ -41,6 +44,10 @@
|
|
|
41
44
|
--accent-ui: color-mix(in oklab, var(--accent) 35%, white);
|
|
42
45
|
--accent-soft: color-mix(in srgb, var(--accent-ui) 14%, transparent);
|
|
43
46
|
--danger: #e0837b;
|
|
47
|
+
--success: #84c896;
|
|
48
|
+
--warn: #dcb064;
|
|
49
|
+
--deprecated: #e6918a;
|
|
50
|
+
--accent-contrast: #111113;
|
|
44
51
|
--surface: #161618;
|
|
45
52
|
--shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 10px 32px rgba(0, 0, 0, 0.45);
|
|
46
53
|
}
|
|
@@ -138,13 +145,8 @@ button {
|
|
|
138
145
|
.wb-logo-mark {
|
|
139
146
|
width: 22px;
|
|
140
147
|
height: 22px;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
color: var(--panel);
|
|
144
|
-
display: grid;
|
|
145
|
-
place-items: center;
|
|
146
|
-
font-size: 10.5px;
|
|
147
|
-
font-weight: 700;
|
|
148
|
+
flex-shrink: 0;
|
|
149
|
+
display: block;
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
.wb-logo-sub {
|
|
@@ -289,6 +291,251 @@ button {
|
|
|
289
291
|
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
290
292
|
}
|
|
291
293
|
|
|
294
|
+
/* ---------- Tag filter ---------- */
|
|
295
|
+
|
|
296
|
+
.wb-tagfilter {
|
|
297
|
+
position: relative;
|
|
298
|
+
margin: 0 12px 2px 12px;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.wb-tagfilter-control {
|
|
302
|
+
display: flex;
|
|
303
|
+
align-items: center;
|
|
304
|
+
gap: 5px;
|
|
305
|
+
width: 100%;
|
|
306
|
+
min-height: 32px;
|
|
307
|
+
padding: 4px 8px 4px 10px;
|
|
308
|
+
border: 1px solid var(--border);
|
|
309
|
+
border-radius: var(--r);
|
|
310
|
+
background: var(--panel2);
|
|
311
|
+
transition:
|
|
312
|
+
border-color 0.12s,
|
|
313
|
+
box-shadow 0.12s;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.wb-tagfilter-control:hover {
|
|
317
|
+
border-color: var(--border-strong);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.wb-tagfilter-control.open {
|
|
321
|
+
border-color: var(--border-strong);
|
|
322
|
+
box-shadow: 0 0 0 3px var(--accent-soft);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.wb-tagfilter-toggle {
|
|
326
|
+
flex: 1;
|
|
327
|
+
display: flex;
|
|
328
|
+
align-items: center;
|
|
329
|
+
justify-content: space-between;
|
|
330
|
+
gap: 6px;
|
|
331
|
+
min-width: 0;
|
|
332
|
+
align-self: stretch;
|
|
333
|
+
border: none;
|
|
334
|
+
background: transparent;
|
|
335
|
+
color: var(--text);
|
|
336
|
+
font: inherit;
|
|
337
|
+
font-size: 12.5px;
|
|
338
|
+
text-align: left;
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.wb-tagfilter-placeholder {
|
|
343
|
+
flex: 1;
|
|
344
|
+
color: var(--faint);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.wb-tagfilter-pills {
|
|
348
|
+
flex: 1 1 auto;
|
|
349
|
+
min-width: 0;
|
|
350
|
+
display: flex;
|
|
351
|
+
flex-wrap: wrap;
|
|
352
|
+
gap: 5px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.wb-tagfilter-chev {
|
|
356
|
+
flex-shrink: 0;
|
|
357
|
+
display: inline-flex;
|
|
358
|
+
align-items: center;
|
|
359
|
+
justify-content: center;
|
|
360
|
+
align-self: stretch;
|
|
361
|
+
padding: 0 2px;
|
|
362
|
+
border: none;
|
|
363
|
+
background: transparent;
|
|
364
|
+
color: var(--faint);
|
|
365
|
+
cursor: pointer;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.wb-tag-pill {
|
|
369
|
+
display: inline-flex;
|
|
370
|
+
align-items: center;
|
|
371
|
+
gap: 4px;
|
|
372
|
+
padding: 3px 4px 3px 9px;
|
|
373
|
+
border-radius: 999px;
|
|
374
|
+
background: var(--accent);
|
|
375
|
+
color: var(--accent-text);
|
|
376
|
+
font-size: 11.5px;
|
|
377
|
+
font-weight: 500;
|
|
378
|
+
line-height: 1;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
[data-theme="dark"] .wb-tag-pill {
|
|
382
|
+
background: var(--accent-ui);
|
|
383
|
+
color: var(--accent-contrast);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.wb-tag-pill .x {
|
|
387
|
+
display: inline-flex;
|
|
388
|
+
align-items: center;
|
|
389
|
+
justify-content: center;
|
|
390
|
+
width: 15px;
|
|
391
|
+
height: 15px;
|
|
392
|
+
padding: 0;
|
|
393
|
+
border: none;
|
|
394
|
+
border-radius: 50%;
|
|
395
|
+
background: transparent;
|
|
396
|
+
color: inherit;
|
|
397
|
+
font: inherit;
|
|
398
|
+
font-size: 13px;
|
|
399
|
+
line-height: 1;
|
|
400
|
+
opacity: 0.6;
|
|
401
|
+
cursor: pointer;
|
|
402
|
+
transition:
|
|
403
|
+
opacity 0.1s,
|
|
404
|
+
background 0.1s;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.wb-tag-pill .x:hover {
|
|
408
|
+
opacity: 1;
|
|
409
|
+
background: color-mix(in srgb, currentColor 22%, transparent);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.wb-tagfilter-control .chev {
|
|
413
|
+
flex-shrink: 0;
|
|
414
|
+
color: var(--faint);
|
|
415
|
+
transition: transform 0.15s;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.wb-tagfilter-control.open .chev {
|
|
419
|
+
transform: rotate(180deg);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.wb-tagfilter-menu {
|
|
423
|
+
position: absolute;
|
|
424
|
+
z-index: 20;
|
|
425
|
+
top: calc(100% + 4px);
|
|
426
|
+
left: 0;
|
|
427
|
+
right: 0;
|
|
428
|
+
padding: 5px;
|
|
429
|
+
border: 1px solid var(--border);
|
|
430
|
+
border-radius: var(--r);
|
|
431
|
+
background: var(--panel);
|
|
432
|
+
box-shadow: var(--shadow);
|
|
433
|
+
max-height: 280px;
|
|
434
|
+
overflow-y: auto;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.wb-tag-option {
|
|
438
|
+
display: flex;
|
|
439
|
+
align-items: center;
|
|
440
|
+
gap: 9px;
|
|
441
|
+
width: 100%;
|
|
442
|
+
padding: 7px 8px;
|
|
443
|
+
border: none;
|
|
444
|
+
border-radius: var(--r);
|
|
445
|
+
background: transparent;
|
|
446
|
+
color: var(--text);
|
|
447
|
+
font: inherit;
|
|
448
|
+
font-size: 13px;
|
|
449
|
+
text-align: left;
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
transition: background 0.1s;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.wb-tag-option:hover {
|
|
455
|
+
background: var(--inset);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.wb-tag-option .lbl {
|
|
459
|
+
flex: 1;
|
|
460
|
+
overflow: hidden;
|
|
461
|
+
text-overflow: ellipsis;
|
|
462
|
+
white-space: nowrap;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.wb-check {
|
|
466
|
+
display: inline-flex;
|
|
467
|
+
align-items: center;
|
|
468
|
+
justify-content: center;
|
|
469
|
+
width: 17px;
|
|
470
|
+
height: 17px;
|
|
471
|
+
flex-shrink: 0;
|
|
472
|
+
border: 1.5px solid var(--border-strong);
|
|
473
|
+
border-radius: 5px;
|
|
474
|
+
background: var(--panel2);
|
|
475
|
+
color: var(--accent-text);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.wb-check.checked {
|
|
479
|
+
background: var(--accent);
|
|
480
|
+
border-color: var(--accent);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
[data-theme="dark"] .wb-check.checked {
|
|
484
|
+
background: var(--accent-ui);
|
|
485
|
+
border-color: var(--accent-ui);
|
|
486
|
+
color: var(--accent-contrast);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.wb-tag-divider {
|
|
490
|
+
height: 1px;
|
|
491
|
+
margin: 5px 4px;
|
|
492
|
+
background: var(--border);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.wb-tagmatch {
|
|
496
|
+
display: flex;
|
|
497
|
+
align-items: center;
|
|
498
|
+
gap: 10px;
|
|
499
|
+
margin: 8px 2px 0 2px;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.wb-tagmatch-label {
|
|
503
|
+
font-size: 10.5px;
|
|
504
|
+
font-weight: 600;
|
|
505
|
+
letter-spacing: 0.07em;
|
|
506
|
+
text-transform: uppercase;
|
|
507
|
+
color: var(--faint);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.wb-tagmatch-seg {
|
|
511
|
+
display: inline-flex;
|
|
512
|
+
padding: 2px;
|
|
513
|
+
border-radius: 999px;
|
|
514
|
+
background: var(--inset);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.wb-tagmatch-seg button {
|
|
518
|
+
border: none;
|
|
519
|
+
background: transparent;
|
|
520
|
+
color: var(--muted);
|
|
521
|
+
font: inherit;
|
|
522
|
+
font-size: 12px;
|
|
523
|
+
font-weight: 500;
|
|
524
|
+
padding: 4px 14px;
|
|
525
|
+
border-radius: 999px;
|
|
526
|
+
cursor: pointer;
|
|
527
|
+
transition:
|
|
528
|
+
background 0.12s,
|
|
529
|
+
color 0.12s,
|
|
530
|
+
box-shadow 0.12s;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.wb-tagmatch-seg button.on {
|
|
534
|
+
background: var(--panel);
|
|
535
|
+
color: var(--text);
|
|
536
|
+
box-shadow: 0 1px 2px rgba(16, 16, 18, 0.08);
|
|
537
|
+
}
|
|
538
|
+
|
|
292
539
|
.wb-nav {
|
|
293
540
|
flex: 1;
|
|
294
541
|
overflow-y: auto;
|
|
@@ -402,29 +649,16 @@ button {
|
|
|
402
649
|
}
|
|
403
650
|
|
|
404
651
|
.wb-status.stable {
|
|
405
|
-
color:
|
|
406
|
-
background:
|
|
652
|
+
color: var(--success);
|
|
653
|
+
background: color-mix(in srgb, var(--success) 10%, transparent);
|
|
407
654
|
}
|
|
408
655
|
.wb-status.beta {
|
|
409
|
-
color:
|
|
410
|
-
background:
|
|
656
|
+
color: var(--warn);
|
|
657
|
+
background: color-mix(in srgb, var(--warn) 10%, transparent);
|
|
411
658
|
}
|
|
412
659
|
.wb-status.deprecated {
|
|
413
|
-
color:
|
|
414
|
-
background:
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
[data-theme="dark"] .wb-status.stable {
|
|
418
|
-
color: #84c896;
|
|
419
|
-
background: rgba(132, 200, 150, 0.12);
|
|
420
|
-
}
|
|
421
|
-
[data-theme="dark"] .wb-status.beta {
|
|
422
|
-
color: #dcb064;
|
|
423
|
-
background: rgba(220, 176, 100, 0.12);
|
|
424
|
-
}
|
|
425
|
-
[data-theme="dark"] .wb-status.deprecated {
|
|
426
|
-
color: #e6918a;
|
|
427
|
-
background: rgba(230, 145, 138, 0.12);
|
|
660
|
+
color: var(--deprecated);
|
|
661
|
+
background: color-mix(in srgb, var(--deprecated) 10%, transparent);
|
|
428
662
|
}
|
|
429
663
|
|
|
430
664
|
.wb-nav-empty {
|
|
@@ -528,7 +762,7 @@ button {
|
|
|
528
762
|
[data-theme="dark"] .wb-trigger.on {
|
|
529
763
|
background: var(--accent-ui);
|
|
530
764
|
border-color: var(--accent-ui);
|
|
531
|
-
color:
|
|
765
|
+
color: var(--accent-contrast);
|
|
532
766
|
}
|
|
533
767
|
|
|
534
768
|
.wb-trigger .tdot {
|
|
@@ -1002,6 +1236,45 @@ button {
|
|
|
1002
1236
|
font-weight: 600;
|
|
1003
1237
|
}
|
|
1004
1238
|
|
|
1239
|
+
/* Editable shared-state strip (ctx.ctxState) — same look as .wb-state, with inline editors */
|
|
1240
|
+
|
|
1241
|
+
.wb-ctxstate {
|
|
1242
|
+
display: flex;
|
|
1243
|
+
align-items: center;
|
|
1244
|
+
gap: 12px;
|
|
1245
|
+
flex-wrap: wrap;
|
|
1246
|
+
padding: 7px 16px;
|
|
1247
|
+
border-bottom: 1px solid var(--border);
|
|
1248
|
+
background: var(--inset);
|
|
1249
|
+
font-size: 11.5px;
|
|
1250
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
1251
|
+
flex-shrink: 0;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.wb-ctxstate .wb-state-item {
|
|
1255
|
+
gap: 6px;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
.wb-ctxstate-input {
|
|
1259
|
+
width: 90px;
|
|
1260
|
+
padding: 1px 6px;
|
|
1261
|
+
border: 1px solid var(--border);
|
|
1262
|
+
border-radius: 5px;
|
|
1263
|
+
background: var(--bg);
|
|
1264
|
+
color: var(--text);
|
|
1265
|
+
font: inherit;
|
|
1266
|
+
font-weight: 600;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.wb-ctxstate-input[type='number'] {
|
|
1270
|
+
width: 60px;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.wb-ctxstate-input:focus {
|
|
1274
|
+
outline: none;
|
|
1275
|
+
border-color: var(--accent-ui);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1005
1278
|
.wb-tab {
|
|
1006
1279
|
height: 100%;
|
|
1007
1280
|
padding: 0 1px;
|
|
@@ -1119,7 +1392,7 @@ button {
|
|
|
1119
1392
|
[data-theme="dark"] .wb-save {
|
|
1120
1393
|
background: var(--accent-ui);
|
|
1121
1394
|
border-color: var(--accent-ui);
|
|
1122
|
-
color:
|
|
1395
|
+
color: var(--accent-contrast);
|
|
1123
1396
|
}
|
|
1124
1397
|
|
|
1125
1398
|
.wb-save:disabled {
|
|
@@ -1161,8 +1434,8 @@ button {
|
|
|
1161
1434
|
font-size: 10.5px;
|
|
1162
1435
|
line-height: 1.6;
|
|
1163
1436
|
color: var(--danger);
|
|
1164
|
-
background:
|
|
1165
|
-
border: 1px solid
|
|
1437
|
+
background: color-mix(in srgb, var(--danger) 7%, transparent);
|
|
1438
|
+
border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
|
|
1166
1439
|
border-radius: var(--r);
|
|
1167
1440
|
padding: 8px 10px;
|
|
1168
1441
|
white-space: pre-wrap;
|
|
@@ -1171,11 +1444,7 @@ button {
|
|
|
1171
1444
|
.wb-saved-flash {
|
|
1172
1445
|
font-size: 11.5px;
|
|
1173
1446
|
font-weight: 550;
|
|
1174
|
-
color:
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
[data-theme="dark"] .wb-saved-flash {
|
|
1178
|
-
color: #84c896;
|
|
1447
|
+
color: var(--success);
|
|
1179
1448
|
}
|
|
1180
1449
|
|
|
1181
1450
|
.wb-schema {
|
|
@@ -1392,11 +1661,7 @@ button {
|
|
|
1392
1661
|
color: var(--text);
|
|
1393
1662
|
}
|
|
1394
1663
|
.wb-copy.copied {
|
|
1395
|
-
color:
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
[data-theme="dark"] .wb-copy.copied {
|
|
1399
|
-
color: #84c896;
|
|
1664
|
+
color: var(--success);
|
|
1400
1665
|
}
|
|
1401
1666
|
|
|
1402
1667
|
/* ---------- Variants gallery ---------- */
|
|
@@ -1645,6 +1910,10 @@ select.wb-ctrl-input {
|
|
|
1645
1910
|
background-position: right 8px center;
|
|
1646
1911
|
}
|
|
1647
1912
|
|
|
1913
|
+
[data-theme="dark"] select.wb-ctrl-input {
|
|
1914
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239b9ba2' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1648
1917
|
.wb-ctrl-row input[type="range"] {
|
|
1649
1918
|
flex: 1;
|
|
1650
1919
|
accent-color: var(--accent-ui);
|
|
@@ -1695,7 +1964,7 @@ select.wb-ctrl-input {
|
|
|
1695
1964
|
}
|
|
1696
1965
|
|
|
1697
1966
|
[data-theme="dark"] .wb-switch.on::after {
|
|
1698
|
-
background:
|
|
1967
|
+
background: var(--accent-contrast);
|
|
1699
1968
|
}
|
|
1700
1969
|
|
|
1701
1970
|
.wb-context-empty {
|
|
@@ -1810,21 +2079,17 @@ select.wb-ctrl-input {
|
|
|
1810
2079
|
color: var(--accent-ui);
|
|
1811
2080
|
}
|
|
1812
2081
|
.wb-log.warn .llevel {
|
|
1813
|
-
color:
|
|
2082
|
+
color: var(--warn);
|
|
1814
2083
|
}
|
|
1815
2084
|
.wb-log.error .llevel {
|
|
1816
2085
|
color: var(--danger);
|
|
1817
2086
|
}
|
|
1818
2087
|
|
|
1819
|
-
[data-theme="dark"] .wb-log.warn .llevel {
|
|
1820
|
-
color: #dcb064;
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
2088
|
.wb-log.warn {
|
|
1824
|
-
background:
|
|
2089
|
+
background: color-mix(in srgb, var(--warn) 5%, transparent);
|
|
1825
2090
|
}
|
|
1826
2091
|
.wb-log.error {
|
|
1827
|
-
background:
|
|
2092
|
+
background: color-mix(in srgb, var(--danger) 5%, transparent);
|
|
1828
2093
|
}
|
|
1829
2094
|
|
|
1830
2095
|
.wb-log .lmsg {
|
|
@@ -1858,8 +2123,8 @@ select.wb-ctrl-input {
|
|
|
1858
2123
|
margin: 14px 16px;
|
|
1859
2124
|
padding: 12px 14px;
|
|
1860
2125
|
border-radius: 10px;
|
|
1861
|
-
background:
|
|
1862
|
-
border: 1px solid
|
|
2126
|
+
background: color-mix(in srgb, var(--danger) 7%, transparent);
|
|
2127
|
+
border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
|
|
1863
2128
|
}
|
|
1864
2129
|
|
|
1865
2130
|
.wb-render-error .rtitle {
|
|
@@ -1907,8 +2172,8 @@ select.wb-ctrl-input {
|
|
|
1907
2172
|
margin: 12px 16px 0 16px;
|
|
1908
2173
|
padding: 8px 11px;
|
|
1909
2174
|
border-radius: var(--r);
|
|
1910
|
-
background:
|
|
1911
|
-
border: 1px solid
|
|
2175
|
+
background: color-mix(in srgb, var(--deprecated) 6%, transparent);
|
|
2176
|
+
border: 1px solid color-mix(in srgb, var(--deprecated) 22%, transparent);
|
|
1912
2177
|
color: var(--danger);
|
|
1913
2178
|
font-size: 12px;
|
|
1914
2179
|
line-height: 1.45;
|
|
@@ -31,6 +31,8 @@ export interface BridgeApi {
|
|
|
31
31
|
readyNonce: number
|
|
32
32
|
title: string
|
|
33
33
|
groups: WindoGroup[]
|
|
34
|
+
/** The config's declared tag set (filter options for the sidebar). */
|
|
35
|
+
tags: string[]
|
|
34
36
|
contexts: WindoContextMeta[]
|
|
35
37
|
manifest: WindoManifestEntry[]
|
|
36
38
|
/** describe payload for the most recently selected id (null until it arrives). */
|
|
@@ -43,15 +45,26 @@ export interface BridgeApi {
|
|
|
43
45
|
stateValues: Record<string, Record<string, unknown>>
|
|
44
46
|
/** Live `disabled` flag per action id (keyed windo id → action id), echoed from the preview. */
|
|
45
47
|
actionDisabled: Record<string, Record<string, boolean>>
|
|
48
|
+
/** Config seed for the shared `ctxState` (from the manifest) — fills keys the chrome hasn't persisted. */
|
|
49
|
+
ctxStateDefaults: Record<string, unknown>
|
|
50
|
+
/** Latest shared-state snapshot echoed after a component wrote it via `ctx.setCtxState`. */
|
|
51
|
+
ctxState: Record<string, unknown>
|
|
52
|
+
/** Latest colour scheme a component pushed via `ctx.toggleTheme`/`setColorScheme` (null until one does). Re-wrapped each echo so repeated same-value pushes still propagate. */
|
|
53
|
+
colorScheme: { value: 'light' | 'dark' } | null
|
|
46
54
|
// outbound
|
|
47
55
|
select: (id: string) => void
|
|
48
56
|
setProps: (id: string, json: string) => void
|
|
49
57
|
setEnv: (env: WindoEnvState) => void
|
|
58
|
+
/** Push the shared state down to the preview (editor edit or reload re-sync). */
|
|
59
|
+
setCtxState: (state: Record<string, unknown>) => void
|
|
50
60
|
invokeAction: (id: string, actionId: string) => void
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
export type InspectorPosition = 'right' | 'bottom'
|
|
54
64
|
|
|
65
|
+
/** How the sidebar's tag filter combines multiple selected tags. */
|
|
66
|
+
export type TagMatch = 'any' | 'all'
|
|
67
|
+
|
|
55
68
|
export type ThemeMode = 'light' | 'dark'
|
|
56
69
|
|
|
57
70
|
/** Cosmetic canvas chrome (drawn behind a transparent iframe), persisted to localStorage. */
|
|
@@ -85,11 +98,18 @@ export interface ChromeEnv {
|
|
|
85
98
|
|
|
86
99
|
export interface SidebarProps {
|
|
87
100
|
groups: WindoGroup[]
|
|
101
|
+
/** Declared tag set — the filter's options. */
|
|
102
|
+
tags: string[]
|
|
88
103
|
manifest: WindoManifestEntry[]
|
|
89
104
|
selected: string | null
|
|
90
105
|
onSelect: (id: string) => void
|
|
91
106
|
query: string
|
|
92
107
|
setQuery: (q: string) => void
|
|
108
|
+
/** Currently-checked tag filters. Empty = no filter. */
|
|
109
|
+
selectedTags: string[]
|
|
110
|
+
setSelectedTags: (next: string[]) => void
|
|
111
|
+
tagMatch: TagMatch
|
|
112
|
+
setTagMatch: (m: TagMatch) => void
|
|
93
113
|
collapsed: boolean
|
|
94
114
|
onToggle: () => void
|
|
95
115
|
}
|
|
@@ -134,6 +154,10 @@ export interface InspectorProps {
|
|
|
134
154
|
clearLogs: () => void
|
|
135
155
|
/** Live component-local state snapshot for the selected windo (drives the read-only State strip). */
|
|
136
156
|
state: Record<string, unknown>
|
|
157
|
+
/** Shared, cross-component state — drives the editable Shared strip. */
|
|
158
|
+
ctxState: Record<string, unknown>
|
|
159
|
+
/** Edit one key of the shared state (pushes down to the preview). */
|
|
160
|
+
setCtxStateValue: (key: string, value: unknown) => void
|
|
137
161
|
/** Context metadata filtered to this windo (its `uses` providers + all ambient). */
|
|
138
162
|
contexts: WindoContextMeta[]
|
|
139
163
|
env: ChromeEnv
|
package/src/define-config.ts
CHANGED
|
@@ -6,18 +6,22 @@ import type { ComponentType, ReactNode } from 'react'
|
|
|
6
6
|
import type { z } from 'zod'
|
|
7
7
|
import type { WindoConfig, WindoContextDefinition, WindoContextMap, WindoControlMap, WindoControlValues, WindoDefinition, WindoFactoryArg, WindoGroup, WindoModule, WindoRenderContext } from './types'
|
|
8
8
|
|
|
9
|
-
export interface DefineWindoConfigResult<Groups extends readonly WindoGroup[], Contexts extends WindoContextMap> {
|
|
10
|
-
config: WindoConfig<Groups, Contexts>
|
|
11
|
-
windo: <Props, State = Record<string, never>>(
|
|
9
|
+
export interface DefineWindoConfigResult<Groups extends readonly WindoGroup[], Tags extends readonly string[], Contexts extends WindoContextMap> {
|
|
10
|
+
config: WindoConfig<Groups, Contexts, Tags>
|
|
11
|
+
windo: <Props, State = Record<string, never>>(
|
|
12
|
+
factory: (w: WindoFactoryArg<Groups, Contexts, Tags>) => WindoDefinition<Props, State, Groups[number]['slug'], Tags[number]>
|
|
13
|
+
) => WindoModule<Props, State>
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export function defineWindoConfig<const Groups extends readonly WindoGroup[], Contexts extends WindoContextMap = Record<string, never>>(
|
|
15
|
-
config: WindoConfig<Groups, Contexts>
|
|
16
|
-
): DefineWindoConfigResult<Groups, Contexts> {
|
|
17
|
-
function windo<Props, State = Record<string, never>>(
|
|
16
|
+
export function defineWindoConfig<const Groups extends readonly WindoGroup[], const Tags extends readonly string[] = readonly [], Contexts extends WindoContextMap = Record<string, never>>(
|
|
17
|
+
config: WindoConfig<Groups, Contexts, Tags>
|
|
18
|
+
): DefineWindoConfigResult<Groups, Tags, Contexts> {
|
|
19
|
+
function windo<Props, State = Record<string, never>>(
|
|
20
|
+
factory: (w: WindoFactoryArg<Groups, Contexts, Tags>) => WindoDefinition<Props, State, Groups[number]['slug'], Tags[number]>
|
|
21
|
+
): WindoModule<Props, State> {
|
|
18
22
|
return {
|
|
19
23
|
__windo: true,
|
|
20
|
-
resolve: w => factory(w as unknown as WindoFactoryArg<Groups, Contexts>),
|
|
24
|
+
resolve: w => factory(w as unknown as WindoFactoryArg<Groups, Contexts, Tags>),
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
return { config, windo }
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export {
|
|
|
14
14
|
WINDO_MSG,
|
|
15
15
|
} from './protocol'
|
|
16
16
|
export type {
|
|
17
|
+
Ctxual,
|
|
17
18
|
WindoAction,
|
|
18
19
|
WindoActionMeta,
|
|
19
20
|
WindoActionTrigger,
|
|
@@ -34,6 +35,7 @@ export type {
|
|
|
34
35
|
WindoFactoryArg,
|
|
35
36
|
WindoFieldError,
|
|
36
37
|
WindoGroup,
|
|
38
|
+
WindoInitContext,
|
|
37
39
|
WindoLogEntry,
|
|
38
40
|
WindoLogger,
|
|
39
41
|
WindoManifestEntry,
|
package/src/preview/ctx.ts
CHANGED
|
@@ -10,7 +10,10 @@ export function buildRenderContext<State>(
|
|
|
10
10
|
contexts: WindoContextMap,
|
|
11
11
|
postLog: (entry: WindoLogEntry) => void,
|
|
12
12
|
state: State,
|
|
13
|
-
setState: (patch: Partial<State>) => void
|
|
13
|
+
setState: (patch: Partial<State>) => void,
|
|
14
|
+
ctxState: Record<string, unknown>,
|
|
15
|
+
setCtxState: (patch: Record<string, unknown>) => void,
|
|
16
|
+
setColorScheme: (scheme: 'light' | 'dark') => void
|
|
14
17
|
): WindoRenderContext<State> {
|
|
15
18
|
const logger = {
|
|
16
19
|
log: (...args: unknown[]) => postLog({ ts: Date.now(), args }),
|
|
@@ -26,6 +29,10 @@ export function buildRenderContext<State>(
|
|
|
26
29
|
state,
|
|
27
30
|
setState,
|
|
28
31
|
contexts: {},
|
|
32
|
+
ctxState,
|
|
33
|
+
setCtxState,
|
|
34
|
+
setColorScheme,
|
|
35
|
+
toggleTheme: () => setColorScheme(env.colorScheme === 'light' ? 'dark' : 'light'),
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
for (const name of Object.keys(contexts)) {
|