@kyralabs/m3e-motion 1.4.0 → 1.6.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/NOTICE +20 -1
- package/README.md +35 -0
- package/dist/index.d.ts +764 -5
- package/dist/index.js +1421 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -379,16 +379,17 @@ var SpringAnimatable = class {
|
|
|
379
379
|
}
|
|
380
380
|
/**
|
|
381
381
|
* Animates to `target` from the value and velocity at `now` (ms); a null spec (e.g. a spatial
|
|
382
|
-
* spring under reduced motion) jumps there.
|
|
382
|
+
* spring under reduced motion) jumps there. `velocity` (units per second) overrides the current
|
|
383
|
+
* velocity, e.g. after the value was driven by something else (a drag, a tween).
|
|
383
384
|
*/
|
|
384
|
-
animateTo(target, spec, now) {
|
|
385
|
+
animateTo(target, spec, now, velocity) {
|
|
385
386
|
this.sample(now);
|
|
386
387
|
if (spec === null) {
|
|
387
388
|
this.snapTo(target);
|
|
388
389
|
return;
|
|
389
390
|
}
|
|
390
391
|
this.#from = this.#value;
|
|
391
|
-
this.#velocity0 = this.#velocity;
|
|
392
|
+
this.#velocity0 = velocity ?? this.#velocity;
|
|
392
393
|
this.#target = target;
|
|
393
394
|
this.#start = now;
|
|
394
395
|
this.#spec = spec;
|
|
@@ -437,8 +438,21 @@ function menuNavigationTarget(key, count, current) {
|
|
|
437
438
|
}
|
|
438
439
|
}
|
|
439
440
|
|
|
441
|
+
// src/type-select.ts
|
|
442
|
+
var TYPEAHEAD_TIMEOUT_MS = 1e3;
|
|
443
|
+
var collator;
|
|
444
|
+
function typeSelectTarget(texts, from, search) {
|
|
445
|
+
collator ??= new Intl.Collator(void 0, { usage: "search", sensitivity: "base" });
|
|
446
|
+
const compare = collator;
|
|
447
|
+
const matches = (text) => text !== "" && compare.compare(text.slice(0, search.length), search) === 0;
|
|
448
|
+
const start = Math.max(from, 0);
|
|
449
|
+
for (let i = start; i < texts.length; i++) if (matches(texts[i] ?? "")) return i;
|
|
450
|
+
for (let i = 0; i < start; i++) if (matches(texts[i] ?? "")) return i;
|
|
451
|
+
return -1;
|
|
452
|
+
}
|
|
453
|
+
|
|
440
454
|
// src/toolbar-navigation.ts
|
|
441
|
-
function toolbarNavigationTarget(key, count, current, orientation = "horizontal", rtl = false) {
|
|
455
|
+
function toolbarNavigationTarget(key, count, current, orientation = "horizontal", rtl = false, wrap = false) {
|
|
442
456
|
if (count === 0) return null;
|
|
443
457
|
let step;
|
|
444
458
|
switch (key) {
|
|
@@ -448,19 +462,21 @@ function toolbarNavigationTarget(key, count, current, orientation = "horizontal"
|
|
|
448
462
|
return count - 1;
|
|
449
463
|
case "ArrowRight":
|
|
450
464
|
case "ArrowLeft":
|
|
451
|
-
if (orientation
|
|
465
|
+
if (orientation === "vertical") return null;
|
|
452
466
|
step = key === "ArrowRight" !== rtl ? 1 : -1;
|
|
453
467
|
break;
|
|
454
468
|
case "ArrowDown":
|
|
455
469
|
case "ArrowUp":
|
|
456
|
-
if (orientation
|
|
470
|
+
if (orientation === "horizontal") return null;
|
|
457
471
|
step = key === "ArrowDown" ? 1 : -1;
|
|
458
472
|
break;
|
|
459
473
|
default:
|
|
460
474
|
return null;
|
|
461
475
|
}
|
|
462
476
|
if (current < 0) return step > 0 ? 0 : count - 1;
|
|
463
|
-
|
|
477
|
+
const next = current + step;
|
|
478
|
+
if (wrap) return (next + count) % count;
|
|
479
|
+
return Math.min(Math.max(next, 0), count - 1);
|
|
464
480
|
}
|
|
465
481
|
|
|
466
482
|
// src/cubic-bezier.ts
|
|
@@ -1031,6 +1047,1403 @@ function buttonGroupWidths(items, pressed, expandedRatio, visibleCount = items.l
|
|
|
1031
1047
|
return widths.slice(0, last);
|
|
1032
1048
|
}
|
|
1033
1049
|
|
|
1034
|
-
|
|
1050
|
+
// src/window-size-class.ts
|
|
1051
|
+
var WINDOW_WIDTH_BREAKPOINTS = /* @__PURE__ */ Object.freeze({
|
|
1052
|
+
compact: 0,
|
|
1053
|
+
medium: 600,
|
|
1054
|
+
expanded: 840,
|
|
1055
|
+
large: 1200,
|
|
1056
|
+
"extra-large": 1600
|
|
1057
|
+
});
|
|
1058
|
+
var WINDOW_HEIGHT_BREAKPOINTS = /* @__PURE__ */ Object.freeze({ compact: 0, medium: 480, expanded: 900 });
|
|
1059
|
+
var WIDTH_CLASSES = [
|
|
1060
|
+
"compact",
|
|
1061
|
+
"medium",
|
|
1062
|
+
"expanded",
|
|
1063
|
+
"large",
|
|
1064
|
+
"extra-large"
|
|
1065
|
+
];
|
|
1066
|
+
var HEIGHT_CLASSES = ["compact", "medium", "expanded"];
|
|
1067
|
+
function bucket(size, compact, classes, bounds) {
|
|
1068
|
+
let match = compact;
|
|
1069
|
+
for (const c of classes) if (size >= bounds[c]) match = c;
|
|
1070
|
+
return match;
|
|
1071
|
+
}
|
|
1072
|
+
function windowWidthSizeClass(widthPx, options = {}) {
|
|
1073
|
+
const classes = options.largeAndExtraLargeWidth === false ? WIDTH_CLASSES.slice(0, 3) : WIDTH_CLASSES;
|
|
1074
|
+
return bucket(widthPx, "compact", classes, WINDOW_WIDTH_BREAKPOINTS);
|
|
1075
|
+
}
|
|
1076
|
+
function windowHeightSizeClass(heightPx) {
|
|
1077
|
+
return bucket(heightPx, "compact", HEIGHT_CLASSES, WINDOW_HEIGHT_BREAKPOINTS);
|
|
1078
|
+
}
|
|
1079
|
+
function windowSizeClass(size, options = {}) {
|
|
1080
|
+
const widthClass = windowWidthSizeClass(size.width, options);
|
|
1081
|
+
const heightClass = windowHeightSizeClass(size.height);
|
|
1082
|
+
return {
|
|
1083
|
+
widthClass,
|
|
1084
|
+
heightClass,
|
|
1085
|
+
minWidth: WINDOW_WIDTH_BREAKPOINTS[widthClass],
|
|
1086
|
+
minHeight: WINDOW_HEIGHT_BREAKPOINTS[heightClass]
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
function sameWindowSizeClass(a, b) {
|
|
1090
|
+
return a.minWidth === b.minWidth && a.minHeight === b.minHeight;
|
|
1091
|
+
}
|
|
1092
|
+
var widthBound = (b) => typeof b === "number" ? b : WINDOW_WIDTH_BREAKPOINTS[b];
|
|
1093
|
+
var heightBound = (b) => typeof b === "number" ? b : WINDOW_HEIGHT_BREAKPOINTS[b];
|
|
1094
|
+
function isWidthAtLeastBreakpoint(sizeClass, breakpoint) {
|
|
1095
|
+
return sizeClass.minWidth >= widthBound(breakpoint);
|
|
1096
|
+
}
|
|
1097
|
+
function isHeightAtLeastBreakpoint(sizeClass, breakpoint) {
|
|
1098
|
+
return sizeClass.minHeight >= heightBound(breakpoint);
|
|
1099
|
+
}
|
|
1100
|
+
function isAtLeastBreakpoint(sizeClass, widthBreakpoint, heightBreakpoint) {
|
|
1101
|
+
return isWidthAtLeastBreakpoint(sizeClass, widthBreakpoint) && isHeightAtLeastBreakpoint(sizeClass, heightBreakpoint);
|
|
1102
|
+
}
|
|
1103
|
+
var PARTITION_SPACER = 24;
|
|
1104
|
+
var DEFAULT_PREFERRED_WIDTH = 360;
|
|
1105
|
+
var DEFAULT_PREFERRED_WIDTH_XL = 412;
|
|
1106
|
+
var DEFAULT_PREFERRED_HEIGHT = 420;
|
|
1107
|
+
function paneScaffoldDirective(sizeClass, options = {}) {
|
|
1108
|
+
let maxHorizontalPartitions;
|
|
1109
|
+
let horizontalPartitionSpacerSize;
|
|
1110
|
+
let defaultPanePreferredWidth;
|
|
1111
|
+
switch (sizeClass.minWidth) {
|
|
1112
|
+
case WINDOW_WIDTH_BREAKPOINTS.compact:
|
|
1113
|
+
case WINDOW_WIDTH_BREAKPOINTS.medium:
|
|
1114
|
+
maxHorizontalPartitions = 1;
|
|
1115
|
+
horizontalPartitionSpacerSize = 0;
|
|
1116
|
+
defaultPanePreferredWidth = DEFAULT_PREFERRED_WIDTH;
|
|
1117
|
+
break;
|
|
1118
|
+
case WINDOW_WIDTH_BREAKPOINTS.expanded:
|
|
1119
|
+
maxHorizontalPartitions = 2;
|
|
1120
|
+
horizontalPartitionSpacerSize = PARTITION_SPACER;
|
|
1121
|
+
defaultPanePreferredWidth = DEFAULT_PREFERRED_WIDTH;
|
|
1122
|
+
break;
|
|
1123
|
+
default:
|
|
1124
|
+
maxHorizontalPartitions = 3;
|
|
1125
|
+
horizontalPartitionSpacerSize = PARTITION_SPACER;
|
|
1126
|
+
defaultPanePreferredWidth = DEFAULT_PREFERRED_WIDTH_XL;
|
|
1127
|
+
}
|
|
1128
|
+
const stacked = options.isTabletop === true || maxHorizontalPartitions === 1 && sizeClass.minHeight === WINDOW_HEIGHT_BREAKPOINTS.expanded;
|
|
1129
|
+
return {
|
|
1130
|
+
maxHorizontalPartitions,
|
|
1131
|
+
horizontalPartitionSpacerSize,
|
|
1132
|
+
maxVerticalPartitions: stacked ? 2 : 1,
|
|
1133
|
+
verticalPartitionSpacerSize: stacked ? PARTITION_SPACER : 0,
|
|
1134
|
+
defaultPanePreferredWidth,
|
|
1135
|
+
defaultPanePreferredHeight: DEFAULT_PREFERRED_HEIGHT
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
var NAVIGATION_SUITE_TYPES = [
|
|
1139
|
+
"short-navigation-bar-compact",
|
|
1140
|
+
"short-navigation-bar-medium",
|
|
1141
|
+
"wide-navigation-rail-collapsed",
|
|
1142
|
+
"wide-navigation-rail-expanded",
|
|
1143
|
+
"navigation-drawer",
|
|
1144
|
+
"none"
|
|
1145
|
+
];
|
|
1146
|
+
function isNavigationBarType(type) {
|
|
1147
|
+
return type === "short-navigation-bar-compact" || type === "short-navigation-bar-medium";
|
|
1148
|
+
}
|
|
1149
|
+
var NAVIGATION_SUITE_EXPANDED_FROM = "large";
|
|
1150
|
+
function navigationSuiteType(sizeClass, options = {}) {
|
|
1151
|
+
if (sizeClass.minWidth === WINDOW_WIDTH_BREAKPOINTS.compact)
|
|
1152
|
+
return "short-navigation-bar-compact";
|
|
1153
|
+
if (options.isTabletop === true || sizeClass.minHeight === WINDOW_HEIGHT_BREAKPOINTS.compact) {
|
|
1154
|
+
return "short-navigation-bar-medium";
|
|
1155
|
+
}
|
|
1156
|
+
const { expandedFrom } = options;
|
|
1157
|
+
if (expandedFrom !== void 0 && expandedFrom !== null && isWidthAtLeastBreakpoint(sizeClass, expandedFrom)) {
|
|
1158
|
+
return options.expandedType ?? "wide-navigation-rail-expanded";
|
|
1159
|
+
}
|
|
1160
|
+
return "wide-navigation-rail-collapsed";
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/navigation-suite.ts
|
|
1164
|
+
var HIDDEN = 0;
|
|
1165
|
+
var VISIBLE = 1;
|
|
1166
|
+
var NavigationSuiteScaffoldAnimation = class {
|
|
1167
|
+
#state;
|
|
1168
|
+
#progress;
|
|
1169
|
+
#spec = null;
|
|
1170
|
+
/** `hidden`: rememberNavigationSuiteScaffoldState(initialValue = Hidden); rendered at rest. */
|
|
1171
|
+
constructor(hidden = false) {
|
|
1172
|
+
const value = hidden ? HIDDEN : VISIBLE;
|
|
1173
|
+
this.#state = new SpringAnimatable(value);
|
|
1174
|
+
this.#progress = new SpringAnimatable(value);
|
|
1175
|
+
}
|
|
1176
|
+
/** NavigationSuiteScaffoldState.targetValue == Hidden. */
|
|
1177
|
+
get targetHidden() {
|
|
1178
|
+
return this.#state.target !== VISIBLE;
|
|
1179
|
+
}
|
|
1180
|
+
/** NavigationSuiteScaffoldState.currentValue == Hidden (anything but exactly Visible). */
|
|
1181
|
+
get currentHidden() {
|
|
1182
|
+
return this.#state.value !== VISIBLE;
|
|
1183
|
+
}
|
|
1184
|
+
/** NavigationSuiteScaffoldState.isAnimating (the state's spring, not the layout's). */
|
|
1185
|
+
get isAnimating() {
|
|
1186
|
+
return this.#state.isRunning;
|
|
1187
|
+
}
|
|
1188
|
+
/** NavigationSuiteScaffoldState.hide(). */
|
|
1189
|
+
hide(spec, now) {
|
|
1190
|
+
this.#animate(HIDDEN, spec, now);
|
|
1191
|
+
}
|
|
1192
|
+
/** NavigationSuiteScaffoldState.show(). */
|
|
1193
|
+
show(spec, now) {
|
|
1194
|
+
this.#animate(VISIBLE, spec, now);
|
|
1195
|
+
}
|
|
1196
|
+
/** NavigationSuiteScaffoldState.toggle(): towards the opposite of the target. */
|
|
1197
|
+
toggle(spec, now) {
|
|
1198
|
+
this.#animate(this.targetHidden ? VISIBLE : HIDDEN, spec, now);
|
|
1199
|
+
}
|
|
1200
|
+
/** NavigationSuiteScaffoldState.snapTo(): the state jumps; the layout animates from `now`. */
|
|
1201
|
+
snapTo(hidden, spec, now) {
|
|
1202
|
+
this.#spec = spec;
|
|
1203
|
+
this.#state.snapTo(hidden ? HIDDEN : VISIBLE);
|
|
1204
|
+
this.sample(now);
|
|
1205
|
+
}
|
|
1206
|
+
#animate(target, spec, now) {
|
|
1207
|
+
this.#spec = spec;
|
|
1208
|
+
this.#state.animateTo(target, spec, now);
|
|
1209
|
+
this.sample(now);
|
|
1210
|
+
}
|
|
1211
|
+
/** Advances both springs to `now`; the layout retargets when currentValue changes. */
|
|
1212
|
+
sample(now) {
|
|
1213
|
+
this.#state.sample(now);
|
|
1214
|
+
const target = this.currentHidden ? HIDDEN : VISIBLE;
|
|
1215
|
+
if (this.#progress.target !== target) this.#progress.animateTo(target, this.#spec, now);
|
|
1216
|
+
const progress = this.#progress.sample(now);
|
|
1217
|
+
return { progress, running: this.#state.isRunning || this.#progress.isRunning };
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
function navigationSuiteOffset(size, progress) {
|
|
1221
|
+
return size - Math.trunc(size * progress);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/wide-navigation-rail.ts
|
|
1225
|
+
var MODAL_RAIL_EXPANDED_PROGRESS = 0.3;
|
|
1226
|
+
var to = (expanded) => expanded ? 1 : 0;
|
|
1227
|
+
var WideNavigationRailAnimation = class {
|
|
1228
|
+
modal;
|
|
1229
|
+
hideOnCollapse;
|
|
1230
|
+
#expanded;
|
|
1231
|
+
#item;
|
|
1232
|
+
#width;
|
|
1233
|
+
#layout;
|
|
1234
|
+
#position;
|
|
1235
|
+
#scrim = new SpringAnimatable(0);
|
|
1236
|
+
#slide;
|
|
1237
|
+
#specs = null;
|
|
1238
|
+
#open = false;
|
|
1239
|
+
#modalExpanded = false;
|
|
1240
|
+
/** hideOnCollapse: positionProgress waits for the slide out (animateToDismiss). */
|
|
1241
|
+
#closeAfterSlide = false;
|
|
1242
|
+
constructor(options) {
|
|
1243
|
+
this.modal = Boolean(options.modal);
|
|
1244
|
+
this.hideOnCollapse = this.modal && Boolean(options.hideOnCollapse);
|
|
1245
|
+
this.#expanded = options.expanded;
|
|
1246
|
+
const v = to(options.expanded);
|
|
1247
|
+
const laidOut = this.hideOnCollapse ? 1 : this.modal ? options.expanded ? 1 : 0 : v;
|
|
1248
|
+
this.#item = new SpringAnimatable(this.hideOnCollapse ? 1 : v);
|
|
1249
|
+
this.#width = new SpringAnimatable(laidOut, options.widthThreshold ?? 0.01 / 264);
|
|
1250
|
+
this.#layout = new SpringAnimatable(laidOut, options.layoutThreshold ?? 0.01 / 16);
|
|
1251
|
+
this.#position = new SpringAnimatable(this.modal ? v : 0);
|
|
1252
|
+
this.#slide = new SpringAnimatable(v, 0.01 / 360);
|
|
1253
|
+
if (this.modal && options.expanded) {
|
|
1254
|
+
this.#open = true;
|
|
1255
|
+
this.#modalExpanded = true;
|
|
1256
|
+
this.#scrim.snapTo(1);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
/** WideNavigationRailState.targetValue. */
|
|
1260
|
+
get expanded() {
|
|
1261
|
+
return this.#expanded;
|
|
1262
|
+
}
|
|
1263
|
+
get isRunning() {
|
|
1264
|
+
return this.#item.isRunning || this.#width.isRunning || this.#layout.isRunning || this.#position.isRunning || this.#scrim.isRunning || this.#slide.isRunning || this.#closeAfterSlide;
|
|
1265
|
+
}
|
|
1266
|
+
/** expand() / collapse() at `now` (ms). */
|
|
1267
|
+
setExpanded(expanded, specs, now) {
|
|
1268
|
+
this.sample(now);
|
|
1269
|
+
this.#specs = specs;
|
|
1270
|
+
if (expanded === this.#expanded) return;
|
|
1271
|
+
this.#expanded = expanded;
|
|
1272
|
+
const v = to(expanded);
|
|
1273
|
+
if (!this.modal) {
|
|
1274
|
+
this.#item.animateTo(v, specs.iconPosition, now);
|
|
1275
|
+
this.#width.animateTo(v, specs.width, now);
|
|
1276
|
+
this.#layout.animateTo(v, specs.width, now);
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
if (this.hideOnCollapse) {
|
|
1280
|
+
this.#slide.animateTo(v, specs.slide, now);
|
|
1281
|
+
this.#scrim.animateTo(v, specs.scrim, now);
|
|
1282
|
+
if (expanded) {
|
|
1283
|
+
this.#closeAfterSlide = false;
|
|
1284
|
+
this.#position.animateTo(1, specs.position, now);
|
|
1285
|
+
} else {
|
|
1286
|
+
this.#closeAfterSlide = true;
|
|
1287
|
+
}
|
|
1288
|
+
this.sample(now);
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
this.#item.animateTo(v, specs.iconPosition, now);
|
|
1292
|
+
this.#position.animateTo(v, specs.position, now);
|
|
1293
|
+
this.sample(now);
|
|
1294
|
+
}
|
|
1295
|
+
/** WideNavigationRailState.snapTo. */
|
|
1296
|
+
snapTo(expanded) {
|
|
1297
|
+
this.#expanded = expanded;
|
|
1298
|
+
const v = to(expanded);
|
|
1299
|
+
this.#closeAfterSlide = false;
|
|
1300
|
+
if (!this.modal) {
|
|
1301
|
+
for (const a of [this.#item, this.#width, this.#layout]) a.snapTo(v);
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
this.#position.snapTo(v);
|
|
1305
|
+
this.#slide.snapTo(v);
|
|
1306
|
+
this.#scrim.snapTo(v);
|
|
1307
|
+
this.#open = expanded;
|
|
1308
|
+
this.#modalExpanded = expanded;
|
|
1309
|
+
if (!this.hideOnCollapse) {
|
|
1310
|
+
for (const a of [this.#item, this.#width, this.#layout]) a.snapTo(v);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
sample(now) {
|
|
1314
|
+
const item = this.#item.sample(now);
|
|
1315
|
+
if (this.modal) this.#sampleModal(now);
|
|
1316
|
+
const width = this.#width.sample(now);
|
|
1317
|
+
const layout = this.#layout.sample(now);
|
|
1318
|
+
return {
|
|
1319
|
+
item: Math.max(item, 0),
|
|
1320
|
+
// iconPositionProgress.coerceAtLeast(0f) (NavigationItem.kt L544)
|
|
1321
|
+
width,
|
|
1322
|
+
layout,
|
|
1323
|
+
open: this.#open,
|
|
1324
|
+
railExpanded: !this.modal ? this.#expanded : this.#open && (this.hideOnCollapse || this.#modalExpanded),
|
|
1325
|
+
scrim: Math.min(Math.max(this.#scrim.value, 0), 1),
|
|
1326
|
+
slide: this.#slide.value,
|
|
1327
|
+
running: this.isRunning
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
#sampleModal(now) {
|
|
1331
|
+
const specs = this.#specs;
|
|
1332
|
+
if (this.hideOnCollapse) {
|
|
1333
|
+
this.#slide.sample(now);
|
|
1334
|
+
this.#scrim.sample(now);
|
|
1335
|
+
if (this.#closeAfterSlide && !this.#slide.isRunning) {
|
|
1336
|
+
this.#closeAfterSlide = false;
|
|
1337
|
+
this.#position.animateTo(0, specs?.position ?? null, now);
|
|
1338
|
+
}
|
|
1339
|
+
this.#open = this.#position.sample(now) > 0;
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const position = this.#position.sample(now);
|
|
1343
|
+
const open = position > 0;
|
|
1344
|
+
const modalExpanded = position >= MODAL_RAIL_EXPANDED_PROGRESS;
|
|
1345
|
+
if (!open) {
|
|
1346
|
+
this.#width.snapTo(0);
|
|
1347
|
+
this.#layout.snapTo(0);
|
|
1348
|
+
this.#scrim.snapTo(0);
|
|
1349
|
+
} else if (!this.#open) {
|
|
1350
|
+
const v = to(modalExpanded);
|
|
1351
|
+
this.#width.snapTo(v);
|
|
1352
|
+
this.#layout.snapTo(v);
|
|
1353
|
+
this.#scrim.snapTo(v);
|
|
1354
|
+
} else if (modalExpanded !== this.#modalExpanded) {
|
|
1355
|
+
const v = to(modalExpanded);
|
|
1356
|
+
this.#width.animateTo(v, specs?.modalWidth ?? null, now);
|
|
1357
|
+
this.#layout.animateTo(v, specs?.width ?? null, now);
|
|
1358
|
+
this.#scrim.animateTo(v, specs?.scrim ?? null, now);
|
|
1359
|
+
}
|
|
1360
|
+
this.#scrim.sample(now);
|
|
1361
|
+
this.#open = open;
|
|
1362
|
+
this.#modalExpanded = open && modalExpanded;
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
var lerp2 = (a, b, t) => a + (b - a) * t;
|
|
1366
|
+
function wideNavigationRailItemWidth(content, progress, m, maxWidth) {
|
|
1367
|
+
const pad = m.itemHorizontalPadding;
|
|
1368
|
+
const indicatorPadding = lerp2(m.collapsedIndicatorPadding, m.expandedIndicatorPadding, progress);
|
|
1369
|
+
if (content === null)
|
|
1370
|
+
return Math.min(m.iconSize + 2 * m.collapsedIndicatorPadding + 2 * pad, maxWidth);
|
|
1371
|
+
const gapAndLabel = content - m.iconSize - 2 * m.expandedIndicatorPadding;
|
|
1372
|
+
const label = gapAndLabel - m.iconLabelSpace;
|
|
1373
|
+
const widthTop = Math.min(Math.max(label, m.iconSize + 2 * pad + 2 * indicatorPadding), maxWidth);
|
|
1374
|
+
const ripple = lerp2(m.iconSize, m.iconSize + gapAndLabel, progress) + 2 * indicatorPadding;
|
|
1375
|
+
const widthStart = Math.min(ripple + pad, maxWidth);
|
|
1376
|
+
return widthTop + (widthStart - widthTop) * progress;
|
|
1377
|
+
}
|
|
1378
|
+
function wideNavigationRailWidth(input) {
|
|
1379
|
+
const m = input.metrics;
|
|
1380
|
+
const max = Math.min(input.maxWidth ?? m.expandedMaxWidth, m.expandedMaxWidth);
|
|
1381
|
+
const minWidth = Math.min(lerp2(m.collapsedWidth, m.expandedMinWidth, input.widthProgress), max);
|
|
1382
|
+
const fullRange = lerp2(m.collapsedWidth, m.expandedMaxWidth, input.widthProgress);
|
|
1383
|
+
const expandedMin = Math.min(m.expandedMinWidth, max);
|
|
1384
|
+
if (input.expanded) {
|
|
1385
|
+
const itemMax = max - m.itemHorizontalPadding;
|
|
1386
|
+
let widestItem = 0;
|
|
1387
|
+
for (const content of input.items) {
|
|
1388
|
+
const w = wideNavigationRailItemWidth(content, input.itemProgress, m, itemMax);
|
|
1389
|
+
widestItem = Math.max(widestItem, w + m.itemHorizontalPadding);
|
|
1390
|
+
}
|
|
1391
|
+
const widest = Math.max(widestItem, input.header);
|
|
1392
|
+
if (widest > minWidth && widest > expandedMin) {
|
|
1393
|
+
const constrain = Math.min(Math.max(widest, expandedMin), max);
|
|
1394
|
+
return { width: Math.min(fullRange, constrain), wide: true };
|
|
1395
|
+
}
|
|
1396
|
+
return { width: minWidth, wide: input.wide };
|
|
1397
|
+
}
|
|
1398
|
+
if (input.wide) {
|
|
1399
|
+
const upper = Math.max(input.previousWidth, minWidth);
|
|
1400
|
+
return { width: Math.min(Math.max(fullRange, minWidth), upper), wide: true };
|
|
1401
|
+
}
|
|
1402
|
+
return { width: minWidth, wide: false };
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// src/navigation-drawer.ts
|
|
1406
|
+
var DRAWER_POSITIONAL_THRESHOLD = 0.5;
|
|
1407
|
+
var DRAWER_VELOCITY_THRESHOLD = 400;
|
|
1408
|
+
var DRAWER_SETTLE_MILLIS = 256;
|
|
1409
|
+
var DECAY_FRICTION = -4.2;
|
|
1410
|
+
var DECAY_VELOCITY_THRESHOLD = 0.1;
|
|
1411
|
+
function exponentialDecayTarget(value, velocity) {
|
|
1412
|
+
if (Math.abs(velocity) <= DECAY_VELOCITY_THRESHOLD) return value;
|
|
1413
|
+
const duration = Math.log(Math.abs(DECAY_VELOCITY_THRESHOLD / velocity)) / DECAY_FRICTION * 1e3;
|
|
1414
|
+
return value - velocity / DECAY_FRICTION + velocity / DECAY_FRICTION * Math.exp(DECAY_FRICTION * duration / 1e3);
|
|
1415
|
+
}
|
|
1416
|
+
function drawerSettlesOpen(offset, velocity, width, velocityThreshold = DRAWER_VELOCITY_THRESHOLD) {
|
|
1417
|
+
const closed = -width;
|
|
1418
|
+
if (velocity === 0) return Math.abs(offset) <= Math.abs(offset - closed);
|
|
1419
|
+
const forward = velocity > 0;
|
|
1420
|
+
if (Math.abs(velocity) >= Math.abs(velocityThreshold)) return forward;
|
|
1421
|
+
const threshold = Math.abs(width * DRAWER_POSITIONAL_THRESHOLD);
|
|
1422
|
+
const fromStart = Math.abs((forward ? closed : 0) - offset);
|
|
1423
|
+
return fromStart >= threshold ? forward : !forward;
|
|
1424
|
+
}
|
|
1425
|
+
var DrawerAnimation = class {
|
|
1426
|
+
#width;
|
|
1427
|
+
#open;
|
|
1428
|
+
#settled;
|
|
1429
|
+
#mode = "rest";
|
|
1430
|
+
#spring;
|
|
1431
|
+
#offset;
|
|
1432
|
+
#velocity = 0;
|
|
1433
|
+
// Tween / decay state.
|
|
1434
|
+
#from = 0;
|
|
1435
|
+
#to = 0;
|
|
1436
|
+
#v0 = 0;
|
|
1437
|
+
#start = 0;
|
|
1438
|
+
#duration = 0;
|
|
1439
|
+
#easing = (t) => t;
|
|
1440
|
+
/** @param open initial value (at rest); @param width the sheet width in px. */
|
|
1441
|
+
constructor(open, width) {
|
|
1442
|
+
this.#width = Math.max(0, width);
|
|
1443
|
+
this.#open = open;
|
|
1444
|
+
this.#settled = open;
|
|
1445
|
+
this.#offset = open ? 0 : -this.#width;
|
|
1446
|
+
this.#spring = new SpringAnimatable(this.#offset);
|
|
1447
|
+
}
|
|
1448
|
+
/** DrawerState.targetValue === Open. */
|
|
1449
|
+
get isOpen() {
|
|
1450
|
+
return this.#open;
|
|
1451
|
+
}
|
|
1452
|
+
/** DrawerState.currentValue === Open: the last anchor it settled on. */
|
|
1453
|
+
get isSettledOpen() {
|
|
1454
|
+
return this.#settled;
|
|
1455
|
+
}
|
|
1456
|
+
get isDragging() {
|
|
1457
|
+
return this.#mode === "drag";
|
|
1458
|
+
}
|
|
1459
|
+
get width() {
|
|
1460
|
+
return this.#width;
|
|
1461
|
+
}
|
|
1462
|
+
/** Units: px per second, positive towards open (AnchoredDraggableState.lastVelocity). */
|
|
1463
|
+
get velocity() {
|
|
1464
|
+
return this.#velocity;
|
|
1465
|
+
}
|
|
1466
|
+
/** New anchors (the sheet was measured): at rest the offset follows its anchor. */
|
|
1467
|
+
setWidth(width) {
|
|
1468
|
+
const w = Math.max(0, width);
|
|
1469
|
+
if (w === this.#width) return;
|
|
1470
|
+
const previous = this.#width;
|
|
1471
|
+
this.#width = w;
|
|
1472
|
+
if (this.#mode === "rest") {
|
|
1473
|
+
this.#offset = this.#open ? 0 : -w;
|
|
1474
|
+
this.#spring.snapTo(this.#offset);
|
|
1475
|
+
} else if (this.#mode !== "drag" && !this.#open && this.#to === -previous) {
|
|
1476
|
+
this.#to = -w;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
/** Jumps (DrawerState.snapTo). */
|
|
1480
|
+
snapTo(open) {
|
|
1481
|
+
this.#mode = "rest";
|
|
1482
|
+
this.#open = open;
|
|
1483
|
+
this.#settled = open;
|
|
1484
|
+
this.#offset = open ? 0 : -this.#width;
|
|
1485
|
+
this.#velocity = 0;
|
|
1486
|
+
this.#spring.snapTo(this.#offset);
|
|
1487
|
+
}
|
|
1488
|
+
/** DrawerState.open() / close() at `now` (ms): springs from the current offset and velocity. */
|
|
1489
|
+
animateTo(open, specs, now) {
|
|
1490
|
+
this.sample(now);
|
|
1491
|
+
if (this.#mode === "drag") this.#mode = "rest";
|
|
1492
|
+
this.#open = open;
|
|
1493
|
+
const target = open ? 0 : -this.#width;
|
|
1494
|
+
const spec = open ? specs.open : specs.close;
|
|
1495
|
+
if (spec === null || this.#offset === target && this.#velocity === 0) {
|
|
1496
|
+
this.snapTo(open);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
const velocity = this.#velocity;
|
|
1500
|
+
this.#spring.snapTo(this.#offset);
|
|
1501
|
+
this.#spring.animateTo(target, spec, now, velocity);
|
|
1502
|
+
if (this.#spring.isRunning) this.#mode = "spring";
|
|
1503
|
+
else this.snapTo(open);
|
|
1504
|
+
}
|
|
1505
|
+
/** Grabs the sheet (pointer down past the slop): stops any animation where it is. */
|
|
1506
|
+
startDrag(now) {
|
|
1507
|
+
this.sample(now);
|
|
1508
|
+
this.#mode = "drag";
|
|
1509
|
+
this.#velocity = 0;
|
|
1510
|
+
}
|
|
1511
|
+
/** Moves the offset by `delta` px (positive towards open), coerced between the anchors. */
|
|
1512
|
+
dragBy(delta) {
|
|
1513
|
+
if (this.#mode !== "drag") return;
|
|
1514
|
+
this.#offset = Math.min(0, Math.max(-this.#width, this.#offset + delta));
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Ends a drag with the pointer `velocity` (px/s, positive towards open): picks the target
|
|
1518
|
+
* (computeTarget) and settles on it (animateToWithDecay). Returns whether it settles open.
|
|
1519
|
+
* `velocityThreshold`: DrawerVelocityThreshold in px/s.
|
|
1520
|
+
*/
|
|
1521
|
+
release(velocity, specs, now, velocityThreshold = DRAWER_VELOCITY_THRESHOLD, confirm = () => true) {
|
|
1522
|
+
if (this.#mode !== "drag") return this.#open;
|
|
1523
|
+
const proposed = drawerSettlesOpen(this.#offset, velocity, this.#width, velocityThreshold);
|
|
1524
|
+
const open = proposed === this.#settled || confirm(proposed) ? proposed : this.#settled;
|
|
1525
|
+
this.#open = open;
|
|
1526
|
+
const target = open ? 0 : -this.#width;
|
|
1527
|
+
const prev = this.#offset;
|
|
1528
|
+
this.#start = now;
|
|
1529
|
+
this.#from = prev;
|
|
1530
|
+
this.#to = target;
|
|
1531
|
+
this.#v0 = velocity;
|
|
1532
|
+
this.#velocity = velocity;
|
|
1533
|
+
if (prev === target) {
|
|
1534
|
+
this.snapTo(open);
|
|
1535
|
+
return open;
|
|
1536
|
+
}
|
|
1537
|
+
const towards = velocity * (target - prev) > 0;
|
|
1538
|
+
if (towards) {
|
|
1539
|
+
const projected = exponentialDecayTarget(prev, velocity);
|
|
1540
|
+
if (velocity > 0 ? projected >= target : projected <= target) {
|
|
1541
|
+
this.#mode = "decay";
|
|
1542
|
+
this.#duration = 1e3 * Math.log(DECAY_VELOCITY_THRESHOLD / Math.abs(velocity)) / DECAY_FRICTION;
|
|
1543
|
+
return open;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
if (specs.settle === null || specs.settle.duration <= 0) {
|
|
1547
|
+
this.snapTo(open);
|
|
1548
|
+
return open;
|
|
1549
|
+
}
|
|
1550
|
+
this.#mode = "tween";
|
|
1551
|
+
this.#duration = specs.settle.duration;
|
|
1552
|
+
this.#easing = specs.settle.easing;
|
|
1553
|
+
return open;
|
|
1554
|
+
}
|
|
1555
|
+
/** Advances to `now` (ms). */
|
|
1556
|
+
sample(now) {
|
|
1557
|
+
switch (this.#mode) {
|
|
1558
|
+
case "spring": {
|
|
1559
|
+
this.#offset = this.#spring.sample(now);
|
|
1560
|
+
this.#velocity = this.#spring.velocity;
|
|
1561
|
+
if (!this.#spring.isRunning) this.#settle();
|
|
1562
|
+
break;
|
|
1563
|
+
}
|
|
1564
|
+
case "tween": {
|
|
1565
|
+
const elapsed = now - this.#start;
|
|
1566
|
+
if (elapsed >= this.#duration) {
|
|
1567
|
+
this.#settle();
|
|
1568
|
+
break;
|
|
1569
|
+
}
|
|
1570
|
+
const f = (t) => {
|
|
1571
|
+
const p = Math.min(1, Math.max(0, t / this.#duration));
|
|
1572
|
+
return this.#from + (this.#to - this.#from) * this.#easing(p);
|
|
1573
|
+
};
|
|
1574
|
+
const value = f(elapsed);
|
|
1575
|
+
this.#velocity = (f(elapsed + 1) - value) * 1e3;
|
|
1576
|
+
this.#offset = value;
|
|
1577
|
+
break;
|
|
1578
|
+
}
|
|
1579
|
+
case "decay": {
|
|
1580
|
+
const t = (now - this.#start) / 1e3;
|
|
1581
|
+
const value = this.#from - this.#v0 / DECAY_FRICTION + this.#v0 / DECAY_FRICTION * Math.exp(DECAY_FRICTION * t);
|
|
1582
|
+
const crossed = this.#v0 > 0 ? value >= this.#to : value <= this.#to;
|
|
1583
|
+
if (crossed || now - this.#start >= this.#duration) {
|
|
1584
|
+
this.#settle();
|
|
1585
|
+
break;
|
|
1586
|
+
}
|
|
1587
|
+
this.#offset = value;
|
|
1588
|
+
this.#velocity = this.#v0 * Math.exp(DECAY_FRICTION * t);
|
|
1589
|
+
break;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
const w = this.#width;
|
|
1593
|
+
const fraction = w <= 0 ? this.#open ? 1 : 0 : Math.min(1, Math.max(0, (this.#offset + w) / w));
|
|
1594
|
+
return {
|
|
1595
|
+
offset: this.#offset,
|
|
1596
|
+
fraction,
|
|
1597
|
+
running: this.#mode !== "rest",
|
|
1598
|
+
visible: fraction !== 0
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
#settle() {
|
|
1602
|
+
this.#mode = "rest";
|
|
1603
|
+
this.#offset = this.#open ? 0 : -this.#width;
|
|
1604
|
+
this.#velocity = 0;
|
|
1605
|
+
this.#settled = this.#open;
|
|
1606
|
+
this.#spring.snapTo(this.#offset);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
|
|
1610
|
+
// src/slider.ts
|
|
1611
|
+
var SLIDER_KEY_DIVISIONS = 100;
|
|
1612
|
+
var SLIDER_PAGE_DIVISOR = 10;
|
|
1613
|
+
var SLIDER_PAGE_MAX_STEPS = 10;
|
|
1614
|
+
var clamp = (v, lo, hi) => Math.min(Math.max(v, lo), hi);
|
|
1615
|
+
var lerp3 = (a, b, t) => a + (b - a) * t;
|
|
1616
|
+
function sliderSteps(min, max, step) {
|
|
1617
|
+
if (step === void 0 || !(step > 0) || !(max > min)) return 0;
|
|
1618
|
+
return Math.max(0, Math.round((max - min) / step) - 1);
|
|
1619
|
+
}
|
|
1620
|
+
function sliderTickFractions(steps) {
|
|
1621
|
+
if (steps <= 0) return [];
|
|
1622
|
+
return Array.from({ length: steps + 2 }, (_, i) => i / (steps + 1));
|
|
1623
|
+
}
|
|
1624
|
+
function sliderFraction(value, min, max) {
|
|
1625
|
+
return clamp(max - min === 0 ? 0 : (value - min) / (max - min), 0, 1);
|
|
1626
|
+
}
|
|
1627
|
+
var sliderValueAt = (fraction, min, max) => lerp3(min, max, fraction);
|
|
1628
|
+
function sliderSnap(value, steps, min, max) {
|
|
1629
|
+
const ticks = sliderTickFractions(steps);
|
|
1630
|
+
if (ticks.length === 0) return value;
|
|
1631
|
+
let best = value;
|
|
1632
|
+
let distance = Infinity;
|
|
1633
|
+
for (const t of ticks) {
|
|
1634
|
+
const v = lerp3(min, max, t);
|
|
1635
|
+
const d = Math.abs(v - value);
|
|
1636
|
+
if (d < distance) {
|
|
1637
|
+
distance = d;
|
|
1638
|
+
best = v;
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
return best;
|
|
1642
|
+
}
|
|
1643
|
+
function sliderThumbValue(value, bounds, steps, min, max) {
|
|
1644
|
+
return sliderSnap(clamp(value, bounds.min, bounds.max), steps, min, max);
|
|
1645
|
+
}
|
|
1646
|
+
function sliderThumbBounds(values, index, min, max) {
|
|
1647
|
+
return {
|
|
1648
|
+
min: index > 0 ? values[index - 1] ?? min : min,
|
|
1649
|
+
max: index < values.length - 1 ? values[index + 1] ?? max : max
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
function sliderKeyDelta(steps, min, max) {
|
|
1653
|
+
const actual = steps > 0 ? steps + 1 : SLIDER_KEY_DIVISIONS;
|
|
1654
|
+
return Math.abs(max - min) / actual;
|
|
1655
|
+
}
|
|
1656
|
+
function sliderPageSteps(steps) {
|
|
1657
|
+
const actual = steps > 0 ? steps + 1 : SLIDER_KEY_DIVISIONS;
|
|
1658
|
+
return clamp(Math.floor(actual / SLIDER_PAGE_DIVISOR), 1, SLIDER_PAGE_MAX_STEPS);
|
|
1659
|
+
}
|
|
1660
|
+
function sliderKeyAction(key, options = {}) {
|
|
1661
|
+
const { vertical = false, rtl = false, shiftKey = false } = options;
|
|
1662
|
+
const page = (up) => shiftKey ? up ? "page-increment" : "page-decrement" : up ? "increment" : "decrement";
|
|
1663
|
+
switch (key) {
|
|
1664
|
+
case "ArrowUp":
|
|
1665
|
+
return page(true);
|
|
1666
|
+
case "ArrowDown":
|
|
1667
|
+
return page(false);
|
|
1668
|
+
case "ArrowRight":
|
|
1669
|
+
return page(vertical || !rtl);
|
|
1670
|
+
case "ArrowLeft":
|
|
1671
|
+
return page(!(vertical || !rtl));
|
|
1672
|
+
case "PageUp":
|
|
1673
|
+
return "page-increment";
|
|
1674
|
+
case "PageDown":
|
|
1675
|
+
return "page-decrement";
|
|
1676
|
+
case "Home":
|
|
1677
|
+
return "min";
|
|
1678
|
+
case "End":
|
|
1679
|
+
return "max";
|
|
1680
|
+
default:
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
function sliderKeyValue(action, values, index, steps, min, max) {
|
|
1685
|
+
const value = values[index] ?? min;
|
|
1686
|
+
const bounds = sliderThumbBounds(values, index, min, max);
|
|
1687
|
+
const delta = sliderKeyDelta(steps, min, max);
|
|
1688
|
+
const page = sliderPageSteps(steps) * delta;
|
|
1689
|
+
const target = action === "increment" ? value + delta : action === "decrement" ? value - delta : action === "page-increment" ? value + page : action === "page-decrement" ? value - page : action === "min" ? bounds.min : bounds.max;
|
|
1690
|
+
return sliderThumbValue(target, bounds, steps, min, max);
|
|
1691
|
+
}
|
|
1692
|
+
function sliderClosestThumb(values, value) {
|
|
1693
|
+
const [start, end] = values;
|
|
1694
|
+
if (start === void 0 || end === void 0) return 0;
|
|
1695
|
+
const diffStart = Math.abs(start - value);
|
|
1696
|
+
const diffEnd = Math.abs(end - value);
|
|
1697
|
+
if (diffStart !== diffEnd) return diffStart < diffEnd ? 0 : 1;
|
|
1698
|
+
return start > value ? 0 : 1;
|
|
1699
|
+
}
|
|
1700
|
+
function sliderTrackGeometry(input) {
|
|
1701
|
+
const {
|
|
1702
|
+
length,
|
|
1703
|
+
cornerSize: c,
|
|
1704
|
+
insideCornerSize: inside,
|
|
1705
|
+
thumbWidth,
|
|
1706
|
+
gapSize,
|
|
1707
|
+
steps,
|
|
1708
|
+
fraction,
|
|
1709
|
+
centered = false,
|
|
1710
|
+
cornerShrinking = false,
|
|
1711
|
+
stopIndicator = true
|
|
1712
|
+
} = input;
|
|
1713
|
+
const range = input.startFraction !== void 0;
|
|
1714
|
+
const ticks = sliderTickFractions(steps);
|
|
1715
|
+
const onEdge = (f) => f === ticks[0] || f === ticks[ticks.length - 1];
|
|
1716
|
+
const position = (f) => ticks.length > 0 && !onEdge(f) ? (length - c * 2) * f + c : length * f;
|
|
1717
|
+
const end = position(fraction);
|
|
1718
|
+
const start = range ? position(input.startFraction) : 0;
|
|
1719
|
+
const centre = length / 2;
|
|
1720
|
+
const before = fraction < 0.5;
|
|
1721
|
+
const after = fraction > 0.5;
|
|
1722
|
+
const startThumb = centered ? !after ? thumbWidth : 0 : range ? thumbWidth : 0;
|
|
1723
|
+
const endThumb = centered ? !before ? thumbWidth : 0 : thumbWidth;
|
|
1724
|
+
const startGapSize = centered || range ? gapSize : 0;
|
|
1725
|
+
const startGap = startGapSize > 0 ? startThumb / 2 + startGapSize : 0;
|
|
1726
|
+
const endGap = gapSize > 0 ? endThumb / 2 + gapSize : 0;
|
|
1727
|
+
const thresholdCorner = !cornerShrinking || ticks.length > 0;
|
|
1728
|
+
const parts = [];
|
|
1729
|
+
const stops = [];
|
|
1730
|
+
const adjustedEnd = centered ? Math.min(end, centre) : start;
|
|
1731
|
+
const rangeThreshold = startGap + (thresholdCorner ? c : 0);
|
|
1732
|
+
if ((centered || range) && adjustedEnd > rangeThreshold) {
|
|
1733
|
+
parts.push({
|
|
1734
|
+
kind: "inactive-start",
|
|
1735
|
+
start: 0,
|
|
1736
|
+
end: adjustedEnd - startGap,
|
|
1737
|
+
startRadius: c,
|
|
1738
|
+
endRadius: inside
|
|
1739
|
+
});
|
|
1740
|
+
if (stopIndicator) stops.push(c);
|
|
1741
|
+
}
|
|
1742
|
+
const adjustedStart = centered ? Math.max(end, centre) : end;
|
|
1743
|
+
const inactiveThreshold = length - endGap - (thresholdCorner ? c : 0);
|
|
1744
|
+
if (adjustedStart < inactiveThreshold) {
|
|
1745
|
+
parts.push({
|
|
1746
|
+
kind: "inactive-end",
|
|
1747
|
+
start: adjustedStart + endGap,
|
|
1748
|
+
end: length,
|
|
1749
|
+
startRadius: inside,
|
|
1750
|
+
endRadius: c
|
|
1751
|
+
});
|
|
1752
|
+
if (stopIndicator) stops.push(length - c);
|
|
1753
|
+
}
|
|
1754
|
+
const activeStart = centered ? adjustedEnd + (adjustedEnd < centre ? startGap : 0) : range ? start + startGap : 0;
|
|
1755
|
+
const activeEnd = centered ? adjustedStart - (adjustedStart > centre ? endGap : 0) : end - endGap;
|
|
1756
|
+
const activeStartRadius = centered || range ? inside : c;
|
|
1757
|
+
const activeThreshold = thresholdCorner ? activeStartRadius : 0;
|
|
1758
|
+
if (activeEnd - activeStart > activeThreshold) {
|
|
1759
|
+
parts.push({
|
|
1760
|
+
kind: "active",
|
|
1761
|
+
start: activeStart,
|
|
1762
|
+
end: activeEnd,
|
|
1763
|
+
startRadius: activeStartRadius,
|
|
1764
|
+
endRadius: inside
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
const tickList = [];
|
|
1768
|
+
const centreGap = centered ? end > centre ? startGap : endGap : 0;
|
|
1769
|
+
const thumbGap = centered ? end > centre ? endGap : startGap : endGap;
|
|
1770
|
+
ticks.forEach((t, i) => {
|
|
1771
|
+
if (stopIndicator && ((centered || range) && i === 0 || i === ticks.length - 1)) return;
|
|
1772
|
+
const p = lerp3(c, length - c, t);
|
|
1773
|
+
const within = (centreOf, gap) => p >= centreOf - gap && p <= centreOf + gap;
|
|
1774
|
+
if (centered && within(centre, centreGap) || range && within(start, startGap) || within(end, thumbGap)) {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
tickList.push({ position: p, active: p >= activeStart && p <= activeEnd });
|
|
1778
|
+
});
|
|
1779
|
+
return { thumbs: range ? [start, end] : [end], parts, stops, ticks: tickList };
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// src/tabs.ts
|
|
1783
|
+
var TAB_INDICATOR_MIN_WIDTH = 24;
|
|
1784
|
+
var THRESHOLD = 0.01;
|
|
1785
|
+
function tabPositions(tabs, start = 0, minIndicatorWidth = TAB_INDICATOR_MIN_WIDTH) {
|
|
1786
|
+
let left = start;
|
|
1787
|
+
return tabs.map(({ width, contentWidth }) => {
|
|
1788
|
+
const position = { left, width, contentWidth: Math.max(contentWidth, minIndicatorWidth) };
|
|
1789
|
+
left += width;
|
|
1790
|
+
return position;
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
function tabIndicatorTarget(position, variant) {
|
|
1794
|
+
return {
|
|
1795
|
+
offset: position.left,
|
|
1796
|
+
width: variant === "primary" ? position.contentWidth : position.width
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
var TabIndicatorAnimation = class {
|
|
1800
|
+
#offset;
|
|
1801
|
+
#width;
|
|
1802
|
+
/** Starts at rest on the first layout's target (Compose: initialOffset / initialWidth). */
|
|
1803
|
+
constructor(offset, width) {
|
|
1804
|
+
this.#offset = new SpringAnimatable(offset, THRESHOLD);
|
|
1805
|
+
this.#width = new SpringAnimatable(width, THRESHOLD);
|
|
1806
|
+
}
|
|
1807
|
+
get offset() {
|
|
1808
|
+
return this.#offset;
|
|
1809
|
+
}
|
|
1810
|
+
get width() {
|
|
1811
|
+
return this.#width;
|
|
1812
|
+
}
|
|
1813
|
+
get running() {
|
|
1814
|
+
return this.#offset.isRunning || this.#width.isRunning;
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Retargets each Animatable whose target changed, from its value and velocity at `now`; a null
|
|
1818
|
+
* spec (reduced motion) jumps.
|
|
1819
|
+
*/
|
|
1820
|
+
animateTo(offset, width, spec, now) {
|
|
1821
|
+
if (width !== this.#width.target) this.#width.animateTo(width, spec, now);
|
|
1822
|
+
if (offset !== this.#offset.target) this.#offset.animateTo(offset, spec, now);
|
|
1823
|
+
}
|
|
1824
|
+
snapTo(offset, width) {
|
|
1825
|
+
this.#offset.snapTo(offset);
|
|
1826
|
+
this.#width.snapTo(width);
|
|
1827
|
+
}
|
|
1828
|
+
sample(now) {
|
|
1829
|
+
const offset = this.#offset.sample(now);
|
|
1830
|
+
const width = this.#width.sample(now);
|
|
1831
|
+
return { offset, width, running: this.running };
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
var tabIndicatorShift = (sample, selected) => sample.offset - selected.left;
|
|
1835
|
+
function scrollableTabOffset(tab, scrollWidth, visibleWidth) {
|
|
1836
|
+
const centered = tab.left - (visibleWidth / 2 - tab.width / 2);
|
|
1837
|
+
const available = Math.max(scrollWidth - visibleWidth, 0);
|
|
1838
|
+
return Math.min(Math.max(centered, 0), available);
|
|
1839
|
+
}
|
|
1840
|
+
var TabScrollAnimation = class {
|
|
1841
|
+
value;
|
|
1842
|
+
constructor(position) {
|
|
1843
|
+
this.value = new SpringAnimatable(position, THRESHOLD);
|
|
1844
|
+
}
|
|
1845
|
+
/** Starts a new scroll from `from` (the scroll state's value), velocity 0. */
|
|
1846
|
+
animateTo(from, target, spec, now) {
|
|
1847
|
+
this.value.snapTo(from);
|
|
1848
|
+
this.value.animateTo(target, spec, now, 0);
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
|
|
1852
|
+
// src/three-pane-scaffold.ts
|
|
1853
|
+
var THREE_PANE_SCAFFOLD_ROLES = [
|
|
1854
|
+
"primary",
|
|
1855
|
+
"secondary",
|
|
1856
|
+
"tertiary"
|
|
1857
|
+
];
|
|
1858
|
+
var PRIORITY = {
|
|
1859
|
+
primary: 10,
|
|
1860
|
+
secondary: 5,
|
|
1861
|
+
tertiary: 1
|
|
1862
|
+
};
|
|
1863
|
+
var LIST_DETAIL_ADAPT_STRATEGIES = {
|
|
1864
|
+
primary: "hide",
|
|
1865
|
+
secondary: "hide",
|
|
1866
|
+
tertiary: "hide"
|
|
1867
|
+
};
|
|
1868
|
+
var SUPPORTING_PANE_ADAPT_STRATEGIES = {
|
|
1869
|
+
primary: "hide",
|
|
1870
|
+
secondary: { reflowUnder: "primary" },
|
|
1871
|
+
tertiary: "hide"
|
|
1872
|
+
};
|
|
1873
|
+
var ListDetailPaneScaffoldRole = /* @__PURE__ */ Object.freeze({
|
|
1874
|
+
List: "secondary",
|
|
1875
|
+
Detail: "primary",
|
|
1876
|
+
Extra: "tertiary"
|
|
1877
|
+
});
|
|
1878
|
+
var SupportingPaneScaffoldRole = /* @__PURE__ */ Object.freeze({
|
|
1879
|
+
Main: "primary",
|
|
1880
|
+
Supporting: "secondary",
|
|
1881
|
+
Extra: "tertiary"
|
|
1882
|
+
});
|
|
1883
|
+
var LIST_DETAIL_PANE_ORDER = [
|
|
1884
|
+
"secondary",
|
|
1885
|
+
"primary",
|
|
1886
|
+
"tertiary"
|
|
1887
|
+
];
|
|
1888
|
+
var SUPPORTING_PANE_ORDER = [
|
|
1889
|
+
"primary",
|
|
1890
|
+
"secondary",
|
|
1891
|
+
"tertiary"
|
|
1892
|
+
];
|
|
1893
|
+
function sameThreePaneScaffoldValue(a, b) {
|
|
1894
|
+
return a.primary === b.primary && a.secondary === b.secondary && a.tertiary === b.tertiary;
|
|
1895
|
+
}
|
|
1896
|
+
function calculateThreePaneScaffoldValue(maxHorizontalPartitions, adaptStrategies, destinationHistory, maxVerticalPartitions = 1) {
|
|
1897
|
+
let expandedCount = 0;
|
|
1898
|
+
const values = {};
|
|
1899
|
+
let checkReflowedPane = maxHorizontalPartitions === 1 && maxVerticalPartitions > 1 && THREE_PANE_SCAFFOLD_ROLES.some((r) => adaptStrategies[r] !== "hide");
|
|
1900
|
+
const order = [...destinationHistory.map((d) => d.pane).reverse(), ...THREE_PANE_SCAFFOLD_ROLES];
|
|
1901
|
+
for (const pane of order) {
|
|
1902
|
+
const hasAvailablePartition = expandedCount < maxHorizontalPartitions;
|
|
1903
|
+
if (!hasAvailablePartition && !checkReflowedPane) break;
|
|
1904
|
+
if (values[pane] !== void 0) continue;
|
|
1905
|
+
let reflowedPane = null;
|
|
1906
|
+
let anchorPane = pane;
|
|
1907
|
+
let anchorValue;
|
|
1908
|
+
const strategy = adaptStrategies[pane];
|
|
1909
|
+
if (checkReflowedPane && strategy !== "hide") {
|
|
1910
|
+
reflowedPane = pane;
|
|
1911
|
+
anchorPane = strategy.reflowUnder;
|
|
1912
|
+
anchorValue = values[anchorPane];
|
|
1913
|
+
}
|
|
1914
|
+
if (anchorValue === void 0) {
|
|
1915
|
+
if (!hasAvailablePartition) continue;
|
|
1916
|
+
values[anchorPane] = "expanded";
|
|
1917
|
+
expandedCount++;
|
|
1918
|
+
} else if (anchorValue !== "expanded") {
|
|
1919
|
+
continue;
|
|
1920
|
+
}
|
|
1921
|
+
if (reflowedPane !== null) {
|
|
1922
|
+
values[reflowedPane] = "reflowed";
|
|
1923
|
+
checkReflowedPane = false;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return {
|
|
1927
|
+
primary: values.primary ?? "hidden",
|
|
1928
|
+
secondary: values.secondary ?? "hidden",
|
|
1929
|
+
tertiary: values.tertiary ?? "hidden",
|
|
1930
|
+
currentDestination: destinationHistory[destinationHistory.length - 1]?.pane ?? null
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
function expandedPanes(value, order) {
|
|
1934
|
+
return order.filter((r) => value[r] === "expanded");
|
|
1935
|
+
}
|
|
1936
|
+
var RECOMMENDED_MAX_PANES = /* @__PURE__ */ Object.freeze({
|
|
1937
|
+
compact: 1,
|
|
1938
|
+
medium: 1,
|
|
1939
|
+
expanded: 2,
|
|
1940
|
+
large: 2,
|
|
1941
|
+
"extra-large": 3
|
|
1942
|
+
});
|
|
1943
|
+
function threePaneScaffoldDirective(sizeClass, options = {}) {
|
|
1944
|
+
const directive = paneScaffoldDirective(sizeClass, options);
|
|
1945
|
+
if (options.paneRule === "compose") return directive;
|
|
1946
|
+
return {
|
|
1947
|
+
...directive,
|
|
1948
|
+
maxHorizontalPartitions: Math.min(
|
|
1949
|
+
directive.maxHorizontalPartitions,
|
|
1950
|
+
RECOMMENDED_MAX_PANES[sizeClass.widthClass]
|
|
1951
|
+
)
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
var LIST_DETAIL_INITIAL_HISTORY = [
|
|
1955
|
+
{ pane: "secondary" }
|
|
1956
|
+
];
|
|
1957
|
+
var SUPPORTING_PANE_INITIAL_HISTORY = [
|
|
1958
|
+
{ pane: "primary" }
|
|
1959
|
+
];
|
|
1960
|
+
var ThreePaneScaffoldNavigator = class {
|
|
1961
|
+
#history;
|
|
1962
|
+
#directive;
|
|
1963
|
+
#strategies;
|
|
1964
|
+
#historyAware;
|
|
1965
|
+
#value;
|
|
1966
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
1967
|
+
constructor(options) {
|
|
1968
|
+
this.#history = [...options.initialDestinationHistory];
|
|
1969
|
+
this.#directive = options.scaffoldDirective;
|
|
1970
|
+
this.#strategies = options.adaptStrategies;
|
|
1971
|
+
this.#historyAware = options.isDestinationHistoryAware ?? true;
|
|
1972
|
+
this.#value = this.#calculate(this.#history.length - 1);
|
|
1973
|
+
}
|
|
1974
|
+
get scaffoldDirective() {
|
|
1975
|
+
return this.#directive;
|
|
1976
|
+
}
|
|
1977
|
+
set scaffoldDirective(directive) {
|
|
1978
|
+
this.#directive = directive;
|
|
1979
|
+
this.#recalculate();
|
|
1980
|
+
}
|
|
1981
|
+
get adaptStrategies() {
|
|
1982
|
+
return this.#strategies;
|
|
1983
|
+
}
|
|
1984
|
+
set adaptStrategies(strategies) {
|
|
1985
|
+
this.#strategies = strategies;
|
|
1986
|
+
this.#recalculate();
|
|
1987
|
+
}
|
|
1988
|
+
get isDestinationHistoryAware() {
|
|
1989
|
+
return this.#historyAware;
|
|
1990
|
+
}
|
|
1991
|
+
set isDestinationHistoryAware(aware) {
|
|
1992
|
+
this.#historyAware = aware;
|
|
1993
|
+
this.#recalculate();
|
|
1994
|
+
}
|
|
1995
|
+
/** The destination history, oldest first. */
|
|
1996
|
+
get destinationHistory() {
|
|
1997
|
+
return this.#history;
|
|
1998
|
+
}
|
|
1999
|
+
get currentDestination() {
|
|
2000
|
+
return this.#history[this.#history.length - 1] ?? null;
|
|
2001
|
+
}
|
|
2002
|
+
get scaffoldValue() {
|
|
2003
|
+
return this.#value;
|
|
2004
|
+
}
|
|
2005
|
+
/** Calls `listener` after every change of the history or the value; returns the unsubscriber. */
|
|
2006
|
+
subscribe(listener) {
|
|
2007
|
+
this.#listeners.add(listener);
|
|
2008
|
+
return () => {
|
|
2009
|
+
this.#listeners.delete(listener);
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
peekPreviousScaffoldValue(behavior = "pop-until-scaffold-value-change") {
|
|
2013
|
+
const index = this.#previousIndex(behavior);
|
|
2014
|
+
return index === -1 ? this.#value : this.#calculate(index);
|
|
2015
|
+
}
|
|
2016
|
+
navigateTo(pane, contentKey) {
|
|
2017
|
+
this.#history.push({ pane, contentKey });
|
|
2018
|
+
this.#recalculate(true);
|
|
2019
|
+
}
|
|
2020
|
+
canNavigateBack(behavior = "pop-until-scaffold-value-change") {
|
|
2021
|
+
return this.#previousIndex(behavior) >= 0;
|
|
2022
|
+
}
|
|
2023
|
+
/** Returns true when there was a destination to go back to (else the history is cleared). */
|
|
2024
|
+
navigateBack(behavior = "pop-until-scaffold-value-change") {
|
|
2025
|
+
const previous = this.#previousIndex(behavior);
|
|
2026
|
+
if (previous < 0) {
|
|
2027
|
+
this.#history = [];
|
|
2028
|
+
this.#recalculate(true);
|
|
2029
|
+
return false;
|
|
2030
|
+
}
|
|
2031
|
+
this.#history.length = previous + 1;
|
|
2032
|
+
this.#recalculate(true);
|
|
2033
|
+
return true;
|
|
2034
|
+
}
|
|
2035
|
+
#recalculate(force = false) {
|
|
2036
|
+
const next = this.#calculate(this.#history.length - 1);
|
|
2037
|
+
const changed = force || !sameThreePaneScaffoldValue(next, this.#value);
|
|
2038
|
+
this.#value = next;
|
|
2039
|
+
if (changed) for (const listener of [...this.#listeners]) listener();
|
|
2040
|
+
}
|
|
2041
|
+
/** getPreviousDestinationIndex (L430-466). */
|
|
2042
|
+
#previousIndex(behavior) {
|
|
2043
|
+
const history = this.#history;
|
|
2044
|
+
if (history.length <= 1) return -1;
|
|
2045
|
+
const last = history.length - 1;
|
|
2046
|
+
const current = history[last];
|
|
2047
|
+
for (let i = last - 1; i >= 0; i--) {
|
|
2048
|
+
const item = history[i];
|
|
2049
|
+
if (!item) continue;
|
|
2050
|
+
switch (behavior) {
|
|
2051
|
+
case "pop-latest":
|
|
2052
|
+
return i;
|
|
2053
|
+
case "pop-until-scaffold-value-change":
|
|
2054
|
+
if (!sameThreePaneScaffoldValue(this.#calculate(i), this.#value)) return i;
|
|
2055
|
+
break;
|
|
2056
|
+
case "pop-until-current-destination-change":
|
|
2057
|
+
if (item.pane !== current?.pane) return i;
|
|
2058
|
+
break;
|
|
2059
|
+
case "pop-until-content-change":
|
|
2060
|
+
if (!Object.is(item.contentKey, current?.contentKey)) return i;
|
|
2061
|
+
if (!sameThreePaneScaffoldValue(this.#calculate(i), this.#value)) return i;
|
|
2062
|
+
break;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
return -1;
|
|
2066
|
+
}
|
|
2067
|
+
/** calculateScaffoldValue (L468-490). */
|
|
2068
|
+
#calculate(index) {
|
|
2069
|
+
const { maxHorizontalPartitions, maxVerticalPartitions } = this.#directive;
|
|
2070
|
+
const history = index === -1 ? [] : this.#historyAware ? this.#history.slice(0, index + 1) : this.#history.slice(index, index + 1);
|
|
2071
|
+
return calculateThreePaneScaffoldValue(
|
|
2072
|
+
maxHorizontalPartitions,
|
|
2073
|
+
this.#strategies,
|
|
2074
|
+
history,
|
|
2075
|
+
maxVerticalPartitions
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
function threePaneScaffoldLayout(input) {
|
|
2080
|
+
const { width: W, height: H, directive, value, order } = input;
|
|
2081
|
+
const present = input.present ?? THREE_PANE_SCAFFOLD_ROLES;
|
|
2082
|
+
const make = (role) => ({
|
|
2083
|
+
role,
|
|
2084
|
+
width: input.preferredWidths?.[role] ?? directive.defaultPanePreferredWidth,
|
|
2085
|
+
height: input.preferredHeights?.[role] ?? directive.defaultPanePreferredHeight,
|
|
2086
|
+
bounds: null
|
|
2087
|
+
});
|
|
2088
|
+
const select = (pick2) => order.filter((r) => present.includes(r) && pick2(value[r])).map(make);
|
|
2089
|
+
const expanded = select((v) => v === "expanded");
|
|
2090
|
+
const reflowed = select((v) => v === "reflowed");
|
|
2091
|
+
const spacer = directive.horizontalPartitionSpacerSize;
|
|
2092
|
+
const vSpacer = directive.verticalPartitionSpacerSize;
|
|
2093
|
+
const outer = { x: 0, y: 0, width: W, height: H };
|
|
2094
|
+
const right = (r) => r.x + r.width;
|
|
2095
|
+
const between = (left, rightEdge) => ({
|
|
2096
|
+
x: left,
|
|
2097
|
+
y: 0,
|
|
2098
|
+
width: rightEdge - left,
|
|
2099
|
+
height: H
|
|
2100
|
+
});
|
|
2101
|
+
const inPartition = (partition, pane) => {
|
|
2102
|
+
const flowed = reflowed[0];
|
|
2103
|
+
const strategy = flowed ? input.adaptStrategies[flowed.role] : "hide";
|
|
2104
|
+
if (flowed && strategy !== "hide" && strategy.reflowUnder === pane.role) {
|
|
2105
|
+
const available = partition.height - vSpacer;
|
|
2106
|
+
pane.height = Math.max(available - flowed.height, Math.trunc(available / 2));
|
|
2107
|
+
flowed.height = available - pane.height;
|
|
2108
|
+
flowed.bounds = {
|
|
2109
|
+
x: partition.x,
|
|
2110
|
+
y: partition.y + pane.height + vSpacer,
|
|
2111
|
+
width: partition.width,
|
|
2112
|
+
height: partition.height - pane.height - vSpacer
|
|
2113
|
+
};
|
|
2114
|
+
} else {
|
|
2115
|
+
pane.height = partition.height;
|
|
2116
|
+
}
|
|
2117
|
+
pane.bounds = { ...partition, height: pane.height };
|
|
2118
|
+
};
|
|
2119
|
+
const partitions = (bounds, panes2) => {
|
|
2120
|
+
if (panes2.length === 0) return;
|
|
2121
|
+
const allocatable = bounds.width - (panes2.length - 1) * spacer;
|
|
2122
|
+
const total = panes2.reduce((sum, p) => sum + p.width, 0);
|
|
2123
|
+
if (allocatable > total) {
|
|
2124
|
+
const top = panes2.reduce((a, b) => PRIORITY[b.role] > PRIORITY[a.role] ? b : a);
|
|
2125
|
+
top.width += allocatable - total;
|
|
2126
|
+
} else if (allocatable < total) {
|
|
2127
|
+
const scale = Math.fround(allocatable / total);
|
|
2128
|
+
for (const p of panes2) p.width = Math.trunc(Math.fround(p.width * scale));
|
|
2129
|
+
}
|
|
2130
|
+
let x = bounds.x;
|
|
2131
|
+
for (const p of panes2) {
|
|
2132
|
+
inPartition({ x, y: bounds.y, width: p.width, height: bounds.height }, p);
|
|
2133
|
+
x += p.width + spacer;
|
|
2134
|
+
}
|
|
2135
|
+
};
|
|
2136
|
+
const expansion = input.expansion;
|
|
2137
|
+
const first = expanded[0];
|
|
2138
|
+
const second = expanded[1];
|
|
2139
|
+
const dragging = expansion?.draggingOffset;
|
|
2140
|
+
const resting = expansion?.firstPaneWidth;
|
|
2141
|
+
if (expanded.length === 2 && first && second && (dragging !== void 0 || resting !== void 0)) {
|
|
2142
|
+
const half = Math.trunc(spacer / 2);
|
|
2143
|
+
if (dragging !== void 0) {
|
|
2144
|
+
if (dragging <= half)
|
|
2145
|
+
inPartition({ ...outer, x: dragging * 2, width: W - dragging * 2 }, second);
|
|
2146
|
+
else if (dragging >= W - half) inPartition({ ...outer, width: dragging * 2 - W }, first);
|
|
2147
|
+
else {
|
|
2148
|
+
inPartition(between(0, dragging - half), first);
|
|
2149
|
+
inPartition(between(dragging + half, W), second);
|
|
2150
|
+
}
|
|
2151
|
+
} else if (resting !== void 0) {
|
|
2152
|
+
const firstWidth = Math.max(0, Math.min(resting, W));
|
|
2153
|
+
if (firstWidth === 0) inPartition(outer, second);
|
|
2154
|
+
else if (firstWidth >= W - spacer) inPartition(outer, first);
|
|
2155
|
+
else {
|
|
2156
|
+
inPartition(between(0, firstWidth), first);
|
|
2157
|
+
inPartition(between(firstWidth + spacer, W), second);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
} else {
|
|
2161
|
+
partitions(outer, expanded);
|
|
2162
|
+
}
|
|
2163
|
+
let handleOffset = null;
|
|
2164
|
+
if (expanded.length === 2 && first && second) {
|
|
2165
|
+
if (dragging !== void 0) handleOffset = dragging;
|
|
2166
|
+
else if (first.bounds && second.bounds)
|
|
2167
|
+
handleOffset = Math.trunc((right(first.bounds) + second.bounds.x) / 2);
|
|
2168
|
+
else if (first.bounds) handleOffset = right(first.bounds);
|
|
2169
|
+
else if (second.bounds) handleOffset = 0;
|
|
2170
|
+
}
|
|
2171
|
+
const panes = {};
|
|
2172
|
+
for (const p of [...expanded, ...reflowed]) {
|
|
2173
|
+
panes[p.role] = p.bounds ?? { x: 0, y: 0, width: 0, height: 0 };
|
|
2174
|
+
}
|
|
2175
|
+
return { panes, handleOffset };
|
|
2176
|
+
}
|
|
2177
|
+
var motionType = (motion) => motion === "none" ? "hidden" : motion === "animate-bounds" ? "shown" : motion.startsWith("enter") ? "entering" : "exiting";
|
|
2178
|
+
function typeOf(previous, current) {
|
|
2179
|
+
const was = previous !== "hidden";
|
|
2180
|
+
const is = current !== "hidden";
|
|
2181
|
+
return was && is ? "shown" : was ? "exiting" : is ? "entering" : "hidden";
|
|
2182
|
+
}
|
|
2183
|
+
function calculatePaneMotion(previous, current, order) {
|
|
2184
|
+
const n = order.length;
|
|
2185
|
+
const types = order.map((r) => typeOf(previous[r], current[r]));
|
|
2186
|
+
const motions = order.map(() => "none");
|
|
2187
|
+
let firstShown = n;
|
|
2188
|
+
let firstEntering = n;
|
|
2189
|
+
let lastShown = -1;
|
|
2190
|
+
let lastEntering = -1;
|
|
2191
|
+
types.forEach((t, i) => {
|
|
2192
|
+
if (t === "shown") {
|
|
2193
|
+
firstShown = Math.min(firstShown, i);
|
|
2194
|
+
lastShown = Math.max(lastShown, i);
|
|
2195
|
+
motions[i] = "animate-bounds";
|
|
2196
|
+
} else if (t === "entering") {
|
|
2197
|
+
firstEntering = Math.min(firstEntering, i);
|
|
2198
|
+
lastEntering = Math.max(lastEntering, i);
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
let exitRight = false;
|
|
2202
|
+
let exitLeft = false;
|
|
2203
|
+
let firstExitRight = n;
|
|
2204
|
+
let lastExitLeft = -1;
|
|
2205
|
+
types.forEach((t, i) => {
|
|
2206
|
+
if (t !== "exiting") return;
|
|
2207
|
+
const shownLeft = firstShown < i;
|
|
2208
|
+
const enteringLeft = firstEntering < i;
|
|
2209
|
+
const shownRight = lastShown > i;
|
|
2210
|
+
const enteringRight = lastEntering > i;
|
|
2211
|
+
const toRight = () => {
|
|
2212
|
+
exitRight = true;
|
|
2213
|
+
firstExitRight = Math.min(firstExitRight, i);
|
|
2214
|
+
motions[i] = "exit-to-right";
|
|
2215
|
+
};
|
|
2216
|
+
const toLeft = () => {
|
|
2217
|
+
exitLeft = true;
|
|
2218
|
+
lastExitLeft = Math.max(lastExitLeft, i);
|
|
2219
|
+
motions[i] = "exit-to-left";
|
|
2220
|
+
};
|
|
2221
|
+
if (!shownRight && !enteringRight) toRight();
|
|
2222
|
+
else if (!shownLeft && !enteringLeft) toLeft();
|
|
2223
|
+
else if (!shownRight) toRight();
|
|
2224
|
+
else if (!shownLeft) toLeft();
|
|
2225
|
+
else motions[i] = "exit-with-shrink";
|
|
2226
|
+
});
|
|
2227
|
+
types.forEach((t, i) => {
|
|
2228
|
+
if (t !== "entering") return;
|
|
2229
|
+
const freeRight = !(lastShown > i) && !(lastExitLeft > i);
|
|
2230
|
+
const freeLeft = !(firstShown < i) && !(firstExitRight < i);
|
|
2231
|
+
motions[i] = freeRight && !exitRight ? "enter-from-right" : freeLeft && !exitLeft ? "enter-from-left" : freeRight ? "enter-from-right-delayed" : freeLeft ? "enter-from-left-delayed" : "enter-with-expand";
|
|
2232
|
+
});
|
|
2233
|
+
const out = { primary: "none", secondary: "none", tertiary: "none" };
|
|
2234
|
+
order.forEach((r, i) => {
|
|
2235
|
+
out[r] = motions[i] ?? "none";
|
|
2236
|
+
});
|
|
2237
|
+
return out;
|
|
2238
|
+
}
|
|
2239
|
+
var PANE_MOTION_DELAYED_RATIO = 0.1;
|
|
2240
|
+
function paneTransitions(motions, order, origin, target, scaffoldWidth) {
|
|
2241
|
+
const zero = { x: 0, y: 0, width: 0, height: 0 };
|
|
2242
|
+
const t = (r) => target[r] ?? origin[r] ?? zero;
|
|
2243
|
+
const o = (r) => origin[r] ?? target[r] ?? zero;
|
|
2244
|
+
const type = (r) => motionType(motions[r]);
|
|
2245
|
+
const shown = (r, other) => type(r) === "shown" || type(r) === other;
|
|
2246
|
+
const reversed = [...order].reverse();
|
|
2247
|
+
const slideInFromLeft = () => {
|
|
2248
|
+
let previous = null;
|
|
2249
|
+
for (const r of reversed) {
|
|
2250
|
+
const m = motions[r];
|
|
2251
|
+
if (m === "enter-from-left" || m === "enter-from-left-delayed")
|
|
2252
|
+
return -(previous ? t(previous).x : t(r).x + t(r).width);
|
|
2253
|
+
if (shown(r, "entering")) previous = r;
|
|
2254
|
+
}
|
|
2255
|
+
return 0;
|
|
2256
|
+
};
|
|
2257
|
+
const slideInFromRight = () => {
|
|
2258
|
+
let previous = null;
|
|
2259
|
+
for (const r of order) {
|
|
2260
|
+
const m = motions[r];
|
|
2261
|
+
if (m === "enter-from-right" || m === "enter-from-right-delayed")
|
|
2262
|
+
return scaffoldWidth - (previous ? t(previous).x + t(previous).width : t(r).x);
|
|
2263
|
+
if (shown(r, "entering")) previous = r;
|
|
2264
|
+
}
|
|
2265
|
+
return 0;
|
|
2266
|
+
};
|
|
2267
|
+
const slideOutToLeft = () => {
|
|
2268
|
+
let previous = null;
|
|
2269
|
+
for (const r of reversed) {
|
|
2270
|
+
if (motions[r] === "exit-to-left") return -(previous ? o(previous).x : o(r).x + o(r).width);
|
|
2271
|
+
if (shown(r, "exiting")) previous = r;
|
|
2272
|
+
}
|
|
2273
|
+
return 0;
|
|
2274
|
+
};
|
|
2275
|
+
const slideOutToRight = () => {
|
|
2276
|
+
let previous = null;
|
|
2277
|
+
for (const r of order) {
|
|
2278
|
+
if (motions[r] === "exit-to-right")
|
|
2279
|
+
return scaffoldWidth - (previous ? o(previous).x + o(previous).width : o(r).x);
|
|
2280
|
+
if (shown(r, "exiting")) previous = r;
|
|
2281
|
+
}
|
|
2282
|
+
return 0;
|
|
2283
|
+
};
|
|
2284
|
+
const leftEdge = (role, other, rect) => {
|
|
2285
|
+
let edge = 0;
|
|
2286
|
+
for (const r of order) {
|
|
2287
|
+
if (r === role) return edge;
|
|
2288
|
+
if (shown(r, other)) edge = rect(r).x + rect(r).width;
|
|
2289
|
+
}
|
|
2290
|
+
return edge;
|
|
2291
|
+
};
|
|
2292
|
+
const out = {};
|
|
2293
|
+
for (const r of order) {
|
|
2294
|
+
const motion = motions[r];
|
|
2295
|
+
const to2 = t(r);
|
|
2296
|
+
const from = o(r);
|
|
2297
|
+
const shift = (rect, dx) => ({ ...rect, x: rect.x + dx });
|
|
2298
|
+
let transition = null;
|
|
2299
|
+
switch (motion) {
|
|
2300
|
+
case "animate-bounds":
|
|
2301
|
+
transition = { motion, from, to: to2, delayed: false };
|
|
2302
|
+
break;
|
|
2303
|
+
case "enter-from-left":
|
|
2304
|
+
case "enter-from-left-delayed":
|
|
2305
|
+
transition = {
|
|
2306
|
+
motion,
|
|
2307
|
+
from: shift(to2, slideInFromLeft()),
|
|
2308
|
+
to: to2,
|
|
2309
|
+
delayed: motion.endsWith("delayed")
|
|
2310
|
+
};
|
|
2311
|
+
break;
|
|
2312
|
+
case "enter-from-right":
|
|
2313
|
+
case "enter-from-right-delayed":
|
|
2314
|
+
transition = {
|
|
2315
|
+
motion,
|
|
2316
|
+
from: shift(to2, slideInFromRight()),
|
|
2317
|
+
to: to2,
|
|
2318
|
+
delayed: motion.endsWith("delayed")
|
|
2319
|
+
};
|
|
2320
|
+
break;
|
|
2321
|
+
case "enter-with-expand":
|
|
2322
|
+
transition = {
|
|
2323
|
+
motion,
|
|
2324
|
+
from: { ...to2, x: leftEdge(r, "exiting", o), width: 0 },
|
|
2325
|
+
to: to2,
|
|
2326
|
+
delayed: false
|
|
2327
|
+
};
|
|
2328
|
+
break;
|
|
2329
|
+
case "exit-to-left":
|
|
2330
|
+
transition = { motion, from, to: shift(from, slideOutToLeft()), delayed: false };
|
|
2331
|
+
break;
|
|
2332
|
+
case "exit-to-right":
|
|
2333
|
+
transition = { motion, from, to: shift(from, slideOutToRight()), delayed: false };
|
|
2334
|
+
break;
|
|
2335
|
+
case "exit-with-shrink":
|
|
2336
|
+
transition = {
|
|
2337
|
+
motion,
|
|
2338
|
+
from,
|
|
2339
|
+
to: { ...from, x: leftEdge(r, "entering", t), width: 0 },
|
|
2340
|
+
delayed: false
|
|
2341
|
+
};
|
|
2342
|
+
break;
|
|
2343
|
+
}
|
|
2344
|
+
if (transition) out[r] = transition;
|
|
2345
|
+
}
|
|
2346
|
+
return out;
|
|
2347
|
+
}
|
|
2348
|
+
var PANE_EXPANSION_SAMPLE_ANCHORS = [
|
|
2349
|
+
{ proportion: 0 },
|
|
2350
|
+
{ offsetFromStart: 240 },
|
|
2351
|
+
{ proportion: 0.5 },
|
|
2352
|
+
{ offsetFromEnd: 240 },
|
|
2353
|
+
{ proportion: 1 }
|
|
2354
|
+
];
|
|
2355
|
+
var PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD = 200;
|
|
2356
|
+
function paneExpansionAnchorPosition(anchor, width, rtl = false) {
|
|
2357
|
+
const offset = "proportion" in anchor ? Math.min(Math.max(Math.round(width * anchor.proportion), 0), width) : "offsetFromStart" in anchor ? Math.round(anchor.offsetFromStart) : width - Math.round(anchor.offsetFromEnd);
|
|
2358
|
+
return rtl ? width - offset : offset;
|
|
2359
|
+
}
|
|
2360
|
+
function closestPaneExpansionAnchor(anchors, width, position, velocity, rtl = false) {
|
|
2361
|
+
let best = -1;
|
|
2362
|
+
let bestScore = Infinity;
|
|
2363
|
+
const candidates2 = [];
|
|
2364
|
+
anchors.forEach((anchor, index) => {
|
|
2365
|
+
const at2 = paneExpansionAnchorPosition(anchor, width, rtl);
|
|
2366
|
+
let score;
|
|
2367
|
+
if (velocity >= PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD) {
|
|
2368
|
+
const delta = at2 - position;
|
|
2369
|
+
score = delta < 0 ? width - delta : delta;
|
|
2370
|
+
} else if (velocity <= -PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD) {
|
|
2371
|
+
const delta = position - at2;
|
|
2372
|
+
score = delta < 0 ? width - delta : delta;
|
|
2373
|
+
} else score = Math.abs(position - at2);
|
|
2374
|
+
candidates2.push({ at: at2, index, score });
|
|
2375
|
+
});
|
|
2376
|
+
candidates2.sort((a, b) => a.at - b.at || a.index - b.index);
|
|
2377
|
+
for (const c of candidates2) {
|
|
2378
|
+
if (c.score < bestScore) {
|
|
2379
|
+
best = c.index;
|
|
2380
|
+
bestScore = c.score;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
return best;
|
|
2384
|
+
}
|
|
2385
|
+
function nextPaneExpansionAnchor(anchors, width, position, rtl = false) {
|
|
2386
|
+
const sorted = anchors.map((anchor, index) => ({ at: paneExpansionAnchorPosition(anchor, width, rtl), index })).sort((a, b) => a.at - b.at || a.index - b.index);
|
|
2387
|
+
return (sorted.find((a) => position < a.at) ?? sorted[0])?.index ?? -1;
|
|
2388
|
+
}
|
|
2389
|
+
var PANE_MOTION_VISIBILITY_THRESHOLD = 1;
|
|
2390
|
+
var KEYS = ["x", "y", "width", "height"];
|
|
2391
|
+
var ThreePaneScaffoldAnimation = class {
|
|
2392
|
+
#panes = /* @__PURE__ */ new Map();
|
|
2393
|
+
start(transitions, spec, now) {
|
|
2394
|
+
const next = /* @__PURE__ */ new Map();
|
|
2395
|
+
for (const role of THREE_PANE_SCAFFOLD_ROLES) {
|
|
2396
|
+
const transition = transitions[role];
|
|
2397
|
+
if (!transition) continue;
|
|
2398
|
+
const { from, to: to2 } = transition;
|
|
2399
|
+
const previous = this.#panes.get(role);
|
|
2400
|
+
if (previous) for (const k of KEYS) previous.springs[k].sample(now);
|
|
2401
|
+
const springs = previous?.springs ?? Object.fromEntries(
|
|
2402
|
+
KEYS.map((k) => [k, new SpringAnimatable(from[k], PANE_MOTION_VISIBILITY_THRESHOLD)])
|
|
2403
|
+
);
|
|
2404
|
+
const pane = { springs, to: to2, spec, delayUntil: null };
|
|
2405
|
+
if (transition.delayed && spec !== null && !previous) {
|
|
2406
|
+
const duration = Math.max(
|
|
2407
|
+
...KEYS.map(
|
|
2408
|
+
(k) => springDurationMillis(spec, from[k], to2[k], 0, PANE_MOTION_VISIBILITY_THRESHOLD)
|
|
2409
|
+
)
|
|
2410
|
+
);
|
|
2411
|
+
pane.delayUntil = now + Math.trunc(duration * PANE_MOTION_DELAYED_RATIO);
|
|
2412
|
+
} else {
|
|
2413
|
+
for (const k of KEYS) springs[k].animateTo(to2[k], spec, now);
|
|
2414
|
+
}
|
|
2415
|
+
next.set(role, pane);
|
|
2416
|
+
}
|
|
2417
|
+
this.#panes = next;
|
|
2418
|
+
}
|
|
2419
|
+
/** Jumps every pane to its target. */
|
|
2420
|
+
finish() {
|
|
2421
|
+
for (const pane of this.#panes.values()) {
|
|
2422
|
+
pane.delayUntil = null;
|
|
2423
|
+
for (const k of KEYS) pane.springs[k].snapTo(pane.to[k]);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
sample(now) {
|
|
2427
|
+
const panes = {};
|
|
2428
|
+
let running = false;
|
|
2429
|
+
for (const [role, pane] of this.#panes) {
|
|
2430
|
+
const s = pane.springs;
|
|
2431
|
+
if (pane.delayUntil !== null && now >= pane.delayUntil) {
|
|
2432
|
+
for (const k of KEYS) s[k].animateTo(pane.to[k], pane.spec, pane.delayUntil);
|
|
2433
|
+
pane.delayUntil = null;
|
|
2434
|
+
}
|
|
2435
|
+
panes[role] = {
|
|
2436
|
+
x: s.x.sample(now),
|
|
2437
|
+
y: s.y.sample(now),
|
|
2438
|
+
width: Math.max(0, s.width.sample(now)),
|
|
2439
|
+
height: Math.max(0, s.height.sample(now))
|
|
2440
|
+
};
|
|
2441
|
+
if (pane.delayUntil !== null || KEYS.some((k) => s[k].isRunning)) running = true;
|
|
2442
|
+
}
|
|
2443
|
+
return { panes, running };
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
|
|
2447
|
+
export { AmplitudeAnimation, DEFAULT_DISPLACEMENT_THRESHOLD, DRAWER_POSITIONAL_THRESHOLD, DRAWER_SETTLE_MILLIS, DRAWER_VELOCITY_THRESHOLD, DrawerAnimation, FAST_OUT_LINEAR_IN_EASING, LIST_DETAIL_ADAPT_STRATEGIES, LIST_DETAIL_INITIAL_HISTORY, LIST_DETAIL_PANE_ORDER, ListDetailPaneScaffoldRole, MODAL_RAIL_EXPANDED_PROGRESS, NAVIGATION_SUITE_EXPANDED_FROM, NAVIGATION_SUITE_TYPES, NavigationSuiteScaffoldAnimation, PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD, PANE_EXPANSION_SAMPLE_ANCHORS, PANE_MOTION_DELAYED_RATIO, PANE_MOTION_VISIBILITY_THRESHOLD, RECOMMENDED_MAX_PANES, SEARCH_BAR_EXPANDED_THRESHOLD, SEARCH_DROPDOWN_VISIBLE_PROGRESS, SLIDER_KEY_DIVISIONS, SLIDER_PAGE_DIVISOR, SLIDER_PAGE_MAX_STEPS, SUPPORTING_PANE_ADAPT_STRATEGIES, SUPPORTING_PANE_INITIAL_HISTORY, SUPPORTING_PANE_ORDER, SearchBarAnimation, SpringAnimatable, SpringSimulation, SupportingPaneScaffoldRole, TAB_INDICATOR_MIN_WIDTH, THREE_PANE_SCAFFOLD_ROLES, TOP_TITLE_ALPHA_EASING, TYPEAHEAD_TIMEOUT_MS, TabIndicatorAnimation, TabScrollAnimation, ThreePaneScaffoldAnimation, ThreePaneScaffoldNavigator, TweenAnimatable, WINDOW_HEIGHT_BREAKPOINTS, WINDOW_WIDTH_BREAKPOINTS, WideNavigationRailAnimation, animatedInt, appBarScrollState, buttonGroupVisibleCount, buttonGroupWidths, calculatePaneMotion, calculateThreePaneScaffoldValue, circularIndeterminateFrame, closestPaneExpansionAnchor, collapsedFraction, cubicBezier, dampingCoefficient, dampingRatioFromCoefficient, drawerSettlesOpen, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, expandedPanes, exponentialDecayTarget, fabMenuItemVisible, floatingToolbarScrollState, indeterminateFrame, indicatorAmplitude, initialIndeterminateFrame, isAtLeastBreakpoint, isHeightAtLeastBreakpoint, isNavigationBarType, isScrolledUnder, isWidthAtLeastBreakpoint, linearIndeterminateFractions, menuNavigationTarget, menuPosition, menuTransformOrigin, morphSpringDurationMillis, navigationSuiteOffset, navigationSuiteType, nextPaneExpansionAnchor, overlappedFraction, paneExpansionAnchorPosition, paneScaffoldDirective, paneTransitions, parseCubicBezier, sameThreePaneScaffoldValue, sameWindowSizeClass, scrollAppBar, scrollFloatingToolbar, scrollToolbarExpansion, scrollableTabOffset, searchNavigationTarget, searchViewFrame, settleTarget, sliderClosestThumb, sliderFraction, sliderKeyAction, sliderKeyDelta, sliderKeyValue, sliderPageSteps, sliderSnap, sliderSteps, sliderThumbBounds, sliderThumbValue, sliderTickFractions, sliderTrackGeometry, sliderValueAt, springDurationMillis, springToLinear, springValue, springVelocity, tabIndicatorShift, tabIndicatorTarget, tabPositions, threePaneScaffoldDirective, threePaneScaffoldLayout, toolbarCollapsedFraction, toolbarExpansionScroll, toolbarNavigationTarget, toolbarSettleTarget, twoRowsFrame, typeSelectTarget, waveOffset, waveTravelMillis, wideNavigationRailItemWidth, wideNavigationRailWidth, windowHeightSizeClass, windowSizeClass, windowWidthSizeClass, withHeight, withHeightOffset, withToolbarOffset, withToolbarOffsetLimit };
|
|
1035
2448
|
//# sourceMappingURL=index.js.map
|
|
1036
2449
|
//# sourceMappingURL=index.js.map
|