@unif/react-native-design 0.24.1 → 0.26.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.
Files changed (41) hide show
  1. package/lib/module/components/ui/Confirm/ConfirmHost.js +7 -12
  2. package/lib/module/components/ui/Confirm/ConfirmHost.js.map +1 -1
  3. package/lib/module/components/ui/Confirm/confirm.js +3 -2
  4. package/lib/module/components/ui/Confirm/confirm.js.map +1 -1
  5. package/lib/module/components/ui/Confirm/store.js +58 -8
  6. package/lib/module/components/ui/Confirm/store.js.map +1 -1
  7. package/lib/module/components/ui/Toast/ToastHost.js +20 -2
  8. package/lib/module/components/ui/Toast/ToastHost.js.map +1 -1
  9. package/lib/module/components/ui/Toast/ToastHost.web.js +11 -1
  10. package/lib/module/components/ui/Toast/ToastHost.web.js.map +1 -1
  11. package/lib/module/components/ui/Toast/store.js +95 -12
  12. package/lib/module/components/ui/Toast/store.js.map +1 -1
  13. package/lib/module/components/ui/Toast/toast.js +3 -2
  14. package/lib/module/components/ui/Toast/toast.js.map +1 -1
  15. package/lib/module/icons/data.js +8 -1
  16. package/lib/module/icons/data.js.map +1 -1
  17. package/lib/typescript/src/components/ui/Confirm/ConfirmHost.d.ts +7 -5
  18. package/lib/typescript/src/components/ui/Confirm/ConfirmHost.d.ts.map +1 -1
  19. package/lib/typescript/src/components/ui/Confirm/confirm.d.ts +4 -3
  20. package/lib/typescript/src/components/ui/Confirm/confirm.d.ts.map +1 -1
  21. package/lib/typescript/src/components/ui/Confirm/store.d.ts +13 -4
  22. package/lib/typescript/src/components/ui/Confirm/store.d.ts.map +1 -1
  23. package/lib/typescript/src/components/ui/Toast/ToastHost.d.ts +5 -1
  24. package/lib/typescript/src/components/ui/Toast/ToastHost.d.ts.map +1 -1
  25. package/lib/typescript/src/components/ui/Toast/ToastHost.web.d.ts +1 -0
  26. package/lib/typescript/src/components/ui/Toast/ToastHost.web.d.ts.map +1 -1
  27. package/lib/typescript/src/components/ui/Toast/store.d.ts +25 -1
  28. package/lib/typescript/src/components/ui/Toast/store.d.ts.map +1 -1
  29. package/lib/typescript/src/components/ui/Toast/toast.d.ts +4 -3
  30. package/lib/typescript/src/components/ui/Toast/toast.d.ts.map +1 -1
  31. package/lib/typescript/src/icons/data.d.ts +1 -1
  32. package/lib/typescript/src/icons/data.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/components/ui/Confirm/ConfirmHost.tsx +8 -14
  35. package/src/components/ui/Confirm/confirm.ts +3 -2
  36. package/src/components/ui/Confirm/store.ts +61 -13
  37. package/src/components/ui/Toast/ToastHost.tsx +20 -2
  38. package/src/components/ui/Toast/ToastHost.web.tsx +11 -1
  39. package/src/components/ui/Toast/store.ts +112 -16
  40. package/src/components/ui/Toast/toast.ts +3 -2
  41. package/src/icons/data.ts +11 -0
@@ -5,10 +5,17 @@ import type { ConfirmOptions } from './types';
5
5
  * Confirm 的纯状态机 —— 不含任何 React / 渲染依赖,可直接单测。
6
6
  *
7
7
  * 两条不变量:
8
- * 1. **唯一 owner** —— 同一时间只有一个 `<ConfirmHost />` 持有订阅。重复挂载拿到 `null`
9
- * lease、永久惰性,不会出现两个 Host 争抢同一个 entry。
8
+ * 1. **单一活跃 owner + 栈式接管** —— 同一时间只有一个 `<ConfirmHost />` 收事件,但
9
+ * 后挂载者**接管**、前任入栈挂起,卸载时自动归还。RN `Modal` 是独立 native window,
10
+ * 根 Host 渲染的对话框会被 Modal 物理盖住(iOS 兄弟 Modal 更是不叠放),所以
11
+ * 「Modal 内自挂一个 Host」是唯一正解、必须是合法用法 —— 旧的 first-wins 把它判成
12
+ * 恒惰性死码,才是要修的东西。
10
13
  * 2. **唯一 active entry** —— 同一时间只有一个未决对话框。所有关闭路径(确认 / 取消 /
11
- * backdrop / 系统返回 / Host 卸载 / subscriber 抛错)都汇聚到 `settle()`。
14
+ * backdrop / 系统返回 / Host 卸载 / owner 切换 / subscriber 抛错)都汇聚到 `settle()`。
15
+ *
16
+ * 由 1 派生出一条关键不变量:**active entry 永远属于当前 owner**。owner 每次切换
17
+ * (接管或归还)前都把 active 排空为 `false`,因此挂起中的 owner 手里不可能有未决
18
+ * 对话框,恢复时也不会继承一个自己没见过 `show` 的槽位。
12
19
  *
13
20
  * `settle()` 用 **identity guard**(`active !== entry` 直接返回 false)而非 id 比较:
14
21
  * 旧 entry 的迟到回调拿着的是旧对象引用,永远匹配不上新 active,因此不可能误关新对话框。
@@ -32,13 +39,15 @@ export type ConfirmHostLease = {
32
39
  /**
33
40
  * Host 卸载。`heldEntry` 是 Host 当时手里那个未决 entry(没有则传 `null`)——
34
41
  * 只有它仍是 active 时才会被 settle 成 `false`,避免误伤后来的对话框。
42
+ * 幂等:重复调用、或本 owner 早已被接管者顶下去,都是无副作用的 no-op。
35
43
  */
36
44
  release(heldEntry: ConfirmEntry | null): void;
37
45
  };
38
46
 
39
47
  export type ConfirmStore = {
40
48
  request(options: ConfirmOptions): Promise<boolean>;
41
- registerHost(subscriber: ConfirmSubscriber): ConfirmHostLease | null;
49
+ /** 挂载 Host。恒返回可用 lease —— 已有 owner 时走接管,不再拒绝。 */
50
+ registerHost(subscriber: ConfirmSubscriber): ConfirmHostLease;
42
51
  settle(entry: ConfirmEntry, result: boolean): boolean;
43
52
  activeEntry(): ConfirmEntry | null;
44
53
  };
@@ -49,6 +58,8 @@ export function createConfirmStore(log: Logger): ConfirmStore {
49
58
  let nextId = 0;
50
59
  let active: ConfirmEntry | null = null;
51
60
  let owner: Owner | null = null;
61
+ /** 被接管而挂起的前任,栈顶 = 最近一个。当前 owner 卸载时从这里恢复。 */
62
+ const suspended: Owner[] = [];
52
63
 
53
64
  function settle(entry: ConfirmEntry, result: boolean): boolean {
54
65
  if (entry.settled || active !== entry) return false;
@@ -88,7 +99,7 @@ export function createConfirmStore(log: Logger): ConfirmStore {
88
99
  const current = owner;
89
100
  if (!current?.subscriber) {
90
101
  log.warn(
91
- 'confirm() 调用时未挂载 <ConfirmHost />,对话框无法显示,已 resolve(false)。请在 app 根附近挂一次 <ConfirmHost />。'
102
+ 'confirm() 调用时未挂载 <ConfirmHost />,对话框无法显示,已 resolve(false)。请在 app 根附近挂一个 <ConfirmHost />。'
92
103
  );
93
104
  return Promise.resolve(false);
94
105
  }
@@ -114,26 +125,63 @@ export function createConfirmStore(log: Logger): ConfirmStore {
114
125
  });
115
126
  }
116
127
 
117
- function registerHost(
118
- subscriber: ConfirmSubscriber
119
- ): ConfirmHostLease | null {
120
- if (owner) {
121
- log.warn(
122
- '检测到多个 <ConfirmHost />。只有第一个生效,重复挂载的实例保持惰性 —— 请在 app 根只挂一次。'
123
- );
124
- return null;
128
+ /**
129
+ * owner 切换前把 active 排空为 `false` —— Promise 不悬挂、单例槽不被带走。
130
+ *
131
+ * 每轮 settle 成功即 `active = null`,只有 clear 回调同步再 `request()` 时才会多转
132
+ * 一轮;settle 返回 false(排不动)立即退出,不给死循环留口子。
133
+ */
134
+ function drainActive(): void {
135
+ while (active) {
136
+ if (!settle(active, false)) break;
125
137
  }
138
+ }
139
+
140
+ /** 弹出最近一个仍可用的挂起 owner;抛错被作废的(subscriber 已置空)直接丢弃。 */
141
+ function popSuspended(): Owner | null {
142
+ while (suspended.length > 0) {
143
+ const next = suspended.pop();
144
+ if (next?.subscriber) return next;
145
+ }
146
+ return null;
147
+ }
148
+
149
+ function registerHost(subscriber: ConfirmSubscriber): ConfirmHostLease {
126
150
  const token = Symbol('ConfirmHostOwner');
127
151
  const self: Owner = { token, subscriber };
152
+ if (owner) {
153
+ // 先排空再换人:此刻前任仍是 owner,clear 事件正好发给它,它的对话框就地关闭。
154
+ // 顺序反过来(先换 owner 再 settle)clear 会误投给刚接管的新 Host。
155
+ drainActive();
156
+ // 排空期间 clear 回调若抛错,settle 已把前任作废(owner 置 null)—— 作废的不入栈,
157
+ // 免得恢复出一个死订阅;若回调期间又有人注册,入栈的就是那位,同样不丢。
158
+ const outgoing = owner;
159
+ if (outgoing) suspended.push(outgoing);
160
+ }
128
161
  owner = self;
129
162
  return {
130
163
  ownerToken: token,
131
164
  release(heldEntry: ConfirmEntry | null): void {
165
+ const index = suspended.indexOf(self);
166
+ if (index >= 0) {
167
+ // 乱序卸载(父 Modal 先于内层 Host 卸载):挂起者的 active 在被接管时已结算,
168
+ // 这里只把它摘出栈,绝不能碰当前 owner。
169
+ suspended.splice(index, 1);
170
+ self.subscriber = null;
171
+ return;
172
+ }
132
173
  if (owner?.token !== token) return;
133
174
  // 先摘订阅,再结算:settle 内部发的 clear 事件不应再回到正在卸载的 Host。
134
175
  self.subscriber = null;
135
176
  owner = null;
136
177
  if (heldEntry) settle(heldEntry, false);
178
+ const successor = popSuspended();
179
+ if (successor) {
180
+ // 归还前再排空一次:前任没见过残留 entry 的 show,不能让它继承一个锁死的槽。
181
+ // 此刻 owner 为 null,排空不会发出任何 clear。
182
+ drainActive();
183
+ owner = successor;
184
+ }
137
185
  },
138
186
  };
139
187
  }
@@ -27,9 +27,13 @@ type DeliveryIdentity = {
27
27
  };
28
28
 
29
29
  /**
30
- * 在根附近挂**一次**。监听 toast() 调用并渲染当前 toast。
30
+ * 在根附近挂一个。监听 toast() 调用并渲染当前 toast。
31
31
  * 同一时间只显示一条 —— 新的会替换旧的(latest-wins)。
32
32
  *
33
+ * 栈式 owner:后挂载的实例接管投递,前任挂起并收起当前 toast;接管者卸载后自动归还。
34
+ * 因此**允许**在自己的 `Modal` 里再挂一个 —— RN `Modal` 是独立 native window,根 Host
35
+ * 的 toast 会被它物理盖住,内层自挂才看得见。
36
+ *
33
37
  * 位置由 `entry.position`('top' / 'bottom' / 'center')决定,top/bottom 自动避让
34
38
  * safe-area;进入动画方向随位置(top 从上滑、bottom/center 从下滑)。
35
39
  *
@@ -66,7 +70,21 @@ export function ToastHost({
66
70
  };
67
71
  setDelivery(next);
68
72
  };
69
- const lease = registerToastHost(subscriber);
73
+ // 被后挂载的 Host 接管:立刻收起当前 toast。store 已丢弃这次投递,自身的退场
74
+ // timer 从此过不了 CAS —— 不主动清,这条 toast 会冻在屏幕上直到本 Host 卸载。
75
+ const clearOnSuspend = () => {
76
+ currentDeliveryRef.current = null;
77
+ if (dismissTimer.current) {
78
+ clearTimeout(dismissTimer.current);
79
+ dismissTimer.current = null;
80
+ }
81
+ cancelAnimation(op);
82
+ cancelAnimation(ty);
83
+ setDelivery(null);
84
+ };
85
+ const lease = registerToastHost(subscriber, clearOnSuspend);
86
+ // null lease 只剩一种成因:补投 pending 时 subscriber 抛错,本 owner 当场被作废
87
+ //(不再是「重复挂载」—— 那条现在走接管)。惰性到卸载为止。
70
88
  if (!lease) {
71
89
  setInert(true);
72
90
  return;
@@ -34,6 +34,7 @@ type DeliveryIdentity = {
34
34
  * - opacity 0→1 + translateY 8→0 入场(motion.base ms)
35
35
  * - 停留 entry.duration ms
36
36
  * - opacity 1→0 + translateY 0→8 退场后 unmount
37
+ * - 栈式 owner:后挂载者接管、前任挂起并收起 toast,接管者卸载后自动归还
37
38
  *
38
39
  * 竞态纪律与 native 版一致:timer / RAF 在改 UI 或上报完成前,都要同时通过同步 ref
39
40
  * 与 `isCurrentToastDelivery(delivery)` 两道校验。
@@ -79,7 +80,16 @@ export function ToastHost({
79
80
  };
80
81
  setDelivery(next);
81
82
  };
82
- const lease = registerToastHost(subscriber);
83
+ // 被后挂载的 Host 接管:立刻收起当前 toast。store 已丢弃这次投递,自身的退场
84
+ // timer/RAF 从此过不了 CAS —— 不主动清,这条 toast 会冻在屏幕上直到本 Host 卸载。
85
+ const clearOnSuspend = () => {
86
+ currentDeliveryRef.current = null;
87
+ cancelCallbacks();
88
+ setDelivery(null);
89
+ };
90
+ const lease = registerToastHost(subscriber, clearOnSuspend);
91
+ // null lease 只剩一种成因:补投 pending 时 subscriber 抛错,本 owner 当场被作废
92
+ //(不再是「重复挂载」—— 那条现在走接管)。惰性到卸载为止。
83
93
  if (!lease) {
84
94
  setInert(true);
85
95
  return;
@@ -17,6 +17,18 @@ import type { ToastEntry } from './types';
17
17
  *
18
18
  * `leaseId` 单调递增,同一 entry 被重新投递(Host 重挂)也会拿到新的 leaseId ——
19
19
  * 仅比较 entry.id 不足以区分「同一条消息的两次投递」。
20
+ *
21
+ * **栈式 owner**(与 Confirm 同构):后挂载的 Host 接管投递,前任入栈挂起并收到 clear,
22
+ * 接管者卸载后自动归还。RN `Modal` 是独立 native window,根 Host 渲染的 toast 会被
23
+ * Modal 物理盖住,只有「Modal 内自挂一个 Host」能显示 —— 旧的 first-wins 把这条唯一
24
+ * 正解判成恒惰性死码。
25
+ *
26
+ * 两个方向对在途 toast 的处理**刻意不同**:
27
+ * - **接管**(有人挂到我上面)→ 在途 toast **丢弃**。它属于「已经被盖住的过去」,
28
+ * 搬到接管者身上重放没有意义。
29
+ * - **归还**(接管者卸载、我恢复)→ 在途 toast **整条交回、立即重投**。
30
+ * 「Modal 内操作成功 → toast → 关窗」是最常见的一条路径,那条 toast 刚发出、用户
31
+ * 一眼都还没看到;丢掉的话比不挂内层 Host 还糟。不追剩余时长,重投 = 完整重播一遍。
20
32
  */
21
33
 
22
34
  export type ToastDelivery = {
@@ -27,27 +39,49 @@ export type ToastDelivery = {
27
39
 
28
40
  export type ToastSubscriber = (delivery: ToastDelivery) => void;
29
41
 
42
+ /**
43
+ * owner 被接管 / 归还时的撤回通知 —— 对应 Confirm 的 `clear` 事件。
44
+ *
45
+ * 没有它,挂起中的 Host 会把最后一条 toast **冻在屏幕上**:store 已丢弃那次投递,
46
+ * Host 自己的退场 timer 过不了 `isCurrent` CAS,永远走不到清 UI 那一步。
47
+ */
48
+ export type ToastClearSubscriber = () => void;
49
+
30
50
  export type ToastHostLease = {
31
51
  readonly ownerToken: symbol;
52
+ /** Host 卸载。幂等:重复调用、或本 owner 已被摘掉,都是无副作用的 no-op。 */
32
53
  release(): void;
33
54
  };
34
55
 
35
56
  export type ToastStore = {
36
57
  publish(entry: ToastEntry): void;
37
- registerHost(subscriber: ToastSubscriber): ToastHostLease | null;
58
+ /**
59
+ * 挂载 Host。已有 owner 时走接管(不再拒绝);返回 `null` 只剩一种含义 ——
60
+ * 补投 pending 时 subscriber 抛错,这个 owner 当场就被作废了。
61
+ */
62
+ registerHost(
63
+ subscriber: ToastSubscriber,
64
+ onClear?: ToastClearSubscriber
65
+ ): ToastHostLease | null;
38
66
  complete(ownerToken: symbol, leaseId: number, entryId: number): boolean;
39
67
  isCurrent(delivery: ToastDelivery): boolean;
40
68
  pendingEntry(): ToastEntry | null;
41
69
  currentDelivery(): ToastDelivery | null;
42
70
  };
43
71
 
44
- type Owner = { token: symbol; subscriber: ToastSubscriber | null };
72
+ type Owner = {
73
+ token: symbol;
74
+ subscriber: ToastSubscriber | null;
75
+ onClear: ToastClearSubscriber | null;
76
+ };
45
77
 
46
78
  export function createToastStore(log: Logger): ToastStore {
47
79
  let pending: ToastEntry | null = null;
48
80
  let delivered: ToastDelivery | null = null;
49
81
  let owner: Owner | null = null;
50
82
  let leaseCounter = 0;
83
+ /** 被接管而挂起的前任,栈顶 = 最近一个。当前 owner 卸载时从这里恢复。 */
84
+ const suspended: Owner[] = [];
51
85
 
52
86
  function beginDelivery(entry: ToastEntry, capturedOwner: Owner): void {
53
87
  const delivery: ToastDelivery = {
@@ -85,30 +119,92 @@ export function createToastStore(log: Logger): ToastStore {
85
119
  beginDelivery(entry, current);
86
120
  }
87
121
 
88
- function registerHost(subscriber: ToastSubscriber): ToastHostLease | null {
89
- if (owner) {
90
- log.warn(
91
- '检测到多个 <ToastHost />。只有第一个生效,重复挂载的实例保持惰性 —— 请在 app 根只挂一次。'
92
- );
93
- return null;
122
+ /** 把前任降为挂起态:丢弃它的在途投递,并通知它收起屏幕上那条 toast。 */
123
+ function suspendOwner(target: Owner): void {
124
+ // 不回退到 pending —— 否则接管者一挂上就把前任那条补投一遍(跨 owner 重放)。
125
+ if (delivered?.ownerToken === target.token) delivered = null;
126
+ const notify = target.onClear;
127
+ if (!notify) return;
128
+ try {
129
+ notify();
130
+ } catch (error) {
131
+ log.error('ToastHost clear 回调抛错', error);
132
+ // 坏 Host 就地作废:留在栈里也只会在恢复时接着抛。
133
+ target.subscriber = null;
134
+ target.onClear = null;
135
+ }
136
+ }
137
+
138
+ /** 弹出最近一个仍可用的挂起 owner;抛错被作废的(subscriber 已置空)直接丢弃。 */
139
+ function popSuspended(): Owner | null {
140
+ while (suspended.length > 0) {
141
+ const next = suspended.pop();
142
+ if (next?.subscriber) return next;
94
143
  }
144
+ return null;
145
+ }
146
+
147
+ /** 刚上任的 owner 在首投里抛错被作废:继续往下弹,别把栈里剩下的人一起埋掉。 */
148
+ function resumeAfterFailedInstall(): void {
149
+ const fallback = popSuspended();
150
+ if (fallback) owner = fallback;
151
+ }
152
+
153
+ function registerHost(
154
+ subscriber: ToastSubscriber,
155
+ onClear?: ToastClearSubscriber
156
+ ): ToastHostLease | null {
95
157
  const token = Symbol('ToastHostOwner');
96
- const self: Owner = { token, subscriber };
158
+ const self: Owner = { token, subscriber, onClear: onClear ?? null };
159
+ const previous = owner;
160
+ // 先换 owner 再通知前任:clear 回调里同步 publish() 的那条应当投给**接管者**,
161
+ // 投给正在退场的前任会立刻变成一条冻在屏幕上的孤儿 toast。
162
+ //(Confirm 那侧顺序相反 —— 它的 clear 由 settle 发给当时的 owner,必须先排空。)
97
163
  owner = self;
164
+ if (previous) {
165
+ suspendOwner(previous);
166
+ // clear 回调抛错作废的前任不入栈,免得恢复出一个死订阅。
167
+ if (previous.subscriber) suspended.push(previous);
168
+ }
98
169
  if (pending) beginDelivery(pending, self);
99
- // 首投期间 subscriber 抛错会把 owner 作废 —— 此时不能发出可用的 lease
100
- if (owner?.token !== token) return null;
170
+ // 首投期间 subscriber 抛错会把 owner 作废 —— 此时不能发出可用的 lease,
171
+ // 并且要立刻把刚挂起的前任放回 owner,否则栈里的人再也醒不过来。
172
+ if (owner?.token !== token) {
173
+ resumeAfterFailedInstall();
174
+ return null;
175
+ }
101
176
  return {
102
177
  ownerToken: token,
103
178
  release(): void {
179
+ const index = suspended.indexOf(self);
180
+ if (index >= 0) {
181
+ // 乱序卸载(父 Modal 先于内层 Host 卸载):挂起者的在途投递在被接管时已丢弃,
182
+ // 这里只把它摘出栈,绝不能碰当前 owner。
183
+ suspended.splice(index, 1);
184
+ self.subscriber = null;
185
+ self.onClear = null;
186
+ return;
187
+ }
104
188
  if (owner?.token !== token) return;
105
189
  self.subscriber = null;
190
+ self.onClear = null;
106
191
  owner = null;
107
- if (delivered?.ownerToken === token) {
108
- // 未完成的投递退回 pending,让下一个 Host 能补投;但更新的 pending 优先。
109
- if (!pending) pending = delivered.entry;
110
- delivered = null;
111
- }
192
+ const mine = delivered?.ownerToken === token ? delivered : null;
193
+ if (mine) delivered = null;
194
+ // 归还方向**不丢**在途 toast —— 与接管方向相反,这条区分是有实证的:
195
+ // 「Modal 内操作成功 → toast → setVisible(false)」是最常见的一条路径,
196
+ // 内层 Host 跟着 Modal 一起卸载,这条 toast 刚发出、用户一眼都没看到。
197
+ // 接管方向丢弃是因为前任那条属于「已经被盖住的过去」;归还方向是把刚发生的
198
+ // 事情**交回上一层**,不是跨 owner 重放。整条交回、不追剩余时长 —— 这正是
199
+ // 既有的「owner A 卸载后 B 拿到同一 entry、新 leaseId」形态。
200
+ if (mine && !pending) pending = mine.entry;
201
+ const successor = popSuspended();
202
+ if (!successor) return;
203
+ owner = successor;
204
+ // 有人接手就当场重投(新 ownerToken + 新 leaseId,前任的迟到回调仍认不出它);
205
+ // 没人接手时它就停在 pending,等下一个挂上来的 Host 补投 —— 既有语义不变。
206
+ if (pending) beginDelivery(pending, successor);
207
+ if (owner?.token !== successor.token) resumeAfterFailedInstall();
112
208
  },
113
209
  };
114
210
  }
@@ -56,7 +56,8 @@ function emit(input: ToastInput, kind: ToastKind = 'info') {
56
56
  }
57
57
 
58
58
  /**
59
- * 命令式 toast API。在 app 根附近挂一次 `<ToastHost />` 即可。
59
+ * 命令式 toast API。在 app 根附近挂一个 `<ToastHost />` 即可;需要在 `Modal` 里显示
60
+ * 时可在 Modal 内再挂一个,它会接管、关闭后自动归还。
60
61
  *
61
62
  * toast('已切换到日报');
62
63
  * toast.success('订单提交成功');
@@ -69,7 +70,7 @@ export const toast = Object.assign((input: ToastInput) => emit(input, 'info'), {
69
70
  error: (input: ToastInput) => emit(input, 'error'),
70
71
  });
71
72
 
72
- /** 内部:ToastHost 挂载时注册唯一 owner;重复挂载得到 null。 */
73
+ /** 内部:ToastHost 挂载时接管 owner;前任入栈挂起,本 lease 释放时归还。 */
73
74
  export const registerToastHost = store.registerHost;
74
75
 
75
76
  /** 内部:三重身份 CAS —— owner token + leaseId + entry id 全对才算完成。 */
package/src/icons/data.ts CHANGED
@@ -76,6 +76,7 @@ export type IconName =
76
76
  | 'menu'
77
77
  | 'mic-on'
78
78
  | 'mic'
79
+ | 'minimize'
79
80
  | 'more-h'
80
81
  | 'more-v'
81
82
  | 'order'
@@ -1509,6 +1510,15 @@ export const ICONS: Record<IconName, IconDef> = {
1509
1510
  },
1510
1511
  ],
1511
1512
  },
1513
+ 'minimize': {
1514
+ strokeWidth: 1.75,
1515
+ elements: [
1516
+ {
1517
+ kind: 'path',
1518
+ d: 'M4 14h6v6M20 10h-6V4M14 10l7-7M3 21l7-7',
1519
+ },
1520
+ ],
1521
+ },
1512
1522
  'more-h': {
1513
1523
  strokeWidth: 1.75,
1514
1524
  elements: [
@@ -2566,6 +2576,7 @@ export const ICON_NAMES: IconName[] = [
2566
2576
  'menu',
2567
2577
  'mic-on',
2568
2578
  'mic',
2579
+ 'minimize',
2569
2580
  'more-h',
2570
2581
  'more-v',
2571
2582
  'order',