@kitlangton/knobs 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +303 -41
- package/dist/dev/{chunk-qtt698hp.js → chunk-7xgkerd2.js} +34 -11
- package/dist/dev/{chunk-ktsn42p7.js → chunk-jx1ktap3.js} +13762 -11794
- package/dist/dev/{chunk-kdewv0mt.js → chunk-pmkvb9ep.js} +1692 -207
- package/dist/dev/{chunk-e13znr7c.js → chunk-v8ssbcbk.js} +18 -7
- package/dist/dev/index.js +557 -130
- package/dist/index.js +589 -141
- package/dist/panel.js +21615 -17048
- package/dist/types/core/keys.d.ts +2 -0
- package/dist/types/core/random.d.ts +61 -1
- package/dist/types/core/remote.d.ts +5 -1
- package/dist/types/core/schema.d.ts +35 -6
- package/dist/types/core/store.d.ts +97 -8
- package/dist/types/core/unlock.d.ts +77 -0
- package/dist/types/core/variants.d.ts +10 -2
- package/dist/types/index.d.ts +4 -2
- package/dist/types/panel/attach.d.ts +2 -0
- package/dist/types/panel/crumbs.d.ts +19 -0
- package/dist/types/panel/editors.d.ts +20 -0
- package/dist/types/panel/feel.d.ts +103 -0
- package/dist/types/panel/flash.d.ts +13 -0
- package/dist/types/panel/give.d.ts +34 -1
- package/dist/types/panel/gpu/color.d.ts +4 -4
- package/dist/types/panel/gpu/renderer.d.ts +110 -6
- package/dist/types/panel/gpu/shader.wgsl.d.ts +1 -1
- package/dist/types/panel/haptics.d.ts +6 -2
- package/dist/types/panel/has.d.ts +0 -1
- package/dist/types/panel/index.d.ts +3 -1
- package/dist/types/panel/inspector.d.ts +33 -3
- package/dist/types/panel/lens.d.ts +113 -0
- package/dist/types/panel/motion.d.ts +2 -0
- package/dist/types/panel/optkeys.d.ts +7 -0
- package/dist/types/panel/page-hints.d.ts +2 -1
- package/dist/types/panel/prefs.d.ts +2 -2
- package/dist/types/panel/presence.d.ts +20 -0
- package/dist/types/panel/presets.d.ts +17 -5
- package/dist/types/panel/ramp-morph.d.ts +117 -0
- package/dist/types/panel/ramps.d.ts +1 -1
- package/dist/types/panel/reel.d.ts +43 -0
- package/dist/types/panel/scope.d.ts +48 -0
- package/dist/types/panel/slider.d.ts +22 -5
- package/dist/types/panel/sound.d.ts +137 -0
- package/dist/types/panel/styles.d.ts +1 -1
- package/dist/types/panel/tab-transition.d.ts +15 -0
- package/dist/types/panel/tabs.d.ts +1 -1
- package/dist/types/panel/toggle.d.ts +27 -0
- package/dist/types/panel/toolbar-grid.d.ts +6 -0
- package/dist/types/ui/activity-css.d.ts +1 -0
- package/dist/types/ui/activity-model.d.ts +122 -0
- package/dist/types/ui/activity.d.ts +67 -0
- package/dist/types/ui/follow.d.ts +17 -0
- package/dist/types/ui/index.d.ts +5 -1
- package/dist/types/ui/look.d.ts +9 -0
- package/dist/types/ui/picker-css.d.ts +1 -0
- package/dist/types/ui/picker-model.d.ts +53 -0
- package/dist/types/ui/picker.d.ts +67 -0
- package/dist/types/ui/react.d.ts +27 -0
- package/dist/types/ui/scrollbar.d.ts +12 -0
- package/dist/types/ui/solid.d.ts +23 -0
- package/dist/types/ui/split-model.d.ts +55 -0
- package/dist/types/ui/split.d.ts +22 -3
- package/dist/ui-react.js +3462 -690
- package/dist/ui-solid.js +3440 -689
- package/dist/ui.js +2963 -264
- 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:none;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. */
|
|
@@ -393,6 +627,160 @@ var readoutCss = `
|
|
|
393
627
|
@media(prefers-reduced-motion:reduce){.knobs-rd :where(*){transition:none!important}}
|
|
394
628
|
`;
|
|
395
629
|
|
|
630
|
+
// src/core/keys.ts
|
|
631
|
+
var MODS = ["Ctrl", "Alt", "Shift", "Meta"];
|
|
632
|
+
var ALIASES = {
|
|
633
|
+
ctrl: "Ctrl",
|
|
634
|
+
control: "Ctrl",
|
|
635
|
+
"⌃": "Ctrl",
|
|
636
|
+
alt: "Alt",
|
|
637
|
+
option: "Alt",
|
|
638
|
+
opt: "Alt",
|
|
639
|
+
"⌥": "Alt",
|
|
640
|
+
shift: "Shift",
|
|
641
|
+
"⇧": "Shift",
|
|
642
|
+
meta: "Meta",
|
|
643
|
+
cmd: "Meta",
|
|
644
|
+
command: "Meta",
|
|
645
|
+
"⌘": "Meta",
|
|
646
|
+
mod: "Mod"
|
|
647
|
+
};
|
|
648
|
+
var NAMED = {
|
|
649
|
+
" ": "Space",
|
|
650
|
+
space: "Space",
|
|
651
|
+
spacebar: "Space",
|
|
652
|
+
esc: "Escape",
|
|
653
|
+
escape: "Escape",
|
|
654
|
+
enter: "Enter",
|
|
655
|
+
return: "Enter",
|
|
656
|
+
tab: "Tab",
|
|
657
|
+
backspace: "Backspace",
|
|
658
|
+
delete: "Delete",
|
|
659
|
+
del: "Delete",
|
|
660
|
+
up: "ArrowUp",
|
|
661
|
+
down: "ArrowDown",
|
|
662
|
+
left: "ArrowLeft",
|
|
663
|
+
right: "ArrowRight",
|
|
664
|
+
arrowup: "ArrowUp",
|
|
665
|
+
arrowdown: "ArrowDown",
|
|
666
|
+
arrowleft: "ArrowLeft",
|
|
667
|
+
arrowright: "ArrowRight",
|
|
668
|
+
home: "Home",
|
|
669
|
+
end: "End",
|
|
670
|
+
pageup: "PageUp",
|
|
671
|
+
pagedown: "PageDown"
|
|
672
|
+
};
|
|
673
|
+
var isApple = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform ?? navigator.platform ?? "");
|
|
674
|
+
var keyName = (raw) => {
|
|
675
|
+
if (!raw)
|
|
676
|
+
return "";
|
|
677
|
+
const named = NAMED[raw.toLowerCase()];
|
|
678
|
+
if (named)
|
|
679
|
+
return named;
|
|
680
|
+
if (raw.length === 1)
|
|
681
|
+
return raw.toUpperCase();
|
|
682
|
+
if (/^f\d{1,2}$/i.test(raw))
|
|
683
|
+
return raw.toUpperCase();
|
|
684
|
+
return raw.charAt(0).toUpperCase() + raw.slice(1);
|
|
685
|
+
};
|
|
686
|
+
function normalizeCombo(combo) {
|
|
687
|
+
const trimmed = combo.trim();
|
|
688
|
+
if (!trimmed)
|
|
689
|
+
return "";
|
|
690
|
+
const parts = trimmed === "+" ? ["+"] : trimmed.replace(/\+\+$/, "+plus").split("+");
|
|
691
|
+
const mods = new Set;
|
|
692
|
+
let key = "";
|
|
693
|
+
for (const part of parts) {
|
|
694
|
+
const alias = ALIASES[part.trim().toLowerCase()] ?? ALIASES[part.trim()];
|
|
695
|
+
if (alias === "Mod")
|
|
696
|
+
mods.add(isApple() ? "Meta" : "Ctrl");
|
|
697
|
+
else if (alias)
|
|
698
|
+
mods.add(alias);
|
|
699
|
+
else
|
|
700
|
+
key = part === "plus" ? "+" : keyName(part.trim() || part);
|
|
701
|
+
}
|
|
702
|
+
if (!key)
|
|
703
|
+
return "";
|
|
704
|
+
return [...MODS.filter((m) => mods.has(m)), key].join("+");
|
|
705
|
+
}
|
|
706
|
+
var layout = null;
|
|
707
|
+
var layoutAsked = false;
|
|
708
|
+
function askLayout() {
|
|
709
|
+
if (layoutAsked)
|
|
710
|
+
return;
|
|
711
|
+
layoutAsked = true;
|
|
712
|
+
const keyboard = globalThis.navigator?.keyboard;
|
|
713
|
+
keyboard?.getLayoutMap?.().then((map) => {
|
|
714
|
+
layout = map;
|
|
715
|
+
}).catch(() => {});
|
|
716
|
+
}
|
|
717
|
+
function letterOf(event) {
|
|
718
|
+
askLayout();
|
|
719
|
+
const code = event.code ?? "";
|
|
720
|
+
if (/^[a-z]$/i.test(event.key) && !event.altKey)
|
|
721
|
+
return event.key.toUpperCase();
|
|
722
|
+
const mapped = layout?.get(code);
|
|
723
|
+
if (mapped && /^[a-z]$/i.test(mapped))
|
|
724
|
+
return mapped.toUpperCase();
|
|
725
|
+
return /^Key[A-Z]$/.test(code) ? code.slice(3) : "";
|
|
726
|
+
}
|
|
727
|
+
function comboFromEvent(event) {
|
|
728
|
+
if (["Shift", "Alt", "Meta", "Control", "CapsLock", "Fn", "OS"].includes(event.key))
|
|
729
|
+
return "";
|
|
730
|
+
const code = event.code ?? "";
|
|
731
|
+
const letter = letterOf(event);
|
|
732
|
+
const key = letter ? letter : /^Digit\d$/.test(code) ? code.slice(5) : code === "Space" ? "Space" : keyName(event.key);
|
|
733
|
+
return [
|
|
734
|
+
event.ctrlKey ? "Ctrl" : "",
|
|
735
|
+
event.altKey ? "Alt" : "",
|
|
736
|
+
event.shiftKey ? "Shift" : "",
|
|
737
|
+
event.metaKey ? "Meta" : "",
|
|
738
|
+
key
|
|
739
|
+
].filter(Boolean).join("+");
|
|
740
|
+
}
|
|
741
|
+
function matchesCombo(combo, event) {
|
|
742
|
+
const want = normalizeCombo(combo);
|
|
743
|
+
return want !== "" && want === comboFromEvent(event);
|
|
744
|
+
}
|
|
745
|
+
var GLYPHS = { Ctrl: "⌃", Alt: "⌥", Shift: "⇧", Meta: "⌘" };
|
|
746
|
+
var WORDS = { Ctrl: "Ctrl", Alt: "Alt", Shift: "Shift", Meta: "Meta" };
|
|
747
|
+
var KEY_GLYPHS = {
|
|
748
|
+
ArrowUp: "↑",
|
|
749
|
+
ArrowDown: "↓",
|
|
750
|
+
ArrowLeft: "←",
|
|
751
|
+
ArrowRight: "→",
|
|
752
|
+
Backspace: "⌫",
|
|
753
|
+
Delete: "⌦",
|
|
754
|
+
Enter: "↩",
|
|
755
|
+
Escape: "Esc",
|
|
756
|
+
Tab: "⇥",
|
|
757
|
+
PageUp: "PgUp",
|
|
758
|
+
PageDown: "PgDn"
|
|
759
|
+
};
|
|
760
|
+
function comboParts(combo, apple = isApple()) {
|
|
761
|
+
const norm = normalizeCombo(combo);
|
|
762
|
+
if (!norm)
|
|
763
|
+
return [];
|
|
764
|
+
const parts = norm === "+" ? ["+"] : norm.split("+");
|
|
765
|
+
if (norm.endsWith("++"))
|
|
766
|
+
parts.splice(-2, 2, "+");
|
|
767
|
+
const key = parts.pop();
|
|
768
|
+
const mods = parts;
|
|
769
|
+
const shown = KEY_GLYPHS[key] ?? key;
|
|
770
|
+
return apple ? [...mods.map((m) => GLYPHS[m]), shown] : [...mods.map((m) => WORDS[m]), shown];
|
|
771
|
+
}
|
|
772
|
+
function isTypingTarget(target) {
|
|
773
|
+
const el = target;
|
|
774
|
+
if (!el || typeof el.tagName !== "string")
|
|
775
|
+
return false;
|
|
776
|
+
const tag = el.tagName;
|
|
777
|
+
if (tag === "SELECT" || el.isContentEditable)
|
|
778
|
+
return true;
|
|
779
|
+
if (tag === "TEXTAREA")
|
|
780
|
+
return !el.readOnly;
|
|
781
|
+
return tag === "INPUT" && !el.readOnly && !["range", "checkbox", "radio", "button", "submit", "reset", "color"].includes(el.type);
|
|
782
|
+
}
|
|
783
|
+
|
|
396
784
|
// src/ui/look.ts
|
|
397
785
|
var ease = springEasing(26, 1);
|
|
398
786
|
var TOKENS = {
|
|
@@ -488,6 +876,39 @@ var css = `
|
|
|
488
876
|
:is(.knobs-tree,.knobs-split>.knobs-pane>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head) [hidden]{display:none!important}
|
|
489
877
|
:is(.knobs-pane-head,.knobs-pane-rail,.knobs-tree) svg{display:block;flex:none}
|
|
490
878
|
|
|
879
|
+
/* Scroll fades: a scroller's content fades out over --knobs-fade at an edge with more beyond it,
|
|
880
|
+
coming in over the first --knobs-fade-travel of scroll, so reaching an end never pops. They're
|
|
881
|
+
scroll-driven (no script), so where those aren't supported there's no fade. --knobs-fade-inset
|
|
882
|
+
starts the top one below a sticky header; .knobs-scroll-fade-x fades across instead (a single
|
|
883
|
+
line that's cut off, like a tree's labels: no ellipsis). Pane bodies, trees and the palette's
|
|
884
|
+
list carry the class; around a panel the GPU draws, the mask goes (it would trap the panel's
|
|
885
|
+
overlays under it). */
|
|
886
|
+
@property --knobs-fade-a{syntax:"<number>";inherits:false;initial-value:1}
|
|
887
|
+
@property --knobs-fade-b{syntax:"<number>";inherits:false;initial-value:1}
|
|
888
|
+
@keyframes knobs-fade-a{from{--knobs-fade-a:1}to{--knobs-fade-a:0}}
|
|
889
|
+
@keyframes knobs-fade-b{from{--knobs-fade-b:0}to{--knobs-fade-b:1}}
|
|
890
|
+
@supports (animation-timeline:scroll()){
|
|
891
|
+
: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;
|
|
892
|
+
animation-timeline:scroll(self block),scroll(self block);animation-range:0 var(--knobs-fade-travel),calc(100% - var(--knobs-fade-travel)) 100%}
|
|
893
|
+
.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)}
|
|
894
|
+
.knobs-scroll-fade-x{--knobs-fade:16px;--knobs-fade-travel:4px;animation-timeline:scroll(self inline),scroll(self inline);
|
|
895
|
+
--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)}
|
|
896
|
+
.knobs-scroll-fade:has(.knobs-panel[data-gpu-active="true"]){-webkit-mask-image:none;mask-image:none}
|
|
897
|
+
.knobs-tree-row[data-editing] .knobs-tree-label{-webkit-mask-image:none;mask-image:none}
|
|
898
|
+
}
|
|
899
|
+
@supports not (animation-timeline:scroll()){.knobs-scroll-fade-x{text-overflow:ellipsis}}
|
|
900
|
+
|
|
901
|
+
/* Overlay scrollbars (trees, activity rails): a thin thumb over the content, so the rows never
|
|
902
|
+
give up width to a scrollbar as they start or stop overflowing. It shows while the content
|
|
903
|
+
scrolls or the pointer is over it. */
|
|
904
|
+
:is(.knobs-tree,.knobs-activity)::-webkit-scrollbar{display:none}
|
|
905
|
+
.knobs-scrollbar{position:sticky;top:0;z-index:3;height:0;pointer-events:none}
|
|
906
|
+
.knobs-scrollbar[hidden]{display:none}
|
|
907
|
+
.knobs-scrollbar-thumb{position:absolute;top:0;right:2px;width:5px;border-radius:3px;background:color-mix(in srgb,var(--ku-text) 30%,transparent);opacity:0;
|
|
908
|
+
transition:opacity .3s ease-out,background .15s}
|
|
909
|
+
:hover>.knobs-scrollbar>.knobs-scrollbar-thumb,.knobs-scrollbar:is([data-active],[data-dragging])>.knobs-scrollbar-thumb{opacity:1;pointer-events:auto;transition-duration:.12s,.15s}
|
|
910
|
+
.knobs-scrollbar-thumb:hover,.knobs-scrollbar[data-dragging]>.knobs-scrollbar-thumb{background:color-mix(in srgb,var(--ku-text) 48%,transparent)}
|
|
911
|
+
|
|
491
912
|
/* Split: panes along a row or column, hairline dividers with a wider grip. */
|
|
492
913
|
.knobs-split{position:relative;display:flex;width:100%;height:100%;min-width:0;min-height:0;overflow:hidden}
|
|
493
914
|
.knobs-split[data-direction="column"]{flex-direction:column}
|
|
@@ -500,7 +921,7 @@ var css = `
|
|
|
500
921
|
.knobs-pane-inner{position:absolute;inset:0;display:flex;flex-direction:column;min-width:0;min-height:0}
|
|
501
922
|
.knobs-pane-body{position:relative;flex:1;min-width:0;min-height:0;overflow:hidden}
|
|
502
923
|
.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}
|
|
924
|
+
.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
925
|
.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
926
|
.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
927
|
.knobs-pane-count{flex:none;color:var(--ku-dim);font-variant-numeric:tabular-nums}
|
|
@@ -511,17 +932,35 @@ var css = `
|
|
|
511
932
|
.knobs-ui .knobs-pane-btn[aria-pressed="true"]{color:var(--ku-accent)}
|
|
512
933
|
.knobs-pane-btn svg{width:13px;height:13px}
|
|
513
934
|
.knobs-pane-head[data-toggles]{cursor:pointer}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
.knobs-ui .knobs-pane-rail{position:absolute;
|
|
935
|
+
/* A collapsed pane's rail: its title along the edge; a click opens it. It holds on to the edge the
|
|
936
|
+
pane folds toward, as wide as the rail, over the card (which folds to its size): only its label
|
|
937
|
+
and chevron draw, and a nested split's slot, which has no card, gives it one of its own. */
|
|
938
|
+
.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
939
|
font-weight:var(--ku-title-weight);transition:background .15s,color .15s}
|
|
519
|
-
.knobs-
|
|
520
|
-
.knobs-split[data-direction="
|
|
940
|
+
.knobs-ui .knobs-pane[data-nested]>.knobs-pane-rail{background-color:var(--ku-pane-bg);box-shadow:var(--ku-pane-ring)}
|
|
941
|
+
.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}
|
|
942
|
+
.knobs-split[data-direction="row"]>.knobs-pane[data-edge="start"]>.knobs-pane-rail{right:0}
|
|
943
|
+
.knobs-split[data-direction="row"]>.knobs-pane[data-edge="end"]>.knobs-pane-rail{left:0}
|
|
944
|
+
.knobs-split[data-direction="column"]>.knobs-pane>.knobs-pane-rail{left:0;right:0;height:var(--ku-rail);padding:0 var(--ku-inset)}
|
|
945
|
+
.knobs-split[data-direction="column"]>.knobs-pane[data-edge="start"]>.knobs-pane-rail{bottom:0}
|
|
946
|
+
.knobs-split[data-direction="column"]>.knobs-pane[data-edge="end"]>.knobs-pane-rail{top:0}
|
|
521
947
|
.knobs-pane[data-collapsed]>.knobs-pane-rail{pointer-events:auto}
|
|
522
|
-
|
|
523
|
-
.knobs-pane-rail
|
|
524
|
-
.knobs-pane-rail
|
|
948
|
+
/* Its hover wash fades, rather than going in one frame as a click opens the pane. */
|
|
949
|
+
.knobs-ui .knobs-pane-rail::before{content:"";position:absolute;inset:0;border-radius:inherit;background:var(--ku-wash);opacity:0;transition:opacity .15s;pointer-events:none}
|
|
950
|
+
.knobs-pane-rail>*{position:relative}
|
|
951
|
+
.knobs-ui .knobs-pane[data-collapsed]>.knobs-pane-rail:is(:hover,:focus-visible){color:var(--ku-text)}
|
|
952
|
+
.knobs-ui .knobs-pane[data-collapsed]>.knobs-pane-rail:is(:hover,:focus-visible)::before{opacity:1}
|
|
953
|
+
.knobs-pane-rail-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
954
|
+
.knobs-pane-chevron{display:flex;flex:none;width:11px;height:11px;writing-mode:horizontal-tb;color:var(--ku-dim)}
|
|
955
|
+
.knobs-pane-turn{display:flex;width:100%;height:100%;transform-origin:50% 50%}
|
|
956
|
+
.knobs-pane-rail svg{width:11px;height:11px}
|
|
957
|
+
/* The rail's chevron stands in for the header's collapse icon (it turns into the rail's), so the
|
|
958
|
+
icon itself isn't drawn; hovering its button lights the chevron instead. */
|
|
959
|
+
.knobs-pane[data-morph]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head>.knobs-pane-collapse>svg{visibility:hidden}
|
|
960
|
+
/* So does the rail's label for the title, when it travels (split's fold: { title: "travel" }). */
|
|
961
|
+
.knobs-pane[data-travel]>.knobs-pane-clip>.knobs-pane-inner>.knobs-pane-head>.knobs-pane-title{visibility:hidden}
|
|
962
|
+
.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)}
|
|
963
|
+
.knobs-pane[data-morph]:not([data-collapsed])>.knobs-pane-rail .knobs-pane-chevron{transition:color .15s}
|
|
525
964
|
|
|
526
965
|
.knobs-divider{position:relative;z-index:2;flex:none;width:1px;background:var(--ku-divider);touch-action:none;outline:none}
|
|
527
966
|
.knobs-split[data-direction="column"]>.knobs-divider{width:auto;height:1px}
|
|
@@ -547,7 +986,7 @@ var css = `
|
|
|
547
986
|
:root[data-knobs-resizing] :is(iframe,canvas:not(.knobs-gpu-canvas)){pointer-events:none}
|
|
548
987
|
|
|
549
988
|
/* Tree: one scroller, rows placed by transform, only those near the view in the DOM. */
|
|
550
|
-
.knobs-tree{position:relative;overflow:auto;height:100%;outline:none;scrollbar-width:
|
|
989
|
+
.knobs-tree{position:relative;overflow:auto;height:100%;outline:none;scrollbar-width:none;overscroll-behavior:contain;user-select:none;-webkit-user-select:none}
|
|
551
990
|
.knobs-tree-space{position:relative;width:100%;pointer-events:none}
|
|
552
991
|
.knobs-tree-row{position:absolute;left:var(--ku-row-x);right:var(--ku-row-x);top:0;display:flex;align-items:center;height:var(--ku-row);padding-right:calc(var(--ku-inset) - 4px);
|
|
553
992
|
color:var(--ku-text);white-space:nowrap;cursor:default;will-change:transform;contain:layout style}
|
|
@@ -564,7 +1003,7 @@ var css = `
|
|
|
564
1003
|
.knobs-tree-row[aria-expanded="true"]>.knobs-tree-caret{transform:rotate(90deg)}
|
|
565
1004
|
.knobs-tree-row:not([aria-expanded])>.knobs-tree-caret{visibility:hidden}
|
|
566
1005
|
.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;
|
|
1006
|
+
.knobs-tree-label{position:relative;flex:1;min-width:0;overflow:hidden;font-weight:var(--ku-font-weight)}
|
|
568
1007
|
.knobs-tree-row[data-ancestor] .knobs-tree-label{color:var(--ku-label)}
|
|
569
1008
|
.knobs-tree-label .knobs-tree-mark{color:var(--ku-accent)}
|
|
570
1009
|
.knobs-tree-row[data-off~="visible"] :is(.knobs-tree-label,.knobs-tree-icon){opacity:.45}
|
|
@@ -602,7 +1041,7 @@ var css = `
|
|
|
602
1041
|
.knobs-tl-play svg{width:12px;height:12px}
|
|
603
1042
|
.knobs-timeline[data-playing] .knobs-tl-play{background:var(--ku-accent);color:var(--ku-bg)}
|
|
604
1043
|
.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}
|
|
1044
|
+
.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
1045
|
.knobs-tl-sub{font-size:var(--ku-text-meta);color:var(--ku-dim);white-space:nowrap}
|
|
607
1046
|
.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
1047
|
transition:background calc(var(--ku-hover-out) * 1ms)}
|
|
@@ -654,7 +1093,7 @@ function injectUiStyles(doc) {
|
|
|
654
1093
|
return;
|
|
655
1094
|
const style = doc.createElement("style");
|
|
656
1095
|
style.dataset.knobsUi = "";
|
|
657
|
-
style.textContent = css + readoutCss + overlayCss + bentoCss;
|
|
1096
|
+
style.textContent = css + readoutCss + overlayCss + bentoCss + activityCss + pickerCss + rolling_css_default;
|
|
658
1097
|
doc.head.append(style);
|
|
659
1098
|
}
|
|
660
1099
|
function injectUiPreset(doc, preset) {
|
|
@@ -743,6 +1182,11 @@ function injectPanelPreset(doc, preset) {
|
|
|
743
1182
|
doc.head.append(style);
|
|
744
1183
|
}
|
|
745
1184
|
var reducedMotion = (win) => win?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
1185
|
+
var tune = (s, m) => {
|
|
1186
|
+
s.omega = m.omega;
|
|
1187
|
+
s.zeta = m.zeta;
|
|
1188
|
+
return s;
|
|
1189
|
+
};
|
|
746
1190
|
function notifyLayout(doc) {
|
|
747
1191
|
doc.dispatchEvent(new Event("knobs-layout"));
|
|
748
1192
|
}
|
|
@@ -781,161 +1225,10 @@ var ICONS = {
|
|
|
781
1225
|
lock: svg('<rect x="3.5" y="7" width="9" height="6.5" rx="1.2"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2"/>'),
|
|
782
1226
|
unlock: svg('<rect x="3.5" y="7" width="9" height="6.5" rx="1.2"/><path d="M5.5 7V5a2.5 2.5 0 0 1 4.8-1"/>')
|
|
783
1227
|
};
|
|
784
|
-
// src/core/keys.ts
|
|
785
|
-
var MODS = ["Ctrl", "Alt", "Shift", "Meta"];
|
|
786
|
-
var ALIASES = {
|
|
787
|
-
ctrl: "Ctrl",
|
|
788
|
-
control: "Ctrl",
|
|
789
|
-
"⌃": "Ctrl",
|
|
790
|
-
alt: "Alt",
|
|
791
|
-
option: "Alt",
|
|
792
|
-
opt: "Alt",
|
|
793
|
-
"⌥": "Alt",
|
|
794
|
-
shift: "Shift",
|
|
795
|
-
"⇧": "Shift",
|
|
796
|
-
meta: "Meta",
|
|
797
|
-
cmd: "Meta",
|
|
798
|
-
command: "Meta",
|
|
799
|
-
"⌘": "Meta",
|
|
800
|
-
mod: "Mod"
|
|
801
|
-
};
|
|
802
|
-
var NAMED = {
|
|
803
|
-
" ": "Space",
|
|
804
|
-
space: "Space",
|
|
805
|
-
spacebar: "Space",
|
|
806
|
-
esc: "Escape",
|
|
807
|
-
escape: "Escape",
|
|
808
|
-
enter: "Enter",
|
|
809
|
-
return: "Enter",
|
|
810
|
-
tab: "Tab",
|
|
811
|
-
backspace: "Backspace",
|
|
812
|
-
delete: "Delete",
|
|
813
|
-
del: "Delete",
|
|
814
|
-
up: "ArrowUp",
|
|
815
|
-
down: "ArrowDown",
|
|
816
|
-
left: "ArrowLeft",
|
|
817
|
-
right: "ArrowRight",
|
|
818
|
-
arrowup: "ArrowUp",
|
|
819
|
-
arrowdown: "ArrowDown",
|
|
820
|
-
arrowleft: "ArrowLeft",
|
|
821
|
-
arrowright: "ArrowRight",
|
|
822
|
-
home: "Home",
|
|
823
|
-
end: "End",
|
|
824
|
-
pageup: "PageUp",
|
|
825
|
-
pagedown: "PageDown"
|
|
826
|
-
};
|
|
827
|
-
var isApple = () => typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.userAgentData?.platform ?? navigator.platform ?? "");
|
|
828
|
-
var keyName = (raw) => {
|
|
829
|
-
if (!raw)
|
|
830
|
-
return "";
|
|
831
|
-
const named = NAMED[raw.toLowerCase()];
|
|
832
|
-
if (named)
|
|
833
|
-
return named;
|
|
834
|
-
if (raw.length === 1)
|
|
835
|
-
return raw.toUpperCase();
|
|
836
|
-
if (/^f\d{1,2}$/i.test(raw))
|
|
837
|
-
return raw.toUpperCase();
|
|
838
|
-
return raw.charAt(0).toUpperCase() + raw.slice(1);
|
|
839
|
-
};
|
|
840
|
-
function normalizeCombo(combo) {
|
|
841
|
-
const trimmed = combo.trim();
|
|
842
|
-
if (!trimmed)
|
|
843
|
-
return "";
|
|
844
|
-
const parts = trimmed === "+" ? ["+"] : trimmed.replace(/\+\+$/, "+plus").split("+");
|
|
845
|
-
const mods = new Set;
|
|
846
|
-
let key = "";
|
|
847
|
-
for (const part of parts) {
|
|
848
|
-
const alias = ALIASES[part.trim().toLowerCase()] ?? ALIASES[part.trim()];
|
|
849
|
-
if (alias === "Mod")
|
|
850
|
-
mods.add(isApple() ? "Meta" : "Ctrl");
|
|
851
|
-
else if (alias)
|
|
852
|
-
mods.add(alias);
|
|
853
|
-
else
|
|
854
|
-
key = part === "plus" ? "+" : keyName(part.trim() || part);
|
|
855
|
-
}
|
|
856
|
-
if (!key)
|
|
857
|
-
return "";
|
|
858
|
-
return [...MODS.filter((m) => mods.has(m)), key].join("+");
|
|
859
|
-
}
|
|
860
|
-
var layout = null;
|
|
861
|
-
var layoutAsked = false;
|
|
862
|
-
function askLayout() {
|
|
863
|
-
if (layoutAsked)
|
|
864
|
-
return;
|
|
865
|
-
layoutAsked = true;
|
|
866
|
-
const keyboard = globalThis.navigator?.keyboard;
|
|
867
|
-
keyboard?.getLayoutMap?.().then((map) => {
|
|
868
|
-
layout = map;
|
|
869
|
-
}).catch(() => {});
|
|
870
|
-
}
|
|
871
|
-
function letterOf(event) {
|
|
872
|
-
askLayout();
|
|
873
|
-
const code = event.code ?? "";
|
|
874
|
-
if (/^[a-z]$/i.test(event.key) && !event.altKey)
|
|
875
|
-
return event.key.toUpperCase();
|
|
876
|
-
const mapped = layout?.get(code);
|
|
877
|
-
if (mapped && /^[a-z]$/i.test(mapped))
|
|
878
|
-
return mapped.toUpperCase();
|
|
879
|
-
return /^Key[A-Z]$/.test(code) ? code.slice(3) : "";
|
|
880
|
-
}
|
|
881
|
-
function comboFromEvent(event) {
|
|
882
|
-
if (["Shift", "Alt", "Meta", "Control", "CapsLock", "Fn", "OS"].includes(event.key))
|
|
883
|
-
return "";
|
|
884
|
-
const code = event.code ?? "";
|
|
885
|
-
const letter = letterOf(event);
|
|
886
|
-
const key = letter ? letter : /^Digit\d$/.test(code) ? code.slice(5) : code === "Space" ? "Space" : keyName(event.key);
|
|
887
|
-
return [
|
|
888
|
-
event.ctrlKey ? "Ctrl" : "",
|
|
889
|
-
event.altKey ? "Alt" : "",
|
|
890
|
-
event.shiftKey ? "Shift" : "",
|
|
891
|
-
event.metaKey ? "Meta" : "",
|
|
892
|
-
key
|
|
893
|
-
].filter(Boolean).join("+");
|
|
894
|
-
}
|
|
895
|
-
function matchesCombo(combo, event) {
|
|
896
|
-
const want = normalizeCombo(combo);
|
|
897
|
-
return want !== "" && want === comboFromEvent(event);
|
|
898
|
-
}
|
|
899
|
-
var GLYPHS = { Ctrl: "⌃", Alt: "⌥", Shift: "⇧", Meta: "⌘" };
|
|
900
|
-
var WORDS = { Ctrl: "Ctrl", Alt: "Alt", Shift: "Shift", Meta: "Meta" };
|
|
901
|
-
var KEY_GLYPHS = {
|
|
902
|
-
ArrowUp: "↑",
|
|
903
|
-
ArrowDown: "↓",
|
|
904
|
-
ArrowLeft: "←",
|
|
905
|
-
ArrowRight: "→",
|
|
906
|
-
Backspace: "⌫",
|
|
907
|
-
Delete: "⌦",
|
|
908
|
-
Enter: "↩",
|
|
909
|
-
Escape: "Esc",
|
|
910
|
-
Tab: "⇥",
|
|
911
|
-
PageUp: "PgUp",
|
|
912
|
-
PageDown: "PgDn"
|
|
913
|
-
};
|
|
914
|
-
function comboParts(combo, apple = isApple()) {
|
|
915
|
-
const norm = normalizeCombo(combo);
|
|
916
|
-
if (!norm)
|
|
917
|
-
return [];
|
|
918
|
-
const parts = norm === "+" ? ["+"] : norm.split("+");
|
|
919
|
-
if (norm.endsWith("++"))
|
|
920
|
-
parts.splice(-2, 2, "+");
|
|
921
|
-
const key = parts.pop();
|
|
922
|
-
const mods = parts;
|
|
923
|
-
const shown = KEY_GLYPHS[key] ?? key;
|
|
924
|
-
return apple ? [...mods.map((m) => GLYPHS[m]), shown] : [...mods.map((m) => WORDS[m]), shown];
|
|
925
|
-
}
|
|
926
|
-
|
|
927
1228
|
// src/core/schema.ts
|
|
928
1229
|
var READOUT_KINDS = new Set(["watch", "sparkline", "graph", "meter", "table", "log"]);
|
|
929
1230
|
var isReadout = (field) => READOUT_KINDS.has(field.kind);
|
|
930
1231
|
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
1232
|
|
|
940
1233
|
// src/ui/commands.ts
|
|
941
1234
|
var labelOf = (key, field) => field.label ?? key;
|
|
@@ -946,12 +1239,16 @@ function commandsFrom(controls, options = {}) {
|
|
|
946
1239
|
const id = (s) => `${controls.id}:${s}`;
|
|
947
1240
|
const schema = controls.schema;
|
|
948
1241
|
for (const [key, field] of Object.entries(schema)) {
|
|
1242
|
+
const keyOf = (item) => {
|
|
1243
|
+
const combo = controls.shortcut(key, item);
|
|
1244
|
+
return combo ? { shortcut: combo } : {};
|
|
1245
|
+
};
|
|
949
1246
|
if (field.kind === "action")
|
|
950
1247
|
out.push({
|
|
951
1248
|
id: id(key),
|
|
952
1249
|
label: labelOf(key, field),
|
|
953
1250
|
section: sec(field.group ? controls.groupLabel(field.group) ?? field.group : "Actions"),
|
|
954
|
-
...
|
|
1251
|
+
...keyOf(),
|
|
955
1252
|
disabled: controls.isDisabled(key),
|
|
956
1253
|
run: () => controls.action(key)
|
|
957
1254
|
});
|
|
@@ -961,7 +1258,7 @@ function commandsFrom(controls, options = {}) {
|
|
|
961
1258
|
id: id(`${key}/${item.id ?? item.label}`),
|
|
962
1259
|
label: item.label,
|
|
963
1260
|
section: sec(field.label ?? "Actions"),
|
|
964
|
-
...
|
|
1261
|
+
...keyOf(item.id ?? item.label),
|
|
965
1262
|
...item.disabled ? { disabled: true } : {},
|
|
966
1263
|
run: () => controls.action(key, item.id ?? item.label)
|
|
967
1264
|
});
|
|
@@ -1488,15 +1785,7 @@ function claimsHintKey(doc, key) {
|
|
|
1488
1785
|
const holder = doc;
|
|
1489
1786
|
return key === PAGE_HINT_KEY && Boolean(holder[KEY]?.listening);
|
|
1490
1787
|
}
|
|
1491
|
-
var isTyping =
|
|
1492
|
-
const el = target;
|
|
1493
|
-
if (!el || typeof el.tagName !== "string")
|
|
1494
|
-
return false;
|
|
1495
|
-
const tag = el.tagName;
|
|
1496
|
-
if (tag === "TEXTAREA" || tag === "SELECT" || el.isContentEditable)
|
|
1497
|
-
return true;
|
|
1498
|
-
return tag === "INPUT" && !["range", "checkbox", "radio", "button", "submit", "reset", "color"].includes(el.type);
|
|
1499
|
-
};
|
|
1788
|
+
var isTyping = isTypingTarget;
|
|
1500
1789
|
var PRESSABLE = "button,a[href],summary,[role=button],[role=tab],[role=radio],[role=switch],[role=checkbox],[role=menuitem],[role=option]";
|
|
1501
1790
|
function activateElement(el) {
|
|
1502
1791
|
const pressable = el.matches(PRESSABLE) || el.tabIndex < 0 && !el.matches("input,select,textarea");
|
|
@@ -2346,7 +2635,7 @@ function commandPalette(options) {
|
|
|
2346
2635
|
input.value = query;
|
|
2347
2636
|
field.append(input);
|
|
2348
2637
|
const list = doc.createElement("div");
|
|
2349
|
-
list.className = "knobs-palette-list";
|
|
2638
|
+
list.className = "knobs-palette-list knobs-scroll-fade";
|
|
2350
2639
|
list.setAttribute("role", "listbox");
|
|
2351
2640
|
list.id = `knobs-palette-list-${Math.random().toString(36).slice(2, 8)}`;
|
|
2352
2641
|
input.setAttribute("aria-controls", list.id);
|
|
@@ -3081,7 +3370,18 @@ function parseCssColor(raw, fallback = [1, 1, 1, 1]) {
|
|
|
3081
3370
|
parseInt(full.slice(4, 6), 16) / 255,
|
|
3082
3371
|
full.length === 8 ? parseInt(full.slice(6, 8), 16) / 255 : 1
|
|
3083
3372
|
];
|
|
3084
|
-
} else {
|
|
3373
|
+
} else if (s.startsWith("rgb")) {
|
|
3374
|
+
const nums = s.match(/[\d.]+/g)?.map(Number);
|
|
3375
|
+
if (nums && nums.length >= 3) {
|
|
3376
|
+
out = [
|
|
3377
|
+
Math.min(1, Math.max(0, nums[0] / 255)),
|
|
3378
|
+
Math.min(1, Math.max(0, nums[1] / 255)),
|
|
3379
|
+
Math.min(1, Math.max(0, nums[2] / 255)),
|
|
3380
|
+
nums.length >= 4 ? Math.min(1, Math.max(0, nums[3])) : 1
|
|
3381
|
+
];
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
if (!out) {
|
|
3085
3385
|
const ctx = probeCtx();
|
|
3086
3386
|
if (ctx) {
|
|
3087
3387
|
ctx.clearRect(0, 0, 1, 1);
|
|
@@ -3801,7 +4101,7 @@ function paletteOf(el, now = performance.now()) {
|
|
|
3801
4101
|
palettes.set(el, { at: now, p });
|
|
3802
4102
|
return p;
|
|
3803
4103
|
}
|
|
3804
|
-
var reduced = (doc) => doc.defaultView
|
|
4104
|
+
var reduced = (doc) => reducedMotion(doc.defaultView);
|
|
3805
4105
|
function make(doc) {
|
|
3806
4106
|
return (tag, cls, text) => {
|
|
3807
4107
|
const node = doc.createElement(tag);
|
|
@@ -4392,7 +4692,7 @@ function createGraph(env) {
|
|
|
4392
4692
|
font: "meta",
|
|
4393
4693
|
align: "left"
|
|
4394
4694
|
});
|
|
4395
|
-
items.push(...k.value.texts(p,
|
|
4695
|
+
items.push(...k.value.texts(p, p.text));
|
|
4396
4696
|
}
|
|
4397
4697
|
items.push({
|
|
4398
4698
|
el: top,
|
|
@@ -5408,6 +5708,43 @@ function edgeOf(panes, id) {
|
|
|
5408
5708
|
const first = panes.findIndex((p) => flex.has(p.id));
|
|
5409
5709
|
return panes.findIndex((p) => p.id === id) < first ? "start" : "end";
|
|
5410
5710
|
}
|
|
5711
|
+
function foldProgress(size, open, rail) {
|
|
5712
|
+
const span = open - rail;
|
|
5713
|
+
if (span <= 0)
|
|
5714
|
+
return size > rail ? 0 : 1;
|
|
5715
|
+
return Math.min(1, Math.max(0, (open - size) / span));
|
|
5716
|
+
}
|
|
5717
|
+
var FACE_OUT = 0.4;
|
|
5718
|
+
var FACE_IN = 0.3;
|
|
5719
|
+
var clamp01 = (x) => Math.min(1, Math.max(0, x));
|
|
5720
|
+
function face(prev, away) {
|
|
5721
|
+
const lo = clamp01(1 - away / FACE_IN);
|
|
5722
|
+
const hi = clamp01(1 - away / FACE_OUT);
|
|
5723
|
+
return Math.min(hi, Math.max(lo, prev));
|
|
5724
|
+
}
|
|
5725
|
+
function foldFaces(prev, p) {
|
|
5726
|
+
return { content: face(prev.content, p), rail: face(prev.rail, 1 - p) };
|
|
5727
|
+
}
|
|
5728
|
+
function chevronTurn(p, edge) {
|
|
5729
|
+
return (edge === "start" ? 180 : -180) * (1 - clamp01(p));
|
|
5730
|
+
}
|
|
5731
|
+
function chevronFlip(f, edge) {
|
|
5732
|
+
return chevronTurn(f, edge);
|
|
5733
|
+
}
|
|
5734
|
+
var FOLD_STYLE = { chevron: "flip", title: "travel", duration: 0.25 };
|
|
5735
|
+
function foldStyle(options = {}) {
|
|
5736
|
+
const duration = options.duration;
|
|
5737
|
+
return {
|
|
5738
|
+
chevron: options.chevron === "turn" ? "turn" : "flip",
|
|
5739
|
+
title: options.title === "fade" ? "fade" : "travel",
|
|
5740
|
+
duration: duration !== undefined && Number.isFinite(duration) && duration > 0 ? Math.min(2, duration) : FOLD_STYLE.duration
|
|
5741
|
+
};
|
|
5742
|
+
}
|
|
5743
|
+
function titleTravel(at, open, rail, edge, p) {
|
|
5744
|
+
const k = 1 - clamp01(p);
|
|
5745
|
+
const dx = at.title - at.label - (edge === "start" ? open - rail : 0);
|
|
5746
|
+
return { x: dx * k, y: at.dy * k, turn: -90 * k };
|
|
5747
|
+
}
|
|
5411
5748
|
function parseLayout(raw, panes) {
|
|
5412
5749
|
if (!raw || typeof raw !== "object")
|
|
5413
5750
|
return;
|
|
@@ -5435,8 +5772,26 @@ function serializeLayout(layout) {
|
|
|
5435
5772
|
}
|
|
5436
5773
|
|
|
5437
5774
|
// src/ui/split.ts
|
|
5438
|
-
var
|
|
5775
|
+
var FLIP = springMotion({ duration: 0.25, bounce: 0 });
|
|
5776
|
+
var FLIP_DEPTH = 28;
|
|
5439
5777
|
var SETTLE = springMotion({ duration: 0.3, bounce: 0 });
|
|
5778
|
+
var CONTENT_BLUR = 3;
|
|
5779
|
+
var LABEL_BLUR = 2;
|
|
5780
|
+
var COUNT_CLEAR = 0.12;
|
|
5781
|
+
var put = (el, prop, value) => {
|
|
5782
|
+
if (el.style.getPropertyValue(prop) !== value)
|
|
5783
|
+
el.style.setProperty(prop, value);
|
|
5784
|
+
};
|
|
5785
|
+
var hide = (el, hidden) => {
|
|
5786
|
+
if (hidden)
|
|
5787
|
+
el.setAttribute("aria-hidden", "true");
|
|
5788
|
+
else
|
|
5789
|
+
el.removeAttribute("aria-hidden");
|
|
5790
|
+
};
|
|
5791
|
+
var fade = (el, a, blur) => {
|
|
5792
|
+
put(el, "opacity", a >= 1 ? "" : a.toFixed(3));
|
|
5793
|
+
put(el, "filter", a >= 1 || a <= 0 || !blur ? "" : `blur(${(blur * (1 - a)).toFixed(2)}px)`);
|
|
5794
|
+
};
|
|
5440
5795
|
var iconNode = (doc, icon, label) => {
|
|
5441
5796
|
if (icon instanceof Node)
|
|
5442
5797
|
return icon;
|
|
@@ -5455,6 +5810,8 @@ function split(container, options) {
|
|
|
5455
5810
|
const row = direction === "row";
|
|
5456
5811
|
const specs = options.panes;
|
|
5457
5812
|
const flex = flexible(specs);
|
|
5813
|
+
const style = foldStyle(options.fold);
|
|
5814
|
+
const COLLAPSE = springMotion({ duration: style.duration, bounce: 0 });
|
|
5458
5815
|
const store = options.storage === undefined ? browserStorage() : options.storage;
|
|
5459
5816
|
const key = options.id ? storageKey(options.id, "split") : undefined;
|
|
5460
5817
|
const saved = (() => {
|
|
@@ -5483,13 +5840,31 @@ function split(container, options) {
|
|
|
5483
5840
|
const el = doc.createElement("section");
|
|
5484
5841
|
el.className = "knobs-pane";
|
|
5485
5842
|
el.dataset.pane = spec.id;
|
|
5843
|
+
const edge = edgeOf(specs, spec.id);
|
|
5844
|
+
el.dataset.edge = edge;
|
|
5486
5845
|
const clip = doc.createElement("div");
|
|
5487
5846
|
clip.className = "knobs-pane-clip";
|
|
5488
5847
|
const inner = doc.createElement("div");
|
|
5489
5848
|
inner.className = "knobs-pane-inner";
|
|
5490
5849
|
const body = doc.createElement("div");
|
|
5491
5850
|
body.className = "knobs-pane-body";
|
|
5492
|
-
const
|
|
5851
|
+
const shut = Boolean(collapsed[spec.id]);
|
|
5852
|
+
const view = {
|
|
5853
|
+
spec,
|
|
5854
|
+
el,
|
|
5855
|
+
clip,
|
|
5856
|
+
inner,
|
|
5857
|
+
body,
|
|
5858
|
+
edge,
|
|
5859
|
+
open: 0,
|
|
5860
|
+
shown: 0,
|
|
5861
|
+
folding: false,
|
|
5862
|
+
faces: { content: shut ? 0 : 1, rail: shut ? 1 : 0 },
|
|
5863
|
+
headPx: 0,
|
|
5864
|
+
chev: { iconEnd: 0, chevEnd: 0, dy: 0, scale: 1 },
|
|
5865
|
+
places: { title: 0, label: 0, dy: 0 },
|
|
5866
|
+
flip: new Spring(shut ? 1 : 0, FLIP.omega, FLIP.zeta, 0.002)
|
|
5867
|
+
};
|
|
5493
5868
|
if (spec.title !== undefined) {
|
|
5494
5869
|
const head = doc.createElement("header");
|
|
5495
5870
|
head.className = "knobs-pane-head";
|
|
@@ -5527,9 +5902,10 @@ function split(container, options) {
|
|
|
5527
5902
|
tooltip(b, () => collapsed[spec.id] ? "Open" : row ? "Collapse" : "Fold");
|
|
5528
5903
|
b.innerHTML = row ? ICONS.caret : ICONS.chevronDown;
|
|
5529
5904
|
if (row)
|
|
5530
|
-
b.firstElementChild?.setAttribute("style",
|
|
5905
|
+
b.firstElementChild?.setAttribute("style", edge === "start" ? "transform:scaleX(-1)" : "");
|
|
5531
5906
|
else
|
|
5532
5907
|
b.firstElementChild?.classList.add("knobs-pane-caret");
|
|
5908
|
+
view.toggleIcon = b.firstElementChild ?? undefined;
|
|
5533
5909
|
b.addEventListener("click", (e) => {
|
|
5534
5910
|
e.stopPropagation();
|
|
5535
5911
|
setCollapsed(spec.id, !collapsed[spec.id]);
|
|
@@ -5538,7 +5914,12 @@ function split(container, options) {
|
|
|
5538
5914
|
if (!row) {
|
|
5539
5915
|
head.dataset.toggles = "";
|
|
5540
5916
|
head.addEventListener("click", () => setCollapsed(spec.id, !collapsed[spec.id]));
|
|
5541
|
-
}
|
|
5917
|
+
} else
|
|
5918
|
+
head.addEventListener("dblclick", (e) => {
|
|
5919
|
+
if (e.target.closest(".knobs-pane-btn"))
|
|
5920
|
+
return;
|
|
5921
|
+
setCollapsed(spec.id, true);
|
|
5922
|
+
});
|
|
5542
5923
|
}
|
|
5543
5924
|
inner.append(head);
|
|
5544
5925
|
view.head = head;
|
|
@@ -5548,8 +5929,10 @@ function split(container, options) {
|
|
|
5548
5929
|
inner.append(body);
|
|
5549
5930
|
clip.append(inner);
|
|
5550
5931
|
el.append(clip);
|
|
5551
|
-
if (spec.scroll ?? spec.title !== undefined)
|
|
5932
|
+
if (spec.scroll ?? spec.title !== undefined) {
|
|
5552
5933
|
el.dataset.scroll = "";
|
|
5934
|
+
body.classList.add("knobs-scroll-fade");
|
|
5935
|
+
}
|
|
5553
5936
|
if (spec.element)
|
|
5554
5937
|
body.append(spec.element);
|
|
5555
5938
|
if (spec.collapsible && (row || !view.head)) {
|
|
@@ -5561,13 +5944,22 @@ function split(container, options) {
|
|
|
5561
5944
|
rail.setAttribute("aria-label", `Open ${label}`);
|
|
5562
5945
|
tooltip(rail, `Open ${label}`, { placement: row ? "right" : "top" });
|
|
5563
5946
|
const text = doc.createElement("span");
|
|
5947
|
+
text.className = "knobs-pane-rail-label";
|
|
5564
5948
|
text.textContent = spec.rail ?? spec.title ?? "";
|
|
5565
|
-
|
|
5566
|
-
|
|
5949
|
+
const chevron = doc.createElement("span");
|
|
5950
|
+
chevron.className = "knobs-pane-chevron";
|
|
5951
|
+
const turn = doc.createElement("span");
|
|
5952
|
+
turn.className = "knobs-pane-turn";
|
|
5953
|
+
turn.innerHTML = row ? ICONS.caret.replace("<svg", `<svg style="transform:scaleX(${edge === "start" ? 1 : -1})"`) : ICONS.chevronDown;
|
|
5954
|
+
chevron.append(turn);
|
|
5955
|
+
rail.append(chevron, text);
|
|
5567
5956
|
rail.addEventListener("click", () => setCollapsed(spec.id, false));
|
|
5568
5957
|
el.append(rail);
|
|
5569
5958
|
el.dataset.rail = "";
|
|
5570
5959
|
view.rail = rail;
|
|
5960
|
+
view.railLabel = text;
|
|
5961
|
+
view.chevron = chevron;
|
|
5962
|
+
view.turn = turn;
|
|
5571
5963
|
}
|
|
5572
5964
|
return view;
|
|
5573
5965
|
};
|
|
@@ -5597,9 +5989,10 @@ function split(container, options) {
|
|
|
5597
5989
|
const total = () => along(root);
|
|
5598
5990
|
let paneM = 0;
|
|
5599
5991
|
const marginOf = (v) => v.el.hasAttribute("data-nested") ? 0 : paneM;
|
|
5600
|
-
const headerSize = (v) => v.head ? v.
|
|
5992
|
+
const headerSize = (v) => v.head ? v.headPx + marginOf(v) * 2 : 0;
|
|
5601
5993
|
let railPx = 0;
|
|
5602
|
-
|
|
5994
|
+
let measured = false;
|
|
5995
|
+
const measure = () => {
|
|
5603
5996
|
syncFrame(root);
|
|
5604
5997
|
const probe = doc.createElement("div");
|
|
5605
5998
|
probe.style.cssText = "position:absolute;visibility:hidden;width:var(--ku-rail);height:var(--ku-pane-m)";
|
|
@@ -5608,8 +6001,44 @@ function split(container, options) {
|
|
|
5608
6001
|
paneM = r.height;
|
|
5609
6002
|
railPx = (r.width || 26) + paneM * 2;
|
|
5610
6003
|
probe.remove();
|
|
6004
|
+
for (const v of views.values())
|
|
6005
|
+
if (v.head)
|
|
6006
|
+
v.headPx = v.head.getBoundingClientRect().height;
|
|
6007
|
+
measured = root.isConnected && r.width > 0;
|
|
6008
|
+
};
|
|
6009
|
+
const measureChevrons = (only) => {
|
|
6010
|
+
if (!row)
|
|
6011
|
+
return;
|
|
6012
|
+
for (const v of only ? [only] : views.values()) {
|
|
6013
|
+
if (!v.chevron || !v.toggleIcon || !v.rail || !v.railLabel)
|
|
6014
|
+
continue;
|
|
6015
|
+
const inner = v.inner.getBoundingClientRect();
|
|
6016
|
+
const icon = v.toggleIcon.getBoundingClientRect();
|
|
6017
|
+
const rail = v.rail.getBoundingClientRect();
|
|
6018
|
+
const chev = v.chevron.getBoundingClientRect();
|
|
6019
|
+
if (!inner.width || !chev.width)
|
|
6020
|
+
continue;
|
|
6021
|
+
v.chev = {
|
|
6022
|
+
iconEnd: inner.right - (icon.left + icon.width / 2),
|
|
6023
|
+
chevEnd: rail.right - (chev.left + chev.width / 2),
|
|
6024
|
+
dy: icon.top + icon.height / 2 - inner.top - (chev.top + chev.height / 2 - rail.top),
|
|
6025
|
+
scale: icon.width / chev.width
|
|
6026
|
+
};
|
|
6027
|
+
if (!v.titleEl)
|
|
6028
|
+
continue;
|
|
6029
|
+
const moved = v.railLabel.style.transform;
|
|
6030
|
+
v.railLabel.style.transform = "none";
|
|
6031
|
+
const label = v.railLabel.getBoundingClientRect();
|
|
6032
|
+
v.railLabel.style.transform = moved;
|
|
6033
|
+
const title = v.titleEl.getBoundingClientRect();
|
|
6034
|
+
v.places = {
|
|
6035
|
+
title: title.left + title.width / 2 - inner.left,
|
|
6036
|
+
label: label.left + label.width / 2 - rail.left,
|
|
6037
|
+
dy: title.top + title.height / 2 - inner.top - (label.top + label.height / 2 - rail.top)
|
|
6038
|
+
};
|
|
6039
|
+
}
|
|
5611
6040
|
};
|
|
5612
|
-
|
|
6041
|
+
measure();
|
|
5613
6042
|
const rail = (id) => {
|
|
5614
6043
|
const v = views.get(id);
|
|
5615
6044
|
return !row && v.head ? headerSize(v) : railPx;
|
|
@@ -5622,47 +6051,105 @@ function split(container, options) {
|
|
|
5622
6051
|
};
|
|
5623
6052
|
const target = () => solve({ panes: specs, sizes, collapsed, total: total(), rail });
|
|
5624
6053
|
const current = () => solve({ panes: specs, sizes, collapsed, total: total(), rail, fixed: fixed() });
|
|
6054
|
+
const SIDES = { row: ["right", "left"], column: ["bottom", "top"] };
|
|
6055
|
+
const sides = (v) => {
|
|
6056
|
+
const [a, b] = SIDES[direction];
|
|
6057
|
+
return v.edge === "start" ? [a, b] : [b, a];
|
|
6058
|
+
};
|
|
6059
|
+
const renderFold = (v, size) => {
|
|
6060
|
+
const id = v.spec.id;
|
|
6061
|
+
const isCollapsed = collapsed[id];
|
|
6062
|
+
const folding = isCollapsed || v.folding;
|
|
6063
|
+
const r = rail(id);
|
|
6064
|
+
const open = folding ? Math.max(v.open, r + 1) : size;
|
|
6065
|
+
const p = folding ? foldProgress(size, open, r) : 0;
|
|
6066
|
+
v.faces = foldFaces(v.faces, p);
|
|
6067
|
+
const m = marginOf(v);
|
|
6068
|
+
const settled = !springs.has(id);
|
|
6069
|
+
const content = isCollapsed && settled ? 1 : v.faces.content;
|
|
6070
|
+
put(v.rail ? v.inner : v.body, "will-change", v.folding ? "opacity, filter" : "");
|
|
6071
|
+
if (!v.rail) {
|
|
6072
|
+
put(v.inner, "height", folding ? `${open - m * 2}px` : "");
|
|
6073
|
+
put(v.inner, "bottom", folding ? "auto" : "");
|
|
6074
|
+
fade(v.body, content, CONTENT_BLUR);
|
|
6075
|
+
if (v.toggleIcon)
|
|
6076
|
+
put(v.toggleIcon, "transform", p ? `rotate(${(-90 * p).toFixed(2)}deg)` : "");
|
|
6077
|
+
hide(v.body, isCollapsed && settled);
|
|
6078
|
+
return;
|
|
6079
|
+
}
|
|
6080
|
+
const [side, far] = sides(v);
|
|
6081
|
+
put(v.inner, row ? "width" : "height", folding ? `${open - m * 2}px` : "");
|
|
6082
|
+
put(v.inner, side, folding ? "0" : "");
|
|
6083
|
+
put(v.inner, far, folding ? "auto" : "");
|
|
6084
|
+
fade(v.inner, content, CONTENT_BLUR);
|
|
6085
|
+
hide(v.clip, isCollapsed && settled);
|
|
6086
|
+
const morph = row && Boolean(v.toggleIcon) && !v.el.hasAttribute("data-nested");
|
|
6087
|
+
v.el.toggleAttribute("data-morph", morph);
|
|
6088
|
+
const label = v.railLabel;
|
|
6089
|
+
const travel = morph && style.title === "travel" && Boolean(v.titleEl) && label.textContent === v.titleEl.textContent;
|
|
6090
|
+
v.el.toggleAttribute("data-travel", travel && folding);
|
|
6091
|
+
if (v.countEl)
|
|
6092
|
+
put(v.countEl, "opacity", travel && folding && p > 0 ? Math.max(0, 1 - p / COUNT_CLEAR).toFixed(3) : "");
|
|
6093
|
+
const k = 1 - p;
|
|
6094
|
+
if (travel && !folding) {
|
|
6095
|
+
put(label, "opacity", "0");
|
|
6096
|
+
put(label, "filter", "");
|
|
6097
|
+
put(label, "transform", "");
|
|
6098
|
+
put(label, "color", "");
|
|
6099
|
+
} else if (travel) {
|
|
6100
|
+
const t = titleTravel(v.places, open, r, v.edge, p);
|
|
6101
|
+
put(label, "opacity", "");
|
|
6102
|
+
put(label, "filter", "");
|
|
6103
|
+
put(label, "transform", k === 0 ? "" : `translate(${t.x.toFixed(2)}px,${t.y.toFixed(2)}px) rotate(${t.turn.toFixed(2)}deg)`);
|
|
6104
|
+
put(label, "color", k === 0 ? "" : `color-mix(in srgb,var(--ku-text) ${(k * 100).toFixed(1)}%,var(--ku-label))`);
|
|
6105
|
+
} else {
|
|
6106
|
+
put(label, "transform", "");
|
|
6107
|
+
put(label, "color", "");
|
|
6108
|
+
}
|
|
6109
|
+
if (morph) {
|
|
6110
|
+
put(v.rail, "opacity", "1");
|
|
6111
|
+
if (!travel)
|
|
6112
|
+
fade(label, v.faces.rail, LABEL_BLUR);
|
|
6113
|
+
const c = v.chev;
|
|
6114
|
+
const dx = c.chevEnd - c.iconEnd + (v.edge === "end" ? open - r : 0);
|
|
6115
|
+
const move = `translate(${(dx * k).toFixed(2)}px,${(c.dy * k).toFixed(2)}px)`;
|
|
6116
|
+
const size = `scale(${(1 + (c.scale - 1) * k).toFixed(4)})`;
|
|
6117
|
+
if (style.chevron === "turn")
|
|
6118
|
+
put(v.turn, "transform", k === 0 ? "" : `${move} rotate(${chevronTurn(p, v.edge).toFixed(2)}deg) ${size}`);
|
|
6119
|
+
else {
|
|
6120
|
+
const turn = chevronFlip(v.flip.x, v.edge);
|
|
6121
|
+
const over = v.flip.resting ? turn === 0 ? "" : "scaleX(-1)" : `perspective(${FLIP_DEPTH}px) rotateY(${turn.toFixed(2)}deg)`;
|
|
6122
|
+
put(v.turn, "transform", k === 0 && !over ? "" : `${move} ${size} ${over}`);
|
|
6123
|
+
}
|
|
6124
|
+
} else {
|
|
6125
|
+
const a = v.faces.rail;
|
|
6126
|
+
put(v.rail, "opacity", a >= 1 ? "1" : a.toFixed(3));
|
|
6127
|
+
put(label, "opacity", "");
|
|
6128
|
+
put(label, "filter", a >= 1 || a <= 0 ? "" : `blur(${(LABEL_BLUR * (1 - a)).toFixed(2)}px)`);
|
|
6129
|
+
put(v.turn, "transform", "");
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
5625
6132
|
let lastReport = "";
|
|
5626
6133
|
const render = (shown) => {
|
|
5627
6134
|
for (const spec of specs) {
|
|
5628
6135
|
const v = views.get(spec.id);
|
|
5629
6136
|
const size = Math.max(0, shown[spec.id] ?? 0);
|
|
5630
6137
|
v.shown = size;
|
|
5631
|
-
v.el
|
|
5632
|
-
v.el
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
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
|
-
}
|
|
6138
|
+
put(v.el, "flex-basis", `${size}px`);
|
|
6139
|
+
put(v.el, row ? "width" : "height", `${size}px`);
|
|
6140
|
+
v.el.toggleAttribute("data-collapsed", collapsed[spec.id]);
|
|
6141
|
+
v.el.toggleAttribute("data-settled", !springs.has(spec.id));
|
|
6142
|
+
if (spec.collapsible)
|
|
6143
|
+
renderFold(v, size);
|
|
5660
6144
|
}
|
|
5661
6145
|
dividers.forEach((d, i) => {
|
|
5662
6146
|
const a = specs[i];
|
|
5663
6147
|
const b = specs[i + 1];
|
|
5664
|
-
|
|
5665
|
-
d.
|
|
6148
|
+
const now = String(Math.round(views.get(a.id).shown));
|
|
6149
|
+
if (d.getAttribute("aria-valuenow") !== now)
|
|
6150
|
+
d.setAttribute("aria-valuenow", now);
|
|
6151
|
+
if (!d.hasAttribute("aria-controls"))
|
|
6152
|
+
d.setAttribute("aria-controls", `${a.id} ${b.id}`);
|
|
5666
6153
|
});
|
|
5667
6154
|
const layout = snapshot();
|
|
5668
6155
|
const report = JSON.stringify(layout);
|
|
@@ -5695,51 +6182,76 @@ function split(container, options) {
|
|
|
5695
6182
|
const loop = frameLoop(win, (dt) => {
|
|
5696
6183
|
for (const [id, s] of springs) {
|
|
5697
6184
|
s.step(dt);
|
|
5698
|
-
if (s.resting)
|
|
6185
|
+
if (s.resting) {
|
|
5699
6186
|
springs.delete(id);
|
|
6187
|
+
views.get(id).folding = false;
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
let flipping = false;
|
|
6191
|
+
for (const v of views.values()) {
|
|
6192
|
+
v.flip.step(dt);
|
|
6193
|
+
if (!v.flip.resting)
|
|
6194
|
+
flipping = true;
|
|
5700
6195
|
}
|
|
5701
6196
|
const shown = current();
|
|
5702
|
-
|
|
5703
|
-
if (springs.size === 0) {
|
|
6197
|
+
if (springs.size === 0)
|
|
5704
6198
|
rememberOpen(shown);
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
return springs.size > 0;
|
|
6199
|
+
render(shown);
|
|
6200
|
+
return springs.size > 0 || flipping;
|
|
5708
6201
|
});
|
|
5709
6202
|
const animate = (motion = SETTLE) => {
|
|
5710
6203
|
const to = target();
|
|
6204
|
+
for (const v of views.values())
|
|
6205
|
+
if (v.folding && !collapsed[v.spec.id])
|
|
6206
|
+
v.open = to[v.spec.id];
|
|
5711
6207
|
if (reducedMotion(win)) {
|
|
5712
6208
|
springs.clear();
|
|
5713
|
-
|
|
6209
|
+
const arriving = [...views.values()].filter((v) => v.folding).map((v) => collapsed[v.spec.id] ? v.rail : v.rail ? v.inner : v.body);
|
|
6210
|
+
for (const v of views.values()) {
|
|
6211
|
+
v.folding = false;
|
|
6212
|
+
v.flip.snap(collapsed[v.spec.id] ? 1 : 0);
|
|
6213
|
+
}
|
|
5714
6214
|
rememberOpen(to);
|
|
6215
|
+
render(to);
|
|
6216
|
+
for (const el of arriving)
|
|
6217
|
+
el?.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
6218
|
+
duration: 160,
|
|
6219
|
+
easing: "cubic-bezier(.2,.8,.2,1)"
|
|
6220
|
+
});
|
|
5715
6221
|
return;
|
|
5716
6222
|
}
|
|
5717
6223
|
for (const spec of specs) {
|
|
5718
|
-
const
|
|
6224
|
+
const v = views.get(spec.id);
|
|
5719
6225
|
const goal = to[spec.id];
|
|
5720
6226
|
const s = springs.get(spec.id);
|
|
5721
6227
|
if (s) {
|
|
5722
6228
|
s.omega = motion.omega;
|
|
5723
6229
|
s.zeta = motion.zeta;
|
|
5724
6230
|
s.set(goal);
|
|
5725
|
-
} else if (Math.abs(goal -
|
|
5726
|
-
springs.set(spec.id, new Spring(
|
|
5727
|
-
}
|
|
6231
|
+
} else if (Math.abs(goal - v.shown) > 0.5) {
|
|
6232
|
+
springs.set(spec.id, new Spring(v.shown, motion.omega, motion.zeta, 0.2).set(goal));
|
|
6233
|
+
} else
|
|
6234
|
+
v.folding = false;
|
|
5728
6235
|
}
|
|
5729
6236
|
loop.wake();
|
|
5730
6237
|
};
|
|
6238
|
+
const fold = (id, value) => {
|
|
6239
|
+
const v = views.get(id);
|
|
6240
|
+
if (value && !v.folding)
|
|
6241
|
+
v.open = v.shown;
|
|
6242
|
+
collapsed[id] = value;
|
|
6243
|
+
v.folding = true;
|
|
6244
|
+
v.flip.set(value ? 1 : 0);
|
|
6245
|
+
};
|
|
6246
|
+
const release = (id) => {
|
|
6247
|
+
springs.delete(id);
|
|
6248
|
+
views.get(id).folding = false;
|
|
6249
|
+
};
|
|
5731
6250
|
function setCollapsed(id, value, save = true) {
|
|
5732
6251
|
const spec = specs.find((p) => p.id === id);
|
|
5733
6252
|
if (!spec?.collapsible || collapsed[id] === value)
|
|
5734
6253
|
return;
|
|
5735
|
-
|
|
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;
|
|
6254
|
+
fold(id, value);
|
|
5743
6255
|
if (save)
|
|
5744
6256
|
persist();
|
|
5745
6257
|
animate(COLLAPSE);
|
|
@@ -5761,7 +6273,8 @@ function split(container, options) {
|
|
|
5761
6273
|
d.focus({ preventScroll: true });
|
|
5762
6274
|
const shown = current();
|
|
5763
6275
|
for (const id of [a.id, b.id])
|
|
5764
|
-
|
|
6276
|
+
if (!collapsed[id])
|
|
6277
|
+
release(id);
|
|
5765
6278
|
start = { ...shown };
|
|
5766
6279
|
for (const id of [a.id, b.id])
|
|
5767
6280
|
if (collapsed[id])
|
|
@@ -5795,7 +6308,7 @@ function split(container, options) {
|
|
|
5795
6308
|
return;
|
|
5796
6309
|
setSizes(result.sizes);
|
|
5797
6310
|
for (const id of [a.id, b.id])
|
|
5798
|
-
|
|
6311
|
+
release(id);
|
|
5799
6312
|
const shown = current();
|
|
5800
6313
|
render(shown);
|
|
5801
6314
|
rememberOpen(shown);
|
|
@@ -5858,17 +6371,21 @@ function split(container, options) {
|
|
|
5858
6371
|
}
|
|
5859
6372
|
function reset(...ids) {
|
|
5860
6373
|
const which = ids.length ? ids : specs.map((p) => p.id);
|
|
6374
|
+
let folds = false;
|
|
5861
6375
|
for (const id of which) {
|
|
5862
6376
|
delete sizes[id];
|
|
5863
6377
|
const spec = specs.find((p) => p.id === id);
|
|
5864
|
-
|
|
5865
|
-
|
|
6378
|
+
const shut = Boolean(spec?.collapsed);
|
|
6379
|
+
if (spec?.collapsible && collapsed[id] !== shut) {
|
|
6380
|
+
fold(id, shut);
|
|
6381
|
+
folds = true;
|
|
6382
|
+
}
|
|
5866
6383
|
}
|
|
5867
6384
|
if (which.some((id) => flex.has(id)))
|
|
5868
6385
|
for (const id of flex)
|
|
5869
6386
|
delete sizes[id];
|
|
5870
6387
|
persist();
|
|
5871
|
-
animate();
|
|
6388
|
+
animate(folds ? COLLAPSE : SETTLE);
|
|
5872
6389
|
}
|
|
5873
6390
|
{
|
|
5874
6391
|
const first = target();
|
|
@@ -5877,18 +6394,29 @@ function split(container, options) {
|
|
|
5877
6394
|
views.get(spec.id).open = collapsed[spec.id] ? solve({ panes: specs, sizes, collapsed: open, total: total(), rail })[spec.id] : first[spec.id];
|
|
5878
6395
|
}
|
|
5879
6396
|
render(first);
|
|
6397
|
+
measureChevrons();
|
|
6398
|
+
render(first);
|
|
5880
6399
|
}
|
|
5881
|
-
const relayout = () => {
|
|
5882
|
-
|
|
5883
|
-
|
|
6400
|
+
const relayout = (remeasure) => {
|
|
6401
|
+
if (remeasure)
|
|
6402
|
+
measure();
|
|
6403
|
+
if (springs.size) {
|
|
6404
|
+
if (remeasure)
|
|
6405
|
+
measureChevrons();
|
|
5884
6406
|
return loop.wake();
|
|
6407
|
+
}
|
|
5885
6408
|
const shown = target();
|
|
5886
|
-
render(shown);
|
|
5887
6409
|
rememberOpen(shown);
|
|
6410
|
+
render(shown);
|
|
6411
|
+
if (remeasure) {
|
|
6412
|
+
measureChevrons();
|
|
6413
|
+
render(shown);
|
|
6414
|
+
}
|
|
5888
6415
|
};
|
|
5889
|
-
const ro = new ResizeObserver(relayout);
|
|
6416
|
+
const ro = new ResizeObserver(() => relayout(!measured));
|
|
5890
6417
|
ro.observe(root);
|
|
5891
|
-
|
|
6418
|
+
const restyled = () => relayout(true);
|
|
6419
|
+
root.addEventListener("knobs-restyle", restyled);
|
|
5892
6420
|
const paneApi = (id) => {
|
|
5893
6421
|
const v = views.get(id);
|
|
5894
6422
|
if (!v)
|
|
@@ -5911,9 +6439,9 @@ function split(container, options) {
|
|
|
5911
6439
|
v.titleEl.textContent = text;
|
|
5912
6440
|
if (v.countEl && count !== undefined)
|
|
5913
6441
|
v.countEl.textContent = String(count);
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
6442
|
+
if (v.railLabel)
|
|
6443
|
+
v.railLabel.textContent = text;
|
|
6444
|
+
measureChevrons(v);
|
|
5917
6445
|
}
|
|
5918
6446
|
};
|
|
5919
6447
|
};
|
|
@@ -5948,7 +6476,7 @@ function split(container, options) {
|
|
|
5948
6476
|
unregisterHints?.();
|
|
5949
6477
|
loop.stop();
|
|
5950
6478
|
ro.disconnect();
|
|
5951
|
-
root.removeEventListener("knobs-restyle",
|
|
6479
|
+
root.removeEventListener("knobs-restyle", restyled);
|
|
5952
6480
|
host?.removeAttribute("data-nested");
|
|
5953
6481
|
root.remove();
|
|
5954
6482
|
}
|
|
@@ -6956,8 +7484,81 @@ function timeline(container, options) {
|
|
|
6956
7484
|
}
|
|
6957
7485
|
var PLAY = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M5 3.6v8.8c0 .5.5.8.9.5l6.6-4.4c.4-.3.4-.8 0-1L5.9 3.1c-.4-.3-.9 0-.9.5Z" fill="currentColor"/></svg>';
|
|
6958
7486
|
var PAUSE = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="4" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/><rect x="9.2" y="3.2" width="2.8" height="9.6" rx="1" fill="currentColor"/></svg>';
|
|
7487
|
+
// src/ui/scrollbar.ts
|
|
7488
|
+
function overlayScrollbar(scroller, content) {
|
|
7489
|
+
const doc = scroller.ownerDocument;
|
|
7490
|
+
const win = doc.defaultView;
|
|
7491
|
+
const track = doc.createElement("div");
|
|
7492
|
+
track.className = "knobs-scrollbar";
|
|
7493
|
+
track.setAttribute("aria-hidden", "true");
|
|
7494
|
+
const thumb = doc.createElement("div");
|
|
7495
|
+
thumb.className = "knobs-scrollbar-thumb";
|
|
7496
|
+
track.append(thumb);
|
|
7497
|
+
scroller.prepend(track);
|
|
7498
|
+
let size = 0;
|
|
7499
|
+
const update = () => {
|
|
7500
|
+
const view = scroller.clientHeight;
|
|
7501
|
+
const over = scroller.scrollHeight - view;
|
|
7502
|
+
const shown = over > 1 && view > 0;
|
|
7503
|
+
track.hidden = !shown;
|
|
7504
|
+
if (!shown)
|
|
7505
|
+
return;
|
|
7506
|
+
size = Math.max(20, view * view / (view + over));
|
|
7507
|
+
const y = Math.min(over, Math.max(0, scroller.scrollTop)) / over * (view - size);
|
|
7508
|
+
thumb.style.height = `${size.toFixed(1)}px`;
|
|
7509
|
+
thumb.style.transform = `translate3d(0,${y.toFixed(1)}px,0)`;
|
|
7510
|
+
};
|
|
7511
|
+
let idle = 0;
|
|
7512
|
+
const onScroll = () => {
|
|
7513
|
+
update();
|
|
7514
|
+
track.dataset.active = "";
|
|
7515
|
+
win.clearTimeout(idle);
|
|
7516
|
+
idle = win.setTimeout(() => delete track.dataset.active, 800);
|
|
7517
|
+
};
|
|
7518
|
+
scroller.addEventListener("scroll", onScroll, { passive: true });
|
|
7519
|
+
let drag;
|
|
7520
|
+
thumb.addEventListener("pointerdown", (e) => {
|
|
7521
|
+
if (e.button !== 0)
|
|
7522
|
+
return;
|
|
7523
|
+
e.preventDefault();
|
|
7524
|
+
e.stopPropagation();
|
|
7525
|
+
drag = { y: e.clientY, top: scroller.scrollTop, pointer: e.pointerId };
|
|
7526
|
+
thumb.setPointerCapture(e.pointerId);
|
|
7527
|
+
track.dataset.dragging = "";
|
|
7528
|
+
});
|
|
7529
|
+
thumb.addEventListener("pointermove", (e) => {
|
|
7530
|
+
if (!drag || e.pointerId !== drag.pointer)
|
|
7531
|
+
return;
|
|
7532
|
+
const view = scroller.clientHeight;
|
|
7533
|
+
const over = scroller.scrollHeight - view;
|
|
7534
|
+
scroller.scrollTop = drag.top + (e.clientY - drag.y) * over / Math.max(1, view - size);
|
|
7535
|
+
});
|
|
7536
|
+
const end = (e) => {
|
|
7537
|
+
if (!drag || e.pointerId !== drag.pointer)
|
|
7538
|
+
return;
|
|
7539
|
+
drag = undefined;
|
|
7540
|
+
delete track.dataset.dragging;
|
|
7541
|
+
};
|
|
7542
|
+
thumb.addEventListener("pointerup", end);
|
|
7543
|
+
thumb.addEventListener("pointercancel", end);
|
|
7544
|
+
thumb.addEventListener("lostpointercapture", end);
|
|
7545
|
+
const ro = new ResizeObserver(update);
|
|
7546
|
+
ro.observe(scroller);
|
|
7547
|
+
ro.observe(content);
|
|
7548
|
+
update();
|
|
7549
|
+
return {
|
|
7550
|
+
update,
|
|
7551
|
+
dispose() {
|
|
7552
|
+
ro.disconnect();
|
|
7553
|
+
win.clearTimeout(idle);
|
|
7554
|
+
scroller.removeEventListener("scroll", onScroll);
|
|
7555
|
+
track.remove();
|
|
7556
|
+
}
|
|
7557
|
+
};
|
|
7558
|
+
}
|
|
7559
|
+
|
|
6959
7560
|
// src/ui/tree.ts
|
|
6960
|
-
var MOVE = springMotion({ duration: 0.
|
|
7561
|
+
var MOVE = springMotion({ duration: 0.3, bounce: 0 });
|
|
6961
7562
|
var EDGE = 28;
|
|
6962
7563
|
function tree(container, options) {
|
|
6963
7564
|
const doc = container.ownerDocument;
|
|
@@ -6980,7 +7581,7 @@ function tree(container, options) {
|
|
|
6980
7581
|
let index = indexTree(items, access);
|
|
6981
7582
|
const renamed = new Map;
|
|
6982
7583
|
const root = doc.createElement("div");
|
|
6983
|
-
root.className = "knobs-tree";
|
|
7584
|
+
root.className = "knobs-tree knobs-scroll-fade";
|
|
6984
7585
|
root.tabIndex = 0;
|
|
6985
7586
|
root.setAttribute("role", "tree");
|
|
6986
7587
|
root.setAttribute("aria-multiselectable", "true");
|
|
@@ -6996,6 +7597,7 @@ function tree(container, options) {
|
|
|
6996
7597
|
empty.hidden = true;
|
|
6997
7598
|
root.append(space, line, empty);
|
|
6998
7599
|
container.append(root);
|
|
7600
|
+
const scrollbar = overlayScrollbar(root, space);
|
|
6999
7601
|
let h = 26;
|
|
7000
7602
|
let indent = 14;
|
|
7001
7603
|
let inset = 8;
|
|
@@ -7046,7 +7648,7 @@ function tree(container, options) {
|
|
|
7046
7648
|
const icon = doc.createElement("span");
|
|
7047
7649
|
icon.className = "knobs-tree-icon";
|
|
7048
7650
|
const label = doc.createElement("span");
|
|
7049
|
-
label.className = "knobs-tree-label";
|
|
7651
|
+
label.className = "knobs-tree-label knobs-scroll-fade-x";
|
|
7050
7652
|
const text = doc.createElement("span");
|
|
7051
7653
|
text.className = "knobs-tree-text";
|
|
7052
7654
|
label.append(text);
|
|
@@ -7608,6 +8210,8 @@ function tree(container, options) {
|
|
|
7608
8210
|
const rule = options.typeahead ?? true;
|
|
7609
8211
|
if (rule === false)
|
|
7610
8212
|
return false;
|
|
8213
|
+
if (!(running && typed !== "") && !/^[\p{L}\p{N}]$/u.test(key))
|
|
8214
|
+
return false;
|
|
7611
8215
|
if (!(running && typed !== "") && options.hints !== false && claimsHintKey(doc, key))
|
|
7612
8216
|
return false;
|
|
7613
8217
|
return rule === true || running && typed !== "" || rule(key);
|
|
@@ -7843,6 +8447,7 @@ function tree(container, options) {
|
|
|
7843
8447
|
loop.stop();
|
|
7844
8448
|
autoScroll.stop();
|
|
7845
8449
|
ro.disconnect();
|
|
8450
|
+
scrollbar.dispose();
|
|
7846
8451
|
dragging?.ghost.remove();
|
|
7847
8452
|
root.remove();
|
|
7848
8453
|
}
|
|
@@ -8188,11 +8793,7 @@ var SLIDE_BY = 0.12;
|
|
|
8188
8793
|
var EXIT_BLUR = 3;
|
|
8189
8794
|
var px = (x) => new Spring(x, LAYOUT.omega, LAYOUT.zeta, 0.05);
|
|
8190
8795
|
var unit = (x) => new Spring(x, ENTER.omega, ENTER.zeta, 0.0005);
|
|
8191
|
-
var drive = (s, m, target) =>
|
|
8192
|
-
s.omega = m.omega;
|
|
8193
|
-
s.zeta = m.zeta;
|
|
8194
|
-
return s.set(target);
|
|
8195
|
-
};
|
|
8796
|
+
var drive = (s, m, target) => tune(s, m).set(target);
|
|
8196
8797
|
var probed = new Map;
|
|
8197
8798
|
var smallest = (srcset) => {
|
|
8198
8799
|
let best;
|
|
@@ -8953,7 +9554,7 @@ function bento(container, options) {
|
|
|
8953
9554
|
}
|
|
8954
9555
|
zoomIn(t.id);
|
|
8955
9556
|
};
|
|
8956
|
-
const typing = (target) => target
|
|
9557
|
+
const typing = (target) => target !== root && isTypingTarget(target);
|
|
8957
9558
|
const reveal = (id) => {
|
|
8958
9559
|
const r = rectOf(id);
|
|
8959
9560
|
if (!r)
|
|
@@ -9170,9 +9771,2093 @@ function bento(container, options) {
|
|
|
9170
9771
|
}
|
|
9171
9772
|
};
|
|
9172
9773
|
}
|
|
9774
|
+
// node_modules/@kitlangton/rolling-number/dist/chunk-vm1v7ncb.js
|
|
9775
|
+
var z = new Map;
|
|
9776
|
+
var le = /[\u0590-\u08ff\u200e\u200f\u202a-\u202e\u2066-\u2069\ufb1d-\ufeff]/u;
|
|
9777
|
+
var U = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:.-/&+'";
|
|
9778
|
+
var V = new Map;
|
|
9779
|
+
function Re(e) {
|
|
9780
|
+
let t = V.get(e);
|
|
9781
|
+
if (!t) {
|
|
9782
|
+
if (t = [...new Set(ue(e))], V.size >= 16)
|
|
9783
|
+
V.delete(V.keys().next().value);
|
|
9784
|
+
V.set(e, t);
|
|
9785
|
+
}
|
|
9786
|
+
return t;
|
|
9787
|
+
}
|
|
9788
|
+
function ue(e) {
|
|
9789
|
+
if (typeof Intl.Segmenter === "function")
|
|
9790
|
+
return [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(e)].map((t) => t.segment);
|
|
9791
|
+
return [...e];
|
|
9792
|
+
}
|
|
9793
|
+
function pe(e, t = {}) {
|
|
9794
|
+
let n = t.charset ?? U, i = !le.test(e);
|
|
9795
|
+
if (!i)
|
|
9796
|
+
return { text: e, tokens: [], rollable: i, signature: "text", magnitude: "" };
|
|
9797
|
+
let r = ue(e).map((s, o) => {
|
|
9798
|
+
if (t.transition === "direct")
|
|
9799
|
+
return { key: `char:${o}`, identity: `char:${o}`, text: s, wheel: [s], index: 0 };
|
|
9800
|
+
let h = Re(typeof n === "string" ? n : n[o] ?? n.at(-1) ?? U), c = `char:${o}`, m = h.indexOf(s);
|
|
9801
|
+
return m >= 0 ? { key: c, identity: c, text: s, wheel: h, index: m } : { key: `${c}:${s}`, identity: c, text: s };
|
|
9802
|
+
});
|
|
9803
|
+
return { text: e, tokens: r, rollable: i, signature: `text:${t.transition ?? "wheel"}`, magnitude: "" };
|
|
9804
|
+
}
|
|
9805
|
+
function me(e, t, n = 0.14) {
|
|
9806
|
+
return { target: 0, duration: t, points: Array.from({ length: 49 }, (i, r) => {
|
|
9807
|
+
if (r === 48)
|
|
9808
|
+
return 0;
|
|
9809
|
+
let s = Math.max(0, Math.min(1, (r / 48 - n) / (1 - n)));
|
|
9810
|
+
return e * (1 + 10 * s) * Math.exp(-10 * s);
|
|
9811
|
+
}) };
|
|
9812
|
+
}
|
|
9813
|
+
function W(e, t) {
|
|
9814
|
+
if (t <= 0 || e.duration <= 0)
|
|
9815
|
+
return e;
|
|
9816
|
+
let n = e.duration + t, i = Math.round((e.points.length - 1) * n / e.duration) + 1, r = e.points[0] ?? e.target;
|
|
9817
|
+
return { target: e.target, duration: n, points: Array.from({ length: i }, (s, o) => {
|
|
9818
|
+
if (o === i - 1)
|
|
9819
|
+
return e.target;
|
|
9820
|
+
let h = o / (i - 1) * n - t;
|
|
9821
|
+
return h <= 0 ? r : J(e, h).position;
|
|
9822
|
+
}) };
|
|
9823
|
+
}
|
|
9824
|
+
function L(e, t, n, i) {
|
|
9825
|
+
if (i <= 0)
|
|
9826
|
+
return { points: [t, t], duration: 0, target: t };
|
|
9827
|
+
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;
|
|
9828
|
+
return { points: Array.from({ length: 49 }, (m, f) => {
|
|
9829
|
+
if (f === 48)
|
|
9830
|
+
return t;
|
|
9831
|
+
let y = f / 48;
|
|
9832
|
+
return t + (s + (h + 10 * s) * y) * Math.exp(-10 * y);
|
|
9833
|
+
}), duration: i, target: t };
|
|
9834
|
+
}
|
|
9835
|
+
function fe(e, t = 0, n = 24) {
|
|
9836
|
+
if (e.duration <= 0)
|
|
9837
|
+
return { points: [0, 0], duration: 0, target: 0 };
|
|
9838
|
+
let i = e.duration / (e.points.length - 1) / 1000;
|
|
9839
|
+
return { duration: e.duration, target: 0, points: e.points.map((r, s, o) => {
|
|
9840
|
+
if (s === 0)
|
|
9841
|
+
return Math.max(0, Math.min(1, t));
|
|
9842
|
+
if (s === o.length - 1)
|
|
9843
|
+
return 0;
|
|
9844
|
+
let h = Math.abs((o[s + 1] - o[s - 1]) / (2 * i)), c = n / 6;
|
|
9845
|
+
return Math.max(0, Math.min(1, (h - c) / (n - c)));
|
|
9846
|
+
}) };
|
|
9847
|
+
}
|
|
9848
|
+
function J(e, t) {
|
|
9849
|
+
if (t >= e.duration || e.duration === 0)
|
|
9850
|
+
return { position: e.target, velocity: 0 };
|
|
9851
|
+
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;
|
|
9852
|
+
return { position: r + (s - r) * (n - i), velocity: (s - r) * (e.points.length - 1) * 1000 / e.duration };
|
|
9853
|
+
}
|
|
9854
|
+
function Q(e, t, n, i = 10) {
|
|
9855
|
+
let r = Math.floor(e / i) * i + t;
|
|
9856
|
+
if (n > 0 && r < e - 0.001)
|
|
9857
|
+
r += i;
|
|
9858
|
+
else if (n < 0 && r > e + 0.001)
|
|
9859
|
+
r -= i;
|
|
9860
|
+
else if (n === 0)
|
|
9861
|
+
r += Math.round((e - r) / i) * i;
|
|
9862
|
+
return r;
|
|
9863
|
+
}
|
|
9864
|
+
var P = (e, t) => e[(t % e.length + e.length) % e.length];
|
|
9865
|
+
function ge(e, t, n) {
|
|
9866
|
+
let i = Math.floor(t), r = t - i, s = [P(e, i)];
|
|
9867
|
+
if (r > 0.00001)
|
|
9868
|
+
s.push(P(e, i + 1));
|
|
9869
|
+
if (s.at(-1) !== n)
|
|
9870
|
+
s.push(n);
|
|
9871
|
+
return { wheel: s, from: r, target: s.length - 1 };
|
|
9872
|
+
}
|
|
9873
|
+
function ye(e, t = "outward") {
|
|
9874
|
+
if (t !== "outward") {
|
|
9875
|
+
let r = e.map((o, h) => o ? -1 : h).filter((o) => o >= 0);
|
|
9876
|
+
if (t === "end")
|
|
9877
|
+
r.reverse();
|
|
9878
|
+
let s = e.map((o) => o ? 0 : 1);
|
|
9879
|
+
if (t !== "none")
|
|
9880
|
+
r.forEach((o, h) => {
|
|
9881
|
+
s[o] = h + 1;
|
|
9882
|
+
});
|
|
9883
|
+
return s;
|
|
9884
|
+
}
|
|
9885
|
+
let n = e.map((r, s) => r ? 0 : s + 1);
|
|
9886
|
+
if (!e.includes(true))
|
|
9887
|
+
return n;
|
|
9888
|
+
let i = -1 / 0;
|
|
9889
|
+
for (let r = 0;r < e.length; r++)
|
|
9890
|
+
if (e[r])
|
|
9891
|
+
i = r;
|
|
9892
|
+
else
|
|
9893
|
+
n[r] = r - i;
|
|
9894
|
+
i = 1 / 0;
|
|
9895
|
+
for (let r = e.length - 1;r >= 0; r--)
|
|
9896
|
+
if (e[r])
|
|
9897
|
+
i = r;
|
|
9898
|
+
else
|
|
9899
|
+
n[r] = Math.min(n[r], i - r);
|
|
9900
|
+
return n;
|
|
9901
|
+
}
|
|
9902
|
+
function Z(e, t) {
|
|
9903
|
+
let n = new Map, i = [], r = 0;
|
|
9904
|
+
for (let s of e) {
|
|
9905
|
+
let o = t.get(s);
|
|
9906
|
+
if (!o) {
|
|
9907
|
+
i.push(s);
|
|
9908
|
+
continue;
|
|
9909
|
+
}
|
|
9910
|
+
for (let h of i)
|
|
9911
|
+
n.set(h, o.x);
|
|
9912
|
+
i.length = 0, r = o.x + o.width;
|
|
9913
|
+
}
|
|
9914
|
+
for (let s of i)
|
|
9915
|
+
n.set(s, r);
|
|
9916
|
+
return n;
|
|
9917
|
+
}
|
|
9918
|
+
var ee = new WeakMap;
|
|
9919
|
+
|
|
9920
|
+
class Y {
|
|
9921
|
+
view;
|
|
9922
|
+
media;
|
|
9923
|
+
members = new Set;
|
|
9924
|
+
pending = new Set;
|
|
9925
|
+
sizes = new WeakMap;
|
|
9926
|
+
intersections = new WeakMap;
|
|
9927
|
+
resize;
|
|
9928
|
+
intersection;
|
|
9929
|
+
frame = 0;
|
|
9930
|
+
static for(e) {
|
|
9931
|
+
let t = ee.get(e);
|
|
9932
|
+
if (!t)
|
|
9933
|
+
t = new Y(e), ee.set(e, t);
|
|
9934
|
+
return t;
|
|
9935
|
+
}
|
|
9936
|
+
constructor(e) {
|
|
9937
|
+
this.view = e;
|
|
9938
|
+
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)
|
|
9939
|
+
this.resize = new e.ResizeObserver((t) => {
|
|
9940
|
+
for (let n of t) {
|
|
9941
|
+
let i = this.sizes.get(n.target);
|
|
9942
|
+
if (i?.sizeChanged(n.target, n.contentRect.width, n.contentRect.height))
|
|
9943
|
+
i.refresh();
|
|
9944
|
+
}
|
|
9945
|
+
});
|
|
9946
|
+
if (e.IntersectionObserver)
|
|
9947
|
+
this.intersection = new e.IntersectionObserver((t) => {
|
|
9948
|
+
for (let n of t)
|
|
9949
|
+
this.intersections.get(n.target)?.visibility(n.isIntersecting);
|
|
9950
|
+
}, { rootMargin: "64px" });
|
|
9951
|
+
}
|
|
9952
|
+
refresh = () => {
|
|
9953
|
+
for (let e of this.members)
|
|
9954
|
+
e.refresh();
|
|
9955
|
+
};
|
|
9956
|
+
add(e, t) {
|
|
9957
|
+
this.members.add(e), this.intersections.set(t, e), this.intersection?.observe(t);
|
|
9958
|
+
}
|
|
9959
|
+
watch(e, t) {
|
|
9960
|
+
this.sizes.set(e, t), this.resize?.observe(e);
|
|
9961
|
+
}
|
|
9962
|
+
unwatch(e) {
|
|
9963
|
+
this.resize?.unobserve(e), this.sizes.delete(e);
|
|
9964
|
+
}
|
|
9965
|
+
enqueue(e) {
|
|
9966
|
+
if (this.pending.add(e), !this.frame)
|
|
9967
|
+
this.frame = this.view.requestAnimationFrame(() => {
|
|
9968
|
+
this.frame = 0;
|
|
9969
|
+
let t = [...this.pending];
|
|
9970
|
+
this.pending.clear();
|
|
9971
|
+
let n = t.map((r) => r.stage());
|
|
9972
|
+
for (let r of n)
|
|
9973
|
+
r?.();
|
|
9974
|
+
let i = t.map((r) => r.measure());
|
|
9975
|
+
for (let r of i)
|
|
9976
|
+
r?.();
|
|
9977
|
+
});
|
|
9978
|
+
}
|
|
9979
|
+
remove(e, t) {
|
|
9980
|
+
if (this.pending.delete(e), this.members.delete(e), this.intersection?.unobserve(t), this.intersections.delete(t), this.members.size)
|
|
9981
|
+
return;
|
|
9982
|
+
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);
|
|
9983
|
+
}
|
|
9984
|
+
}
|
|
9985
|
+
var be = new WeakMap;
|
|
9986
|
+
function F(e, t, n) {
|
|
9987
|
+
let i = e.animate(t, n), r = e.ownerDocument.timeline?.currentTime;
|
|
9988
|
+
if (typeof r === "number" && i.playState === "running")
|
|
9989
|
+
i.startTime = r;
|
|
9990
|
+
return i;
|
|
9991
|
+
}
|
|
9992
|
+
function ve(e) {
|
|
9993
|
+
let t = e.ownerDocument.defaultView;
|
|
9994
|
+
if (!t)
|
|
9995
|
+
return false;
|
|
9996
|
+
let n = be.get(t);
|
|
9997
|
+
if (n === undefined)
|
|
9998
|
+
n = t.CSS?.supports("animation-timing-function", "linear(0, 1)") ?? false, be.set(t, n);
|
|
9999
|
+
return n;
|
|
10000
|
+
}
|
|
10001
|
+
|
|
10002
|
+
class N {
|
|
10003
|
+
element;
|
|
10004
|
+
property;
|
|
10005
|
+
animation;
|
|
10006
|
+
motion;
|
|
10007
|
+
value = 0;
|
|
10008
|
+
constructor(e, t) {
|
|
10009
|
+
this.element = e;
|
|
10010
|
+
this.property = t;
|
|
10011
|
+
}
|
|
10012
|
+
read() {
|
|
10013
|
+
let e = this.animation?.currentTime;
|
|
10014
|
+
return this.animation && this.motion ? J(this.motion, typeof e === "number" ? e : 0) : { position: this.value, velocity: 0 };
|
|
10015
|
+
}
|
|
10016
|
+
set(e, t) {
|
|
10017
|
+
this.cancel(), this.value = e, this.element.style.setProperty(this.property, t(e));
|
|
10018
|
+
}
|
|
10019
|
+
play(e, t, n) {
|
|
10020
|
+
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)) {
|
|
10021
|
+
n?.();
|
|
10022
|
+
return;
|
|
10023
|
+
}
|
|
10024
|
+
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 });
|
|
10025
|
+
this.animation = m, this.motion = e, m.onfinish = () => {
|
|
10026
|
+
if (this.animation !== m)
|
|
10027
|
+
return;
|
|
10028
|
+
this.animation = undefined, this.motion = undefined, m.onfinish = null, m.cancel(), n?.();
|
|
10029
|
+
};
|
|
10030
|
+
}
|
|
10031
|
+
cancel() {
|
|
10032
|
+
if (this.animation)
|
|
10033
|
+
this.animation.onfinish = null, this.animation.cancel(), this.animation = undefined;
|
|
10034
|
+
this.motion = undefined;
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
var te = "http://www.w3.org/2000/svg";
|
|
10038
|
+
var $e = 0;
|
|
10039
|
+
|
|
10040
|
+
class G {
|
|
10041
|
+
host;
|
|
10042
|
+
layers = new Map;
|
|
10043
|
+
filter;
|
|
10044
|
+
intensity = 1;
|
|
10045
|
+
constructor(e) {
|
|
10046
|
+
this.host = e;
|
|
10047
|
+
}
|
|
10048
|
+
filterUrl(e) {
|
|
10049
|
+
if (!this.filter) {
|
|
10050
|
+
let n = this.host.ownerDocument, i = n.createElementNS(te, "svg");
|
|
10051
|
+
i.classList.add("rn-blur-defs"), i.setAttribute("aria-hidden", "true"), i.setAttribute("focusable", "false");
|
|
10052
|
+
let r = n.createElementNS(te, "filter"), s;
|
|
10053
|
+
do
|
|
10054
|
+
s = `rn-vertical-blur-${++$e}`;
|
|
10055
|
+
while (n.getElementById(s));
|
|
10056
|
+
r.id = s, r.setAttribute("x", "-15%"), r.setAttribute("width", "130%"), r.setAttribute("color-interpolation-filters", "sRGB");
|
|
10057
|
+
let o = n.createElementNS(te, "feGaussianBlur");
|
|
10058
|
+
r.append(o), i.append(r), this.host.append(i), this.filter = { svg: i, blur: o, id: s, height: 0 };
|
|
10059
|
+
}
|
|
10060
|
+
let t = e * 0.035 * this.intensity;
|
|
10061
|
+
if (this.filter.height !== t)
|
|
10062
|
+
this.filter.blur.setAttribute("stdDeviation", `0 ${t}`), this.filter.height = t;
|
|
10063
|
+
return `url("#${this.filter.id}")`;
|
|
10064
|
+
}
|
|
10065
|
+
apply(e, t, n, i, r = "roll") {
|
|
10066
|
+
let s = fe(t, i, r === "entry" ? 6 : 24);
|
|
10067
|
+
if (s.points.every((f) => f === 0))
|
|
10068
|
+
return false;
|
|
10069
|
+
let o = this.host.ownerDocument.createElement("span");
|
|
10070
|
+
o.className = "rn-sharp", o.append(...e.childNodes);
|
|
10071
|
+
let h = o.cloneNode(true);
|
|
10072
|
+
h.className = "rn-smear", h.style.filter = this.filterUrl(n), e.append(o, h);
|
|
10073
|
+
let c = new N(o, "opacity"), m = new N(h, "opacity");
|
|
10074
|
+
return this.layers.set(e, { sharp: o, sharpOpacity: c, smearOpacity: m }), c.play(s, (f) => String(1 - f)), m.play(s, String), true;
|
|
10075
|
+
}
|
|
10076
|
+
remove(e) {
|
|
10077
|
+
let t = this.layers.get(e);
|
|
10078
|
+
if (!t)
|
|
10079
|
+
return 0;
|
|
10080
|
+
let n = t.smearOpacity.read().position;
|
|
10081
|
+
return t.sharpOpacity.cancel(), t.smearOpacity.cancel(), e.replaceChildren(...t.sharp.childNodes), this.layers.delete(e), n;
|
|
10082
|
+
}
|
|
10083
|
+
destroy() {
|
|
10084
|
+
for (let e of this.layers.keys())
|
|
10085
|
+
this.remove(e);
|
|
10086
|
+
this.filter?.svg.remove(), this.filter = undefined;
|
|
10087
|
+
}
|
|
10088
|
+
}
|
|
10089
|
+
function xe(e) {
|
|
10090
|
+
return Math.max(45, Math.min(110, e / 7));
|
|
10091
|
+
}
|
|
10092
|
+
function we(e, t, n) {
|
|
10093
|
+
let i = Math.abs(t - e);
|
|
10094
|
+
return { points: [e, t], target: t, duration: i * n };
|
|
10095
|
+
}
|
|
10096
|
+
function Ae(e) {
|
|
10097
|
+
let i = Array.from({ length: e + 1 }, (o, h) => ({ "--rn-flap-step": String(h), offset: h / e, easing: "steps(1, end)" })), r = [], s = [];
|
|
10098
|
+
for (let o = 0;o < e; o++) {
|
|
10099
|
+
let h = o / e, c = (o + 0.5) / e, m = (o + 1) / e;
|
|
10100
|
+
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 });
|
|
10101
|
+
}
|
|
10102
|
+
return { index: i, falls: r, lands: s };
|
|
10103
|
+
}
|
|
10104
|
+
function Me(e) {
|
|
10105
|
+
for (let t of e.querySelectorAll(".rn-flap-smear")) {
|
|
10106
|
+
for (let n of t.getAnimations())
|
|
10107
|
+
n.cancel();
|
|
10108
|
+
t.remove();
|
|
10109
|
+
}
|
|
10110
|
+
for (let t of e.querySelectorAll(".rn-flap-sharp")) {
|
|
10111
|
+
for (let n of t.getAnimations())
|
|
10112
|
+
n.cancel();
|
|
10113
|
+
t.classList.remove("rn-flap-sharp");
|
|
10114
|
+
}
|
|
10115
|
+
}
|
|
10116
|
+
function ke(e, t, n, i, r, s, o, h) {
|
|
10117
|
+
let c = e.ownerDocument, m = Math.abs(i - n), f = i >= n ? 1 : -1;
|
|
10118
|
+
if (!m) {
|
|
10119
|
+
e.replaceChildren();
|
|
10120
|
+
return;
|
|
10121
|
+
}
|
|
10122
|
+
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");
|
|
10123
|
+
g.style.cssText = `display:block;position:relative;height:${r}px`, F(g, y.index, { delay: o, duration: m * s, fill: "both" });
|
|
10124
|
+
let T = (p, w) => {
|
|
10125
|
+
let k = c.createElement("span");
|
|
10126
|
+
k.className = `rn-face rn-flap rn-flap-${p}`, k.style.height = `${r}px`, k.style.overflow = "hidden";
|
|
10127
|
+
let v = c.createElement("span");
|
|
10128
|
+
v.style.cssText = `display:block;white-space:pre;line-height:${r}px`;
|
|
10129
|
+
let l = w ? S : M;
|
|
10130
|
+
if (u)
|
|
10131
|
+
for (let b of l) {
|
|
10132
|
+
let O = c.createElement("span");
|
|
10133
|
+
O.style.cssText = `display:block;height:${r}px`, O.textContent = b, v.append(O);
|
|
10134
|
+
}
|
|
10135
|
+
else
|
|
10136
|
+
v.textContent = l.join(`
|
|
10137
|
+
`);
|
|
10138
|
+
return k.append(v), v.style.transform = `translateY(calc(var(--rn-flap-step) * ${-r}px))`, k;
|
|
10139
|
+
}, H = T("bottom", false), j = T("top", true), d = T("top", false), a = T("bottom", true);
|
|
10140
|
+
if (h) {
|
|
10141
|
+
let p = (w, k) => {
|
|
10142
|
+
let v = w.firstElementChild, l = v.cloneNode(true);
|
|
10143
|
+
v.classList.add("rn-flap-sharp");
|
|
10144
|
+
let b = c.createElement("span");
|
|
10145
|
+
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);
|
|
10146
|
+
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" };
|
|
10147
|
+
F(b, O, A), F(v, O.map((C) => ({ ...C, opacity: 1 - C.opacity })), A);
|
|
10148
|
+
};
|
|
10149
|
+
p(d, y.falls), p(a, y.lands);
|
|
10150
|
+
}
|
|
10151
|
+
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);
|
|
10152
|
+
}
|
|
10153
|
+
var Ee = new WeakMap;
|
|
10154
|
+
var _ = new WeakSet;
|
|
10155
|
+
var ne = (e) => `translateX(${e}px)`;
|
|
10156
|
+
var ie = (e) => `scale(${e})`;
|
|
10157
|
+
var re = (e) => String(Math.max(0, Math.min(1, e)));
|
|
10158
|
+
var se = (e) => ("transition" in e) && e.transition === "direct";
|
|
10159
|
+
function Te(e) {
|
|
10160
|
+
if (e.duration !== undefined && (!Number.isFinite(e.duration) || e.duration < 0 || e.duration > 1e4))
|
|
10161
|
+
throw RangeError("duration must be between 0 and 10000 milliseconds");
|
|
10162
|
+
if (e.flipDuration !== undefined && (!Number.isFinite(e.flipDuration) || e.flipDuration < 1 || e.flipDuration > 1e4))
|
|
10163
|
+
throw RangeError("flipDuration must be between 1 and 10000 milliseconds");
|
|
10164
|
+
}
|
|
10165
|
+
var Fe = { validate(e) {
|
|
10166
|
+
if (typeof e.text !== "string")
|
|
10167
|
+
throw TypeError("text must be a string");
|
|
10168
|
+
if (e.transition !== undefined && e.transition !== "direct" && e.transition !== "wheel")
|
|
10169
|
+
throw RangeError("transition must be direct or wheel");
|
|
10170
|
+
if (e.transition === "direct" && e.mode === "flap")
|
|
10171
|
+
throw RangeError("Direct text transitions require roll mode");
|
|
10172
|
+
Te(e);
|
|
10173
|
+
}, model: (e) => pe(e.text, e), direction: () => 1 };
|
|
10174
|
+
|
|
10175
|
+
class oe {
|
|
10176
|
+
host;
|
|
10177
|
+
source;
|
|
10178
|
+
options;
|
|
10179
|
+
target;
|
|
10180
|
+
displayed;
|
|
10181
|
+
semantic;
|
|
10182
|
+
measurement;
|
|
10183
|
+
visual;
|
|
10184
|
+
measures = new Map;
|
|
10185
|
+
columns = new Map;
|
|
10186
|
+
sizes = new Map;
|
|
10187
|
+
scheduler;
|
|
10188
|
+
enhanced = false;
|
|
10189
|
+
destroyed = false;
|
|
10190
|
+
visible = true;
|
|
10191
|
+
reset = true;
|
|
10192
|
+
measurementPending = false;
|
|
10193
|
+
hadClass;
|
|
10194
|
+
previousLeft;
|
|
10195
|
+
blur;
|
|
10196
|
+
blurIntensity = 1;
|
|
10197
|
+
constructor(e, t, n) {
|
|
10198
|
+
this.host = e;
|
|
10199
|
+
this.source = n;
|
|
10200
|
+
n.validate(t), this.options = { ...t }, this.target = this.displayed = n.model(t);
|
|
10201
|
+
let i = e.ownerDocument, r = (o) => {
|
|
10202
|
+
let h = i.createElement("span");
|
|
10203
|
+
return h.className = o, h;
|
|
10204
|
+
};
|
|
10205
|
+
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);
|
|
10206
|
+
let s = i.defaultView;
|
|
10207
|
+
if (s && typeof s.matchMedia === "function" && typeof s.requestAnimationFrame === "function" && typeof e.animate === "function")
|
|
10208
|
+
this.scheduler = Y.for(s), this.scheduler.add(this, e), this.scheduler.watch(this.measurement, this);
|
|
10209
|
+
this.prepare();
|
|
10210
|
+
}
|
|
10211
|
+
canAnimate() {
|
|
10212
|
+
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;
|
|
10213
|
+
}
|
|
10214
|
+
update(e) {
|
|
10215
|
+
if (this.destroyed)
|
|
10216
|
+
return;
|
|
10217
|
+
let t = { ...this.options, ...e };
|
|
10218
|
+
this.source.validate(t);
|
|
10219
|
+
let n = this.source.model(t), i = n.text === this.target.text && n.signature === this.target.signature;
|
|
10220
|
+
if (this.options.motionBlur && !t.motionBlur)
|
|
10221
|
+
this.blur?.destroy(), this.blur = undefined, Me(this.visual);
|
|
10222
|
+
if (se(this.options) !== se(t))
|
|
10223
|
+
this.reset = true;
|
|
10224
|
+
if (this.options = t, this.target = n, !this.canAnimate()) {
|
|
10225
|
+
this.finish();
|
|
10226
|
+
return;
|
|
10227
|
+
}
|
|
10228
|
+
if (i && this.enhanced && !this.reset)
|
|
10229
|
+
return;
|
|
10230
|
+
this.semantic.textContent = n.text, this.prepare();
|
|
10231
|
+
}
|
|
10232
|
+
prepare() {
|
|
10233
|
+
if (!this.canAnimate()) {
|
|
10234
|
+
this.finish();
|
|
10235
|
+
return;
|
|
10236
|
+
}
|
|
10237
|
+
this.measurementPending = true, this.scheduler?.enqueue(this);
|
|
10238
|
+
}
|
|
10239
|
+
stage() {
|
|
10240
|
+
if (this.destroyed)
|
|
10241
|
+
return;
|
|
10242
|
+
if (!this.canAnimate())
|
|
10243
|
+
return () => this.finish();
|
|
10244
|
+
return this.previousLeft = this.enhanced && !this.reset ? this.measurement.getBoundingClientRect().left : undefined, () => this.stageMeasurement();
|
|
10245
|
+
}
|
|
10246
|
+
stageMeasurement() {
|
|
10247
|
+
let e = new Set(this.target.tokens.map((n) => n.key));
|
|
10248
|
+
for (let [n, i] of this.measures) {
|
|
10249
|
+
if (e.has(n))
|
|
10250
|
+
continue;
|
|
10251
|
+
this.scheduler?.unwatch(i), this.sizes.delete(i), i.remove(), this.measures.delete(n);
|
|
10252
|
+
}
|
|
10253
|
+
let t = null;
|
|
10254
|
+
for (let n of this.target.tokens) {
|
|
10255
|
+
let i = this.measures.get(n.key);
|
|
10256
|
+
if (!i)
|
|
10257
|
+
i = this.host.ownerDocument.createElement("span"), i.className = "rn-token", this.measures.set(n.key, i), this.scheduler?.watch(i, this);
|
|
10258
|
+
if (i.textContent !== n.text)
|
|
10259
|
+
i.textContent = n.text;
|
|
10260
|
+
let r = t ? t.nextSibling : this.measurement.firstChild;
|
|
10261
|
+
if (i !== r)
|
|
10262
|
+
this.measurement.insertBefore(i, r);
|
|
10263
|
+
t = i;
|
|
10264
|
+
}
|
|
10265
|
+
this.host.dataset.rnMeasuring = "";
|
|
10266
|
+
}
|
|
10267
|
+
measure() {
|
|
10268
|
+
if (this.destroyed)
|
|
10269
|
+
return;
|
|
10270
|
+
if (!this.canAnimate())
|
|
10271
|
+
return () => this.finish();
|
|
10272
|
+
let e = this.measurement.getBoundingClientRect(), t = this.host.ownerDocument.defaultView;
|
|
10273
|
+
if (!t)
|
|
10274
|
+
return () => this.finish();
|
|
10275
|
+
let n = t.getComputedStyle(this.measurement);
|
|
10276
|
+
if (n.direction === "rtl")
|
|
10277
|
+
return () => this.finish();
|
|
10278
|
+
let i = parseFloat(n.width), r = parseFloat(n.height);
|
|
10279
|
+
if (!i || !r || !e.width || !e.height)
|
|
10280
|
+
return () => this.finish();
|
|
10281
|
+
let s = e.width / i, o = e.height / r, h = parseFloat(n.getPropertyValue("--rn-blur"));
|
|
10282
|
+
this.blurIntensity = Number.isFinite(h) ? Math.max(0, h) : 1, this.sizes.set(this.measurement, { width: i, height: r });
|
|
10283
|
+
let c = new Map;
|
|
10284
|
+
for (let [f, y] of this.measures) {
|
|
10285
|
+
let M = y.getBoundingClientRect(), S = { width: M.width / s, height: M.height / o };
|
|
10286
|
+
this.sizes.set(y, S), c.set(f, { ...S, x: (M.left - e.left) / s, y: (M.top - e.top) / o });
|
|
10287
|
+
}
|
|
10288
|
+
let m = this.previousLeft === undefined ? 0 : (this.previousLeft - e.left) / s;
|
|
10289
|
+
return () => this.commit(c, m);
|
|
10290
|
+
}
|
|
10291
|
+
makeColumn(e) {
|
|
10292
|
+
let t = this.host.ownerDocument.createElement("span");
|
|
10293
|
+
if (t.className = "rn-slot", t.dataset.rnKey = e.key, e.index !== undefined)
|
|
10294
|
+
t.dataset.rnWheel = "";
|
|
10295
|
+
if (this.options.mode === "flap")
|
|
10296
|
+
t.dataset.rnFlap = "";
|
|
10297
|
+
let n = this.host.ownerDocument.createElement("span");
|
|
10298
|
+
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 };
|
|
10299
|
+
}
|
|
10300
|
+
face(e, t) {
|
|
10301
|
+
let n = this.host.ownerDocument.createElement("span");
|
|
10302
|
+
n.className = "rn-face", n.textContent = t, n.style.height = `${e.height}px`;
|
|
10303
|
+
let i = e.reel.children.length;
|
|
10304
|
+
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);
|
|
10305
|
+
}
|
|
10306
|
+
rest(e) {
|
|
10307
|
+
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)
|
|
10308
|
+
e.roll.set(1, ie);
|
|
10309
|
+
else
|
|
10310
|
+
e.roll.set(e.token.index, () => "translateY(0px)");
|
|
10311
|
+
}
|
|
10312
|
+
wrapInk(e) {
|
|
10313
|
+
if (this.options.mode === "flap")
|
|
10314
|
+
return;
|
|
10315
|
+
let t = this.host.ownerDocument.createElement("span");
|
|
10316
|
+
t.className = "rn-ink", t.append(...e.reel.childNodes), e.reel.append(t);
|
|
10317
|
+
}
|
|
10318
|
+
finishEntry(e) {
|
|
10319
|
+
if (!e.entry)
|
|
10320
|
+
return;
|
|
10321
|
+
if (e.entry.blurred)
|
|
10322
|
+
this.blur?.remove(e.reel);
|
|
10323
|
+
e.entry.track.cancel(), e.entry.element.replaceWith(e.reel), e.entry = undefined;
|
|
10324
|
+
}
|
|
10325
|
+
enter(e, t, n, i) {
|
|
10326
|
+
let r = this.host.ownerDocument.createElement("span");
|
|
10327
|
+
r.className = "rn-enter", e.reel.replaceWith(r), r.append(e.reel);
|
|
10328
|
+
let s = new N(r, "transform");
|
|
10329
|
+
e.entry = { element: r, track: s, blurred: false };
|
|
10330
|
+
let o = W(me(e.height * (i?.entryDistance ?? 1), i?.entryDuration ?? t, i?.entryHold), n);
|
|
10331
|
+
if (this.options.motionBlur && e.token.text.trim()) {
|
|
10332
|
+
this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity;
|
|
10333
|
+
let h = { ...o, points: o.points.map((c) => c / e.height) };
|
|
10334
|
+
e.entry.blurred = this.blur.apply(e.reel, h, e.height, 0, "entry");
|
|
10335
|
+
}
|
|
10336
|
+
s.play(o, (h) => `translateY(${h}px)`, () => this.finishEntry(e));
|
|
10337
|
+
}
|
|
10338
|
+
commit(e, t) {
|
|
10339
|
+
if (this.destroyed)
|
|
10340
|
+
return;
|
|
10341
|
+
this.measurementPending = false;
|
|
10342
|
+
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);
|
|
10343
|
+
if (this.target.text !== this.displayed.text)
|
|
10344
|
+
this.host.dataset.rnTrend = h > 0 ? "up" : h < 0 ? "down" : "none";
|
|
10345
|
+
let c = new Map([...this.columns].map(([d, a]) => {
|
|
10346
|
+
let p = a.x.read();
|
|
10347
|
+
return [d, { ...p, x: p.position, width: a.width }];
|
|
10348
|
+
})), 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) => {
|
|
10349
|
+
let a = this.columns.get(d.key);
|
|
10350
|
+
return !a || a.exiting || u && d.index !== undefined && a.token.text !== d.text;
|
|
10351
|
+
}), 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));
|
|
10352
|
+
for (let [d, a] of this.target.tokens.entries()) {
|
|
10353
|
+
let p = e.get(a.key);
|
|
10354
|
+
if (!p)
|
|
10355
|
+
continue;
|
|
10356
|
+
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;
|
|
10357
|
+
if (!l) {
|
|
10358
|
+
l = this.makeColumn(a), this.columns.set(a.key, l);
|
|
10359
|
+
let x = (v?.x ?? m.get(a.key) ?? p.x) + t;
|
|
10360
|
+
l.x.set(n ? x + (p.x - x) * (v ? 0 : r?.entryOrigin ?? 0) : p.x, ne), l.opacity.set(n ? 0 : 1, re);
|
|
10361
|
+
}
|
|
10362
|
+
let O = l.token.text !== a.text, A = Math.abs(l.height - p.height) > 0.1, C = l.exiting;
|
|
10363
|
+
l.exiting = false, l.element.style.width = `${p.width}px`, l.element.style.height = `${p.height}px`, l.element.style.top = `${p.y}px`;
|
|
10364
|
+
let q = c.get(a.key);
|
|
10365
|
+
if (l.x.play(L(q ? q.position + t : l.x.read().position, p.x, q?.velocity ?? 0, s), ne), b || C || !n) {
|
|
10366
|
+
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;
|
|
10367
|
+
l.opacity.play(b ? W(E, w + R) : E, re);
|
|
10368
|
+
}
|
|
10369
|
+
if (l.height = p.height, l.width = p.width, !n || A)
|
|
10370
|
+
this.finishEntry(l);
|
|
10371
|
+
if (b && o && a.wheel && i)
|
|
10372
|
+
l.roll.set(Math.max(0, a.wheel.indexOf(" ")), () => "translateY(0px)");
|
|
10373
|
+
if (o && !A && (O || b) && a.index !== undefined && a.wheel && i && l.roll.read().position !== a.index) {
|
|
10374
|
+
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);
|
|
10375
|
+
this.blur?.remove(l.reel);
|
|
10376
|
+
let I;
|
|
10377
|
+
if (this.options.motionBlur && this.blurIntensity > 0)
|
|
10378
|
+
this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity, I = this.blur.filterUrl(p.height);
|
|
10379
|
+
ke(l.reel, a.wheel, E, R, p.height, D, w, I), l.token = a;
|
|
10380
|
+
let X = l;
|
|
10381
|
+
l.roll.play(W(we(E, R, D), w), () => "translateY(0px)", () => this.rest(X));
|
|
10382
|
+
} else if (!b && !A && O && a.index !== undefined && a.wheel && l.token.index !== undefined && i) {
|
|
10383
|
+
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));
|
|
10384
|
+
if (l.entry)
|
|
10385
|
+
l.entry.blurred = false;
|
|
10386
|
+
let Se = this.blur?.remove(l.reel) ?? 0;
|
|
10387
|
+
l.reel.replaceChildren();
|
|
10388
|
+
for (let B = ae;B <= Oe; B++)
|
|
10389
|
+
this.face(l, P(I, B));
|
|
10390
|
+
if (this.wrapInk(l), this.options.motionBlur)
|
|
10391
|
+
this.blur ??= new G(this.host), this.blur.intensity = this.blurIntensity, this.blur.apply(l.reel, K, p.height, Se);
|
|
10392
|
+
l.token = E ? { ...a, wheel: I, index: D } : a;
|
|
10393
|
+
let Ce = l;
|
|
10394
|
+
l.roll.play(K, (B) => `translateY(${(ae - B) * p.height}px)`, () => this.rest(Ce));
|
|
10395
|
+
} else if (b || A || O || !n)
|
|
10396
|
+
l.token = a, this.rest(l);
|
|
10397
|
+
if (b && i && a.index !== undefined && !o)
|
|
10398
|
+
this.enter(l, i, w, r);
|
|
10399
|
+
if (v && i && (b || C)) {
|
|
10400
|
+
let x = l.roll.read(), E = l;
|
|
10401
|
+
l.roll.play(L(b ? 0.96 : x.position, 1, x.velocity, Math.min(i, 180)), ie, () => this.rest(E));
|
|
10402
|
+
}
|
|
10403
|
+
}
|
|
10404
|
+
for (let [d, a] of this.columns) {
|
|
10405
|
+
if (e.has(d))
|
|
10406
|
+
continue;
|
|
10407
|
+
let p = c.get(d), w = S.get(a.token.identity), k = w ? e.get(w) : undefined;
|
|
10408
|
+
if (a.x.play(L(p.position + t, k?.x ?? y.get(d) ?? p.position, p.velocity, s), ne), a.exiting)
|
|
10409
|
+
continue;
|
|
10410
|
+
if (a.exiting = true, k && i) {
|
|
10411
|
+
let l = a.roll.read();
|
|
10412
|
+
a.roll.play(L(l.position, 1.04, l.velocity, Math.min(i, 180)), ie);
|
|
10413
|
+
}
|
|
10414
|
+
let v = a.opacity.read();
|
|
10415
|
+
a.opacity.play(L(v.position, 0, v.velocity, a.token.index === undefined ? Math.min(i, 180) : i * 0.65), re, () => {
|
|
10416
|
+
if (!a.exiting)
|
|
10417
|
+
return;
|
|
10418
|
+
this.removeColumn(a), this.columns.delete(d);
|
|
10419
|
+
});
|
|
10420
|
+
}
|
|
10421
|
+
this.enhanced = true, this.reset = false, this.displayed = this.target, this.host.dataset.rnReady = "";
|
|
10422
|
+
}
|
|
10423
|
+
removeColumn(e) {
|
|
10424
|
+
this.blur?.remove(e.reel), this.finishEntry(e), e.x.cancel(), e.roll.cancel(), e.opacity.cancel(), e.element.remove();
|
|
10425
|
+
}
|
|
10426
|
+
refresh() {
|
|
10427
|
+
if (this.destroyed)
|
|
10428
|
+
return;
|
|
10429
|
+
this.reset = true, this.prepare();
|
|
10430
|
+
}
|
|
10431
|
+
sizeChanged(e, t, n) {
|
|
10432
|
+
if (this.measurementPending || !this.host.hasAttribute("data-rn-measuring"))
|
|
10433
|
+
return false;
|
|
10434
|
+
let i = this.sizes.get(e);
|
|
10435
|
+
return !i || Math.abs(i.width - t) > 0.2 || Math.abs(i.height - n) > 0.2;
|
|
10436
|
+
}
|
|
10437
|
+
visibility(e) {
|
|
10438
|
+
if (this.visible === e)
|
|
10439
|
+
return;
|
|
10440
|
+
if (this.visible = e, e || this.options.pauseOffscreen !== false)
|
|
10441
|
+
this.refresh();
|
|
10442
|
+
}
|
|
10443
|
+
finish() {
|
|
10444
|
+
if (this.destroyed)
|
|
10445
|
+
return;
|
|
10446
|
+
this.measurementPending = false;
|
|
10447
|
+
for (let e of this.columns.values())
|
|
10448
|
+
this.removeColumn(e);
|
|
10449
|
+
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;
|
|
10450
|
+
}
|
|
10451
|
+
destroy() {
|
|
10452
|
+
if (this.destroyed)
|
|
10453
|
+
return;
|
|
10454
|
+
this.finish(), this.destroyed = true;
|
|
10455
|
+
for (let e of this.measures.values())
|
|
10456
|
+
this.scheduler?.unwatch(e);
|
|
10457
|
+
if (this.scheduler?.unwatch(this.measurement), this.scheduler?.remove(this, this.host), this.host.replaceChildren(this.host.ownerDocument.createTextNode(this.target.text)), !this.hadClass)
|
|
10458
|
+
this.host.classList.remove("rn-root");
|
|
10459
|
+
_.delete(this.host);
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10462
|
+
function rt(e, t) {
|
|
10463
|
+
if (_.has(e))
|
|
10464
|
+
throw Error("A rolling number is already mounted on this element");
|
|
10465
|
+
let n = new oe(e, t, Fe);
|
|
10466
|
+
return _.add(e), n;
|
|
10467
|
+
}
|
|
10468
|
+
|
|
10469
|
+
// src/ui/activity-model.ts
|
|
10470
|
+
function flattenActivity(events, expanded) {
|
|
10471
|
+
const rows = [];
|
|
10472
|
+
for (const event of events) {
|
|
10473
|
+
const kids = event.children ?? [];
|
|
10474
|
+
const group = kids.length > 0;
|
|
10475
|
+
const open = group && expanded.has(event.id);
|
|
10476
|
+
rows.push({ id: event.id, event, depth: 0, parent: null, group, expanded: open });
|
|
10477
|
+
if (open)
|
|
10478
|
+
for (const child of flatChildren(kids))
|
|
10479
|
+
rows.push({
|
|
10480
|
+
id: child.id,
|
|
10481
|
+
event: child,
|
|
10482
|
+
depth: 1,
|
|
10483
|
+
parent: event.id,
|
|
10484
|
+
group: false,
|
|
10485
|
+
expanded: false
|
|
10486
|
+
});
|
|
10487
|
+
}
|
|
10488
|
+
return rows;
|
|
10489
|
+
}
|
|
10490
|
+
function flatChildren(events) {
|
|
10491
|
+
const out = [];
|
|
10492
|
+
for (const e of events) {
|
|
10493
|
+
out.push(e);
|
|
10494
|
+
if (e.children?.length)
|
|
10495
|
+
out.push(...flatChildren(e.children));
|
|
10496
|
+
}
|
|
10497
|
+
return out;
|
|
10498
|
+
}
|
|
10499
|
+
function indexActivity(events) {
|
|
10500
|
+
const index = new Map;
|
|
10501
|
+
for (const event of events) {
|
|
10502
|
+
index.set(event.id, { event, parent: null });
|
|
10503
|
+
for (const child of flatChildren(event.children ?? []))
|
|
10504
|
+
index.set(child.id, { event: child, parent: event.id });
|
|
10505
|
+
}
|
|
10506
|
+
return index;
|
|
10507
|
+
}
|
|
10508
|
+
var isActivityKey = (key) => key === "ArrowUp" || key === "ArrowDown" || key === "ArrowLeft" || key === "ArrowRight" || key === "Home" || key === "End";
|
|
10509
|
+
function navigateActivity(rows, selected, key) {
|
|
10510
|
+
if (!rows.length)
|
|
10511
|
+
return {};
|
|
10512
|
+
const i = selected === null ? -1 : rows.findIndex((r) => r.id === selected);
|
|
10513
|
+
const row = i >= 0 ? rows[i] : undefined;
|
|
10514
|
+
switch (key) {
|
|
10515
|
+
case "ArrowDown":
|
|
10516
|
+
return { select: rows[i < 0 ? 0 : Math.min(rows.length - 1, i + 1)].id };
|
|
10517
|
+
case "ArrowUp":
|
|
10518
|
+
return { select: rows[i < 0 ? rows.length - 1 : Math.max(0, i - 1)].id };
|
|
10519
|
+
case "Home":
|
|
10520
|
+
return { select: rows[0].id };
|
|
10521
|
+
case "End":
|
|
10522
|
+
return { select: rows[rows.length - 1].id };
|
|
10523
|
+
case "ArrowRight":
|
|
10524
|
+
if (!row?.group)
|
|
10525
|
+
return {};
|
|
10526
|
+
if (!row.expanded)
|
|
10527
|
+
return { toggle: { id: row.id, expanded: true } };
|
|
10528
|
+
return rows[i + 1]?.parent === row.id ? { select: rows[i + 1].id } : {};
|
|
10529
|
+
case "ArrowLeft":
|
|
10530
|
+
if (!row)
|
|
10531
|
+
return {};
|
|
10532
|
+
if (row.group && row.expanded)
|
|
10533
|
+
return { toggle: { id: row.id, expanded: false } };
|
|
10534
|
+
return row.parent !== null ? { select: row.parent } : {};
|
|
10535
|
+
}
|
|
10536
|
+
}
|
|
10537
|
+
function takesActivityKey(key, result, rows) {
|
|
10538
|
+
if (result.select !== undefined || result.toggle !== undefined)
|
|
10539
|
+
return true;
|
|
10540
|
+
return rows > 0 && key !== "ArrowLeft" && key !== "ArrowRight";
|
|
10541
|
+
}
|
|
10542
|
+
function keepSelection(rows, selected, parentOf) {
|
|
10543
|
+
if (selected === null)
|
|
10544
|
+
return null;
|
|
10545
|
+
if (rows.some((r) => r.id === selected))
|
|
10546
|
+
return selected;
|
|
10547
|
+
const parent = parentOf(selected);
|
|
10548
|
+
return parent && rows.some((r) => r.id === parent) ? parent : null;
|
|
10549
|
+
}
|
|
10550
|
+
function showsSelection(showing, input, keys = "focus") {
|
|
10551
|
+
if (input === "key")
|
|
10552
|
+
return true;
|
|
10553
|
+
if (input === "pointer")
|
|
10554
|
+
return false;
|
|
10555
|
+
if (input === "blur")
|
|
10556
|
+
return keys === "page" ? showing : false;
|
|
10557
|
+
return showing;
|
|
10558
|
+
}
|
|
10559
|
+
function diffActivity(before, after) {
|
|
10560
|
+
const was = new Set(before);
|
|
10561
|
+
const now = new Set(after);
|
|
10562
|
+
return {
|
|
10563
|
+
entered: after.filter((id) => !was.has(id)),
|
|
10564
|
+
left: before.filter((id) => !now.has(id)),
|
|
10565
|
+
kept: after.filter((id) => was.has(id))
|
|
10566
|
+
};
|
|
10567
|
+
}
|
|
10568
|
+
function stackRows(heights, top = 0, gap = 0) {
|
|
10569
|
+
const y = [];
|
|
10570
|
+
let at = top;
|
|
10571
|
+
heights.forEach((h, i) => {
|
|
10572
|
+
y.push(at);
|
|
10573
|
+
at += h + (i < heights.length - 1 ? gap : 0);
|
|
10574
|
+
});
|
|
10575
|
+
return { y, bottom: at };
|
|
10576
|
+
}
|
|
10577
|
+
function railSegments(nodes, from, to) {
|
|
10578
|
+
const sorted = [...nodes].sort((a, b) => a.y - b.y);
|
|
10579
|
+
const out = [];
|
|
10580
|
+
for (let i = 0;i < sorted.length - 1; i++) {
|
|
10581
|
+
const a = sorted[i];
|
|
10582
|
+
const b = sorted[i + 1];
|
|
10583
|
+
const top = Math.max(from, a.y + a.r);
|
|
10584
|
+
const bottom = Math.min(to, b.y - b.r);
|
|
10585
|
+
if (bottom - top > 0.25)
|
|
10586
|
+
out.push([top, bottom]);
|
|
10587
|
+
}
|
|
10588
|
+
return out;
|
|
10589
|
+
}
|
|
10590
|
+
function holdScroll(hold, height, view) {
|
|
10591
|
+
if (hold.from <= 0)
|
|
10592
|
+
return { scroll: 0, space: height };
|
|
10593
|
+
const end = Math.min(hold.from, Math.max(0, hold.h1 - view));
|
|
10594
|
+
const span = hold.h1 - hold.h0;
|
|
10595
|
+
const p = Math.abs(span) < 0.5 ? 1 : Math.min(1, Math.max(0, (height - hold.h0) / span));
|
|
10596
|
+
const scroll = hold.from + (end - hold.from) * p;
|
|
10597
|
+
return { scroll, space: Math.max(height, scroll + view) };
|
|
10598
|
+
}
|
|
10599
|
+
function formatDuration(duration) {
|
|
10600
|
+
if (typeof duration === "string")
|
|
10601
|
+
return duration;
|
|
10602
|
+
const s = Math.max(0, Math.round(duration));
|
|
10603
|
+
const h = Math.floor(s / 3600);
|
|
10604
|
+
const m = Math.floor(s % 3600 / 60);
|
|
10605
|
+
const sec = String(s % 60).padStart(2, "0");
|
|
10606
|
+
return h ? `${h}:${String(m).padStart(2, "0")}:${sec}` : `${m}:${sec}`;
|
|
10607
|
+
}
|
|
10608
|
+
function groupTitle(count) {
|
|
10609
|
+
return `${count} update${count === 1 ? "" : "s"}`;
|
|
10610
|
+
}
|
|
10611
|
+
|
|
10612
|
+
// src/ui/activity.ts
|
|
10613
|
+
var ACTIVITY_ICONS = {
|
|
10614
|
+
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"/>'),
|
|
10615
|
+
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"/>'),
|
|
10616
|
+
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"/>'),
|
|
10617
|
+
review: svg('<rect x="2" y="3.5" width="12" height="9" rx="2.2"/><path d="M7 6.3v3.4L9.8 8Z"/>'),
|
|
10618
|
+
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"/>'),
|
|
10619
|
+
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"/>'),
|
|
10620
|
+
blocked: svg('<path d="M3.8 14V2.6M3.8 3h8l-1.9 3 1.9 3h-8"/>'),
|
|
10621
|
+
shipped: svg('<circle cx="8" cy="8" r="5.8"/><path d="m5.6 8.2 1.7 1.7 3.2-3.6"/>')
|
|
10622
|
+
};
|
|
10623
|
+
var PLAY2 = '<svg viewBox="0 0 8 8" aria-hidden="true"><path d="M1.5 1v6l5.2-3Z" fill="currentColor"/></svg>';
|
|
10624
|
+
var REFLOW = springMotion({ duration: 0.3, bounce: 0 });
|
|
10625
|
+
var OPEN = springMotion({ duration: 0.22, bounce: 0 });
|
|
10626
|
+
var CLOSE = springMotion({ duration: 0.18, bounce: 0 });
|
|
10627
|
+
var BLOOM = springMotion({ duration: 0.3, bounce: 0 });
|
|
10628
|
+
var EXIT2 = springMotion({ duration: 0.24, bounce: 0 });
|
|
10629
|
+
var FADE2 = springMotion({ duration: 0.16, bounce: 0 });
|
|
10630
|
+
var CLEAR = [11, 5];
|
|
10631
|
+
var PAD = 6;
|
|
10632
|
+
var SLIDE2 = 8;
|
|
10633
|
+
function activity(container, options) {
|
|
10634
|
+
const doc = container.ownerDocument;
|
|
10635
|
+
const win = doc.defaultView;
|
|
10636
|
+
let newest = options.newest ?? "bottom";
|
|
10637
|
+
const keysFrom = options.keys ?? "focus";
|
|
10638
|
+
let events = options.events;
|
|
10639
|
+
let index = indexActivity(events);
|
|
10640
|
+
const expanded = new Set(options.expanded ?? []);
|
|
10641
|
+
let rows = [];
|
|
10642
|
+
let selected = options.selected ?? null;
|
|
10643
|
+
let showing = false;
|
|
10644
|
+
const root = doc.createElement("div");
|
|
10645
|
+
root.className = "knobs-activity knobs-scroll-fade";
|
|
10646
|
+
root.tabIndex = 0;
|
|
10647
|
+
root.setAttribute("role", "tree");
|
|
10648
|
+
if (options.label)
|
|
10649
|
+
root.setAttribute("aria-label", options.label);
|
|
10650
|
+
applyLook(root, options);
|
|
10651
|
+
const space = doc.createElement("div");
|
|
10652
|
+
space.className = "knobs-activity-space";
|
|
10653
|
+
const hl = doc.createElement("div");
|
|
10654
|
+
hl.className = "knobs-activity-hl";
|
|
10655
|
+
hl.setAttribute("aria-hidden", "true");
|
|
10656
|
+
const line = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
10657
|
+
line.setAttribute("class", "knobs-activity-line");
|
|
10658
|
+
line.setAttribute("aria-hidden", "true");
|
|
10659
|
+
const path = doc.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
10660
|
+
line.append(path);
|
|
10661
|
+
const empty = doc.createElement("div");
|
|
10662
|
+
empty.className = "knobs-activity-empty";
|
|
10663
|
+
empty.hidden = true;
|
|
10664
|
+
space.append(hl, line);
|
|
10665
|
+
root.append(empty, space);
|
|
10666
|
+
container.append(root);
|
|
10667
|
+
const scrollbar = overlayScrollbar(root, space);
|
|
10668
|
+
let heights = [32, 26];
|
|
10669
|
+
const measure = () => {
|
|
10670
|
+
syncFrame(root);
|
|
10671
|
+
const probe = (depth) => {
|
|
10672
|
+
const p = doc.createElement("div");
|
|
10673
|
+
p.className = "knobs-activity-row";
|
|
10674
|
+
p.dataset.depth = String(depth);
|
|
10675
|
+
p.style.visibility = "hidden";
|
|
10676
|
+
space.append(p);
|
|
10677
|
+
const h = p.getBoundingClientRect().height;
|
|
10678
|
+
p.remove();
|
|
10679
|
+
return h;
|
|
10680
|
+
};
|
|
10681
|
+
heights = [probe(0) || 32, probe(1) || 26];
|
|
10682
|
+
};
|
|
10683
|
+
measure();
|
|
10684
|
+
const uid = `ka${Math.random().toString(36).slice(2, 7)}`;
|
|
10685
|
+
const domIds = new Map;
|
|
10686
|
+
const domId = (id) => {
|
|
10687
|
+
let d = domIds.get(id);
|
|
10688
|
+
if (!d)
|
|
10689
|
+
domIds.set(id, d = `${uid}-${domIds.size}`);
|
|
10690
|
+
return d;
|
|
10691
|
+
};
|
|
10692
|
+
const views = new Map;
|
|
10693
|
+
const makeView = (row) => {
|
|
10694
|
+
const el = doc.createElement("div");
|
|
10695
|
+
el.className = "knobs-activity-row";
|
|
10696
|
+
el.setAttribute("role", "treeitem");
|
|
10697
|
+
el.id = domId(row.id);
|
|
10698
|
+
el.dataset.id = row.id;
|
|
10699
|
+
const node = doc.createElement("span");
|
|
10700
|
+
node.className = "knobs-activity-node";
|
|
10701
|
+
const main = doc.createElement("span");
|
|
10702
|
+
main.className = "knobs-activity-main knobs-scroll-fade-x";
|
|
10703
|
+
const actor = doc.createElement("span");
|
|
10704
|
+
actor.className = "knobs-activity-actor";
|
|
10705
|
+
const title = doc.createElement("span");
|
|
10706
|
+
title.className = "knobs-activity-title";
|
|
10707
|
+
main.append(actor, title);
|
|
10708
|
+
const meta = doc.createElement("span");
|
|
10709
|
+
meta.className = "knobs-activity-meta";
|
|
10710
|
+
const thumbs = doc.createElement("span");
|
|
10711
|
+
thumbs.className = "knobs-activity-thumbs";
|
|
10712
|
+
const caret = doc.createElement("span");
|
|
10713
|
+
caret.className = "knobs-activity-caret";
|
|
10714
|
+
caret.innerHTML = ICONS.caret;
|
|
10715
|
+
const time = doc.createElement("span");
|
|
10716
|
+
time.className = "knobs-activity-time";
|
|
10717
|
+
el.append(node, main, meta);
|
|
10718
|
+
space.append(el);
|
|
10719
|
+
const v = {
|
|
10720
|
+
id: row.id,
|
|
10721
|
+
el,
|
|
10722
|
+
node,
|
|
10723
|
+
actor,
|
|
10724
|
+
title,
|
|
10725
|
+
meta,
|
|
10726
|
+
thumbs,
|
|
10727
|
+
chip: null,
|
|
10728
|
+
caret,
|
|
10729
|
+
time,
|
|
10730
|
+
roll: null,
|
|
10731
|
+
chipRoll: null,
|
|
10732
|
+
y: new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05),
|
|
10733
|
+
p: new Spring(1, BLOOM.omega, BLOOM.zeta, 0.002),
|
|
10734
|
+
depth: row.depth,
|
|
10735
|
+
under: null,
|
|
10736
|
+
from: 0,
|
|
10737
|
+
leaving: false,
|
|
10738
|
+
event: undefined,
|
|
10739
|
+
state: ""
|
|
10740
|
+
};
|
|
10741
|
+
views.set(row.id, v);
|
|
10742
|
+
return v;
|
|
10743
|
+
};
|
|
10744
|
+
const dropView = (v) => {
|
|
10745
|
+
v.roll?.destroy();
|
|
10746
|
+
v.chipRoll?.destroy();
|
|
10747
|
+
v.el.remove();
|
|
10748
|
+
views.delete(v.id);
|
|
10749
|
+
};
|
|
10750
|
+
const rollInto = (host, roll, text) => {
|
|
10751
|
+
if (!text) {
|
|
10752
|
+
roll?.destroy();
|
|
10753
|
+
host.textContent = "";
|
|
10754
|
+
return null;
|
|
10755
|
+
}
|
|
10756
|
+
if (roll) {
|
|
10757
|
+
roll.update({ text });
|
|
10758
|
+
return roll;
|
|
10759
|
+
}
|
|
10760
|
+
return rt(host, {
|
|
10761
|
+
text,
|
|
10762
|
+
charset: "0123456789",
|
|
10763
|
+
transition: "direct",
|
|
10764
|
+
animated: !reducedMotion(win)
|
|
10765
|
+
});
|
|
10766
|
+
};
|
|
10767
|
+
const bind = (v, row) => {
|
|
10768
|
+
const e = row.event;
|
|
10769
|
+
const state = `${row.depth}|${row.group}|${row.expanded}|${selected === row.id}`;
|
|
10770
|
+
if (v.event === e && v.state === state)
|
|
10771
|
+
return;
|
|
10772
|
+
const changed = v.event !== e;
|
|
10773
|
+
v.event = e;
|
|
10774
|
+
v.state = state;
|
|
10775
|
+
v.depth = row.depth;
|
|
10776
|
+
const el = v.el;
|
|
10777
|
+
el.dataset.depth = String(row.depth);
|
|
10778
|
+
el.setAttribute("aria-level", String(row.depth + 1));
|
|
10779
|
+
el.setAttribute("aria-selected", String(selected === row.id));
|
|
10780
|
+
if (row.group)
|
|
10781
|
+
el.setAttribute("aria-expanded", String(row.expanded));
|
|
10782
|
+
else
|
|
10783
|
+
el.removeAttribute("aria-expanded");
|
|
10784
|
+
if (!changed)
|
|
10785
|
+
return;
|
|
10786
|
+
if (e.kind)
|
|
10787
|
+
el.dataset.kind = e.kind;
|
|
10788
|
+
else
|
|
10789
|
+
delete el.dataset.kind;
|
|
10790
|
+
el.toggleAttribute("data-current", Boolean(e.current));
|
|
10791
|
+
el.toggleAttribute("data-dimmed", Boolean(e.dimmed));
|
|
10792
|
+
const tint = e.tint ?? (e.kind ? options.tints?.[e.kind] : undefined);
|
|
10793
|
+
if (tint)
|
|
10794
|
+
el.style.setProperty("--ka-tint", tint);
|
|
10795
|
+
else
|
|
10796
|
+
el.style.removeProperty("--ka-tint");
|
|
10797
|
+
const icon = e.icon ?? (row.depth === 1 ? undefined : (e.kind && (options.icons?.[e.kind] ?? ACTIVITY_ICONS[e.kind])) ?? undefined);
|
|
10798
|
+
if (icon instanceof Node)
|
|
10799
|
+
v.node.replaceChildren(icon);
|
|
10800
|
+
else if (icon === undefined) {
|
|
10801
|
+
if (!v.node.firstElementChild?.classList.contains("knobs-activity-dot"))
|
|
10802
|
+
v.node.innerHTML = '<i class="knobs-activity-dot"></i>';
|
|
10803
|
+
} else if (icon.trimStart().startsWith("<")) {
|
|
10804
|
+
if (v.node.innerHTML !== icon)
|
|
10805
|
+
v.node.innerHTML = icon;
|
|
10806
|
+
} else {
|
|
10807
|
+
const glyph = doc.createElement("span");
|
|
10808
|
+
glyph.className = "knobs-activity-glyph";
|
|
10809
|
+
glyph.textContent = icon;
|
|
10810
|
+
v.node.replaceChildren(glyph);
|
|
10811
|
+
}
|
|
10812
|
+
const kids = e.children?.length ?? 0;
|
|
10813
|
+
v.actor.textContent = e.actor ?? "";
|
|
10814
|
+
const title = e.title ?? (kids ? groupTitle(kids) : "");
|
|
10815
|
+
if (v.title.textContent !== title)
|
|
10816
|
+
v.title.textContent = title;
|
|
10817
|
+
el.setAttribute("aria-label", [e.actor, title, e.time].filter(Boolean).join(", "));
|
|
10818
|
+
const parts = [];
|
|
10819
|
+
const thumbs = e.thumbs?.slice(0, 4) ?? [];
|
|
10820
|
+
const shown = [...v.thumbs.querySelectorAll("img")].map((i) => i.getAttribute("src"));
|
|
10821
|
+
if (thumbs.join(`
|
|
10822
|
+
`) !== shown.join(`
|
|
10823
|
+
`))
|
|
10824
|
+
v.thumbs.replaceChildren(...thumbs.map((src) => {
|
|
10825
|
+
const img = doc.createElement("img");
|
|
10826
|
+
img.src = src;
|
|
10827
|
+
img.alt = "";
|
|
10828
|
+
img.loading = "lazy";
|
|
10829
|
+
img.draggable = false;
|
|
10830
|
+
return img;
|
|
10831
|
+
}));
|
|
10832
|
+
if (thumbs.length)
|
|
10833
|
+
parts.push(v.thumbs);
|
|
10834
|
+
if (e.duration !== undefined) {
|
|
10835
|
+
const button = Boolean(options.onPlay);
|
|
10836
|
+
if (!v.chip || v.chip.tagName === "BUTTON" !== button) {
|
|
10837
|
+
v.chipRoll?.destroy();
|
|
10838
|
+
v.chipRoll = null;
|
|
10839
|
+
v.chip = doc.createElement(button ? "button" : "span");
|
|
10840
|
+
v.chip.className = "knobs-activity-chip";
|
|
10841
|
+
if (button) {
|
|
10842
|
+
v.chip.type = "button";
|
|
10843
|
+
v.chip.tabIndex = -1;
|
|
10844
|
+
v.chip.setAttribute("aria-label", "Play");
|
|
10845
|
+
}
|
|
10846
|
+
v.chip.innerHTML = `${PLAY2}<span></span>`;
|
|
10847
|
+
}
|
|
10848
|
+
v.chipRoll = rollInto(v.chip.lastElementChild, v.chipRoll, formatDuration(e.duration));
|
|
10849
|
+
parts.push(v.chip);
|
|
10850
|
+
}
|
|
10851
|
+
if (kids)
|
|
10852
|
+
parts.push(v.caret);
|
|
10853
|
+
v.roll = rollInto(v.time, v.roll, e.time ?? "");
|
|
10854
|
+
if (e.time)
|
|
10855
|
+
parts.push(v.time);
|
|
10856
|
+
const now = [...v.meta.children];
|
|
10857
|
+
if (now.length !== parts.length || now.some((n, i) => n !== parts[i]))
|
|
10858
|
+
v.meta.replaceChildren(...parts);
|
|
10859
|
+
};
|
|
10860
|
+
const nodeY = (v) => v.y.x + heights[v.depth] / 2;
|
|
10861
|
+
let targets = new Map;
|
|
10862
|
+
const lineTop = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
|
|
10863
|
+
const lineBottom = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
|
|
10864
|
+
const hlY = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
|
|
10865
|
+
const hlH = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
|
|
10866
|
+
const height = new Spring(0, REFLOW.omega, REFLOW.zeta, 0.05);
|
|
10867
|
+
let following = false;
|
|
10868
|
+
let scrollHold = null;
|
|
10869
|
+
const place = (v, reduced) => {
|
|
10870
|
+
const p = Math.max(0, Math.min(1, v.p.x));
|
|
10871
|
+
let y = v.y.x;
|
|
10872
|
+
let clip = 0;
|
|
10873
|
+
let transform = "";
|
|
10874
|
+
let filter = "";
|
|
10875
|
+
if (v.under !== null) {
|
|
10876
|
+
const parent = views.get(v.under);
|
|
10877
|
+
const bottom = (parent ? parent.y.x : targets.get(v.under) ?? 0) + heights[0];
|
|
10878
|
+
clip = Math.min(heights[v.depth], Math.max(0, bottom - y));
|
|
10879
|
+
} else if (p < 1 && !reduced) {
|
|
10880
|
+
y += (1 - p) * SLIDE2 * v.from;
|
|
10881
|
+
transform = ` scale(${(0.97 + 0.03 * p).toFixed(4)})`;
|
|
10882
|
+
const blur = (1 - p) * 3;
|
|
10883
|
+
if (blur > 0.05)
|
|
10884
|
+
filter = `blur(${blur.toFixed(2)}px)`;
|
|
10885
|
+
}
|
|
10886
|
+
v.el.style.transform = `translate3d(0,${Math.round(y * 2) / 2}px,0)${transform}`;
|
|
10887
|
+
v.el.style.clipPath = clip > 0 ? `inset(${clip}px 0 0 0)` : "";
|
|
10888
|
+
v.el.style.opacity = p < 0.999 ? p.toFixed(3) : "";
|
|
10889
|
+
v.el.style.filter = filter;
|
|
10890
|
+
};
|
|
10891
|
+
const drawLine = () => {
|
|
10892
|
+
const nodes = [];
|
|
10893
|
+
for (const v of views.values()) {
|
|
10894
|
+
const p = Math.max(0, Math.min(1, v.p.x));
|
|
10895
|
+
if (p <= 0.001)
|
|
10896
|
+
continue;
|
|
10897
|
+
const y = nodeY(v);
|
|
10898
|
+
if (v.under !== null) {
|
|
10899
|
+
const parent = views.get(v.under);
|
|
10900
|
+
if (parent && y < parent.y.x + heights[0])
|
|
10901
|
+
continue;
|
|
10902
|
+
}
|
|
10903
|
+
nodes.push({ y, r: CLEAR[v.depth] * Math.min(1, p * 1.5) });
|
|
10904
|
+
}
|
|
10905
|
+
const segs = railSegments(nodes, lineTop.x, lineBottom.x);
|
|
10906
|
+
path.setAttribute("d", segs.map(([a, b]) => `M1 ${a.toFixed(2)}V${b.toFixed(2)}`).join(""));
|
|
10907
|
+
};
|
|
10908
|
+
const placeHighlight = () => {
|
|
10909
|
+
hl.style.transform = `translate3d(0,${Math.round(hlY.x * 2) / 2}px,0)`;
|
|
10910
|
+
hl.style.height = `${Math.max(0, hlH.x).toFixed(2)}px`;
|
|
10911
|
+
};
|
|
10912
|
+
const loop = frameLoop(win, (dt) => {
|
|
10913
|
+
const reduced = reducedMotion(win);
|
|
10914
|
+
let moving = false;
|
|
10915
|
+
for (const s of [lineTop, lineBottom, hlY, hlH, height]) {
|
|
10916
|
+
s.step(dt);
|
|
10917
|
+
if (!s.resting)
|
|
10918
|
+
moving = true;
|
|
10919
|
+
}
|
|
10920
|
+
for (const v of [...views.values()]) {
|
|
10921
|
+
v.y.step(dt);
|
|
10922
|
+
v.p.step(dt);
|
|
10923
|
+
if (v.y.resting && v.p.resting) {
|
|
10924
|
+
if (v.leaving) {
|
|
10925
|
+
dropView(v);
|
|
10926
|
+
continue;
|
|
10927
|
+
}
|
|
10928
|
+
v.under = null;
|
|
10929
|
+
v.from = 0;
|
|
10930
|
+
} else
|
|
10931
|
+
moving = true;
|
|
10932
|
+
place(v, reduced);
|
|
10933
|
+
}
|
|
10934
|
+
drawLine();
|
|
10935
|
+
placeHighlight();
|
|
10936
|
+
if (scrollHold && !following) {
|
|
10937
|
+
const { scroll, space: reserved } = holdScroll(scrollHold, height.x, root.clientHeight);
|
|
10938
|
+
space.style.height = `${Math.max(0, reserved).toFixed(1)}px`;
|
|
10939
|
+
root.scrollTop = scroll;
|
|
10940
|
+
} else
|
|
10941
|
+
space.style.height = `${Math.max(0, height.x).toFixed(1)}px`;
|
|
10942
|
+
if (following)
|
|
10943
|
+
root.scrollTop = newest === "bottom" ? root.scrollHeight : 0;
|
|
10944
|
+
if (!moving) {
|
|
10945
|
+
following = false;
|
|
10946
|
+
scrollHold = null;
|
|
10947
|
+
}
|
|
10948
|
+
return moving;
|
|
10949
|
+
});
|
|
10950
|
+
const atNewestEnd = () => newest === "bottom" ? root.scrollTop + root.clientHeight >= root.scrollHeight - 4 : root.scrollTop <= 4;
|
|
10951
|
+
function sync(cause, toggled) {
|
|
10952
|
+
const reduced = reducedMotion(win);
|
|
10953
|
+
const animate = cause !== "snap";
|
|
10954
|
+
const glide = cause === "open" ? OPEN : cause === "close" ? CLOSE : REFLOW;
|
|
10955
|
+
const before = [...views.values()].filter((v) => !v.leaving).map((v) => v.id);
|
|
10956
|
+
rows = flattenActivity(events, expanded);
|
|
10957
|
+
selected = keepSelection(rows, selected, (id) => index.get(id)?.parent);
|
|
10958
|
+
const stack = stackRows(rows.map((r) => heights[r.depth]), PAD);
|
|
10959
|
+
targets = new Map(rows.map((r, i) => [r.id, stack.y[i]]));
|
|
10960
|
+
const { entered } = diffActivity(before, rows.map((r) => r.id));
|
|
10961
|
+
const fresh = new Set(entered);
|
|
10962
|
+
let opened = 0;
|
|
10963
|
+
if (cause === "open") {
|
|
10964
|
+
for (const r of rows)
|
|
10965
|
+
if (r.parent === toggled && fresh.has(r.id))
|
|
10966
|
+
opened += heights[r.depth];
|
|
10967
|
+
}
|
|
10968
|
+
let shut = 0;
|
|
10969
|
+
const live = new Set(rows.map((r) => r.id));
|
|
10970
|
+
if (cause === "close") {
|
|
10971
|
+
for (const v of views.values())
|
|
10972
|
+
if (!live.has(v.id) && !v.leaving && index.get(v.id)?.parent === toggled)
|
|
10973
|
+
shut += heights[v.depth];
|
|
10974
|
+
}
|
|
10975
|
+
const following0 = animate && options.follow !== false && atNewestEnd();
|
|
10976
|
+
const lastIndex = rows.length - 1;
|
|
10977
|
+
rows.forEach((row, i) => {
|
|
10978
|
+
const goal = stack.y[i];
|
|
10979
|
+
let v = views.get(row.id);
|
|
10980
|
+
if (v && v.leaving) {
|
|
10981
|
+
v.leaving = false;
|
|
10982
|
+
delete v.el.dataset.leaving;
|
|
10983
|
+
tune(v.p, cause === "open" ? OPEN : BLOOM).set(1);
|
|
10984
|
+
}
|
|
10985
|
+
if (!v) {
|
|
10986
|
+
v = makeView(row);
|
|
10987
|
+
if (!animate) {
|
|
10988
|
+
v.y.snap(goal);
|
|
10989
|
+
v.p.snap(1);
|
|
10990
|
+
} else if (reduced) {
|
|
10991
|
+
v.y.snap(goal);
|
|
10992
|
+
tune(v.p, FADE2).snap(0).set(1);
|
|
10993
|
+
} else {
|
|
10994
|
+
const parent = row.parent !== null ? views.get(row.parent) : undefined;
|
|
10995
|
+
if (parent && !parent.leaving) {
|
|
10996
|
+
v.under = row.parent;
|
|
10997
|
+
const drawer = cause === "open" && row.parent === toggled;
|
|
10998
|
+
v.y.snap(drawer ? goal - opened + parent.y.x - parent.y.target : parent.y.x);
|
|
10999
|
+
tune(v.y, drawer ? OPEN : glide).set(goal);
|
|
11000
|
+
tune(v.p, drawer ? OPEN : BLOOM).snap(0).set(1);
|
|
11001
|
+
} else {
|
|
11002
|
+
v.y.snap(goal);
|
|
11003
|
+
v.from = newest === "bottom" ? 1 : -1;
|
|
11004
|
+
tune(v.p, BLOOM).snap(0).set(1);
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
11007
|
+
} else if (!animate || reduced)
|
|
11008
|
+
v.y.snap(goal);
|
|
11009
|
+
else
|
|
11010
|
+
tune(v.y, glide).set(goal);
|
|
11011
|
+
bind(v, row);
|
|
11012
|
+
});
|
|
11013
|
+
for (const v of [...views.values()]) {
|
|
11014
|
+
if (live.has(v.id) || v.leaving)
|
|
11015
|
+
continue;
|
|
11016
|
+
if (!animate) {
|
|
11017
|
+
dropView(v);
|
|
11018
|
+
continue;
|
|
11019
|
+
}
|
|
11020
|
+
v.leaving = true;
|
|
11021
|
+
v.el.dataset.leaving = "";
|
|
11022
|
+
v.el.setAttribute("aria-selected", "false");
|
|
11023
|
+
if (reduced) {
|
|
11024
|
+
tune(v.p, FADE2).set(0);
|
|
11025
|
+
continue;
|
|
11026
|
+
}
|
|
11027
|
+
const group = index.get(v.id)?.parent ?? null;
|
|
11028
|
+
const parent = group !== null ? views.get(group) : undefined;
|
|
11029
|
+
if (parent && !parent.leaving && v.depth === 1) {
|
|
11030
|
+
v.under = group;
|
|
11031
|
+
const drawer = cause === "close" && group === toggled;
|
|
11032
|
+
tune(v.y, drawer ? CLOSE : glide).set(drawer ? v.y.target - shut : targets.get(group) ?? parent.y.target);
|
|
11033
|
+
tune(v.p, drawer ? CLOSE : EXIT2).set(0);
|
|
11034
|
+
} else {
|
|
11035
|
+
v.from = 0;
|
|
11036
|
+
tune(v.p, EXIT2).set(0);
|
|
11037
|
+
}
|
|
11038
|
+
}
|
|
11039
|
+
const first = rows[0];
|
|
11040
|
+
const last = rows[lastIndex];
|
|
11041
|
+
const firstY = first ? targets.get(first.id) + heights[first.depth] / 2 : PAD;
|
|
11042
|
+
const lastY = last ? targets.get(last.id) + heights[last.depth] / 2 : PAD;
|
|
11043
|
+
const bottom = stack.bottom + PAD;
|
|
11044
|
+
if (!animate || reduced) {
|
|
11045
|
+
lineTop.snap(firstY);
|
|
11046
|
+
lineBottom.snap(lastY);
|
|
11047
|
+
height.snap(bottom);
|
|
11048
|
+
} else {
|
|
11049
|
+
if (!before.length) {
|
|
11050
|
+
lineTop.snap(firstY);
|
|
11051
|
+
lineBottom.snap(firstY);
|
|
11052
|
+
}
|
|
11053
|
+
tune(lineTop, glide).set(firstY);
|
|
11054
|
+
tune(lineBottom, cause === "set" ? BLOOM : glide).set(lastY);
|
|
11055
|
+
tune(height, glide).set(bottom);
|
|
11056
|
+
}
|
|
11057
|
+
moveHighlight(animate && !reduced ? glide : null);
|
|
11058
|
+
hl.hidden = !selected;
|
|
11059
|
+
empty.hidden = rows.length > 0;
|
|
11060
|
+
empty.textContent = options.empty ?? "Nothing yet";
|
|
11061
|
+
if (selected)
|
|
11062
|
+
root.setAttribute("aria-activedescendant", domId(selected));
|
|
11063
|
+
else
|
|
11064
|
+
root.removeAttribute("aria-activedescendant");
|
|
11065
|
+
following = following || following0 && cause === "set" && fresh.size > 0;
|
|
11066
|
+
scrollHold = animate && !following && !reduced ? { from: root.scrollTop, h0: height.x, h1: height.target } : null;
|
|
11067
|
+
for (const v of views.values())
|
|
11068
|
+
place(v, reduced);
|
|
11069
|
+
drawLine();
|
|
11070
|
+
placeHighlight();
|
|
11071
|
+
space.style.height = `${height.x.toFixed(1)}px`;
|
|
11072
|
+
loop.wake();
|
|
11073
|
+
}
|
|
11074
|
+
const moveHighlight = (motion) => {
|
|
11075
|
+
if (!showing)
|
|
11076
|
+
return;
|
|
11077
|
+
const y = selected ? targets.get(selected) : undefined;
|
|
11078
|
+
if (y === undefined)
|
|
11079
|
+
return;
|
|
11080
|
+
const h = heights[rows.find((r) => r.id === selected)?.depth ?? 0];
|
|
11081
|
+
if (!motion) {
|
|
11082
|
+
hlY.snap(y);
|
|
11083
|
+
hlH.snap(h);
|
|
11084
|
+
return;
|
|
11085
|
+
}
|
|
11086
|
+
tune(hlY, motion).set(y);
|
|
11087
|
+
tune(hlH, motion).set(h);
|
|
11088
|
+
};
|
|
11089
|
+
const setShowing = (input) => {
|
|
11090
|
+
const next = showsSelection(showing, input, keysFrom);
|
|
11091
|
+
if (next === showing)
|
|
11092
|
+
return;
|
|
11093
|
+
showing = next;
|
|
11094
|
+
root.toggleAttribute("data-keys", next);
|
|
11095
|
+
};
|
|
11096
|
+
const rebind = () => {
|
|
11097
|
+
for (const row of rows) {
|
|
11098
|
+
const v = views.get(row.id);
|
|
11099
|
+
if (v && !v.leaving)
|
|
11100
|
+
bind(v, row);
|
|
11101
|
+
}
|
|
11102
|
+
};
|
|
11103
|
+
const reveal = (id) => {
|
|
11104
|
+
const y = targets.get(id);
|
|
11105
|
+
if (y === undefined)
|
|
11106
|
+
return;
|
|
11107
|
+
const h = heights[rows.find((r) => r.id === id)?.depth ?? 0];
|
|
11108
|
+
const top = root.scrollTop;
|
|
11109
|
+
const view = root.clientHeight;
|
|
11110
|
+
if (view <= 0 || root.scrollHeight <= view)
|
|
11111
|
+
return;
|
|
11112
|
+
const behavior = reducedMotion(win) ? "auto" : "smooth";
|
|
11113
|
+
if (y - PAD < top)
|
|
11114
|
+
root.scrollTo({ top: y - PAD, behavior });
|
|
11115
|
+
else if (y + h + PAD > top + view)
|
|
11116
|
+
root.scrollTo({ top: y + h + PAD - view, behavior });
|
|
11117
|
+
};
|
|
11118
|
+
const choose = (id, source) => {
|
|
11119
|
+
if (source === "key") {
|
|
11120
|
+
const wasShowing = showing;
|
|
11121
|
+
setShowing("key");
|
|
11122
|
+
if (!wasShowing)
|
|
11123
|
+
moveHighlight(null);
|
|
11124
|
+
} else if (source === "pointer")
|
|
11125
|
+
setShowing("pointer");
|
|
11126
|
+
if (id === selected)
|
|
11127
|
+
return;
|
|
11128
|
+
const from = selected ? targets.get(selected) : undefined;
|
|
11129
|
+
selected = id;
|
|
11130
|
+
rebind();
|
|
11131
|
+
hl.hidden = !id;
|
|
11132
|
+
if (id) {
|
|
11133
|
+
const to = targets.get(id);
|
|
11134
|
+
const far = from !== undefined && to !== undefined && Math.abs(to - from) > 400;
|
|
11135
|
+
const reduced = reducedMotion(win);
|
|
11136
|
+
moveHighlight(reduced || from === undefined ? null : springMotion({ duration: far ? 0.42 : 0.3, bounce: 0 }));
|
|
11137
|
+
root.setAttribute("aria-activedescendant", domId(id));
|
|
11138
|
+
if (source === "key") {
|
|
11139
|
+
scrollHold = null;
|
|
11140
|
+
reveal(id);
|
|
11141
|
+
}
|
|
11142
|
+
const event = index.get(id)?.event;
|
|
11143
|
+
if (event && source !== "code")
|
|
11144
|
+
options.onSelect?.(id, event, source);
|
|
11145
|
+
} else
|
|
11146
|
+
root.removeAttribute("aria-activedescendant");
|
|
11147
|
+
loop.wake();
|
|
11148
|
+
};
|
|
11149
|
+
const toggle = (id, open) => {
|
|
11150
|
+
const row = rows.find((r) => r.id === id);
|
|
11151
|
+
if (!row?.group || row.expanded === open)
|
|
11152
|
+
return;
|
|
11153
|
+
if (open)
|
|
11154
|
+
expanded.add(id);
|
|
11155
|
+
else
|
|
11156
|
+
expanded.delete(id);
|
|
11157
|
+
sync(open ? "open" : "close", id);
|
|
11158
|
+
options.onToggle?.(id, open);
|
|
11159
|
+
};
|
|
11160
|
+
root.addEventListener("pointerdown", (e) => {
|
|
11161
|
+
if (e.button !== 0)
|
|
11162
|
+
return;
|
|
11163
|
+
setShowing("pointer");
|
|
11164
|
+
const el = e.target.closest(".knobs-activity-row");
|
|
11165
|
+
const id = el?.dataset.id;
|
|
11166
|
+
if (!el || !id || el.dataset.leaving !== undefined)
|
|
11167
|
+
return;
|
|
11168
|
+
e.preventDefault();
|
|
11169
|
+
root.focus({ preventScroll: true });
|
|
11170
|
+
if (e.target.closest(".knobs-activity-chip"))
|
|
11171
|
+
return;
|
|
11172
|
+
const row = rows.find((r) => r.id === id);
|
|
11173
|
+
choose(id, "pointer");
|
|
11174
|
+
if (row?.group)
|
|
11175
|
+
toggle(id, !row.expanded);
|
|
11176
|
+
});
|
|
11177
|
+
root.addEventListener("click", (e) => {
|
|
11178
|
+
const chip = e.target.closest(".knobs-activity-chip");
|
|
11179
|
+
const id = chip?.closest(".knobs-activity-row")?.dataset.id;
|
|
11180
|
+
const event = id ? index.get(id)?.event : undefined;
|
|
11181
|
+
if (chip && id && event && options.onPlay) {
|
|
11182
|
+
e.stopPropagation();
|
|
11183
|
+
options.onPlay(id, event);
|
|
11184
|
+
}
|
|
11185
|
+
});
|
|
11186
|
+
const release = () => {
|
|
11187
|
+
scrollHold = null;
|
|
11188
|
+
following = false;
|
|
11189
|
+
};
|
|
11190
|
+
root.addEventListener("wheel", release, { passive: true });
|
|
11191
|
+
root.addEventListener("touchstart", release, { passive: true });
|
|
11192
|
+
const onPointer = () => setShowing("pointer");
|
|
11193
|
+
if (keysFrom === "page")
|
|
11194
|
+
win.addEventListener("pointerdown", onPointer, true);
|
|
11195
|
+
const onKey = (e) => {
|
|
11196
|
+
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey)
|
|
11197
|
+
return;
|
|
11198
|
+
if (keysFrom === "page") {
|
|
11199
|
+
if (e.target !== root && (isTypingTarget(e.target) || !root.getClientRects().length))
|
|
11200
|
+
return;
|
|
11201
|
+
const t = e.target;
|
|
11202
|
+
if (t !== root && t?.closest?.(".knobs-panel,[role=tree],[role=listbox],[role=grid],[role=slider]"))
|
|
11203
|
+
return;
|
|
11204
|
+
}
|
|
11205
|
+
let handled = true;
|
|
11206
|
+
if (isActivityKey(e.key) && !e.shiftKey) {
|
|
11207
|
+
const r = navigateActivity(rows, selected, e.key);
|
|
11208
|
+
if (!takesActivityKey(e.key, r, rows.length))
|
|
11209
|
+
return;
|
|
11210
|
+
if (r.toggle) {
|
|
11211
|
+
setShowing("key");
|
|
11212
|
+
toggle(r.toggle.id, r.toggle.expanded);
|
|
11213
|
+
} else if (r.select)
|
|
11214
|
+
choose(r.select, "key");
|
|
11215
|
+
else
|
|
11216
|
+
setShowing("key");
|
|
11217
|
+
} else if (e.key === "Enter" && selected) {
|
|
11218
|
+
setShowing("key");
|
|
11219
|
+
const row = rows.find((r) => r.id === selected);
|
|
11220
|
+
const event = index.get(selected)?.event;
|
|
11221
|
+
if (options.onActivate && event)
|
|
11222
|
+
options.onActivate(selected, event);
|
|
11223
|
+
else if (row?.group)
|
|
11224
|
+
toggle(row.id, !row.expanded);
|
|
11225
|
+
else
|
|
11226
|
+
handled = false;
|
|
11227
|
+
} else
|
|
11228
|
+
handled = false;
|
|
11229
|
+
if (handled) {
|
|
11230
|
+
e.preventDefault();
|
|
11231
|
+
e.stopPropagation();
|
|
11232
|
+
}
|
|
11233
|
+
};
|
|
11234
|
+
if (keysFrom === "page")
|
|
11235
|
+
win.addEventListener("keydown", onKey);
|
|
11236
|
+
else
|
|
11237
|
+
root.addEventListener("keydown", onKey);
|
|
11238
|
+
root.addEventListener("blur", () => setShowing("blur"));
|
|
11239
|
+
const remeasure = () => {
|
|
11240
|
+
const was = heights.join();
|
|
11241
|
+
measure();
|
|
11242
|
+
if (heights.join() !== was)
|
|
11243
|
+
sync("snap");
|
|
11244
|
+
};
|
|
11245
|
+
const ro = new ResizeObserver(remeasure);
|
|
11246
|
+
ro.observe(root);
|
|
11247
|
+
root.addEventListener("knobs-restyle", () => {
|
|
11248
|
+
measure();
|
|
11249
|
+
sync("snap");
|
|
11250
|
+
});
|
|
11251
|
+
sync("snap");
|
|
11252
|
+
const handle = {
|
|
11253
|
+
element: root,
|
|
11254
|
+
set(next) {
|
|
11255
|
+
handle.update({ events: next });
|
|
11256
|
+
},
|
|
11257
|
+
add(event) {
|
|
11258
|
+
handle.set(newest === "bottom" ? [...events, event] : [event, ...events]);
|
|
11259
|
+
},
|
|
11260
|
+
update(next) {
|
|
11261
|
+
if (next.newest)
|
|
11262
|
+
newest = next.newest;
|
|
11263
|
+
if (next.events) {
|
|
11264
|
+
events = next.events;
|
|
11265
|
+
index = indexActivity(events);
|
|
11266
|
+
for (const id of [...expanded])
|
|
11267
|
+
if (!index.has(id))
|
|
11268
|
+
expanded.delete(id);
|
|
11269
|
+
}
|
|
11270
|
+
sync("set");
|
|
11271
|
+
},
|
|
11272
|
+
select(id) {
|
|
11273
|
+
if (id !== null) {
|
|
11274
|
+
const parent = index.get(id)?.parent;
|
|
11275
|
+
if (parent && !expanded.has(parent)) {
|
|
11276
|
+
expanded.add(parent);
|
|
11277
|
+
sync("open", parent);
|
|
11278
|
+
}
|
|
11279
|
+
}
|
|
11280
|
+
choose(id, "code");
|
|
11281
|
+
},
|
|
11282
|
+
get selected() {
|
|
11283
|
+
return selected;
|
|
11284
|
+
},
|
|
11285
|
+
expand: (id, open = !expanded.has(id)) => toggle(id, open),
|
|
11286
|
+
isExpanded: (id) => expanded.has(id),
|
|
11287
|
+
focus: () => root.focus({ preventScroll: true }),
|
|
11288
|
+
destroy() {
|
|
11289
|
+
loop.stop();
|
|
11290
|
+
ro.disconnect();
|
|
11291
|
+
scrollbar.dispose();
|
|
11292
|
+
if (keysFrom === "page") {
|
|
11293
|
+
win.removeEventListener("keydown", onKey);
|
|
11294
|
+
win.removeEventListener("pointerdown", onPointer, true);
|
|
11295
|
+
}
|
|
11296
|
+
for (const v of [...views.values()])
|
|
11297
|
+
dropView(v);
|
|
11298
|
+
root.remove();
|
|
11299
|
+
},
|
|
11300
|
+
dispose: () => handle.destroy()
|
|
11301
|
+
};
|
|
11302
|
+
return handle;
|
|
11303
|
+
}
|
|
11304
|
+
// src/ui/picker-model.ts
|
|
11305
|
+
function digitPick(ids, key) {
|
|
11306
|
+
if (!/^[1-9]$/.test(key))
|
|
11307
|
+
return;
|
|
11308
|
+
return ids[Number(key) - 1];
|
|
11309
|
+
}
|
|
11310
|
+
function stepPick(ids, current, key) {
|
|
11311
|
+
if (!ids.length)
|
|
11312
|
+
return;
|
|
11313
|
+
if (key === "Home")
|
|
11314
|
+
return ids[0];
|
|
11315
|
+
if (key === "End")
|
|
11316
|
+
return ids[ids.length - 1];
|
|
11317
|
+
const i = current === null ? -1 : ids.indexOf(current);
|
|
11318
|
+
if (i < 0)
|
|
11319
|
+
return key === "ArrowDown" ? ids[0] : ids[ids.length - 1];
|
|
11320
|
+
return ids[Math.max(0, Math.min(ids.length - 1, i + (key === "ArrowDown" ? 1 : -1)))];
|
|
11321
|
+
}
|
|
11322
|
+
function keepPick(ids, selected, wanted = null) {
|
|
11323
|
+
if (wanted !== null && ids.includes(wanted))
|
|
11324
|
+
return wanted;
|
|
11325
|
+
if (selected !== null && ids.includes(selected))
|
|
11326
|
+
return selected;
|
|
11327
|
+
return ids[0] ?? null;
|
|
11328
|
+
}
|
|
11329
|
+
function askPick(ids, id) {
|
|
11330
|
+
return ids.includes(id) ? { pick: id, wanted: null } : { pick: undefined, wanted: id };
|
|
11331
|
+
}
|
|
11332
|
+
var stillWanted = (ids, wanted) => wanted !== null && ids.includes(wanted) ? null : wanted;
|
|
11333
|
+
var pickDigit = (index) => String(index + 1);
|
|
11334
|
+
function claimsDigit(event, typing = false) {
|
|
11335
|
+
return /^[1-9]$/.test(event.key) && !event.defaultPrevented && !event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.repeat && !event.typing && !typing;
|
|
11336
|
+
}
|
|
11337
|
+
function cardTarget(heads, index, body, gap = 0, top = 0) {
|
|
11338
|
+
if (body === undefined)
|
|
11339
|
+
return null;
|
|
11340
|
+
let y = top;
|
|
11341
|
+
for (let i = 0;i < index; i++)
|
|
11342
|
+
y += heads[i] + gap;
|
|
11343
|
+
return { y, h: (heads[index] ?? 0) + body };
|
|
11344
|
+
}
|
|
11345
|
+
function settleHeight(previous, now, frames, limit = 6) {
|
|
11346
|
+
if (previous !== undefined && Math.abs(now - previous) < 0.5)
|
|
11347
|
+
return now;
|
|
11348
|
+
return frames >= limit ? now : undefined;
|
|
11349
|
+
}
|
|
11350
|
+
|
|
11351
|
+
// src/ui/picker.ts
|
|
11352
|
+
var OPEN2 = springMotion({ duration: 0.22, bounce: 0 });
|
|
11353
|
+
var CLOSE2 = springMotion({ duration: 0.18, bounce: 0 });
|
|
11354
|
+
var CARD = springMotion({ duration: 0.3, bounce: 0 });
|
|
11355
|
+
var FADE3 = springMotion({ duration: 0.16, bounce: 0 });
|
|
11356
|
+
var DRIFT = 6;
|
|
11357
|
+
var CHECK2 = svg('<path d="m3.5 8.4 3 3 6-6.6"/>');
|
|
11358
|
+
function optionPicker(container, options) {
|
|
11359
|
+
const doc = container.ownerDocument;
|
|
11360
|
+
const win = doc.defaultView;
|
|
11361
|
+
let list = options.options;
|
|
11362
|
+
let wanted = null;
|
|
11363
|
+
let selected = null;
|
|
11364
|
+
{
|
|
11365
|
+
const ids = list.map((o) => o.id);
|
|
11366
|
+
if (options.selected != null)
|
|
11367
|
+
wanted = askPick(ids, options.selected).wanted;
|
|
11368
|
+
selected = keepPick(ids, options.selected ?? null);
|
|
11369
|
+
}
|
|
11370
|
+
let chosen = options.chosen ?? null;
|
|
11371
|
+
const digits = options.digits ?? "focus";
|
|
11372
|
+
const root = doc.createElement("div");
|
|
11373
|
+
root.className = "knobs-picker";
|
|
11374
|
+
root.setAttribute("role", "radiogroup");
|
|
11375
|
+
if (options.label)
|
|
11376
|
+
root.setAttribute("aria-label", options.label);
|
|
11377
|
+
applyLook(root, options);
|
|
11378
|
+
const card = doc.createElement("div");
|
|
11379
|
+
card.className = "knobs-picker-card";
|
|
11380
|
+
card.setAttribute("aria-hidden", "true");
|
|
11381
|
+
root.append(card);
|
|
11382
|
+
container.append(root);
|
|
11383
|
+
const entries = new Map;
|
|
11384
|
+
const uid = `kp${Math.random().toString(36).slice(2, 7)}`;
|
|
11385
|
+
let serial = 0;
|
|
11386
|
+
const make = (option) => {
|
|
11387
|
+
const el = doc.createElement("div");
|
|
11388
|
+
el.className = "knobs-picker-option";
|
|
11389
|
+
el.dataset.id = option.id;
|
|
11390
|
+
const head = doc.createElement("button");
|
|
11391
|
+
head.type = "button";
|
|
11392
|
+
head.className = "knobs-picker-head";
|
|
11393
|
+
head.setAttribute("role", "radio");
|
|
11394
|
+
head.id = `${uid}-${serial++}`;
|
|
11395
|
+
const key = doc.createElement("span");
|
|
11396
|
+
key.className = "knobs-picker-key";
|
|
11397
|
+
key.setAttribute("aria-hidden", "true");
|
|
11398
|
+
const name = doc.createElement("span");
|
|
11399
|
+
name.className = "knobs-picker-name knobs-scroll-fade-x";
|
|
11400
|
+
const suggested = doc.createElement("span");
|
|
11401
|
+
suggested.className = "knobs-picker-suggested";
|
|
11402
|
+
const check = doc.createElement("span");
|
|
11403
|
+
check.className = "knobs-picker-check";
|
|
11404
|
+
check.innerHTML = CHECK2;
|
|
11405
|
+
check.setAttribute("aria-hidden", "true");
|
|
11406
|
+
head.append(key, name, suggested, check);
|
|
11407
|
+
const body = doc.createElement("div");
|
|
11408
|
+
body.className = "knobs-picker-body";
|
|
11409
|
+
body.hidden = true;
|
|
11410
|
+
body.setAttribute("role", "group");
|
|
11411
|
+
body.setAttribute("aria-labelledby", head.id);
|
|
11412
|
+
const inner = doc.createElement("div");
|
|
11413
|
+
inner.className = "knobs-picker-inner";
|
|
11414
|
+
body.append(inner);
|
|
11415
|
+
el.append(head, body);
|
|
11416
|
+
const entry = {
|
|
11417
|
+
option,
|
|
11418
|
+
el,
|
|
11419
|
+
head,
|
|
11420
|
+
key,
|
|
11421
|
+
thumb: undefined,
|
|
11422
|
+
name,
|
|
11423
|
+
suggested,
|
|
11424
|
+
body,
|
|
11425
|
+
inner,
|
|
11426
|
+
mounted: false,
|
|
11427
|
+
measured: true,
|
|
11428
|
+
cleanup: undefined,
|
|
11429
|
+
h: new Spring(0, OPEN2.omega, OPEN2.zeta, 0.05),
|
|
11430
|
+
o: new Spring(0, OPEN2.omega, OPEN2.zeta, 0.002),
|
|
11431
|
+
moving: false,
|
|
11432
|
+
open: false,
|
|
11433
|
+
presence: new Spring(1, OPEN2.omega, OPEN2.zeta, 0.002),
|
|
11434
|
+
leaving: false
|
|
11435
|
+
};
|
|
11436
|
+
entries.set(option.id, entry);
|
|
11437
|
+
return entry;
|
|
11438
|
+
};
|
|
11439
|
+
const setThumb = (e, url) => {
|
|
11440
|
+
if ((e.thumb?.getAttribute("src") ?? undefined) === (url || undefined))
|
|
11441
|
+
return;
|
|
11442
|
+
if (!url) {
|
|
11443
|
+
e.thumb?.remove();
|
|
11444
|
+
e.thumb = undefined;
|
|
11445
|
+
return;
|
|
11446
|
+
}
|
|
11447
|
+
let img = e.thumb;
|
|
11448
|
+
if (!img) {
|
|
11449
|
+
const el = doc.createElement("img");
|
|
11450
|
+
el.className = "knobs-picker-thumb";
|
|
11451
|
+
el.alt = "";
|
|
11452
|
+
el.loading = "lazy";
|
|
11453
|
+
el.decoding = "async";
|
|
11454
|
+
el.draggable = false;
|
|
11455
|
+
el.addEventListener("load", () => el.dataset.state = "loaded");
|
|
11456
|
+
el.addEventListener("error", () => el.dataset.state = "failed");
|
|
11457
|
+
e.key.after(el);
|
|
11458
|
+
e.thumb = img = el;
|
|
11459
|
+
}
|
|
11460
|
+
const shown = img;
|
|
11461
|
+
shown.dataset.state = "loading";
|
|
11462
|
+
shown.src = url;
|
|
11463
|
+
if (shown.complete && shown.naturalWidth > 0) {
|
|
11464
|
+
shown.dataset.state = "loaded";
|
|
11465
|
+
shown.dataset.instant = "";
|
|
11466
|
+
win.requestAnimationFrame(() => delete shown.dataset.instant);
|
|
11467
|
+
}
|
|
11468
|
+
};
|
|
11469
|
+
const bind = (e, i) => {
|
|
11470
|
+
e.option = list[i];
|
|
11471
|
+
e.key.textContent = pickDigit(i);
|
|
11472
|
+
setThumb(e, e.option.thumb);
|
|
11473
|
+
if (e.name.textContent !== e.option.label)
|
|
11474
|
+
e.name.textContent = e.option.label;
|
|
11475
|
+
e.suggested.textContent = e.option.suggested ? options.suggestedLabel ?? "Suggested" : "";
|
|
11476
|
+
e.suggested.hidden = !e.option.suggested;
|
|
11477
|
+
const on = e.option.id === selected;
|
|
11478
|
+
e.el.toggleAttribute("data-selected", on);
|
|
11479
|
+
e.head.setAttribute("aria-checked", String(on));
|
|
11480
|
+
e.head.tabIndex = on ? 0 : -1;
|
|
11481
|
+
e.el.toggleAttribute("data-chosen", e.option.id === chosen);
|
|
11482
|
+
e.head.setAttribute("aria-label", [
|
|
11483
|
+
e.option.label,
|
|
11484
|
+
e.option.suggested ? options.suggestedLabel ?? "Suggested" : "",
|
|
11485
|
+
e.option.id === chosen ? "chosen" : ""
|
|
11486
|
+
].filter(Boolean).join(", "));
|
|
11487
|
+
};
|
|
11488
|
+
const mount = (e) => {
|
|
11489
|
+
if (e.mounted || !options.body)
|
|
11490
|
+
return;
|
|
11491
|
+
e.mounted = true;
|
|
11492
|
+
const out = options.body(e.option, e.inner);
|
|
11493
|
+
if (typeof out === "function")
|
|
11494
|
+
e.cleanup = out;
|
|
11495
|
+
};
|
|
11496
|
+
const cardY = new Spring(0, CARD.omega, CARD.zeta, 0.05);
|
|
11497
|
+
const cardH = new Spring(0, CARD.omega, CARD.zeta, 0.05);
|
|
11498
|
+
let gliding = false;
|
|
11499
|
+
const liveCard = () => {
|
|
11500
|
+
const e = selected ? entries.get(selected) : undefined;
|
|
11501
|
+
return e && !e.leaving ? { y: e.el.offsetTop, h: e.el.offsetHeight } : null;
|
|
11502
|
+
};
|
|
11503
|
+
const finalCard = () => {
|
|
11504
|
+
const live = list.map((o) => entries.get(o.id)).filter((e) => !!e && !e.leaving);
|
|
11505
|
+
const index = live.findIndex((e) => e.option.id === selected);
|
|
11506
|
+
if (index < 0)
|
|
11507
|
+
return null;
|
|
11508
|
+
const gap = parseFloat(win.getComputedStyle(root).rowGap) || 0;
|
|
11509
|
+
const e = live[index];
|
|
11510
|
+
return cardTarget(live.map((x) => x.head.offsetHeight), index, e.measured ? natural(e) : undefined, gap);
|
|
11511
|
+
};
|
|
11512
|
+
const placeCard = () => {
|
|
11513
|
+
card.style.transform = `translate3d(0,${Math.round(cardY.x * 2) / 2}px,0)`;
|
|
11514
|
+
card.style.height = `${Math.max(0, cardH.x).toFixed(2)}px`;
|
|
11515
|
+
card.hidden = cardH.x < 0.5;
|
|
11516
|
+
};
|
|
11517
|
+
const natural = (e) => e.inner.offsetHeight;
|
|
11518
|
+
const setOpen = (e, open, animate) => {
|
|
11519
|
+
if (e.open === open && (e.moving || e.body.hidden === !open))
|
|
11520
|
+
return;
|
|
11521
|
+
e.open = open;
|
|
11522
|
+
const reduced = reducedMotion(win);
|
|
11523
|
+
if (open && !e.mounted) {
|
|
11524
|
+
if (animate && e.body.hidden) {
|
|
11525
|
+
e.body.hidden = false;
|
|
11526
|
+
e.body.style.height = "0px";
|
|
11527
|
+
e.body.dataset.moving = "";
|
|
11528
|
+
e.h.snap(0);
|
|
11529
|
+
e.o.snap(0);
|
|
11530
|
+
e.moving = true;
|
|
11531
|
+
}
|
|
11532
|
+
mount(e);
|
|
11533
|
+
}
|
|
11534
|
+
if (!animate) {
|
|
11535
|
+
e.body.hidden = !open;
|
|
11536
|
+
e.moving = false;
|
|
11537
|
+
e.body.style.height = "";
|
|
11538
|
+
delete e.body.dataset.moving;
|
|
11539
|
+
e.inner.style.opacity = "";
|
|
11540
|
+
e.inner.style.transform = "";
|
|
11541
|
+
return;
|
|
11542
|
+
}
|
|
11543
|
+
if (!e.moving) {
|
|
11544
|
+
const from = e.body.hidden ? 0 : e.body.offsetHeight;
|
|
11545
|
+
e.h.snap(from);
|
|
11546
|
+
e.o.snap(from > 0.5 ? 1 : 0);
|
|
11547
|
+
}
|
|
11548
|
+
e.body.hidden = false;
|
|
11549
|
+
e.moving = true;
|
|
11550
|
+
e.body.dataset.moving = "";
|
|
11551
|
+
if (reduced) {
|
|
11552
|
+
e.h.snap(open ? natural(e) : 0);
|
|
11553
|
+
tune(e.o, FADE3).set(open ? 1 : 0);
|
|
11554
|
+
} else {
|
|
11555
|
+
tune(e.h, open ? OPEN2 : CLOSE2).set(open ? natural(e) : 0);
|
|
11556
|
+
tune(e.o, open ? OPEN2 : CLOSE2).set(open ? 1 : 0);
|
|
11557
|
+
}
|
|
11558
|
+
loop.wake();
|
|
11559
|
+
};
|
|
11560
|
+
let pending = null;
|
|
11561
|
+
const premount = (e) => {
|
|
11562
|
+
e.body.hidden = false;
|
|
11563
|
+
e.body.style.height = "0px";
|
|
11564
|
+
e.body.dataset.moving = "";
|
|
11565
|
+
e.inner.style.opacity = "0";
|
|
11566
|
+
e.measured = false;
|
|
11567
|
+
mount(e);
|
|
11568
|
+
};
|
|
11569
|
+
const shelve = (e) => {
|
|
11570
|
+
if (e.open || e.moving)
|
|
11571
|
+
return;
|
|
11572
|
+
e.body.hidden = true;
|
|
11573
|
+
e.body.style.height = "";
|
|
11574
|
+
delete e.body.dataset.moving;
|
|
11575
|
+
e.inner.style.opacity = "";
|
|
11576
|
+
e.measured = true;
|
|
11577
|
+
};
|
|
11578
|
+
const start = (was, now, animate) => {
|
|
11579
|
+
now.measured = true;
|
|
11580
|
+
if (was && was !== now)
|
|
11581
|
+
setOpen(was, false, animate);
|
|
11582
|
+
setOpen(now, true, animate);
|
|
11583
|
+
if (animate && !reducedMotion(win)) {
|
|
11584
|
+
tune(cardY, CARD);
|
|
11585
|
+
tune(cardH, CARD);
|
|
11586
|
+
gliding = true;
|
|
11587
|
+
}
|
|
11588
|
+
loop.wake();
|
|
11589
|
+
};
|
|
11590
|
+
const flush = () => {
|
|
11591
|
+
const p = pending;
|
|
11592
|
+
if (!p)
|
|
11593
|
+
return;
|
|
11594
|
+
pending = null;
|
|
11595
|
+
start(p.was, p.now, true);
|
|
11596
|
+
};
|
|
11597
|
+
const loop = frameLoop(win, (dt) => {
|
|
11598
|
+
let moving = false;
|
|
11599
|
+
if (pending) {
|
|
11600
|
+
const p = pending;
|
|
11601
|
+
const h = natural(p.now);
|
|
11602
|
+
p.frames++;
|
|
11603
|
+
if (settleHeight(p.last, h, p.frames) !== undefined)
|
|
11604
|
+
flush();
|
|
11605
|
+
else {
|
|
11606
|
+
p.last = h;
|
|
11607
|
+
moving = true;
|
|
11608
|
+
}
|
|
11609
|
+
}
|
|
11610
|
+
for (const e of [...entries.values()]) {
|
|
11611
|
+
if (e.moving) {
|
|
11612
|
+
if (e.open && !reducedMotion(win))
|
|
11613
|
+
e.h.set(natural(e));
|
|
11614
|
+
e.h.step(dt);
|
|
11615
|
+
e.o.step(dt);
|
|
11616
|
+
const fade = Math.max(0, Math.min(1, e.o.x));
|
|
11617
|
+
e.body.style.height = `${Math.max(0, e.h.x).toFixed(2)}px`;
|
|
11618
|
+
const shown = e.open ? fade : Math.max(0, (fade - 0.4) / 0.6);
|
|
11619
|
+
e.inner.style.opacity = shown < 0.999 ? shown.toFixed(3) : "";
|
|
11620
|
+
const drift = reducedMotion(win) ? 0 : (1 - fade) * -DRIFT;
|
|
11621
|
+
e.inner.style.transform = Math.abs(drift) > 0.05 ? `translateY(${drift.toFixed(2)}px)` : "";
|
|
11622
|
+
if (e.h.resting && e.o.resting) {
|
|
11623
|
+
e.moving = false;
|
|
11624
|
+
delete e.body.dataset.moving;
|
|
11625
|
+
e.body.style.height = "";
|
|
11626
|
+
e.inner.style.opacity = "";
|
|
11627
|
+
e.inner.style.transform = "";
|
|
11628
|
+
e.body.hidden = !e.open;
|
|
11629
|
+
} else
|
|
11630
|
+
moving = true;
|
|
11631
|
+
}
|
|
11632
|
+
if (e.leaving || !e.presence.resting) {
|
|
11633
|
+
e.presence.step(dt);
|
|
11634
|
+
const p = Math.max(0, Math.min(1, e.presence.x));
|
|
11635
|
+
e.el.style.opacity = p < 0.999 ? p.toFixed(3) : "";
|
|
11636
|
+
e.el.style.height = p < 0.999 ? `${(p * e.head.offsetHeight).toFixed(2)}px` : "";
|
|
11637
|
+
e.el.style.overflow = p < 0.999 ? "hidden" : "";
|
|
11638
|
+
if (e.presence.resting) {
|
|
11639
|
+
if (e.leaving) {
|
|
11640
|
+
e.cleanup?.();
|
|
11641
|
+
e.el.remove();
|
|
11642
|
+
entries.delete(e.option.id);
|
|
11643
|
+
}
|
|
11644
|
+
} else
|
|
11645
|
+
moving = true;
|
|
11646
|
+
}
|
|
11647
|
+
}
|
|
11648
|
+
const t = pending ? null : gliding ? finalCard() : liveCard();
|
|
11649
|
+
if (t) {
|
|
11650
|
+
if (gliding) {
|
|
11651
|
+
cardY.set(t.y);
|
|
11652
|
+
cardH.set(t.h);
|
|
11653
|
+
cardY.step(dt);
|
|
11654
|
+
cardH.step(dt);
|
|
11655
|
+
if (cardY.resting && cardH.resting && !moving)
|
|
11656
|
+
gliding = false;
|
|
11657
|
+
else
|
|
11658
|
+
moving = true;
|
|
11659
|
+
} else {
|
|
11660
|
+
cardY.snap(t.y);
|
|
11661
|
+
cardH.snap(t.h);
|
|
11662
|
+
}
|
|
11663
|
+
}
|
|
11664
|
+
placeCard();
|
|
11665
|
+
notifyLayout(doc);
|
|
11666
|
+
return moving;
|
|
11667
|
+
});
|
|
11668
|
+
const rebind = () => {
|
|
11669
|
+
list.forEach((o, i) => {
|
|
11670
|
+
const e = entries.get(o.id);
|
|
11671
|
+
if (e)
|
|
11672
|
+
bind(e, i);
|
|
11673
|
+
});
|
|
11674
|
+
};
|
|
11675
|
+
const pick = (id, animate = true) => {
|
|
11676
|
+
if (id === selected || !entries.has(id))
|
|
11677
|
+
return;
|
|
11678
|
+
let was = selected ? entries.get(selected) : undefined;
|
|
11679
|
+
if (pending) {
|
|
11680
|
+
was = pending.was;
|
|
11681
|
+
const waiting = pending.now;
|
|
11682
|
+
pending = null;
|
|
11683
|
+
if (waiting.option.id !== id)
|
|
11684
|
+
shelve(waiting);
|
|
11685
|
+
}
|
|
11686
|
+
selected = id;
|
|
11687
|
+
rebind();
|
|
11688
|
+
const now = entries.get(id);
|
|
11689
|
+
if (animate && !reducedMotion(win) && !now.mounted && options.body) {
|
|
11690
|
+
premount(now);
|
|
11691
|
+
pending = { was, now, last: natural(now), frames: 0 };
|
|
11692
|
+
loop.wake();
|
|
11693
|
+
return;
|
|
11694
|
+
}
|
|
11695
|
+
start(was, now, animate);
|
|
11696
|
+
};
|
|
11697
|
+
const select = (id, source) => {
|
|
11698
|
+
if (!id)
|
|
11699
|
+
return;
|
|
11700
|
+
wanted = null;
|
|
11701
|
+
if (id === selected)
|
|
11702
|
+
return;
|
|
11703
|
+
const inside = root.contains(doc.activeElement);
|
|
11704
|
+
pick(id);
|
|
11705
|
+
if (source !== "pointer" && inside)
|
|
11706
|
+
entries.get(id)?.head.focus({ preventScroll: true });
|
|
11707
|
+
options.onSelect?.(id, source);
|
|
11708
|
+
};
|
|
11709
|
+
const sync = (animate) => {
|
|
11710
|
+
flush();
|
|
11711
|
+
const ids = list.map((o) => o.id);
|
|
11712
|
+
const was = selected;
|
|
11713
|
+
selected = keepPick(ids, selected, wanted);
|
|
11714
|
+
wanted = stillWanted(ids, wanted);
|
|
11715
|
+
if (animate && was !== selected && !reducedMotion(win))
|
|
11716
|
+
gliding = true;
|
|
11717
|
+
const reduced = reducedMotion(win);
|
|
11718
|
+
const live = new Set(ids);
|
|
11719
|
+
for (const e of entries.values()) {
|
|
11720
|
+
if (live.has(e.option.id) || e.leaving)
|
|
11721
|
+
continue;
|
|
11722
|
+
if (!animate) {
|
|
11723
|
+
e.cleanup?.();
|
|
11724
|
+
e.el.remove();
|
|
11725
|
+
entries.delete(e.option.id);
|
|
11726
|
+
continue;
|
|
11727
|
+
}
|
|
11728
|
+
e.leaving = true;
|
|
11729
|
+
e.el.setAttribute("aria-hidden", "true");
|
|
11730
|
+
e.head.tabIndex = -1;
|
|
11731
|
+
if (e.open)
|
|
11732
|
+
setOpen(e, false, true);
|
|
11733
|
+
tune(e.presence, reduced ? FADE3 : CLOSE2).set(0);
|
|
11734
|
+
}
|
|
11735
|
+
let before = card;
|
|
11736
|
+
list.forEach((o, i) => {
|
|
11737
|
+
let e = entries.get(o.id);
|
|
11738
|
+
if (e?.leaving) {
|
|
11739
|
+
e.leaving = false;
|
|
11740
|
+
e.el.removeAttribute("aria-hidden");
|
|
11741
|
+
tune(e.presence, OPEN2).set(1);
|
|
11742
|
+
}
|
|
11743
|
+
if (!e) {
|
|
11744
|
+
e = make(o);
|
|
11745
|
+
ro.observe(e.el);
|
|
11746
|
+
if (animate)
|
|
11747
|
+
tune(e.presence, reduced ? FADE3 : OPEN2).snap(0).set(1);
|
|
11748
|
+
}
|
|
11749
|
+
if (before.nextElementSibling !== e.el)
|
|
11750
|
+
before.after(e.el);
|
|
11751
|
+
before = e.el;
|
|
11752
|
+
bind(e, i);
|
|
11753
|
+
});
|
|
11754
|
+
const open = selected ? entries.get(selected) : undefined;
|
|
11755
|
+
const ahead = animate && !reduced && open && !open.open && !open.mounted && !!options.body ? { was: was ? entries.get(was) : undefined, now: open } : null;
|
|
11756
|
+
for (const e of entries.values())
|
|
11757
|
+
if (e !== open && e !== ahead?.was && e.open && !e.leaving)
|
|
11758
|
+
setOpen(e, false, animate);
|
|
11759
|
+
if (ahead) {
|
|
11760
|
+
premount(ahead.now);
|
|
11761
|
+
pending = { ...ahead, last: natural(ahead.now), frames: 0 };
|
|
11762
|
+
} else if (open && !open.open)
|
|
11763
|
+
setOpen(open, true, animate);
|
|
11764
|
+
loop.wake();
|
|
11765
|
+
};
|
|
11766
|
+
const ids = () => list.map((o) => o.id).filter((id) => !entries.get(id)?.leaving);
|
|
11767
|
+
const onDigit = (e) => {
|
|
11768
|
+
if (!claimsDigit(e, isTypingTarget(e.target)))
|
|
11769
|
+
return;
|
|
11770
|
+
if (!root.getClientRects().length)
|
|
11771
|
+
return;
|
|
11772
|
+
const id = digitPick(ids(), e.key);
|
|
11773
|
+
if (!id)
|
|
11774
|
+
return;
|
|
11775
|
+
e.preventDefault();
|
|
11776
|
+
select(id, "digit");
|
|
11777
|
+
};
|
|
11778
|
+
root.addEventListener("keydown", (e) => {
|
|
11779
|
+
const head = e.target.closest?.(".knobs-picker-head");
|
|
11780
|
+
if (head && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
11781
|
+
if (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Home" || e.key === "End") {
|
|
11782
|
+
e.preventDefault();
|
|
11783
|
+
select(stepPick(ids(), selected, e.key), "key");
|
|
11784
|
+
return;
|
|
11785
|
+
}
|
|
11786
|
+
if (e.key === "Enter" && selected) {
|
|
11787
|
+
e.preventDefault();
|
|
11788
|
+
options.onChoose?.(selected);
|
|
11789
|
+
return;
|
|
11790
|
+
}
|
|
11791
|
+
}
|
|
11792
|
+
if (digits === "focus")
|
|
11793
|
+
onDigit(e);
|
|
11794
|
+
});
|
|
11795
|
+
if (digits === "page")
|
|
11796
|
+
win.addEventListener("keydown", onDigit);
|
|
11797
|
+
root.addEventListener("click", (e) => {
|
|
11798
|
+
const el = e.target.closest(".knobs-picker-head");
|
|
11799
|
+
const id = el?.closest(".knobs-picker-option")?.dataset.id;
|
|
11800
|
+
if (!id || entries.get(id)?.leaving)
|
|
11801
|
+
return;
|
|
11802
|
+
select(id, e.detail === 0 ? "key" : "pointer");
|
|
11803
|
+
});
|
|
11804
|
+
const ro = new ResizeObserver(() => loop.wake());
|
|
11805
|
+
ro.observe(root);
|
|
11806
|
+
root.addEventListener("knobs-restyle", () => {
|
|
11807
|
+
syncFrame(root);
|
|
11808
|
+
loop.wake();
|
|
11809
|
+
});
|
|
11810
|
+
sync(false);
|
|
11811
|
+
const first = liveCard();
|
|
11812
|
+
if (first) {
|
|
11813
|
+
cardY.snap(first.y);
|
|
11814
|
+
cardH.snap(first.h);
|
|
11815
|
+
}
|
|
11816
|
+
placeCard();
|
|
11817
|
+
loop.wake();
|
|
11818
|
+
const handle = {
|
|
11819
|
+
element: root,
|
|
11820
|
+
set(next) {
|
|
11821
|
+
list = next;
|
|
11822
|
+
sync(true);
|
|
11823
|
+
},
|
|
11824
|
+
select(id) {
|
|
11825
|
+
const ask = askPick(ids(), id);
|
|
11826
|
+
wanted = ask.wanted;
|
|
11827
|
+
if (ask.pick)
|
|
11828
|
+
pick(ask.pick);
|
|
11829
|
+
},
|
|
11830
|
+
get selected() {
|
|
11831
|
+
return selected;
|
|
11832
|
+
},
|
|
11833
|
+
choose(id) {
|
|
11834
|
+
chosen = id;
|
|
11835
|
+
rebind();
|
|
11836
|
+
},
|
|
11837
|
+
get chosen() {
|
|
11838
|
+
return chosen;
|
|
11839
|
+
},
|
|
11840
|
+
focus() {
|
|
11841
|
+
(selected ? entries.get(selected)?.head : undefined)?.focus({ preventScroll: true });
|
|
11842
|
+
},
|
|
11843
|
+
destroy() {
|
|
11844
|
+
loop.stop();
|
|
11845
|
+
ro.disconnect();
|
|
11846
|
+
if (digits === "page")
|
|
11847
|
+
win.removeEventListener("keydown", onDigit);
|
|
11848
|
+
for (const e of entries.values())
|
|
11849
|
+
e.cleanup?.();
|
|
11850
|
+
entries.clear();
|
|
11851
|
+
root.remove();
|
|
11852
|
+
},
|
|
11853
|
+
dispose: () => handle.destroy()
|
|
11854
|
+
};
|
|
11855
|
+
return handle;
|
|
11856
|
+
}
|
|
9173
11857
|
export {
|
|
9174
11858
|
COLLAPSE_PAST,
|
|
9175
11859
|
FIT_MAX,
|
|
11860
|
+
activity,
|
|
9176
11861
|
adjacentMarker,
|
|
9177
11862
|
advance,
|
|
9178
11863
|
applyMove,
|
|
@@ -9180,22 +11865,30 @@ export {
|
|
|
9180
11865
|
bento,
|
|
9181
11866
|
neighbour as bentoNeighbour,
|
|
9182
11867
|
windowOf as bentoWindow,
|
|
11868
|
+
claimsDigit,
|
|
9183
11869
|
clampView,
|
|
9184
11870
|
commandPalette,
|
|
9185
11871
|
commandsFrom,
|
|
9186
11872
|
confirm,
|
|
9187
11873
|
contextMenu,
|
|
11874
|
+
diffActivity,
|
|
11875
|
+
digitPick,
|
|
9188
11876
|
drag as dragDivider,
|
|
9189
11877
|
dropTarget,
|
|
9190
11878
|
fitRect,
|
|
9191
11879
|
flatten,
|
|
11880
|
+
flattenActivity,
|
|
9192
11881
|
followView,
|
|
11882
|
+
formatDuration,
|
|
9193
11883
|
frameTime,
|
|
9194
11884
|
fuzzy,
|
|
9195
11885
|
hints,
|
|
9196
11886
|
inTriangle,
|
|
11887
|
+
indexActivity,
|
|
9197
11888
|
indexTree,
|
|
9198
11889
|
injectUiStyles,
|
|
11890
|
+
keepSelection as keepActivitySelection,
|
|
11891
|
+
keepPick,
|
|
9199
11892
|
magnet,
|
|
9200
11893
|
marks,
|
|
9201
11894
|
matchItem,
|
|
@@ -9203,6 +11896,8 @@ export {
|
|
|
9203
11896
|
menu,
|
|
9204
11897
|
motionBlur,
|
|
9205
11898
|
navigate,
|
|
11899
|
+
navigateActivity,
|
|
11900
|
+
optionPicker,
|
|
9206
11901
|
overlayLook,
|
|
9207
11902
|
pageHints,
|
|
9208
11903
|
parseLayout,
|
|
@@ -9210,6 +11905,7 @@ export {
|
|
|
9210
11905
|
plainAccess,
|
|
9211
11906
|
planBento,
|
|
9212
11907
|
popover,
|
|
11908
|
+
railSegments,
|
|
9213
11909
|
rank,
|
|
9214
11910
|
readout,
|
|
9215
11911
|
restyle,
|
|
@@ -9218,11 +11914,14 @@ export {
|
|
|
9218
11914
|
safeTriangle,
|
|
9219
11915
|
scrubTime,
|
|
9220
11916
|
select,
|
|
11917
|
+
showsSelection,
|
|
9221
11918
|
softClamp,
|
|
9222
11919
|
solve as solveSplit,
|
|
9223
11920
|
split,
|
|
11921
|
+
stackRows,
|
|
9224
11922
|
stepItem,
|
|
9225
11923
|
stepMove,
|
|
11924
|
+
stepPick,
|
|
9226
11925
|
timeLabel,
|
|
9227
11926
|
timeline,
|
|
9228
11927
|
toFrame,
|