@flemo/core 1.1.2 → 1.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.
@@ -12,6 +12,7 @@ interface HistoryStore {
12
12
  addHistory: (history: History) => void;
13
13
  replaceHistory: (index: number) => void;
14
14
  popHistory: (index: number) => void;
15
+ popHistories: (count: number) => void;
15
16
  }
16
17
  declare const useHistoryStore: import('zustand').UseBoundStore<import('zustand').StoreApi<HistoryStore>>;
17
18
  export default useHistoryStore;
package/dist/index.mjs CHANGED
@@ -68,7 +68,7 @@ class Q {
68
68
  return new Promise((a, r) => {
69
69
  this.taskQueue = this.taskQueue.then(async () => {
70
70
  try {
71
- const { control: o, validate: c, rollback: l, dependencies: u = [], delay: d } = e, m = new AbortController(), i = {
71
+ const { control: o, validate: c, rollback: l, dependencies: u = [], delay: d } = e, p = new AbortController(), i = {
72
72
  id: s,
73
73
  execute: t,
74
74
  timestamp: Date.now(),
@@ -79,7 +79,7 @@ class Q {
79
79
  validate: c,
80
80
  rollback: l,
81
81
  control: o,
82
- abortController: m
82
+ abortController: p
83
83
  };
84
84
  this.tasks.set(i.id, i), this.pendingTaskQueue.length > 0 && (this.pendingTaskQueue.push(i), await this.waitForPendingTasks(), this.pendingTaskQueue = this.pendingTaskQueue.filter((P) => P.id !== i.id));
85
85
  try {
@@ -95,7 +95,7 @@ class Q {
95
95
  if (i.validate && !await i.validate())
96
96
  throw i.status = "FAILED", new Error("FAILED");
97
97
  d && d > 0 && await new Promise((f) => setTimeout(f, d));
98
- const p = await i.execute(i.abortController);
98
+ const h = await i.execute(i.abortController);
99
99
  if (i.abortController.signal.aborted) {
100
100
  i.status = "COMPLETED", await this.onTaskStatusChange(i.id, "COMPLETED"), a({
101
101
  success: !0,
@@ -109,32 +109,32 @@ class Q {
109
109
  if (e.control) {
110
110
  const f = e.control;
111
111
  if (f.delay && f.delay > 0 && await new Promise((y) => setTimeout(y, f.delay)), f.manual) {
112
- i.status = "MANUAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: p }, this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "MANUAL_PENDING");
112
+ i.status = "MANUAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: h }, this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "MANUAL_PENDING");
113
113
  return;
114
114
  }
115
115
  if (f.signal) {
116
- i.status = "SIGNAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: p }, this.signalListeners.has(f.signal) || this.signalListeners.set(f.signal, /* @__PURE__ */ new Set()), this.signalListeners.get(f.signal).add(i.id), this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "SIGNAL_PENDING");
116
+ i.status = "SIGNAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: h }, this.signalListeners.has(f.signal) || this.signalListeners.set(f.signal, /* @__PURE__ */ new Set()), this.signalListeners.get(f.signal).add(i.id), this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "SIGNAL_PENDING");
117
117
  return;
118
118
  }
119
119
  if (f.condition && !await f.condition()) {
120
- i.status = "MANUAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: p }, this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "MANUAL_PENDING");
120
+ i.status = "MANUAL_PENDING", i.manualResolver = { resolve: a, reject: r, result: h }, this.pendingTaskQueue.push(i), await this.onTaskStatusChange(i.id, "MANUAL_PENDING");
121
121
  return;
122
122
  }
123
123
  }
124
124
  i.status = "COMPLETED", await this.onTaskStatusChange(i.id, "COMPLETED"), a({
125
125
  success: !0,
126
- result: p,
126
+ result: h,
127
127
  taskId: i.id,
128
128
  timestamp: Date.now(),
129
129
  instanceId: this.instanceId
130
130
  });
131
- } catch (p) {
131
+ } catch (h) {
132
132
  if (i.status = "FAILED", i.rollback)
133
133
  try {
134
134
  await i.rollback(), i.status = "ROLLEDBACK";
135
135
  } catch {
136
136
  }
137
- throw await this.onTaskStatusChange(i.id, i.status), p;
137
+ throw await this.onTaskStatusChange(i.id, i.status), h;
138
138
  } finally {
139
139
  this.releaseLock(i.id);
140
140
  }
@@ -187,7 +187,20 @@ const yt = new Q(), Pt = w((n) => ({
187
187
  popHistory: (t) => n((e) => ({
188
188
  index: e.index - 1,
189
189
  histories: e.histories.filter((s, a) => a !== t)
190
- }))
190
+ })),
191
+ // Drop `count` entries sitting directly below the current top, keeping the
192
+ // top itself. Used by pop(n) to remove the screens it skips over in the same
193
+ // synchronous block that starts the transition — so they never paint — while
194
+ // the leaving top stays mounted to drive and resolve the animation.
195
+ popHistories: (t) => {
196
+ t <= 0 || n((e) => {
197
+ const s = e.index;
198
+ return {
199
+ index: e.index - t,
200
+ histories: e.histories.filter((a, r) => r < s - t || r >= s)
201
+ };
202
+ });
203
+ }
191
204
  })), gt = w((n) => ({
192
205
  status: "IDLE",
193
206
  transitionTaskId: null,
@@ -241,7 +254,7 @@ function kt({
241
254
  popOnExit: l,
242
255
  completedOnExit: u,
243
256
  completedOnEnter: d,
244
- options: m
257
+ options: p
245
258
  }) {
246
259
  return {
247
260
  name: n,
@@ -258,7 +271,7 @@ function kt({
258
271
  "COMPLETED-false": u,
259
272
  "COMPLETED-true": d
260
273
  },
261
- ...m
274
+ ...p
262
275
  };
263
276
  }
264
277
  const X = (n, t, e) => {
@@ -299,7 +312,7 @@ const X = (n, t, e) => {
299
312
  },
300
313
  exit: {
301
314
  value: {
302
- x: -100
315
+ x: "-30%"
303
316
  },
304
317
  options: {
305
318
  duration: 0.7,
@@ -332,7 +345,7 @@ const X = (n, t, e) => {
332
345
  ), e(
333
346
  a,
334
347
  {
335
- x: -100 + l
348
+ x: `${-30 + l * 0.3}%`
336
349
  },
337
350
  {
338
351
  duration: 0
@@ -355,7 +368,7 @@ const X = (n, t, e) => {
355
368
  e(
356
369
  a,
357
370
  {
358
- x: u ? 0 : -100
371
+ x: u ? 0 : "-30%"
359
372
  },
360
373
  {
361
374
  duration: 0.3,
@@ -420,7 +433,7 @@ const X = (n, t, e) => {
420
433
  swipeDirection: "y",
421
434
  onSwipeStart: async () => !0,
422
435
  onSwipe: (n, t, { animate: e, currentScreen: s, onProgress: a }) => {
423
- const { offset: r } = t, o = r.y, c = Math.max(0, Math.min(56, o)), l = z(c, [0, 56], [1, 0.96]), u = Math.max(0, o - 56), d = Math.min(1, u / 160), m = Math.sqrt(d) * 12, i = Math.max(0, c + m), h = Math.min(56, i);
436
+ const { offset: r } = t, o = r.y, c = Math.max(0, Math.min(56, o)), l = z(c, [0, 56], [1, 0.96]), u = Math.max(0, o - 56), d = Math.min(1, u / 160), p = Math.sqrt(d) * 12, i = Math.max(0, c + p), m = Math.min(56, i);
424
437
  return a?.(!0, 100), e(
425
438
  s,
426
439
  {
@@ -430,7 +443,7 @@ const X = (n, t, e) => {
430
443
  {
431
444
  duration: 0
432
445
  }
433
- ), h;
446
+ ), m;
434
447
  },
435
448
  onSwipeEnd: async (n, t, { animate: e, currentScreen: s, prevScreen: a, onStart: r }) => {
436
449
  const { offset: o, velocity: c } = t, u = o.y > 56 || c.y > 20;
@@ -465,7 +478,8 @@ const X = (n, t, e) => {
465
478
  },
466
479
  idle: {
467
480
  value: {
468
- y: 0
481
+ y: 0,
482
+ opacity: 1
469
483
  },
470
484
  options: {
471
485
  duration: 0
@@ -491,7 +505,8 @@ const X = (n, t, e) => {
491
505
  },
492
506
  exit: {
493
507
  value: {
494
- y: -56
508
+ y: -56,
509
+ opacity: 0
495
510
  },
496
511
  options: {
497
512
  duration: 0.35,
@@ -500,7 +515,8 @@ const X = (n, t, e) => {
500
515
  },
501
516
  exitBack: {
502
517
  value: {
503
- y: 0
518
+ y: 0,
519
+ opacity: 1
504
520
  },
505
521
  options: {
506
522
  duration: 0.25,
@@ -511,8 +527,8 @@ const X = (n, t, e) => {
511
527
  swipeDirection: "y",
512
528
  onSwipeStart: async () => !0,
513
529
  onSwipe: (n, t, { animate: e, currentScreen: s, prevScreen: a, onProgress: r }) => {
514
- const { offset: o } = t, c = o.y, l = Math.max(0, Math.min(56, c)), u = Math.max(0, c - 56), d = Math.min(1, u / 160), m = Math.sqrt(d) * 12, i = Math.max(0, l + m), h = Math.min(56, i);
515
- return r?.(!0, h), e(
530
+ const { offset: o } = t, c = o.y, l = Math.max(0, Math.min(56, c)), u = Math.max(0, c - 56), d = Math.min(1, u / 160), p = Math.sqrt(d) * 12, i = Math.max(0, l + p), m = Math.min(56, i);
531
+ return r?.(!0, m), e(
516
532
  s,
517
533
  {
518
534
  y: i
@@ -523,10 +539,11 @@ const X = (n, t, e) => {
523
539
  ), e(
524
540
  a,
525
541
  {
526
- y: -56 + h
542
+ y: -56 + m,
543
+ opacity: m / 56
527
544
  },
528
545
  { duration: 0 }
529
- ), h;
546
+ ), m;
530
547
  },
531
548
  onSwipeEnd: async (n, t, { animate: e, currentScreen: s, prevScreen: a, onStart: r }) => {
532
549
  const { offset: o, velocity: c } = t, u = o.y > 56 || c.y > 20;
@@ -544,7 +561,8 @@ const X = (n, t, e) => {
544
561
  e(
545
562
  a,
546
563
  {
547
- y: u ? 0 : -56
564
+ y: u ? 0 : -56,
565
+ opacity: u ? 1 : 0
548
566
  },
549
567
  {
550
568
  duration: u ? 0.22 : 0.24,
@@ -634,7 +652,7 @@ function Lt({
634
652
  popOnExit: l,
635
653
  completedOnEnter: u,
636
654
  completedOnExit: d,
637
- options: m
655
+ options: p
638
656
  }) {
639
657
  return {
640
658
  name: n,
@@ -651,7 +669,7 @@ function Lt({
651
669
  "COMPLETED-false": d,
652
670
  "COMPLETED-true": u
653
671
  },
654
- ...m
672
+ ...p
655
673
  };
656
674
  }
657
675
  const I = "rgba(0, 0, 0, 0.3)", q = K({
@@ -671,17 +689,22 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
671
689
  },
672
690
  // Visible dim — applied when this screen is the one going behind / sitting
673
691
  // behind a new active screen (PUSHING-false / REPLACING-false / COMPLETED-false).
674
- // Duration + easing track cupertino's enter/exit so the dim arrives in
675
- // lockstep with the underlying screen slide and there's no
676
- // animation-vs-hold-by-fill window for the rest-rule handoff to race against.
692
+ // Duration matches cupertino's enter so the dim resolves in lockstep with the
693
+ // underlying screen slide (and there's no animation-vs-hold-by-fill window for
694
+ // the rest-rule handoff to race against — that's a function of duration + fill,
695
+ // not the curve). Easing is intentionally left at the default: this animates
696
+ // `opacity` (a luminance channel), not position, so cupertino's positional
697
+ // decelerate curve would front-load the darkening into an abrupt step with a
698
+ // long invisible tail. The default ease spreads the perceived dim evenly across
699
+ // the duration, matching this decorator's linear-perceived-ramp design (see the
700
+ // DIM_COLOR note above).
677
701
  enter: {
678
702
  value: {
679
703
  opacity: 1,
680
704
  backgroundColor: I
681
705
  },
682
706
  options: {
683
- duration: 0.7,
684
- ease: [0.32, 0.72, 0, 1]
707
+ duration: 0.7
685
708
  }
686
709
  },
687
710
  // POPPING-false target: the previously-behind screen is returning to active.
@@ -694,8 +717,7 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
694
717
  backgroundColor: I
695
718
  },
696
719
  options: {
697
- duration: 0.6,
698
- ease: [0.32, 0.72, 0, 1]
720
+ duration: 0.6
699
721
  }
700
722
  },
701
723
  options: {
@@ -861,9 +883,9 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
861
883
  }, ct = (n, t) => {
862
884
  const [e, s] = t.split("-");
863
885
  return `[data-flemo-bar][data-flemo-bar-transition="${n}"][data-flemo-bar-status="${e}"][data-flemo-bar-active="${s}"][data-flemo-bar-riding="true"]`;
864
- }, ut = (n, t, e) => `flemo-${n}-${J(t)}-${e}`, C = (n, t, e, s, a, r) => {
865
- const o = g(s), c = g(a.value), l = H(a.options), u = U(a.options), d = it(a.options?.ease), m = r(t, e), i = n === "screen" ? `${m},
866
- ${ct(t, e)}` : m;
886
+ }, ut = (n, t, e) => `flemo-${n}-${J(t)}-${e}`, x = (n, t, e, s, a, r) => {
887
+ const o = g(s), c = g(a.value), l = H(a.options), u = U(a.options), d = it(a.options?.ease), p = r(t, e), i = n === "screen" ? `${p},
888
+ ${ct(t, e)}` : p;
867
889
  if (c.length === 0 && o.length === 0)
868
890
  return "";
869
891
  if (l <= 0 && u <= 0)
@@ -871,8 +893,8 @@ ${ct(t, e)}` : m;
871
893
  ${E(c)}
872
894
  animation: none;
873
895
  }`;
874
- const h = ut(n, t, e), P = [
875
- `@keyframes ${h} {`,
896
+ const m = ut(n, t, e), P = [
897
+ `@keyframes ${m} {`,
876
898
  " from {",
877
899
  E(o).replace(/^/gm, " "),
878
900
  " }",
@@ -881,8 +903,8 @@ ${E(c)}
881
903
  " }",
882
904
  "}"
883
905
  ].join(`
884
- `), p = [
885
- `${h}`,
906
+ `), h = [
907
+ `${m}`,
886
908
  `${l}s`,
887
909
  d,
888
910
  u > 0 ? `${u}s` : null,
@@ -891,13 +913,13 @@ ${E(c)}
891
913
  /* @__PURE__ */ new Set([...o.map((N) => N.property), ...c.map((N) => N.property)])
892
914
  ), y = f.length > 0 ? ` will-change: ${f.join(", ")};
893
915
  ` : "", S = e.split("-")[0], Y = `${i} {
894
- animation: ${p};
916
+ animation: ${h};
895
917
  ${y}${S === "PUSHING" || S === "REPLACING" ? ` contain: layout;
896
918
  pointer-events: none;
897
919
  ` : ""}}`;
898
920
  return `${P}
899
921
  ${Y}`;
900
- }, x = (n, t, e, s) => {
922
+ }, C = (n, t, e, s) => {
901
923
  const a = g(s.value);
902
924
  return a.length === 0 ? "" : `${n(t, e)} {
903
925
  ${E(a)}
@@ -909,12 +931,12 @@ ${E(a)}
909
931
  for (const r of O) {
910
932
  const o = s.variants[r], c = k[r];
911
933
  if (c === "self") {
912
- e.push(x(A, a, r, o));
934
+ e.push(C(A, a, r, o));
913
935
  continue;
914
936
  }
915
937
  const l = c === "initial" ? s.initial : s.variants[c].value;
916
938
  e.push(
917
- C("screen", a, r, l, o, A)
939
+ x("screen", a, r, l, o, A)
918
940
  );
919
941
  }
920
942
  }
@@ -923,12 +945,12 @@ ${E(a)}
923
945
  for (const r of W) {
924
946
  const o = s.variants[r], c = k[r];
925
947
  if (c === "self") {
926
- e.push(x(M, a, r, o));
948
+ e.push(C(M, a, r, o));
927
949
  continue;
928
950
  }
929
951
  const l = c === "initial" ? s.initial : s.variants[c].value;
930
952
  e.push(
931
- C(
953
+ x(
932
954
  "decorator",
933
955
  a,
934
956
  r,
@@ -960,7 +982,7 @@ function Mt(n, t, e) {
960
982
  const s = lt(n, t), a = B(s)(t), r = new URLSearchParams(e), o = Object.fromEntries(r.entries());
961
983
  return a ? { ...a.params, ...o } : {};
962
984
  }
963
- function Ct(n, t) {
985
+ function xt(n, t) {
964
986
  const {
965
987
  direction: e = "x",
966
988
  markerSelector: s = "[data-swipe-at-edge]",
@@ -1010,7 +1032,7 @@ export {
1010
1032
  F as cupertino,
1011
1033
  Dt as decoratorMap,
1012
1034
  it as easingToCss,
1013
- Ct as findScrollable,
1035
+ xt as findScrollable,
1014
1036
  lt as getMatchedPathPattern,
1015
1037
  Mt as getParams,
1016
1038
  At as isServer,
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flemo/core",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Framework-agnostic primitives for flemo: history, navigation, transitions, task manager.",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.mjs",