@flemo/core 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,8 @@ 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;
16
+ setTransitionName: (index: number, transitionName: TransitionName) => void;
15
17
  }
16
18
  declare const useHistoryStore: import('zustand').UseBoundStore<import('zustand').StoreApi<HistoryStore>>;
17
19
  export default useHistoryStore;
package/dist/index.mjs CHANGED
@@ -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,30 @@ 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
+ },
204
+ // Override one entry's transition. Used by pop() to relabel the leaving top
205
+ // before the POPPING flip so the back animation uses the caller's
206
+ // `transitionName` from the first frame — its original transition never
207
+ // paints. Returns a fresh array so the renderer re-reads it.
208
+ setTransitionName: (t, e) => n((s) => {
209
+ const a = s.histories[t];
210
+ if (!a || a.transitionName === e) return {};
211
+ const r = s.histories.slice();
212
+ return r[t] = { ...a, transitionName: e }, { histories: r };
213
+ })
191
214
  })), gt = w((n) => ({
192
215
  status: "IDLE",
193
216
  transitionTaskId: null,
@@ -299,7 +322,7 @@ const X = (n, t, e) => {
299
322
  },
300
323
  exit: {
301
324
  value: {
302
- x: -100
325
+ x: "-30%"
303
326
  },
304
327
  options: {
305
328
  duration: 0.7,
@@ -332,7 +355,7 @@ const X = (n, t, e) => {
332
355
  ), e(
333
356
  a,
334
357
  {
335
- x: -100 + l
358
+ x: `${-30 + l * 0.3}%`
336
359
  },
337
360
  {
338
361
  duration: 0
@@ -355,7 +378,7 @@ const X = (n, t, e) => {
355
378
  e(
356
379
  a,
357
380
  {
358
- x: u ? 0 : -100
381
+ x: u ? 0 : "-30%"
359
382
  },
360
383
  {
361
384
  duration: 0.3,
@@ -420,7 +443,7 @@ const X = (n, t, e) => {
420
443
  swipeDirection: "y",
421
444
  onSwipeStart: async () => !0,
422
445
  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);
446
+ 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), p = Math.min(56, i);
424
447
  return a?.(!0, 100), e(
425
448
  s,
426
449
  {
@@ -430,7 +453,7 @@ const X = (n, t, e) => {
430
453
  {
431
454
  duration: 0
432
455
  }
433
- ), h;
456
+ ), p;
434
457
  },
435
458
  onSwipeEnd: async (n, t, { animate: e, currentScreen: s, prevScreen: a, onStart: r }) => {
436
459
  const { offset: o, velocity: c } = t, u = o.y > 56 || c.y > 20;
@@ -465,7 +488,8 @@ const X = (n, t, e) => {
465
488
  },
466
489
  idle: {
467
490
  value: {
468
- y: 0
491
+ y: 0,
492
+ opacity: 1
469
493
  },
470
494
  options: {
471
495
  duration: 0
@@ -491,7 +515,8 @@ const X = (n, t, e) => {
491
515
  },
492
516
  exit: {
493
517
  value: {
494
- y: -56
518
+ y: -56,
519
+ opacity: 0
495
520
  },
496
521
  options: {
497
522
  duration: 0.35,
@@ -500,7 +525,8 @@ const X = (n, t, e) => {
500
525
  },
501
526
  exitBack: {
502
527
  value: {
503
- y: 0
528
+ y: 0,
529
+ opacity: 1
504
530
  },
505
531
  options: {
506
532
  duration: 0.25,
@@ -511,8 +537,8 @@ const X = (n, t, e) => {
511
537
  swipeDirection: "y",
512
538
  onSwipeStart: async () => !0,
513
539
  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(
540
+ 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), p = Math.min(56, i);
541
+ return r?.(!0, p), e(
516
542
  s,
517
543
  {
518
544
  y: i
@@ -523,10 +549,11 @@ const X = (n, t, e) => {
523
549
  ), e(
524
550
  a,
525
551
  {
526
- y: -56 + h
552
+ y: -56 + p,
553
+ opacity: p / 56
527
554
  },
528
555
  { duration: 0 }
529
- ), h;
556
+ ), p;
530
557
  },
531
558
  onSwipeEnd: async (n, t, { animate: e, currentScreen: s, prevScreen: a, onStart: r }) => {
532
559
  const { offset: o, velocity: c } = t, u = o.y > 56 || c.y > 20;
@@ -544,7 +571,8 @@ const X = (n, t, e) => {
544
571
  e(
545
572
  a,
546
573
  {
547
- y: u ? 0 : -56
574
+ y: u ? 0 : -56,
575
+ opacity: u ? 1 : 0
548
576
  },
549
577
  {
550
578
  duration: u ? 0.22 : 0.24,
@@ -671,17 +699,22 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
671
699
  },
672
700
  // Visible dim — applied when this screen is the one going behind / sitting
673
701
  // 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.
702
+ // Duration matches cupertino's enter so the dim resolves in lockstep with the
703
+ // underlying screen slide (and there's no animation-vs-hold-by-fill window for
704
+ // the rest-rule handoff to race against — that's a function of duration + fill,
705
+ // not the curve). Easing is intentionally left at the default: this animates
706
+ // `opacity` (a luminance channel), not position, so cupertino's positional
707
+ // decelerate curve would front-load the darkening into an abrupt step with a
708
+ // long invisible tail. The default ease spreads the perceived dim evenly across
709
+ // the duration, matching this decorator's linear-perceived-ramp design (see the
710
+ // DIM_COLOR note above).
677
711
  enter: {
678
712
  value: {
679
713
  opacity: 1,
680
714
  backgroundColor: I
681
715
  },
682
716
  options: {
683
- duration: 0.7,
684
- ease: [0.32, 0.72, 0, 1]
717
+ duration: 0.7
685
718
  }
686
719
  },
687
720
  // POPPING-false target: the previously-behind screen is returning to active.
@@ -694,8 +727,7 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
694
727
  backgroundColor: I
695
728
  },
696
729
  options: {
697
- duration: 0.6,
698
- ease: [0.32, 0.72, 0, 1]
730
+ duration: 0.6
699
731
  }
700
732
  },
701
733
  options: {
@@ -861,7 +893,7 @@ const I = "rgba(0, 0, 0, 0.3)", q = K({
861
893
  }, ct = (n, t) => {
862
894
  const [e, s] = t.split("-");
863
895
  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) => {
896
+ }, ut = (n, t, e) => `flemo-${n}-${J(t)}-${e}`, x = (n, t, e, s, a, r) => {
865
897
  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
898
  ${ct(t, e)}` : m;
867
899
  if (c.length === 0 && o.length === 0)
@@ -871,8 +903,8 @@ ${ct(t, e)}` : m;
871
903
  ${E(c)}
872
904
  animation: none;
873
905
  }`;
874
- const h = ut(n, t, e), P = [
875
- `@keyframes ${h} {`,
906
+ const p = ut(n, t, e), P = [
907
+ `@keyframes ${p} {`,
876
908
  " from {",
877
909
  E(o).replace(/^/gm, " "),
878
910
  " }",
@@ -881,8 +913,8 @@ ${E(c)}
881
913
  " }",
882
914
  "}"
883
915
  ].join(`
884
- `), p = [
885
- `${h}`,
916
+ `), h = [
917
+ `${p}`,
886
918
  `${l}s`,
887
919
  d,
888
920
  u > 0 ? `${u}s` : null,
@@ -891,13 +923,13 @@ ${E(c)}
891
923
  /* @__PURE__ */ new Set([...o.map((N) => N.property), ...c.map((N) => N.property)])
892
924
  ), y = f.length > 0 ? ` will-change: ${f.join(", ")};
893
925
  ` : "", S = e.split("-")[0], Y = `${i} {
894
- animation: ${p};
926
+ animation: ${h};
895
927
  ${y}${S === "PUSHING" || S === "REPLACING" ? ` contain: layout;
896
928
  pointer-events: none;
897
929
  ` : ""}}`;
898
930
  return `${P}
899
931
  ${Y}`;
900
- }, x = (n, t, e, s) => {
932
+ }, C = (n, t, e, s) => {
901
933
  const a = g(s.value);
902
934
  return a.length === 0 ? "" : `${n(t, e)} {
903
935
  ${E(a)}
@@ -909,12 +941,12 @@ ${E(a)}
909
941
  for (const r of O) {
910
942
  const o = s.variants[r], c = k[r];
911
943
  if (c === "self") {
912
- e.push(x(A, a, r, o));
944
+ e.push(C(A, a, r, o));
913
945
  continue;
914
946
  }
915
947
  const l = c === "initial" ? s.initial : s.variants[c].value;
916
948
  e.push(
917
- C("screen", a, r, l, o, A)
949
+ x("screen", a, r, l, o, A)
918
950
  );
919
951
  }
920
952
  }
@@ -923,12 +955,12 @@ ${E(a)}
923
955
  for (const r of W) {
924
956
  const o = s.variants[r], c = k[r];
925
957
  if (c === "self") {
926
- e.push(x(M, a, r, o));
958
+ e.push(C(M, a, r, o));
927
959
  continue;
928
960
  }
929
961
  const l = c === "initial" ? s.initial : s.variants[c].value;
930
962
  e.push(
931
- C(
963
+ x(
932
964
  "decorator",
933
965
  a,
934
966
  r,
@@ -960,7 +992,7 @@ function Mt(n, t, e) {
960
992
  const s = lt(n, t), a = B(s)(t), r = new URLSearchParams(e), o = Object.fromEntries(r.entries());
961
993
  return a ? { ...a.params, ...o } : {};
962
994
  }
963
- function Ct(n, t) {
995
+ function xt(n, t) {
964
996
  const {
965
997
  direction: e = "x",
966
998
  markerSelector: s = "[data-swipe-at-edge]",
@@ -1010,7 +1042,7 @@ export {
1010
1042
  F as cupertino,
1011
1043
  Dt as decoratorMap,
1012
1044
  it as easingToCss,
1013
- Ct as findScrollable,
1045
+ xt as findScrollable,
1014
1046
  lt as getMatchedPathPattern,
1015
1047
  Mt as getParams,
1016
1048
  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.3.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",