@foldkit/devtools 0.126.0 → 0.128.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.
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAEN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EAGlB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKhB,MAAM,uBAAuB,CAAA;AAW9B,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;;oFAyDnC,CAAC;;;;;;;;;;;;;;;;;AAyQnC,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAgCjD,eAAO,MAAM,oBAAoB;;;;;iBAiBhC,CAAA;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;wBAU5B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;wBAIqB,CAAA;AAE9C,eAAO,MAAM,aAAa;;;;;;wBASzB,CAAA;AAED,eAAO,MAAM,MAAM;;wBASlB,CAAA;AAED,eAAO,MAAM,KAAK;;wBASjB,CAAA;AAED,eAAO,MAAM,WAAW;;6BAYvB,CAAA;AA66DD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAgFhC,CAAA"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,OAAO,EACP,MAAM,EAEN,OAAO,EAGP,MAAM,EAKN,MAAM,IAAI,CAAC,EAGX,eAAe,EAEhB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,aAAa,EAGlB,KAAK,WAAW,EAChB,KAAK,UAAU,EAKhB,MAAM,uBAAuB,CAAA;AAW9B,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;;oFAkD1B,CAAC;;;;;;;;;;;;;;;;;AAqQ5C,cAAM,YAAa,SAAQ,iBAE1B;CAAG;;AAEJ,cAAM,iBAAkB,SAAQ,sBAGC;CAAG;AAEpC,eAAO,MAAM,UAAU;;iBAGsB,CAAA;AAE7C,eAAO,MAAM,YAAY;;iBAGwB,CAAA;AAgCjD,eAAO,MAAM,oBAAoB;;;;;iBAiBhC,CAAA;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;wBAU5B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;wBAIqB,CAAA;AAE9C,eAAO,MAAM,aAAa;;;;;;wBASzB,CAAA;AAED,eAAO,MAAM,MAAM;;wBASlB,CAAA;AAED,eAAO,MAAM,KAAK;;wBASjB,CAAA;AAED,eAAO,MAAM,WAAW;;6BAYvB,CAAA;AAq6DD,eAAO,MAAM,aAAa,GACxB,OAAO,aAAa,EACpB,UAAU,gBAAgB,EAC1B,MAAM,YAAY,EAClB,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,6DAkFhC,CAAA"}
package/dist/overlay.js CHANGED
@@ -40,18 +40,8 @@ const INSPECTOR_TABS_ID = 'dt-inspector';
40
40
  const SUBMODEL_FILTER_ID = 'dt-submodel-filter';
41
41
  const FLATTEN_SWITCH_ID = 'dt-flatten-switch';
42
42
  const SCRUBBER_SLIDER_ID = 'dt-scrubber';
43
- const InspectorTabsModel = S.Struct({
44
- id: S.String,
45
- activeIndex: S.Number,
46
- focusedIndex: S.Number,
47
- activationMode: S.Literals(['Automatic', 'Manual']),
48
- });
49
- const INSPECTOR_TABS = [
50
- 'Model',
51
- 'Message',
52
- 'Commands',
53
- 'Mounts',
54
- ];
43
+ const InspectorTab = S.Literals(['Model', 'Message', 'Commands', 'Mounts']);
44
+ const INSPECTOR_TABS = InspectorTab.literals;
55
45
  const InspectorTabs = Tabs.create();
56
46
  /**
57
47
  * `S.Unknown` whose equivalence is reference equality. Effect 4's default
@@ -83,13 +73,14 @@ const Model = S.Struct({
83
73
  maybeInspectedMessage: S.Option(UnknownByReference),
84
74
  submodelTags: S.Array(S.String),
85
75
  maybeSubmodelFilter: S.Option(S.String),
86
- flattenSwitch: Switch.Model,
76
+ isFlattened: S.Boolean,
87
77
  submodelFilterListbox: Listbox.Model,
88
78
  expandedPaths: S.HashSet(S.String),
89
79
  changedPaths: S.HashSet(S.String),
90
80
  affectedPaths: S.HashSet(S.String),
91
81
  maybePendingScrubIndex: S.Option(S.Number),
92
- inspectorTabs: InspectorTabsModel,
82
+ inspectorTabs: Tabs.Model,
83
+ activeInspectorTab: InspectorTab,
93
84
  // NOTE: empirically, inlining `Slider.Model` here throws
94
85
  // "Cannot read properties of undefined (reading 'ast')" when running slider
95
86
  // tests, because slider imports html → runtime → overlay, and overlay
@@ -99,6 +90,7 @@ const Model = S.Struct({
99
90
  // pinned down. Suspend is the conservative fix until the runtime ↔ overlay
100
91
  // cycle is broken at the source.
101
92
  scrubberSlider: S.suspend(() => Slider.Model),
93
+ scrubberValue: S.Number,
102
94
  });
103
95
  const Flags = S.Struct({
104
96
  isOpen: S.Boolean,
@@ -114,9 +106,7 @@ const Flags = S.Struct({
114
106
  // MESSAGE
115
107
  const ClickedToggle = m('ClickedToggle');
116
108
  const ClickedSettingsToggle = m('ClickedSettingsToggle');
117
- const GotFlattenSwitchMessage = m('GotFlattenSwitchMessage', {
118
- message: Switch.Message,
119
- });
109
+ const ToggledFlatten = m('ToggledFlatten', { isFlattened: S.Boolean });
120
110
  const CompletedPersistDevToolsState = m('CompletedPersistDevToolsState');
121
111
  const ClickedRow = m('ClickedRow', { index: S.Number });
122
112
  const ClickedResume = m('ClickedResume');
@@ -161,7 +151,7 @@ const GotScrubberSliderMessage = m('GotScrubberSliderMessage', {
161
151
  const Message = S.Union([
162
152
  ClickedToggle,
163
153
  ClickedSettingsToggle,
164
- GotFlattenSwitchMessage,
154
+ ToggledFlatten,
165
155
  CompletedPersistDevToolsState,
166
156
  ClickedRow,
167
157
  ClickedResume,
@@ -339,7 +329,7 @@ const makeUpdate = (store, shadow, mode) => {
339
329
  ...Option.toArray(maybeToggleScrollLock(model.isMobile, nextIsOpen)),
340
330
  PersistDevToolsState({
341
331
  isOpen: nextIsOpen,
342
- isFlattened: model.flattenSwitch.isChecked,
332
+ isFlattened: model.isFlattened,
343
333
  }),
344
334
  ],
345
335
  ];
@@ -350,28 +340,10 @@ const makeUpdate = (store, shadow, mode) => {
350
340
  }),
351
341
  [],
352
342
  ],
353
- GotFlattenSwitchMessage: ({ message: switchMessage }) => {
354
- const [nextFlattenSwitch, switchCommands, maybeOutMessage] = Switch.update(model.flattenSwitch, switchMessage);
355
- const mappedCommands = Command.mapMessages(switchCommands, message => GotFlattenSwitchMessage({ message }));
356
- return Option.match(maybeOutMessage, {
357
- onNone: () => [
358
- evo(model, { flattenSwitch: () => nextFlattenSwitch }),
359
- mappedCommands,
360
- ],
361
- onSome: M.type().pipe(M.withReturnType(), M.tagsExhaustive({
362
- ToggledChecked: ({ isChecked }) => [
363
- evo(model, { flattenSwitch: () => nextFlattenSwitch }),
364
- [
365
- ...mappedCommands,
366
- PersistDevToolsState({
367
- isOpen: model.isOpen,
368
- isFlattened: isChecked,
369
- }),
370
- ],
371
- ],
372
- })),
373
- });
374
- },
343
+ ToggledFlatten: ({ isFlattened }) => [
344
+ evo(model, { isFlattened: () => isFlattened }),
345
+ [PersistDevToolsState({ isOpen: model.isOpen, isFlattened })],
346
+ ],
375
347
  CrossedMobileBreakpoint: ({ isMobile }) => [
376
348
  evo(model, { isMobile: () => isMobile }),
377
349
  Option.toArray(maybeToggleScrollLock(model.isOpen, isMobile)),
@@ -443,10 +415,17 @@ const makeUpdate = (store, shadow, mode) => {
443
415
  [],
444
416
  ],
445
417
  GotInspectorTabsMessage: ({ message: tabsMessage }) => {
446
- const [nextTabsModel, tabsCommands] = InspectorTabs.update(model.inspectorTabs, tabsMessage);
418
+ const [nextTabsModel, tabsCommands, maybeOutMessage] = InspectorTabs.update(model.inspectorTabs, tabsMessage);
419
+ const nextActiveInspectorTab = Option.match(maybeOutMessage, {
420
+ onNone: () => model.activeInspectorTab,
421
+ onSome: M.type().pipe(M.tagsExhaustive({
422
+ Selected: ({ value }) => value,
423
+ })),
424
+ });
447
425
  return [
448
426
  evo(model, {
449
427
  inspectorTabs: () => nextTabsModel,
428
+ activeInspectorTab: () => nextActiveInspectorTab,
450
429
  }),
451
430
  Command.mapMessages(tabsCommands, message => GotInspectorTabsMessage({ message })),
452
431
  ];
@@ -468,6 +447,10 @@ const makeUpdate = (store, shadow, mode) => {
468
447
  });
469
448
  const nextSubmodelTags = computeSubmodelTags(entries);
470
449
  const isFilterStale = Option.exists(model.maybeSubmodelFilter, filterTag => !Array_.contains(nextSubmodelTags, filterTag));
450
+ const sliderMax = entries.length;
451
+ const targetSliderValue = isPaused
452
+ ? hostIndexToSliderValue(pausedAtIndex, startIndex)
453
+ : sliderMax;
471
454
  return [
472
455
  evo(model, {
473
456
  entries: () => entries,
@@ -478,19 +461,9 @@ const makeUpdate = (store, shadow, mode) => {
478
461
  pausedAtIndex: () => pausedAtIndex,
479
462
  submodelTags: () => nextSubmodelTags,
480
463
  maybeSubmodelFilter: current => isFilterStale ? Option.none() : current,
481
- submodelFilterListbox: current => isFilterStale
482
- ? evo(current, {
483
- maybeSelectedItem: () => Option.some(ALL_MESSAGES_VALUE),
484
- })
485
- : current,
486
464
  selectedIndex: current => shouldFollowSelection ? latestIndex : current,
487
- scrubberSlider: current => {
488
- const sliderMax = entries.length;
489
- const targetSliderValue = isPaused
490
- ? hostIndexToSliderValue(pausedAtIndex, startIndex)
491
- : sliderMax;
492
- return Slider.reflectValue(Slider.reflectRange(current, { min: 0, max: sliderMax }), targetSliderValue);
493
- },
465
+ scrubberSlider: current => Slider.reflectRange(current, { min: 0, max: sliderMax }),
466
+ scrubberValue: current => M.value(model.scrubberSlider.dragState).pipe(M.tag('Dragging', () => Slider.snapAndClamp(current, 0, sliderMax, 1)), M.orElse(() => Slider.snapAndClamp(targetSliderValue, 0, sliderMax, 1))),
494
467
  }),
495
468
  [
496
469
  ...(shouldFollowSelection ? [inspectLatest] : []),
@@ -528,13 +501,20 @@ const makeUpdate = (store, shadow, mode) => {
528
501
  // than they complete.
529
502
  const nextMaybePendingScrubIndex = Option.match(maybeOutMessage, {
530
503
  onNone: () => model.maybePendingScrubIndex,
531
- onSome: outMessage => M.value(outMessage).pipe(M.tagsExhaustive({
504
+ onSome: M.type().pipe(M.tagsExhaustive({
532
505
  ChangedValue: ({ value }) => Option.some(sliderValueToHostIndex(value, model.startIndex)),
533
506
  })),
534
507
  });
508
+ const nextScrubberValue = Option.match(maybeOutMessage, {
509
+ onNone: () => model.scrubberValue,
510
+ onSome: M.type().pipe(M.tagsExhaustive({
511
+ ChangedValue: ({ value }) => value,
512
+ })),
513
+ });
535
514
  return [
536
515
  evo(model, {
537
516
  scrubberSlider: () => nextSlider,
517
+ scrubberValue: () => nextScrubberValue,
538
518
  maybePendingScrubIndex: () => nextMaybePendingScrubIndex,
539
519
  }),
540
520
  mappedSliderCommands,
@@ -933,7 +913,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
933
913
  ])), M.when('Message', () => lazyTabContent('Message', messageTabContent, [
934
914
  model.maybeInspectedMessage,
935
915
  model.maybeSubmodelFilter,
936
- model.flattenSwitch.isChecked,
916
+ model.isFlattened,
937
917
  model.expandedPaths,
938
918
  inspectedTimestamp(model),
939
919
  ])), M.when('Commands', () => lazyTabContent('Commands', commandsTabContent, [
@@ -956,6 +936,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
956
936
  view: InspectorTabs.view,
957
937
  viewInputs: {
958
938
  tabs: INSPECTOR_TABS,
939
+ selectedValue: model.activeInspectorTab,
959
940
  ariaLabel: 'Inspector tabs',
960
941
  toView: ({ tablist, tabs, activeIndex }) => h.div([h.Class('flex flex-col flex-1 min-h-0')], [
961
942
  h.div([...tablist, h.Class('flex border-b shrink-0')], tabs.map(tab => h.button([
@@ -1057,6 +1038,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
1057
1038
  view: SubmodelFilterListbox.view,
1058
1039
  viewInputs: {
1059
1040
  items: [ALL_MESSAGES_VALUE, ...model.submodelTags],
1041
+ maybeSelectedValue: Option.orElseSome(model.maybeSubmodelFilter, () => ALL_MESSAGES_VALUE),
1060
1042
  itemToConfig: item => ({
1061
1043
  className: 'dt-filter-item',
1062
1044
  content: h.div([h.Class('flex items-center gap-2')], [checkIconView, h.span([], [filterItemLabel(item)])]),
@@ -1089,23 +1071,20 @@ const makeView = (position, mode, shadow, maybeBanner) => {
1089
1071
  });
1090
1072
  };
1091
1073
  // SETTINGS
1092
- const flattenSwitchView = (model) => h.submodel({
1093
- slotId: 'flatten-switch',
1094
- model: model.flattenSwitch,
1095
- view: Switch.view,
1096
- viewInputs: {
1097
- toView: attributes => h.div([h.Class('dt-settings-row')], [
1098
- h.div([...attributes.button, h.Class('dt-switch')], [h.span([h.Class('dt-switch-thumb')], [])]),
1099
- h.div([h.Class('dt-settings-row-text')], [
1100
- h.label([...attributes.label, h.Class('dt-settings-row-label')], ['Flatten to leaf Message']),
1101
- h.span([
1102
- ...attributes.description,
1103
- h.Class('dt-settings-row-description'),
1104
- ], ['Label each row with its innermost Message']),
1105
- ]),
1074
+ const flattenSwitchView = (model) => Switch.view({
1075
+ id: FLATTEN_SWITCH_ID,
1076
+ isChecked: model.isFlattened,
1077
+ onToggle: isFlattened => ToggledFlatten({ isFlattened }),
1078
+ toView: attributes => h.div([h.Class('dt-settings-row')], [
1079
+ h.div([...attributes.button, h.Class('dt-switch')], [h.span([h.Class('dt-switch-thumb')], [])]),
1080
+ h.div([h.Class('dt-settings-row-text')], [
1081
+ h.label([...attributes.label, h.Class('dt-settings-row-label')], ['Flatten to leaf Message']),
1082
+ h.span([
1083
+ ...attributes.description,
1084
+ h.Class('dt-settings-row-description'),
1085
+ ], ['Label each row with its innermost Message']),
1106
1086
  ]),
1107
- },
1108
- toParentMessage: message => GotFlattenSwitchMessage({ message }),
1087
+ ]),
1109
1088
  });
1110
1089
  const settingsScreenView = (model) => h.keyed('div')('Settings', [h.Class('flex flex-col flex-1 min-h-0 overflow-y-auto overscroll-none')], [
1111
1090
  h.div([h.Class('flex flex-col')], [
@@ -1235,13 +1214,13 @@ const makeView = (position, mode, shadow, maybeBanner) => {
1235
1214
  model.isPaused,
1236
1215
  model.pausedAtIndex,
1237
1216
  model.maybeSubmodelFilter,
1238
- model.flattenSwitch.isChecked,
1217
+ model.isFlattened,
1239
1218
  ]);
1240
1219
  };
1241
1220
  // SCRUBBER
1242
1221
  const scrubberPositionLabel = (model) => {
1243
1222
  const total = String(model.entries.length).padStart(3, '0');
1244
- const current = String(model.scrubberSlider.value).padStart(3, '0');
1223
+ const current = String(model.scrubberValue).padStart(3, '0');
1245
1224
  return `${current} / ${total}`;
1246
1225
  };
1247
1226
  const scrubberView = (model) => h.submodel({
@@ -1249,6 +1228,7 @@ const makeView = (position, mode, shadow, maybeBanner) => {
1249
1228
  model: model.scrubberSlider,
1250
1229
  view: Slider.view,
1251
1230
  viewInputs: {
1231
+ value: model.scrubberValue,
1252
1232
  ariaLabel: 'Session scrubber',
1253
1233
  getTrackRoot: () => shadow,
1254
1234
  formatValue: value => value === 0 ? 'init' : `Message ${String(value)}`,
@@ -1400,10 +1380,7 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
1400
1380
  {
1401
1381
  screen: 'Messages',
1402
1382
  ...displayFlags,
1403
- flattenSwitch: Switch.init({
1404
- id: FLATTEN_SWITCH_ID,
1405
- isChecked: isFlattened,
1406
- }),
1383
+ isFlattened,
1407
1384
  selectedIndex: INIT_INDEX,
1408
1385
  isFollowingLatest: true,
1409
1386
  isFollowingTop: true,
@@ -1411,7 +1388,6 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
1411
1388
  maybeSubmodelFilter: Option.none(),
1412
1389
  submodelFilterListbox: Listbox.init({
1413
1390
  id: SUBMODEL_FILTER_ID,
1414
- selectedItem: ALL_MESSAGES_VALUE,
1415
1391
  }),
1416
1392
  maybeInspectedModel: Option.none(),
1417
1393
  maybeInspectedMessage: Option.none(),
@@ -1420,13 +1396,14 @@ export const createOverlay = (store, position, mode, maybeBanner) => Effect.gen(
1420
1396
  affectedPaths: HashSet.empty(),
1421
1397
  maybePendingScrubIndex: Option.none(),
1422
1398
  inspectorTabs: Tabs.init({ id: INSPECTOR_TABS_ID }),
1399
+ activeInspectorTab: 'Model',
1423
1400
  scrubberSlider: Slider.init({
1424
1401
  id: SCRUBBER_SLIDER_ID,
1425
1402
  min: 0,
1426
1403
  max: sliderMax,
1427
1404
  step: 1,
1428
- initialValue: initialSliderValue,
1429
1405
  }),
1406
+ scrubberValue: Slider.snapAndClamp(initialSliderValue, 0, sliderMax, 1),
1430
1407
  },
1431
1408
  Option.toArray(maybeLockScroll(flags.isOpen, flags.isMobile)),
1432
1409
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foldkit/devtools",
3
- "version": "0.126.0",
3
+ "version": "0.128.0",
4
4
  "description": "In-browser DevTools overlay for Foldkit applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,8 +30,8 @@
30
30
  "effect": "4.0.0-beta.88",
31
31
  "rimraf": "^6.1.3",
32
32
  "typescript": "^6.0.3",
33
- "@foldkit/ui": "0.126.0",
34
- "foldkit": "0.126.0"
33
+ "@foldkit/ui": "0.128.0",
34
+ "foldkit": "0.128.0"
35
35
  },
36
36
  "keywords": [
37
37
  "foldkit",