@kitlangton/knobs 0.1.0 → 0.2.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.
Files changed (48) hide show
  1. package/README.md +174 -30
  2. package/dist/dev/{chunk-e13znr7c.js → chunk-4km87zfx.js} +3 -3
  3. package/dist/dev/{chunk-ktsn42p7.js → chunk-5cr85vv6.js} +7448 -5390
  4. package/dist/dev/{chunk-kdewv0mt.js → chunk-693jd1gj.js} +171 -70
  5. package/dist/dev/{chunk-qtt698hp.js → chunk-gezhc24g.js} +21 -7
  6. package/dist/dev/index.js +377 -106
  7. package/dist/index.js +392 -108
  8. package/dist/panel.js +9518 -6749
  9. package/dist/types/core/random.d.ts +61 -1
  10. package/dist/types/core/remote.d.ts +3 -1
  11. package/dist/types/core/schema.d.ts +30 -6
  12. package/dist/types/core/store.d.ts +68 -6
  13. package/dist/types/core/variants.d.ts +10 -2
  14. package/dist/types/index.d.ts +3 -2
  15. package/dist/types/panel/editors.d.ts +11 -0
  16. package/dist/types/panel/flash.d.ts +13 -0
  17. package/dist/types/panel/gpu/renderer.d.ts +78 -6
  18. package/dist/types/panel/haptics.d.ts +6 -2
  19. package/dist/types/panel/has.d.ts +0 -1
  20. package/dist/types/panel/index.d.ts +1 -0
  21. package/dist/types/panel/inspector.d.ts +32 -2
  22. package/dist/types/panel/optkeys.d.ts +7 -0
  23. package/dist/types/panel/presets.d.ts +17 -5
  24. package/dist/types/panel/ramp-morph.d.ts +117 -0
  25. package/dist/types/panel/ramps.d.ts +1 -1
  26. package/dist/types/panel/reel.d.ts +43 -0
  27. package/dist/types/panel/scope.d.ts +19 -0
  28. package/dist/types/panel/slider.d.ts +1 -1
  29. package/dist/types/panel/sound.d.ts +137 -0
  30. package/dist/types/panel/styles.d.ts +1 -1
  31. package/dist/types/panel/toolbar-grid.d.ts +6 -0
  32. package/dist/types/ui/activity-css.d.ts +1 -0
  33. package/dist/types/ui/activity-model.d.ts +122 -0
  34. package/dist/types/ui/activity.d.ts +67 -0
  35. package/dist/types/ui/follow.d.ts +17 -0
  36. package/dist/types/ui/index.d.ts +5 -1
  37. package/dist/types/ui/look.d.ts +9 -0
  38. package/dist/types/ui/picker-css.d.ts +1 -0
  39. package/dist/types/ui/picker-model.d.ts +53 -0
  40. package/dist/types/ui/picker.d.ts +67 -0
  41. package/dist/types/ui/react.d.ts +27 -0
  42. package/dist/types/ui/solid.d.ts +23 -0
  43. package/dist/types/ui/split-model.d.ts +54 -0
  44. package/dist/types/ui/split.d.ts +17 -0
  45. package/dist/ui-react.js +3239 -567
  46. package/dist/ui-solid.js +3123 -472
  47. package/dist/ui.js +2688 -100
  48. package/package.json +1 -1
package/dist/ui.js CHANGED
@@ -80,6 +80,105 @@ function springCss(value) {
80
80
  return { easing, duration: ms };
81
81
  }
82
82
 
83
+ // src/panel/rolling-css.ts
84
+ var rolling_css_default = `.rn-root {
85
+ display: inline-block;
86
+ position: relative;
87
+ white-space: pre;
88
+ unicode-bidi: isolate;
89
+ vertical-align: baseline;
90
+ }
91
+ .rn-root > .rn-measure,
92
+ .rn-root > .rn-visual { display: none; }
93
+ .rn-root[data-rn-measuring] > .rn-measure {
94
+ display: inline-flex;
95
+ position: relative;
96
+ visibility: hidden;
97
+ white-space: pre;
98
+ padding: 0;
99
+ border: 0;
100
+ }
101
+ .rn-token { display: inline-block; padding: 0; border: 0; }
102
+ .rn-root[data-rn-measuring] > .rn-value,
103
+ .rn-react[data-rn-hydrated] > .rn-semantic,
104
+ .rn-solid[data-rn-hydrated] > .rn-semantic {
105
+ position: absolute;
106
+ inset: 0;
107
+ padding: 0;
108
+ margin: 0;
109
+ color: transparent;
110
+ z-index: 1;
111
+ }
112
+ /* A single native text layer is selectable; decorative reels never enter a copy. */
113
+ .rn-value::selection, .rn-semantic::selection {
114
+ color: HighlightText;
115
+ background: Highlight;
116
+ }
117
+ .rn-root[data-rn-ready] > .rn-visual {
118
+ display: block;
119
+ position: absolute;
120
+ inset: 0;
121
+ pointer-events: none;
122
+ user-select: none;
123
+ }
124
+ .rn-slot {
125
+ position: absolute;
126
+ left: 0;
127
+ overflow: hidden;
128
+ /* Space for italic overhang without changing the measured advance width. */
129
+ box-sizing: content-box;
130
+ padding-inline: 0.15em;
131
+ margin-inline-start: -0.15em;
132
+ -webkit-mask-image: var(--rn-mask, linear-gradient(
133
+ to bottom,
134
+ transparent,
135
+ #000 var(--rn-edge-fade, 0.12em),
136
+ #000 calc(100% - var(--rn-edge-fade, 0.12em)),
137
+ transparent
138
+ ));
139
+ mask-image: var(--rn-mask, linear-gradient(
140
+ to bottom,
141
+ transparent,
142
+ #000 var(--rn-edge-fade, 0.12em),
143
+ #000 calc(100% - var(--rn-edge-fade, 0.12em)),
144
+ transparent
145
+ ));
146
+ -webkit-mask-repeat: no-repeat;
147
+ mask-repeat: no-repeat;
148
+ }
149
+ @supports (overflow: clip) {
150
+ .rn-slot { overflow-x: visible; overflow-y: clip; }
151
+ }
152
+ .rn-slot:not([data-rn-wheel]) {
153
+ overflow: visible;
154
+ -webkit-mask-image: none;
155
+ mask-image: none;
156
+ }
157
+ .rn-enter, .rn-reel, .rn-face { display: block; }
158
+ .rn-reel { position: relative; }
159
+ .rn-ink { display: block; position: absolute; inset: 0; will-change: transform; }
160
+ /* Safari's SVG filter must rasterize the smear's descendants into its input. */
161
+ .rn-smear .rn-ink { will-change: auto; }
162
+ /* Each turning half carries its own perspective transform, not a shared 3D scene. */
163
+ /* The slot acts as the bezel: the card stays vertically framed while it hinges. */
164
+ .rn-slot[data-rn-flap] { -webkit-mask-image: none; mask-image: none; }
165
+ /* Hinged faces must occlude the cards behind them, including with default CSS. */
166
+ :where(.rn-slot[data-rn-flap]) .rn-face { background: var(--rn-flap-background, Canvas); }
167
+ .rn-flap { position: absolute; inset: 0; transform-origin: 50% 50%; backface-visibility: hidden; }
168
+ /* --rn-crease is the visible hinge gap between the two halves. */
169
+ .rn-flap-top { clip-path: inset(0 0 calc(50% + var(--rn-crease, 1px) / 2) 0); }
170
+ .rn-flap-bottom { clip-path: inset(calc(50% + var(--rn-crease, 1px) / 2) 0 0 0); }
171
+ .rn-sharp, .rn-smear { display: block; }
172
+ .rn-smear { position: absolute; inset: 0; pointer-events: none; }
173
+ .rn-blur-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
174
+ .rn-face { text-align: center; white-space: pre; }
175
+ .rn-react, .rn-solid { display: inline-block; position: relative; white-space: pre; unicode-bidi: isolate; }
176
+ .rn-mount { display: inline-block; user-select: none; }
177
+ .rn-mount .rn-value { pointer-events: none; }
178
+ .rn-react:not([data-rn-hydrated]) > .rn-mount,
179
+ .rn-solid:not([data-rn-hydrated]) > .rn-mount { display: none; }
180
+ `;
181
+
83
182
  // src/core/theme.ts
84
183
  var block = (tokens) => Object.entries(tokens).map(([k, v]) => `${k.startsWith("--") || k === "color-scheme" ? k : `--k-${k}`}:${v}`).join(";");
85
184
  function presetCss(preset) {
@@ -172,6 +271,88 @@ var problemsPreset = {
172
271
  }
173
272
  };
174
273
 
274
+ // src/ui/activity-css.ts
275
+ var open = springEasing(2 * Math.PI / 0.22, 1);
276
+ var activityCss = `
277
+ :where(.knobs-activity,.knobs-activity *){box-sizing:border-box}
278
+ :where(.knobs-activity){color-scheme:dark}
279
+ .knobs-ui.knobs-activity{position:relative;display:block;height:100%;overflow:auto;overflow-anchor:none;outline:none;scrollbar-width:thin;overscroll-behavior:contain;user-select:none;-webkit-user-select:none;
280
+ font:var(--ku-font-weight) var(--ku-font-size)/1.35 var(--ku-font);color:var(--ku-text);text-align:left;letter-spacing:normal;-webkit-font-smoothing:antialiased;
281
+ --ka-gutter:var(--k-activity-gutter,28px);--ka-row:var(--k-activity-row,var(--ku-row));--ka-row-child:var(--k-activity-row-child,calc(var(--ka-row) - 6px));
282
+ --ka-line:var(--k-activity-line,var(--ku-line-hi));--ka-select:var(--k-activity-select,var(--ku-wash-hi));--ka-hover:var(--k-activity-hover,var(--ku-wash));
283
+ --ka-you:var(--k-activity-you,light-dark(#007aff,#0a84ff));--ka-agent:var(--k-activity-agent,var(--ku-label));--ka-proposal:var(--k-activity-proposal,var(--ku-text));
284
+ --ka-review:var(--k-activity-review,var(--ku-text));--ka-pr:var(--k-activity-pr,light-dark(#8944ab,#bf5af2));--ka-build:var(--k-activity-build,var(--ku-label));
285
+ --ka-blocked:var(--k-activity-blocked,var(--ku-warn));--ka-shipped:var(--k-activity-shipped,light-dark(#248a3d,#30d158));--ka-open-ease:${open.easing};--ka-open-ms:${open.ms}ms}
286
+ .knobs-activity [hidden]{display:none!important}
287
+ /* Clipped below: the content grows on a spring, so a new last row shows as the rail makes room. */
288
+ .knobs-activity-space{position:relative;width:100%;overflow-x:visible;overflow-y:clip;pointer-events:none}
289
+ .knobs-activity-line{position:absolute;top:0;left:calc(var(--ku-row-x) + var(--ka-gutter) / 2 - 1px);width:2px;height:100%;overflow:visible;pointer-events:none;z-index:1}
290
+ .knobs-activity-line path{fill:none;stroke:var(--ka-line);stroke-width:1px}
291
+ /* The selection's tint: a wash that glides between rows, shown only once keys move it. It leaves
292
+ in 100 ms when the pointer is used, and comes back at once. */
293
+ .knobs-activity-hl{position:absolute;left:var(--ku-row-x);right:var(--ku-row-x);top:0;height:0;border-radius:var(--ku-row-radius);background:var(--ka-select);opacity:0;
294
+ transition:opacity 100ms ease-out;pointer-events:none;will-change:transform}
295
+ .knobs-activity[data-keys] .knobs-activity-hl{opacity:1;transition:none}
296
+ .knobs-activity-row{position:absolute;left:var(--ku-row-x);right:var(--ku-row-x);top:0;display:flex;align-items:center;height:var(--ka-row);padding-right:calc(var(--ku-inset) - 4px);
297
+ color:var(--ku-text);white-space:nowrap;cursor:default;will-change:transform;transform-origin:calc(var(--ka-gutter) / 2) 50%;pointer-events:auto;--ka-tint:var(--ka-agent)}
298
+ .knobs-activity-row[data-leaving]{pointer-events:none}
299
+ .knobs-activity-row[data-depth="1"]{height:var(--ka-row-child)}
300
+ .knobs-activity-row>*{position:relative}
301
+ /* Hover: in at once, out over 100 ms; not while keys drive the selection. */
302
+ .knobs-activity-row::before{content:"";position:absolute;inset:0;border-radius:var(--ku-row-radius);background:var(--ka-hover);opacity:0;transition:opacity calc(var(--k-hover-out,100) * 1ms) ease-out;pointer-events:none}
303
+ .knobs-activity:not([data-keys]) .knobs-activity-row:not([data-leaving]):hover::before{opacity:1;transition-duration:calc(var(--k-hover-in,0) * 1ms)}
304
+ .knobs-activity-row[data-kind="you"]{--ka-tint:var(--ka-you)}
305
+ .knobs-activity-row[data-kind="agent"]{--ka-tint:var(--ka-agent)}
306
+ .knobs-activity-row[data-kind="proposal"]{--ka-tint:var(--ka-proposal)}
307
+ .knobs-activity-row[data-kind="review"]{--ka-tint:var(--ka-review)}
308
+ .knobs-activity-row[data-kind="pr"]{--ka-tint:var(--ka-pr)}
309
+ .knobs-activity-row[data-kind="build"]{--ka-tint:var(--ka-build)}
310
+ .knobs-activity-row[data-kind="blocked"]{--ka-tint:var(--ka-blocked)}
311
+ .knobs-activity-row[data-kind="shipped"]{--ka-tint:var(--ka-shipped)}
312
+ /* The node: the kind's icon on the line (which stops clear of it), or a small dot inside a group. */
313
+ .knobs-activity-node{flex:none;display:flex;align-items:center;justify-content:center;width:var(--ka-gutter);height:100%;color:var(--ka-tint)}
314
+ .knobs-activity-node svg{display:block;width:14px;height:14px}
315
+ .knobs-activity-glyph{display:flex;align-items:center;justify-content:center;width:14px;height:14px;font-size:calc(var(--ku-font-size) - 1px);line-height:1}
316
+ .knobs-activity-node::before{content:"";position:absolute;left:50%;top:50%;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;background:color-mix(in srgb,var(--ka-tint) 15%,transparent);
317
+ opacity:0;scale:.8;transition:opacity .16s ease-out,scale var(--ka-open-ms) var(--ka-open-ease)}
318
+ .knobs-activity-row[aria-selected="true"] .knobs-activity-node::before{opacity:1;scale:1}
319
+ .knobs-activity-node::after{content:"";position:absolute;left:50%;top:50%;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ka-tint) 55%,transparent);opacity:0;pointer-events:none}
320
+ .knobs-activity-row[data-current] .knobs-activity-node::after{opacity:1;animation:knobs-activity-breathe 2.6s ease-in-out infinite}
321
+ @keyframes knobs-activity-breathe{0%,100%{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ka-tint) 55%,transparent),0 0 0 0 color-mix(in srgb,var(--ka-tint) 0%,transparent)}
322
+ 50%{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--ka-tint) 70%,transparent),0 0 0 3px color-mix(in srgb,var(--ka-tint) 14%,transparent)}}
323
+ .knobs-activity-dot{display:block;width:5px;height:5px;border-radius:50%;background:currentColor}
324
+ .knobs-activity-row[data-depth="1"] .knobs-activity-node::before,.knobs-activity-row[data-depth="1"] .knobs-activity-node::after{width:13px;height:13px;margin:-6.5px 0 0 -6.5px}
325
+ /* The words: who in the text colour, then the title, one line that fades where it's cut off. */
326
+ .knobs-activity-main{flex:1;min-width:0;overflow:hidden;white-space:nowrap}
327
+ .knobs-activity-actor{margin-right:6px;font-weight:var(--ku-label-weight);color:var(--ku-text)}
328
+ .knobs-activity-actor:empty{display:none}
329
+ .knobs-activity-title{color:var(--ku-label)}
330
+ .knobs-activity-row[data-depth="1"] .knobs-activity-main{font-size:var(--ku-text-meta)}
331
+ .knobs-activity-row[data-depth="1"] .knobs-activity-actor{font-weight:var(--ku-font-weight);color:var(--ku-label)}
332
+ .knobs-activity-row[data-depth="1"] .knobs-activity-title{color:var(--ku-dim)}
333
+ .knobs-activity-row[aria-selected="true"] .knobs-activity-title{color:var(--ku-text)}
334
+ .knobs-activity-row[data-dimmed] :is(.knobs-activity-main,.knobs-activity-meta){opacity:.55}
335
+ .knobs-activity-row[data-dimmed] .knobs-activity-node{opacity:.6}
336
+ /* Trailing: thumbnails, a duration chip, the group's chevron and the time. */
337
+ .knobs-activity-meta{flex:none;display:flex;align-items:center;gap:6px;margin-left:8px;color:var(--ku-dim);font-size:var(--ku-text-meta);font-variant-numeric:tabular-nums}
338
+ .knobs-activity-meta:empty{display:none}
339
+ .knobs-activity-thumbs{display:flex;gap:3px}
340
+ .knobs-activity-thumbs img{display:block;width:18px;height:18px;border-radius:4px;object-fit:cover;background:var(--ku-surface);box-shadow:inset 0 0 0 .5px var(--ku-line)}
341
+ .knobs-activity-row[data-depth="1"] .knobs-activity-thumbs img{width:15px;height:15px}
342
+ :where(.knobs-ui) .knobs-activity-chip{all:revert;box-sizing:border-box;display:inline-flex;align-items:center;gap:4px;height:18px;padding:0 6px 0 5px;border:0;margin:0;border-radius:9px;
343
+ background:var(--ku-surface);color:var(--ku-label);font:inherit;font-variant-numeric:tabular-nums;letter-spacing:inherit;outline:none;transition:background calc(var(--k-hover-out,100) * 1ms) ease-out}
344
+ .knobs-activity-chip svg{width:8px;height:8px}
345
+ button.knobs-activity-chip{cursor:pointer}
346
+ button.knobs-activity-chip:hover{background:var(--ku-surface-hi);color:var(--ku-text);transition-duration:0s}
347
+ .knobs-activity-caret{display:flex;width:12px;height:12px;color:var(--ku-dim);transition:rotate .18s var(--ku-ease)}
348
+ .knobs-activity-caret svg{width:10px;height:10px;margin:1px}
349
+ .knobs-activity-row[aria-expanded="true"] .knobs-activity-caret{rotate:90deg;transition:rotate var(--ka-open-ms) var(--ka-open-ease)}
350
+ .knobs-activity-time{min-width:2ch;text-align:right;white-space:nowrap}
351
+ .knobs-activity-time:empty{display:none}
352
+ .knobs-activity-empty{padding:10px var(--ku-inset);color:var(--ku-dim)}
353
+ @media(prefers-reduced-motion:reduce){.knobs-activity :where(*,::before,::after){transition:none!important;animation:none!important}}
354
+ `;
355
+
175
356
  // src/ui/bento-css.ts
176
357
  var bentoCss = `
177
358
  .knobs-ui.knobs-bento{--ku-bento-radius:var(--k-ui-bento-radius,max(0px,calc(var(--ku-radius) - 5px)));
@@ -304,6 +485,59 @@ var overlayCss = `
304
485
  .knobs-toast .knobs-toast-action[hidden]{display:none}
305
486
  `;
306
487
 
488
+ // src/ui/picker-css.ts
489
+ var snappy = springEasing(2 * Math.PI / 0.25, 1);
490
+ var pickerCss = `
491
+ :where(.knobs-picker,.knobs-picker-option,.knobs-picker-head,.knobs-picker-head *,.knobs-picker-card,.knobs-picker-body){box-sizing:border-box}
492
+ .knobs-ui.knobs-picker{position:relative;display:flex;flex-direction:column;gap:2px;padding:0;outline:none;
493
+ font:var(--ku-font-weight) var(--ku-font-size)/1.35 var(--ku-font);color:var(--ku-text);text-align:left;letter-spacing:normal;-webkit-font-smoothing:antialiased;
494
+ --kp-card:var(--k-picker-card,var(--ku-surface));--kp-radius:var(--k-picker-radius,var(--ku-panel-radius));--kp-snappy:${snappy.easing};--kp-snappy-ms:${snappy.ms}ms}
495
+ .knobs-picker [hidden]{display:none!important}
496
+ /* The selection: one card behind the selected option and its parameters, gliding between them. */
497
+ .knobs-picker-card{position:absolute;left:0;right:0;top:0;height:0;border-radius:var(--kp-radius);background:var(--kp-card);box-shadow:inset 0 0 0 1px var(--ku-line);pointer-events:none}
498
+ .knobs-picker[data-frame="flat"] .knobs-picker-card{box-shadow:none}
499
+ .knobs-picker-option{position:relative;flex:none}
500
+ :where(.knobs-ui) .knobs-picker-head{all:revert;box-sizing:border-box;position:relative;display:flex;align-items:center;gap:8px;width:100%;height:var(--ku-row);padding:0 calc(var(--ku-inset) - 2px) 0 calc(var(--ku-inset) - 4px);
501
+ border:0;margin:0;background:transparent;color:var(--ku-label);font:inherit;letter-spacing:inherit;text-align:left;cursor:default;outline:none;user-select:none;-webkit-user-select:none}
502
+ /* Hover: in at once, out over 100 ms. Keyboard focus: the same wash, a little firmer. */
503
+ .knobs-picker-head::before{content:"";position:absolute;inset:0;border-radius:var(--kp-radius);background:var(--ku-wash);opacity:0;transition:opacity calc(var(--k-hover-out,100) * 1ms) ease-out;pointer-events:none}
504
+ .knobs-picker-option:not([data-selected]) .knobs-picker-head:hover::before{opacity:1;transition-duration:calc(var(--k-hover-in,0) * 1ms)}
505
+ .knobs-picker-head:focus-visible::before{opacity:1;background:var(--ku-wash-hi);transition-duration:0s}
506
+ .knobs-picker-head>*{position:relative}
507
+ .knobs-picker-option[data-selected] .knobs-picker-head{color:var(--ku-text)}
508
+ /* Every row is numbered (only 1–9 are keys): tabular digits in a column two digits wide, so the
509
+ names line up past the ninth. */
510
+ .knobs-picker-key{flex:none;display:inline-flex;align-items:center;justify-content:center;width:max(17px,calc(2ch + 6px));height:17px;padding:0;border-radius:5px;background:var(--ku-surface);
511
+ color:var(--ku-dim);font:var(--ku-label-weight) calc(var(--ku-font-size) - 1.5px)/1 var(--ku-font);font-variant-numeric:tabular-nums;transition:background .15s,color .15s}
512
+ .knobs-picker-key:empty{visibility:hidden}
513
+ /* An option's picture: cover-fit, the rows' corner language and a hairline drawn over it. Its
514
+ space is kept while it loads (nothing drawn), it fades in once loaded, and one that fails
515
+ gives its space back on the same ease. */
516
+ .knobs-picker-thumb{flex:none;display:block;width:var(--k-picker-thumb,min(24px,calc(var(--ku-row) - 10px)));aspect-ratio:1;margin:0;border-radius:max(3px,calc(var(--ku-radius) - 2px));
517
+ object-fit:cover;background:none;outline:1px solid var(--ku-line);outline-offset:-1px;opacity:0;
518
+ transition:opacity .2s ease-out,width .18s ease-out,margin .18s ease-out}
519
+ .knobs-picker-thumb[data-state="loaded"]{opacity:1}
520
+ .knobs-picker-thumb[data-instant]{transition:none}
521
+ .knobs-picker-thumb[data-state="failed"]{width:0;margin-right:-8px;outline-color:transparent}
522
+ .knobs-picker-option[data-selected] .knobs-picker-key{background:var(--ku-surface-hi);color:var(--ku-text)}
523
+ .knobs-picker-name{flex:1;min-width:0;overflow:hidden;white-space:nowrap;font-weight:var(--ku-label-weight)}
524
+ .knobs-picker-suggested{flex:none;color:var(--ku-dim);font-size:var(--ku-text-meta)}
525
+ .knobs-picker-check{flex:none;display:flex;width:14px;height:14px;color:var(--ku-accent);opacity:0;scale:.6;filter:blur(2px);
526
+ transition:opacity .11s ease-in,scale .11s ease-in,filter .11s ease-in}
527
+ .knobs-picker-check svg{display:block;width:14px;height:14px}
528
+ .knobs-picker-option[data-chosen] .knobs-picker-check{opacity:1;scale:1;filter:none;transition:opacity .15s ease-out,scale var(--kp-snappy-ms) var(--kp-snappy),filter .15s ease-out}
529
+ .knobs-picker-body{position:relative;overflow:visible}
530
+ .knobs-picker-body[data-moving]{overflow:hidden}
531
+ /* The picker insets its parameters itself (--k-picker-pad), whatever a panel's own pad: a panel
532
+ inside sheds its card and pad for the picker's, so nothing draws a card inside a card and no
533
+ heading sits at the card's edge. */
534
+ .knobs-picker-inner{padding:var(--k-picker-pad,0 8px 8px)}
535
+ .knobs-picker-inner:empty{padding:0}
536
+ .knobs-picker-inner .knobs-panel.knobs-inline{--k-chrome:0;padding:0}
537
+ .knobs-picker-empty{padding:8px var(--ku-inset);color:var(--ku-dim)}
538
+ @media(prefers-reduced-motion:reduce){.knobs-picker :where(*,::before,::after){transition-duration:.15s!important;scale:none!important;filter:none!important}}
539
+ `;
540
+
307
541
  // src/ui/readout-css.ts
308
542
  var readoutCss = `
309
543
  /* Readouts: live values, sparklines, graphs, meters, tables and logs. */
@@ -488,6 +722,28 @@ var css = `
488
722
  :is(.knobs-tree,.knobs-split>.knobs-pane>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head) [hidden]{display:none!important}
489
723
  :is(.knobs-pane-head,.knobs-pane-rail,.knobs-tree) svg{display:block;flex:none}
490
724
 
725
+ /* Scroll fades: a scroller's content fades out over --knobs-fade at an edge with more beyond it,
726
+ coming in over the first --knobs-fade-travel of scroll, so reaching an end never pops. They're
727
+ scroll-driven (no script), so where those aren't supported there's no fade. --knobs-fade-inset
728
+ starts the top one below a sticky header; .knobs-scroll-fade-x fades across instead (a single
729
+ line that's cut off, like a tree's labels: no ellipsis). Pane bodies, trees and the palette's
730
+ list carry the class; around a panel the GPU draws, the mask goes (it would trap the panel's
731
+ overlays under it). */
732
+ @property --knobs-fade-a{syntax:"<number>";inherits:false;initial-value:1}
733
+ @property --knobs-fade-b{syntax:"<number>";inherits:false;initial-value:1}
734
+ @keyframes knobs-fade-a{from{--knobs-fade-a:1}to{--knobs-fade-a:0}}
735
+ @keyframes knobs-fade-b{from{--knobs-fade-b:0}to{--knobs-fade-b:1}}
736
+ @supports (animation-timeline:scroll()){
737
+ :is(.knobs-scroll-fade,.knobs-scroll-fade-x){--knobs-fade:20px;--knobs-fade-travel:24px;animation:knobs-fade-a linear both,knobs-fade-b linear both;animation-duration:auto;
738
+ animation-timeline:scroll(self block),scroll(self block);animation-range:0 var(--knobs-fade-travel),calc(100% - var(--knobs-fade-travel)) 100%}
739
+ .knobs-scroll-fade{--knobs-fade-mask:linear-gradient(to bottom,#000 var(--knobs-fade-inset,0px),rgb(0 0 0/var(--knobs-fade-a)) var(--knobs-fade-inset,0px),#000 calc(var(--knobs-fade-inset,0px) + var(--knobs-fade)),#000 calc(100% - var(--knobs-fade)),rgb(0 0 0/var(--knobs-fade-b)));-webkit-mask-image:var(--knobs-fade-mask);mask-image:var(--knobs-fade-mask)}
740
+ .knobs-scroll-fade-x{--knobs-fade:16px;--knobs-fade-travel:4px;animation-timeline:scroll(self inline),scroll(self inline);
741
+ --knobs-fade-mask:linear-gradient(to right,rgb(0 0 0/var(--knobs-fade-a)),#000 var(--knobs-fade),#000 calc(100% - var(--knobs-fade)),rgb(0 0 0/var(--knobs-fade-b)));-webkit-mask-image:var(--knobs-fade-mask);mask-image:var(--knobs-fade-mask)}
742
+ .knobs-scroll-fade:has(.knobs-panel[data-gpu-active="true"]){-webkit-mask-image:none;mask-image:none}
743
+ .knobs-tree-row[data-editing] .knobs-tree-label{-webkit-mask-image:none;mask-image:none}
744
+ }
745
+ @supports not (animation-timeline:scroll()){.knobs-scroll-fade-x{text-overflow:ellipsis}}
746
+
491
747
  /* Split: panes along a row or column, hairline dividers with a wider grip. */
492
748
  .knobs-split{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden}
493
749
  .knobs-split[data-direction="column"]{flex-direction:column}
@@ -500,7 +756,7 @@ var css = `
500
756
  .knobs-pane-inner{position:absolute;inset:0;display:flex;flex-direction:column;min-width:0;min-height:0}
501
757
  .knobs-pane-body{position:relative;flex:1;min-width:0;min-height:0;overflow:hidden}
502
758
  .knobs-pane[data-scroll] .knobs-pane-body{overflow:auto;scrollbar-width:thin}
503
- .knobs-pane[data-rail][data-collapsed][data-settled]>.knobs-pane-clip,.knobs-pane:not([data-rail])[data-collapsed][data-settled]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-body{visibility:hidden}
759
+ .knobs-pane[data-rail][data-collapsed][data-settled]>.knobs-pane-clip>.knobs-pane-inner,.knobs-pane:not([data-rail])[data-collapsed][data-settled]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-body{visibility:hidden}
504
760
  .knobs-ui .knobs-pane-head{display:flex;align-items:center;gap:6px;flex:none;height:var(--ku-row);padding:0 calc(var(--ku-inset) - 4px) 0 var(--ku-inset);user-select:none;-webkit-user-select:none}
505
761
  .knobs-pane-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:var(--ku-title-weight);color:var(--ku-text)}
506
762
  .knobs-pane-count{flex:none;color:var(--ku-dim);font-variant-numeric:tabular-nums}
@@ -511,17 +767,31 @@ var css = `
511
767
  .knobs-ui .knobs-pane-btn[aria-pressed="true"]{color:var(--ku-accent)}
512
768
  .knobs-pane-btn svg{width:13px;height:13px}
513
769
  .knobs-pane-head[data-toggles]{cursor:pointer}
514
- .knobs-pane-caret{transition:transform var(--ku-ease-ms) var(--ku-ease)}
515
- .knobs-pane[data-collapsed] .knobs-pane-caret{transform:rotate(-90deg)}
516
- /* A collapsed pane's rail: its title along the edge; a click opens it. */
517
- .knobs-ui .knobs-pane-rail{position:absolute;inset:0;margin:var(--ku-pane-m);border-radius:var(--ku-pane-radius);background-color:var(--ku-pane-bg);box-shadow:var(--ku-pane-ring);display:flex;align-items:center;gap:8px;color:var(--ku-label);cursor:pointer;opacity:0;pointer-events:none;
770
+ /* A collapsed pane's rail: its title along the edge; a click opens it. It holds on to the edge the
771
+ pane folds toward, as wide as the rail, over the card (which folds to its size): only its label
772
+ and chevron draw, and a nested split's slot, which has no card, gives it one of its own. */
773
+ .knobs-ui .knobs-pane-rail{position:absolute;margin:var(--ku-pane-m);border-radius:var(--ku-pane-radius);background-color:transparent;display:flex;align-items:center;gap:8px;color:var(--ku-label);cursor:pointer;opacity:0;pointer-events:none;
518
774
  font-weight:var(--ku-title-weight);transition:background .15s,color .15s}
519
- .knobs-split[data-direction="row"]>.knobs-pane>.knobs-pane-rail{writing-mode:vertical-rl;padding:10px 0}
520
- .knobs-split[data-direction="column"]>.knobs-pane>.knobs-pane-rail{padding:0 var(--ku-inset)}
775
+ .knobs-ui .knobs-pane[data-nested]>.knobs-pane-rail{background-color:var(--ku-pane-bg);box-shadow:var(--ku-pane-ring)}
776
+ .knobs-split[data-direction="row"]>.knobs-pane>.knobs-pane-rail{top:0;bottom:0;width:var(--ku-rail);writing-mode:vertical-rl;padding:10px 0}
777
+ .knobs-split[data-direction="row"]>.knobs-pane[data-edge="start"]>.knobs-pane-rail{right:0}
778
+ .knobs-split[data-direction="row"]>.knobs-pane[data-edge="end"]>.knobs-pane-rail{left:0}
779
+ .knobs-split[data-direction="column"]>.knobs-pane>.knobs-pane-rail{left:0;right:0;height:var(--ku-rail);padding:0 var(--ku-inset)}
780
+ .knobs-split[data-direction="column"]>.knobs-pane[data-edge="start"]>.knobs-pane-rail{bottom:0}
781
+ .knobs-split[data-direction="column"]>.knobs-pane[data-edge="end"]>.knobs-pane-rail{top:0}
521
782
  .knobs-pane[data-collapsed]>.knobs-pane-rail{pointer-events:auto}
522
- .knobs-ui .knobs-pane-rail:is(:hover,:focus-visible){background-image:linear-gradient(var(--ku-wash),var(--ku-wash));color:var(--ku-text)}
523
- .knobs-pane-rail span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
524
- .knobs-pane-rail svg{width:11px;height:11px;color:var(--ku-dim);writing-mode:horizontal-tb}
783
+ .knobs-ui .knobs-pane[data-collapsed]>.knobs-pane-rail:is(:hover,:focus-visible){background-image:linear-gradient(var(--ku-wash),var(--ku-wash));color:var(--ku-text)}
784
+ .knobs-pane-rail-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
785
+ .knobs-pane-chevron{display:flex;flex:none;width:11px;height:11px;writing-mode:horizontal-tb;color:var(--ku-dim)}
786
+ .knobs-pane-turn{display:flex;width:100%;height:100%;transform-origin:50% 50%}
787
+ .knobs-pane-rail svg{width:11px;height:11px}
788
+ /* The rail's chevron stands in for the header's collapse icon (it turns into the rail's), so the
789
+ icon itself isn't drawn; hovering its button lights the chevron instead. */
790
+ .knobs-pane[data-morph]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head>.knobs-pane-collapse>svg{visibility:hidden}
791
+ /* So does the rail's label for the title, when it travels (split's fold: { title: "travel" }). */
792
+ .knobs-pane[data-travel]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head>.knobs-pane-title{visibility:hidden}
793
+ .knobs-pane[data-morph]:not([data-collapsed]):has(>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head>.knobs-pane-collapse:is(:hover,:focus-visible))>.knobs-pane-rail .knobs-pane-chevron{color:var(--ku-text)}
794
+ .knobs-pane[data-morph]:not([data-collapsed])>.knobs-pane-rail .knobs-pane-chevron{transition:color .15s}
525
795
 
526
796
  .knobs-divider{position:relative;z-index:2;flex:none;width:1px;background:var(--ku-divider);touch-action:none;outline:none}
527
797
  .knobs-split[data-direction="column"]>.knobs-divider{width:auto;height:1px}
@@ -564,7 +834,7 @@ var css = `
564
834
  .knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
565
835
  .knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
566
836
  .knobs-tree-icon{flex:none;display:flex;align-items:center;justify-content:center;width:14px;margin-right:6px;color:var(--ku-dim);font-size:calc(var(--ku-font-size) - 1px)}
567
- .knobs-tree-label{position:relative;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;font-weight:var(--ku-font-weight)}
837
+ .knobs-tree-label{position:relative;flex:1;min-width:0;overflow:hidden;font-weight:var(--ku-font-weight)}
568
838
  .knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--ku-label)}
569
839
  .knobs-tree-label .knobs-tree-mark{color:var(--ku-accent)}
570
840
  .knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
@@ -602,7 +872,7 @@ var css = `
602
872
  .knobs-tl-play svg{width:12px;height:12px}
603
873
  .knobs-timeline[data-playing] .knobs-tl-play{background:var(--ku-accent);color:var(--ku-bg)}
604
874
  .knobs-tl-time{display:flex;flex-direction:column;line-height:1.2;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
605
- .knobs-tl-now{font:var(--ku-font-weight) var(--ku-value-size)/1.2 var(--ku-value-font);color:var(--ku-text);white-space:nowrap}
875
+ .knobs-tl-now{font:var(--ku-font-weight) var(--ku-value-size)/1.2 var(--ku-value-font);font-variant-numeric:tabular-nums;font-feature-settings:"tnum";color:var(--ku-text);white-space:nowrap}
606
876
  .knobs-tl-sub{font-size:var(--ku-text-meta);color:var(--ku-dim);white-space:nowrap}
607
877
  .knobs-tl-track{position:relative;flex:1;min-width:0;overflow:hidden;border-radius:var(--ku-radius);background:var(--ku-surface);cursor:col-resize;touch-action:none;
608
878
  transition:background calc(var(--ku-hover-out) * 1ms)}
@@ -654,7 +924,7 @@ function injectUiStyles(doc) {
654
924
  return;
655
925
  const style = doc.createElement("style");
656
926
  style.dataset.knobsUi = "";
657
- style.textContent = css + readoutCss + overlayCss + bentoCss;
927
+ style.textContent = css + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + rolling_css_default;
658
928
  doc.head.append(style);
659
929
  }
660
930
  function injectUiPreset(doc, preset) {
@@ -743,6 +1013,12 @@ function injectPanelPreset(doc, preset) {
743
1013
  doc.head.append(style);
744
1014
  }
745
1015
  var reducedMotion = (win) => win?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
1016
+ var tune = (s, m) => {
1017
+ s.omega = m.omega;
1018
+ s.zeta = m.zeta;
1019
+ return s;
1020
+ };
1021
+ var isTypingTarget = (t) => t instanceof HTMLElement && (t.isContentEditable || t instanceof HTMLSelectElement || t instanceof HTMLTextAreaElement || t instanceof HTMLInputElement && !t.readOnly && !["range", "checkbox", "radio", "button"].includes(t.type));
746
1022
  function notifyLayout(doc) {
747
1023
  doc.dispatchEvent(new Event("knobs-layout"));
748
1024
  }
@@ -928,14 +1204,6 @@ function comboParts(combo, apple = isApple()) {
928
1204
  var READOUT_KINDS = new Set(["watch", "sparkline", "graph", "meter", "table", "log"]);
929
1205
  var isReadout = (field) => READOUT_KINDS.has(field.kind);
930
1206
  var hasValue = (field) => field.kind !== "action" && field.kind !== "toolbar" && !READOUT_KINDS.has(field.kind);
931
- function toolbarShortcut(item) {
932
- const s = item.shortcut;
933
- if (!s)
934
- return;
935
- if (typeof s === "string")
936
- return { key: s, scope: item.global ? "page" : "panel" };
937
- return s.key ? { key: s.key, scope: s.scope ?? (item.global ? "page" : "panel") } : undefined;
938
- }
939
1207
 
940
1208
  // src/ui/commands.ts
941
1209
  var labelOf = (key, field) => field.label ?? key;
@@ -946,12 +1214,16 @@ function commandsFrom(controls, options = {}) {
946
1214
  const id = (s) => `${controls.id}:${s}`;
947
1215
  const schema = controls.schema;
948
1216
  for (const [key, field] of Object.entries(schema)) {
1217
+ const keyOf = (item) => {
1218
+ const combo = controls.shortcut(key, item);
1219
+ return combo ? { shortcut: combo } : {};
1220
+ };
949
1221
  if (field.kind === "action")
950
1222
  out.push({
951
1223
  id: id(key),
952
1224
  label: labelOf(key, field),
953
1225
  section: sec(field.group ? controls.groupLabel(field.group) ?? field.group : "Actions"),
954
- ...field.shortcut ? { shortcut: field.shortcut } : {},
1226
+ ...keyOf(),
955
1227
  disabled: controls.isDisabled(key),
956
1228
  run: () => controls.action(key)
957
1229
  });
@@ -961,7 +1233,7 @@ function commandsFrom(controls, options = {}) {
961
1233
  id: id(`${key}/${item.id ?? item.label}`),
962
1234
  label: item.label,
963
1235
  section: sec(field.label ?? "Actions"),
964
- ...toolbarShortcut(item) ? { shortcut: toolbarShortcut(item).key } : {},
1236
+ ...keyOf(item.id ?? item.label),
965
1237
  ...item.disabled ? { disabled: true } : {},
966
1238
  run: () => controls.action(key, item.id ?? item.label)
967
1239
  });
@@ -2346,7 +2618,7 @@ function commandPalette(options) {
2346
2618
  input.value = query;
2347
2619
  field.append(input);
2348
2620
  const list = doc.createElement("div");
2349
- list.className = "knobs-palette-list";
2621
+ list.className = "knobs-palette-list knobs-scroll-fade";
2350
2622
  list.setAttribute("role", "listbox");
2351
2623
  list.id = `knobs-palette-list-${Math.random().toString(36).slice(2, 8)}`;
2352
2624
  input.setAttribute("aria-controls", list.id);
@@ -5408,6 +5680,43 @@ function edgeOf(panes, id) {
5408
5680
  const first = panes.findIndex((p) => flex.has(p.id));
5409
5681
  return panes.findIndex((p) => p.id === id) < first ? "start" : "end";
5410
5682
  }
5683
+ function foldProgress(size, open, rail) {
5684
+ const span = open - rail;
5685
+ if (span <= 0)
5686
+ return size > rail ? 0 : 1;
5687
+ return Math.min(1, Math.max(0, (open - size) / span));
5688
+ }
5689
+ var FACE_OUT = 0.4;
5690
+ var FACE_IN = 0.3;
5691
+ var clamp01 = (x) => Math.min(1, Math.max(0, x));
5692
+ function face(prev, away) {
5693
+ const lo = clamp01(1 - away / FACE_IN);
5694
+ const hi = clamp01(1 - away / FACE_OUT);
5695
+ return Math.min(hi, Math.max(lo, prev));
5696
+ }
5697
+ function foldFaces(prev, p) {
5698
+ return { content: face(prev.content, p), rail: face(prev.rail, 1 - p) };
5699
+ }
5700
+ function chevronTurn(p, edge) {
5701
+ return (edge === "start" ? 180 : -180) * (1 - clamp01(p));
5702
+ }
5703
+ function chevronFlip(f) {
5704
+ return 2 * clamp01(f) - 1;
5705
+ }
5706
+ var FOLD_STYLE = { chevron: "flip", title: "travel", duration: 0.3 };
5707
+ function foldStyle(options = {}) {
5708
+ const duration = options.duration;
5709
+ return {
5710
+ chevron: options.chevron === "turn" ? "turn" : "flip",
5711
+ title: options.title === "fade" ? "fade" : "travel",
5712
+ duration: duration !== undefined && Number.isFinite(duration) && duration > 0 ? Math.min(2, duration) : FOLD_STYLE.duration
5713
+ };
5714
+ }
5715
+ function titleTravel(at, open, rail, edge, p) {
5716
+ const k = 1 - clamp01(p);
5717
+ const dx = at.title - at.label - (edge === "start" ? open - rail : 0);
5718
+ return { x: dx * k, y: at.dy * k, turn: -90 * k };
5719
+ }
5411
5720
  function parseLayout(raw, panes) {
5412
5721
  if (!raw || typeof raw !== "object")
5413
5722
  return;
@@ -5435,8 +5744,24 @@ function serializeLayout(layout) {
5435
5744
  }
5436
5745
 
5437
5746
  // src/ui/split.ts
5438
- var COLLAPSE = springMotion({ duration: 0.42, bounce: 0.04 });
5747
+ var FLIP = springMotion({ duration: 0.18, bounce: 0 });
5439
5748
  var SETTLE = springMotion({ duration: 0.3, bounce: 0 });
5749
+ var CONTENT_BLUR = 3;
5750
+ var LABEL_BLUR = 2;
5751
+ var put = (el, prop, value) => {
5752
+ if (el.style.getPropertyValue(prop) !== value)
5753
+ el.style.setProperty(prop, value);
5754
+ };
5755
+ var hide = (el, hidden) => {
5756
+ if (hidden)
5757
+ el.setAttribute("aria-hidden", "true");
5758
+ else
5759
+ el.removeAttribute("aria-hidden");
5760
+ };
5761
+ var fade = (el, a, blur) => {
5762
+ put(el, "opacity", a >= 1 ? "" : a.toFixed(3));
5763
+ put(el, "filter", a >= 1 || a <= 0 || !blur ? "" : `blur(${(blur * (1 - a)).toFixed(2)}px)`);
5764
+ };
5440
5765
  var iconNode = (doc, icon, label) => {
5441
5766
  if (icon instanceof Node)
5442
5767
  return icon;
@@ -5455,6 +5780,8 @@ function split(container, options) {
5455
5780
  const row = direction === "row";
5456
5781
  const specs = options.panes;
5457
5782
  const flex = flexible(specs);
5783
+ const style = foldStyle(options.fold);
5784
+ const COLLAPSE = springMotion({ duration: style.duration, bounce: 0 });
5458
5785
  const store = options.storage === undefined ? browserStorage() : options.storage;
5459
5786
  const key = options.id ? storageKey(options.id, "split") : undefined;
5460
5787
  const saved = (() => {
@@ -5483,13 +5810,31 @@ function split(container, options) {
5483
5810
  const el = doc.createElement("section");
5484
5811
  el.className = "knobs-pane";
5485
5812
  el.dataset.pane = spec.id;
5813
+ const edge = edgeOf(specs, spec.id);
5814
+ el.dataset.edge = edge;
5486
5815
  const clip = doc.createElement("div");
5487
5816
  clip.className = "knobs-pane-clip";
5488
5817
  const inner = doc.createElement("div");
5489
5818
  inner.className = "knobs-pane-inner";
5490
5819
  const body = doc.createElement("div");
5491
5820
  body.className = "knobs-pane-body";
5492
- const view = { spec, el, clip, inner, body, open: 0, shown: 0 };
5821
+ const shut = Boolean(collapsed[spec.id]);
5822
+ const view = {
5823
+ spec,
5824
+ el,
5825
+ clip,
5826
+ inner,
5827
+ body,
5828
+ edge,
5829
+ open: 0,
5830
+ shown: 0,
5831
+ folding: false,
5832
+ faces: { content: shut ? 0 : 1, rail: shut ? 1 : 0 },
5833
+ headPx: 0,
5834
+ chev: { iconEnd: 0, chevEnd: 0, dy: 0, scale: 1 },
5835
+ places: { title: 0, label: 0, dy: 0 },
5836
+ flip: new Spring(shut ? 1 : 0, FLIP.omega, FLIP.zeta, 0.002)
5837
+ };
5493
5838
  if (spec.title !== undefined) {
5494
5839
  const head = doc.createElement("header");
5495
5840
  head.className = "knobs-pane-head";
@@ -5527,9 +5872,10 @@ function split(container, options) {
5527
5872
  tooltip(b, () => collapsed[spec.id] ? "Open" : row ? "Collapse" : "Fold");
5528
5873
  b.innerHTML = row ? ICONS.caret : ICONS.chevronDown;
5529
5874
  if (row)
5530
- b.firstElementChild?.setAttribute("style", edgeOf(specs, spec.id) === "start" ? "transform:scaleX(-1)" : "");
5875
+ b.firstElementChild?.setAttribute("style", edge === "start" ? "transform:scaleX(-1)" : "");
5531
5876
  else
5532
5877
  b.firstElementChild?.classList.add("knobs-pane-caret");
5878
+ view.toggleIcon = b.firstElementChild ?? undefined;
5533
5879
  b.addEventListener("click", (e) => {
5534
5880
  e.stopPropagation();
5535
5881
  setCollapsed(spec.id, !collapsed[spec.id]);
@@ -5548,8 +5894,10 @@ function split(container, options) {
5548
5894
  inner.append(body);
5549
5895
  clip.append(inner);
5550
5896
  el.append(clip);
5551
- if (spec.scroll ?? spec.title !== undefined)
5897
+ if (spec.scroll ?? spec.title !== undefined) {
5552
5898
  el.dataset.scroll = "";
5899
+ body.classList.add("knobs-scroll-fade");
5900
+ }
5553
5901
  if (spec.element)
5554
5902
  body.append(spec.element);
5555
5903
  if (spec.collapsible && (row || !view.head)) {
@@ -5561,13 +5909,22 @@ function split(container, options) {
5561
5909
  rail.setAttribute("aria-label", `Open ${label}`);
5562
5910
  tooltip(rail, `Open ${label}`, { placement: row ? "right" : "top" });
5563
5911
  const text = doc.createElement("span");
5912
+ text.className = "knobs-pane-rail-label";
5564
5913
  text.textContent = spec.rail ?? spec.title ?? "";
5565
- rail.innerHTML = row ? ICONS.caret.replace("<svg", `<svg style="transform:scaleX(${edgeOf(specs, spec.id) === "start" ? 1 : -1})"`) : ICONS.chevronDown;
5566
- rail.append(text);
5914
+ const chevron = doc.createElement("span");
5915
+ chevron.className = "knobs-pane-chevron";
5916
+ const turn = doc.createElement("span");
5917
+ turn.className = "knobs-pane-turn";
5918
+ turn.innerHTML = row ? ICONS.caret.replace("<svg", `<svg style="transform:scaleX(${edge === "start" ? 1 : -1})"`) : ICONS.chevronDown;
5919
+ chevron.append(turn);
5920
+ rail.append(chevron, text);
5567
5921
  rail.addEventListener("click", () => setCollapsed(spec.id, false));
5568
5922
  el.append(rail);
5569
5923
  el.dataset.rail = "";
5570
5924
  view.rail = rail;
5925
+ view.railLabel = text;
5926
+ view.chevron = chevron;
5927
+ view.turn = turn;
5571
5928
  }
5572
5929
  return view;
5573
5930
  };
@@ -5597,9 +5954,10 @@ function split(container, options) {
5597
5954
  const total = () => along(root);
5598
5955
  let paneM = 0;
5599
5956
  const marginOf = (v) => v.el.hasAttribute("data-nested") ? 0 : paneM;
5600
- const headerSize = (v) => v.head ? v.head.getBoundingClientRect().height + marginOf(v) * 2 : 0;
5957
+ const headerSize = (v) => v.head ? v.headPx + marginOf(v) * 2 : 0;
5601
5958
  let railPx = 0;
5602
- const readRail = () => {
5959
+ let measured = false;
5960
+ const measure = () => {
5603
5961
  syncFrame(root);
5604
5962
  const probe = doc.createElement("div");
5605
5963
  probe.style.cssText = "position:absolute;visibility:hidden;width:var(--ku-rail);height:var(--ku-pane-m)";
@@ -5608,8 +5966,44 @@ function split(container, options) {
5608
5966
  paneM = r.height;
5609
5967
  railPx = (r.width || 26) + paneM * 2;
5610
5968
  probe.remove();
5969
+ for (const v of views.values())
5970
+ if (v.head)
5971
+ v.headPx = v.head.getBoundingClientRect().height;
5972
+ measured = root.isConnected && r.width > 0;
5973
+ };
5974
+ const measureChevrons = (only) => {
5975
+ if (!row)
5976
+ return;
5977
+ for (const v of only ? [only] : views.values()) {
5978
+ if (!v.chevron || !v.toggleIcon || !v.rail || !v.railLabel)
5979
+ continue;
5980
+ const inner = v.inner.getBoundingClientRect();
5981
+ const icon = v.toggleIcon.getBoundingClientRect();
5982
+ const rail = v.rail.getBoundingClientRect();
5983
+ const chev = v.chevron.getBoundingClientRect();
5984
+ if (!inner.width || !chev.width)
5985
+ continue;
5986
+ v.chev = {
5987
+ iconEnd: inner.right - (icon.left + icon.width / 2),
5988
+ chevEnd: rail.right - (chev.left + chev.width / 2),
5989
+ dy: icon.top + icon.height / 2 - inner.top - (chev.top + chev.height / 2 - rail.top),
5990
+ scale: icon.width / chev.width
5991
+ };
5992
+ if (!v.titleEl)
5993
+ continue;
5994
+ const moved = v.railLabel.style.transform;
5995
+ v.railLabel.style.transform = "none";
5996
+ const label = v.railLabel.getBoundingClientRect();
5997
+ v.railLabel.style.transform = moved;
5998
+ const title = v.titleEl.getBoundingClientRect();
5999
+ v.places = {
6000
+ title: title.left + title.width / 2 - inner.left,
6001
+ label: label.left + label.width / 2 - rail.left,
6002
+ dy: title.top + title.height / 2 - inner.top - (label.top + label.height / 2 - rail.top)
6003
+ };
6004
+ }
5611
6005
  };
5612
- readRail();
6006
+ measure();
5613
6007
  const rail = (id) => {
5614
6008
  const v = views.get(id);
5615
6009
  return !row && v.head ? headerSize(v) : railPx;
@@ -5622,47 +6016,102 @@ function split(container, options) {
5622
6016
  };
5623
6017
  const target = () => solve({ panes: specs, sizes, collapsed, total: total(), rail });
5624
6018
  const current = () => solve({ panes: specs, sizes, collapsed, total: total(), rail, fixed: fixed() });
6019
+ const SIDES = { row: ["right", "left"], column: ["bottom", "top"] };
6020
+ const sides = (v) => {
6021
+ const [a, b] = SIDES[direction];
6022
+ return v.edge === "start" ? [a, b] : [b, a];
6023
+ };
6024
+ const renderFold = (v, size) => {
6025
+ const id = v.spec.id;
6026
+ const isCollapsed = collapsed[id];
6027
+ const folding = isCollapsed || v.folding;
6028
+ const r = rail(id);
6029
+ const open = folding ? Math.max(v.open, r + 1) : size;
6030
+ const p = folding ? foldProgress(size, open, r) : 0;
6031
+ v.faces = foldFaces(v.faces, p);
6032
+ const m = marginOf(v);
6033
+ const settled = !springs.has(id);
6034
+ const content = isCollapsed && settled ? 1 : v.faces.content;
6035
+ put(v.rail ? v.inner : v.body, "will-change", v.folding ? "opacity, filter" : "");
6036
+ if (!v.rail) {
6037
+ put(v.inner, "height", folding ? `${open - m * 2}px` : "");
6038
+ put(v.inner, "bottom", folding ? "auto" : "");
6039
+ fade(v.body, content, CONTENT_BLUR);
6040
+ if (v.toggleIcon)
6041
+ put(v.toggleIcon, "transform", p ? `rotate(${(-90 * p).toFixed(2)}deg)` : "");
6042
+ hide(v.body, isCollapsed && settled);
6043
+ return;
6044
+ }
6045
+ const [side, far] = sides(v);
6046
+ put(v.inner, row ? "width" : "height", folding ? `${open - m * 2}px` : "");
6047
+ put(v.inner, side, folding ? "0" : "");
6048
+ put(v.inner, far, folding ? "auto" : "");
6049
+ fade(v.inner, content, CONTENT_BLUR);
6050
+ hide(v.clip, isCollapsed && settled);
6051
+ const morph = row && Boolean(v.toggleIcon) && !v.el.hasAttribute("data-nested");
6052
+ v.el.toggleAttribute("data-morph", morph);
6053
+ const label = v.railLabel;
6054
+ const travel = morph && style.title === "travel" && Boolean(v.titleEl) && label.textContent === v.titleEl.textContent;
6055
+ v.el.toggleAttribute("data-travel", travel && folding);
6056
+ const k = 1 - p;
6057
+ if (travel && !folding) {
6058
+ put(label, "opacity", "0");
6059
+ put(label, "filter", "");
6060
+ put(label, "transform", "");
6061
+ put(label, "color", "");
6062
+ } else if (travel) {
6063
+ const t = titleTravel(v.places, open, r, v.edge, p);
6064
+ put(label, "opacity", "");
6065
+ put(label, "filter", "");
6066
+ put(label, "transform", k === 0 ? "" : `translate(${t.x.toFixed(2)}px,${t.y.toFixed(2)}px) rotate(${t.turn.toFixed(2)}deg)`);
6067
+ put(label, "color", k === 0 ? "" : `color-mix(in srgb,var(--ku-text) ${(k * 100).toFixed(1)}%,var(--ku-label))`);
6068
+ } else {
6069
+ put(label, "transform", "");
6070
+ put(label, "color", "");
6071
+ }
6072
+ if (morph) {
6073
+ put(v.rail, "opacity", "1");
6074
+ if (!travel)
6075
+ fade(label, v.faces.rail, LABEL_BLUR);
6076
+ const c = v.chev;
6077
+ const dx = c.chevEnd - c.iconEnd + (v.edge === "end" ? open - r : 0);
6078
+ const move = `translate(${(dx * k).toFixed(2)}px,${(c.dy * k).toFixed(2)}px)`;
6079
+ const size = `scale(${(1 + (c.scale - 1) * k).toFixed(4)})`;
6080
+ if (style.chevron === "turn")
6081
+ put(v.turn, "transform", k === 0 ? "" : `${move} rotate(${chevronTurn(p, v.edge).toFixed(2)}deg) ${size}`);
6082
+ else {
6083
+ const w = chevronFlip(v.flip.x);
6084
+ put(v.turn, "transform", k === 0 && w === 1 ? "" : `${move} ${size} scaleX(${w.toFixed(4)})`);
6085
+ }
6086
+ } else {
6087
+ const a = v.faces.rail;
6088
+ put(v.rail, "opacity", a >= 1 ? "1" : a.toFixed(3));
6089
+ put(label, "opacity", "");
6090
+ put(label, "filter", a >= 1 || a <= 0 ? "" : `blur(${(LABEL_BLUR * (1 - a)).toFixed(2)}px)`);
6091
+ put(v.turn, "transform", "");
6092
+ }
6093
+ };
5625
6094
  let lastReport = "";
5626
6095
  const render = (shown) => {
5627
6096
  for (const spec of specs) {
5628
6097
  const v = views.get(spec.id);
5629
6098
  const size = Math.max(0, shown[spec.id] ?? 0);
5630
6099
  v.shown = size;
5631
- v.el.style.flexBasis = `${size}px`;
5632
- v.el.style[row ? "width" : "height"] = `${size}px`;
5633
- const isCollapsed = collapsed[spec.id];
5634
- const moving = springs.has(spec.id);
5635
- v.el.toggleAttribute("data-collapsed", isCollapsed);
5636
- v.el.toggleAttribute("data-settled", !moving);
5637
- v.el.setAttribute("aria-hidden", String(isCollapsed && !moving));
5638
- const r = rail(spec.id);
5639
- const open = Math.max(v.open, r + 1);
5640
- const m = marginOf(v);
5641
- if (moving || isCollapsed) {
5642
- const p = Math.min(1, Math.max(0, (open - size) / (open - r)));
5643
- if (v.rail) {
5644
- const visible = Math.max(0, (size - r) / (open - r) * open);
5645
- const edge = edgeOf(specs, spec.id);
5646
- const side = row ? edge === "start" ? "right" : "left" : edge === "start" ? "bottom" : "top";
5647
- v.clip.style.cssText = `${row ? "width" : "height"}:${Math.max(0, visible - m * 2)}px;${side}:0;${row ? side === "right" ? "left:auto" : "right:auto" : side === "bottom" ? "top:auto" : "bottom:auto"}`;
5648
- v.inner.style.cssText = `${row ? "width" : "height"}:${open - m * 2}px;${side}:0;${row ? side === "right" ? "left:auto" : "right:auto" : side === "bottom" ? "top:auto" : "bottom:auto"}`;
5649
- v.rail.style.opacity = String(Math.max(0, (p - 0.35) / 0.65));
5650
- } else {
5651
- v.clip.style.cssText = "";
5652
- v.inner.style.cssText = `height:${open - m * 2}px;bottom:auto`;
5653
- }
5654
- } else {
5655
- v.clip.style.cssText = "";
5656
- v.inner.style.cssText = "";
5657
- if (v.rail)
5658
- v.rail.style.opacity = "0";
5659
- }
6100
+ put(v.el, "flex-basis", `${size}px`);
6101
+ put(v.el, row ? "width" : "height", `${size}px`);
6102
+ v.el.toggleAttribute("data-collapsed", collapsed[spec.id]);
6103
+ v.el.toggleAttribute("data-settled", !springs.has(spec.id));
6104
+ if (spec.collapsible)
6105
+ renderFold(v, size);
5660
6106
  }
5661
6107
  dividers.forEach((d, i) => {
5662
6108
  const a = specs[i];
5663
6109
  const b = specs[i + 1];
5664
- d.setAttribute("aria-valuenow", String(Math.round(views.get(a.id).shown)));
5665
- d.setAttribute("aria-controls", `${a.id} ${b.id}`);
6110
+ const now = String(Math.round(views.get(a.id).shown));
6111
+ if (d.getAttribute("aria-valuenow") !== now)
6112
+ d.setAttribute("aria-valuenow", now);
6113
+ if (!d.hasAttribute("aria-controls"))
6114
+ d.setAttribute("aria-controls", `${a.id} ${b.id}`);
5666
6115
  });
5667
6116
  const layout = snapshot();
5668
6117
  const report = JSON.stringify(layout);
@@ -5695,51 +6144,76 @@ function split(container, options) {
5695
6144
  const loop = frameLoop(win, (dt) => {
5696
6145
  for (const [id, s] of springs) {
5697
6146
  s.step(dt);
5698
- if (s.resting)
6147
+ if (s.resting) {
5699
6148
  springs.delete(id);
6149
+ views.get(id).folding = false;
6150
+ }
6151
+ }
6152
+ let flipping = false;
6153
+ for (const v of views.values()) {
6154
+ v.flip.step(dt);
6155
+ if (!v.flip.resting)
6156
+ flipping = true;
5700
6157
  }
5701
6158
  const shown = current();
5702
- render(shown);
5703
- if (springs.size === 0) {
6159
+ if (springs.size === 0)
5704
6160
  rememberOpen(shown);
5705
- render(shown);
5706
- }
5707
- return springs.size > 0;
6161
+ render(shown);
6162
+ return springs.size > 0 || flipping;
5708
6163
  });
5709
6164
  const animate = (motion = SETTLE) => {
5710
6165
  const to = target();
6166
+ for (const v of views.values())
6167
+ if (v.folding && !collapsed[v.spec.id])
6168
+ v.open = to[v.spec.id];
5711
6169
  if (reducedMotion(win)) {
5712
6170
  springs.clear();
5713
- render(to);
6171
+ const arriving = [...views.values()].filter((v) => v.folding).map((v) => collapsed[v.spec.id] ? v.rail : v.rail ? v.inner : v.body);
6172
+ for (const v of views.values()) {
6173
+ v.folding = false;
6174
+ v.flip.snap(collapsed[v.spec.id] ? 1 : 0);
6175
+ }
5714
6176
  rememberOpen(to);
6177
+ render(to);
6178
+ for (const el of arriving)
6179
+ el?.animate([{ opacity: 0 }, { opacity: 1 }], {
6180
+ duration: 160,
6181
+ easing: "cubic-bezier(.2,.8,.2,1)"
6182
+ });
5715
6183
  return;
5716
6184
  }
5717
6185
  for (const spec of specs) {
5718
- const from = views.get(spec.id).shown;
6186
+ const v = views.get(spec.id);
5719
6187
  const goal = to[spec.id];
5720
6188
  const s = springs.get(spec.id);
5721
6189
  if (s) {
5722
6190
  s.omega = motion.omega;
5723
6191
  s.zeta = motion.zeta;
5724
6192
  s.set(goal);
5725
- } else if (Math.abs(goal - from) > 0.5) {
5726
- springs.set(spec.id, new Spring(from, motion.omega, motion.zeta, 0.2).set(goal));
5727
- }
6193
+ } else if (Math.abs(goal - v.shown) > 0.5) {
6194
+ springs.set(spec.id, new Spring(v.shown, motion.omega, motion.zeta, 0.2).set(goal));
6195
+ } else
6196
+ v.folding = false;
5728
6197
  }
5729
6198
  loop.wake();
5730
6199
  };
6200
+ const fold = (id, value) => {
6201
+ const v = views.get(id);
6202
+ if (value && !v.folding)
6203
+ v.open = v.shown;
6204
+ collapsed[id] = value;
6205
+ v.folding = true;
6206
+ v.flip.set(value ? 1 : 0);
6207
+ };
6208
+ const release = (id) => {
6209
+ springs.delete(id);
6210
+ views.get(id).folding = false;
6211
+ };
5731
6212
  function setCollapsed(id, value, save = true) {
5732
6213
  const spec = specs.find((p) => p.id === id);
5733
6214
  if (!spec?.collapsible || collapsed[id] === value)
5734
6215
  return;
5735
- const v = views.get(id);
5736
- if (value && !springs.has(id))
5737
- v.open = v.shown;
5738
- if (!value) {
5739
- collapsed[id] = false;
5740
- v.open = target()[id];
5741
- }
5742
- collapsed[id] = value;
6216
+ fold(id, value);
5743
6217
  if (save)
5744
6218
  persist();
5745
6219
  animate(COLLAPSE);
@@ -5761,7 +6235,8 @@ function split(container, options) {
5761
6235
  d.focus({ preventScroll: true });
5762
6236
  const shown = current();
5763
6237
  for (const id of [a.id, b.id])
5764
- springs.delete(id);
6238
+ if (!collapsed[id])
6239
+ release(id);
5765
6240
  start = { ...shown };
5766
6241
  for (const id of [a.id, b.id])
5767
6242
  if (collapsed[id])
@@ -5795,7 +6270,7 @@ function split(container, options) {
5795
6270
  return;
5796
6271
  setSizes(result.sizes);
5797
6272
  for (const id of [a.id, b.id])
5798
- springs.delete(id);
6273
+ release(id);
5799
6274
  const shown = current();
5800
6275
  render(shown);
5801
6276
  rememberOpen(shown);
@@ -5858,17 +6333,21 @@ function split(container, options) {
5858
6333
  }
5859
6334
  function reset(...ids) {
5860
6335
  const which = ids.length ? ids : specs.map((p) => p.id);
6336
+ let folds = false;
5861
6337
  for (const id of which) {
5862
6338
  delete sizes[id];
5863
6339
  const spec = specs.find((p) => p.id === id);
5864
- if (spec?.collapsible)
5865
- collapsed[id] = Boolean(spec.collapsed);
6340
+ const shut = Boolean(spec?.collapsed);
6341
+ if (spec?.collapsible && collapsed[id] !== shut) {
6342
+ fold(id, shut);
6343
+ folds = true;
6344
+ }
5866
6345
  }
5867
6346
  if (which.some((id) => flex.has(id)))
5868
6347
  for (const id of flex)
5869
6348
  delete sizes[id];
5870
6349
  persist();
5871
- animate();
6350
+ animate(folds ? COLLAPSE : SETTLE);
5872
6351
  }
5873
6352
  {
5874
6353
  const first = target();
@@ -5877,18 +6356,29 @@ function split(container, options) {
5877
6356
  views.get(spec.id).open = collapsed[spec.id] ? solve({ panes: specs, sizes, collapsed: open, total: total(), rail })[spec.id] : first[spec.id];
5878
6357
  }
5879
6358
  render(first);
6359
+ measureChevrons();
6360
+ render(first);
5880
6361
  }
5881
- const relayout = () => {
5882
- readRail();
5883
- if (springs.size)
6362
+ const relayout = (remeasure) => {
6363
+ if (remeasure)
6364
+ measure();
6365
+ if (springs.size) {
6366
+ if (remeasure)
6367
+ measureChevrons();
5884
6368
  return loop.wake();
6369
+ }
5885
6370
  const shown = target();
5886
- render(shown);
5887
6371
  rememberOpen(shown);
6372
+ render(shown);
6373
+ if (remeasure) {
6374
+ measureChevrons();
6375
+ render(shown);
6376
+ }
5888
6377
  };
5889
- const ro = new ResizeObserver(relayout);
6378
+ const ro = new ResizeObserver(() => relayout(!measured));
5890
6379
  ro.observe(root);
5891
- root.addEventListener("knobs-restyle", relayout);
6380
+ const restyled = () => relayout(true);
6381
+ root.addEventListener("knobs-restyle", restyled);
5892
6382
  const paneApi = (id) => {
5893
6383
  const v = views.get(id);
5894
6384
  if (!v)
@@ -5911,9 +6401,9 @@ function split(container, options) {
5911
6401
  v.titleEl.textContent = text;
5912
6402
  if (v.countEl && count !== undefined)
5913
6403
  v.countEl.textContent = String(count);
5914
- const label = v.rail?.querySelector("span");
5915
- if (label)
5916
- label.textContent = text;
6404
+ if (v.railLabel)
6405
+ v.railLabel.textContent = text;
6406
+ measureChevrons(v);
5917
6407
  }
5918
6408
  };
5919
6409
  };
@@ -5948,7 +6438,7 @@ function split(container, options) {
5948
6438
  unregisterHints?.();
5949
6439
  loop.stop();
5950
6440
  ro.disconnect();
5951
- root.removeEventListener("knobs-restyle", relayout);
6441
+ root.removeEventListener("knobs-restyle", restyled);
5952
6442
  host?.removeAttribute("data-nested");
5953
6443
  root.remove();
5954
6444
  }
@@ -6980,7 +7470,7 @@ function tree(container, options) {
6980
7470
  let index = indexTree(items, access);
6981
7471
  const renamed = new Map;
6982
7472
  const root = doc.createElement("div");
6983
- root.className = "knobs-tree";
7473
+ root.className = "knobs-tree knobs-scroll-fade";
6984
7474
  root.tabIndex = 0;
6985
7475
  root.setAttribute("role", "tree");
6986
7476
  root.setAttribute("aria-multiselectable", "true");
@@ -7046,7 +7536,7 @@ function tree(container, options) {
7046
7536
  const icon = doc.createElement("span");
7047
7537
  icon.className = "knobs-tree-icon";
7048
7538
  const label = doc.createElement("span");
7049
- label.className = "knobs-tree-label";
7539
+ label.className = "knobs-tree-label knobs-scroll-fade-x";
7050
7540
  const text = doc.createElement("span");
7051
7541
  text.className = "knobs-tree-text";
7052
7542
  label.append(text);
@@ -7608,6 +8098,8 @@ function tree(container, options) {
7608
8098
  const rule = options.typeahead ?? true;
7609
8099
  if (rule === false)
7610
8100
  return false;
8101
+ if (!(running && typed !== "") && !/^[\p{L}\p{N}]$/u.test(key))
8102
+ return false;
7611
8103
  if (!(running && typed !== "") && options.hints !== false && claimsHintKey(doc, key))
7612
8104
  return false;
7613
8105
  return rule === true || running && typed !== "" || rule(key);
@@ -9170,9 +9662,2091 @@ function bento(container, options) {
9170
9662
  }
9171
9663
  };
9172
9664
  }
9665
+ // node_modules/@kitlangton/rolling-number/dist/chunk-vm1v7ncb.js
9666
+ var z = new Map;
9667
+ var le = /[\u0590-\u08ff\u200e\u200f\u202a-\u202e\u2066-\u2069\ufb1d-\ufeff]/u;
9668
+ var U = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:.-/&+'";
9669
+ var V = new Map;
9670
+ function Re(e) {
9671
+ let t = V.get(e);
9672
+ if (!t) {
9673
+ if (t = [...new Set(ue(e))], V.size >= 16)
9674
+ V.delete(V.keys().next().value);
9675
+ V.set(e, t);
9676
+ }
9677
+ return t;
9678
+ }
9679
+ function ue(e) {
9680
+ if (typeof Intl.Segmenter === "function")
9681
+ return [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(e)].map((t) => t.segment);
9682
+ return [...e];
9683
+ }
9684
+ function pe(e, t = {}) {
9685
+ let n = t.charset ?? U, i = !le.test(e);
9686
+ if (!i)
9687
+ return { text: e, tokens: [], rollable: i, signature: "text", magnitude: "" };
9688
+ let r = ue(e).map((s, o) => {
9689
+ if (t.transition === "direct")
9690
+ return { key: `char:${o}`, identity: `char:${o}`, text: s, wheel: [s], index: 0 };
9691
+ let h = Re(typeof n === "string" ? n : n[o] ?? n.at(-1) ?? U), c = `char:${o}`, m = h.indexOf(s);
9692
+ return m >= 0 ? { key: c, identity: c, text: s, wheel: h, index: m } : { key: `${c}:${s}`, identity: c, text: s };
9693
+ });
9694
+ return { text: e, tokens: r, rollable: i, signature: `text:${t.transition ?? "wheel"}`, magnitude: "" };
9695
+ }
9696
+ function me(e, t, n = 0.14) {
9697
+ return { target: 0, duration: t, points: Array.from({ length: 49 }, (i, r) => {
9698
+ if (r === 48)
9699
+ return 0;
9700
+ let s = Math.max(0, Math.min(1, (r / 48 - n) / (1 - n)));
9701
+ return e * (1 + 10 * s) * Math.exp(-10 * s);
9702
+ }) };
9703
+ }
9704
+ function W(e, t) {
9705
+ if (t <= 0 || e.duration <= 0)
9706
+ return e;
9707
+ let n = e.duration + t, i = Math.round((e.points.length - 1) * n / e.duration) + 1, r = e.points[0] ?? e.target;
9708
+ return { target: e.target, duration: n, points: Array.from({ length: i }, (s, o) => {
9709
+ if (o === i - 1)
9710
+ return e.target;
9711
+ let h = o / (i - 1) * n - t;
9712
+ return h <= 0 ? r : J(e, h).position;
9713
+ }) };
9714
+ }
9715
+ function L(e, t, n, i) {
9716
+ if (i <= 0)
9717
+ return { points: [t, t], duration: 0, target: t };
9718
+ let r = i / 1000, s = e - t, o = Math.max(Math.abs(s), 1) * 12 / r, h = Math.max(-o, Math.min(o, n)) * r;
9719
+ return { points: Array.from({ length: 49 }, (m, f) => {
9720
+ if (f === 48)
9721
+ return t;
9722
+ let y = f / 48;
9723
+ return t + (s + (h + 10 * s) * y) * Math.exp(-10 * y);
9724
+ }), duration: i, target: t };
9725
+ }
9726
+ function fe(e, t = 0, n = 24) {
9727
+ if (e.duration <= 0)
9728
+ return { points: [0, 0], duration: 0, target: 0 };
9729
+ let i = e.duration / (e.points.length - 1) / 1000;
9730
+ return { duration: e.duration, target: 0, points: e.points.map((r, s, o) => {
9731
+ if (s === 0)
9732
+ return Math.max(0, Math.min(1, t));
9733
+ if (s === o.length - 1)
9734
+ return 0;
9735
+ let h = Math.abs((o[s + 1] - o[s - 1]) / (2 * i)), c = n / 6;
9736
+ return Math.max(0, Math.min(1, (h - c) / (n - c)));
9737
+ }) };
9738
+ }
9739
+ function J(e, t) {
9740
+ if (t >= e.duration || e.duration === 0)
9741
+ return { position: e.target, velocity: 0 };
9742
+ let n = Math.max(0, t) / e.duration * (e.points.length - 1), i = Math.min(Math.floor(n), e.points.length - 2), r = e.points[i] ?? e.target, s = e.points[i + 1] ?? e.target;
9743
+ return { position: r + (s - r) * (n - i), velocity: (s - r) * (e.points.length - 1) * 1000 / e.duration };
9744
+ }
9745
+ function Q(e, t, n, i = 10) {
9746
+ let r = Math.floor(e / i) * i + t;
9747
+ if (n > 0 && r < e - 0.001)
9748
+ r += i;
9749
+ else if (n < 0 && r > e + 0.001)
9750
+ r -= i;
9751
+ else if (n === 0)
9752
+ r += Math.round((e - r) / i) * i;
9753
+ return r;
9754
+ }
9755
+ var P = (e, t) => e[(t % e.length + e.length) % e.length];
9756
+ function ge(e, t, n) {
9757
+ let i = Math.floor(t), r = t - i, s = [P(e, i)];
9758
+ if (r > 0.00001)
9759
+ s.push(P(e, i + 1));
9760
+ if (s.at(-1) !== n)
9761
+ s.push(n);
9762
+ return { wheel: s, from: r, target: s.length - 1 };
9763
+ }
9764
+ function ye(e, t = "outward") {
9765
+ if (t !== "outward") {
9766
+ let r = e.map((o, h) => o ? -1 : h).filter((o) => o >= 0);
9767
+ if (t === "end")
9768
+ r.reverse();
9769
+ let s = e.map((o) => o ? 0 : 1);
9770
+ if (t !== "none")
9771
+ r.forEach((o, h) => {
9772
+ s[o] = h + 1;
9773
+ });
9774
+ return s;
9775
+ }
9776
+ let n = e.map((r, s) => r ? 0 : s + 1);
9777
+ if (!e.includes(true))
9778
+ return n;
9779
+ let i = -1 / 0;
9780
+ for (let r = 0;r < e.length; r++)
9781
+ if (e[r])
9782
+ i = r;
9783
+ else
9784
+ n[r] = r - i;
9785
+ i = 1 / 0;
9786
+ for (let r = e.length - 1;r >= 0; r--)
9787
+ if (e[r])
9788
+ i = r;
9789
+ else
9790
+ n[r] = Math.min(n[r], i - r);
9791
+ return n;
9792
+ }
9793
+ function Z(e, t) {
9794
+ let n = new Map, i = [], r = 0;
9795
+ for (let s of e) {
9796
+ let o = t.get(s);
9797
+ if (!o) {
9798
+ i.push(s);
9799
+ continue;
9800
+ }
9801
+ for (let h of i)
9802
+ n.set(h, o.x);
9803
+ i.length = 0, r = o.x + o.width;
9804
+ }
9805
+ for (let s of i)
9806
+ n.set(s, r);
9807
+ return n;
9808
+ }
9809
+ var ee = new WeakMap;
9810
+
9811
+ class Y {
9812
+ view;
9813
+ media;
9814
+ members = new Set;
9815
+ pending = new Set;
9816
+ sizes = new WeakMap;
9817
+ intersections = new WeakMap;
9818
+ resize;
9819
+ intersection;
9820
+ frame = 0;
9821
+ static for(e) {
9822
+ let t = ee.get(e);
9823
+ if (!t)
9824
+ t = new Y(e), ee.set(e, t);
9825
+ return t;
9826
+ }
9827
+ constructor(e) {
9828
+ this.view = e;
9829
+ if (this.media = e.matchMedia("(prefers-reduced-motion: reduce)"), this.media.addEventListener("change", this.refresh), e.document.addEventListener("visibilitychange", this.refresh), e.document.fonts?.addEventListener("loadingdone", this.refresh), e.document.fonts?.ready.then(this.refresh), e.ResizeObserver)
9830
+ this.resize = new e.ResizeObserver((t) => {
9831
+ for (let n of t) {
9832
+ let i = this.sizes.get(n.target);
9833
+ if (i?.sizeChanged(n.target, n.contentRect.width, n.contentRect.height))
9834
+ i.refresh();
9835
+ }
9836
+ });
9837
+ if (e.IntersectionObserver)
9838
+ this.intersection = new e.IntersectionObserver((t) => {
9839
+ for (let n of t)
9840
+ this.intersections.get(n.target)?.visibility(n.isIntersecting);
9841
+ }, { rootMargin: "64px" });
9842
+ }
9843
+ refresh = () => {
9844
+ for (let e of this.members)
9845
+ e.refresh();
9846
+ };
9847
+ add(e, t) {
9848
+ this.members.add(e), this.intersections.set(t, e), this.intersection?.observe(t);
9849
+ }
9850
+ watch(e, t) {
9851
+ this.sizes.set(e, t), this.resize?.observe(e);
9852
+ }
9853
+ unwatch(e) {
9854
+ this.resize?.unobserve(e), this.sizes.delete(e);
9855
+ }
9856
+ enqueue(e) {
9857
+ if (this.pending.add(e), !this.frame)
9858
+ this.frame = this.view.requestAnimationFrame(() => {
9859
+ this.frame = 0;
9860
+ let t = [...this.pending];
9861
+ this.pending.clear();
9862
+ let n = t.map((r) => r.stage());
9863
+ for (let r of n)
9864
+ r?.();
9865
+ let i = t.map((r) => r.measure());
9866
+ for (let r of i)
9867
+ r?.();
9868
+ });
9869
+ }
9870
+ remove(e, t) {
9871
+ if (this.pending.delete(e), this.members.delete(e), this.intersection?.unobserve(t), this.intersections.delete(t), this.members.size)
9872
+ return;
9873
+ this.view.cancelAnimationFrame(this.frame), this.resize?.disconnect(), this.intersection?.disconnect(), this.media.removeEventListener("change", this.refresh), this.view.document.removeEventListener("visibilitychange", this.refresh), this.view.document.fonts?.removeEventListener("loadingdone", this.refresh), ee.delete(this.view);
9874
+ }
9875
+ }
9876
+ var be = new WeakMap;
9877
+ function F(e, t, n) {
9878
+ let i = e.animate(t, n), r = e.ownerDocument.timeline?.currentTime;
9879
+ if (typeof r === "number" && i.playState === "running")
9880
+ i.startTime = r;
9881
+ return i;
9882
+ }
9883
+ function ve(e) {
9884
+ let t = e.ownerDocument.defaultView;
9885
+ if (!t)
9886
+ return false;
9887
+ let n = be.get(t);
9888
+ if (n === undefined)
9889
+ n = t.CSS?.supports("animation-timing-function", "linear(0, 1)") ?? false, be.set(t, n);
9890
+ return n;
9891
+ }
9892
+
9893
+ class N {
9894
+ element;
9895
+ property;
9896
+ animation;
9897
+ motion;
9898
+ value = 0;
9899
+ constructor(e, t) {
9900
+ this.element = e;
9901
+ this.property = t;
9902
+ }
9903
+ read() {
9904
+ let e = this.animation?.currentTime;
9905
+ return this.animation && this.motion ? J(this.motion, typeof e === "number" ? e : 0) : { position: this.value, velocity: 0 };
9906
+ }
9907
+ set(e, t) {
9908
+ this.cancel(), this.value = e, this.element.style.setProperty(this.property, t(e));
9909
+ }
9910
+ play(e, t, n) {
9911
+ if (this.cancel(), this.value = e.target, this.element.style.setProperty(this.property, t(e.target)), !e.duration || e.points.every((f) => f === e.target)) {
9912
+ n?.();
9913
+ return;
9914
+ }
9915
+ let i = e.points[0] ?? e.target, r = e.target - i, s = this.property === "opacity" && ve(this.element), o = this.property === "transform" && Math.abs(r) > 0.00001 && ve(this.element), h = s ? [{ opacity: 0 }, { opacity: 1 }] : o ? [{ [this.property]: t(i) }, { [this.property]: t(e.target) }] : e.points.map((f) => ({ [this.property]: t(f) })), c = s ? `linear(${e.points.map(t).join(",")})` : o ? `linear(${e.points.map((f) => Number(((f - i) / r).toFixed(6))).join(",")})` : "linear", m = F(this.element, h, { duration: e.duration, easing: c });
9916
+ this.animation = m, this.motion = e, m.onfinish = () => {
9917
+ if (this.animation !== m)
9918
+ return;
9919
+ this.animation = undefined, this.motion = undefined, m.onfinish = null, m.cancel(), n?.();
9920
+ };
9921
+ }
9922
+ cancel() {
9923
+ if (this.animation)
9924
+ this.animation.onfinish = null, this.animation.cancel(), this.animation = undefined;
9925
+ this.motion = undefined;
9926
+ }
9927
+ }
9928
+ var te = "http://www.w3.org/2000/svg";
9929
+ var $e = 0;
9930
+
9931
+ class G {
9932
+ host;
9933
+ layers = new Map;
9934
+ filter;
9935
+ intensity = 1;
9936
+ constructor(e) {
9937
+ this.host = e;
9938
+ }
9939
+ filterUrl(e) {
9940
+ if (!this.filter) {
9941
+ let n = this.host.ownerDocument, i = n.createElementNS(te, "svg");
9942
+ i.classList.add("rn-blur-defs"), i.setAttribute("aria-hidden", "true"), i.setAttribute("focusable", "false");
9943
+ let r = n.createElementNS(te, "filter"), s;
9944
+ do
9945
+ s = `rn-vertical-blur-${++$e}`;
9946
+ while (n.getElementById(s));
9947
+ r.id = s, r.setAttribute("x", "-15%"), r.setAttribute("width", "130%"), r.setAttribute("color-interpolation-filters", "sRGB");
9948
+ let o = n.createElementNS(te, "feGaussianBlur");
9949
+ r.append(o), i.append(r), this.host.append(i), this.filter = { svg: i, blur: o, id: s, height: 0 };
9950
+ }
9951
+ let t = e * 0.035 * this.intensity;
9952
+ if (this.filter.height !== t)
9953
+ this.filter.blur.setAttribute("stdDeviation", `0 ${t}`), this.filter.height = t;
9954
+ return `url("#${this.filter.id}")`;
9955
+ }
9956
+ apply(e, t, n, i, r = "roll") {
9957
+ let s = fe(t, i, r === "entry" ? 6 : 24);
9958
+ if (s.points.every((f) => f === 0))
9959
+ return false;
9960
+ let o = this.host.ownerDocument.createElement("span");
9961
+ o.className = "rn-sharp", o.append(...e.childNodes);
9962
+ let h = o.cloneNode(true);
9963
+ h.className = "rn-smear", h.style.filter = this.filterUrl(n), e.append(o, h);
9964
+ let c = new N(o, "opacity"), m = new N(h, "opacity");
9965
+ return this.layers.set(e, { sharp: o, sharpOpacity: c, smearOpacity: m }), c.play(s, (f) => String(1 - f)), m.play(s, String), true;
9966
+ }
9967
+ remove(e) {
9968
+ let t = this.layers.get(e);
9969
+ if (!t)
9970
+ return 0;
9971
+ let n = t.smearOpacity.read().position;
9972
+ return t.sharpOpacity.cancel(), t.smearOpacity.cancel(), e.replaceChildren(...t.sharp.childNodes), this.layers.delete(e), n;
9973
+ }
9974
+ destroy() {
9975
+ for (let e of this.layers.keys())
9976
+ this.remove(e);
9977
+ this.filter?.svg.remove(), this.filter = undefined;
9978
+ }
9979
+ }
9980
+ function xe(e) {
9981
+ return Math.max(45, Math.min(110, e / 7));
9982
+ }
9983
+ function we(e, t, n) {
9984
+ let i = Math.abs(t - e);
9985
+ return { points: [e, t], target: t, duration: i * n };
9986
+ }
9987
+ function Ae(e) {
9988
+ let i = Array.from({ length: e + 1 }, (o, h) => ({ "--rn-flap-step": String(h), offset: h / e, easing: "steps(1, end)" })), r = [], s = [];
9989
+ for (let o = 0;o < e; o++) {
9990
+ let h = o / e, c = (o + 0.5) / e, m = (o + 1) / e;
9991
+ r.push({ transform: "perspective(5em) rotateX(0deg)", filter: "brightness(1)", offset: h, easing: "cubic-bezier(.6, 0, 1, .5)" }, { transform: "perspective(5em) rotateX(-90deg)", filter: "brightness(.45)", offset: c }, { transform: "perspective(5em) rotateX(-90deg)", filter: "brightness(.45)", offset: m }), s.push({ transform: "perspective(5em) rotateX(90deg)", filter: "brightness(.45)", offset: h }, { transform: "perspective(5em) rotateX(90deg)", filter: "brightness(.45)", offset: c, easing: "linear(0, 0.58, 0.9, 1, 1.045 78%, 1)" }, { transform: "perspective(5em) rotateX(0deg)", filter: "brightness(1)", offset: m });
9992
+ }
9993
+ return { index: i, falls: r, lands: s };
9994
+ }
9995
+ function Me(e) {
9996
+ for (let t of e.querySelectorAll(".rn-flap-smear")) {
9997
+ for (let n of t.getAnimations())
9998
+ n.cancel();
9999
+ t.remove();
10000
+ }
10001
+ for (let t of e.querySelectorAll(".rn-flap-sharp")) {
10002
+ for (let n of t.getAnimations())
10003
+ n.cancel();
10004
+ t.classList.remove("rn-flap-sharp");
10005
+ }
10006
+ }
10007
+ function ke(e, t, n, i, r, s, o, h) {
10008
+ let c = e.ownerDocument, m = Math.abs(i - n), f = i >= n ? 1 : -1;
10009
+ if (!m) {
10010
+ e.replaceChildren();
10011
+ return;
10012
+ }
10013
+ let y = Ae(m), M = Array.from({ length: m + 1 }, (p, w) => P(t, n + w * f)), S = [...M.slice(1), M.at(-1)], u = M.some((p) => /[\r\n\f\u2028\u2029]/u.test(p)), g = c.createElement("span");
10014
+ g.style.cssText = `display:block;position:relative;height:${r}px`, F(g, y.index, { delay: o, duration: m * s, fill: "both" });
10015
+ let T = (p, w) => {
10016
+ let k = c.createElement("span");
10017
+ k.className = `rn-face rn-flap rn-flap-${p}`, k.style.height = `${r}px`, k.style.overflow = "hidden";
10018
+ let v = c.createElement("span");
10019
+ v.style.cssText = `display:block;white-space:pre;line-height:${r}px`;
10020
+ let l = w ? S : M;
10021
+ if (u)
10022
+ for (let b of l) {
10023
+ let O = c.createElement("span");
10024
+ O.style.cssText = `display:block;height:${r}px`, O.textContent = b, v.append(O);
10025
+ }
10026
+ else
10027
+ v.textContent = l.join(`
10028
+ `);
10029
+ return k.append(v), v.style.transform = `translateY(calc(var(--rn-flap-step) * ${-r}px))`, k;
10030
+ }, H = T("bottom", false), j = T("top", true), d = T("top", false), a = T("bottom", true);
10031
+ if (h) {
10032
+ let p = (w, k) => {
10033
+ let v = w.firstElementChild, l = v.cloneNode(true);
10034
+ v.classList.add("rn-flap-sharp");
10035
+ let b = c.createElement("span");
10036
+ b.className = "rn-flap-smear", b.style.cssText = "display:block;position:absolute;inset:0;overflow:hidden", b.style.filter = h, b.append(l), w.append(b);
10037
+ let O = k.map((C) => ({ offset: C.offset, easing: C.easing ?? "linear", opacity: C.filter === "brightness(1)" ? 0 : 1 })), A = { delay: o, duration: m * s, fill: "both" };
10038
+ F(b, O, A), F(v, O.map((C) => ({ ...C, opacity: 1 - C.opacity })), A);
10039
+ };
10040
+ p(d, y.falls), p(a, y.lands);
10041
+ }
10042
+ d.style.transform = "perspective(5em) rotateX(-90deg)", F(d, y.falls, { delay: o, duration: m * s, fill: "backwards" }), a.style.transform = "perspective(5em) rotateX(90deg)", F(a, y.lands, { delay: o, duration: m * s, fill: "forwards" }), e.style.height = `${r}px`, g.append(H, j, a, d), e.replaceChildren(g);
10043
+ }
10044
+ var Ee = new WeakMap;
10045
+ var _ = new WeakSet;
10046
+ var ne = (e) => `translateX(${e}px)`;
10047
+ var ie = (e) => `scale(${e})`;
10048
+ var re = (e) => String(Math.max(0, Math.min(1, e)));
10049
+ var se = (e) => ("transition" in e) && e.transition === "direct";
10050
+ function Te(e) {
10051
+ if (e.duration !== undefined && (!Number.isFinite(e.duration) || e.duration < 0 || e.duration > 1e4))
10052
+ throw RangeError("duration must be between 0 and 10000 milliseconds");
10053
+ if (e.flipDuration !== undefined && (!Number.isFinite(e.flipDuration) || e.flipDuration < 1 || e.flipDuration > 1e4))
10054
+ throw RangeError("flipDuration must be between 1 and 10000 milliseconds");
10055
+ }
10056
+ var Fe = { validate(e) {
10057
+ if (typeof e.text !== "string")
10058
+ throw TypeError("text must be a string");
10059
+ if (e.transition !== undefined && e.transition !== "direct" && e.transition !== "wheel")
10060
+ throw RangeError("transition must be direct or wheel");
10061
+ if (e.transition === "direct" && e.mode === "flap")
10062
+ throw RangeError("Direct text transitions require roll mode");
10063
+ Te(e);
10064
+ }, model: (e) => pe(e.text, e), direction: () => 1 };
10065
+
10066
+ class oe {
10067
+ host;
10068
+ source;
10069
+ options;
10070
+ target;
10071
+ displayed;
10072
+ semantic;
10073
+ measurement;
10074
+ visual;
10075
+ measures = new Map;
10076
+ columns = new Map;
10077
+ sizes = new Map;
10078
+ scheduler;
10079
+ enhanced = false;
10080
+ destroyed = false;
10081
+ visible = true;
10082
+ reset = true;
10083
+ measurementPending = false;
10084
+ hadClass;
10085
+ previousLeft;
10086
+ blur;
10087
+ blurIntensity = 1;
10088
+ constructor(e, t, n) {
10089
+ this.host = e;
10090
+ this.source = n;
10091
+ n.validate(t), this.options = { ...t }, this.target = this.displayed = n.model(t);
10092
+ let i = e.ownerDocument, r = (o) => {
10093
+ let h = i.createElement("span");
10094
+ return h.className = o, h;
10095
+ };
10096
+ this.semantic = r("rn-value"), this.measurement = r("rn-measure"), this.visual = r("rn-visual"), this.measurement.setAttribute("aria-hidden", "true"), this.visual.setAttribute("aria-hidden", "true"), this.semantic.textContent = this.target.text, this.hadClass = e.classList.contains("rn-root"), e.classList.add("rn-root"), e.replaceChildren(this.semantic, this.measurement, this.visual);
10097
+ let s = i.defaultView;
10098
+ if (s && typeof s.matchMedia === "function" && typeof s.requestAnimationFrame === "function" && typeof e.animate === "function")
10099
+ this.scheduler = Y.for(s), this.scheduler.add(this, e), this.scheduler.watch(this.measurement, this);
10100
+ this.prepare();
10101
+ }
10102
+ canAnimate() {
10103
+ return !!this.scheduler && this.options.animated !== false && (this.options.duration ?? 500) > 0 && !this.scheduler.media.matches && !this.host.ownerDocument.hidden && (this.visible || this.options.pauseOffscreen === false) && this.target.rollable && this.host.isConnected;
10104
+ }
10105
+ update(e) {
10106
+ if (this.destroyed)
10107
+ return;
10108
+ let t = { ...this.options, ...e };
10109
+ this.source.validate(t);
10110
+ let n = this.source.model(t), i = n.text === this.target.text && n.signature === this.target.signature;
10111
+ if (this.options.motionBlur && !t.motionBlur)
10112
+ this.blur?.destroy(), this.blur = undefined, Me(this.visual);
10113
+ if (se(this.options) !== se(t))
10114
+ this.reset = true;
10115
+ if (this.options = t, this.target = n, !this.canAnimate()) {
10116
+ this.finish();
10117
+ return;
10118
+ }
10119
+ if (i && this.enhanced && !this.reset)
10120
+ return;
10121
+ this.semantic.textContent = n.text, this.prepare();
10122
+ }
10123
+ prepare() {
10124
+ if (!this.canAnimate()) {
10125
+ this.finish();
10126
+ return;
10127
+ }
10128
+ this.measurementPending = true, this.scheduler?.enqueue(this);
10129
+ }
10130
+ stage() {
10131
+ if (this.destroyed)
10132
+ return;
10133
+ if (!this.canAnimate())
10134
+ return () => this.finish();
10135
+ return this.previousLeft = this.enhanced && !this.reset ? this.measurement.getBoundingClientRect().left : undefined, () => this.stageMeasurement();
10136
+ }
10137
+ stageMeasurement() {
10138
+ let e = new Set(this.target.tokens.map((n) => n.key));
10139
+ for (let [n, i] of this.measures) {
10140
+ if (e.has(n))
10141
+ continue;
10142
+ this.scheduler?.unwatch(i), this.sizes.delete(i), i.remove(), this.measures.delete(n);
10143
+ }
10144
+ let t = null;
10145
+ for (let n of this.target.tokens) {
10146
+ let i = this.measures.get(n.key);
10147
+ if (!i)
10148
+ i = this.host.ownerDocument.createElement("span"), i.className = "rn-token", this.measures.set(n.key, i), this.scheduler?.watch(i, this);
10149
+ if (i.textContent !== n.text)
10150
+ i.textContent = n.text;
10151
+ let r = t ? t.nextSibling : this.measurement.firstChild;
10152
+ if (i !== r)
10153
+ this.measurement.insertBefore(i, r);
10154
+ t = i;
10155
+ }
10156
+ this.host.dataset.rnMeasuring = "";
10157
+ }
10158
+ measure() {
10159
+ if (this.destroyed)
10160
+ return;
10161
+ if (!this.canAnimate())
10162
+ return () => this.finish();
10163
+ let e = this.measurement.getBoundingClientRect(), t = this.host.ownerDocument.defaultView;
10164
+ if (!t)
10165
+ return () => this.finish();
10166
+ let n = t.getComputedStyle(this.measurement);
10167
+ if (n.direction === "rtl")
10168
+ return () => this.finish();
10169
+ let i = parseFloat(n.width), r = parseFloat(n.height);
10170
+ if (!i || !r || !e.width || !e.height)
10171
+ return () => this.finish();
10172
+ let s = e.width / i, o = e.height / r, h = parseFloat(n.getPropertyValue("--rn-blur"));
10173
+ this.blurIntensity = Number.isFinite(h) ? Math.max(0, h) : 1, this.sizes.set(this.measurement, { width: i, height: r });
10174
+ let c = new Map;
10175
+ for (let [f, y] of this.measures) {
10176
+ let M = y.getBoundingClientRect(), S = { width: M.width / s, height: M.height / o };
10177
+ this.sizes.set(y, S), c.set(f, { ...S, x: (M.left - e.left) / s, y: (M.top - e.top) / o });
10178
+ }
10179
+ let m = this.previousLeft === undefined ? 0 : (this.previousLeft - e.left) / s;
10180
+ return () => this.commit(c, m);
10181
+ }
10182
+ makeColumn(e) {
10183
+ let t = this.host.ownerDocument.createElement("span");
10184
+ if (t.className = "rn-slot", t.dataset.rnKey = e.key, e.index !== undefined)
10185
+ t.dataset.rnWheel = "";
10186
+ if (this.options.mode === "flap")
10187
+ t.dataset.rnFlap = "";
10188
+ let n = this.host.ownerDocument.createElement("span");
10189
+ return n.className = "rn-reel", t.append(n), this.visual.append(t), { token: e, element: t, reel: n, x: new N(t, "transform"), opacity: new N(t, "opacity"), roll: new N(n, "transform"), exiting: false, height: 0, width: 0 };
10190
+ }
10191
+ face(e, t) {
10192
+ let n = this.host.ownerDocument.createElement("span");
10193
+ n.className = "rn-face", n.textContent = t, n.style.height = `${e.height}px`;
10194
+ let i = e.reel.children.length;
10195
+ n.style.position = "absolute", n.style.top = "0", n.style.left = "0", n.style.width = "100%", n.style.transform = `translateY(${i * e.height}px)`, e.reel.style.height = `${(i + 1) * e.height}px`, e.reel.append(n);
10196
+ }
10197
+ rest(e) {
10198
+ if (this.blur?.remove(e.reel), e.reel.replaceChildren(), e.reel.style.removeProperty("height"), this.face(e, e.token.text), this.wrapInk(e), e.token.index === undefined)
10199
+ e.roll.set(1, ie);
10200
+ else
10201
+ e.roll.set(e.token.index, () => "translateY(0px)");
10202
+ }
10203
+ wrapInk(e) {
10204
+ if (this.options.mode === "flap")
10205
+ return;
10206
+ let t = this.host.ownerDocument.createElement("span");
10207
+ t.className = "rn-ink", t.append(...e.reel.childNodes), e.reel.append(t);
10208
+ }
10209
+ finishEntry(e) {
10210
+ if (!e.entry)
10211
+ return;
10212
+ if (e.entry.blurred)
10213
+ this.blur?.remove(e.reel);
10214
+ e.entry.track.cancel(), e.entry.element.replaceWith(e.reel), e.entry = undefined;
10215
+ }
10216
+ enter(e, t, n, i) {
10217
+ let r = this.host.ownerDocument.createElement("span");
10218
+ r.className = "rn-enter", e.reel.replaceWith(r), r.append(e.reel);
10219
+ let s = new N(r, "transform");
10220
+ e.entry = { element: r, track: s, blurred: false };
10221
+ let o = W(me(e.height * (i?.entryDistance ?? 1), i?.entryDuration ?? t, i?.entryHold), n);
10222
+ if (this.options.motionBlur && e.token.text.trim()) {
10223
+ this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity;
10224
+ let h = { ...o, points: o.points.map((c) => c / e.height) };
10225
+ e.entry.blurred = this.blur.apply(e.reel, h, e.height, 0, "entry");
10226
+ }
10227
+ s.play(o, (h) => `translateY(${h}px)`, () => this.finishEntry(e));
10228
+ }
10229
+ commit(e, t) {
10230
+ if (this.destroyed)
10231
+ return;
10232
+ this.measurementPending = false;
10233
+ let n = this.enhanced && !this.reset, i = n ? this.options.duration ?? 500 : 0, r = Ee.get(this.host), s = i ? r?.widthDuration ?? i : 0, o = this.options.mode === "flap", h = this.options.direction === "up" ? 1 : this.options.direction === "down" ? -1 : this.source.direction(this.displayed, this.target);
10234
+ if (this.target.text !== this.displayed.text)
10235
+ this.host.dataset.rnTrend = h > 0 ? "up" : h < 0 ? "down" : "none";
10236
+ let c = new Map([...this.columns].map(([d, a]) => {
10237
+ let p = a.x.read();
10238
+ return [d, { ...p, x: p.position, width: a.width }];
10239
+ })), m = Z(this.target.tokens.map((d) => d.key), c), f = [...c.keys()].sort((d, a) => c.get(d).x - c.get(a).x), y = Z(f, e), M = new Map(this.displayed.tokens.filter((d) => d.index === undefined).map((d) => [d.identity, d.key])), S = new Map(this.target.tokens.filter((d) => d.index === undefined).map((d) => [d.identity, d.key])), u = this.options.stagger === "start" || this.options.stagger === "end", g = this.target.tokens.map((d) => {
10240
+ let a = this.columns.get(d.key);
10241
+ return !a || a.exiting || u && d.index !== undefined && a.token.text !== d.text;
10242
+ }), T = ye(this.target.tokens.map((d, a) => d.index !== undefined && !g[a]), this.options.stagger), H = Math.max(0, ...this.target.tokens.map((d, a) => g[a] ? T[a] - 1 : 0)), j = Math.min(i * 0.045, i * 0.3 / Math.max(1, H));
10243
+ for (let [d, a] of this.target.tokens.entries()) {
10244
+ let p = e.get(a.key);
10245
+ if (!p)
10246
+ continue;
10247
+ let w = Math.max(0, T[d] - 1) * j, k = M.get(a.identity), v = k !== undefined && k !== a.key ? c.get(k) : undefined, l = this.columns.get(a.key), b = !l;
10248
+ if (!l) {
10249
+ l = this.makeColumn(a), this.columns.set(a.key, l);
10250
+ let x = (v?.x ?? m.get(a.key) ?? p.x) + t;
10251
+ l.x.set(n ? x + (p.x - x) * (v ? 0 : r?.entryOrigin ?? 0) : p.x, ne), l.opacity.set(n ? 0 : 1, re);
10252
+ }
10253
+ let O = l.token.text !== a.text, A = Math.abs(l.height - p.height) > 0.1, C = l.exiting;
10254
+ l.exiting = false, l.element.style.width = `${p.width}px`, l.element.style.height = `${p.height}px`, l.element.style.top = `${p.y}px`;
10255
+ let q = c.get(a.key);
10256
+ if (l.x.play(L(q ? q.position + t : l.x.read().position, p.x, q?.velocity ?? 0, s), ne), b || C || !n) {
10257
+ let x = l.opacity.read(), E = L(x.position, 1, x.velocity, a.index === undefined ? Math.min(i, 180) : i ? r?.fadeDuration ?? i : 0), R = !o && a.identity.startsWith("group:") && !v ? (r?.entryDuration ?? i) * (r?.entryHold ?? 0.14) : 0;
10258
+ l.opacity.play(b ? W(E, w + R) : E, re);
10259
+ }
10260
+ if (l.height = p.height, l.width = p.width, !n || A)
10261
+ this.finishEntry(l);
10262
+ if (b && o && a.wheel && i)
10263
+ l.roll.set(Math.max(0, a.wheel.indexOf(" ")), () => "translateY(0px)");
10264
+ if (o && !A && (O || b) && a.index !== undefined && a.wheel && i && l.roll.read().position !== a.index) {
10265
+ let x = l.roll.read(), E = Math.round(x.position), R = Q(E, a.index, h, a.wheel.length), D = this.options.flipDuration ?? xe(i);
10266
+ this.blur?.remove(l.reel);
10267
+ let I;
10268
+ if (this.options.motionBlur && this.blurIntensity > 0)
10269
+ this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity, I = this.blur.filterUrl(p.height);
10270
+ ke(l.reel, a.wheel, E, R, p.height, D, w, I), l.token = a;
10271
+ let X = l;
10272
+ l.roll.play(W(we(E, R, D), w), () => "translateY(0px)", () => this.rest(X));
10273
+ } else if (!b && !A && O && a.index !== undefined && a.wheel && l.token.index !== undefined && i) {
10274
+ let x = l.roll.read(), E = se(this.options) ? ge(l.token.wheel, x.position, a.text) : undefined, R = E?.from ?? x.position, D = E?.target ?? Q(x.position, a.index, h, a.wheel.length), I = E?.wheel ?? a.wheel, X = E ? Math.min(Math.max(0, x.velocity), (D - R) * 1e4 / i) : x.velocity, K = u ? W(L(R, D, X, i), w) : L(R, D, X, i), ae = Math.floor(Math.min(...K.points)), Oe = Math.ceil(Math.max(...K.points));
10275
+ if (l.entry)
10276
+ l.entry.blurred = false;
10277
+ let Se = this.blur?.remove(l.reel) ?? 0;
10278
+ l.reel.replaceChildren();
10279
+ for (let B = ae;B <= Oe; B++)
10280
+ this.face(l, P(I, B));
10281
+ if (this.wrapInk(l), this.options.motionBlur)
10282
+ this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity, this.blur.apply(l.reel, K, p.height, Se);
10283
+ l.token = E ? { ...a, wheel: I, index: D } : a;
10284
+ let Ce = l;
10285
+ l.roll.play(K, (B) => `translateY(${(ae - B) * p.height}px)`, () => this.rest(Ce));
10286
+ } else if (b || A || O || !n)
10287
+ l.token = a, this.rest(l);
10288
+ if (b && i && a.index !== undefined && !o)
10289
+ this.enter(l, i, w, r);
10290
+ if (v && i && (b || C)) {
10291
+ let x = l.roll.read(), E = l;
10292
+ l.roll.play(L(b ? 0.96 : x.position, 1, x.velocity, Math.min(i, 180)), ie, () => this.rest(E));
10293
+ }
10294
+ }
10295
+ for (let [d, a] of this.columns) {
10296
+ if (e.has(d))
10297
+ continue;
10298
+ let p = c.get(d), w = S.get(a.token.identity), k = w ? e.get(w) : undefined;
10299
+ if (a.x.play(L(p.position + t, k?.x ?? y.get(d) ?? p.position, p.velocity, s), ne), a.exiting)
10300
+ continue;
10301
+ if (a.exiting = true, k && i) {
10302
+ let l = a.roll.read();
10303
+ a.roll.play(L(l.position, 1.04, l.velocity, Math.min(i, 180)), ie);
10304
+ }
10305
+ let v = a.opacity.read();
10306
+ a.opacity.play(L(v.position, 0, v.velocity, a.token.index === undefined ? Math.min(i, 180) : i * 0.65), re, () => {
10307
+ if (!a.exiting)
10308
+ return;
10309
+ this.removeColumn(a), this.columns.delete(d);
10310
+ });
10311
+ }
10312
+ this.enhanced = true, this.reset = false, this.displayed = this.target, this.host.dataset.rnReady = "";
10313
+ }
10314
+ removeColumn(e) {
10315
+ this.blur?.remove(e.reel), this.finishEntry(e), e.x.cancel(), e.roll.cancel(), e.opacity.cancel(), e.element.remove();
10316
+ }
10317
+ refresh() {
10318
+ if (this.destroyed)
10319
+ return;
10320
+ this.reset = true, this.prepare();
10321
+ }
10322
+ sizeChanged(e, t, n) {
10323
+ if (this.measurementPending || !this.host.hasAttribute("data-rn-measuring"))
10324
+ return false;
10325
+ let i = this.sizes.get(e);
10326
+ return !i || Math.abs(i.width - t) > 0.2 || Math.abs(i.height - n) > 0.2;
10327
+ }
10328
+ visibility(e) {
10329
+ if (this.visible === e)
10330
+ return;
10331
+ if (this.visible = e, e || this.options.pauseOffscreen !== false)
10332
+ this.refresh();
10333
+ }
10334
+ finish() {
10335
+ if (this.destroyed)
10336
+ return;
10337
+ this.measurementPending = false;
10338
+ for (let e of this.columns.values())
10339
+ this.removeColumn(e);
10340
+ this.columns.clear(), this.blur?.destroy(), this.blur = undefined, this.semantic.textContent = this.target.text, delete this.host.dataset.rnReady, delete this.host.dataset.rnMeasuring, delete this.host.dataset.rnTrend, this.enhanced = false, this.reset = true, this.displayed = this.target;
10341
+ }
10342
+ destroy() {
10343
+ if (this.destroyed)
10344
+ return;
10345
+ this.finish(), this.destroyed = true;
10346
+ for (let e of this.measures.values())
10347
+ this.scheduler?.unwatch(e);
10348
+ if (this.scheduler?.unwatch(this.measurement), this.scheduler?.remove(this, this.host), this.host.replaceChildren(this.host.ownerDocument.createTextNode(this.target.text)), !this.hadClass)
10349
+ this.host.classList.remove("rn-root");
10350
+ _.delete(this.host);
10351
+ }
10352
+ }
10353
+ function rt(e, t) {
10354
+ if (_.has(e))
10355
+ throw Error("A rolling number is already mounted on this element");
10356
+ let n = new oe(e, t, Fe);
10357
+ return _.add(e), n;
10358
+ }
10359
+
10360
+ // src/ui/activity-model.ts
10361
+ function flattenActivity(events, expanded) {
10362
+ const rows = [];
10363
+ for (const event of events) {
10364
+ const kids = event.children ?? [];
10365
+ const group = kids.length > 0;
10366
+ const open = group && expanded.has(event.id);
10367
+ rows.push({ id: event.id, event, depth: 0, parent: null, group, expanded: open });
10368
+ if (open)
10369
+ for (const child of flatChildren(kids))
10370
+ rows.push({
10371
+ id: child.id,
10372
+ event: child,
10373
+ depth: 1,
10374
+ parent: event.id,
10375
+ group: false,
10376
+ expanded: false
10377
+ });
10378
+ }
10379
+ return rows;
10380
+ }
10381
+ function flatChildren(events) {
10382
+ const out = [];
10383
+ for (const e of events) {
10384
+ out.push(e);
10385
+ if (e.children?.length)
10386
+ out.push(...flatChildren(e.children));
10387
+ }
10388
+ return out;
10389
+ }
10390
+ function indexActivity(events) {
10391
+ const index = new Map;
10392
+ for (const event of events) {
10393
+ index.set(event.id, { event, parent: null });
10394
+ for (const child of flatChildren(event.children ?? []))
10395
+ index.set(child.id, { event: child, parent: event.id });
10396
+ }
10397
+ return index;
10398
+ }
10399
+ var isActivityKey = (key) => key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight" || key === "Home" || key === "End";
10400
+ function navigateActivity(rows, selected, key) {
10401
+ if (!rows.length)
10402
+ return {};
10403
+ const i = selected === null ? -1 : rows.findIndex((r) => r.id === selected);
10404
+ const row = i >= 0 ? rows[i] : undefined;
10405
+ switch (key) {
10406
+ case "ArrowDown":
10407
+ return { select: rows[i < 0 ? 0 : Math.min(rows.length - 1, i + 1)].id };
10408
+ case "ArrowUp":
10409
+ return { select: rows[i < 0 ? rows.length - 1 : Math.max(0, i - 1)].id };
10410
+ case "Home":
10411
+ return { select: rows[0].id };
10412
+ case "End":
10413
+ return { select: rows[rows.length - 1].id };
10414
+ case "ArrowRight":
10415
+ if (!row?.group)
10416
+ return {};
10417
+ if (!row.expanded)
10418
+ return { toggle: { id: row.id, expanded: true } };
10419
+ return rows[i + 1]?.parent === row.id ? { select: rows[i + 1].id } : {};
10420
+ case "ArrowLeft":
10421
+ if (!row)
10422
+ return {};
10423
+ if (row.group && row.expanded)
10424
+ return { toggle: { id: row.id, expanded: false } };
10425
+ return row.parent !== null ? { select: row.parent } : {};
10426
+ }
10427
+ }
10428
+ function takesActivityKey(key, result, rows) {
10429
+ if (result.select !== undefined || result.toggle !== undefined)
10430
+ return true;
10431
+ return rows > 0 && key !== "ArrowLeft" && key !== "ArrowRight";
10432
+ }
10433
+ function keepSelection(rows, selected, parentOf) {
10434
+ if (selected === null)
10435
+ return null;
10436
+ if (rows.some((r) => r.id === selected))
10437
+ return selected;
10438
+ const parent = parentOf(selected);
10439
+ return parent && rows.some((r) => r.id === parent) ? parent : null;
10440
+ }
10441
+ function showsSelection(showing, input, keys = "focus") {
10442
+ if (input === "key")
10443
+ return true;
10444
+ if (input === "pointer")
10445
+ return false;
10446
+ if (input === "blur")
10447
+ return keys === "page" ? showing : false;
10448
+ return showing;
10449
+ }
10450
+ function diffActivity(before, after) {
10451
+ const was = new Set(before);
10452
+ const now = new Set(after);
10453
+ return {
10454
+ entered: after.filter((id) => !was.has(id)),
10455
+ left: before.filter((id) => !now.has(id)),
10456
+ kept: after.filter((id) => was.has(id))
10457
+ };
10458
+ }
10459
+ function stackRows(heights, top = 0, gap = 0) {
10460
+ const y = [];
10461
+ let at = top;
10462
+ heights.forEach((h, i) => {
10463
+ y.push(at);
10464
+ at += h + (i < heights.length - 1 ? gap : 0);
10465
+ });
10466
+ return { y, bottom: at };
10467
+ }
10468
+ function railSegments(nodes, from, to) {
10469
+ const sorted = [...nodes].sort((a, b) => a.y - b.y);
10470
+ const out = [];
10471
+ for (let i = 0;i < sorted.length - 1; i++) {
10472
+ const a = sorted[i];
10473
+ const b = sorted[i + 1];
10474
+ const top = Math.max(from, a.y + a.r);
10475
+ const bottom = Math.min(to, b.y - b.r);
10476
+ if (bottom - top > 0.25)
10477
+ out.push([top, bottom]);
10478
+ }
10479
+ return out;
10480
+ }
10481
+ function holdScroll(hold, height, view) {
10482
+ if (hold.from <= 0)
10483
+ return { scroll: 0, space: height };
10484
+ const end = Math.min(hold.from, Math.max(0, hold.h1 - view));
10485
+ const span = hold.h1 - hold.h0;
10486
+ const p = Math.abs(span) < 0.5 ? 1 : Math.min(1, Math.max(0, (height - hold.h0) / span));
10487
+ const scroll = hold.from + (end - hold.from) * p;
10488
+ return { scroll, space: Math.max(height, scroll + view) };
10489
+ }
10490
+ function formatDuration(duration) {
10491
+ if (typeof duration === "string")
10492
+ return duration;
10493
+ const s = Math.max(0, Math.round(duration));
10494
+ const h = Math.floor(s / 3600);
10495
+ const m = Math.floor(s % 3600 / 60);
10496
+ const sec = String(s % 60).padStart(2, "0");
10497
+ return h ? `${h}:${String(m).padStart(2, "0")}:${sec}` : `${m}:${sec}`;
10498
+ }
10499
+ function groupTitle(count) {
10500
+ return `${count} update${count === 1 ? "" : "s"}`;
10501
+ }
10502
+
10503
+ // src/ui/activity.ts
10504
+ var ACTIVITY_ICONS = {
10505
+ you: svg('<circle cx="8" cy="5.5" r="2.5"/><path d="M3.2 13.5c.8-2.4 2.6-3.8 4.8-3.8s4 1.4 4.8 3.8"/>'),
10506
+ agent: svg('<path d="M8 2.2 9.4 6.6 13.8 8 9.4 9.4 8 13.8 6.6 9.4 2.2 8 6.6 6.6Z"/>'),
10507
+ proposal: svg('<rect x="2.5" y="2.5" width="4.5" height="4.5" rx="1.2"/><rect x="9" y="2.5" width="4.5" height="4.5" rx="1.2"/><rect x="2.5" y="9" width="4.5" height="4.5" rx="1.2"/><rect x="9" y="9" width="4.5" height="4.5" rx="1.2"/>'),
10508
+ review: svg('<rect x="2" y="3.5" width="12" height="9" rx="2.2"/><path d="M7 6.3v3.4L9.8 8Z"/>'),
10509
+ pr: svg('<circle cx="4.5" cy="3.8" r="1.6"/><circle cx="4.5" cy="12.2" r="1.6"/><circle cx="11.5" cy="12.2" r="1.6"/><path d="M4.5 5.4v5.2M11.5 10.6V6.8a2 2 0 0 0-2-2H7.2M8.8 3.2 7.2 4.8l1.6 1.6"/>'),
10510
+ build: svg('<path d="M8 2.2 13.5 5v6L8 13.8 2.5 11V5Z"/><path d="M2.5 5 8 7.9 13.5 5M8 7.9v5.9"/>'),
10511
+ blocked: svg('<path d="M3.8 14V2.6M3.8 3h8l-1.9 3 1.9 3h-8"/>'),
10512
+ shipped: svg('<circle cx="8" cy="8" r="5.8"/><path d="m5.6 8.2 1.7 1.7 3.2-3.6"/>')
10513
+ };
10514
+ var PLAY2 = '<svg viewBox="0 0 8 8" aria-hidden="true"><path d="M1.5 1v6l5.2-3Z" fill="currentColor"/></svg>';
10515
+ var REFLOW = springMotion({ duration: 0.4, bounce: 0 });
10516
+ var OPEN = springMotion({ duration: 0.22, bounce: 0 });
10517
+ var CLOSE = springMotion({ duration: 0.18, bounce: 0 });
10518
+ var BLOOM = springMotion({ duration: 0.3, bounce: 0 });
10519
+ var EXIT2 = springMotion({ duration: 0.24, bounce: 0 });
10520
+ var FADE2 = springMotion({ duration: 0.16, bounce: 0 });
10521
+ var CLEAR = [11, 5];
10522
+ var PAD = 6;
10523
+ var SLIDE2 = 8;
10524
+ function activity(container, options) {
10525
+ const doc = container.ownerDocument;
10526
+ const win = doc.defaultView;
10527
+ let newest = options.newest ?? "bottom";
10528
+ const keysFrom = options.keys ?? "focus";
10529
+ let events = options.events;
10530
+ let index = indexActivity(events);
10531
+ const expanded = new Set(options.expanded ?? []);
10532
+ let rows = [];
10533
+ let selected = options.selected ?? null;
10534
+ let showing = false;
10535
+ const root = doc.createElement("div");
10536
+ root.className = "knobs-activity knobs-scroll-fade";
10537
+ root.tabIndex = 0;
10538
+ root.setAttribute("role", "tree");
10539
+ if (options.label)
10540
+ root.setAttribute("aria-label", options.label);
10541
+ applyLook(root, options);
10542
+ const space = doc.createElement("div");
10543
+ space.className = "knobs-activity-space";
10544
+ const hl = doc.createElement("div");
10545
+ hl.className = "knobs-activity-hl";
10546
+ hl.setAttribute("aria-hidden", "true");
10547
+ const line = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
10548
+ line.setAttribute("class", "knobs-activity-line");
10549
+ line.setAttribute("aria-hidden", "true");
10550
+ const path = doc.createElementNS("http://www.w3.org/2000/svg", "path");
10551
+ line.append(path);
10552
+ const empty = doc.createElement("div");
10553
+ empty.className = "knobs-activity-empty";
10554
+ empty.hidden = true;
10555
+ space.append(hl, line);
10556
+ root.append(empty, space);
10557
+ container.append(root);
10558
+ let heights = [32, 26];
10559
+ const measure = () => {
10560
+ syncFrame(root);
10561
+ const probe = (depth) => {
10562
+ const p = doc.createElement("div");
10563
+ p.className = "knobs-activity-row";
10564
+ p.dataset.depth = String(depth);
10565
+ p.style.visibility = "hidden";
10566
+ space.append(p);
10567
+ const h = p.getBoundingClientRect().height;
10568
+ p.remove();
10569
+ return h;
10570
+ };
10571
+ heights = [probe(0) || 32, probe(1) || 26];
10572
+ };
10573
+ measure();
10574
+ const uid = `ka${Math.random().toString(36).slice(2, 7)}`;
10575
+ const domIds = new Map;
10576
+ const domId = (id) => {
10577
+ let d = domIds.get(id);
10578
+ if (!d)
10579
+ domIds.set(id, d = `${uid}-${domIds.size}`);
10580
+ return d;
10581
+ };
10582
+ const views = new Map;
10583
+ const makeView = (row) => {
10584
+ const el = doc.createElement("div");
10585
+ el.className = "knobs-activity-row";
10586
+ el.setAttribute("role", "treeitem");
10587
+ el.id = domId(row.id);
10588
+ el.dataset.id = row.id;
10589
+ const node = doc.createElement("span");
10590
+ node.className = "knobs-activity-node";
10591
+ const main = doc.createElement("span");
10592
+ main.className = "knobs-activity-main knobs-scroll-fade-x";
10593
+ const actor = doc.createElement("span");
10594
+ actor.className = "knobs-activity-actor";
10595
+ const title = doc.createElement("span");
10596
+ title.className = "knobs-activity-title";
10597
+ main.append(actor, title);
10598
+ const meta = doc.createElement("span");
10599
+ meta.className = "knobs-activity-meta";
10600
+ const thumbs = doc.createElement("span");
10601
+ thumbs.className = "knobs-activity-thumbs";
10602
+ const caret = doc.createElement("span");
10603
+ caret.className = "knobs-activity-caret";
10604
+ caret.innerHTML = ICONS.caret;
10605
+ const time = doc.createElement("span");
10606
+ time.className = "knobs-activity-time";
10607
+ el.append(node, main, meta);
10608
+ space.append(el);
10609
+ const v = {
10610
+ id: row.id,
10611
+ el,
10612
+ node,
10613
+ actor,
10614
+ title,
10615
+ meta,
10616
+ thumbs,
10617
+ chip: null,
10618
+ caret,
10619
+ time,
10620
+ roll: null,
10621
+ chipRoll: null,
10622
+ y: new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05),
10623
+ p: new Spring(1, BLOOM.omega, BLOOM.zeta, 0.002),
10624
+ depth: row.depth,
10625
+ under: null,
10626
+ from: 0,
10627
+ leaving: false,
10628
+ event: undefined,
10629
+ state: ""
10630
+ };
10631
+ views.set(row.id, v);
10632
+ return v;
10633
+ };
10634
+ const dropView = (v) => {
10635
+ v.roll?.destroy();
10636
+ v.chipRoll?.destroy();
10637
+ v.el.remove();
10638
+ views.delete(v.id);
10639
+ };
10640
+ const rollInto = (host, roll, text) => {
10641
+ if (!text) {
10642
+ roll?.destroy();
10643
+ host.textContent = "";
10644
+ return null;
10645
+ }
10646
+ if (roll) {
10647
+ roll.update({ text });
10648
+ return roll;
10649
+ }
10650
+ return rt(host, {
10651
+ text,
10652
+ charset: "0123456789",
10653
+ transition: "direct",
10654
+ animated: !reducedMotion(win)
10655
+ });
10656
+ };
10657
+ const bind = (v, row) => {
10658
+ const e = row.event;
10659
+ const state = `${row.depth}|${row.group}|${row.expanded}|${selected === row.id}`;
10660
+ if (v.event === e && v.state === state)
10661
+ return;
10662
+ const changed = v.event !== e;
10663
+ v.event = e;
10664
+ v.state = state;
10665
+ v.depth = row.depth;
10666
+ const el = v.el;
10667
+ el.dataset.depth = String(row.depth);
10668
+ el.setAttribute("aria-level", String(row.depth + 1));
10669
+ el.setAttribute("aria-selected", String(selected === row.id));
10670
+ if (row.group)
10671
+ el.setAttribute("aria-expanded", String(row.expanded));
10672
+ else
10673
+ el.removeAttribute("aria-expanded");
10674
+ if (!changed)
10675
+ return;
10676
+ if (e.kind)
10677
+ el.dataset.kind = e.kind;
10678
+ else
10679
+ delete el.dataset.kind;
10680
+ el.toggleAttribute("data-current", Boolean(e.current));
10681
+ el.toggleAttribute("data-dimmed", Boolean(e.dimmed));
10682
+ const tint = e.tint ?? (e.kind ? options.tints?.[e.kind] : undefined);
10683
+ if (tint)
10684
+ el.style.setProperty("--ka-tint", tint);
10685
+ else
10686
+ el.style.removeProperty("--ka-tint");
10687
+ const icon = e.icon ?? (row.depth === 1 ? undefined : (e.kind && (options.icons?.[e.kind] ?? ACTIVITY_ICONS[e.kind])) ?? undefined);
10688
+ if (icon instanceof Node)
10689
+ v.node.replaceChildren(icon);
10690
+ else if (icon === undefined) {
10691
+ if (!v.node.firstElementChild?.classList.contains("knobs-activity-dot"))
10692
+ v.node.innerHTML = '<i class="knobs-activity-dot"></i>';
10693
+ } else if (icon.trimStart().startsWith("<")) {
10694
+ if (v.node.innerHTML !== icon)
10695
+ v.node.innerHTML = icon;
10696
+ } else {
10697
+ const glyph = doc.createElement("span");
10698
+ glyph.className = "knobs-activity-glyph";
10699
+ glyph.textContent = icon;
10700
+ v.node.replaceChildren(glyph);
10701
+ }
10702
+ const kids = e.children?.length ?? 0;
10703
+ v.actor.textContent = e.actor ?? "";
10704
+ const title = e.title ?? (kids ? groupTitle(kids) : "");
10705
+ if (v.title.textContent !== title)
10706
+ v.title.textContent = title;
10707
+ el.setAttribute("aria-label", [e.actor, title, e.time].filter(Boolean).join(", "));
10708
+ const parts = [];
10709
+ const thumbs = e.thumbs?.slice(0, 4) ?? [];
10710
+ const shown = [...v.thumbs.querySelectorAll("img")].map((i) => i.getAttribute("src"));
10711
+ if (thumbs.join(`
10712
+ `) !== shown.join(`
10713
+ `))
10714
+ v.thumbs.replaceChildren(...thumbs.map((src) => {
10715
+ const img = doc.createElement("img");
10716
+ img.src = src;
10717
+ img.alt = "";
10718
+ img.loading = "lazy";
10719
+ img.draggable = false;
10720
+ return img;
10721
+ }));
10722
+ if (thumbs.length)
10723
+ parts.push(v.thumbs);
10724
+ if (e.duration !== undefined) {
10725
+ const button = Boolean(options.onPlay);
10726
+ if (!v.chip || v.chip.tagName === "BUTTON" !== button) {
10727
+ v.chipRoll?.destroy();
10728
+ v.chipRoll = null;
10729
+ v.chip = doc.createElement(button ? "button" : "span");
10730
+ v.chip.className = "knobs-activity-chip";
10731
+ if (button) {
10732
+ v.chip.type = "button";
10733
+ v.chip.tabIndex = -1;
10734
+ v.chip.setAttribute("aria-label", "Play");
10735
+ }
10736
+ v.chip.innerHTML = `${PLAY2}<span></span>`;
10737
+ }
10738
+ v.chipRoll = rollInto(v.chip.lastElementChild, v.chipRoll, formatDuration(e.duration));
10739
+ parts.push(v.chip);
10740
+ }
10741
+ if (kids)
10742
+ parts.push(v.caret);
10743
+ v.roll = rollInto(v.time, v.roll, e.time ?? "");
10744
+ if (e.time)
10745
+ parts.push(v.time);
10746
+ const now = [...v.meta.children];
10747
+ if (now.length !== parts.length || now.some((n, i) => n !== parts[i]))
10748
+ v.meta.replaceChildren(...parts);
10749
+ };
10750
+ const nodeY = (v) => v.y.x + heights[v.depth] / 2;
10751
+ let targets = new Map;
10752
+ const lineTop = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
10753
+ const lineBottom = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
10754
+ const hlY = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
10755
+ const hlH = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
10756
+ const height = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
10757
+ let following = false;
10758
+ let scrollHold = null;
10759
+ const place = (v, reduced) => {
10760
+ const p = Math.max(0, Math.min(1, v.p.x));
10761
+ let y = v.y.x;
10762
+ let clip = 0;
10763
+ let transform = "";
10764
+ let filter = "";
10765
+ if (v.under !== null) {
10766
+ const parent = views.get(v.under);
10767
+ const bottom = (parent ? parent.y.x : targets.get(v.under) ?? 0) + heights[0];
10768
+ clip = Math.min(heights[v.depth], Math.max(0, bottom - y));
10769
+ } else if (p < 1 && !reduced) {
10770
+ y += (1 - p) * SLIDE2 * v.from;
10771
+ transform = ` scale(${(0.97 + 0.03 * p).toFixed(4)})`;
10772
+ const blur = (1 - p) * 3;
10773
+ if (blur > 0.05)
10774
+ filter = `blur(${blur.toFixed(2)}px)`;
10775
+ }
10776
+ v.el.style.transform = `translate3d(0,${Math.round(y * 2) / 2}px,0)${transform}`;
10777
+ v.el.style.clipPath = clip > 0 ? `inset(${clip}px 0 0 0)` : "";
10778
+ v.el.style.opacity = p < 0.999 ? p.toFixed(3) : "";
10779
+ v.el.style.filter = filter;
10780
+ };
10781
+ const drawLine = () => {
10782
+ const nodes = [];
10783
+ for (const v of views.values()) {
10784
+ const p = Math.max(0, Math.min(1, v.p.x));
10785
+ if (p <= 0.001)
10786
+ continue;
10787
+ const y = nodeY(v);
10788
+ if (v.under !== null) {
10789
+ const parent = views.get(v.under);
10790
+ if (parent && y < parent.y.x + heights[0])
10791
+ continue;
10792
+ }
10793
+ nodes.push({ y, r: CLEAR[v.depth] * Math.min(1, p * 1.5) });
10794
+ }
10795
+ const segs = railSegments(nodes, lineTop.x, lineBottom.x);
10796
+ path.setAttribute("d", segs.map(([a, b]) => `M1 ${a.toFixed(2)}V${b.toFixed(2)}`).join(""));
10797
+ };
10798
+ const placeHighlight = () => {
10799
+ hl.style.transform = `translate3d(0,${Math.round(hlY.x * 2) / 2}px,0)`;
10800
+ hl.style.height = `${Math.max(0, hlH.x).toFixed(2)}px`;
10801
+ };
10802
+ const loop = frameLoop(win, (dt) => {
10803
+ const reduced = reducedMotion(win);
10804
+ let moving = false;
10805
+ for (const s of [lineTop, lineBottom, hlY, hlH, height]) {
10806
+ s.step(dt);
10807
+ if (!s.resting)
10808
+ moving = true;
10809
+ }
10810
+ for (const v of [...views.values()]) {
10811
+ v.y.step(dt);
10812
+ v.p.step(dt);
10813
+ if (v.y.resting && v.p.resting) {
10814
+ if (v.leaving) {
10815
+ dropView(v);
10816
+ continue;
10817
+ }
10818
+ v.under = null;
10819
+ v.from = 0;
10820
+ } else
10821
+ moving = true;
10822
+ place(v, reduced);
10823
+ }
10824
+ drawLine();
10825
+ placeHighlight();
10826
+ if (scrollHold && !following) {
10827
+ const { scroll, space: reserved } = holdScroll(scrollHold, height.x, root.clientHeight);
10828
+ space.style.height = `${Math.max(0, reserved).toFixed(1)}px`;
10829
+ root.scrollTop = scroll;
10830
+ } else
10831
+ space.style.height = `${Math.max(0, height.x).toFixed(1)}px`;
10832
+ if (following)
10833
+ root.scrollTop = newest === "bottom" ? root.scrollHeight : 0;
10834
+ if (!moving) {
10835
+ following = false;
10836
+ scrollHold = null;
10837
+ }
10838
+ return moving;
10839
+ });
10840
+ const atNewestEnd = () => newest === "bottom" ? root.scrollTop + root.clientHeight >= root.scrollHeight - 4 : root.scrollTop <= 4;
10841
+ function sync(cause, toggled) {
10842
+ const reduced = reducedMotion(win);
10843
+ const animate = cause !== "snap";
10844
+ const glide = cause === "open" ? OPEN : cause === "close" ? CLOSE : REFLOW;
10845
+ const before = [...views.values()].filter((v) => !v.leaving).map((v) => v.id);
10846
+ rows = flattenActivity(events, expanded);
10847
+ selected = keepSelection(rows, selected, (id) => index.get(id)?.parent);
10848
+ const stack = stackRows(rows.map((r) => heights[r.depth]), PAD);
10849
+ targets = new Map(rows.map((r, i) => [r.id, stack.y[i]]));
10850
+ const { entered } = diffActivity(before, rows.map((r) => r.id));
10851
+ const fresh = new Set(entered);
10852
+ let opened = 0;
10853
+ if (cause === "open") {
10854
+ for (const r of rows)
10855
+ if (r.parent === toggled && fresh.has(r.id))
10856
+ opened += heights[r.depth];
10857
+ }
10858
+ let shut = 0;
10859
+ const live = new Set(rows.map((r) => r.id));
10860
+ if (cause === "close") {
10861
+ for (const v of views.values())
10862
+ if (!live.has(v.id) && !v.leaving && index.get(v.id)?.parent === toggled)
10863
+ shut += heights[v.depth];
10864
+ }
10865
+ const following0 = animate && options.follow !== false && atNewestEnd();
10866
+ const lastIndex = rows.length - 1;
10867
+ rows.forEach((row, i) => {
10868
+ const goal = stack.y[i];
10869
+ let v = views.get(row.id);
10870
+ if (v && v.leaving) {
10871
+ v.leaving = false;
10872
+ delete v.el.dataset.leaving;
10873
+ tune(v.p, cause === "open" ? OPEN : BLOOM).set(1);
10874
+ }
10875
+ if (!v) {
10876
+ v = makeView(row);
10877
+ if (!animate) {
10878
+ v.y.snap(goal);
10879
+ v.p.snap(1);
10880
+ } else if (reduced) {
10881
+ v.y.snap(goal);
10882
+ tune(v.p, FADE2).snap(0).set(1);
10883
+ } else {
10884
+ const parent = row.parent !== null ? views.get(row.parent) : undefined;
10885
+ if (parent && !parent.leaving) {
10886
+ v.under = row.parent;
10887
+ const drawer = cause === "open" && row.parent === toggled;
10888
+ v.y.snap(drawer ? goal - opened + parent.y.x - parent.y.target : parent.y.x);
10889
+ tune(v.y, drawer ? OPEN : glide).set(goal);
10890
+ tune(v.p, drawer ? OPEN : BLOOM).snap(0).set(1);
10891
+ } else {
10892
+ v.y.snap(goal);
10893
+ v.from = newest === "bottom" ? 1 : -1;
10894
+ tune(v.p, BLOOM).snap(0).set(1);
10895
+ }
10896
+ }
10897
+ } else if (!animate || reduced)
10898
+ v.y.snap(goal);
10899
+ else
10900
+ tune(v.y, glide).set(goal);
10901
+ bind(v, row);
10902
+ });
10903
+ for (const v of [...views.values()]) {
10904
+ if (live.has(v.id) || v.leaving)
10905
+ continue;
10906
+ if (!animate) {
10907
+ dropView(v);
10908
+ continue;
10909
+ }
10910
+ v.leaving = true;
10911
+ v.el.dataset.leaving = "";
10912
+ v.el.setAttribute("aria-selected", "false");
10913
+ if (reduced) {
10914
+ tune(v.p, FADE2).set(0);
10915
+ continue;
10916
+ }
10917
+ const group = index.get(v.id)?.parent ?? null;
10918
+ const parent = group !== null ? views.get(group) : undefined;
10919
+ if (parent && !parent.leaving && v.depth === 1) {
10920
+ v.under = group;
10921
+ const drawer = cause === "close" && group === toggled;
10922
+ tune(v.y, drawer ? CLOSE : glide).set(drawer ? v.y.target - shut : targets.get(group) ?? parent.y.target);
10923
+ tune(v.p, drawer ? CLOSE : EXIT2).set(0);
10924
+ } else {
10925
+ v.from = 0;
10926
+ tune(v.p, EXIT2).set(0);
10927
+ }
10928
+ }
10929
+ const first = rows[0];
10930
+ const last = rows[lastIndex];
10931
+ const firstY = first ? targets.get(first.id) + heights[first.depth] / 2 : PAD;
10932
+ const lastY = last ? targets.get(last.id) + heights[last.depth] / 2 : PAD;
10933
+ const bottom = stack.bottom + PAD;
10934
+ if (!animate || reduced) {
10935
+ lineTop.snap(firstY);
10936
+ lineBottom.snap(lastY);
10937
+ height.snap(bottom);
10938
+ } else {
10939
+ if (!before.length) {
10940
+ lineTop.snap(firstY);
10941
+ lineBottom.snap(firstY);
10942
+ }
10943
+ tune(lineTop, glide).set(firstY);
10944
+ tune(lineBottom, cause === "set" ? BLOOM : glide).set(lastY);
10945
+ tune(height, glide).set(bottom);
10946
+ }
10947
+ moveHighlight(animate && !reduced ? glide : null);
10948
+ hl.hidden = !selected;
10949
+ empty.hidden = rows.length > 0;
10950
+ empty.textContent = options.empty ?? "Nothing yet";
10951
+ if (selected)
10952
+ root.setAttribute("aria-activedescendant", domId(selected));
10953
+ else
10954
+ root.removeAttribute("aria-activedescendant");
10955
+ following = following || following0 && cause === "set" && fresh.size > 0;
10956
+ scrollHold = animate && !following && !reduced ? { from: root.scrollTop, h0: height.x, h1: height.target } : null;
10957
+ for (const v of views.values())
10958
+ place(v, reduced);
10959
+ drawLine();
10960
+ placeHighlight();
10961
+ space.style.height = `${height.x.toFixed(1)}px`;
10962
+ loop.wake();
10963
+ }
10964
+ const moveHighlight = (motion) => {
10965
+ if (!showing)
10966
+ return;
10967
+ const y = selected ? targets.get(selected) : undefined;
10968
+ if (y === undefined)
10969
+ return;
10970
+ const h = heights[rows.find((r) => r.id === selected)?.depth ?? 0];
10971
+ if (!motion) {
10972
+ hlY.snap(y);
10973
+ hlH.snap(h);
10974
+ return;
10975
+ }
10976
+ tune(hlY, motion).set(y);
10977
+ tune(hlH, motion).set(h);
10978
+ };
10979
+ const setShowing = (input) => {
10980
+ const next = showsSelection(showing, input, keysFrom);
10981
+ if (next === showing)
10982
+ return;
10983
+ showing = next;
10984
+ root.toggleAttribute("data-keys", next);
10985
+ };
10986
+ const rebind = () => {
10987
+ for (const row of rows) {
10988
+ const v = views.get(row.id);
10989
+ if (v && !v.leaving)
10990
+ bind(v, row);
10991
+ }
10992
+ };
10993
+ const reveal = (id) => {
10994
+ const y = targets.get(id);
10995
+ if (y === undefined)
10996
+ return;
10997
+ const h = heights[rows.find((r) => r.id === id)?.depth ?? 0];
10998
+ const top = root.scrollTop;
10999
+ const view = root.clientHeight;
11000
+ if (view <= 0 || root.scrollHeight <= view)
11001
+ return;
11002
+ const behavior = reducedMotion(win) ? "auto" : "smooth";
11003
+ if (y - PAD < top)
11004
+ root.scrollTo({ top: y - PAD, behavior });
11005
+ else if (y + h + PAD > top + view)
11006
+ root.scrollTo({ top: y + h + PAD - view, behavior });
11007
+ };
11008
+ const choose = (id, source) => {
11009
+ if (source === "key") {
11010
+ const wasShowing = showing;
11011
+ setShowing("key");
11012
+ if (!wasShowing)
11013
+ moveHighlight(null);
11014
+ } else if (source === "pointer")
11015
+ setShowing("pointer");
11016
+ if (id === selected)
11017
+ return;
11018
+ const from = selected ? targets.get(selected) : undefined;
11019
+ selected = id;
11020
+ rebind();
11021
+ hl.hidden = !id;
11022
+ if (id) {
11023
+ const to = targets.get(id);
11024
+ const far = from !== undefined && to !== undefined && Math.abs(to - from) > 400;
11025
+ const reduced = reducedMotion(win);
11026
+ moveHighlight(reduced || from === undefined ? null : springMotion({ duration: far ? 0.42 : 0.3, bounce: 0 }));
11027
+ root.setAttribute("aria-activedescendant", domId(id));
11028
+ if (source === "key") {
11029
+ scrollHold = null;
11030
+ reveal(id);
11031
+ }
11032
+ const event = index.get(id)?.event;
11033
+ if (event && source !== "code")
11034
+ options.onSelect?.(id, event, source);
11035
+ } else
11036
+ root.removeAttribute("aria-activedescendant");
11037
+ loop.wake();
11038
+ };
11039
+ const toggle = (id, open) => {
11040
+ const row = rows.find((r) => r.id === id);
11041
+ if (!row?.group || row.expanded === open)
11042
+ return;
11043
+ if (open)
11044
+ expanded.add(id);
11045
+ else
11046
+ expanded.delete(id);
11047
+ sync(open ? "open" : "close", id);
11048
+ options.onToggle?.(id, open);
11049
+ };
11050
+ root.addEventListener("pointerdown", (e) => {
11051
+ if (e.button !== 0)
11052
+ return;
11053
+ setShowing("pointer");
11054
+ const el = e.target.closest(".knobs-activity-row");
11055
+ const id = el?.dataset.id;
11056
+ if (!el || !id || el.dataset.leaving !== undefined)
11057
+ return;
11058
+ e.preventDefault();
11059
+ root.focus({ preventScroll: true });
11060
+ if (e.target.closest(".knobs-activity-chip"))
11061
+ return;
11062
+ const row = rows.find((r) => r.id === id);
11063
+ choose(id, "pointer");
11064
+ if (row?.group)
11065
+ toggle(id, !row.expanded);
11066
+ });
11067
+ root.addEventListener("click", (e) => {
11068
+ const chip = e.target.closest(".knobs-activity-chip");
11069
+ const id = chip?.closest(".knobs-activity-row")?.dataset.id;
11070
+ const event = id ? index.get(id)?.event : undefined;
11071
+ if (chip && id && event && options.onPlay) {
11072
+ e.stopPropagation();
11073
+ options.onPlay(id, event);
11074
+ }
11075
+ });
11076
+ const release = () => {
11077
+ scrollHold = null;
11078
+ following = false;
11079
+ };
11080
+ root.addEventListener("wheel", release, { passive: true });
11081
+ root.addEventListener("touchstart", release, { passive: true });
11082
+ const onPointer = () => setShowing("pointer");
11083
+ if (keysFrom === "page")
11084
+ win.addEventListener("pointerdown", onPointer, true);
11085
+ const onKey = (e) => {
11086
+ if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey)
11087
+ return;
11088
+ if (keysFrom === "page") {
11089
+ if (e.target !== root && (isTypingTarget(e.target) || !root.getClientRects().length))
11090
+ return;
11091
+ const t = e.target;
11092
+ if (t !== root && t?.closest?.(".knobs-panel,[role=tree],[role=listbox],[role=grid],[role=slider]"))
11093
+ return;
11094
+ }
11095
+ let handled = true;
11096
+ if (isActivityKey(e.key) && !e.shiftKey) {
11097
+ const r = navigateActivity(rows, selected, e.key);
11098
+ if (!takesActivityKey(e.key, r, rows.length))
11099
+ return;
11100
+ if (r.toggle) {
11101
+ setShowing("key");
11102
+ toggle(r.toggle.id, r.toggle.expanded);
11103
+ } else if (r.select)
11104
+ choose(r.select, "key");
11105
+ else
11106
+ setShowing("key");
11107
+ } else if (e.key === "Enter" && selected) {
11108
+ setShowing("key");
11109
+ const row = rows.find((r) => r.id === selected);
11110
+ const event = index.get(selected)?.event;
11111
+ if (options.onActivate && event)
11112
+ options.onActivate(selected, event);
11113
+ else if (row?.group)
11114
+ toggle(row.id, !row.expanded);
11115
+ else
11116
+ handled = false;
11117
+ } else
11118
+ handled = false;
11119
+ if (handled) {
11120
+ e.preventDefault();
11121
+ e.stopPropagation();
11122
+ }
11123
+ };
11124
+ if (keysFrom === "page")
11125
+ win.addEventListener("keydown", onKey);
11126
+ else
11127
+ root.addEventListener("keydown", onKey);
11128
+ root.addEventListener("blur", () => setShowing("blur"));
11129
+ const remeasure = () => {
11130
+ const was = heights.join();
11131
+ measure();
11132
+ if (heights.join() !== was)
11133
+ sync("snap");
11134
+ };
11135
+ const ro = new ResizeObserver(remeasure);
11136
+ ro.observe(root);
11137
+ root.addEventListener("knobs-restyle", () => {
11138
+ measure();
11139
+ sync("snap");
11140
+ });
11141
+ sync("snap");
11142
+ const handle = {
11143
+ element: root,
11144
+ set(next) {
11145
+ handle.update({ events: next });
11146
+ },
11147
+ add(event) {
11148
+ handle.set(newest === "bottom" ? [...events, event] : [event, ...events]);
11149
+ },
11150
+ update(next) {
11151
+ if (next.newest)
11152
+ newest = next.newest;
11153
+ if (next.events) {
11154
+ events = next.events;
11155
+ index = indexActivity(events);
11156
+ for (const id of [...expanded])
11157
+ if (!index.has(id))
11158
+ expanded.delete(id);
11159
+ }
11160
+ sync("set");
11161
+ },
11162
+ select(id) {
11163
+ if (id !== null) {
11164
+ const parent = index.get(id)?.parent;
11165
+ if (parent && !expanded.has(parent)) {
11166
+ expanded.add(parent);
11167
+ sync("open", parent);
11168
+ }
11169
+ }
11170
+ choose(id, "code");
11171
+ },
11172
+ get selected() {
11173
+ return selected;
11174
+ },
11175
+ expand: (id, open = !expanded.has(id)) => toggle(id, open),
11176
+ isExpanded: (id) => expanded.has(id),
11177
+ focus: () => root.focus({ preventScroll: true }),
11178
+ destroy() {
11179
+ loop.stop();
11180
+ ro.disconnect();
11181
+ if (keysFrom === "page") {
11182
+ win.removeEventListener("keydown", onKey);
11183
+ win.removeEventListener("pointerdown", onPointer, true);
11184
+ }
11185
+ for (const v of [...views.values()])
11186
+ dropView(v);
11187
+ root.remove();
11188
+ },
11189
+ dispose: () => handle.destroy()
11190
+ };
11191
+ return handle;
11192
+ }
11193
+ // src/ui/picker-model.ts
11194
+ function digitPick(ids, key) {
11195
+ if (!/^[1-9]$/.test(key))
11196
+ return;
11197
+ return ids[Number(key) - 1];
11198
+ }
11199
+ function stepPick(ids, current, key) {
11200
+ if (!ids.length)
11201
+ return;
11202
+ if (key === "Home")
11203
+ return ids[0];
11204
+ if (key === "End")
11205
+ return ids[ids.length - 1];
11206
+ const i = current === null ? -1 : ids.indexOf(current);
11207
+ if (i < 0)
11208
+ return key === "ArrowDown" ? ids[0] : ids[ids.length - 1];
11209
+ return ids[Math.max(0, Math.min(ids.length - 1, i + (key === "ArrowDown" ? 1 : -1)))];
11210
+ }
11211
+ function keepPick(ids, selected, wanted = null) {
11212
+ if (wanted !== null && ids.includes(wanted))
11213
+ return wanted;
11214
+ if (selected !== null && ids.includes(selected))
11215
+ return selected;
11216
+ return ids[0] ?? null;
11217
+ }
11218
+ function askPick(ids, id) {
11219
+ return ids.includes(id) ? { pick: id, wanted: null } : { pick: undefined, wanted: id };
11220
+ }
11221
+ var stillWanted = (ids, wanted) => wanted !== null && ids.includes(wanted) ? null : wanted;
11222
+ var pickDigit = (index) => String(index + 1);
11223
+ function claimsDigit(event, typing = false) {
11224
+ return /^[1-9]$/.test(event.key) && !event.defaultPrevented && !event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.repeat && !event.typing && !typing;
11225
+ }
11226
+ function cardTarget(heads, index, body, gap = 0, top = 0) {
11227
+ if (body === undefined)
11228
+ return null;
11229
+ let y = top;
11230
+ for (let i = 0;i < index; i++)
11231
+ y += heads[i] + gap;
11232
+ return { y, h: (heads[index] ?? 0) + body };
11233
+ }
11234
+ function settleHeight(previous, now, frames, limit = 6) {
11235
+ if (previous !== undefined && Math.abs(now - previous) < 0.5)
11236
+ return now;
11237
+ return frames >= limit ? now : undefined;
11238
+ }
11239
+
11240
+ // src/ui/picker.ts
11241
+ var OPEN2 = springMotion({ duration: 0.22, bounce: 0 });
11242
+ var CLOSE2 = springMotion({ duration: 0.18, bounce: 0 });
11243
+ var CARD = springMotion({ duration: 0.3, bounce: 0 });
11244
+ var FADE3 = springMotion({ duration: 0.16, bounce: 0 });
11245
+ var DRIFT = 6;
11246
+ var CHECK2 = svg('<path d="m3.5 8.4 3 3 6-6.6"/>');
11247
+ function optionPicker(container, options) {
11248
+ const doc = container.ownerDocument;
11249
+ const win = doc.defaultView;
11250
+ let list = options.options;
11251
+ let wanted = null;
11252
+ let selected = null;
11253
+ {
11254
+ const ids = list.map((o) => o.id);
11255
+ if (options.selected != null)
11256
+ wanted = askPick(ids, options.selected).wanted;
11257
+ selected = keepPick(ids, options.selected ?? null);
11258
+ }
11259
+ let chosen = options.chosen ?? null;
11260
+ const digits = options.digits ?? "focus";
11261
+ const root = doc.createElement("div");
11262
+ root.className = "knobs-picker";
11263
+ root.setAttribute("role", "radiogroup");
11264
+ if (options.label)
11265
+ root.setAttribute("aria-label", options.label);
11266
+ applyLook(root, options);
11267
+ const card = doc.createElement("div");
11268
+ card.className = "knobs-picker-card";
11269
+ card.setAttribute("aria-hidden", "true");
11270
+ root.append(card);
11271
+ container.append(root);
11272
+ const entries = new Map;
11273
+ const uid = `kp${Math.random().toString(36).slice(2, 7)}`;
11274
+ let serial = 0;
11275
+ const make = (option) => {
11276
+ const el = doc.createElement("div");
11277
+ el.className = "knobs-picker-option";
11278
+ el.dataset.id = option.id;
11279
+ const head = doc.createElement("button");
11280
+ head.type = "button";
11281
+ head.className = "knobs-picker-head";
11282
+ head.setAttribute("role", "radio");
11283
+ head.id = `${uid}-${serial++}`;
11284
+ const key = doc.createElement("span");
11285
+ key.className = "knobs-picker-key";
11286
+ key.setAttribute("aria-hidden", "true");
11287
+ const name = doc.createElement("span");
11288
+ name.className = "knobs-picker-name knobs-scroll-fade-x";
11289
+ const suggested = doc.createElement("span");
11290
+ suggested.className = "knobs-picker-suggested";
11291
+ const check = doc.createElement("span");
11292
+ check.className = "knobs-picker-check";
11293
+ check.innerHTML = CHECK2;
11294
+ check.setAttribute("aria-hidden", "true");
11295
+ head.append(key, name, suggested, check);
11296
+ const body = doc.createElement("div");
11297
+ body.className = "knobs-picker-body";
11298
+ body.hidden = true;
11299
+ body.setAttribute("role", "group");
11300
+ body.setAttribute("aria-labelledby", head.id);
11301
+ const inner = doc.createElement("div");
11302
+ inner.className = "knobs-picker-inner";
11303
+ body.append(inner);
11304
+ el.append(head, body);
11305
+ const entry = {
11306
+ option,
11307
+ el,
11308
+ head,
11309
+ key,
11310
+ thumb: undefined,
11311
+ name,
11312
+ suggested,
11313
+ body,
11314
+ inner,
11315
+ mounted: false,
11316
+ measured: true,
11317
+ cleanup: undefined,
11318
+ h: new Spring(0, OPEN2.omega, OPEN2.zeta, 0.05),
11319
+ o: new Spring(0, OPEN2.omega, OPEN2.zeta, 0.002),
11320
+ moving: false,
11321
+ open: false,
11322
+ presence: new Spring(1, OPEN2.omega, OPEN2.zeta, 0.002),
11323
+ leaving: false
11324
+ };
11325
+ entries.set(option.id, entry);
11326
+ return entry;
11327
+ };
11328
+ const setThumb = (e, url) => {
11329
+ if ((e.thumb?.getAttribute("src") ?? undefined) === (url || undefined))
11330
+ return;
11331
+ if (!url) {
11332
+ e.thumb?.remove();
11333
+ e.thumb = undefined;
11334
+ return;
11335
+ }
11336
+ let img = e.thumb;
11337
+ if (!img) {
11338
+ const el = doc.createElement("img");
11339
+ el.className = "knobs-picker-thumb";
11340
+ el.alt = "";
11341
+ el.loading = "lazy";
11342
+ el.decoding = "async";
11343
+ el.draggable = false;
11344
+ el.addEventListener("load", () => el.dataset.state = "loaded");
11345
+ el.addEventListener("error", () => el.dataset.state = "failed");
11346
+ e.key.after(el);
11347
+ e.thumb = img = el;
11348
+ }
11349
+ const shown = img;
11350
+ shown.dataset.state = "loading";
11351
+ shown.src = url;
11352
+ if (shown.complete && shown.naturalWidth > 0) {
11353
+ shown.dataset.state = "loaded";
11354
+ shown.dataset.instant = "";
11355
+ win.requestAnimationFrame(() => delete shown.dataset.instant);
11356
+ }
11357
+ };
11358
+ const bind = (e, i) => {
11359
+ e.option = list[i];
11360
+ e.key.textContent = pickDigit(i);
11361
+ setThumb(e, e.option.thumb);
11362
+ if (e.name.textContent !== e.option.label)
11363
+ e.name.textContent = e.option.label;
11364
+ e.suggested.textContent = e.option.suggested ? options.suggestedLabel ?? "Suggested" : "";
11365
+ e.suggested.hidden = !e.option.suggested;
11366
+ const on = e.option.id === selected;
11367
+ e.el.toggleAttribute("data-selected", on);
11368
+ e.head.setAttribute("aria-checked", String(on));
11369
+ e.head.tabIndex = on ? 0 : -1;
11370
+ e.el.toggleAttribute("data-chosen", e.option.id === chosen);
11371
+ e.head.setAttribute("aria-label", [
11372
+ e.option.label,
11373
+ e.option.suggested ? options.suggestedLabel ?? "Suggested" : "",
11374
+ e.option.id === chosen ? "chosen" : ""
11375
+ ].filter(Boolean).join(", "));
11376
+ };
11377
+ const mount = (e) => {
11378
+ if (e.mounted || !options.body)
11379
+ return;
11380
+ e.mounted = true;
11381
+ const out = options.body(e.option, e.inner);
11382
+ if (typeof out === "function")
11383
+ e.cleanup = out;
11384
+ };
11385
+ const cardY = new Spring(0, CARD.omega, CARD.zeta, 0.05);
11386
+ const cardH = new Spring(0, CARD.omega, CARD.zeta, 0.05);
11387
+ let gliding = false;
11388
+ const liveCard = () => {
11389
+ const e = selected ? entries.get(selected) : undefined;
11390
+ return e && !e.leaving ? { y: e.el.offsetTop, h: e.el.offsetHeight } : null;
11391
+ };
11392
+ const finalCard = () => {
11393
+ const live = list.map((o) => entries.get(o.id)).filter((e) => !!e && !e.leaving);
11394
+ const index = live.findIndex((e) => e.option.id === selected);
11395
+ if (index < 0)
11396
+ return null;
11397
+ const gap = parseFloat(win.getComputedStyle(root).rowGap) || 0;
11398
+ const e = live[index];
11399
+ return cardTarget(live.map((x) => x.head.offsetHeight), index, e.measured ? natural(e) : undefined, gap);
11400
+ };
11401
+ const placeCard = () => {
11402
+ card.style.transform = `translate3d(0,${Math.round(cardY.x * 2) / 2}px,0)`;
11403
+ card.style.height = `${Math.max(0, cardH.x).toFixed(2)}px`;
11404
+ card.hidden = cardH.x < 0.5;
11405
+ };
11406
+ const natural = (e) => e.inner.offsetHeight;
11407
+ const setOpen = (e, open, animate) => {
11408
+ if (e.open === open && (e.moving || e.body.hidden === !open))
11409
+ return;
11410
+ e.open = open;
11411
+ const reduced = reducedMotion(win);
11412
+ if (open && !e.mounted) {
11413
+ if (animate && e.body.hidden) {
11414
+ e.body.hidden = false;
11415
+ e.body.style.height = "0px";
11416
+ e.body.dataset.moving = "";
11417
+ e.h.snap(0);
11418
+ e.o.snap(0);
11419
+ e.moving = true;
11420
+ }
11421
+ mount(e);
11422
+ }
11423
+ if (!animate) {
11424
+ e.body.hidden = !open;
11425
+ e.moving = false;
11426
+ e.body.style.height = "";
11427
+ delete e.body.dataset.moving;
11428
+ e.inner.style.opacity = "";
11429
+ e.inner.style.transform = "";
11430
+ return;
11431
+ }
11432
+ if (!e.moving) {
11433
+ const from = e.body.hidden ? 0 : e.body.offsetHeight;
11434
+ e.h.snap(from);
11435
+ e.o.snap(from > 0.5 ? 1 : 0);
11436
+ }
11437
+ e.body.hidden = false;
11438
+ e.moving = true;
11439
+ e.body.dataset.moving = "";
11440
+ if (reduced) {
11441
+ e.h.snap(open ? natural(e) : 0);
11442
+ tune(e.o, FADE3).set(open ? 1 : 0);
11443
+ } else {
11444
+ tune(e.h, open ? OPEN2 : CLOSE2).set(open ? natural(e) : 0);
11445
+ tune(e.o, open ? OPEN2 : CLOSE2).set(open ? 1 : 0);
11446
+ }
11447
+ loop.wake();
11448
+ };
11449
+ let pending = null;
11450
+ const premount = (e) => {
11451
+ e.body.hidden = false;
11452
+ e.body.style.height = "0px";
11453
+ e.body.dataset.moving = "";
11454
+ e.inner.style.opacity = "0";
11455
+ e.measured = false;
11456
+ mount(e);
11457
+ };
11458
+ const shelve = (e) => {
11459
+ if (e.open || e.moving)
11460
+ return;
11461
+ e.body.hidden = true;
11462
+ e.body.style.height = "";
11463
+ delete e.body.dataset.moving;
11464
+ e.inner.style.opacity = "";
11465
+ e.measured = true;
11466
+ };
11467
+ const start = (was, now, animate) => {
11468
+ now.measured = true;
11469
+ if (was && was !== now)
11470
+ setOpen(was, false, animate);
11471
+ setOpen(now, true, animate);
11472
+ if (animate && !reducedMotion(win)) {
11473
+ tune(cardY, CARD);
11474
+ tune(cardH, CARD);
11475
+ gliding = true;
11476
+ }
11477
+ loop.wake();
11478
+ };
11479
+ const flush = () => {
11480
+ const p = pending;
11481
+ if (!p)
11482
+ return;
11483
+ pending = null;
11484
+ start(p.was, p.now, true);
11485
+ };
11486
+ const loop = frameLoop(win, (dt) => {
11487
+ let moving = false;
11488
+ if (pending) {
11489
+ const p = pending;
11490
+ const h = natural(p.now);
11491
+ p.frames++;
11492
+ if (settleHeight(p.last, h, p.frames) !== undefined)
11493
+ flush();
11494
+ else {
11495
+ p.last = h;
11496
+ moving = true;
11497
+ }
11498
+ }
11499
+ for (const e of [...entries.values()]) {
11500
+ if (e.moving) {
11501
+ if (e.open && !reducedMotion(win))
11502
+ e.h.set(natural(e));
11503
+ e.h.step(dt);
11504
+ e.o.step(dt);
11505
+ const fade = Math.max(0, Math.min(1, e.o.x));
11506
+ e.body.style.height = `${Math.max(0, e.h.x).toFixed(2)}px`;
11507
+ const shown = e.open ? fade : Math.max(0, (fade - 0.4) / 0.6);
11508
+ e.inner.style.opacity = shown < 0.999 ? shown.toFixed(3) : "";
11509
+ const drift = reducedMotion(win) ? 0 : (1 - fade) * -DRIFT;
11510
+ e.inner.style.transform = Math.abs(drift) > 0.05 ? `translateY(${drift.toFixed(2)}px)` : "";
11511
+ if (e.h.resting && e.o.resting) {
11512
+ e.moving = false;
11513
+ delete e.body.dataset.moving;
11514
+ e.body.style.height = "";
11515
+ e.inner.style.opacity = "";
11516
+ e.inner.style.transform = "";
11517
+ e.body.hidden = !e.open;
11518
+ } else
11519
+ moving = true;
11520
+ }
11521
+ if (e.leaving || !e.presence.resting) {
11522
+ e.presence.step(dt);
11523
+ const p = Math.max(0, Math.min(1, e.presence.x));
11524
+ e.el.style.opacity = p < 0.999 ? p.toFixed(3) : "";
11525
+ e.el.style.height = p < 0.999 ? `${(p * e.head.offsetHeight).toFixed(2)}px` : "";
11526
+ e.el.style.overflow = p < 0.999 ? "hidden" : "";
11527
+ if (e.presence.resting) {
11528
+ if (e.leaving) {
11529
+ e.cleanup?.();
11530
+ e.el.remove();
11531
+ entries.delete(e.option.id);
11532
+ }
11533
+ } else
11534
+ moving = true;
11535
+ }
11536
+ }
11537
+ const t = pending ? null : gliding ? finalCard() : liveCard();
11538
+ if (t) {
11539
+ if (gliding) {
11540
+ cardY.set(t.y);
11541
+ cardH.set(t.h);
11542
+ cardY.step(dt);
11543
+ cardH.step(dt);
11544
+ if (cardY.resting && cardH.resting && !moving)
11545
+ gliding = false;
11546
+ else
11547
+ moving = true;
11548
+ } else {
11549
+ cardY.snap(t.y);
11550
+ cardH.snap(t.h);
11551
+ }
11552
+ }
11553
+ placeCard();
11554
+ notifyLayout(doc);
11555
+ return moving;
11556
+ });
11557
+ const rebind = () => {
11558
+ list.forEach((o, i) => {
11559
+ const e = entries.get(o.id);
11560
+ if (e)
11561
+ bind(e, i);
11562
+ });
11563
+ };
11564
+ const pick = (id, animate = true) => {
11565
+ if (id === selected || !entries.has(id))
11566
+ return;
11567
+ let was = selected ? entries.get(selected) : undefined;
11568
+ if (pending) {
11569
+ was = pending.was;
11570
+ const waiting = pending.now;
11571
+ pending = null;
11572
+ if (waiting.option.id !== id)
11573
+ shelve(waiting);
11574
+ }
11575
+ selected = id;
11576
+ rebind();
11577
+ const now = entries.get(id);
11578
+ if (animate && !reducedMotion(win) && !now.mounted && options.body) {
11579
+ premount(now);
11580
+ pending = { was, now, last: natural(now), frames: 0 };
11581
+ loop.wake();
11582
+ return;
11583
+ }
11584
+ start(was, now, animate);
11585
+ };
11586
+ const select = (id, source) => {
11587
+ if (!id)
11588
+ return;
11589
+ wanted = null;
11590
+ if (id === selected)
11591
+ return;
11592
+ const inside = root.contains(doc.activeElement);
11593
+ pick(id);
11594
+ if (source !== "pointer" && inside)
11595
+ entries.get(id)?.head.focus({ preventScroll: true });
11596
+ options.onSelect?.(id, source);
11597
+ };
11598
+ const sync = (animate) => {
11599
+ flush();
11600
+ const ids = list.map((o) => o.id);
11601
+ const was = selected;
11602
+ selected = keepPick(ids, selected, wanted);
11603
+ wanted = stillWanted(ids, wanted);
11604
+ if (animate && was !== selected && !reducedMotion(win))
11605
+ gliding = true;
11606
+ const reduced = reducedMotion(win);
11607
+ const live = new Set(ids);
11608
+ for (const e of entries.values()) {
11609
+ if (live.has(e.option.id) || e.leaving)
11610
+ continue;
11611
+ if (!animate) {
11612
+ e.cleanup?.();
11613
+ e.el.remove();
11614
+ entries.delete(e.option.id);
11615
+ continue;
11616
+ }
11617
+ e.leaving = true;
11618
+ e.el.setAttribute("aria-hidden", "true");
11619
+ e.head.tabIndex = -1;
11620
+ if (e.open)
11621
+ setOpen(e, false, true);
11622
+ tune(e.presence, reduced ? FADE3 : CLOSE2).set(0);
11623
+ }
11624
+ let before = card;
11625
+ list.forEach((o, i) => {
11626
+ let e = entries.get(o.id);
11627
+ if (e?.leaving) {
11628
+ e.leaving = false;
11629
+ e.el.removeAttribute("aria-hidden");
11630
+ tune(e.presence, OPEN2).set(1);
11631
+ }
11632
+ if (!e) {
11633
+ e = make(o);
11634
+ ro.observe(e.el);
11635
+ if (animate)
11636
+ tune(e.presence, reduced ? FADE3 : OPEN2).snap(0).set(1);
11637
+ }
11638
+ if (before.nextElementSibling !== e.el)
11639
+ before.after(e.el);
11640
+ before = e.el;
11641
+ bind(e, i);
11642
+ });
11643
+ const open = selected ? entries.get(selected) : undefined;
11644
+ const ahead = animate && !reduced && open && !open.open && !open.mounted && !!options.body ? { was: was ? entries.get(was) : undefined, now: open } : null;
11645
+ for (const e of entries.values())
11646
+ if (e !== open && e !== ahead?.was && e.open && !e.leaving)
11647
+ setOpen(e, false, animate);
11648
+ if (ahead) {
11649
+ premount(ahead.now);
11650
+ pending = { ...ahead, last: natural(ahead.now), frames: 0 };
11651
+ } else if (open && !open.open)
11652
+ setOpen(open, true, animate);
11653
+ loop.wake();
11654
+ };
11655
+ const ids = () => list.map((o) => o.id).filter((id) => !entries.get(id)?.leaving);
11656
+ const onDigit = (e) => {
11657
+ if (!claimsDigit(e, isTypingTarget(e.target)))
11658
+ return;
11659
+ if (!root.getClientRects().length)
11660
+ return;
11661
+ const id = digitPick(ids(), e.key);
11662
+ if (!id)
11663
+ return;
11664
+ e.preventDefault();
11665
+ select(id, "digit");
11666
+ };
11667
+ root.addEventListener("keydown", (e) => {
11668
+ const head = e.target.closest?.(".knobs-picker-head");
11669
+ if (head && !e.metaKey && !e.ctrlKey && !e.altKey) {
11670
+ if (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Home" || e.key === "End") {
11671
+ e.preventDefault();
11672
+ select(stepPick(ids(), selected, e.key), "key");
11673
+ return;
11674
+ }
11675
+ if (e.key === "Enter" && selected) {
11676
+ e.preventDefault();
11677
+ options.onChoose?.(selected);
11678
+ return;
11679
+ }
11680
+ }
11681
+ if (digits === "focus")
11682
+ onDigit(e);
11683
+ });
11684
+ if (digits === "page")
11685
+ win.addEventListener("keydown", onDigit);
11686
+ root.addEventListener("click", (e) => {
11687
+ const el = e.target.closest(".knobs-picker-head");
11688
+ const id = el?.closest(".knobs-picker-option")?.dataset.id;
11689
+ if (!id || entries.get(id)?.leaving)
11690
+ return;
11691
+ select(id, e.detail === 0 ? "key" : "pointer");
11692
+ });
11693
+ const ro = new ResizeObserver(() => loop.wake());
11694
+ ro.observe(root);
11695
+ root.addEventListener("knobs-restyle", () => {
11696
+ syncFrame(root);
11697
+ loop.wake();
11698
+ });
11699
+ sync(false);
11700
+ const first = liveCard();
11701
+ if (first) {
11702
+ cardY.snap(first.y);
11703
+ cardH.snap(first.h);
11704
+ }
11705
+ placeCard();
11706
+ loop.wake();
11707
+ const handle = {
11708
+ element: root,
11709
+ set(next) {
11710
+ list = next;
11711
+ sync(true);
11712
+ },
11713
+ select(id) {
11714
+ const ask = askPick(ids(), id);
11715
+ wanted = ask.wanted;
11716
+ if (ask.pick)
11717
+ pick(ask.pick);
11718
+ },
11719
+ get selected() {
11720
+ return selected;
11721
+ },
11722
+ choose(id) {
11723
+ chosen = id;
11724
+ rebind();
11725
+ },
11726
+ get chosen() {
11727
+ return chosen;
11728
+ },
11729
+ focus() {
11730
+ (selected ? entries.get(selected)?.head : undefined)?.focus({ preventScroll: true });
11731
+ },
11732
+ destroy() {
11733
+ loop.stop();
11734
+ ro.disconnect();
11735
+ if (digits === "page")
11736
+ win.removeEventListener("keydown", onDigit);
11737
+ for (const e of entries.values())
11738
+ e.cleanup?.();
11739
+ entries.clear();
11740
+ root.remove();
11741
+ },
11742
+ dispose: () => handle.destroy()
11743
+ };
11744
+ return handle;
11745
+ }
9173
11746
  export {
9174
11747
  COLLAPSE_PAST,
9175
11748
  FIT_MAX,
11749
+ activity,
9176
11750
  adjacentMarker,
9177
11751
  advance,
9178
11752
  applyMove,
@@ -9180,22 +11754,30 @@ export {
9180
11754
  bento,
9181
11755
  neighbour as bentoNeighbour,
9182
11756
  windowOf as bentoWindow,
11757
+ claimsDigit,
9183
11758
  clampView,
9184
11759
  commandPalette,
9185
11760
  commandsFrom,
9186
11761
  confirm,
9187
11762
  contextMenu,
11763
+ diffActivity,
11764
+ digitPick,
9188
11765
  drag as dragDivider,
9189
11766
  dropTarget,
9190
11767
  fitRect,
9191
11768
  flatten,
11769
+ flattenActivity,
9192
11770
  followView,
11771
+ formatDuration,
9193
11772
  frameTime,
9194
11773
  fuzzy,
9195
11774
  hints,
9196
11775
  inTriangle,
11776
+ indexActivity,
9197
11777
  indexTree,
9198
11778
  injectUiStyles,
11779
+ keepSelection as keepActivitySelection,
11780
+ keepPick,
9199
11781
  magnet,
9200
11782
  marks,
9201
11783
  matchItem,
@@ -9203,6 +11785,8 @@ export {
9203
11785
  menu,
9204
11786
  motionBlur,
9205
11787
  navigate,
11788
+ navigateActivity,
11789
+ optionPicker,
9206
11790
  overlayLook,
9207
11791
  pageHints,
9208
11792
  parseLayout,
@@ -9210,6 +11794,7 @@ export {
9210
11794
  plainAccess,
9211
11795
  planBento,
9212
11796
  popover,
11797
+ railSegments,
9213
11798
  rank,
9214
11799
  readout,
9215
11800
  restyle,
@@ -9218,11 +11803,14 @@ export {
9218
11803
  safeTriangle,
9219
11804
  scrubTime,
9220
11805
  select,
11806
+ showsSelection,
9221
11807
  softClamp,
9222
11808
  solve as solveSplit,
9223
11809
  split,
11810
+ stackRows,
9224
11811
  stepItem,
9225
11812
  stepMove,
11813
+ stepPick,
9226
11814
  timeLabel,
9227
11815
  timeline,
9228
11816
  toFrame,