jssm 5.136.0 → 5.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/custom-elements.json +377 -8
- package/dist/cdn/instance.js +419 -8
- package/dist/cdn/viz.js +1 -1
- package/dist/cli/fsl-render.cjs +1 -1
- package/dist/cli/fsl.cjs +1 -1
- package/dist/deno/README.md +7 -7
- package/dist/deno/jssm.js +1 -1
- package/dist/jssm.es5.cjs +1 -1
- package/dist/jssm.es5.iife.js +1 -1
- package/dist/jssm.es6.mjs +1 -1
- package/dist/jssm_viz.cjs +1 -1
- package/dist/jssm_viz.iife.cjs +1 -1
- package/dist/jssm_viz.mjs +1 -1
- package/dist/wc/instance.js +418 -7
- package/package.json +1 -1
package/dist/cdn/instance.js
CHANGED
|
@@ -21327,7 +21327,7 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
21327
21327
|
* Useful for runtime diagnostics and for embedding in serialized machine
|
|
21328
21328
|
* snapshots so that deserializers can detect version-skew.
|
|
21329
21329
|
*/
|
|
21330
|
-
const version = "5.
|
|
21330
|
+
const version = "5.138.0";
|
|
21331
21331
|
|
|
21332
21332
|
// whargarbl lots of these return arrays could/should be sets
|
|
21333
21333
|
const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
|
|
@@ -25070,6 +25070,208 @@ function abstract_everything_hook_step(maybe_hook, hook_args) {
|
|
|
25070
25070
|
}
|
|
25071
25071
|
}
|
|
25072
25072
|
|
|
25073
|
+
const VALID_KINDS = new Set([
|
|
25074
|
+
'hook',
|
|
25075
|
+
'named',
|
|
25076
|
+
'any transition',
|
|
25077
|
+
'standard transition',
|
|
25078
|
+
'main transition',
|
|
25079
|
+
'forced transition',
|
|
25080
|
+
'entry',
|
|
25081
|
+
'exit',
|
|
25082
|
+
'any action',
|
|
25083
|
+
'global action',
|
|
25084
|
+
]);
|
|
25085
|
+
/**
|
|
25086
|
+
* Build a {@link JssmHookProxy} that wraps an arbitrary hook context object.
|
|
25087
|
+
*
|
|
25088
|
+
* The context shape varies by hook kind (`from`/`to`/`action` may be absent
|
|
25089
|
+
* for transition-kind hooks), so this normalizes the shape via optional
|
|
25090
|
+
* fields and exposes mutable `data` while keeping the rest read-only.
|
|
25091
|
+
*
|
|
25092
|
+
* The `machine` parameter is used only for `state()`, so unit tests can
|
|
25093
|
+
* substitute any object with a `state(): unknown` method.
|
|
25094
|
+
*
|
|
25095
|
+
* @param ctx - Raw hook context passed by jssm.
|
|
25096
|
+
* @param machine - The owning machine; used for the `state()` accessor.
|
|
25097
|
+
* @returns A proxy object suitable for passing to a user handler.
|
|
25098
|
+
*/
|
|
25099
|
+
function make_hook_proxy(ctx, machine) {
|
|
25100
|
+
return {
|
|
25101
|
+
get data() {
|
|
25102
|
+
return ctx.data;
|
|
25103
|
+
},
|
|
25104
|
+
set data(next) {
|
|
25105
|
+
ctx.data = next;
|
|
25106
|
+
},
|
|
25107
|
+
get from() {
|
|
25108
|
+
return ctx.from;
|
|
25109
|
+
},
|
|
25110
|
+
get to() {
|
|
25111
|
+
return ctx.to;
|
|
25112
|
+
},
|
|
25113
|
+
get action() {
|
|
25114
|
+
return ctx.action;
|
|
25115
|
+
},
|
|
25116
|
+
state() {
|
|
25117
|
+
return String(machine.state());
|
|
25118
|
+
},
|
|
25119
|
+
};
|
|
25120
|
+
}
|
|
25121
|
+
/**
|
|
25122
|
+
* Compile a textContent body into a callable user handler.
|
|
25123
|
+
*
|
|
25124
|
+
* Uses dynamic function construction — the same primitive browsers use
|
|
25125
|
+
* internally for `<a onclick="...">` and `setTimeout(stringBody, ms)`.
|
|
25126
|
+
* Strict CSP without `'unsafe-eval'` blocks this and the call will throw;
|
|
25127
|
+
* consumers should fall back to the `handler="name"` form there.
|
|
25128
|
+
*
|
|
25129
|
+
* Prepends a `//# sourceURL=` comment so devtools surface a meaningful name
|
|
25130
|
+
* in stack traces instead of `anonymous`.
|
|
25131
|
+
*
|
|
25132
|
+
* @param body - Trimmed textContent of the `<jssm-hook>` element.
|
|
25133
|
+
* @param debug_id - Identifier appended to the synthetic sourceURL.
|
|
25134
|
+
* @returns The compiled handler.
|
|
25135
|
+
*/
|
|
25136
|
+
function compile_inline_body(body, debug_id) {
|
|
25137
|
+
const annotated = `//# sourceURL=jssm-hook:${debug_id}\n${body}`;
|
|
25138
|
+
const ctor = Function;
|
|
25139
|
+
return new ctor('m', annotated);
|
|
25140
|
+
}
|
|
25141
|
+
/**
|
|
25142
|
+
* Resolve a `handler="name"` attribute to a callable by consulting first the
|
|
25143
|
+
* optional in-WC registry, then `globalThis[name]`. Throws a clear error if
|
|
25144
|
+
* neither resolves.
|
|
25145
|
+
*
|
|
25146
|
+
* @param name - The handler name from the `handler=""` attribute.
|
|
25147
|
+
* @param registry - Optional in-WC registry to consult first.
|
|
25148
|
+
* @returns The resolved handler.
|
|
25149
|
+
* @throws Error - If no callable of that name is found in either location.
|
|
25150
|
+
*/
|
|
25151
|
+
function resolve_named_handler(name, registry) {
|
|
25152
|
+
if (registry !== undefined) {
|
|
25153
|
+
const registered = registry.get(name);
|
|
25154
|
+
if (registered !== undefined) {
|
|
25155
|
+
return registered;
|
|
25156
|
+
}
|
|
25157
|
+
}
|
|
25158
|
+
const global = globalThis[name];
|
|
25159
|
+
if (typeof global === 'function') {
|
|
25160
|
+
return global;
|
|
25161
|
+
}
|
|
25162
|
+
throw new Error(`<jssm-hook handler="${name}">: handler not found in registry or globalThis`);
|
|
25163
|
+
}
|
|
25164
|
+
/**
|
|
25165
|
+
* Validate and normalize a `<jssm-hook kind="...">` value, defaulting to
|
|
25166
|
+
* `"hook"` when the attribute is absent. Throws on unknown kinds rather
|
|
25167
|
+
* than silently doing nothing later.
|
|
25168
|
+
*
|
|
25169
|
+
* @param raw - The raw attribute value, or null if not present.
|
|
25170
|
+
* @returns The normalized {@link JssmHookKind}.
|
|
25171
|
+
* @throws Error - On an unknown kind.
|
|
25172
|
+
*/
|
|
25173
|
+
function normalize_hook_kind(raw) {
|
|
25174
|
+
if (raw === null || raw === undefined || raw === '') {
|
|
25175
|
+
return 'hook';
|
|
25176
|
+
}
|
|
25177
|
+
if (!VALID_KINDS.has(raw)) {
|
|
25178
|
+
throw new Error(`<jssm-hook kind="${raw}">: unknown hook kind (expected one of: ${[...VALID_KINDS].join(', ')})`);
|
|
25179
|
+
}
|
|
25180
|
+
return raw;
|
|
25181
|
+
}
|
|
25182
|
+
/**
|
|
25183
|
+
* Parse a single `<jssm-hook>` element into a {@link JssmHookInstallSpec}.
|
|
25184
|
+
*
|
|
25185
|
+
* Validates the mutual-exclusion rule between `handler="name"` and inline
|
|
25186
|
+
* body, defaults `kind` to `"hook"`, resolves named handlers against the
|
|
25187
|
+
* optional registry then `globalThis`, and compiles inline bodies via
|
|
25188
|
+
* dynamic function construction. Conditional-required attributes (e.g.
|
|
25189
|
+
* `from`/`to` for `kind="hook"`) are NOT validated here — `set_hook` will
|
|
25190
|
+
* throw with its own clear errors on missing pieces, which keeps the
|
|
25191
|
+
* error surface single-sourced.
|
|
25192
|
+
*
|
|
25193
|
+
* @param el - The `<jssm-hook>` element to parse.
|
|
25194
|
+
* @param debug_id - Identifier used in the inline body's sourceURL.
|
|
25195
|
+
* @param registry - Optional in-WC registry of named handlers.
|
|
25196
|
+
* @returns A {@link JssmHookInstallSpec} describing what to install.
|
|
25197
|
+
* @throws Error - On mutual-exclusion violation, unknown kind, or unresolved name.
|
|
25198
|
+
*/
|
|
25199
|
+
function parse_hook_element(el, debug_id, registry) {
|
|
25200
|
+
var _a, _b, _c, _d;
|
|
25201
|
+
const handler_attr = el.getAttribute('handler');
|
|
25202
|
+
const raw_text = el.textContent;
|
|
25203
|
+
const body_text = (raw_text === null ? '' : raw_text).trim();
|
|
25204
|
+
if (handler_attr !== null && body_text.length > 0) {
|
|
25205
|
+
throw new Error('<jssm-hook>: specify handler="name" OR inline body, not both');
|
|
25206
|
+
}
|
|
25207
|
+
if (handler_attr === null && body_text.length === 0) {
|
|
25208
|
+
throw new Error('<jssm-hook>: must specify either handler="name" attribute or an inline body');
|
|
25209
|
+
}
|
|
25210
|
+
const user_handler = handler_attr !== null
|
|
25211
|
+
? resolve_named_handler(handler_attr, registry)
|
|
25212
|
+
: compile_inline_body(body_text, debug_id);
|
|
25213
|
+
const kind = normalize_hook_kind(el.getAttribute('kind'));
|
|
25214
|
+
// Convert null → undefined so downstream descriptors omit absent keys.
|
|
25215
|
+
const from = (_a = el.getAttribute('from')) !== null && _a !== void 0 ? _a : undefined;
|
|
25216
|
+
const to = (_b = el.getAttribute('to')) !== null && _b !== void 0 ? _b : undefined;
|
|
25217
|
+
const action = (_c = el.getAttribute('action')) !== null && _c !== void 0 ? _c : undefined;
|
|
25218
|
+
const name = (_d = el.getAttribute('name')) !== null && _d !== void 0 ? _d : undefined;
|
|
25219
|
+
return { kind, name, from, to, action, user_handler };
|
|
25220
|
+
}
|
|
25221
|
+
/**
|
|
25222
|
+
* Wrap a {@link JssmHookUserHandler} so that jssm's native hook contract is
|
|
25223
|
+
* satisfied: the user gets a friendly proxy, the proxy's mutated `data`
|
|
25224
|
+
* becomes the `HookComplexResult.data`, and an explicit `false` return
|
|
25225
|
+
* cancels the transition.
|
|
25226
|
+
*
|
|
25227
|
+
* Any non-`false` return — including `undefined`, `true`, or an arbitrary
|
|
25228
|
+
* object — allows the transition. This matches the contract spelled out
|
|
25229
|
+
* in the issue (#641): "return false cancels; anything else allows".
|
|
25230
|
+
*
|
|
25231
|
+
* @param spec - The parsed install spec carrying the user handler.
|
|
25232
|
+
* @param machine - The owning machine; used by the proxy's `state()`.
|
|
25233
|
+
* @returns A wrapped handler suitable for `set_hook`.
|
|
25234
|
+
*/
|
|
25235
|
+
function wrap_user_handler(spec, machine) {
|
|
25236
|
+
const user = spec.user_handler;
|
|
25237
|
+
return (ctx) => {
|
|
25238
|
+
const proxy = make_hook_proxy(ctx, machine);
|
|
25239
|
+
const result = user(proxy);
|
|
25240
|
+
if (result === false) {
|
|
25241
|
+
return false;
|
|
25242
|
+
}
|
|
25243
|
+
return { pass: true, data: proxy.data };
|
|
25244
|
+
};
|
|
25245
|
+
}
|
|
25246
|
+
/**
|
|
25247
|
+
* Build the typed descriptor object passed to `machine.set_hook` (and later
|
|
25248
|
+
* to `machine.remove_hook` for cleanup) from a parsed {@link JssmHookInstallSpec}
|
|
25249
|
+
* and the wrapped handler.
|
|
25250
|
+
*
|
|
25251
|
+
* For kinds that need `from`/`to`/`action`, the descriptor includes those.
|
|
25252
|
+
* Missing required keys produce `undefined` here; jssm's `set_hook` will
|
|
25253
|
+
* surface the error with its own clear message so we don't duplicate
|
|
25254
|
+
* validation.
|
|
25255
|
+
*
|
|
25256
|
+
* Return type is `unknown` because jssm's `HookDescription` is a
|
|
25257
|
+
* discriminated union and our runtime-discriminator value can't be tracked
|
|
25258
|
+
* by TypeScript across the build. The WC casts at the `set_hook` call site.
|
|
25259
|
+
*
|
|
25260
|
+
* @param spec - The parsed install spec.
|
|
25261
|
+
* @param wrapped - The wrapped (friendly-proxy) handler from {@link wrap_user_handler}.
|
|
25262
|
+
* @returns A descriptor object for `set_hook`/`remove_hook`.
|
|
25263
|
+
*/
|
|
25264
|
+
function build_hook_descriptor(spec, wrapped) {
|
|
25265
|
+
const base = { kind: spec.kind, handler: wrapped };
|
|
25266
|
+
if (spec.from !== undefined)
|
|
25267
|
+
base.from = spec.from;
|
|
25268
|
+
if (spec.to !== undefined)
|
|
25269
|
+
base.to = spec.to;
|
|
25270
|
+
if (spec.action !== undefined)
|
|
25271
|
+
base.action = spec.action;
|
|
25272
|
+
return base;
|
|
25273
|
+
}
|
|
25274
|
+
|
|
25073
25275
|
/**
|
|
25074
25276
|
* Resolve a `<jssm-instance>`'s FSL source from the three legal channels:
|
|
25075
25277
|
* the `fsl=""` attribute, a child `<script type="text/fsl">`, and the
|
|
@@ -25185,6 +25387,46 @@ class JssmInstance extends i {
|
|
|
25185
25387
|
* connection.
|
|
25186
25388
|
*/
|
|
25187
25389
|
this._machine = undefined;
|
|
25390
|
+
/**
|
|
25391
|
+
* Per-instance registry of named hook handlers consulted before
|
|
25392
|
+
* `globalThis` when resolving `<jssm-hook handler="name">`.
|
|
25393
|
+
*
|
|
25394
|
+
* Initialized to an empty `Map`; consumers may populate it before the
|
|
25395
|
+
* element connects to provide handlers without polluting global scope —
|
|
25396
|
+
* useful for module-scoped SPAs where strict CSP blocks inline-body hooks.
|
|
25397
|
+
*
|
|
25398
|
+
* @see {@link parse_hook_element}
|
|
25399
|
+
*/
|
|
25400
|
+
this.registry = new Map();
|
|
25401
|
+
/**
|
|
25402
|
+
* Descriptors for hooks this WC installed at connect time, used in
|
|
25403
|
+
* `disconnectedCallback` to call `remove_hook` for each so the underlying
|
|
25404
|
+
* machine doesn't leak handlers when the element is detached.
|
|
25405
|
+
*
|
|
25406
|
+
* Captured at install time because `remove_hook` matches by descriptor
|
|
25407
|
+
* shape (not handler identity), and we need to record the wrapped handler
|
|
25408
|
+
* we passed to `set_hook` to undo the registration cleanly. Stored as
|
|
25409
|
+
* `unknown[]` and cast at the call site because jssm's `HookDescription`
|
|
25410
|
+
* is a discriminated union whose discriminator is only known at runtime.
|
|
25411
|
+
*/
|
|
25412
|
+
this._installed_hooks = [];
|
|
25413
|
+
/**
|
|
25414
|
+
* Counter used to give each compiled inline-body hook a unique debug id
|
|
25415
|
+
* for its `//# sourceURL=jssm-hook:N` annotation. Per-instance so that
|
|
25416
|
+
* multiple `<jssm-instance>` elements on a page don't share numbering.
|
|
25417
|
+
*/
|
|
25418
|
+
this._hook_debug_counter = 0;
|
|
25419
|
+
/**
|
|
25420
|
+
* Records every DOM listener installed by `<jssm-action>` / `data-jssm-action`
|
|
25421
|
+
* discovery so {@link disconnectedCallback} can remove each one with the
|
|
25422
|
+
* same handler reference originally passed to `addEventListener`.
|
|
25423
|
+
*
|
|
25424
|
+
* Listeners installed via the dedicated `<jssm-action>` tag form may target
|
|
25425
|
+
* elements outside the host (its `selector` is resolved against the host,
|
|
25426
|
+
* but matching elements live in the document tree), so cleanup must be
|
|
25427
|
+
* explicit — relying on the host's GC is not sufficient.
|
|
25428
|
+
*/
|
|
25429
|
+
this._action_listeners = [];
|
|
25188
25430
|
}
|
|
25189
25431
|
/**
|
|
25190
25432
|
* Raw machine accessor. Returns the owned {@link Machine} instance.
|
|
@@ -25249,22 +25491,191 @@ class JssmInstance extends i {
|
|
|
25249
25491
|
this.requestUpdate();
|
|
25250
25492
|
// TODO #638: subscribe to machine.on('transition', ...) once available
|
|
25251
25493
|
// and dispatch DOM CustomEvents from this element.
|
|
25252
|
-
//
|
|
25494
|
+
// #641: <jssm-hook> declarative discovery.
|
|
25495
|
+
this._install_declarative_hooks();
|
|
25253
25496
|
// TODO #643: <jssm-on> discovery happens here.
|
|
25254
|
-
|
|
25497
|
+
this._discover_jssm_actions();
|
|
25255
25498
|
// TODO #645: <jssm-bind> discovery happens here.
|
|
25256
25499
|
}
|
|
25257
25500
|
/**
|
|
25258
|
-
*
|
|
25259
|
-
*
|
|
25260
|
-
*
|
|
25261
|
-
*
|
|
25501
|
+
* Discover every direct-child `<jssm-hook>` element and install each
|
|
25502
|
+
* against the owned machine. Handlers are wrapped with the friendly-proxy
|
|
25503
|
+
* adapter that lets user code write `m.data = ...` and return `false` to
|
|
25504
|
+
* cancel — see {@link make_hook_proxy} and the issue (#641) doc-comment
|
|
25505
|
+
* for the full contract.
|
|
25506
|
+
*
|
|
25507
|
+
* Direct children only (the `:scope > jssm-hook` selector) so that nested
|
|
25508
|
+
* `<jssm-instance>` elements don't have their child hooks installed on
|
|
25509
|
+
* the outer machine.
|
|
25510
|
+
*
|
|
25511
|
+
* Tracks every installed descriptor in `_installed_hooks` so that
|
|
25512
|
+
* `disconnectedCallback` can remove them on detach.
|
|
25513
|
+
*
|
|
25514
|
+
* @throws Error - On a malformed `<jssm-hook>` (mutual-exclusion violation,
|
|
25515
|
+
* unknown kind, unresolved name, or jssm's own missing-key
|
|
25516
|
+
* errors from `set_hook`).
|
|
25517
|
+
*/
|
|
25518
|
+
_install_declarative_hooks() {
|
|
25519
|
+
const machine = this._machine;
|
|
25520
|
+
const hook_els = this.querySelectorAll(':scope > jssm-hook');
|
|
25521
|
+
for (const el of Array.from(hook_els)) {
|
|
25522
|
+
const debug_id = `${this._hook_id_prefix()}${++this._hook_debug_counter}`;
|
|
25523
|
+
const spec = parse_hook_element(el, debug_id, this.registry);
|
|
25524
|
+
const wrapped = wrap_user_handler(spec, machine);
|
|
25525
|
+
const desc = build_hook_descriptor(spec, wrapped);
|
|
25526
|
+
// `desc` is shaped from runtime kind discrimination; jssm's typed
|
|
25527
|
+
// `HookDescription` is a static discriminated union that TS can't
|
|
25528
|
+
// unify with our runtime-built object, hence the cast.
|
|
25529
|
+
machine.set_hook(desc);
|
|
25530
|
+
this._installed_hooks.push(desc);
|
|
25531
|
+
}
|
|
25532
|
+
}
|
|
25533
|
+
/**
|
|
25534
|
+
* Prefix used in synthetic `//# sourceURL=jssm-hook:<prefix><n>` annotations
|
|
25535
|
+
* for inline-body hooks compiled by this element. Includes the element's
|
|
25536
|
+
* `id` when present so multi-instance pages can tell sources apart in
|
|
25537
|
+
* devtools.
|
|
25538
|
+
*/
|
|
25539
|
+
_hook_id_prefix() {
|
|
25540
|
+
const host_id = this.getAttribute('id');
|
|
25541
|
+
return host_id !== null && host_id.length > 0 ? `${host_id}-` : '';
|
|
25542
|
+
}
|
|
25543
|
+
/**
|
|
25544
|
+
* Lifecycle hook. Removes every hook this WC installed via
|
|
25545
|
+
* `<jssm-hook>` discovery so the underlying machine doesn't leak handlers
|
|
25546
|
+
* when the element detaches. Called automatically by the browser; the
|
|
25547
|
+
* machine itself is not destroyed (consumers can reuse it).
|
|
25548
|
+
*
|
|
25549
|
+
* Future tickets #638/#643/#645 will extend this to drop other
|
|
25550
|
+
* subscriptions / listeners installed by their respective tags.
|
|
25262
25551
|
*/
|
|
25263
25552
|
disconnectedCallback() {
|
|
25264
25553
|
super.disconnectedCallback();
|
|
25265
25554
|
// TODO #638: unsubscribe from machine.on(...) handlers.
|
|
25266
|
-
//
|
|
25555
|
+
// #641: remove installed hooks.
|
|
25556
|
+
if (this._machine !== undefined) {
|
|
25557
|
+
const machine = this._machine;
|
|
25558
|
+
for (const desc of this._installed_hooks) {
|
|
25559
|
+
machine.remove_hook(desc);
|
|
25560
|
+
}
|
|
25561
|
+
}
|
|
25562
|
+
this._installed_hooks = [];
|
|
25267
25563
|
// TODO #643/#645: remove installed listeners / bindings.
|
|
25564
|
+
// Remove every listener installed during `<jssm-action>` / `data-jssm-action`
|
|
25565
|
+
// discovery. Using the original handler reference ensures `removeEventListener`
|
|
25566
|
+
// actually unbinds — anonymous re-creation here would silently leak.
|
|
25567
|
+
for (const entry of this._action_listeners) {
|
|
25568
|
+
entry.target.removeEventListener(entry.event, entry.handler);
|
|
25569
|
+
}
|
|
25570
|
+
this._action_listeners = [];
|
|
25571
|
+
}
|
|
25572
|
+
/**
|
|
25573
|
+
* Wire DOM events to machine actions, using the two declarative forms from
|
|
25574
|
+
* issue #640:
|
|
25575
|
+
*
|
|
25576
|
+
* 1. Inline attribute form: every descendant of the host carrying a
|
|
25577
|
+
* `data-jssm-action="<name>"` attribute receives a listener on the
|
|
25578
|
+
* event named by `data-jssm-event` (default `click`).
|
|
25579
|
+
* 2. Dedicated tag form: each direct `<jssm-action>` child of the host
|
|
25580
|
+
* supplies a CSS `selector` (scoped to the host), an `action`, and an
|
|
25581
|
+
* optional `event` (default `click`); every matching descendant
|
|
25582
|
+
* receives a listener configured by the tag's attributes.
|
|
25583
|
+
*
|
|
25584
|
+
* Both forms support optional `from-state` guards (dispatch only when the
|
|
25585
|
+
* machine's current state matches), `from-property` data extraction (pass
|
|
25586
|
+
* the source element's named property as the action's data argument), and
|
|
25587
|
+
* `prevent-default` / `stop-propagation` modifiers.
|
|
25588
|
+
*
|
|
25589
|
+
* Every installed listener is recorded in {@link _action_listeners} so
|
|
25590
|
+
* {@link disconnectedCallback} can detach them cleanly.
|
|
25591
|
+
*/
|
|
25592
|
+
_discover_jssm_actions() {
|
|
25593
|
+
var _a, _b, _c, _d;
|
|
25594
|
+
// Inline attribute form: `[data-jssm-action]` descendants. Per the
|
|
25595
|
+
// ticket, we scan the host's light DOM (not the shadow tree, which is
|
|
25596
|
+
// owned by us) and skip any element living inside a `<jssm-action>` tag
|
|
25597
|
+
// — those tags are pure data markup, never the source of an event.
|
|
25598
|
+
const inline_targets = Array.from(this.querySelectorAll('[data-jssm-action]')).filter(el => el.closest('jssm-action') === null);
|
|
25599
|
+
for (const el of inline_targets) {
|
|
25600
|
+
this._install_action_listener({
|
|
25601
|
+
source: el,
|
|
25602
|
+
event_name: (_a = el.dataset['jssmEvent']) !== null && _a !== void 0 ? _a : 'click',
|
|
25603
|
+
action_name: el.dataset['jssmAction'],
|
|
25604
|
+
from_state: el.dataset['jssmFromState'],
|
|
25605
|
+
from_property: el.dataset['jssmFromProperty'],
|
|
25606
|
+
prevent_default: 'jssmPreventDefault' in el.dataset,
|
|
25607
|
+
stop_propagation: 'jssmStopPropagation' in el.dataset,
|
|
25608
|
+
});
|
|
25609
|
+
}
|
|
25610
|
+
// Dedicated tag form: direct `<jssm-action>` children of the host.
|
|
25611
|
+
// `:scope >` keeps a nested `<jssm-instance>`'s actions from being
|
|
25612
|
+
// claimed by an outer host.
|
|
25613
|
+
const tags = this.querySelectorAll(':scope > jssm-action');
|
|
25614
|
+
for (const tag of Array.from(tags)) {
|
|
25615
|
+
const selector = tag.getAttribute('selector');
|
|
25616
|
+
const action_name = tag.getAttribute('action');
|
|
25617
|
+
if (selector === null || action_name === null) {
|
|
25618
|
+
// Required attrs missing — skip, but don't throw: a malformed tag
|
|
25619
|
+
// shouldn't break the rest of the host's wiring.
|
|
25620
|
+
continue;
|
|
25621
|
+
}
|
|
25622
|
+
const event_name = (_b = tag.getAttribute('event')) !== null && _b !== void 0 ? _b : 'click';
|
|
25623
|
+
const from_state = (_c = tag.getAttribute('from-state')) !== null && _c !== void 0 ? _c : undefined;
|
|
25624
|
+
const from_property = (_d = tag.getAttribute('from-property')) !== null && _d !== void 0 ? _d : undefined;
|
|
25625
|
+
const prevent_default = tag.hasAttribute('prevent-default');
|
|
25626
|
+
const stop_propagation = tag.hasAttribute('stop-propagation');
|
|
25627
|
+
const sources = this.querySelectorAll(selector);
|
|
25628
|
+
for (const src of Array.from(sources)) {
|
|
25629
|
+
this._install_action_listener({
|
|
25630
|
+
source: src,
|
|
25631
|
+
event_name,
|
|
25632
|
+
action_name,
|
|
25633
|
+
from_state,
|
|
25634
|
+
from_property,
|
|
25635
|
+
prevent_default,
|
|
25636
|
+
stop_propagation,
|
|
25637
|
+
});
|
|
25638
|
+
}
|
|
25639
|
+
}
|
|
25640
|
+
}
|
|
25641
|
+
/**
|
|
25642
|
+
* Attach one DOM listener that translates a DOM event into a
|
|
25643
|
+
* `machine.action(...)` call, honoring the configured modifiers. The
|
|
25644
|
+
* listener is recorded in {@link _action_listeners} so it can be removed
|
|
25645
|
+
* on disconnect.
|
|
25646
|
+
*
|
|
25647
|
+
* @param config - Listener configuration.
|
|
25648
|
+
* @param config.source - Element to attach the listener to.
|
|
25649
|
+
* @param config.event_name - DOM event to listen for.
|
|
25650
|
+
* @param config.action_name - Action to dispatch on the machine.
|
|
25651
|
+
* @param config.from_state - If set, only fire when `machine.state() === from_state`.
|
|
25652
|
+
* @param config.from_property - If set, pass `source[from_property]` as the action's data argument.
|
|
25653
|
+
* @param config.prevent_default - If true, call `e.preventDefault()` before checking the guard.
|
|
25654
|
+
* @param config.stop_propagation - If true, call `e.stopPropagation()` before checking the guard.
|
|
25655
|
+
*/
|
|
25656
|
+
_install_action_listener(config) {
|
|
25657
|
+
const handler = (e) => {
|
|
25658
|
+
if (config.prevent_default) {
|
|
25659
|
+
e.preventDefault();
|
|
25660
|
+
}
|
|
25661
|
+
if (config.stop_propagation) {
|
|
25662
|
+
e.stopPropagation();
|
|
25663
|
+
}
|
|
25664
|
+
// Guard: skip dispatch when the machine isn't in the required state.
|
|
25665
|
+
if (config.from_state !== undefined && this.state() !== config.from_state) {
|
|
25666
|
+
return;
|
|
25667
|
+
}
|
|
25668
|
+
const data = config.from_property !== undefined
|
|
25669
|
+
? config.source[config.from_property]
|
|
25670
|
+
: undefined;
|
|
25671
|
+
this.do(config.action_name, data);
|
|
25672
|
+
};
|
|
25673
|
+
config.source.addEventListener(config.event_name, handler);
|
|
25674
|
+
this._action_listeners.push({
|
|
25675
|
+
target: config.source,
|
|
25676
|
+
event: config.event_name,
|
|
25677
|
+
handler,
|
|
25678
|
+
});
|
|
25268
25679
|
}
|
|
25269
25680
|
/**
|
|
25270
25681
|
* Reflect machine state onto host attributes and CSS custom properties.
|
package/dist/cdn/viz.js
CHANGED
|
@@ -21352,7 +21352,7 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
21352
21352
|
* Useful for runtime diagnostics and for embedding in serialized machine
|
|
21353
21353
|
* snapshots so that deserializers can detect version-skew.
|
|
21354
21354
|
*/
|
|
21355
|
-
const version = "5.
|
|
21355
|
+
const version = "5.138.0";
|
|
21356
21356
|
|
|
21357
21357
|
// whargarbl lots of these return arrays could/should be sets
|
|
21358
21358
|
const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
|