@repobit/dex-store-elements 2.0.0 → 2.0.2
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 +15 -0
- package/README.md +308 -285
- package/dist/src/renders/attributes/utilty.js +1 -0
- package/dist/src/renders/attributes/utilty.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
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.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)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **DEX-1000:** add tests for price handling and late option resolution
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [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)
|
|
14
|
+
|
|
15
|
+
**Note:** Version bump only for package @repobit/dex-store-elements
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
## [2.0.0](https://github.com/bitdefender/dex-core/compare/@repobit/dex-store-elements@1.7.3...@repobit/dex-store-elements@2.0.0) (2026-07-23)
|
|
7
22
|
|
|
8
23
|
### ⚠ BREAKING CHANGES
|
package/README.md
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# @repobit/dex-store-elements
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Reactive HTML custom elements + declarative attribute renderers for building dynamic pricing UIs on top of `@repobit/dex-store`.
|
|
4
4
|
|
|
5
|
-
- Custom elements: `<bd-
|
|
6
|
-
-
|
|
7
|
-
- Eta templates for text
|
|
8
|
-
-
|
|
9
|
-
-
|
|
5
|
+
- Custom elements: `<bd-product>`, `<bd-option>`, `<bd-context>` (a Lit-based, scope-providing node tree)
|
|
6
|
+
- Declarative renderers via `data-store-*` attributes — no framework glue code
|
|
7
|
+
- Eta templates for text and attributes with a unified DSL context
|
|
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`
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
|
+
|
|
12
13
|
- Node 18+
|
|
14
|
+
- A browser (or jsdom for tests)
|
|
13
15
|
|
|
14
16
|
## Install
|
|
15
17
|
|
|
@@ -17,80 +19,315 @@ Lightweight HTML custom elements + attribute renderers for building dynamic pric
|
|
|
17
19
|
npm i @repobit/dex-store-elements @repobit/dex-store
|
|
18
20
|
```
|
|
19
21
|
|
|
20
|
-
Peer dependencies are resolved automatically by npm; no extra install command is required.
|
|
21
|
-
|
|
22
22
|
## Quick start
|
|
23
23
|
|
|
24
24
|
```html
|
|
25
|
-
<!-- index.html -->
|
|
26
25
|
<script type="module">
|
|
27
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
registerContextNodes,
|
|
28
|
+
registerActionNodes,
|
|
29
|
+
registerRenderNodes
|
|
30
|
+
} from '@repobit/dex-store-elements';
|
|
28
31
|
import { Store } from '@repobit/dex-store';
|
|
29
32
|
|
|
30
|
-
window.addEventListener('DOMContentLoaded',
|
|
33
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
31
34
|
registerContextNodes();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
const context = document.querySelector('bd-context');
|
|
37
|
+
|
|
38
|
+
context.store = new Store({
|
|
39
|
+
locale : 'en-us',
|
|
35
40
|
provider: { name: 'vlaicu' }
|
|
36
41
|
});
|
|
37
42
|
|
|
38
43
|
// Optional: analytics data layer callback
|
|
39
|
-
// Fires once per <bd-option> that
|
|
40
|
-
|
|
41
|
-
// Example GTM-style push; adapt fields as needed
|
|
44
|
+
// Fires once per <bd-option> that declares `data-layer-event`.
|
|
45
|
+
context.dataLayer = ({ option, event }) => {
|
|
42
46
|
window.dataLayer?.push({
|
|
43
47
|
event,
|
|
44
48
|
productId : option.getProduct().getId(),
|
|
45
49
|
campaign : option.getProduct().getCampaign(),
|
|
46
|
-
variation : option.getVariation(),
|
|
50
|
+
variation : option.getVariation(),
|
|
47
51
|
devices : option.getDevices(),
|
|
48
52
|
subscription: option.getSubscription(),
|
|
49
53
|
price : option.getDiscountedPrice({ currency: false })
|
|
50
54
|
});
|
|
51
55
|
};
|
|
52
56
|
|
|
53
|
-
// Optional:
|
|
54
|
-
|
|
57
|
+
// Optional: derived values/functions available in templates + hide DSL.
|
|
58
|
+
context.derived = async ({ option }) => ({
|
|
55
59
|
mails: (p) => ((option?.getDevices?.() ?? 0) / p) * 100
|
|
56
60
|
});
|
|
57
61
|
|
|
58
|
-
const disposeActions = registerActionNodes(
|
|
59
|
-
const disposeRenders = registerRenderNodes(
|
|
62
|
+
const disposeActions = registerActionNodes(context);
|
|
63
|
+
const disposeRenders = registerRenderNodes(context);
|
|
60
64
|
|
|
61
|
-
//
|
|
65
|
+
// Call disposers during teardown (SPA route changes, dynamic mounts).
|
|
62
66
|
// disposeActions();
|
|
63
67
|
// disposeRenders();
|
|
64
68
|
});
|
|
65
69
|
</script>
|
|
66
70
|
|
|
67
|
-
<bd-
|
|
68
|
-
<bd-product
|
|
71
|
+
<bd-context>
|
|
72
|
+
<bd-product product-id="com.bitdefender.tsmd.v2">
|
|
69
73
|
<bd-option devices="5" subscription="12" data-layer-event="info">
|
|
70
|
-
<!-- Attribute renderers
|
|
74
|
+
<!-- Attribute renderers -->
|
|
71
75
|
<div data-store-render data-store-devices></div>
|
|
72
|
-
<div data-store-render
|
|
76
|
+
<div data-store-render
|
|
77
|
+
data-store-subscription
|
|
78
|
+
data-store-subscription-type="years"></div>
|
|
73
79
|
<div data-store-render data-store-price="discounted || full"></div>
|
|
74
80
|
<a data-store-render data-store-buy-link>Buy</a>
|
|
81
|
+
|
|
75
82
|
<!-- Eta template (text) -->
|
|
76
83
|
<p>Now at only {{= it.option.price.discounted }}!</p>
|
|
77
|
-
|
|
84
|
+
|
|
85
|
+
<!-- Eta template (implicit attribute) -->
|
|
78
86
|
<div title="Devices {{= it.option.devices }}"></div>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
|
|
88
|
+
<!-- Hide via DSL -->
|
|
89
|
+
<div data-store-render
|
|
90
|
+
data-store-hide="!it.option.price.discounted">
|
|
91
|
+
Hidden when no discounted price exists
|
|
82
92
|
</div>
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
|
|
94
|
+
<!-- Action: emit a store event -->
|
|
95
|
+
<button data-store-action
|
|
96
|
+
data-store-set-devices="25"
|
|
97
|
+
data-store-event-id="devicesBtn">
|
|
98
|
+
25 devices
|
|
99
|
+
</button>
|
|
85
100
|
</bd-option>
|
|
86
101
|
</bd-product>
|
|
87
|
-
</bd-
|
|
102
|
+
</bd-context>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Architecture in 30 seconds
|
|
106
|
+
|
|
107
|
+
- `bd-context` publishes a `BdScope` (store, derived, dataLayer, batch schedule) and is a **hard event boundary** — events from outside it cannot drive descendants inside it.
|
|
108
|
+
- `bd-product` consumes a scope, publishes `BdScope.product` (plus a normalised `option` field).
|
|
109
|
+
- `bd-option` consumes a scope and publishes `BdScope.option` after resolving the option from `store + devices + subscription + action`.
|
|
110
|
+
- `registerActionNodes(root)` attaches `BdActionElementAdapter`s to every element matching `[data-store-action]` (or that declares one of the `data-store-set-*` attributes). Adapters dispatch `bd-action-request` events on user interaction; the nearest `bd-*` ancestor catches them and drives its own scope.
|
|
111
|
+
- `registerRenderNodes(root)` walks every `[data-store-render]` element and runs the matching attribute handler whenever an observed attribute changes.
|
|
112
|
+
- Compute (`bd-compute`, opt-out via `compute-disabled`) reduces the reachable option space to a `BdComputeResult` with min/max formatted strings, available as `it.state.*` in templates.
|
|
113
|
+
|
|
114
|
+
## Custom elements
|
|
115
|
+
|
|
116
|
+
Only three elements are registered. `bd-root` / `bd-state` from v1 are intentionally gone — `bd-context` is the scope-publishing root.
|
|
117
|
+
|
|
118
|
+
| Tag | Attributes | Notes |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `<bd-context>` | `ignore-events`, `ignore-events-parent` (always true), `eta-disabled`, `compute-disabled`, `topology-boundary` | Publishes `store`, `derived`, `dataLayer`, `mutationBatchSchedule`. |
|
|
121
|
+
| `<bd-product product-id="…" campaign="…" bundle>` | all the above + `product-id`, `campaign`, `bundle` | Reflects `product-id`, `campaign`, `bundle`. |
|
|
122
|
+
| `<bd-option devices="5" subscription="12" data-layer-event="info">` | all the above + `devices`, `subscription`, `data-layer-event` | Reflects `devices`, `subscription`. Fires `dataLayer` once on first load. |
|
|
123
|
+
|
|
124
|
+
All three extend `BdScopedElement` and pick up every scope-related property (`ignore-events`, `ignore-events-parent`, `eta-disabled`, `compute-disabled`, `topology-boundary`).
|
|
125
|
+
|
|
126
|
+
### Scope-related properties
|
|
127
|
+
|
|
128
|
+
- `ignore-events="a, b, c"` — drop transitions whose `eventId` matches any of the comma-separated ids. Applies to this node **and** every descendant (the cascade is gated here).
|
|
129
|
+
- `ignore-events-parent` (boolean) — drop cascades from the parent scope; only react to local DOM events. `bd-context` enables this by default.
|
|
130
|
+
- `eta-disabled` / `compute-disabled` (boolean) — kill Eta rendering / compute for this subtree.
|
|
131
|
+
- `topology-boundary` (boolean) — on `BdNodeElement`, marks a topology boundary for the action registry.
|
|
132
|
+
|
|
133
|
+
## Render attributes
|
|
134
|
+
|
|
135
|
+
Add `data-store-render` to any element you want re-rendered on scope changes. The matching handler is selected by the data attribute name.
|
|
136
|
+
|
|
137
|
+
| Attribute | Tokens / values | Source |
|
|
138
|
+
| --- | --- | --- |
|
|
139
|
+
| `data-store-devices` | — | current `option.getDevices()` |
|
|
140
|
+
| `data-store-subscription` | — | current `option.getSubscription()` |
|
|
141
|
+
| `data-store-subscription-type` | `months` \| `years` | affects text formatting only |
|
|
142
|
+
| `data-store-text-single` | label string | singular label |
|
|
143
|
+
| `data-store-text-many` | label string | plural label |
|
|
144
|
+
| `data-store-price` | `full`, `discounted`, `full-monthly`, `discounted-monthly` (supports `||` fallbacks) | current option |
|
|
145
|
+
| `data-store-discount` | `value`, `percentage`, `value-monthly`, `percentage-monthly` (supports `||` fallbacks) | current option |
|
|
146
|
+
| `data-store-context-price` | `min-full`, `max-full`, `min-discounted`, `max-discounted`, `min-full-monthly`, `max-full-monthly`, `min-discounted-monthly`, `max-discounted-monthly` | compute result |
|
|
147
|
+
| `data-store-context-discount` | `min-value`, `max-value`, `min-percentage`, `max-percentage`, `min-value-monthly`, `max-value-monthly`, `min-percentage-monthly`, `max-percentage-monthly` | compute result |
|
|
148
|
+
| `data-store-buy-link` | (optional trial duration, e.g. `"30 days"`) | buy URL, or trial URL when a duration is supplied |
|
|
149
|
+
| `data-store-hide` | boolean expression in the DSL | hide the element when truthy |
|
|
150
|
+
| `data-store-hide-type` | `display` (default) \| `opacity` \| `visibility` | how to hide |
|
|
151
|
+
|
|
152
|
+
> `data-store-trial-link` is gone — use `data-store-buy-link="30 days"` to pick a trial URL by duration. Falls back to the regular buy URL when no trial is configured.
|
|
153
|
+
|
|
154
|
+
## Hide DSL
|
|
155
|
+
|
|
156
|
+
Boolean expression compiled once per change, evaluated against the unified context:
|
|
157
|
+
|
|
158
|
+
```html
|
|
159
|
+
<div data-store-render data-store-hide="!it.option.price.discounted">…</div>
|
|
160
|
+
<div data-store-render data-store-hide="it.product.campaign === 'test'">…</div>
|
|
161
|
+
<div data-store-render
|
|
162
|
+
data-store-hide="it.state.discount.percentage.min && !it.mails(10)">
|
|
163
|
+
…
|
|
164
|
+
</div>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The expression runs against the same context the Eta templates see (see `DSL context reference` below). Numeric comparisons on prices are not portable — they're formatted strings and vary by currency. Devices and subscription remain numeric.
|
|
168
|
+
|
|
169
|
+
## Eta templates
|
|
170
|
+
|
|
171
|
+
The Eta context variable is `it` (Eta default). The available shape is identical to the hide DSL:
|
|
172
|
+
|
|
173
|
+
- `it.option.*` (only inside `<bd-option>`)
|
|
174
|
+
- `it.product.*` (only inside `<bd-product>`)
|
|
175
|
+
- `it.state.*` / `it.ctx.*` (everywhere — `ctx` is an alias of `state`)
|
|
176
|
+
- `it.derived.*` (whatever your `derived` factory returned — see below)
|
|
177
|
+
- `it.store` (the raw `@repobit/dex-store` `Store`)
|
|
178
|
+
|
|
179
|
+
Templates can appear in text content (`<p>…{{= it.option.price.discounted }}…</p>`) or implicitly in any attribute whose value contains `{{`.
|
|
180
|
+
|
|
181
|
+
## Derived variables / functions
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
context.derived = async ({ store, product, option }) => ({
|
|
185
|
+
mails: (p) => ((option?.getDevices?.() ?? 0) / p) * 100,
|
|
186
|
+
// Nested overrides are merged into their slot:
|
|
187
|
+
option: { someVar: 'hello' }
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Read from templates as `{{= it.derived.mails(10) }}`. Read from the hide DSL as `it.derived.mails(10)`. The factory is async, called whenever the scope inputs change.
|
|
192
|
+
|
|
193
|
+
`derived` lives in the **nested** `it.derived` slot (not merged into root) — this keeps store-provided fields distinct from user-provided ones. v1's root-merge behaviour is gone.
|
|
194
|
+
|
|
195
|
+
## DSL context reference
|
|
196
|
+
|
|
197
|
+
The shape exposed to both Eta templates and the hide DSL:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
it = {
|
|
201
|
+
store, // raw Store | undefined
|
|
202
|
+
product: { // TemplateProductContext | undefined
|
|
203
|
+
id : string,
|
|
204
|
+
campaign: string | undefined,
|
|
205
|
+
name : string | undefined
|
|
206
|
+
},
|
|
207
|
+
option: { // TemplateOptionContext | undefined
|
|
208
|
+
price: {
|
|
209
|
+
full : string,
|
|
210
|
+
discounted : string | undefined,
|
|
211
|
+
fullMonthly : string,
|
|
212
|
+
discountedMonthly: string | undefined
|
|
213
|
+
},
|
|
214
|
+
discount: {
|
|
215
|
+
percentage : string,
|
|
216
|
+
percentageMonthly: string,
|
|
217
|
+
value : string,
|
|
218
|
+
valueMonthly : string
|
|
219
|
+
},
|
|
220
|
+
links: {
|
|
221
|
+
buy : string | undefined,
|
|
222
|
+
trial: (trialDuration: string) => string | undefined
|
|
223
|
+
},
|
|
224
|
+
devices : number,
|
|
225
|
+
subscription: number
|
|
226
|
+
},
|
|
227
|
+
state: { // TemplateStateContext | undefined
|
|
228
|
+
price: {
|
|
229
|
+
full: {
|
|
230
|
+
min: string, max: string,
|
|
231
|
+
monthly: { min: string, max: string }
|
|
232
|
+
},
|
|
233
|
+
discounted: {
|
|
234
|
+
min: string, max: string,
|
|
235
|
+
monthly: { min: string, max: string }
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
discount: {
|
|
239
|
+
percentage: {
|
|
240
|
+
min: string, max: string,
|
|
241
|
+
monthly: { min: string, max: string }
|
|
242
|
+
},
|
|
243
|
+
value: {
|
|
244
|
+
min: string, max: string,
|
|
245
|
+
monthly: { min: string, max: string }
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
scenarios: number
|
|
249
|
+
},
|
|
250
|
+
ctx, // alias of `state`
|
|
251
|
+
derived: Record<string, unknown> // from `bd-context.derived`
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Notes
|
|
256
|
+
- All price / discount values in the DSL are **formatted strings** (currency-aware). Don't perform numeric comparisons on them.
|
|
257
|
+
- `it.ctx` is an alias of `it.state` for convenience.
|
|
258
|
+
- `it.option.links.trial('30 days')` returns the trial URL for that duration, or `undefined` if no trial is configured.
|
|
259
|
+
- `it.derived.*` is the user-defined overlay from `bd-context.derived`.
|
|
260
|
+
|
|
261
|
+
## Data layer
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
context.dataLayer = ({ option, event }) => {
|
|
265
|
+
window.dataLayer?.push({
|
|
266
|
+
event,
|
|
267
|
+
productId: option.getProduct().getId(),
|
|
268
|
+
devices : option.getDevices(),
|
|
269
|
+
// …
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
- Fires once per `<bd-option>` instance (first successful load). Re-firing requires re-mounting the node.
|
|
275
|
+
- `event` is the value of `data-layer-event` on the option element. Canonical values: `all`, `info`, `comparison`. Custom strings are accepted.
|
|
276
|
+
|
|
277
|
+
## Actions
|
|
278
|
+
|
|
279
|
+
```html
|
|
280
|
+
<button data-store-action
|
|
281
|
+
data-store-set-devices="25"
|
|
282
|
+
data-store-event-id="devicesBtn">25 devices</button>
|
|
283
|
+
|
|
284
|
+
<button data-store-action
|
|
285
|
+
data-store-set-type="devices"
|
|
286
|
+
data-store-set-delta="next"
|
|
287
|
+
data-store-set-min="1"
|
|
288
|
+
data-store-set-max="25">next</button>
|
|
88
289
|
```
|
|
89
290
|
|
|
90
|
-
|
|
91
|
-
|
|
291
|
+
| Attribute | Effect |
|
|
292
|
+
| --- | --- |
|
|
293
|
+
| `data-store-action` | Marks the element as an action source. |
|
|
294
|
+
| `data-store-set-devices="N"` | Set devices = N. |
|
|
295
|
+
| `data-store-set-subscription="N"` | Set subscription = N. |
|
|
296
|
+
| `data-store-set-id="…"` | Switch the current product id. |
|
|
297
|
+
| `data-store-set-campaign="…"` | Switch the campaign for the current product. |
|
|
298
|
+
| `data-store-set-bundle` (boolean) | Toggle bundle inclusion. |
|
|
299
|
+
| `data-store-set-type="devices\|subscription"` | Required for delta updates. |
|
|
300
|
+
| `data-store-set-delta="next\|prev\|<number>"` | Move the option by N (or `next` / `prev`). |
|
|
301
|
+
| `data-store-set-min`, `data-store-set-max` | Bounds for delta updates. |
|
|
302
|
+
| `data-store-set-use-as-value` (boolean) | Treat `delta` as an absolute value rather than an increment. |
|
|
303
|
+
| `data-store-event-id="…"` | Tag the source element so `ignore-events` on `bd-*` nodes can drop its events. |
|
|
304
|
+
|
|
305
|
+
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
|
+
### Ignoring events on a subtree
|
|
308
|
+
|
|
309
|
+
```html
|
|
310
|
+
<bd-option ignore-events="devicesBtn, subscriptionBtn">
|
|
311
|
+
<!-- ignores events from any source tagged with one of those ids -->
|
|
312
|
+
</bd-option>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
`ignore-events` cascades — descendants inherit it. `data-store-event-id` is the matching tag on the source element. (`data-store-id` from v1 is gone.)
|
|
316
|
+
|
|
317
|
+
## Registration and initialization
|
|
92
318
|
|
|
93
|
-
|
|
319
|
+
| Export | Purpose |
|
|
320
|
+
| --- | --- |
|
|
321
|
+
| `registerContextNodes()` | Register `<bd-context>`, `<bd-product>`, `<bd-option>` custom elements. Idempotent. |
|
|
322
|
+
| `registerActionNodes(root)` | Attach `BdActionElementAdapter`s to every action element under `root`. Returns `() => void` to disconnect. |
|
|
323
|
+
| `registerRenderNodes(root)` | Wire every `[data-store-render]` element under `root` to its attribute handler. Returns `() => void` to disconnect. |
|
|
324
|
+
| `elementDefinitions` | `{ 'bd-context': ContextNode, 'bd-product': ProductNode, 'bd-option': OptionNode }` — for advanced consumers that want to register tags themselves. |
|
|
325
|
+
|
|
326
|
+
The package is side-effect free; nothing is registered until you call `registerContextNodes()`.
|
|
327
|
+
|
|
328
|
+
## Store config
|
|
329
|
+
|
|
330
|
+
`trialLinks` and `overrides` come from `@repobit/dex-store` and work transparently with these elements. Configure them on the `Store` and render via attributes:
|
|
94
331
|
|
|
95
332
|
```ts
|
|
96
333
|
import { Store } from '@repobit/dex-store';
|
|
@@ -99,36 +336,26 @@ const store = new Store({
|
|
|
99
336
|
locale : 'en-us',
|
|
100
337
|
provider: { name: 'vlaicu' },
|
|
101
338
|
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
// optionVariation key
|
|
339
|
+
// productAlias -> campaign -> optionVariation -> trialDays -> URL
|
|
340
|
+
// productAlias is the id after adaptor mapping.
|
|
341
|
+
// optionVariation key: '<devices>-<subscription>' (e.g. '5-12').
|
|
105
342
|
trialLinks: {
|
|
106
343
|
'com.bitdefender.tsmd.v2': {
|
|
107
344
|
default: {
|
|
108
|
-
'5-12' : 'https://trial.example.com/default/5-12'
|
|
109
|
-
'10-12': 'https://trial.example.com/default/10-12'
|
|
110
|
-
},
|
|
111
|
-
PromoX: {
|
|
112
|
-
'5-12' : 'https://trial.example.com/promox/5-12',
|
|
113
|
-
'10-12': 'https://trial.example.com/promox/10-12'
|
|
345
|
+
'5-12': { '30 days': 'https://trial.example.com/default/5-12' }
|
|
114
346
|
}
|
|
115
347
|
}
|
|
116
348
|
},
|
|
117
349
|
|
|
118
|
-
// Per-product overrides
|
|
119
|
-
// - Set/redirect campaign via `default.campaign` or `[campaign].campaign`
|
|
120
|
-
// - Merge option fields per variation; use `null` to remove an option
|
|
350
|
+
// Per-product overrides
|
|
121
351
|
overrides: {
|
|
122
352
|
'com.bitdefender.tsmd.v2': {
|
|
123
|
-
|
|
124
|
-
default: {
|
|
125
|
-
campaign: 'OvDefault'
|
|
126
|
-
},
|
|
353
|
+
default: { campaign: 'OvDefault' },
|
|
127
354
|
PromoX: {
|
|
128
355
|
campaign: 'PromoX',
|
|
129
356
|
options : {
|
|
130
|
-
'5-12' : { discountedPrice: 49.99
|
|
131
|
-
'10-12': null
|
|
357
|
+
'5-12' : { discountedPrice: 49.99 },
|
|
358
|
+
'10-12': null // delete this variation
|
|
132
359
|
}
|
|
133
360
|
}
|
|
134
361
|
}
|
|
@@ -136,244 +363,40 @@ const store = new Store({
|
|
|
136
363
|
});
|
|
137
364
|
```
|
|
138
365
|
|
|
139
|
-
|
|
140
|
-
- `data-store-trial-link` uses `trialLinks` to set the anchor `href`. If no mapping exists, the attribute is left untouched.
|
|
141
|
-
- `overrides.options` merges into each option; you can update `buyLink`, `discountedPrice`, etc., or delete an entire variation with `null`.
|
|
142
|
-
- Keys are resolved against the product id returned by the provider (after adaptor mapping). If you don’t use mappings, it’s the id you pass in `<bd-product product-id="...">`.
|
|
143
|
-
|
|
144
|
-
## Rendering model
|
|
145
|
-
- Add `data-store-render` to any element you want updated by the pipeline.
|
|
146
|
-
- A single binder subscribes to option, product and aggregated state contexts and renders attributes + Eta templates.
|
|
147
|
-
- Scoping is natural: a node sees the nearest provider up the tree (e.g., `it.option.*` is only available inside `<bd-option>`).
|
|
148
|
-
|
|
149
|
-
## Supported attributes
|
|
150
|
-
|
|
151
|
-
- `data-store-devices`
|
|
152
|
-
- Renders option devices to text nodes, `<input>` value, or `<select>` options (adds `data-store-set-devices` on each option)
|
|
153
|
-
- Optional label helpers: `data-store-text-single="device"`, `data-store-text-many="devices"`
|
|
154
|
-
|
|
155
|
-
- `data-store-subscription`
|
|
156
|
-
- Renders option subscription similarly; add `data-store-subscription-type="years|months"`
|
|
157
|
-
- Label helpers: `data-store-text-single`, `data-store-text-many`
|
|
158
|
-
|
|
159
|
-
- `data-store-price`
|
|
160
|
-
- Allowed tokens: `full`, `discounted`, `full-monthly`, `discounted-monthly`
|
|
161
|
-
- Supports OR semantics via `||` to choose the first available variant:
|
|
162
|
-
- `data-store-price="discounted || full"`
|
|
163
|
-
|
|
164
|
-
- `data-store-discount`
|
|
165
|
-
- Allowed tokens: `value`, `percentage`, `value-monthly`, `percentage-monthly`
|
|
166
|
-
- Supports `||` fallbacks
|
|
167
|
-
|
|
168
|
-
- Aggregated state (min/max across options):
|
|
169
|
-
- `data-store-context-price` tokens: `min-full`, `max-full`, `min-full-monthly`, `max-full-monthly`, `min-discounted`, `max-discounted`, `min-discounted-monthly`, `max-discounted-monthly`
|
|
170
|
-
- `data-store-context-discount` tokens: `min-value`, `max-value`, `min-value-monthly`, `max-value-monthly`, `min-percentage`, `max-percentage`, `min-percentage-monthly`, `max-percentage-monthly`
|
|
171
|
-
|
|
172
|
-
- Links
|
|
173
|
-
- `data-store-buy-link` sets anchor `href` and useful `data-*` attributes
|
|
174
|
-
- `data-store-trial-link` sets anchor `href` to the trial link (if configured in `@repobit/dex-store` store config)
|
|
175
|
-
|
|
176
|
-
- Hide DSL
|
|
177
|
-
- `data-store-hide="<boolean expression>"` with an optional `data-store-hide-type="display|opacity|visibility"`
|
|
178
|
-
- Expression is compiled and evaluated against the unified context:
|
|
179
|
-
- `it.option.*` current option data. Price- and discount-related fields are formatted strings (currency-aware). Do not rely on numeric math for prices; they vary by currency. Devices/subscription remain numeric.
|
|
180
|
-
- `it.product.*` id/campaign/name
|
|
181
|
-
- `it.state.*` aggregated min/max data (also available under `it.ctx`)
|
|
182
|
-
- any keys returned from your `root.derived`
|
|
183
|
-
- Examples:
|
|
184
|
-
- `data-store-hide="!it.option.price.discounted"` (hide when no discounted price)
|
|
185
|
-
- `data-store-hide="it.product.campaign === 'test'"`
|
|
186
|
-
|
|
187
|
-
## Eta templates
|
|
188
|
-
- Text/HTML: any element that is not a provider and doesn’t contain nested providers is treated as a whole-template; `innerHTML` is compiled once and morphed via nanomorph. This preserves existing DOM event listeners and state.
|
|
189
|
-
- Attributes:
|
|
190
|
-
- Implicit: any attribute whose value contains `{{` is rendered via Eta
|
|
191
|
-
- The Eta context variable is `it` (Eta default). It contains:
|
|
192
|
-
- `it.option.*` (inside `<bd-option>`)
|
|
193
|
-
- `it.product.*` (inside `<bd-product>`)
|
|
194
|
-
- `it.state.*` and `it.ctx.*` (inside any provider subtree)
|
|
195
|
-
- your derived overlay merged at top-level (see below)
|
|
196
|
-
|
|
197
|
-
## Derived variables/functions
|
|
198
|
-
- Provide a function at the root: `root.derived = async ({ option, product, state }) => ({ ... })`
|
|
199
|
-
- The returned object is merged into the Eta/DSL context:
|
|
200
|
-
- Example: `({ mails: (p) => (option?.getDevices?.()/p)*100, option: { someVar: state.discount.value.min } })`
|
|
201
|
-
- Use it in Eta: `{{= it.mails(10) }}` or `{{= it.option.someVar }}`
|
|
202
|
-
- Use it in hide: `data-store-hide="it.mails(10) >= 50"`
|
|
203
|
-
|
|
204
|
-
## DSL context reference
|
|
205
|
-
The DSL and Eta contexts use Eta’s default variable name `it`. The following keys are available:
|
|
206
|
-
|
|
207
|
-
- it.option
|
|
208
|
-
- price
|
|
209
|
-
- full: formatted full price (string)
|
|
210
|
-
- discounted: formatted discounted price (string)
|
|
211
|
-
- fullMonthly: formatted monthly full price (string)
|
|
212
|
-
- discountedMonthly: formatted monthly discounted price (string)
|
|
213
|
-
- discount
|
|
214
|
-
- value: formatted discount amount (string)
|
|
215
|
-
- percentage: formatted percentage discount with symbol (string)
|
|
216
|
-
- valueMonthly: formatted monthly discount amount (string)
|
|
217
|
-
- percentageMonthly: formatted monthly percentage with symbol (string)
|
|
218
|
-
- links
|
|
219
|
-
- buy: buy URL (string)
|
|
220
|
-
- trial: trial URL if available (string)
|
|
221
|
-
- devices: number
|
|
222
|
-
- subscription: number
|
|
223
|
-
|
|
224
|
-
- it.product
|
|
225
|
-
- id: string
|
|
226
|
-
- campaign: string
|
|
227
|
-
- name: string
|
|
228
|
-
|
|
229
|
-
- it.state (also available as `it.ctx`)
|
|
230
|
-
- price
|
|
231
|
-
- full
|
|
232
|
-
- min: formatted string
|
|
233
|
-
- max: formatted string
|
|
234
|
-
- monthly
|
|
235
|
-
- min: formatted string
|
|
236
|
-
- max: formatted string
|
|
237
|
-
- discounted
|
|
238
|
-
- min: formatted string
|
|
239
|
-
- max: formatted string
|
|
240
|
-
- monthly
|
|
241
|
-
- min: formatted string
|
|
242
|
-
- max: formatted string
|
|
243
|
-
- discount
|
|
244
|
-
- percentage
|
|
245
|
-
- min: formatted string
|
|
246
|
-
- max: formatted string
|
|
247
|
-
- monthly
|
|
248
|
-
- min: formatted string
|
|
249
|
-
- max: formatted string
|
|
250
|
-
- value
|
|
251
|
-
- min: formatted string
|
|
252
|
-
- max: formatted string
|
|
253
|
-
- monthly
|
|
254
|
-
- min: formatted string
|
|
255
|
-
- max: formatted string
|
|
256
|
-
|
|
257
|
-
Notes
|
|
258
|
-
- All price/discount values in the DSL are formatted strings (currency-aware). Do not perform numeric comparisons on them. Prefer truthiness checks (e.g., `!it.option.price.discounted`).
|
|
259
|
-
- `it.ctx` is an alias of `it.state` for convenience.
|
|
260
|
-
|
|
261
|
-
## Data Layer
|
|
262
|
-
- Provide a function on `<bd-root>`: `root.dataLayer = ({ option, event }) => { ... }`.
|
|
263
|
-
- Called once per `<bd-option>` instance that declares `data-layer-event` (on first successful load).
|
|
264
|
-
- Safe if attached after the option loads; it still fires once when available.
|
|
265
|
-
- Intended for analytics (e.g., pushing to `window.dataLayer`).
|
|
266
|
-
- Event name is set on each `<bd-option>` with `data-layer-event`.
|
|
267
|
-
- Canonical values: `all`, `info`, `comparison`. Any custom string is also accepted.
|
|
268
|
-
- Payload shape passed to your callback:
|
|
269
|
-
- `event`: string event name.
|
|
270
|
-
- `option`: `ProductOption` from `@repobit/dex-store` with getters like `getProduct()`, `getVariation()`, `getDevices()`, `getSubscription()`, `getBuyLink()`, `getDiscountedPrice()`.
|
|
271
|
-
|
|
272
|
-
Example:
|
|
366
|
+
Render via attributes:
|
|
273
367
|
|
|
274
368
|
```html
|
|
275
|
-
<
|
|
276
|
-
|
|
277
|
-
import { Store } from '@repobit/dex-store';
|
|
278
|
-
|
|
279
|
-
window.addEventListener('DOMContentLoaded', async () => {
|
|
280
|
-
registerContextNodes();
|
|
281
|
-
const root = document.querySelector('bd-root');
|
|
282
|
-
root.store = new Store({ locale: 'en-us', provider: { name: 'vlaicu' } });
|
|
283
|
-
|
|
284
|
-
root.dataLayer = ({ option, event }) => {
|
|
285
|
-
window.dataLayer = window.dataLayer || [];
|
|
286
|
-
window.dataLayer.push({
|
|
287
|
-
event,
|
|
288
|
-
productId: option.getProduct().getId(),
|
|
289
|
-
campaign : option.getProduct().getCampaign(),
|
|
290
|
-
variation: option.getVariation(),
|
|
291
|
-
devices : option.getDevices(),
|
|
292
|
-
subscription: option.getSubscription()
|
|
293
|
-
});
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const disposeActions = registerActionNodes(root);
|
|
297
|
-
|
|
298
|
-
// Optional teardown (for SPA route changes/unmounts)
|
|
299
|
-
// disposeActions();
|
|
300
|
-
});
|
|
301
|
-
</script>
|
|
302
|
-
|
|
303
|
-
<bd-root store-name="root">
|
|
304
|
-
<bd-product store-name="product" product-id="com.bitdefender.tsmd.v2">
|
|
305
|
-
<bd-option devices="5" subscription="12" data-layer-event="info">
|
|
306
|
-
<!-- your UI here -->
|
|
307
|
-
</bd-option>
|
|
308
|
-
</bd-product>
|
|
309
|
-
</bd-root>
|
|
369
|
+
<a data-store-render data-store-buy-link>Buy</a>
|
|
370
|
+
<a data-store-render data-store-buy-link="30 days">30-day trial</a>
|
|
310
371
|
```
|
|
311
372
|
|
|
312
|
-
|
|
313
|
-
- Fires only once per `<bd-option>` instance (first load). Subsequent changes via actions or deltas do not trigger the callback again.
|
|
314
|
-
- Set different `data-layer-event` values on different options if you need multiple distinct analytics events.
|
|
373
|
+
## Caveats
|
|
315
374
|
|
|
316
|
-
|
|
317
|
-
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
- Source identifier: add `data-store-id="someId"` to tag the event's `storeId`. Providers with `ignore-events` that include `someId` will drop these events.
|
|
321
|
-
- Initialize once per mount with:
|
|
322
|
-
- `import { registerActionNodes } from '@repobit/dex-store-elements'`
|
|
323
|
-
- `const disposeActions = registerActionNodes(root)`
|
|
324
|
-
- Call `disposeActions()` on teardown/unmount to disconnect observers.
|
|
375
|
+
- Scoping: `it.option.*` is only available inside `<bd-option>`. `it.product.*` is only available inside `<bd-product>`. Everything else is available everywhere.
|
|
376
|
+
- Nested providers: an inner `bd-context` / `bd-product` / `bd-option` renders its own subtree; templates inside it never see the outer scope's `option` (only the inner one).
|
|
377
|
+
- Eta templates are scoped to non-provider elements — provider elements don't render text content as templates.
|
|
378
|
+
- Compute (state min/max) only runs when at least one `bd-context` / `bd-product` / `bd-option` enables it (default: enabled). Disable with `compute-disabled` on a provider to skip the reduction for preview widgets.
|
|
325
379
|
|
|
326
|
-
##
|
|
327
|
-
- Element registration:
|
|
328
|
-
- `import { registerContextNodes } from '@repobit/dex-store-elements'; registerContextNodes();`
|
|
329
|
-
- Rendering: `import { registerRenderNodes } from '@repobit/dex-store-elements'`
|
|
330
|
-
- Actions: `import { registerActionNodes } from '@repobit/dex-store-elements'`
|
|
331
|
-
- `registerRenderNodes(root)` returns a disposer: `() => void`
|
|
332
|
-
- `registerActionNodes(root)` returns a disposer: `() => void`
|
|
333
|
-
- Call disposers during teardown/unmount in long-lived apps (SPA route changes, dynamic mounts).
|
|
334
|
-
|
|
335
|
-
Note: The package is side-effect free; elements are registered only when `registerContextNodes()` is called.
|
|
336
|
-
|
|
337
|
-
## State & event controls
|
|
338
|
-
These attributes are available on `<bd-state>` and any element that extends it (`<bd-root>`, `<bd-product>`, `<bd-option>`).
|
|
339
|
-
- `ignore-events="store-a, store-b"`
|
|
340
|
-
- Comma-separated list of action ids. Events whose source element has a matching `data-store-id` are ignored by this node (and its subtree). Works for both action and delta events.
|
|
341
|
-
- Coupling with `data-store-id` (on action elements):
|
|
342
|
-
- Example:
|
|
343
|
-
- `<button data-store-action data-store-id="devicesBtn" data-store-set-devices="25">` dispatches an event with `storeId: "devicesBtn"`.
|
|
344
|
-
- `<bd-option ignore-events="devicesBtn">` ignores that event while still accepting events from other buttons.
|
|
345
|
-
- You can list multiple ids: `ignore-events="devicesBtn, subscriptionBtn"`.
|
|
346
|
-
- `ignore-events-parent`
|
|
347
|
-
- Ignores events received from ancestor providers and only reacts to DOM-bubbled events that originate within the current subtree.
|
|
348
|
-
- `<bd-context>` is a convenience element that defaults this behavior to enabled. It’s equivalent to `<bd-state ignore-events-parent>`.
|
|
349
|
-
- Example:
|
|
350
|
-
```html
|
|
351
|
-
<bd-state store-name="outer">
|
|
352
|
-
<!-- Global action updates state here -->
|
|
353
|
-
<button data-store-action data-store-set-devices="25"></button>
|
|
354
|
-
|
|
355
|
-
<!-- Isolated island: only inner actions are observed -->
|
|
356
|
-
<bd-context store-name="island">
|
|
357
|
-
<button data-store-action data-store-set-devices="5"></button>
|
|
358
|
-
</bd-context>
|
|
359
|
-
</bd-state>
|
|
360
|
-
```
|
|
361
|
-
In this setup, the inner `<bd-context>` ignores the outer button’s events.
|
|
362
|
-
- `no-collect`
|
|
363
|
-
- Turns off automatic option collection for aggregated state. Set this when you want the node to work locally without contributing to shared min/max computations (e.g., for preview widgets).
|
|
380
|
+
## TypeScript
|
|
364
381
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
382
|
+
```ts
|
|
383
|
+
import type {
|
|
384
|
+
ContextNode,
|
|
385
|
+
ProductNode,
|
|
386
|
+
OptionNode,
|
|
387
|
+
BdScope,
|
|
388
|
+
BdScopeDeriveFn
|
|
389
|
+
} from '@repobit/dex-store-elements';
|
|
390
|
+
|
|
391
|
+
import {
|
|
392
|
+
registerContextNodes,
|
|
393
|
+
registerActionNodes,
|
|
394
|
+
registerRenderNodes
|
|
395
|
+
} from '@repobit/dex-store-elements';
|
|
396
|
+
```
|
|
368
397
|
|
|
369
|
-
|
|
370
|
-
- Custom element classes are exported from a dedicated entry for advanced use:
|
|
371
|
-
- `import { RootNode, ProductNode, OptionNode, StateNode } from '@repobit/dex-store-elements'`
|
|
372
|
-
- The derived signature:
|
|
373
|
-
```ts
|
|
374
|
-
import type { derivedContextType } from '@repobit/dex-store-elements/src/contexts/context.derived';
|
|
375
|
-
const derived: derivedContextType = async ({ option, product, state, store }) => ({ ... });
|
|
376
|
-
```
|
|
398
|
+
The custom element classes extend `BdScopedElement` and `BdNodeElement` (Lit `LitElement` subclasses). They are exported from the main entry.
|
|
377
399
|
|
|
378
400
|
## License
|
|
401
|
+
|
|
379
402
|
ISC
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilty.js","sourceRoot":"","sources":["../../../../src/renders/attributes/utilty.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,KAAc,EACL,EAAE,CACX,KAAK,KAAK,IAAI;IACd,KAAK,KAAK,SAAS;IACnB,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAExD,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,EAAe,EACW,EAAE,CAC5B,EAAE,YAAY,iBAAiB;IAC7B,CAAC,CAAC,EAAE;IACJ,CAAC,CAAC,EAAE,CAAC,aAAa,CAAoB,GAAG,CAAC,CAAC;AAQ/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,MAAyB,EACzB,MAAoB,EACpB,aAAgB,EAChB,WAAqC,EACrC,gBAAwB,EAClB,EAAE;IACR,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,KAAK,KAAK,aAAa,CAAC;QACzC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,KAAK,EACL,MAAM,CAAC,KAAK,CAAC,EACb,QAAQ,EACR,QAAQ,CACT,CAAC;QAEF,MAAM,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAC","sourcesContent":["export const isPresent = (\n value: unknown\n): boolean =>\n value !== null &&\n value !== undefined &&\n (typeof value !== 'number' || Number.isFinite(value));\n\nexport const resolveAnchor = (\n el: HTMLElement\n): HTMLAnchorElement | null =>\n el instanceof HTMLAnchorElement\n ? el\n : el.querySelector<HTMLAnchorElement>('a');\n\nexport type SelectOptionFormatter<T> = (\n value: T,\n index: number,\n values: readonly T[]\n) => string;\n\nexport const buildSelectOptions = <T>(\n select: HTMLSelectElement,\n values: readonly T[],\n selectedValue: T,\n formatLabel: SelectOptionFormatter<T>,\n setAttributeName: string\n): void => {\n select.options.length = 0;\n\n for (let index = 0; index < values.length; index += 1) {\n const value = values[index];\n const selected = value === selectedValue;\n const label = formatLabel(value, index, values);\n const option = new Option(\n label,\n String(value),\n selected,\n selected\n );\n\n option.setAttribute(setAttributeName, String(value));\n select.add(option);\n }\n};\n"]}
|
|
1
|
+
{"version":3,"file":"utilty.js","sourceRoot":"","sources":["../../../../src/renders/attributes/utilty.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,KAAc,EACL,EAAE,CACX,KAAK,KAAK,IAAI;IACd,KAAK,KAAK,SAAS;IACnB,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAClD,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAExD,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,EAAe,EACW,EAAE,CAC5B,EAAE,YAAY,iBAAiB;IAC7B,CAAC,CAAC,EAAE;IACJ,CAAC,CAAC,EAAE,CAAC,aAAa,CAAoB,GAAG,CAAC,CAAC;AAQ/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,MAAyB,EACzB,MAAoB,EACpB,aAAgB,EAChB,WAAqC,EACrC,gBAAwB,EAClB,EAAE;IACR,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAE1B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,KAAK,KAAK,aAAa,CAAC;QACzC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,KAAK,EACL,MAAM,CAAC,KAAK,CAAC,EACb,QAAQ,EACR,QAAQ,CACT,CAAC;QAEF,MAAM,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAC","sourcesContent":["export const isPresent = (\n value: unknown\n): boolean =>\n value !== null &&\n value !== undefined &&\n (typeof value !== 'string' || value.trim() !== '') &&\n (typeof value !== 'number' || Number.isFinite(value));\n\nexport const resolveAnchor = (\n el: HTMLElement\n): HTMLAnchorElement | null =>\n el instanceof HTMLAnchorElement\n ? el\n : el.querySelector<HTMLAnchorElement>('a');\n\nexport type SelectOptionFormatter<T> = (\n value: T,\n index: number,\n values: readonly T[]\n) => string;\n\nexport const buildSelectOptions = <T>(\n select: HTMLSelectElement,\n values: readonly T[],\n selectedValue: T,\n formatLabel: SelectOptionFormatter<T>,\n setAttributeName: string\n): void => {\n select.options.length = 0;\n\n for (let index = 0; index < values.length; index += 1) {\n const value = values[index];\n const selected = value === selectedValue;\n const label = formatLabel(value, index, values);\n const option = new Option(\n label,\n String(value),\n selected,\n selected\n );\n\n option.setAttribute(setAttributeName, String(value));\n select.add(option);\n }\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repobit/dex-store-elements",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "HTML elements layer for pricings",
|
|
5
5
|
"author": "Buga Adrian Alexandru <abuga@bitdefender.com>",
|
|
6
6
|
"homepage": "https://github.com/bitdefender/dex-core#readme",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@lit/context": "^1.1.6",
|
|
54
54
|
"@lit/task": "^1.0.3",
|
|
55
|
-
"@repobit/dex-store": "1.5.
|
|
55
|
+
"@repobit/dex-store": "1.5.6",
|
|
56
56
|
"eta": "^4.5.1"
|
|
57
57
|
},
|
|
58
58
|
"contributes": {
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
]
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "68817ad232147d936696957b4dfc9dc02d462438"
|
|
66
66
|
}
|