@ptengine/widgets 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/README.md +38 -2
- package/dist/cjs/app-globals-V2Kpy_OQ.js +8 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js.map +1 -0
- package/dist/cjs/index-DRCOne2Q.js +1583 -0
- package/dist/cjs/index-DRCOne2Q.js.map +1 -0
- package/dist/cjs/index.cjs.js +107 -0
- package/dist/cjs/index.cjs.js.map +1 -0
- package/dist/cjs/loader.cjs.js +16 -0
- package/dist/cjs/loader.cjs.js.map +1 -0
- package/dist/cjs/pt-provider.cjs.entry.js +85 -0
- package/dist/cjs/pt-provider.cjs.entry.js.map +1 -0
- package/dist/cjs/ptengine-widgets.cjs.js +28 -0
- package/dist/cjs/ptengine-widgets.cjs.js.map +1 -0
- package/dist/collection/collection-manifest.json +13 -0
- package/dist/collection/components/pt-provider/pt-provider.js +136 -0
- package/dist/collection/components/pt-provider/pt-provider.js.map +1 -0
- package/dist/collection/index.js +9 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/collection/utils/context.js +98 -0
- package/dist/collection/utils/context.js.map +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/pt-provider.d.ts +11 -0
- package/dist/components/pt-provider.js +2 -0
- package/dist/components/pt-provider.js.map +1 -0
- package/dist/define/pt-provider.d.ts +1 -0
- package/dist/define/pt-provider.js +5 -0
- package/dist/esm/app-globals-DQuL1Twl.js +6 -0
- package/dist/esm/app-globals-DQuL1Twl.js.map +1 -0
- package/dist/esm/index-CZKQmozD.js +1559 -0
- package/dist/esm/index-CZKQmozD.js.map +1 -0
- package/dist/esm/index.js +102 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/loader.js +14 -0
- package/dist/esm/loader.js.map +1 -0
- package/dist/esm/pt-provider.entry.js +83 -0
- package/dist/esm/pt-provider.entry.js.map +1 -0
- package/dist/esm/ptengine-widgets.js +24 -0
- package/dist/esm/ptengine-widgets.js.map +1 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/ptengine-widgets/index.esm.js +2 -0
- package/dist/ptengine-widgets/index.esm.js.map +1 -0
- package/dist/ptengine-widgets/p-8a0ee9f5.entry.js +2 -0
- package/dist/ptengine-widgets/p-8a0ee9f5.entry.js.map +1 -0
- package/dist/ptengine-widgets/p-CZKQmozD.js +3 -0
- package/dist/ptengine-widgets/p-CZKQmozD.js.map +1 -0
- package/dist/ptengine-widgets/p-DQuL1Twl.js +2 -0
- package/dist/ptengine-widgets/p-DQuL1Twl.js.map +1 -0
- package/dist/ptengine-widgets/ptengine-widgets.css +1 -0
- package/dist/ptengine-widgets/ptengine-widgets.esm.js +2 -0
- package/dist/ptengine-widgets/ptengine-widgets.esm.js.map +1 -0
- package/dist/types/components/pt-provider/pt-provider.d.ts +59 -0
- package/dist/types/components.d.ts +107 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/stencil-public-runtime.d.ts +1879 -0
- package/dist/types/utils/context.d.ts +45 -0
- package/docs.json +86 -0
- package/hydrate/index.d.ts +287 -0
- package/hydrate/index.js +22214 -0
- package/hydrate/index.mjs +22204 -0
- package/hydrate/package.json +12 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +93 -3
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 依赖注入:Web Components 社区的 Context Protocol。
|
|
5
|
+
*
|
|
6
|
+
* 业务组件不自己创建 client,也不读全局变量,而是在挂载时向上冒泡一个
|
|
7
|
+
* `context-request` 事件,由最近的 `<pt-provider>` 回调返回 client。
|
|
8
|
+
*
|
|
9
|
+
* 选它而不是各框架自己的 context 机制,是因为它走的是 DOM 事件:
|
|
10
|
+
* React、Vue、Angular、原生 HTML 里行为完全一致,也能穿透 Shadow DOM
|
|
11
|
+
* (事件带 composed: true)。两层因此可以独立发版、独立测试。
|
|
12
|
+
*
|
|
13
|
+
* 协议出处:https://github.com/webcomponents-cg/community-protocols
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* context 的标识。
|
|
17
|
+
*
|
|
18
|
+
* 用字符串而不是 Symbol:页面上同时存在两份打包产物时(比如宿主应用装了一份、
|
|
19
|
+
* 某个微前端子应用又装了一份),两个 Symbol 不相等,注入会静默失败;
|
|
20
|
+
* 字符串永远相等。代价是理论上可能与别人撞名,所以带上包名前缀。
|
|
21
|
+
*/
|
|
22
|
+
const PT_CLIENT_CONTEXT = '@ptengine/client';
|
|
23
|
+
/** provider 挂到文档上时广播的事件名(协议里的 context-provider):未得到应答的消费者据此再问一次 */
|
|
24
|
+
const CONTEXT_PROVIDER_EVENT = 'context-provider';
|
|
25
|
+
class ContextRequestEvent extends Event {
|
|
26
|
+
constructor(context, callback, subscribe = false) {
|
|
27
|
+
super('context-request', { bubbles: true, composed: true, cancelable: true });
|
|
28
|
+
this.context = context;
|
|
29
|
+
this.callback = callback;
|
|
30
|
+
this.subscribe = subscribe;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 向上请求一个 client。
|
|
35
|
+
*
|
|
36
|
+
* `subscribe: true` 时,provider 换了 client 会再次回调(例如切换账号),
|
|
37
|
+
* 返回值是退订函数 —— 组件在 disconnectedCallback 里调用它。
|
|
38
|
+
*
|
|
39
|
+
* 找不到 provider 时回调不会被触发,组件应当据此降级(显示「未接入」而不是报错)。
|
|
40
|
+
*/
|
|
41
|
+
function requestClient(element, callback, subscribe = true) {
|
|
42
|
+
let unsubscribe;
|
|
43
|
+
let answered = false;
|
|
44
|
+
let released = false;
|
|
45
|
+
/** 发出去的请求编号与被接受的那一个:同一个消费者只能持有一份订阅 */
|
|
46
|
+
let latest = 0;
|
|
47
|
+
let accepted = 0;
|
|
48
|
+
const fire = () => {
|
|
49
|
+
const id = ++latest;
|
|
50
|
+
element.dispatchEvent(new ContextRequestEvent(PT_CLIENT_CONTEXT, (value, dispose) => {
|
|
51
|
+
/* 组件已经退订(卸载)后才姗姗来迟的应答,直接丢掉。
|
|
52
|
+
* 另一种迟到:兜底重试发了第二个请求,而第一个其实被 provider 排队了
|
|
53
|
+
* (Stencil 在实例就绪前会把 @Listen 收到的事件先攒着、就绪后重放),
|
|
54
|
+
* 两个都被应答就成了两份订阅 —— 只认第一份,其余的当场退订。 */
|
|
55
|
+
if (released || (answered && id !== accepted)) {
|
|
56
|
+
dispose?.();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
answered = true;
|
|
60
|
+
accepted = id;
|
|
61
|
+
/* 只记住最新的退订函数,**不要**调用旧的:provider 每次通知都会给一个新的
|
|
62
|
+
* dispose,而它们删除的是同一个订阅。调旧的等于把自己退订 ——
|
|
63
|
+
* 消费者从此只能收到两次值,第二次换 client 之后永久停更。 */
|
|
64
|
+
if (dispose)
|
|
65
|
+
unsubscribe = dispose;
|
|
66
|
+
callback(value);
|
|
67
|
+
}, subscribe));
|
|
68
|
+
};
|
|
69
|
+
fire();
|
|
70
|
+
/**
|
|
71
|
+
* 没人应答时不能就此放弃:上层的 <pt-provider> 未必比子组件先就绪。
|
|
72
|
+
*
|
|
73
|
+
* 两种情况,两条兜底:
|
|
74
|
+
* 1. provider 的类还没注册(懒加载,Vue / Nuxt 里实测子组件先 upgrade):
|
|
75
|
+
* 等 whenDefined 兑现后再要一次;
|
|
76
|
+
* 2. provider 后插入文档、或在 DOM 里被移动(keep-alive、列表重排):
|
|
77
|
+
* 它 connected 时会广播 context-provider,听到就再要一次。
|
|
78
|
+
* 此刻 provider 的 client 可能仍是 undefined(框架还没把 prop 写进来),没关系:
|
|
79
|
+
* subscribe 已经挂上,等 prop 写进来时 @Watch 会再通知一次。
|
|
80
|
+
*/
|
|
81
|
+
const retry = () => {
|
|
82
|
+
if (!answered && !released && element.isConnected)
|
|
83
|
+
fire();
|
|
84
|
+
};
|
|
85
|
+
if (!answered && typeof customElements !== 'undefined') {
|
|
86
|
+
void customElements.whenDefined('pt-provider').then(retry);
|
|
87
|
+
}
|
|
88
|
+
/* 挂在 document 上:provider 的广播带 composed,从任何影子树里都能冒到这里 */
|
|
89
|
+
const onProviderAvailable = () => retry();
|
|
90
|
+
if (!answered && typeof document !== 'undefined') {
|
|
91
|
+
document.addEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);
|
|
92
|
+
}
|
|
93
|
+
return () => {
|
|
94
|
+
released = true;
|
|
95
|
+
if (typeof document !== 'undefined')
|
|
96
|
+
document.removeEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);
|
|
97
|
+
unsubscribe?.();
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
exports.CONTEXT_PROVIDER_EVENT = CONTEXT_PROVIDER_EVENT;
|
|
102
|
+
exports.ContextRequestEvent = ContextRequestEvent;
|
|
103
|
+
exports.PT_CLIENT_CONTEXT = PT_CLIENT_CONTEXT;
|
|
104
|
+
exports.requestClient = requestClient;
|
|
105
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["src/utils/context.ts"],"sourcesContent":["/**\n * 依赖注入:Web Components 社区的 Context Protocol。\n *\n * 业务组件不自己创建 client,也不读全局变量,而是在挂载时向上冒泡一个\n * `context-request` 事件,由最近的 `<pt-provider>` 回调返回 client。\n *\n * 选它而不是各框架自己的 context 机制,是因为它走的是 DOM 事件:\n * React、Vue、Angular、原生 HTML 里行为完全一致,也能穿透 Shadow DOM\n * (事件带 composed: true)。两层因此可以独立发版、独立测试。\n *\n * 协议出处:https://github.com/webcomponents-cg/community-protocols\n */\n\n/**\n * 注入给子树的 client。\n *\n * 能力层 SDK 暂时移除,这里是它的占位:provider 只做引用传递,不关心 client 长什么样。\n * 将来 SDK 加回来时换成 `@ptengine/sdk` 的 `Client`。\n */\nexport type Client = object;\n\n/**\n * context 的标识。\n *\n * 用字符串而不是 Symbol:页面上同时存在两份打包产物时(比如宿主应用装了一份、\n * 某个微前端子应用又装了一份),两个 Symbol 不相等,注入会静默失败;\n * 字符串永远相等。代价是理论上可能与别人撞名,所以带上包名前缀。\n */\nexport const PT_CLIENT_CONTEXT = '@ptengine/client' as const;\n\n/** provider 挂到文档上时广播的事件名(协议里的 context-provider):未得到应答的消费者据此再问一次 */\nexport const CONTEXT_PROVIDER_EVENT = 'context-provider' as const;\n\nexport type ContextCallback<T> = (value: T, unsubscribe?: () => void) => void;\n\nexport class ContextRequestEvent<T> extends Event {\n readonly context: string;\n readonly callback: ContextCallback<T>;\n readonly subscribe: boolean;\n\n constructor(context: string, callback: ContextCallback<T>, subscribe = false) {\n super('context-request', { bubbles: true, composed: true, cancelable: true });\n this.context = context;\n this.callback = callback;\n this.subscribe = subscribe;\n }\n}\n\n/**\n * 向上请求一个 client。\n *\n * `subscribe: true` 时,provider 换了 client 会再次回调(例如切换账号),\n * 返回值是退订函数 —— 组件在 disconnectedCallback 里调用它。\n *\n * 找不到 provider 时回调不会被触发,组件应当据此降级(显示「未接入」而不是报错)。\n */\nexport function requestClient(\n element: HTMLElement,\n callback: ContextCallback<Client | undefined>,\n subscribe = true\n): () => void {\n let unsubscribe: (() => void) | undefined;\n let answered = false;\n let released = false;\n /** 发出去的请求编号与被接受的那一个:同一个消费者只能持有一份订阅 */\n let latest = 0;\n let accepted = 0;\n\n const fire = () => {\n const id = ++latest;\n element.dispatchEvent(\n new ContextRequestEvent<Client | undefined>(\n PT_CLIENT_CONTEXT,\n (value, dispose) => {\n /* 组件已经退订(卸载)后才姗姗来迟的应答,直接丢掉。\n * 另一种迟到:兜底重试发了第二个请求,而第一个其实被 provider 排队了\n * (Stencil 在实例就绪前会把 @Listen 收到的事件先攒着、就绪后重放),\n * 两个都被应答就成了两份订阅 —— 只认第一份,其余的当场退订。 */\n if (released || (answered && id !== accepted)) {\n dispose?.();\n return;\n }\n answered = true;\n accepted = id;\n /* 只记住最新的退订函数,**不要**调用旧的:provider 每次通知都会给一个新的\n * dispose,而它们删除的是同一个订阅。调旧的等于把自己退订 ——\n * 消费者从此只能收到两次值,第二次换 client 之后永久停更。 */\n if (dispose) unsubscribe = dispose;\n callback(value);\n },\n subscribe\n )\n );\n };\n\n fire();\n\n /**\n * 没人应答时不能就此放弃:上层的 <pt-provider> 未必比子组件先就绪。\n *\n * 两种情况,两条兜底:\n * 1. provider 的类还没注册(懒加载,Vue / Nuxt 里实测子组件先 upgrade):\n * 等 whenDefined 兑现后再要一次;\n * 2. provider 后插入文档、或在 DOM 里被移动(keep-alive、列表重排):\n * 它 connected 时会广播 context-provider,听到就再要一次。\n * 此刻 provider 的 client 可能仍是 undefined(框架还没把 prop 写进来),没关系:\n * subscribe 已经挂上,等 prop 写进来时 @Watch 会再通知一次。\n */\n const retry = () => {\n if (!answered && !released && element.isConnected) fire();\n };\n\n if (!answered && typeof customElements !== 'undefined') {\n void customElements.whenDefined('pt-provider').then(retry);\n }\n\n /* 挂在 document 上:provider 的广播带 composed,从任何影子树里都能冒到这里 */\n const onProviderAvailable = () => retry();\n if (!answered && typeof document !== 'undefined') {\n document.addEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);\n }\n\n return () => {\n released = true;\n if (typeof document !== 'undefined')\n document.removeEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);\n unsubscribe?.();\n };\n}\n"],"names":[],"mappings":";;AAAA;;;;;;;;;;;AAWG;AAUH;;;;;;AAMG;AACI,MAAM,iBAAiB,GAAG;AAEjC;AACO,MAAM,sBAAsB,GAAG;AAIhC,MAAO,mBAAuB,SAAQ,KAAK,CAAA;AAK/C,IAAA,WAAA,CAAY,OAAe,EAAE,QAA4B,EAAE,SAAS,GAAG,KAAK,EAAA;AAC1E,QAAA,KAAK,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC7E,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACxB,QAAA,IAAI,CAAC,SAAS,GAAG,SAAS;;AAE7B;AAED;;;;;;;AAOG;AACG,SAAU,aAAa,CAC3B,OAAoB,EACpB,QAA6C,EAC7C,SAAS,GAAG,IAAI,EAAA;AAEhB,IAAA,IAAI,WAAqC;IACzC,IAAI,QAAQ,GAAG,KAAK;IACpB,IAAI,QAAQ,GAAG,KAAK;;IAEpB,IAAI,MAAM,GAAG,CAAC;IACd,IAAI,QAAQ,GAAG,CAAC;IAEhB,MAAM,IAAI,GAAG,MAAK;AAChB,QAAA,MAAM,EAAE,GAAG,EAAE,MAAM;AACnB,QAAA,OAAO,CAAC,aAAa,CACnB,IAAI,mBAAmB,CACrB,iBAAiB,EACjB,CAAC,KAAK,EAAE,OAAO,KAAI;AACjB;;;AAGqC;YACrC,IAAI,QAAQ,KAAK,QAAQ,IAAI,EAAE,KAAK,QAAQ,CAAC,EAAE;gBAC7C,OAAO,IAAI;gBACX;;YAEF,QAAQ,GAAG,IAAI;YACf,QAAQ,GAAG,EAAE;AACb;;AAEsC;AACtC,YAAA,IAAI,OAAO;gBAAE,WAAW,GAAG,OAAO;YAClC,QAAQ,CAAC,KAAK,CAAC;AACjB,SAAC,EACD,SAAS,CACV,CACF;AACH,KAAC;AAED,IAAA,IAAI,EAAE;AAEN;;;;;;;;;;AAUG;IACH,MAAM,KAAK,GAAG,MAAK;QACjB,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW;AAAE,YAAA,IAAI,EAAE;AAC3D,KAAC;IAED,IAAI,CAAC,QAAQ,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE;QACtD,KAAK,cAAc,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;;;AAI5D,IAAA,MAAM,mBAAmB,GAAG,MAAM,KAAK,EAAE;IACzC,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE;AAChD,QAAA,QAAQ,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,mBAAmB,CAAC;;AAGxE,IAAA,OAAO,MAAK;QACV,QAAQ,GAAG,IAAI;QACf,IAAI,OAAO,QAAQ,KAAK,WAAW;AACjC,YAAA,QAAQ,CAAC,mBAAmB,CAAC,sBAAsB,EAAE,mBAAmB,CAAC;QAC3E,WAAW,IAAI;AACjB,KAAC;AACH;;;;;;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-DRCOne2Q.js');
|
|
4
|
+
var appGlobals = require('./app-globals-V2Kpy_OQ.js');
|
|
5
|
+
|
|
6
|
+
const defineCustomElements = async (win, options) => {
|
|
7
|
+
if (typeof window === 'undefined') return undefined;
|
|
8
|
+
await appGlobals.globalScripts();
|
|
9
|
+
return index.bootstrapLazy([["pt-provider.cjs",[[0,"pt-provider",{"client":[16]},[[0,"context-request","handleContextRequest"]],{"client":[{"onClientChange":0}]}]]]], options);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
exports.setNonce = index.setNonce;
|
|
13
|
+
exports.defineCustomElements = defineCustomElements;
|
|
14
|
+
//# sourceMappingURL=loader.cjs.js.map
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=loader.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.cjs.js","sources":["@lazy-external-entrypoint?app-data=conditional"],"sourcesContent":["export { setNonce } from '@stencil/core';\nimport { bootstrapLazy } from '@stencil/core';\nimport { globalScripts } from '@stencil/core/internal/app-globals';\nexport const defineCustomElements = async (win, options) => {\n if (typeof window === 'undefined') return undefined;\n await globalScripts();\n return bootstrapLazy([/*!__STENCIL_LAZY_DATA__*/], options);\n};\n"],"names":["globalScripts","bootstrapLazy"],"mappings":";;;;;AAGY,MAAC,oBAAoB,GAAG,OAAO,GAAG,EAAE,OAAO,KAAK;AAC5D,EAAE,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,OAAO,SAAS;AACrD,EAAE,MAAMA,wBAAa,EAAE;AACvB,EAAE,OAAOC,mBAAa,CAAC,4BAA4B,EAAE,OAAO,CAAC;AAC7D;;;;;"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-DRCOne2Q.js');
|
|
4
|
+
var index$1 = require('./index.cjs.js');
|
|
5
|
+
|
|
6
|
+
const PtProvider = class {
|
|
7
|
+
constructor(hostRef) {
|
|
8
|
+
index.registerInstance(this, hostRef);
|
|
9
|
+
/**
|
|
10
|
+
* 订阅者 → 最近一次交给它的值。
|
|
11
|
+
*
|
|
12
|
+
* client 变了要逐个通知,而不是让它们自己轮询;记住上次的值是为了不重复通知:
|
|
13
|
+
* 同一个 client 发两遍只是多一次无意义的重渲染。
|
|
14
|
+
*/
|
|
15
|
+
this.subscribers = new Map();
|
|
16
|
+
}
|
|
17
|
+
onClientChange(next) {
|
|
18
|
+
for (const [callback, last] of this.subscribers) {
|
|
19
|
+
if (last === next)
|
|
20
|
+
continue;
|
|
21
|
+
this.subscribers.set(callback, next);
|
|
22
|
+
callback(next, () => this.subscribers.delete(callback));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 挂到文档上就广播一声(协议里的 context-provider)。
|
|
27
|
+
*
|
|
28
|
+
* 子组件先于 provider 就绪、或 provider 后来才插进文档 / 在 DOM 里被移动时,
|
|
29
|
+
* 它们之前的请求都没人接;听到这一声会再请求一次。
|
|
30
|
+
*/
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
this.host.dispatchEvent(new Event(index$1.CONTEXT_PROVIDER_EVENT, { bubbles: true, composed: true }));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 首次渲染完成后补一次通知。
|
|
36
|
+
*
|
|
37
|
+
* @Watch 只在组件进入 watch-ready 之后才触发;在那之前写进来的 client
|
|
38
|
+
* 会被 Stencil 静默当成初始值。Angular 正好落在这个窗口里:它先把元素接进
|
|
39
|
+
* 文档(子组件随即发出 context 请求,拿到 undefined 并订阅),再在第一轮变更
|
|
40
|
+
* 检测里写 [client] —— 没有这一次补发,订阅者会永远停在「没有 client」。
|
|
41
|
+
* 已经拿到这个 client 的订阅者不会被重复通知(见 onClientChange)。
|
|
42
|
+
*/
|
|
43
|
+
componentDidLoad() {
|
|
44
|
+
if (this.client)
|
|
45
|
+
this.onClientChange(this.client);
|
|
46
|
+
}
|
|
47
|
+
/*
|
|
48
|
+
* 断开时**不**清空订阅者。
|
|
49
|
+
*
|
|
50
|
+
* 消费者各自持有退订函数并在自己卸载时调用;provider 只是在 DOM 里被移动
|
|
51
|
+
* (框架 keep-alive、列表重排)时,订阅要原样保留 —— 清掉的话子组件永远停在旧 client 上,
|
|
52
|
+
* 而它们自己没断连,不会重新请求。provider 真的被丢弃时,这个 Set 随它一起被回收。
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* 拦下子树冒泡上来的 context 请求。
|
|
56
|
+
*
|
|
57
|
+
* `stopPropagation()` 是必须的:不拦住的话,嵌套 provider 时外层也会响应,
|
|
58
|
+
* 子组件会先后收到两个 client,最后一个赢 —— 恰好与「就近取用」的直觉相反。
|
|
59
|
+
*/
|
|
60
|
+
handleContextRequest(event) {
|
|
61
|
+
const request = event;
|
|
62
|
+
if (request.context !== index$1.PT_CLIENT_CONTEXT || typeof request.callback !== 'function')
|
|
63
|
+
return;
|
|
64
|
+
event.stopPropagation();
|
|
65
|
+
if (request.subscribe) {
|
|
66
|
+
const callback = request.callback;
|
|
67
|
+
this.subscribers.set(callback, this.client);
|
|
68
|
+
callback(this.client, () => this.subscribers.delete(callback));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
request.callback(this.client);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
get host() { return index.getElement(this); }
|
|
75
|
+
static get watchers() { return {
|
|
76
|
+
"client": [{
|
|
77
|
+
"onClientChange": 0
|
|
78
|
+
}]
|
|
79
|
+
}; }
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.pt_provider = PtProvider;
|
|
83
|
+
//# sourceMappingURL=pt-provider.entry.cjs.js.map
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=pt-provider.cjs.entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"file":"pt-provider.cjs.entry.js","mappings":";;;;;MAkDa,UAAU,GAAA,MAAA;AApBvB,IAAA,WAAA,CAAA,OAAA,EAAA;;AA0BE;;;;;AAKG;AACK,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,GAAG,EAA2D;AAmEzF;AAhEC,IAAA,cAAc,CAAC,IAAwB,EAAA;QACrC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;YAC/C,IAAI,IAAI,KAAK,IAAI;gBAAE;YACnB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC;AACpC,YAAA,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;;;AAI3D;;;;;AAKG;IACH,iBAAiB,GAAA;QACf,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAACA,8BAAsB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;;AAG/F;;;;;;;;AAQG;IACH,gBAAgB,GAAA;QACd,IAAI,IAAI,CAAC,MAAM;AAAE,YAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;;AAGnD;;;;;;AAMG;AAEH;;;;;AAKG;AAEH,IAAA,oBAAoB,CAAC,KAAY,EAAA;QAC/B,MAAM,OAAO,GAAG,KAIf;QACD,IAAI,OAAO,CAAC,OAAO,KAAKC,yBAAiB,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;YAAE;QAErF,KAAK,CAAC,eAAe,EAAE;AAEvB,QAAA,IAAI,OAAO,CAAC,SAAS,EAAE;AACrB,YAAA,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;YACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;AAC3C,YAAA,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;;aACzD;AACL,YAAA,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;","names":["CONTEXT_PROVIDER_EVENT","PT_CLIENT_CONTEXT"],"sources":["src/components/pt-provider/pt-provider.tsx"],"sourcesContent":["import { Component, Element, Listen, Prop, Watch } from '@stencil/core';\n\nimport {\n CONTEXT_PROVIDER_EVENT,\n PT_CLIENT_CONTEXT,\n type Client,\n type ContextCallback\n} from '../../utils/context';\n\n/**\n * 向子树提供一个 client。\n *\n * 业务组件暂时都移除了,这个元素是 widgets 层的占位:注入机制先留着,业务组件以后再加。\n *\n * ```html\n * <pt-provider id=\"root\">\n * <!-- 使用 client 的业务组件 -->\n * </pt-provider>\n * <script type=\"module\">\n * document.querySelector('#root').client = client;\n * </script>\n * ```\n *\n * `client` 是对象,只能走 property,不能走 attribute —— 原生 HTML 下\n * attribute 只能传字符串(docs/component-api.md §2 的属性约定)。\n *\n * 可以嵌套:内层 provider 会拦下请求,子树因此可以对接不同的账号或环境。\n *\n * @slot - 使用这个 client 的子树\n */\n@Component({\n tag: 'pt-provider',\n /**\n * 不用 Shadow DOM,而且**故意不实现 render()**。\n *\n * 这个组件的职责是纯运行时的依赖注入,不该在 DOM 上留下任何痕迹。\n * 另外两种写法都试过,都有实际代价:\n *\n * · `shadow: false` + `render() { return <slot /> }`\n * SSR 时 Stencil 会在 slot 位置写入标记节点,客户端渲染没有它们,\n * React 报 hydration #418 并把整棵子树重渲一遍(首屏闪烁)。\n * · `shadow: true` + `<slot />`\n * Nuxt / Vue 的 SSR 会把子树序列化进 Declarative Shadow DOM 模板里,\n * 客户端接管后又在 light DOM 建了一份 —— 页面上出现两个子组件。\n *\n * 不写 render() 时 Stencil 完全不碰宿主的子节点:SSR 输出就是原样的\n * `<pt-provider>…children…</pt-provider>`,两个框架都没有任何可错配的东西。\n */\n shadow: false\n})\nexport class PtProvider {\n @Element() host!: HTMLPtProviderElement;\n\n /** 注入给子树的 client。用 property 赋值 */\n @Prop() client?: Client;\n\n /**\n * 订阅者 → 最近一次交给它的值。\n *\n * client 变了要逐个通知,而不是让它们自己轮询;记住上次的值是为了不重复通知:\n * 同一个 client 发两遍只是多一次无意义的重渲染。\n */\n private subscribers = new Map<ContextCallback<Client | undefined>, Client | undefined>();\n\n @Watch('client')\n onClientChange(next: Client | undefined) {\n for (const [callback, last] of this.subscribers) {\n if (last === next) continue;\n this.subscribers.set(callback, next);\n callback(next, () => this.subscribers.delete(callback));\n }\n }\n\n /**\n * 挂到文档上就广播一声(协议里的 context-provider)。\n *\n * 子组件先于 provider 就绪、或 provider 后来才插进文档 / 在 DOM 里被移动时,\n * 它们之前的请求都没人接;听到这一声会再请求一次。\n */\n connectedCallback() {\n this.host.dispatchEvent(new Event(CONTEXT_PROVIDER_EVENT, { bubbles: true, composed: true }));\n }\n\n /**\n * 首次渲染完成后补一次通知。\n *\n * @Watch 只在组件进入 watch-ready 之后才触发;在那之前写进来的 client\n * 会被 Stencil 静默当成初始值。Angular 正好落在这个窗口里:它先把元素接进\n * 文档(子组件随即发出 context 请求,拿到 undefined 并订阅),再在第一轮变更\n * 检测里写 [client] —— 没有这一次补发,订阅者会永远停在「没有 client」。\n * 已经拿到这个 client 的订阅者不会被重复通知(见 onClientChange)。\n */\n componentDidLoad() {\n if (this.client) this.onClientChange(this.client);\n }\n\n /*\n * 断开时**不**清空订阅者。\n *\n * 消费者各自持有退订函数并在自己卸载时调用;provider 只是在 DOM 里被移动\n * (框架 keep-alive、列表重排)时,订阅要原样保留 —— 清掉的话子组件永远停在旧 client 上,\n * 而它们自己没断连,不会重新请求。provider 真的被丢弃时,这个 Set 随它一起被回收。\n */\n\n /**\n * 拦下子树冒泡上来的 context 请求。\n *\n * `stopPropagation()` 是必须的:不拦住的话,嵌套 provider 时外层也会响应,\n * 子组件会先后收到两个 client,最后一个赢 —— 恰好与「就近取用」的直觉相反。\n */\n @Listen('context-request')\n handleContextRequest(event: Event) {\n const request = event as Event & {\n context?: string;\n callback?: ContextCallback<Client | undefined>;\n subscribe?: boolean;\n };\n if (request.context !== PT_CLIENT_CONTEXT || typeof request.callback !== 'function') return;\n\n event.stopPropagation();\n\n if (request.subscribe) {\n const callback = request.callback;\n this.subscribers.set(callback, this.client);\n callback(this.client, () => this.subscribers.delete(callback));\n } else {\n request.callback(this.client);\n }\n }\n}\n"],"version":3}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-DRCOne2Q.js');
|
|
4
|
+
var appGlobals = require('./app-globals-V2Kpy_OQ.js');
|
|
5
|
+
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
/*
|
|
8
|
+
Stencil Client Patch Browser v4.45.0 | MIT Licensed | https://stenciljs.com
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
var patchBrowser = () => {
|
|
12
|
+
const importMeta = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('ptengine-widgets.cjs.js', document.baseURI).href));
|
|
13
|
+
const opts = {};
|
|
14
|
+
if (importMeta !== "") {
|
|
15
|
+
opts.resourcesUrl = new URL(".", importMeta).href;
|
|
16
|
+
}
|
|
17
|
+
return index.promiseResolve(opts);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
patchBrowser().then(async (options) => {
|
|
21
|
+
await appGlobals.globalScripts();
|
|
22
|
+
return index.bootstrapLazy([["pt-provider.cjs",[[0,"pt-provider",{"client":[16]},[[0,"context-request","handleContextRequest"]],{"client":[{"onClientChange":0}]}]]]], options);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
exports.setNonce = index.setNonce;
|
|
26
|
+
//# sourceMappingURL=ptengine-widgets.cjs.js.map
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=ptengine-widgets.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ptengine-widgets.cjs.js","sources":["../../node_modules/.pnpm/@stencil+core@4.45.0/node_modules/@stencil/core/internal/client/patch-browser.js","@lazy-browser-entrypoint?app-data=conditional"],"sourcesContent":["/*\n Stencil Client Patch Browser v4.45.0 | MIT Licensed | https://stenciljs.com\n */\n\n// src/client/client-patch-browser.ts\nimport { BUILD, NAMESPACE } from \"@stencil/core/internal/app-data\";\nimport { consoleDevInfo, H, promiseResolve, win } from \"@stencil/core\";\nvar patchBrowser = () => {\n if (BUILD.isDev && !BUILD.isTesting) {\n consoleDevInfo(\"Running in development mode.\");\n }\n if (BUILD.cloneNodeFix) {\n patchCloneNodeFix(H.prototype);\n }\n const scriptElm = BUILD.scriptDataOpts ? win.document && Array.from(win.document.querySelectorAll(\"script\")).find(\n (s) => new RegExp(`/${NAMESPACE}(\\\\.esm)?\\\\.js($|\\\\?|#)`).test(s.src) || s.getAttribute(\"data-stencil-namespace\") === NAMESPACE\n ) : null;\n const importMeta = import.meta.url;\n const opts = BUILD.scriptDataOpts ? (scriptElm || {})[\"data-opts\"] || {} : {};\n if (importMeta !== \"\") {\n opts.resourcesUrl = new URL(\".\", importMeta).href;\n }\n return promiseResolve(opts);\n};\nvar patchCloneNodeFix = (HTMLElementPrototype) => {\n const nativeCloneNodeFn = HTMLElementPrototype.cloneNode;\n HTMLElementPrototype.cloneNode = function(deep) {\n if (this.nodeName === \"TEMPLATE\") {\n return nativeCloneNodeFn.call(this, deep);\n }\n const clonedNode = nativeCloneNodeFn.call(this, false);\n const srcChildNodes = this.childNodes;\n if (deep) {\n for (let i = 0; i < srcChildNodes.length; i++) {\n if (srcChildNodes[i].nodeType !== 2) {\n clonedNode.appendChild(srcChildNodes[i].cloneNode(true));\n }\n }\n }\n return clonedNode;\n };\n};\nexport {\n patchBrowser\n};\n","export { setNonce } from '@stencil/core';\nimport { bootstrapLazy } from '@stencil/core';\nimport { patchBrowser } from '@stencil/core/internal/client/patch-browser';\nimport { globalScripts } from '@stencil/core/internal/app-globals';\npatchBrowser().then(async (options) => {\n await globalScripts();\n return bootstrapLazy([/*!__STENCIL_LAZY_DATA__*/], options);\n});\n"],"names":["promiseResolve","globalScripts","bootstrapLazy"],"mappings":";;;;;;AAAA;AACA;AACA;;AAKA,IAAI,YAAY,GAAG,MAAM;AAUzB,EAAE,MAAM,UAAU,GAAG,yQAAe;AACpC,EAAE,MAAM,IAAI,GAAiE,EAAE;AAC/E,EAAE,IAAI,UAAU,KAAK,EAAE,EAAE;AACzB,IAAI,IAAI,CAAC,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,IAAI;AACrD;AACA,EAAE,OAAOA,oBAAc,CAAC,IAAI,CAAC;AAC7B,CAAC;;ACnBD,YAAY,EAAE,CAAC,IAAI,CAAC,OAAO,OAAO,KAAK;AACvC,EAAE,MAAMC,wBAAa,EAAE;AACvB,EAAE,OAAOC,mBAAa,CAAC,4BAA4B,EAAE,OAAO,CAAC;AAC7D,CAAC,CAAC;;;;","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { CONTEXT_PROVIDER_EVENT, PT_CLIENT_CONTEXT } from "../../utils/context";
|
|
2
|
+
/**
|
|
3
|
+
* 向子树提供一个 client。
|
|
4
|
+
*
|
|
5
|
+
* 业务组件暂时都移除了,这个元素是 widgets 层的占位:注入机制先留着,业务组件以后再加。
|
|
6
|
+
*
|
|
7
|
+
* ```html
|
|
8
|
+
* <pt-provider id="root">
|
|
9
|
+
* <!-- 使用 client 的业务组件 -->
|
|
10
|
+
* </pt-provider>
|
|
11
|
+
* <script type="module">
|
|
12
|
+
* document.querySelector('#root').client = client;
|
|
13
|
+
* </script>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* `client` 是对象,只能走 property,不能走 attribute —— 原生 HTML 下
|
|
17
|
+
* attribute 只能传字符串(docs/component-api.md §2 的属性约定)。
|
|
18
|
+
*
|
|
19
|
+
* 可以嵌套:内层 provider 会拦下请求,子树因此可以对接不同的账号或环境。
|
|
20
|
+
*
|
|
21
|
+
* @slot - 使用这个 client 的子树
|
|
22
|
+
*/
|
|
23
|
+
export class PtProvider {
|
|
24
|
+
constructor() {
|
|
25
|
+
/**
|
|
26
|
+
* 订阅者 → 最近一次交给它的值。
|
|
27
|
+
*
|
|
28
|
+
* client 变了要逐个通知,而不是让它们自己轮询;记住上次的值是为了不重复通知:
|
|
29
|
+
* 同一个 client 发两遍只是多一次无意义的重渲染。
|
|
30
|
+
*/
|
|
31
|
+
this.subscribers = new Map();
|
|
32
|
+
}
|
|
33
|
+
onClientChange(next) {
|
|
34
|
+
for (const [callback, last] of this.subscribers) {
|
|
35
|
+
if (last === next)
|
|
36
|
+
continue;
|
|
37
|
+
this.subscribers.set(callback, next);
|
|
38
|
+
callback(next, () => this.subscribers.delete(callback));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 挂到文档上就广播一声(协议里的 context-provider)。
|
|
43
|
+
*
|
|
44
|
+
* 子组件先于 provider 就绪、或 provider 后来才插进文档 / 在 DOM 里被移动时,
|
|
45
|
+
* 它们之前的请求都没人接;听到这一声会再请求一次。
|
|
46
|
+
*/
|
|
47
|
+
connectedCallback() {
|
|
48
|
+
this.host.dispatchEvent(new Event(CONTEXT_PROVIDER_EVENT, { bubbles: true, composed: true }));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 首次渲染完成后补一次通知。
|
|
52
|
+
*
|
|
53
|
+
* @Watch 只在组件进入 watch-ready 之后才触发;在那之前写进来的 client
|
|
54
|
+
* 会被 Stencil 静默当成初始值。Angular 正好落在这个窗口里:它先把元素接进
|
|
55
|
+
* 文档(子组件随即发出 context 请求,拿到 undefined 并订阅),再在第一轮变更
|
|
56
|
+
* 检测里写 [client] —— 没有这一次补发,订阅者会永远停在「没有 client」。
|
|
57
|
+
* 已经拿到这个 client 的订阅者不会被重复通知(见 onClientChange)。
|
|
58
|
+
*/
|
|
59
|
+
componentDidLoad() {
|
|
60
|
+
if (this.client)
|
|
61
|
+
this.onClientChange(this.client);
|
|
62
|
+
}
|
|
63
|
+
/*
|
|
64
|
+
* 断开时**不**清空订阅者。
|
|
65
|
+
*
|
|
66
|
+
* 消费者各自持有退订函数并在自己卸载时调用;provider 只是在 DOM 里被移动
|
|
67
|
+
* (框架 keep-alive、列表重排)时,订阅要原样保留 —— 清掉的话子组件永远停在旧 client 上,
|
|
68
|
+
* 而它们自己没断连,不会重新请求。provider 真的被丢弃时,这个 Set 随它一起被回收。
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* 拦下子树冒泡上来的 context 请求。
|
|
72
|
+
*
|
|
73
|
+
* `stopPropagation()` 是必须的:不拦住的话,嵌套 provider 时外层也会响应,
|
|
74
|
+
* 子组件会先后收到两个 client,最后一个赢 —— 恰好与「就近取用」的直觉相反。
|
|
75
|
+
*/
|
|
76
|
+
handleContextRequest(event) {
|
|
77
|
+
const request = event;
|
|
78
|
+
if (request.context !== PT_CLIENT_CONTEXT || typeof request.callback !== 'function')
|
|
79
|
+
return;
|
|
80
|
+
event.stopPropagation();
|
|
81
|
+
if (request.subscribe) {
|
|
82
|
+
const callback = request.callback;
|
|
83
|
+
this.subscribers.set(callback, this.client);
|
|
84
|
+
callback(this.client, () => this.subscribers.delete(callback));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
request.callback(this.client);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
static get is() { return "pt-provider"; }
|
|
91
|
+
static get properties() {
|
|
92
|
+
return {
|
|
93
|
+
"client": {
|
|
94
|
+
"type": "unknown",
|
|
95
|
+
"mutable": false,
|
|
96
|
+
"complexType": {
|
|
97
|
+
"original": "Client",
|
|
98
|
+
"resolved": "object | undefined",
|
|
99
|
+
"references": {
|
|
100
|
+
"Client": {
|
|
101
|
+
"location": "import",
|
|
102
|
+
"path": "../../utils/context",
|
|
103
|
+
"id": "src/utils/context.ts::Client",
|
|
104
|
+
"referenceLocation": "Client"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"required": false,
|
|
109
|
+
"optional": true,
|
|
110
|
+
"docs": {
|
|
111
|
+
"tags": [],
|
|
112
|
+
"text": "\u6CE8\u5165\u7ED9\u5B50\u6811\u7684 client\u3002\u7528 property \u8D4B\u503C"
|
|
113
|
+
},
|
|
114
|
+
"getter": false,
|
|
115
|
+
"setter": false
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
static get elementRef() { return "host"; }
|
|
120
|
+
static get watchers() {
|
|
121
|
+
return [{
|
|
122
|
+
"propName": "client",
|
|
123
|
+
"methodName": "onClientChange"
|
|
124
|
+
}];
|
|
125
|
+
}
|
|
126
|
+
static get listeners() {
|
|
127
|
+
return [{
|
|
128
|
+
"name": "context-request",
|
|
129
|
+
"method": "handleContextRequest",
|
|
130
|
+
"target": undefined,
|
|
131
|
+
"capture": false,
|
|
132
|
+
"passive": false
|
|
133
|
+
}];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=pt-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pt-provider.js","sourceRoot":"","sources":["../../../src/components/pt-provider/pt-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;GAoBG;AAqBH,MAAM,OAAO,UAAU;IApBvB;QA0BE;;;;;WAKG;QACK,gBAAW,GAAG,IAAI,GAAG,EAA2D,CAAC;KAmE1F;IAhEC,cAAc,CAAC,IAAwB;QACrC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAChD,IAAI,IAAI,KAAK,IAAI;gBAAE,SAAS;YAC5B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACrC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,iBAAiB;QACf,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChG,CAAC;IAED;;;;;;;;OAQG;IACH,gBAAgB;QACd,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IAED;;;;;;OAMG;IAEH;;;;;OAKG;IAEH,oBAAoB,CAAC,KAAY;QAC/B,MAAM,OAAO,GAAG,KAIf,CAAC;QACF,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,IAAI,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO;QAE5F,KAAK,CAAC,eAAe,EAAE,CAAC;QAExB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5C,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACF","sourcesContent":["import { Component, Element, Listen, Prop, Watch } from '@stencil/core';\n\nimport {\n CONTEXT_PROVIDER_EVENT,\n PT_CLIENT_CONTEXT,\n type Client,\n type ContextCallback\n} from '../../utils/context';\n\n/**\n * 向子树提供一个 client。\n *\n * 业务组件暂时都移除了,这个元素是 widgets 层的占位:注入机制先留着,业务组件以后再加。\n *\n * ```html\n * <pt-provider id=\"root\">\n * <!-- 使用 client 的业务组件 -->\n * </pt-provider>\n * <script type=\"module\">\n * document.querySelector('#root').client = client;\n * </script>\n * ```\n *\n * `client` 是对象,只能走 property,不能走 attribute —— 原生 HTML 下\n * attribute 只能传字符串(docs/component-api.md §2 的属性约定)。\n *\n * 可以嵌套:内层 provider 会拦下请求,子树因此可以对接不同的账号或环境。\n *\n * @slot - 使用这个 client 的子树\n */\n@Component({\n tag: 'pt-provider',\n /**\n * 不用 Shadow DOM,而且**故意不实现 render()**。\n *\n * 这个组件的职责是纯运行时的依赖注入,不该在 DOM 上留下任何痕迹。\n * 另外两种写法都试过,都有实际代价:\n *\n * · `shadow: false` + `render() { return <slot /> }`\n * SSR 时 Stencil 会在 slot 位置写入标记节点,客户端渲染没有它们,\n * React 报 hydration #418 并把整棵子树重渲一遍(首屏闪烁)。\n * · `shadow: true` + `<slot />`\n * Nuxt / Vue 的 SSR 会把子树序列化进 Declarative Shadow DOM 模板里,\n * 客户端接管后又在 light DOM 建了一份 —— 页面上出现两个子组件。\n *\n * 不写 render() 时 Stencil 完全不碰宿主的子节点:SSR 输出就是原样的\n * `<pt-provider>…children…</pt-provider>`,两个框架都没有任何可错配的东西。\n */\n shadow: false\n})\nexport class PtProvider {\n @Element() host!: HTMLPtProviderElement;\n\n /** 注入给子树的 client。用 property 赋值 */\n @Prop() client?: Client;\n\n /**\n * 订阅者 → 最近一次交给它的值。\n *\n * client 变了要逐个通知,而不是让它们自己轮询;记住上次的值是为了不重复通知:\n * 同一个 client 发两遍只是多一次无意义的重渲染。\n */\n private subscribers = new Map<ContextCallback<Client | undefined>, Client | undefined>();\n\n @Watch('client')\n onClientChange(next: Client | undefined) {\n for (const [callback, last] of this.subscribers) {\n if (last === next) continue;\n this.subscribers.set(callback, next);\n callback(next, () => this.subscribers.delete(callback));\n }\n }\n\n /**\n * 挂到文档上就广播一声(协议里的 context-provider)。\n *\n * 子组件先于 provider 就绪、或 provider 后来才插进文档 / 在 DOM 里被移动时,\n * 它们之前的请求都没人接;听到这一声会再请求一次。\n */\n connectedCallback() {\n this.host.dispatchEvent(new Event(CONTEXT_PROVIDER_EVENT, { bubbles: true, composed: true }));\n }\n\n /**\n * 首次渲染完成后补一次通知。\n *\n * @Watch 只在组件进入 watch-ready 之后才触发;在那之前写进来的 client\n * 会被 Stencil 静默当成初始值。Angular 正好落在这个窗口里:它先把元素接进\n * 文档(子组件随即发出 context 请求,拿到 undefined 并订阅),再在第一轮变更\n * 检测里写 [client] —— 没有这一次补发,订阅者会永远停在「没有 client」。\n * 已经拿到这个 client 的订阅者不会被重复通知(见 onClientChange)。\n */\n componentDidLoad() {\n if (this.client) this.onClientChange(this.client);\n }\n\n /*\n * 断开时**不**清空订阅者。\n *\n * 消费者各自持有退订函数并在自己卸载时调用;provider 只是在 DOM 里被移动\n * (框架 keep-alive、列表重排)时,订阅要原样保留 —— 清掉的话子组件永远停在旧 client 上,\n * 而它们自己没断连,不会重新请求。provider 真的被丢弃时,这个 Set 随它一起被回收。\n */\n\n /**\n * 拦下子树冒泡上来的 context 请求。\n *\n * `stopPropagation()` 是必须的:不拦住的话,嵌套 provider 时外层也会响应,\n * 子组件会先后收到两个 client,最后一个赢 —— 恰好与「就近取用」的直觉相反。\n */\n @Listen('context-request')\n handleContextRequest(event: Event) {\n const request = event as Event & {\n context?: string;\n callback?: ContextCallback<Client | undefined>;\n subscribe?: boolean;\n };\n if (request.context !== PT_CLIENT_CONTEXT || typeof request.callback !== 'function') return;\n\n event.stopPropagation();\n\n if (request.subscribe) {\n const callback = request.callback;\n this.subscribers.set(callback, this.client);\n callback(this.client, () => this.subscribers.delete(callback));\n } else {\n request.callback(this.client);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ptengine/widgets —— 业务组件内核的公共入口。
|
|
3
|
+
*
|
|
4
|
+
* 业务组件不自己创建 client:把它们放在 `<pt-provider>` 里,
|
|
5
|
+
* 组件挂载时会向上请求一个 client(Context Protocol,走 DOM 事件,跨框架一致)。
|
|
6
|
+
*/
|
|
7
|
+
export { CONTEXT_PROVIDER_EVENT, PT_CLIENT_CONTEXT, ContextRequestEvent, requestClient } from './utils/context';
|
|
8
|
+
export * from './components';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACd,MAAM,iBAAiB,CAAC;AAGzB,cAAc,cAAc,CAAC","sourcesContent":["/**\n * @ptengine/widgets —— 业务组件内核的公共入口。\n *\n * 业务组件不自己创建 client:把它们放在 `<pt-provider>` 里,\n * 组件挂载时会向上请求一个 client(Context Protocol,走 DOM 事件,跨框架一致)。\n */\nexport {\n CONTEXT_PROVIDER_EVENT,\n PT_CLIENT_CONTEXT,\n ContextRequestEvent,\n requestClient\n} from './utils/context';\nexport type { Client, ContextCallback } from './utils/context';\n\nexport * from './components';\n"]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 依赖注入:Web Components 社区的 Context Protocol。
|
|
3
|
+
*
|
|
4
|
+
* 业务组件不自己创建 client,也不读全局变量,而是在挂载时向上冒泡一个
|
|
5
|
+
* `context-request` 事件,由最近的 `<pt-provider>` 回调返回 client。
|
|
6
|
+
*
|
|
7
|
+
* 选它而不是各框架自己的 context 机制,是因为它走的是 DOM 事件:
|
|
8
|
+
* React、Vue、Angular、原生 HTML 里行为完全一致,也能穿透 Shadow DOM
|
|
9
|
+
* (事件带 composed: true)。两层因此可以独立发版、独立测试。
|
|
10
|
+
*
|
|
11
|
+
* 协议出处:https://github.com/webcomponents-cg/community-protocols
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* context 的标识。
|
|
15
|
+
*
|
|
16
|
+
* 用字符串而不是 Symbol:页面上同时存在两份打包产物时(比如宿主应用装了一份、
|
|
17
|
+
* 某个微前端子应用又装了一份),两个 Symbol 不相等,注入会静默失败;
|
|
18
|
+
* 字符串永远相等。代价是理论上可能与别人撞名,所以带上包名前缀。
|
|
19
|
+
*/
|
|
20
|
+
export const PT_CLIENT_CONTEXT = '@ptengine/client';
|
|
21
|
+
/** provider 挂到文档上时广播的事件名(协议里的 context-provider):未得到应答的消费者据此再问一次 */
|
|
22
|
+
export const CONTEXT_PROVIDER_EVENT = 'context-provider';
|
|
23
|
+
export class ContextRequestEvent extends Event {
|
|
24
|
+
constructor(context, callback, subscribe = false) {
|
|
25
|
+
super('context-request', { bubbles: true, composed: true, cancelable: true });
|
|
26
|
+
this.context = context;
|
|
27
|
+
this.callback = callback;
|
|
28
|
+
this.subscribe = subscribe;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 向上请求一个 client。
|
|
33
|
+
*
|
|
34
|
+
* `subscribe: true` 时,provider 换了 client 会再次回调(例如切换账号),
|
|
35
|
+
* 返回值是退订函数 —— 组件在 disconnectedCallback 里调用它。
|
|
36
|
+
*
|
|
37
|
+
* 找不到 provider 时回调不会被触发,组件应当据此降级(显示「未接入」而不是报错)。
|
|
38
|
+
*/
|
|
39
|
+
export function requestClient(element, callback, subscribe = true) {
|
|
40
|
+
let unsubscribe;
|
|
41
|
+
let answered = false;
|
|
42
|
+
let released = false;
|
|
43
|
+
/** 发出去的请求编号与被接受的那一个:同一个消费者只能持有一份订阅 */
|
|
44
|
+
let latest = 0;
|
|
45
|
+
let accepted = 0;
|
|
46
|
+
const fire = () => {
|
|
47
|
+
const id = ++latest;
|
|
48
|
+
element.dispatchEvent(new ContextRequestEvent(PT_CLIENT_CONTEXT, (value, dispose) => {
|
|
49
|
+
/* 组件已经退订(卸载)后才姗姗来迟的应答,直接丢掉。
|
|
50
|
+
* 另一种迟到:兜底重试发了第二个请求,而第一个其实被 provider 排队了
|
|
51
|
+
* (Stencil 在实例就绪前会把 @Listen 收到的事件先攒着、就绪后重放),
|
|
52
|
+
* 两个都被应答就成了两份订阅 —— 只认第一份,其余的当场退订。 */
|
|
53
|
+
if (released || (answered && id !== accepted)) {
|
|
54
|
+
dispose?.();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
answered = true;
|
|
58
|
+
accepted = id;
|
|
59
|
+
/* 只记住最新的退订函数,**不要**调用旧的:provider 每次通知都会给一个新的
|
|
60
|
+
* dispose,而它们删除的是同一个订阅。调旧的等于把自己退订 ——
|
|
61
|
+
* 消费者从此只能收到两次值,第二次换 client 之后永久停更。 */
|
|
62
|
+
if (dispose)
|
|
63
|
+
unsubscribe = dispose;
|
|
64
|
+
callback(value);
|
|
65
|
+
}, subscribe));
|
|
66
|
+
};
|
|
67
|
+
fire();
|
|
68
|
+
/**
|
|
69
|
+
* 没人应答时不能就此放弃:上层的 <pt-provider> 未必比子组件先就绪。
|
|
70
|
+
*
|
|
71
|
+
* 两种情况,两条兜底:
|
|
72
|
+
* 1. provider 的类还没注册(懒加载,Vue / Nuxt 里实测子组件先 upgrade):
|
|
73
|
+
* 等 whenDefined 兑现后再要一次;
|
|
74
|
+
* 2. provider 后插入文档、或在 DOM 里被移动(keep-alive、列表重排):
|
|
75
|
+
* 它 connected 时会广播 context-provider,听到就再要一次。
|
|
76
|
+
* 此刻 provider 的 client 可能仍是 undefined(框架还没把 prop 写进来),没关系:
|
|
77
|
+
* subscribe 已经挂上,等 prop 写进来时 @Watch 会再通知一次。
|
|
78
|
+
*/
|
|
79
|
+
const retry = () => {
|
|
80
|
+
if (!answered && !released && element.isConnected)
|
|
81
|
+
fire();
|
|
82
|
+
};
|
|
83
|
+
if (!answered && typeof customElements !== 'undefined') {
|
|
84
|
+
void customElements.whenDefined('pt-provider').then(retry);
|
|
85
|
+
}
|
|
86
|
+
/* 挂在 document 上:provider 的广播带 composed,从任何影子树里都能冒到这里 */
|
|
87
|
+
const onProviderAvailable = () => retry();
|
|
88
|
+
if (!answered && typeof document !== 'undefined') {
|
|
89
|
+
document.addEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);
|
|
90
|
+
}
|
|
91
|
+
return () => {
|
|
92
|
+
released = true;
|
|
93
|
+
if (typeof document !== 'undefined')
|
|
94
|
+
document.removeEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);
|
|
95
|
+
unsubscribe?.();
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/utils/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAA2B,CAAC;AAE7D,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAA2B,CAAC;AAIlE,MAAM,OAAO,mBAAuB,SAAQ,KAAK;IAK/C,YAAY,OAAe,EAAE,QAA4B,EAAE,SAAS,GAAG,KAAK;QAC1E,KAAK,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAoB,EACpB,QAA6C,EAC7C,SAAS,GAAG,IAAI;IAEhB,IAAI,WAAqC,CAAC;IAC1C,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,sCAAsC;IACtC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,aAAa,CACnB,IAAI,mBAAmB,CACrB,iBAAiB,EACjB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACjB;;;iDAGqC;YACrC,IAAI,QAAQ,IAAI,CAAC,QAAQ,IAAI,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC9C,OAAO,EAAE,EAAE,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,QAAQ,GAAG,IAAI,CAAC;YAChB,QAAQ,GAAG,EAAE,CAAC;YACd;;kDAEsC;YACtC,IAAI,OAAO;gBAAE,WAAW,GAAG,OAAO,CAAC;YACnC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,EACD,SAAS,CACV,CACF,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,EAAE,CAAC;IAEP;;;;;;;;;;OAUG;IACH,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW;YAAE,IAAI,EAAE,CAAC;IAC5D,CAAC,CAAC;IAEF,IAAI,CAAC,QAAQ,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;QACvD,KAAK,cAAc,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,wDAAwD;IACxD,MAAM,mBAAmB,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IAC1C,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;QACjD,QAAQ,CAAC,gBAAgB,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,GAAG,EAAE;QACV,QAAQ,GAAG,IAAI,CAAC;QAChB,IAAI,OAAO,QAAQ,KAAK,WAAW;YACjC,QAAQ,CAAC,mBAAmB,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;QAC5E,WAAW,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * 依赖注入:Web Components 社区的 Context Protocol。\n *\n * 业务组件不自己创建 client,也不读全局变量,而是在挂载时向上冒泡一个\n * `context-request` 事件,由最近的 `<pt-provider>` 回调返回 client。\n *\n * 选它而不是各框架自己的 context 机制,是因为它走的是 DOM 事件:\n * React、Vue、Angular、原生 HTML 里行为完全一致,也能穿透 Shadow DOM\n * (事件带 composed: true)。两层因此可以独立发版、独立测试。\n *\n * 协议出处:https://github.com/webcomponents-cg/community-protocols\n */\n\n/**\n * 注入给子树的 client。\n *\n * 能力层 SDK 暂时移除,这里是它的占位:provider 只做引用传递,不关心 client 长什么样。\n * 将来 SDK 加回来时换成 `@ptengine/sdk` 的 `Client`。\n */\nexport type Client = object;\n\n/**\n * context 的标识。\n *\n * 用字符串而不是 Symbol:页面上同时存在两份打包产物时(比如宿主应用装了一份、\n * 某个微前端子应用又装了一份),两个 Symbol 不相等,注入会静默失败;\n * 字符串永远相等。代价是理论上可能与别人撞名,所以带上包名前缀。\n */\nexport const PT_CLIENT_CONTEXT = '@ptengine/client' as const;\n\n/** provider 挂到文档上时广播的事件名(协议里的 context-provider):未得到应答的消费者据此再问一次 */\nexport const CONTEXT_PROVIDER_EVENT = 'context-provider' as const;\n\nexport type ContextCallback<T> = (value: T, unsubscribe?: () => void) => void;\n\nexport class ContextRequestEvent<T> extends Event {\n readonly context: string;\n readonly callback: ContextCallback<T>;\n readonly subscribe: boolean;\n\n constructor(context: string, callback: ContextCallback<T>, subscribe = false) {\n super('context-request', { bubbles: true, composed: true, cancelable: true });\n this.context = context;\n this.callback = callback;\n this.subscribe = subscribe;\n }\n}\n\n/**\n * 向上请求一个 client。\n *\n * `subscribe: true` 时,provider 换了 client 会再次回调(例如切换账号),\n * 返回值是退订函数 —— 组件在 disconnectedCallback 里调用它。\n *\n * 找不到 provider 时回调不会被触发,组件应当据此降级(显示「未接入」而不是报错)。\n */\nexport function requestClient(\n element: HTMLElement,\n callback: ContextCallback<Client | undefined>,\n subscribe = true\n): () => void {\n let unsubscribe: (() => void) | undefined;\n let answered = false;\n let released = false;\n /** 发出去的请求编号与被接受的那一个:同一个消费者只能持有一份订阅 */\n let latest = 0;\n let accepted = 0;\n\n const fire = () => {\n const id = ++latest;\n element.dispatchEvent(\n new ContextRequestEvent<Client | undefined>(\n PT_CLIENT_CONTEXT,\n (value, dispose) => {\n /* 组件已经退订(卸载)后才姗姗来迟的应答,直接丢掉。\n * 另一种迟到:兜底重试发了第二个请求,而第一个其实被 provider 排队了\n * (Stencil 在实例就绪前会把 @Listen 收到的事件先攒着、就绪后重放),\n * 两个都被应答就成了两份订阅 —— 只认第一份,其余的当场退订。 */\n if (released || (answered && id !== accepted)) {\n dispose?.();\n return;\n }\n answered = true;\n accepted = id;\n /* 只记住最新的退订函数,**不要**调用旧的:provider 每次通知都会给一个新的\n * dispose,而它们删除的是同一个订阅。调旧的等于把自己退订 ——\n * 消费者从此只能收到两次值,第二次换 client 之后永久停更。 */\n if (dispose) unsubscribe = dispose;\n callback(value);\n },\n subscribe\n )\n );\n };\n\n fire();\n\n /**\n * 没人应答时不能就此放弃:上层的 <pt-provider> 未必比子组件先就绪。\n *\n * 两种情况,两条兜底:\n * 1. provider 的类还没注册(懒加载,Vue / Nuxt 里实测子组件先 upgrade):\n * 等 whenDefined 兑现后再要一次;\n * 2. provider 后插入文档、或在 DOM 里被移动(keep-alive、列表重排):\n * 它 connected 时会广播 context-provider,听到就再要一次。\n * 此刻 provider 的 client 可能仍是 undefined(框架还没把 prop 写进来),没关系:\n * subscribe 已经挂上,等 prop 写进来时 @Watch 会再通知一次。\n */\n const retry = () => {\n if (!answered && !released && element.isConnected) fire();\n };\n\n if (!answered && typeof customElements !== 'undefined') {\n void customElements.whenDefined('pt-provider').then(retry);\n }\n\n /* 挂在 document 上:provider 的广播带 composed,从任何影子树里都能冒到这里 */\n const onProviderAvailable = () => retry();\n if (!answered && typeof document !== 'undefined') {\n document.addEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);\n }\n\n return () => {\n released = true;\n if (typeof document !== 'undefined')\n document.removeEventListener(CONTEXT_PROVIDER_EVENT, onProviderAvailable);\n unsubscribe?.();\n };\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the base path to where the assets can be found. Use "setAssetPath(path)"
|
|
3
|
+
* if the path needs to be customized.
|
|
4
|
+
*/
|
|
5
|
+
export declare const getAssetPath: (path: string) => string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Used to manually set the base path where assets can be found.
|
|
9
|
+
* If the script is used as "module", it's recommended to use "import.meta.url",
|
|
10
|
+
* such as "setAssetPath(import.meta.url)". Other options include
|
|
11
|
+
* "setAssetPath(document.currentScript.src)", or using a bundler's replace plugin to
|
|
12
|
+
* dynamically set the path at build time, such as "setAssetPath(process.env.ASSET_PATH)".
|
|
13
|
+
* But do note that this configuration depends on how your script is bundled, or lack of
|
|
14
|
+
* bundling, and where your assets can be loaded from. Additionally custom bundling
|
|
15
|
+
* will have to ensure the static assets are copied to its build directory.
|
|
16
|
+
*/
|
|
17
|
+
export declare const setAssetPath: (path: string) => void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Used to specify a nonce value that corresponds with an application's CSP.
|
|
21
|
+
* When set, the nonce will be added to all dynamically created script and style tags at runtime.
|
|
22
|
+
* Alternatively, the nonce value can be set on a meta tag in the DOM head
|
|
23
|
+
* (<meta name="csp-nonce" content="{ nonce value here }" />) which
|
|
24
|
+
* will result in the same behavior.
|
|
25
|
+
*/
|
|
26
|
+
export declare const setNonce: (nonce: string) => void
|
|
27
|
+
|
|
28
|
+
export interface SetPlatformOptions {
|
|
29
|
+
raf?: (c: FrameRequestCallback) => number;
|
|
30
|
+
ael?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;
|
|
31
|
+
rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;
|
|
32
|
+
}
|
|
33
|
+
export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;
|
|
34
|
+
|
|
35
|
+
export * from '../types';
|