@repobit/dex-store-elements 2.0.1 → 2.0.3
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/CHANGELOG.md +14 -0
- package/README.md +15 -14
- package/dist/src/actions/action.attributes.d.ts +6 -5
- package/dist/src/actions/action.attributes.js +8 -6
- package/dist/src/actions/action.attributes.js.map +1 -1
- package/dist/src/contexts/context.scope.d.ts +19 -25
- package/dist/src/contexts/context.scope.js +7 -8
- package/dist/src/contexts/context.scope.js.map +1 -1
- package/dist/src/controllers/controller.action-resolve.d.ts +1 -0
- package/dist/src/controllers/controller.action-resolve.js +14 -0
- package/dist/src/controllers/controller.action-resolve.js.map +1 -1
- package/dist/src/core/actions.d.ts +8 -8
- package/dist/src/core/actions.js +4 -4
- package/dist/src/core/actions.js.map +1 -1
- package/dist/src/core/node.scope.d.ts +23 -28
- package/dist/src/core/node.scope.js +12 -35
- package/dist/src/core/node.scope.js.map +1 -1
- package/dist/src/eta/controller.js +11 -1
- package/dist/src/eta/controller.js.map +1 -1
- package/dist/src/eta/types.d.ts +2 -2
- package/dist/src/eta/types.js.map +1 -1
- package/dist/src/renders/attributes/hide.d.ts +1 -1
- package/dist/src/renders/attributes/hide.js +2 -2
- package/dist/src/renders/attributes/hide.js.map +1 -1
- package/dist/src/renders/attributes/utilty.js +1 -0
- package/dist/src/renders/attributes/utilty.js.map +1 -1
- package/dist/src/renders/context.d.ts +13 -16
- package/dist/src/renders/context.js +22 -12
- package/dist/src/renders/context.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.0.3](https://github.com/bitdefender/dex-core/compare/@repobit/dex-store-elements@2.0.2...@repobit/dex-store-elements@2.0.3) (2026-07-24)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **DEX-1000:** restore v1 derived context and event filtering semantics
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [2.0.2](https://github.com/bitdefender/dex-core/compare/@repobit/dex-store-elements@2.0.1...@repobit/dex-store-elements@2.0.2) (2026-07-24)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **DEX-1000:** add tests for price handling and late option resolution
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
## [2.0.1](https://github.com/bitdefender/dex-core/compare/@repobit/dex-store-elements@2.0.0...@repobit/dex-store-elements@2.0.1) (2026-07-23)
|
|
7
21
|
|
|
8
22
|
**Note:** Version bump only for package @repobit/dex-store-elements
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Reactive HTML custom elements + declarative attribute renderers for building dyn
|
|
|
6
6
|
- Declarative renderers via `data-store-*` attributes — no framework glue code
|
|
7
7
|
- Eta templates for text and attributes with a unified DSL context
|
|
8
8
|
- Compute layer (min/max over the reachable option space) feeds a flat state DTO into templates and the hide DSL
|
|
9
|
-
- Composable event topology: ignore-list filtering via `data-store-event-id` + `ignore-events`
|
|
9
|
+
- Composable event topology: node-local ignore-list filtering via `data-store-event-id` + `ignore-events` (`data-store-id` remains a v1 alias)
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
@@ -173,24 +173,25 @@ The Eta context variable is `it` (Eta default). The available shape is identical
|
|
|
173
173
|
- `it.option.*` (only inside `<bd-option>`)
|
|
174
174
|
- `it.product.*` (only inside `<bd-product>`)
|
|
175
175
|
- `it.state.*` / `it.ctx.*` (everywhere — `ctx` is an alias of `state`)
|
|
176
|
-
-
|
|
177
|
-
|
|
176
|
+
- any root-level keys returned by `derived` (see below)
|
|
177
|
+
|
|
178
|
+
The raw `Store`, `BdScope`, transitions, and controller flags are not exposed.
|
|
178
179
|
|
|
179
180
|
Templates can appear in text content (`<p>…{{= it.option.price.discounted }}…</p>`) or implicitly in any attribute whose value contains `{{`.
|
|
180
181
|
|
|
181
182
|
## Derived variables / functions
|
|
182
183
|
|
|
183
184
|
```ts
|
|
184
|
-
context.derived = async ({
|
|
185
|
+
context.derived = async ({ product, option, state }) => ({
|
|
185
186
|
mails: (p) => ((option?.getDevices?.() ?? 0) / p) * 100,
|
|
186
187
|
// Nested overrides are merged into their slot:
|
|
187
188
|
option: { someVar: 'hello' }
|
|
188
189
|
});
|
|
189
190
|
```
|
|
190
191
|
|
|
191
|
-
Read from templates as `{{= it.
|
|
192
|
+
Read from templates as `{{= it.mails(10) }}`. Read from the hide DSL as `it.mails(10)`. The factory may be async and is called whenever the scope inputs change.
|
|
192
193
|
|
|
193
|
-
|
|
194
|
+
As in v1, the returned object is deep-merged into the context root. This also allows a derived object to extend or override nested `option`, `product`, `state`, or `ctx` values.
|
|
194
195
|
|
|
195
196
|
## DSL context reference
|
|
196
197
|
|
|
@@ -198,7 +199,6 @@ The shape exposed to both Eta templates and the hide DSL:
|
|
|
198
199
|
|
|
199
200
|
```ts
|
|
200
201
|
it = {
|
|
201
|
-
store, // raw Store | undefined
|
|
202
202
|
product: { // TemplateProductContext | undefined
|
|
203
203
|
id : string,
|
|
204
204
|
campaign: string | undefined,
|
|
@@ -244,11 +244,11 @@ it = {
|
|
|
244
244
|
min: string, max: string,
|
|
245
245
|
monthly: { min: string, max: string }
|
|
246
246
|
}
|
|
247
|
-
}
|
|
248
|
-
scenarios: number
|
|
247
|
+
}
|
|
249
248
|
},
|
|
250
249
|
ctx, // alias of `state`
|
|
251
|
-
|
|
250
|
+
|
|
251
|
+
// ...root-level values returned by `derived(...)`
|
|
252
252
|
}
|
|
253
253
|
```
|
|
254
254
|
|
|
@@ -256,7 +256,7 @@ Notes
|
|
|
256
256
|
- All price / discount values in the DSL are **formatted strings** (currency-aware). Don't perform numeric comparisons on them.
|
|
257
257
|
- `it.ctx` is an alias of `it.state` for convenience.
|
|
258
258
|
- `it.option.links.trial('30 days')` returns the trial URL for that duration, or `undefined` if no trial is configured.
|
|
259
|
-
- `
|
|
259
|
+
- `derived(...)` receives only `{ option, product, state }`; its result is deep-merged at the root.
|
|
260
260
|
|
|
261
261
|
## Data layer
|
|
262
262
|
|
|
@@ -301,18 +301,19 @@ context.dataLayer = ({ option, event }) => {
|
|
|
301
301
|
| `data-store-set-min`, `data-store-set-max` | Bounds for delta updates. |
|
|
302
302
|
| `data-store-set-use-as-value` (boolean) | Treat `delta` as an absolute value rather than an increment. |
|
|
303
303
|
| `data-store-event-id="…"` | Tag the source element so `ignore-events` on `bd-*` nodes can drop its events. |
|
|
304
|
+
| `data-store-id="…"` | Legacy v1 alias for `data-store-event-id`. The canonical attribute wins when both are present. |
|
|
304
305
|
|
|
305
306
|
For `<input type="number|text">` and `<select>`, the adapter reads the current input value and dispatches a delta update. For `<input type="checkbox|radio">` it fires on click when `checked === true`.
|
|
306
307
|
|
|
307
|
-
### Ignoring events on a
|
|
308
|
+
### Ignoring events on a node
|
|
308
309
|
|
|
309
310
|
```html
|
|
310
311
|
<bd-option ignore-events="devicesBtn, subscriptionBtn">
|
|
311
|
-
<!--
|
|
312
|
+
<!-- this option ignores matching local or inherited transitions -->
|
|
312
313
|
</bd-option>
|
|
313
314
|
```
|
|
314
315
|
|
|
315
|
-
`ignore-events`
|
|
316
|
+
`ignore-events` is node-local, as in v1; it is not copied into `BdScope`. Each node independently decides whether to consume a local or inherited transition. If a parent drops a local event, that event is naturally not forwarded to its descendants. `data-store-event-id` is canonical; legacy `data-store-id` is accepted as an alias.
|
|
316
317
|
|
|
317
318
|
## Registration and initialization
|
|
318
319
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { BdActionCommand } from '../core/actions.js';
|
|
2
2
|
export declare const DATA_ACTION_NODE: "[data-store-action]";
|
|
3
3
|
export declare const DATA_EVENT_ID_ATTR = "data-store-event-id";
|
|
4
|
+
export declare const LEGACY_DATA_STORE_ID_ATTR = "data-store-id";
|
|
4
5
|
/**
|
|
5
|
-
* Reads the optional
|
|
6
|
+
* Reads the optional event-source id from an action element.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* `data-store-event-id` is the canonical v2 spelling because it pairs
|
|
9
|
+
* directly with `ignore-events`. Legacy `data-store-id` is accepted as
|
|
10
|
+
* a fallback so v1 markup keeps working. When both are present, the
|
|
11
|
+
* canonical attribute wins.
|
|
11
12
|
*/
|
|
12
13
|
export declare function readEventId(element: HTMLElement): string | undefined;
|
|
13
14
|
export declare function isActionElement(element: HTMLElement): boolean;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
export const DATA_ACTION_NODE = '[data-store-action]';
|
|
2
2
|
export const DATA_EVENT_ID_ATTR = 'data-store-event-id';
|
|
3
|
+
export const LEGACY_DATA_STORE_ID_ATTR = 'data-store-id';
|
|
3
4
|
/**
|
|
4
|
-
* Reads the optional
|
|
5
|
+
* Reads the optional event-source id from an action element.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* `data-store-event-id` is the canonical v2 spelling because it pairs
|
|
8
|
+
* directly with `ignore-events`. Legacy `data-store-id` is accepted as
|
|
9
|
+
* a fallback so v1 markup keeps working. When both are present, the
|
|
10
|
+
* canonical attribute wins.
|
|
10
11
|
*/
|
|
11
12
|
export function readEventId(element) {
|
|
12
|
-
const value = element.dataset.storeEventId
|
|
13
|
+
const value = element.dataset.storeEventId ||
|
|
14
|
+
element.dataset.storeId;
|
|
13
15
|
if (value === undefined || value === '') {
|
|
14
16
|
return undefined;
|
|
15
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.attributes.js","sourceRoot":"","sources":["../../../src/actions/action.attributes.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAA8B,CAAC;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"action.attributes.js","sourceRoot":"","sources":["../../../src/actions/action.attributes.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAA8B,CAAC;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AACxD,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,OAAoB;IAEpB,MAAM,KAAK,GACT,OAAO,CAAC,OAAO,CAAC,YAAY;QAC5B,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;IAE1B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,OAAoB;IAEpB,OAAO,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAoB;IAEpB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAEhC,IAAI,cAAc,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAE1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO;YACL,IAAI,EAAE,iBAAiB;YACvB,MAAM;SACP,CAAC;IACJ,CAAC;IAED,IACE,CAAC,eAAe,CAAC,OAAO,CAAC;QACzB,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAC1B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI,EAAI,YAAY;QACpB,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,KAAuB;IAEvB,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE3C,IAAI,OAAO,EAAE,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACxC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI,EAAI,iBAAiB;QACzB,MAAM,EAAE;YACN,GAAG,OAAO,CAAC,MAAM;YACjB,KAAK;YACL,GAAG,EAAS,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG;YAC7D,GAAG,EAAS,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG;YAC7D,UAAU,EAAE,IAAI;SACjB;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAoB;IAEpB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;IAElC,IACE,IAAI,KAAK,SAAS;QAClB,IAAI,KAAK,cAAc,EACvB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAE/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI;QACJ,KAAK;QACL,GAAG,EAAS,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC;QACjD,GAAG,EAAS,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC;QACjD,UAAU,EAAE,oBAAoB,CAC9B,OAAO,EACP,oBAAoB,CACrB;QACD,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,OAAoB;IAEpB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAEhC,OAAO;QACL,EAAE,EAAQ,OAAO,CAAC,UAAU;QAC5B,QAAQ,EAAE,OAAO,CAAC,gBAAgB;QAClC,MAAM,EAAI,oBAAoB,CAC5B,OAAO,EACP,gBAAgB,CACjB;QACD,OAAO,EAAO,iBAAiB,CAAC,OAAO,CAAC,eAAe,CAAC;QACxD,YAAY,EAAE,iBAAiB,CAAC,OAAO,CAAC,oBAAoB,CAAC;QAC7D,OAAO,EAAO,WAAW,CAAC,OAAO,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAqB;IAErB,OAAO,CACL,YAAY,IAAI,OAAO;QACvB,kBAAkB,IAAI,OAAO;QAC7B,gBAAgB,IAAI,OAAO;QAC3B,iBAAiB,IAAI,OAAO;QAC5B,sBAAsB,IAAI,OAAO,CAClC,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAChB,KAAyB;IAEzB,IACE,KAAK,KAAK,MAAM;QAChB,KAAK,KAAK,MAAM,EAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,oBAAoB,CAC3B,OAAqB,EACrB,GAAW;IAEX,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE3B,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,MAAM,CAAC;AAC1C,CAAC;AAED,SAAS,gBAAgB,CACvB,KAAyB;IAEzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAE/B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACzB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,CAAC;AACb,CAAC;AAED,SAAS,iBAAiB,CACxB,KAAyB;IAEzB,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAEvC,IACE,MAAM,KAAK,SAAS;QACpB,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACxB,MAAM,GAAG,CAAC;QACV,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EACzB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type {\n Action,\n BdActionCommand,\n UpdateByDelta\n} from '@/core/actions.js';\n\nexport const DATA_ACTION_NODE = '[data-store-action]' as const;\nexport const DATA_EVENT_ID_ATTR = 'data-store-event-id';\nexport const LEGACY_DATA_STORE_ID_ATTR = 'data-store-id';\n\n/**\n * Reads the optional event-source id from an action element.\n *\n * `data-store-event-id` is the canonical v2 spelling because it pairs\n * directly with `ignore-events`. Legacy `data-store-id` is accepted as\n * a fallback so v1 markup keeps working. When both are present, the\n * canonical attribute wins.\n */\nexport function readEventId(\n element: HTMLElement\n): string | undefined {\n const value =\n element.dataset.storeEventId ||\n element.dataset.storeId;\n\n if (value === undefined || value === '') {\n return undefined;\n }\n\n return value;\n}\n\nexport function isActionElement(\n element: HTMLElement\n): boolean {\n return element.matches(DATA_ACTION_NODE);\n}\n\nexport function readBdActionCommand(\n element: HTMLElement\n): BdActionCommand | undefined {\n const dataset = element.dataset;\n\n if ('storeSetType' in dataset) {\n const update = readUpdateByDelta(element);\n\n if (!update) {\n return undefined;\n }\n\n return {\n kind: 'update-by-delta',\n update\n };\n }\n\n if (\n !isActionElement(element) &&\n !hasSetActionData(dataset)\n ) {\n return undefined;\n }\n\n return {\n kind : 'set-action',\n action: readSetAction(element)\n };\n}\n\nexport function readInputValueCommand(\n input: HTMLInputElement\n): BdActionCommand | undefined {\n const command = readBdActionCommand(input);\n\n if (command?.kind !== 'update-by-delta') {\n return command;\n }\n\n const delta = toOptionalNumber(input.value);\n\n if (delta === undefined) {\n return undefined;\n }\n\n return {\n kind : 'update-by-delta',\n update: {\n ...command.update,\n delta,\n min : toOptionalNumber(input.min) ?? command.update.min,\n max : toOptionalNumber(input.max) ?? command.update.max,\n useAsValue: true\n }\n };\n}\n\nfunction readUpdateByDelta(\n element: HTMLElement\n): UpdateByDelta | undefined {\n const dataset = element.dataset;\n const type = dataset.storeSetType;\n\n if (\n type !== 'devices' &&\n type !== 'subscription'\n ) {\n return undefined;\n }\n\n const delta = readDelta(dataset.storeSetDelta);\n\n if (delta === undefined) {\n return undefined;\n }\n\n return {\n type,\n delta,\n min : toOptionalNumber(dataset.storeSetMin),\n max : toOptionalNumber(dataset.storeSetMax),\n useAsValue: readBooleanAttribute(\n dataset,\n 'storeSetUseAsValue'\n ),\n eventId: readEventId(element)\n };\n}\n\nfunction readSetAction(\n element: HTMLElement\n): Action {\n const dataset = element.dataset;\n\n return {\n id : dataset.storeSetId,\n campaign: dataset.storeSetCampaign,\n bundle : readBooleanAttribute(\n dataset,\n 'storeSetBundle'\n ),\n devices : toOptionDimension(dataset.storeSetDevices),\n subscription: toOptionDimension(dataset.storeSetSubscription),\n eventId : readEventId(element)\n };\n}\n\nfunction hasSetActionData(\n dataset: DOMStringMap\n): boolean {\n return (\n 'storeSetId' in dataset ||\n 'storeSetCampaign' in dataset ||\n 'storeSetBundle' in dataset ||\n 'storeSetDevices' in dataset ||\n 'storeSetSubscription' in dataset\n );\n}\n\nfunction readDelta(\n value: string | undefined\n): UpdateByDelta['delta'] | undefined {\n if (\n value === 'next' ||\n value === 'prev'\n ) {\n return value;\n }\n\n return toOptionalNumber(value);\n}\n\nfunction readBooleanAttribute(\n dataset: DOMStringMap,\n key: string\n): boolean {\n if (!(key in dataset)) {\n return false;\n }\n\n const value = dataset[key];\n\n return value === '' || value === 'true';\n}\n\nfunction toOptionalNumber(\n value: string | undefined\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n if (!trimmed) {\n return undefined;\n }\n\n const parsed = Number(trimmed);\n\n return Number.isNaN(parsed)\n ? undefined\n : parsed;\n}\n\nfunction toOptionDimension(\n value: string | undefined\n): number | undefined {\n const parsed = toOptionalNumber(value);\n\n if (\n parsed === undefined ||\n !Number.isFinite(parsed) ||\n parsed < 0 ||\n !Number.isInteger(parsed)\n ) {\n return undefined;\n }\n\n return parsed;\n}\n"]}
|
|
@@ -3,51 +3,47 @@ import type { BdTransition } from '../core/actions.js';
|
|
|
3
3
|
import type { EtaMutationBatchSchedule } from '../eta/types.js';
|
|
4
4
|
import type { Product, ProductOption, Store } from '@repobit/dex-store';
|
|
5
5
|
/**
|
|
6
|
-
* Shape that `derived(
|
|
6
|
+
* Shape that v1-compatible `derived(...)` callbacks receive.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* This is deliberately narrower than `BdScope`: transition metadata,
|
|
9
|
+
* the raw store, controller flags, and callbacks are not template data.
|
|
10
|
+
* The returned object is merged into the root Eta/DSL context.
|
|
11
11
|
*/
|
|
12
12
|
export type BdScopeDerivationInput = Readonly<{
|
|
13
|
-
store: Store | undefined;
|
|
14
13
|
product: Product | undefined;
|
|
15
14
|
option: ProductOption | undefined;
|
|
15
|
+
state: BdComputeResult | undefined;
|
|
16
16
|
}>;
|
|
17
17
|
/**
|
|
18
18
|
* Result shape of a `derived` factory.
|
|
19
19
|
*
|
|
20
|
-
* Returned
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Returned values are deep-merged into the root Eta/DSL context,
|
|
21
|
+
* matching v1. A derived `{ canBuy: true }` is therefore read as
|
|
22
|
+
* `it.canBuy`, while nested values can extend or override the base
|
|
23
|
+
* `option`, `product`, `state`, and `ctx` objects.
|
|
23
24
|
*
|
|
24
25
|
* The default is `unknown` to allow flexible per-scope shapes; a
|
|
25
26
|
* concrete node can narrow it locally via a typed wrapper.
|
|
26
27
|
*/
|
|
27
28
|
export type BdScopeDerived = Readonly<Record<string, unknown>>;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* The function MUST be pure — it is invoked synchronously inside
|
|
33
|
-
* `EtaTemplateController`'s `context` callback on every render.
|
|
34
|
-
* The same `store` / `product` / `option` identity arguments
|
|
35
|
-
* produce the same output (by reference) so the `@lit/task` args
|
|
36
|
-
* tuple can short-circuit re-renders.
|
|
30
|
+
* Function that derives additional Eta/DSL template context.
|
|
31
|
+
* Async factories are supported, as they were in v1.
|
|
37
32
|
*
|
|
38
33
|
* @example
|
|
39
34
|
*
|
|
40
35
|
* ```ts
|
|
41
36
|
* const scope: BdScope = {
|
|
42
37
|
* ...createBdStoreScope(store),
|
|
43
|
-
* derived: ({
|
|
38
|
+
* derived: async ({ product, option, state }) => ({
|
|
44
39
|
* hasProduct: Boolean(product),
|
|
45
|
-
* canBuy : Boolean(
|
|
40
|
+
* canBuy : Boolean(product && option),
|
|
41
|
+
* hasState : Boolean(state)
|
|
46
42
|
* })
|
|
47
43
|
* };
|
|
48
44
|
* ```
|
|
49
45
|
*/
|
|
50
|
-
export type BdScopeDeriveFn = (scope: BdScopeDerivationInput) => BdScopeDerived
|
|
46
|
+
export type BdScopeDeriveFn = (scope: BdScopeDerivationInput) => BdScopeDerived | null | undefined | PromiseLike<BdScopeDerived | null | undefined>;
|
|
51
47
|
/**
|
|
52
48
|
* Snapshot delivered to `BdScope.onScopeChange` callbacks.
|
|
53
49
|
*
|
|
@@ -102,7 +98,7 @@ export type BdScope = Readonly<Partial<{
|
|
|
102
98
|
dataLayer: BdDataLayerFn;
|
|
103
99
|
}>>;
|
|
104
100
|
/**
|
|
105
|
-
* Result of running `scope.derived(
|
|
101
|
+
* Result of running `scope.derived(...)` — exposed by helpers
|
|
106
102
|
* that want to apply the derivation outside the Eta context
|
|
107
103
|
* builder (e.g. tests, diagnostics).
|
|
108
104
|
*/
|
|
@@ -117,12 +113,10 @@ export declare function extendBdOptionScope(parentScope: BdScope, option: Produc
|
|
|
117
113
|
*
|
|
118
114
|
* Exposed so non-Eta consumers (tests, diagnostics, future
|
|
119
115
|
* controllers) can reuse the same derivation rule without going
|
|
120
|
-
* through `EtaTemplateController`. Returning `undefined`
|
|
121
|
-
*
|
|
122
|
-
* what to do with the absence (omit the `derived` key vs.
|
|
123
|
-
* publish an empty object).
|
|
116
|
+
* through `EtaTemplateController`. Returning `undefined` means
|
|
117
|
+
* there is no root overlay to merge into the base context.
|
|
124
118
|
*/
|
|
125
|
-
export declare function runBdScopeDerived(scope: BdScope | undefined): BdDerivedResult | undefined
|
|
119
|
+
export declare function runBdScopeDerived(scope: BdScope | undefined, state?: BdComputeResult): Promise<BdDerivedResult | undefined>;
|
|
126
120
|
export declare const bdScopeContext: {
|
|
127
121
|
__context__: Readonly<Partial<{
|
|
128
122
|
store: Store;
|
|
@@ -32,17 +32,16 @@ export function extendBdOptionScope(parentScope, option, transition) {
|
|
|
32
32
|
*
|
|
33
33
|
* Exposed so non-Eta consumers (tests, diagnostics, future
|
|
34
34
|
* controllers) can reuse the same derivation rule without going
|
|
35
|
-
* through `EtaTemplateController`. Returning `undefined`
|
|
36
|
-
*
|
|
37
|
-
* what to do with the absence (omit the `derived` key vs.
|
|
38
|
-
* publish an empty object).
|
|
35
|
+
* through `EtaTemplateController`. Returning `undefined` means
|
|
36
|
+
* there is no root overlay to merge into the base context.
|
|
39
37
|
*/
|
|
40
|
-
export function runBdScopeDerived(scope) {
|
|
41
|
-
|
|
42
|
-
store: scope.store,
|
|
38
|
+
export async function runBdScopeDerived(scope, state) {
|
|
39
|
+
const result = await scope?.derived?.({
|
|
43
40
|
product: scope.product,
|
|
44
|
-
option: scope.option
|
|
41
|
+
option: scope.option,
|
|
42
|
+
state
|
|
45
43
|
});
|
|
44
|
+
return result ?? undefined;
|
|
46
45
|
}
|
|
47
46
|
export const bdScopeContext = createContext(Symbol.for('bd:scope'));
|
|
48
47
|
//# sourceMappingURL=context.scope.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.scope.js","sourceRoot":"","sources":["../../../src/contexts/context.scope.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgI7C,MAAM,UAAU,kBAAkB,CAChC,KAAY,EACZ,UAAyB;IAEzB,OAAO;QACL,KAAK;QACL,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,OAAgB,EAChB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,OAAO;QACP,MAAM,EAAE,SAAS;QACjB,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAoB,EACpB,MAAqB,EACrB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,MAAM;QACN,UAAU;KACX,CAAC;AACJ,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"context.scope.js","sourceRoot":"","sources":["../../../src/contexts/context.scope.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgI7C,MAAM,UAAU,kBAAkB,CAChC,KAAY,EACZ,UAAyB;IAEzB,OAAO;QACL,KAAK;QACL,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,OAAgB,EAChB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,OAAO;QACP,MAAM,EAAE,SAAS;QACjB,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAoB,EACpB,MAAqB,EACrB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,MAAM;QACN,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA0B,EAC1B,KAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,KAAK,EAAE,OAAO,EAAE,CAAC;QACpC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAG,KAAK,CAAC,MAAM;QACrB,KAAK;KACN,CAAC,CAAC;IAEH,OAAO,MAAM,IAAI,SAAS,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GACzB,aAAa,CACX,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CACvB,CAAC","sourcesContent":["import type { BdComputeResult } from '@/compute/compute.expand.js';\nimport type { BdTransition } from '@/core/actions.js';\nimport type { EtaMutationBatchSchedule } from '@/eta/types.js';\nimport { createContext } from '@lit/context';\nimport type { Product, ProductOption, Store } from '@repobit/dex-store';\n\n/**\n * Shape that v1-compatible `derived(...)` callbacks receive.\n *\n * This is deliberately narrower than `BdScope`: transition metadata,\n * the raw store, controller flags, and callbacks are not template data.\n * The returned object is merged into the root Eta/DSL context.\n */\nexport type BdScopeDerivationInput = Readonly<{\n product: Product | undefined;\n option : ProductOption | undefined;\n state : BdComputeResult | undefined;\n}>;\n\n/**\n * Result shape of a `derived` factory.\n *\n * Returned values are deep-merged into the root Eta/DSL context,\n * matching v1. A derived `{ canBuy: true }` is therefore read as\n * `it.canBuy`, while nested values can extend or override the base\n * `option`, `product`, `state`, and `ctx` objects.\n *\n * The default is `unknown` to allow flexible per-scope shapes; a\n * concrete node can narrow it locally via a typed wrapper.\n */\nexport type BdScopeDerived = Readonly<Record<string, unknown>>;\n\n/**\n * Function that derives additional Eta/DSL template context.\n * Async factories are supported, as they were in v1.\n *\n * @example\n *\n * ```ts\n * const scope: BdScope = {\n * ...createBdStoreScope(store),\n * derived: async ({ product, option, state }) => ({\n * hasProduct: Boolean(product),\n * canBuy : Boolean(product && option),\n * hasState : Boolean(state)\n * })\n * };\n * ```\n */\nexport type BdScopeDeriveFn = (\n scope : BdScopeDerivationInput\n) =>\n | BdScopeDerived\n | null\n | undefined\n | PromiseLike<BdScopeDerived | null | undefined>;\n\n/**\n * Snapshot delivered to `BdScope.onScopeChange` callbacks.\n *\n * Intentionally narrow — the hook fires when the published\n * scope of a `BdScopedElement` changes, but consumers should\n * only need the fields that drive template rendering. Adding a\n * new field here is a public surface change (every consumer can\n * read it), so prefer extending `BdScope` and rebinding this\n * snapshot rather than spreading the full scope.\n *\n * `state` carries the current compute result for the scope;\n * `undefined` when compute is disabled or has not run yet.\n */\nexport type BdScopeChangeSnapshot = Readonly<{\n store : Store | undefined;\n product: Product | undefined;\n option : ProductOption | undefined;\n state : BdComputeResult | undefined;\n}>;\n\n/**\n * Callback fired when the published scope of a\n * `BdScopedElement` changes.\n *\n * Invoked from `BdScopedElement.publishScope(...)` when the\n * normalized published scope reference actually changes, and\n * from `BdScopedElement.clearScope()` with all-undefined fields\n * when the scope is cleared. The hook receives the new\n * snapshot — it does NOT need to read the scope itself.\n *\n * The hook is stored on the published scope (`BdScope.onScopeChange`)\n * so it cascades to descendants via `parentScope.onScopeChange`.\n * Descendants may override the inherited hook by supplying\n * their own `onScopeChange` property.\n */\nexport type BdScopeChangeFn = (\n snapshot: BdScopeChangeSnapshot\n) => void;\n\nexport type BdDataLayerEvent =\n | 'all'\n | 'info'\n | 'comparison'\n | (string & {});\n\nexport type BdDataLayerPayload = Readonly<{\n option: ProductOption;\n event : BdDataLayerEvent;\n}>;\n\nexport type BdDataLayerFn = (\n payload: BdDataLayerPayload\n) => void;\n\nexport type BdScope = Readonly<Partial<{\n store : Store;\n product : Product;\n option : ProductOption;\n transition : BdTransition;\n computeDisabled : boolean;\n etaDisabled : boolean;\n derived : BdScopeDeriveFn;\n mutationBatchSchedule: EtaMutationBatchSchedule;\n onScopeChange : BdScopeChangeFn;\n dataLayer : BdDataLayerFn;\n}>>\n\n/**\n * Result of running `scope.derived(...)` — exposed by helpers\n * that want to apply the derivation outside the Eta context\n * builder (e.g. tests, diagnostics).\n */\nexport type BdDerivedResult = BdScopeDerived;\n\nexport function createBdStoreScope(\n store: Store,\n transition?: BdTransition\n): BdScope {\n return {\n store,\n transition\n };\n}\n\nexport function extendBdContextScope(\n parentScope: BdScope,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n transition\n };\n}\n\nexport function extendBdProductScope(\n parentScope: BdScope,\n product: Product,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n product,\n option: undefined,\n transition\n };\n}\n\nexport function extendBdOptionScope(\n parentScope: BdScope,\n option: ProductOption,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n option,\n transition\n };\n}\n\n/**\n * Invokes `scope.derived` when present, otherwise returns\n * `undefined`.\n *\n * Exposed so non-Eta consumers (tests, diagnostics, future\n * controllers) can reuse the same derivation rule without going\n * through `EtaTemplateController`. Returning `undefined` means\n * there is no root overlay to merge into the base context.\n */\nexport async function runBdScopeDerived(\n scope: BdScope | undefined,\n state?: BdComputeResult\n): Promise<BdDerivedResult | undefined> {\n const result = await scope?.derived?.({\n product: scope.product,\n option : scope.option,\n state\n });\n\n return result ?? undefined;\n}\n\nexport const bdScopeContext =\n createContext<BdScope | undefined>(\n Symbol.for('bd:scope')\n );\n"]}
|
|
@@ -86,6 +86,7 @@ export declare class BdActionResolveController<TArgs extends readonly unknown[],
|
|
|
86
86
|
private readonly _resolver;
|
|
87
87
|
private _localTransition?;
|
|
88
88
|
private _lastCommittedTransitionSeq;
|
|
89
|
+
private readonly _rejectedTransitionSeqs;
|
|
89
90
|
private _listening;
|
|
90
91
|
constructor(host: BdActionResolveHost, options: BdActionResolveOptions<TArgs, TDerivedArgs, TResult>);
|
|
91
92
|
hostConnected(): void;
|
|
@@ -15,6 +15,7 @@ export class BdActionResolveController {
|
|
|
15
15
|
this.host = host;
|
|
16
16
|
this.options = options;
|
|
17
17
|
this._lastCommittedTransitionSeq = 0;
|
|
18
|
+
this._rejectedTransitionSeqs = new Set();
|
|
18
19
|
this._listening = false;
|
|
19
20
|
this._onActionRequest = (event) => {
|
|
20
21
|
if (!isBdActionRequestEvent(event)) {
|
|
@@ -105,6 +106,7 @@ export class BdActionResolveController {
|
|
|
105
106
|
}
|
|
106
107
|
abort(reason) {
|
|
107
108
|
this._localTransition = undefined;
|
|
109
|
+
this._rejectedTransitionSeqs.clear();
|
|
108
110
|
this._resolver.abort(reason);
|
|
109
111
|
}
|
|
110
112
|
_args() {
|
|
@@ -119,6 +121,7 @@ export class BdActionResolveController {
|
|
|
119
121
|
_createActionContext(args) {
|
|
120
122
|
const candidate = this._selectTransitionCandidate(args);
|
|
121
123
|
if (!candidate ||
|
|
124
|
+
this._rejectedTransitionSeqs.has(candidate.transition.seq) ||
|
|
122
125
|
candidate.transition.seq <= this._lastCommittedTransitionSeq) {
|
|
123
126
|
return {
|
|
124
127
|
freshTransition: false
|
|
@@ -150,9 +153,15 @@ export class BdActionResolveController {
|
|
|
150
153
|
if (localCandidate && (!filter || filter(localCandidate))) {
|
|
151
154
|
candidates.push(localCandidate);
|
|
152
155
|
}
|
|
156
|
+
else if (localCandidate) {
|
|
157
|
+
this._rejectedTransitionSeqs.add(localCandidate.transition.seq);
|
|
158
|
+
}
|
|
153
159
|
if (parentCandidate && (!filter || filter(parentCandidate))) {
|
|
154
160
|
candidates.push(parentCandidate);
|
|
155
161
|
}
|
|
162
|
+
else if (parentCandidate) {
|
|
163
|
+
this._rejectedTransitionSeqs.add(parentCandidate.transition.seq);
|
|
164
|
+
}
|
|
156
165
|
if (candidates.length === 0) {
|
|
157
166
|
return undefined;
|
|
158
167
|
}
|
|
@@ -174,6 +183,11 @@ export class BdActionResolveController {
|
|
|
174
183
|
return;
|
|
175
184
|
}
|
|
176
185
|
this._lastCommittedTransitionSeq = Math.max(this._lastCommittedTransitionSeq, transition.seq);
|
|
186
|
+
for (const seq of this._rejectedTransitionSeqs) {
|
|
187
|
+
if (seq <= this._lastCommittedTransitionSeq) {
|
|
188
|
+
this._rejectedTransitionSeqs.delete(seq);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
177
191
|
if (this._localTransition === transition) {
|
|
178
192
|
this._localTransition = undefined;
|
|
179
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.action-resolve.js","sourceRoot":"","sources":["../../../src/controllers/controller.action-resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\n\nimport {\n BD_ACTION_REQUEST_EVENT,\n createBdTransition,\n isBdActionRequestEvent,\n type BdActionRequestDetail,\n type BdTransition\n} from '@/core/actions.js';\nimport {\n BdResolveController,\n type BdResolveContext,\n type BdResolveHookPhase,\n type BdResolveHost,\n type BdResolveStatus,\n type BdWorkKey,\n type MaybePromise\n} from './controller.resolve.js';\n\nexport type BdActionResolveTransitionSource =\n | 'local'\n | 'parent';\n\nexport type BdActionResolveContext = Readonly<{\n /**\n * The transition passed to derive/resolve/commit.\n *\n * This is only set for a fresh transition. Once the controller marks a\n * transition committed, the same transition is suppressed from future args.\n */\n transition?: BdTransition;\n\n transitionSeq? : number;\n transitionSource?: BdActionResolveTransitionSource;\n freshTransition : boolean;\n}>;\n\nexport interface BdActionResolveHost extends BdResolveHost, EventTarget {}\n\nexport interface BdActionResolveOptions<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> {\n name? : string;\n workKey?: BdWorkKey;\n\n /**\n * Base node inputs. Keep this close to @lit/task naming.\n *\n * Examples:\n * () => [this.parentScope, this.devices, this.subscription] as const\n */\n args: () => TArgs;\n\n /**\n * Optional downward transition source, usually parentScope.transition.\n *\n * Local bd-action-request events captured by this controller are considered\n * alongside this transition, with the latest seq winning.\n */\n transition?: (args: TArgs) => BdTransition | undefined;\n\n /**\n * Converts base args + a fresh transition into the actual resolver args.\n *\n * This should be pure. It must not publish scope or mutate host props.\n */\n derive: (\n args: TArgs,\n context: BdActionResolveContext\n ) => TDerivedArgs;\n\n enabled?: (\n args: TDerivedArgs,\n context: BdActionResolveContext\n ) => boolean;\n\n argsEqual?: (\n oldArgs: TDerivedArgs,\n newArgs: TDerivedArgs\n ) => boolean;\n\n autoRun?: boolean | 'afterUpdate';\n\n resolve: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<TResult>;\n\n commit?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onPending?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onDisabled?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onComplete?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onError?: (\n error: unknown,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onHookError?: (\n error: unknown,\n phase: BdResolveHookPhase\n ) => void;\n\n abortOnDisconnect?: boolean;\n\n /**\n * If false, this controller only consumes transitions supplied by options.transition.\n */\n captureActions?: boolean;\n\n createTransition?: (\n detail: BdActionRequestDetail,\n event: CustomEvent<BdActionRequestDetail>\n ) => BdTransition;\n\n /**\n * Optional predicate consulted for every transition candidate (both\n * local `bd-action-request` events and parent cascades).\n *\n * Return `false` to drop the candidate; the controller will not feed it\n * into `derive` / `resolve` / `commit`. The host typically uses this to\n * honour the `ignore-events` and `ignore-events-parent` attributes on\n * `bd-*` provider elements.\n */\n filterTransition?: (\n candidate: TransitionCandidate\n ) => boolean;\n}\n\ntype BdActionResolveInternalArgs<\n TDerivedArgs extends readonly unknown[]\n> = readonly [\n args: TDerivedArgs,\n context: BdActionResolveContext\n];\n\ntype TransitionCandidate = Readonly<{\n transition: BdTransition;\n source : BdActionResolveTransitionSource;\n}>;\n\n/**\n * Node workflow controller for the common bd runtime pattern:\n *\n * base args + fresh transition -> derived resolver args\n * enabled -> resolve -> commit\n * mark transition committed only after successful commit\n *\n * It keeps raw DOM requests out of node code and keeps transition seq\n * bookkeeping out of every concrete resolver.\n */\nexport class BdActionResolveController<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> implements ReactiveController {\n private readonly _resolver: BdResolveController<\n BdActionResolveInternalArgs<TDerivedArgs>,\n TResult\n >;\n\n private _localTransition?: BdTransition;\n private _lastCommittedTransitionSeq = 0;\n private _listening = false;\n\n constructor(\n private readonly host: BdActionResolveHost,\n private readonly options:\n BdActionResolveOptions<TArgs, TDerivedArgs, TResult>\n ) {\n host.addController(this);\n\n this._resolver = new BdResolveController(host, {\n name : options.name,\n workKey : options.workKey,\n autoRun : options.autoRun,\n abortOnDisconnect: options.abortOnDisconnect,\n args : () => this._args(),\n argsEqual : (oldArgs, newArgs) =>\n this._argsEqual(\n oldArgs,\n newArgs\n ),\n enabled: ([args, context]) =>\n options.enabled?.(\n args,\n context\n ) ?? true,\n resolve: ([args, actionContext], resolveContext) =>\n options.resolve(\n args,\n resolveContext,\n actionContext\n ),\n commit: async (\n result,\n [args, actionContext],\n resolveContext\n ) => {\n const commitResult =\n options.commit?.(\n result,\n args,\n resolveContext,\n actionContext\n );\n\n if (isPromiseLike(commitResult)) {\n await commitResult;\n }\n\n this._markTransitionCommitted(actionContext);\n },\n onPending: ([args, actionContext], resolveContext) =>\n options.onPending?.(\n args,\n resolveContext,\n actionContext\n ),\n onDisabled: ([args, actionContext], resolveContext) =>\n options.onDisabled?.(\n args,\n resolveContext,\n actionContext\n ),\n onComplete: (\n result,\n [args, actionContext],\n resolveContext\n ) =>\n options.onComplete?.(\n result,\n args,\n resolveContext,\n actionContext\n ),\n onError: (\n error,\n [args, actionContext],\n resolveContext\n ) =>\n options.onError?.(\n error,\n args,\n resolveContext,\n actionContext\n ),\n onHookError: options.onHookError\n });\n }\n\n hostConnected(): void {\n if (this.options.captureActions === false) {\n return;\n }\n\n if (this._listening) {\n return;\n }\n\n this.host.addEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = true;\n }\n\n hostDisconnected(): void {\n if (!this._listening) {\n return;\n }\n\n this.host.removeEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = false;\n }\n\n get status(): BdResolveStatus {\n return this._resolver.status;\n }\n\n get value(): TResult | undefined {\n return this._resolver.value;\n }\n\n get error(): unknown {\n return this._resolver.error;\n }\n\n get pending(): boolean {\n return this._resolver.pending;\n }\n\n get complete(): boolean {\n return this._resolver.complete;\n }\n\n get disabled(): boolean {\n return this._resolver.disabled;\n }\n\n get failed(): boolean {\n return this._resolver.failed;\n }\n\n get localTransition(): BdTransition | undefined {\n return this._localTransition;\n }\n\n run(): Promise<TResult | undefined> {\n return this._resolver.run();\n }\n\n abort(reason?: unknown): void {\n this._localTransition = undefined;\n this._resolver.abort(reason);\n }\n\n private _args(): BdActionResolveInternalArgs<TDerivedArgs> {\n const baseArgs =\n this.options.args();\n\n const context =\n this._createActionContext(baseArgs);\n\n const derivedArgs =\n this.options.derive(\n baseArgs,\n context\n );\n\n return [\n derivedArgs,\n context\n ] as const;\n }\n\n private _createActionContext(\n args: TArgs\n ): BdActionResolveContext {\n const candidate =\n this._selectTransitionCandidate(args);\n\n if (\n !candidate ||\n candidate.transition.seq <= this._lastCommittedTransitionSeq\n ) {\n return {\n freshTransition: false\n };\n }\n\n return {\n transition : candidate.transition,\n transitionSeq : candidate.transition.seq,\n transitionSource: candidate.source,\n freshTransition : true\n };\n }\n\n private _selectTransitionCandidate(\n args: TArgs\n ): TransitionCandidate | undefined {\n const filter = this.options.filterTransition;\n\n const localCandidate =\n this._localTransition\n ? {\n transition: this._localTransition,\n source : 'local' as const\n }\n : undefined;\n\n const parentTransition =\n this.options.transition?.(args);\n\n const parentCandidate =\n parentTransition\n ? {\n transition: parentTransition,\n source : 'parent' as const\n }\n : undefined;\n\n const candidates: TransitionCandidate[] = [];\n\n if (localCandidate && (!filter || filter(localCandidate))) {\n candidates.push(localCandidate);\n }\n\n if (parentCandidate && (!filter || filter(parentCandidate))) {\n candidates.push(parentCandidate);\n }\n\n if (candidates.length === 0) {\n return undefined;\n }\n\n return candidates.reduce((latest, current) =>\n current.transition.seq >= latest.transition.seq ? current : latest\n );\n }\n\n private _argsEqual(\n oldArgs: BdActionResolveInternalArgs<TDerivedArgs>,\n newArgs: BdActionResolveInternalArgs<TDerivedArgs>\n ): boolean {\n const [oldDerivedArgs, oldContext] = oldArgs;\n const [newDerivedArgs, newContext] = newArgs;\n\n if (\n newContext.freshTransition &&\n newContext.transitionSeq !== oldContext.transitionSeq\n ) {\n return false;\n }\n\n return (\n this.options.argsEqual?.(\n oldDerivedArgs,\n newDerivedArgs\n ) ??\n shallowArrayEqual(\n oldDerivedArgs,\n newDerivedArgs\n )\n );\n }\n\n private _markTransitionCommitted(\n context: BdActionResolveContext\n ): void {\n const transition = context.transition;\n\n if (!transition || !context.freshTransition) {\n return;\n }\n\n this._lastCommittedTransitionSeq = Math.max(\n this._lastCommittedTransitionSeq,\n transition.seq\n );\n\n if (this._localTransition === transition) {\n this._localTransition = undefined;\n }\n\n this.host.requestUpdate();\n }\n\n private readonly _onActionRequest = (\n event: Event\n ): void => {\n if (!isBdActionRequestEvent(event)) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const transition =\n this.options.createTransition?.(\n event.detail,\n event\n ) ??\n createBdTransition(\n event.detail,\n event.target\n );\n\n const filter = this.options.filterTransition;\n\n if (\n filter &&\n !filter({\n transition,\n source: 'local'\n })\n ) {\n return;\n }\n\n this._localTransition = transition;\n\n this.host.requestUpdate();\n };\n}\n\nfunction shallowArrayEqual(\n oldArgs: readonly unknown[],\n newArgs: readonly unknown[]\n): boolean {\n if (oldArgs === newArgs) {\n return true;\n }\n\n if (oldArgs.length !== newArgs.length) {\n return false;\n }\n\n for (let index = 0; index < oldArgs.length; index += 1) {\n if (!Object.is(\n oldArgs[index],\n newArgs[index]\n )) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isPromiseLike<T>(\n value: MaybePromise<T> | undefined\n): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller.action-resolve.js","sourceRoot":"","sources":["../../../src/controllers/controller.action-resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\n\nimport {\n BD_ACTION_REQUEST_EVENT,\n createBdTransition,\n isBdActionRequestEvent,\n type BdActionRequestDetail,\n type BdTransition\n} from '@/core/actions.js';\nimport {\n BdResolveController,\n type BdResolveContext,\n type BdResolveHookPhase,\n type BdResolveHost,\n type BdResolveStatus,\n type BdWorkKey,\n type MaybePromise\n} from './controller.resolve.js';\n\nexport type BdActionResolveTransitionSource =\n | 'local'\n | 'parent';\n\nexport type BdActionResolveContext = Readonly<{\n /**\n * The transition passed to derive/resolve/commit.\n *\n * This is only set for a fresh transition. Once the controller marks a\n * transition committed, the same transition is suppressed from future args.\n */\n transition?: BdTransition;\n\n transitionSeq? : number;\n transitionSource?: BdActionResolveTransitionSource;\n freshTransition : boolean;\n}>;\n\nexport interface BdActionResolveHost extends BdResolveHost, EventTarget {}\n\nexport interface BdActionResolveOptions<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> {\n name? : string;\n workKey?: BdWorkKey;\n\n /**\n * Base node inputs. Keep this close to @lit/task naming.\n *\n * Examples:\n * () => [this.parentScope, this.devices, this.subscription] as const\n */\n args: () => TArgs;\n\n /**\n * Optional downward transition source, usually parentScope.transition.\n *\n * Local bd-action-request events captured by this controller are considered\n * alongside this transition, with the latest seq winning.\n */\n transition?: (args: TArgs) => BdTransition | undefined;\n\n /**\n * Converts base args + a fresh transition into the actual resolver args.\n *\n * This should be pure. It must not publish scope or mutate host props.\n */\n derive: (\n args: TArgs,\n context: BdActionResolveContext\n ) => TDerivedArgs;\n\n enabled?: (\n args: TDerivedArgs,\n context: BdActionResolveContext\n ) => boolean;\n\n argsEqual?: (\n oldArgs: TDerivedArgs,\n newArgs: TDerivedArgs\n ) => boolean;\n\n autoRun?: boolean | 'afterUpdate';\n\n resolve: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<TResult>;\n\n commit?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onPending?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onDisabled?: (\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onComplete?: (\n result: TResult,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onError?: (\n error: unknown,\n args: TDerivedArgs,\n resolveContext: BdResolveContext,\n actionContext: BdActionResolveContext\n ) => MaybePromise<void>;\n\n onHookError?: (\n error: unknown,\n phase: BdResolveHookPhase\n ) => void;\n\n abortOnDisconnect?: boolean;\n\n /**\n * If false, this controller only consumes transitions supplied by options.transition.\n */\n captureActions?: boolean;\n\n createTransition?: (\n detail: BdActionRequestDetail,\n event: CustomEvent<BdActionRequestDetail>\n ) => BdTransition;\n\n /**\n * Optional predicate consulted for every transition candidate (both\n * local `bd-action-request` events and parent cascades).\n *\n * Return `false` to drop the candidate; the controller will not feed it\n * into `derive` / `resolve` / `commit`. The host typically uses this to\n * honour the `ignore-events` and `ignore-events-parent` attributes on\n * `bd-*` provider elements.\n */\n filterTransition?: (\n candidate: TransitionCandidate\n ) => boolean;\n}\n\ntype BdActionResolveInternalArgs<\n TDerivedArgs extends readonly unknown[]\n> = readonly [\n args: TDerivedArgs,\n context: BdActionResolveContext\n];\n\ntype TransitionCandidate = Readonly<{\n transition: BdTransition;\n source : BdActionResolveTransitionSource;\n}>;\n\n/**\n * Node workflow controller for the common bd runtime pattern:\n *\n * base args + fresh transition -> derived resolver args\n * enabled -> resolve -> commit\n * mark transition committed only after successful commit\n *\n * It keeps raw DOM requests out of node code and keeps transition seq\n * bookkeeping out of every concrete resolver.\n */\nexport class BdActionResolveController<\n TArgs extends readonly unknown[],\n TDerivedArgs extends readonly unknown[],\n TResult\n> implements ReactiveController {\n private readonly _resolver: BdResolveController<\n BdActionResolveInternalArgs<TDerivedArgs>,\n TResult\n >;\n\n private _localTransition?: BdTransition;\n private _lastCommittedTransitionSeq = 0;\n private readonly _rejectedTransitionSeqs = new Set<number>();\n private _listening = false;\n\n constructor(\n private readonly host: BdActionResolveHost,\n private readonly options:\n BdActionResolveOptions<TArgs, TDerivedArgs, TResult>\n ) {\n host.addController(this);\n\n this._resolver = new BdResolveController(host, {\n name : options.name,\n workKey : options.workKey,\n autoRun : options.autoRun,\n abortOnDisconnect: options.abortOnDisconnect,\n args : () => this._args(),\n argsEqual : (oldArgs, newArgs) =>\n this._argsEqual(\n oldArgs,\n newArgs\n ),\n enabled: ([args, context]) =>\n options.enabled?.(\n args,\n context\n ) ?? true,\n resolve: ([args, actionContext], resolveContext) =>\n options.resolve(\n args,\n resolveContext,\n actionContext\n ),\n commit: async (\n result,\n [args, actionContext],\n resolveContext\n ) => {\n const commitResult =\n options.commit?.(\n result,\n args,\n resolveContext,\n actionContext\n );\n\n if (isPromiseLike(commitResult)) {\n await commitResult;\n }\n\n this._markTransitionCommitted(actionContext);\n },\n onPending: ([args, actionContext], resolveContext) =>\n options.onPending?.(\n args,\n resolveContext,\n actionContext\n ),\n onDisabled: ([args, actionContext], resolveContext) =>\n options.onDisabled?.(\n args,\n resolveContext,\n actionContext\n ),\n onComplete: (\n result,\n [args, actionContext],\n resolveContext\n ) =>\n options.onComplete?.(\n result,\n args,\n resolveContext,\n actionContext\n ),\n onError: (\n error,\n [args, actionContext],\n resolveContext\n ) =>\n options.onError?.(\n error,\n args,\n resolveContext,\n actionContext\n ),\n onHookError: options.onHookError\n });\n }\n\n hostConnected(): void {\n if (this.options.captureActions === false) {\n return;\n }\n\n if (this._listening) {\n return;\n }\n\n this.host.addEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = true;\n }\n\n hostDisconnected(): void {\n if (!this._listening) {\n return;\n }\n\n this.host.removeEventListener(\n BD_ACTION_REQUEST_EVENT,\n this._onActionRequest as EventListener\n );\n\n this._listening = false;\n }\n\n get status(): BdResolveStatus {\n return this._resolver.status;\n }\n\n get value(): TResult | undefined {\n return this._resolver.value;\n }\n\n get error(): unknown {\n return this._resolver.error;\n }\n\n get pending(): boolean {\n return this._resolver.pending;\n }\n\n get complete(): boolean {\n return this._resolver.complete;\n }\n\n get disabled(): boolean {\n return this._resolver.disabled;\n }\n\n get failed(): boolean {\n return this._resolver.failed;\n }\n\n get localTransition(): BdTransition | undefined {\n return this._localTransition;\n }\n\n run(): Promise<TResult | undefined> {\n return this._resolver.run();\n }\n\n abort(reason?: unknown): void {\n this._localTransition = undefined;\n this._rejectedTransitionSeqs.clear();\n this._resolver.abort(reason);\n }\n\n private _args(): BdActionResolveInternalArgs<TDerivedArgs> {\n const baseArgs =\n this.options.args();\n\n const context =\n this._createActionContext(baseArgs);\n\n const derivedArgs =\n this.options.derive(\n baseArgs,\n context\n );\n\n return [\n derivedArgs,\n context\n ] as const;\n }\n\n private _createActionContext(\n args: TArgs\n ): BdActionResolveContext {\n const candidate =\n this._selectTransitionCandidate(args);\n\n if (\n !candidate ||\n this._rejectedTransitionSeqs.has(candidate.transition.seq) ||\n candidate.transition.seq <= this._lastCommittedTransitionSeq\n ) {\n return {\n freshTransition: false\n };\n }\n\n return {\n transition : candidate.transition,\n transitionSeq : candidate.transition.seq,\n transitionSource: candidate.source,\n freshTransition : true\n };\n }\n\n private _selectTransitionCandidate(\n args: TArgs\n ): TransitionCandidate | undefined {\n const filter = this.options.filterTransition;\n\n const localCandidate =\n this._localTransition\n ? {\n transition: this._localTransition,\n source : 'local' as const\n }\n : undefined;\n\n const parentTransition =\n this.options.transition?.(args);\n\n const parentCandidate =\n parentTransition\n ? {\n transition: parentTransition,\n source : 'parent' as const\n }\n : undefined;\n\n const candidates: TransitionCandidate[] = [];\n\n if (localCandidate && (!filter || filter(localCandidate))) {\n candidates.push(localCandidate);\n } else if (localCandidate) {\n this._rejectedTransitionSeqs.add(\n localCandidate.transition.seq\n );\n }\n\n if (parentCandidate && (!filter || filter(parentCandidate))) {\n candidates.push(parentCandidate);\n } else if (parentCandidate) {\n this._rejectedTransitionSeqs.add(\n parentCandidate.transition.seq\n );\n }\n\n if (candidates.length === 0) {\n return undefined;\n }\n\n return candidates.reduce((latest, current) =>\n current.transition.seq >= latest.transition.seq ? current : latest\n );\n }\n\n private _argsEqual(\n oldArgs: BdActionResolveInternalArgs<TDerivedArgs>,\n newArgs: BdActionResolveInternalArgs<TDerivedArgs>\n ): boolean {\n const [oldDerivedArgs, oldContext] = oldArgs;\n const [newDerivedArgs, newContext] = newArgs;\n\n if (\n newContext.freshTransition &&\n newContext.transitionSeq !== oldContext.transitionSeq\n ) {\n return false;\n }\n\n return (\n this.options.argsEqual?.(\n oldDerivedArgs,\n newDerivedArgs\n ) ??\n shallowArrayEqual(\n oldDerivedArgs,\n newDerivedArgs\n )\n );\n }\n\n private _markTransitionCommitted(\n context: BdActionResolveContext\n ): void {\n const transition = context.transition;\n\n if (!transition || !context.freshTransition) {\n return;\n }\n\n this._lastCommittedTransitionSeq = Math.max(\n this._lastCommittedTransitionSeq,\n transition.seq\n );\n\n for (const seq of this._rejectedTransitionSeqs) {\n if (seq <= this._lastCommittedTransitionSeq) {\n this._rejectedTransitionSeqs.delete(seq);\n }\n }\n\n if (this._localTransition === transition) {\n this._localTransition = undefined;\n }\n\n this.host.requestUpdate();\n }\n\n private readonly _onActionRequest = (\n event: Event\n ): void => {\n if (!isBdActionRequestEvent(event)) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const transition =\n this.options.createTransition?.(\n event.detail,\n event\n ) ??\n createBdTransition(\n event.detail,\n event.target\n );\n\n const filter = this.options.filterTransition;\n\n if (\n filter &&\n !filter({\n transition,\n source: 'local'\n })\n ) {\n return;\n }\n\n this._localTransition = transition;\n\n this.host.requestUpdate();\n };\n}\n\nfunction shallowArrayEqual(\n oldArgs: readonly unknown[],\n newArgs: readonly unknown[]\n): boolean {\n if (oldArgs === newArgs) {\n return true;\n }\n\n if (oldArgs.length !== newArgs.length) {\n return false;\n }\n\n for (let index = 0; index < oldArgs.length; index += 1) {\n if (!Object.is(\n oldArgs[index],\n newArgs[index]\n )) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction isPromiseLike<T>(\n value: MaybePromise<T> | undefined\n): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n"]}
|
|
@@ -6,8 +6,8 @@ export type UpdateByDelta = Readonly<{
|
|
|
6
6
|
useAsValue?: boolean;
|
|
7
7
|
/**
|
|
8
8
|
* Optional identifier for the action source element
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
* (`data-store-event-id`, or legacy `data-store-id`). Consumers filter
|
|
10
|
+
* against this id via `ignore-events` on `bd-*` provider elements.
|
|
11
11
|
*/
|
|
12
12
|
eventId?: string;
|
|
13
13
|
}>;
|
|
@@ -19,8 +19,8 @@ export type Action = Readonly<{
|
|
|
19
19
|
subscription?: number;
|
|
20
20
|
/**
|
|
21
21
|
* Optional identifier for the action source element
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* (`data-store-event-id`, or legacy `data-store-id`). Consumers filter
|
|
23
|
+
* against this id via `ignore-events` on `bd-*` provider elements.
|
|
24
24
|
*/
|
|
25
25
|
eventId?: string;
|
|
26
26
|
}>;
|
|
@@ -52,10 +52,10 @@ export declare function isBdActionRequestEvent(event: Event): event is CustomEve
|
|
|
52
52
|
/**
|
|
53
53
|
* Pulls the optional `eventId` off the command carried by a transition.
|
|
54
54
|
*
|
|
55
|
-
* `eventId` is set on the action element via `data-store-event-id="…"`
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* one.
|
|
55
|
+
* `eventId` is set on the action element via `data-store-event-id="…"`
|
|
56
|
+
* (or legacy `data-store-id="…"`) and is the matching key for the
|
|
57
|
+
* `ignore-events="…"` attribute on `bd-*` provider elements. Returns
|
|
58
|
+
* `undefined` for commands that did not declare one.
|
|
59
59
|
*/
|
|
60
60
|
export declare function getCommandEventId(command: BdActionCommand): string | undefined;
|
|
61
61
|
/**
|
package/dist/src/core/actions.js
CHANGED
|
@@ -28,10 +28,10 @@ export function isBdActionRequestEvent(event) {
|
|
|
28
28
|
/**
|
|
29
29
|
* Pulls the optional `eventId` off the command carried by a transition.
|
|
30
30
|
*
|
|
31
|
-
* `eventId` is set on the action element via `data-store-event-id="…"`
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* one.
|
|
31
|
+
* `eventId` is set on the action element via `data-store-event-id="…"`
|
|
32
|
+
* (or legacy `data-store-id="…"`) and is the matching key for the
|
|
33
|
+
* `ignore-events="…"` attribute on `bd-*` provider elements. Returns
|
|
34
|
+
* `undefined` for commands that did not declare one.
|
|
35
35
|
*/
|
|
36
36
|
export function getCommandEventId(command) {
|
|
37
37
|
return command.kind === 'set-action'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/core/actions.ts"],"names":[],"mappings":"AA6CA,MAAM,CAAC,MAAM,uBAAuB,GAClC,mBAA4B,CAAC;AAY/B,IAAI,eAAe,GAAG,CAAC,CAAC;AAExB,MAAM,UAAU,kBAAkB,CAChC,MAA6B,EAC7B,UAA+B;IAE/B,OAAO;QACL,GAAG,EAAQ,EAAE,eAAe;QAC5B,OAAO,EAAI,MAAM,CAAC,OAAO;QACzB,UAAU;QACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,WAAwB,EACxB,MAA6B;IAE7B,OAAO,WAAW,CAAC,aAAa,CAC9B,IAAI,WAAW,CACb,uBAAuB,EACvB;QACE,OAAO,EAAK,IAAI;QAChB,QAAQ,EAAI,IAAI;QAChB,UAAU,EAAE,IAAI;QAChB,MAAM;KACP,CACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAY;IAEZ,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAI,KAA8B,CAAC,MAAM,CAAC;IAEtD,OAAO,CACL,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,SAAS,IAAI,MAAM,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAwB;IAExB,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY;QAClC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO;QACxB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAAwB;IAExB,OAAO,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["export type UpdateByDelta = Readonly<{\n type : 'devices' | 'subscription';\n delta : number | 'next' | 'prev';\n min? : number;\n max? : number;\n useAsValue?: boolean;\n /**\n * Optional identifier for the action source element\n
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/core/actions.ts"],"names":[],"mappings":"AA6CA,MAAM,CAAC,MAAM,uBAAuB,GAClC,mBAA4B,CAAC;AAY/B,IAAI,eAAe,GAAG,CAAC,CAAC;AAExB,MAAM,UAAU,kBAAkB,CAChC,MAA6B,EAC7B,UAA+B;IAE/B,OAAO;QACL,GAAG,EAAQ,EAAE,eAAe;QAC5B,OAAO,EAAI,MAAM,CAAC,OAAO;QACzB,UAAU;QACV,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,WAAwB,EACxB,MAA6B;IAE7B,OAAO,WAAW,CAAC,aAAa,CAC9B,IAAI,WAAW,CACb,uBAAuB,EACvB;QACE,OAAO,EAAK,IAAI;QAChB,QAAQ,EAAI,IAAI;QAChB,UAAU,EAAE,IAAI;QAChB,MAAM;KACP,CACF,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAY;IAEZ,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAI,KAA8B,CAAC,MAAM,CAAC;IAEtD,OAAO,CACL,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,SAAS,IAAI,MAAM,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAwB;IAExB,OAAO,OAAO,CAAC,IAAI,KAAK,YAAY;QAClC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO;QACxB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,UAAwB;IAExB,OAAO,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["export type UpdateByDelta = Readonly<{\n type : 'devices' | 'subscription';\n delta : number | 'next' | 'prev';\n min? : number;\n max? : number;\n useAsValue?: boolean;\n /**\n * Optional identifier for the action source element\n * (`data-store-event-id`, or legacy `data-store-id`). Consumers filter\n * against this id via `ignore-events` on `bd-*` provider elements.\n */\n eventId? : string;\n}>;\n\nexport type Action = Readonly<{\n id? : string;\n campaign? : string;\n bundle? : boolean;\n devices? : number;\n subscription?: number;\n /**\n * Optional identifier for the action source element\n * (`data-store-event-id`, or legacy `data-store-id`). Consumers filter\n * against this id via `ignore-events` on `bd-*` provider elements.\n */\n eventId? : string;\n}>;\n\nexport type BdActionCommand =\n | Readonly<{\n kind : 'update-by-delta';\n update: UpdateByDelta;\n }>\n | Readonly<{\n kind : 'set-action';\n action: Action;\n }>;\n\nexport type BdTransition = Readonly<{\n seq : number;\n command : BdActionCommand;\n originNode?: EventTarget | null;\n createdAt : number;\n}>;\n\nexport const BD_ACTION_REQUEST_EVENT =\n 'bd-action-request' as const;\n\nexport type BdActionRequestDetail = Readonly<{\n command: BdActionCommand;\n}>;\n\ndeclare global {\n interface HTMLElementEventMap {\n [BD_ACTION_REQUEST_EVENT]: CustomEvent<BdActionRequestDetail>;\n }\n}\n\nlet bdTransitionSeq = 0;\n\nexport function createBdTransition(\n detail: BdActionRequestDetail,\n originNode?: EventTarget | null\n): BdTransition {\n return {\n seq : ++bdTransitionSeq,\n command : detail.command,\n originNode,\n createdAt: Date.now()\n };\n}\n\nexport function dispatchBdActionRequest(\n eventTarget: EventTarget,\n detail: BdActionRequestDetail\n): boolean {\n return eventTarget.dispatchEvent(\n new CustomEvent<BdActionRequestDetail>(\n BD_ACTION_REQUEST_EVENT,\n {\n bubbles : true,\n composed : true,\n cancelable: true,\n detail\n }\n )\n );\n}\n\nexport function isBdActionRequestEvent(\n event: Event\n): event is CustomEvent<BdActionRequestDetail> {\n if (event.type !== BD_ACTION_REQUEST_EVENT) {\n return false;\n }\n\n const detail = (event as CustomEvent<unknown>).detail;\n\n return (\n typeof detail === 'object' &&\n detail !== null &&\n 'command' in detail\n );\n}\n\n/**\n * Pulls the optional `eventId` off the command carried by a transition.\n *\n * `eventId` is set on the action element via `data-store-event-id=\"…\"`\n * (or legacy `data-store-id=\"…\"`) and is the matching key for the\n * `ignore-events=\"…\"` attribute on `bd-*` provider elements. Returns\n * `undefined` for commands that did not declare one.\n */\nexport function getCommandEventId(\n command: BdActionCommand\n): string | undefined {\n return command.kind === 'set-action'\n ? command.action.eventId\n : command.update.eventId;\n}\n\n/**\n * Convenience wrapper around {@link getCommandEventId} for transitions.\n */\nexport function getTransitionEventId(\n transition: BdTransition\n): string | undefined {\n return getCommandEventId(transition.command);\n}\n"]}
|