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