foldkit 0.146.0 → 0.147.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 +5 -2
- package/dist/customElement/index.d.ts.map +1 -1
- package/dist/customElement/index.js +23 -0
- package/dist/experimental/index.d.ts +1 -0
- package/dist/experimental/index.d.ts.map +1 -1
- package/dist/experimental/index.js +1 -0
- package/dist/experimental/machine/machine.d.ts +22 -3
- package/dist/experimental/machine/machine.d.ts.map +1 -1
- package/dist/experimental/machine/machine.js +8 -0
- package/dist/experimental/server/entry.d.ts +73 -0
- package/dist/experimental/server/entry.d.ts.map +1 -0
- package/dist/experimental/server/entry.js +41 -0
- package/dist/experimental/server/host.d.ts +42 -0
- package/dist/experimental/server/host.d.ts.map +1 -0
- package/dist/experimental/server/host.js +169 -0
- package/dist/experimental/server/index.d.ts +5 -0
- package/dist/experimental/server/index.d.ts.map +1 -0
- package/dist/experimental/server/index.js +4 -0
- package/dist/experimental/server/public.d.ts +3 -0
- package/dist/experimental/server/public.d.ts.map +1 -0
- package/dist/experimental/server/public.js +1 -0
- package/dist/experimental/server/serialize.d.ts +33 -0
- package/dist/experimental/server/serialize.d.ts.map +1 -0
- package/dist/experimental/server/serialize.js +563 -0
- package/dist/experimental/server/server.d.ts +201 -0
- package/dist/experimental/server/server.d.ts.map +1 -0
- package/dist/experimental/server/server.js +423 -0
- package/dist/experimental/server/template.d.ts +45 -0
- package/dist/experimental/server/template.d.ts.map +1 -0
- package/dist/experimental/server/template.js +182 -0
- package/dist/html/index.d.ts +5 -0
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +38 -4
- package/dist/hydrate.d.ts +4 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +522 -0
- package/dist/hydrationMarker.d.ts +10 -0
- package/dist/hydrationMarker.d.ts.map +1 -0
- package/dist/hydrationMarker.js +9 -0
- package/dist/runtime/public.d.ts +2 -2
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/public.js +1 -1
- package/dist/runtime/runtime.d.ts +75 -36
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +209 -71
- package/dist/snabbdom/h.d.ts +1 -0
- package/dist/snabbdom/h.d.ts.map +1 -1
- package/dist/snabbdom/h.js +85 -4
- package/dist/snabbdom/tovnode.d.ts.map +1 -1
- package/dist/snabbdom/tovnode.js +5 -1
- package/dist/tagName.d.ts +6 -0
- package/dist/tagName.d.ts.map +1 -0
- package/dist/tagName.js +11 -0
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +25 -1
- package/package.json +8 -1
package/dist/runtime/runtime.js
CHANGED
|
@@ -2,7 +2,9 @@ import { Array, Cause, Context, Duration, Effect, Exit, Fiber, Function, Layer,
|
|
|
2
2
|
import { __CurrentRegistry as __CurrentInterruptRegistry, __makeRegistry as __makeInterruptRegistry, } from '../command/interruptible/index.js';
|
|
3
3
|
import { createDevToolsStore, } from '../devTools/store.js';
|
|
4
4
|
import { startWebSocketBridge } from '../devTools/webSocketBridge.js';
|
|
5
|
-
import { __beginRender as beginHtmlRender, __beginReplayRender as beginReplayHtmlRender, __clearRuntime as clearHtmlRuntime, __createBoundaryRegistry as createHtmlBoundaryRegistry, __endReplayRender as endReplayHtmlRender, __htmlBuilder as htmlBuilderFor, __setRuntime as setHtmlRuntime, } from '../html/index.js';
|
|
5
|
+
import { __beginRender as beginHtmlRender, __beginReplayRender as beginReplayHtmlRender, __clearRuntime as clearHtmlRuntime, __createBoundaryRegistry as createHtmlBoundaryRegistry, __endReplayRender as endReplayHtmlRender, __htmlBuilder as htmlBuilderFor, __setRuntime as setHtmlRuntime, textDirectionToAttribute, } from '../html/index.js';
|
|
6
|
+
import { __hydrateVNode } from '../hydrate.js';
|
|
7
|
+
import { FOLDKIT_APP_ATTRIBUTE, FOLDKIT_FLAGS_ATTRIBUTE, } from '../hydrationMarker.js';
|
|
6
8
|
import { MountTracker } from '../mount/index.js';
|
|
7
9
|
import { __CurrentPortChannels, __makeInboundChannel, } from '../port/index.js';
|
|
8
10
|
import { RenderCommit, createCommitNotifier } from '../render/commit.js';
|
|
@@ -191,6 +193,53 @@ const createDuplicateIdScanner = () => {
|
|
|
191
193
|
/** Effect service tag that provides message dispatching to the view layer. */
|
|
192
194
|
export class Dispatch extends Context.Service()('@foldkit/Dispatch') {
|
|
193
195
|
}
|
|
196
|
+
const hydrationForRoot = (root, isFlagsRequired) => {
|
|
197
|
+
const runtimeId = root.getAttribute(FOLDKIT_APP_ATTRIBUTE) ?? '';
|
|
198
|
+
const flagsPayloads = pipe(Array.fromIterable(document.querySelectorAll(`script[${FOLDKIT_FLAGS_ATTRIBUTE}]`)), Array.filter(script => script.getAttribute(FOLDKIT_FLAGS_ATTRIBUTE) === runtimeId), Array.map(script => script.textContent ?? ''));
|
|
199
|
+
return { root, runtimeId, flagsPayloads, isFlagsRequired };
|
|
200
|
+
};
|
|
201
|
+
// NOTE: hydration is scoped to the app's own stamped root so a server-rendered
|
|
202
|
+
// app never adopts another app's DOM. A container that carries the stamp is that
|
|
203
|
+
// root. A container that does not is a non-root element the caller resolved,
|
|
204
|
+
// which happens when the rendered view has its own element with the container's
|
|
205
|
+
// id (a descendant `id="root"`) and `getElementById` returned that inner element
|
|
206
|
+
// instead of the stamped root above it. That inner element resolves to the app
|
|
207
|
+
// root only when the page has exactly one stamped root and this container sits
|
|
208
|
+
// inside it, so a sibling widget (a stamped root the container is not inside) or
|
|
209
|
+
// an outer application's root (when a nested page carries more than one stamped
|
|
210
|
+
// root) is never wrongly adopted; those fall through to a fresh boot or a hard
|
|
211
|
+
// failure instead. A null container is the replace-parity case, where the server
|
|
212
|
+
// root took the placeholder's place and `getElementById` no longer finds it, so
|
|
213
|
+
// the stamp is the only handle; more than one stamped root is then ambiguous and
|
|
214
|
+
// a hard error rather than a silent wrong-DOM adoption.
|
|
215
|
+
const findDocumentHydration = (container, isFlagsRequired) => {
|
|
216
|
+
const stampedRoots = Array.fromIterable(document.querySelectorAll(`[${FOLDKIT_APP_ATTRIBUTE}]`));
|
|
217
|
+
if (container !== null) {
|
|
218
|
+
if (container.hasAttribute(FOLDKIT_APP_ATTRIBUTE)) {
|
|
219
|
+
return hydrationForRoot(container, isFlagsRequired);
|
|
220
|
+
}
|
|
221
|
+
return Array.match(stampedRoots, {
|
|
222
|
+
onEmpty: () => undefined,
|
|
223
|
+
onNonEmpty: roots => {
|
|
224
|
+
const onlyRoot = Array.headNonEmpty(roots);
|
|
225
|
+
return roots.length === 1 &&
|
|
226
|
+
container.closest(`[${FOLDKIT_APP_ATTRIBUTE}]`) === onlyRoot
|
|
227
|
+
? hydrationForRoot(onlyRoot, isFlagsRequired)
|
|
228
|
+
: undefined;
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
if (stampedRoots.length > 1) {
|
|
233
|
+
throw new Error('[foldkit] Found multiple server-rendered roots stamped with ' +
|
|
234
|
+
`\`${FOLDKIT_APP_ATTRIBUTE}\` but no container to disambiguate them. ` +
|
|
235
|
+
'Give each app its own container element so the runtime can tell ' +
|
|
236
|
+
'which root to hydrate.');
|
|
237
|
+
}
|
|
238
|
+
return Option.match(Array.head(stampedRoots), {
|
|
239
|
+
onNone: () => undefined,
|
|
240
|
+
onSome: root => hydrationForRoot(root, isFlagsRequired),
|
|
241
|
+
});
|
|
242
|
+
};
|
|
194
243
|
const makeHostConnector = () => {
|
|
195
244
|
let isDisposed = false;
|
|
196
245
|
let maybeDeliverInbound = Option.none();
|
|
@@ -314,7 +363,7 @@ const validatePorts = (ports) => {
|
|
|
314
363
|
});
|
|
315
364
|
};
|
|
316
365
|
const runtimeInternals = new WeakMap();
|
|
317
|
-
const makeRuntime = ({ ports, Model,
|
|
366
|
+
const makeRuntime = ({ ports, kind, Model, Flags: FlagsCodec, configuredFlags, isFlagsRequired, init, update, view, manageDocument, subscriptions, container, hydration, routing: routingConfig, crash, slow, viewTransition, freezeModel, preserveScroll, resources, managedResources, devTools, }) => {
|
|
318
367
|
const isSlowVisible = (show) => Match.value(show).pipe(Match.when('Always', () => true), Match.when('Development', () => !!import.meta.hot), Match.exhaustive);
|
|
319
368
|
const htmlBuilder = htmlBuilderFor();
|
|
320
369
|
const resolvedSlow = __resolveSlowConfig(slow, isSlowVisible);
|
|
@@ -352,8 +401,10 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
352
401
|
if (Predicate.isNotUndefined(ports)) {
|
|
353
402
|
validatePorts(ports);
|
|
354
403
|
}
|
|
355
|
-
const runtimeId =
|
|
356
|
-
|
|
404
|
+
const runtimeId = hydration !== undefined && hydration.runtimeId !== ''
|
|
405
|
+
? hydration.runtimeId
|
|
406
|
+
: (container?.id ?? '');
|
|
407
|
+
const startWith = (maybeConnector, hmrModel, bootMode = 'Fresh', bootFlags) => {
|
|
357
408
|
// NOTE: one notifier per runtime, provided across the whole runtime
|
|
358
409
|
// Effect so Commands, Subscriptions, and Mount-forked Effects all resolve
|
|
359
410
|
// the same signal. A commit in one embedded application must never wake a
|
|
@@ -362,7 +413,8 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
362
413
|
return Effect.scoped(Effect.gen(function* () {
|
|
363
414
|
if (runtimeId === '') {
|
|
364
415
|
return yield* Effect.die(new Error('[foldkit] Runtime container must have an `id` for HMR model preservation. ' +
|
|
365
|
-
'Set `container.id = "app"` (or any unique string) before passing it to makeApplication or makeElement.'
|
|
416
|
+
'Set `container.id = "app"` (or any unique string) before passing it to makeApplication or makeElement. ' +
|
|
417
|
+
'On a server-rendered page the id comes from the `data-foldkit-app` root stamp instead.'));
|
|
366
418
|
}
|
|
367
419
|
// NOTE: every perpetual fiber (for example, Subscription streams
|
|
368
420
|
// and ManagedResource lifecycles) and every Command fiber forks
|
|
@@ -434,28 +486,28 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
434
486
|
});
|
|
435
487
|
return Effect.provideService(withPortChannels, __CurrentInterruptRegistry, interruptRegistry);
|
|
436
488
|
};
|
|
437
|
-
// NOTE:
|
|
489
|
+
// NOTE: Flags run through the same cached build that Commands and
|
|
438
490
|
// Subscriptions use, rather than being handed the Layer again, so a
|
|
439
491
|
// service needed both at startup and by a Command is constructed
|
|
440
|
-
// once. An app without
|
|
492
|
+
// once. An app without Flags never reaches it, which keeps the Layer
|
|
441
493
|
// lazy when the first thing that needs it is a Command.
|
|
442
494
|
//
|
|
443
495
|
// NOTE: a Layer that fails to build is not fatal here. Flags resolve
|
|
444
496
|
// before `init`, so there is no Model for a crash view to render
|
|
445
497
|
// against and a failure escaping this point kills the app with a
|
|
446
|
-
// blank container. Running
|
|
447
|
-
// lets an app whose
|
|
448
|
-
// before
|
|
498
|
+
// blank container. Running Flags against an empty context instead
|
|
499
|
+
// lets an app whose Flags never touch the Layer boot as it did
|
|
500
|
+
// before Flags could consume `resources`: the cached failure then
|
|
449
501
|
// surfaces at the first Command or Subscription, where `crashWith`
|
|
450
502
|
// does render the crash view. Flags that do need the Layer still
|
|
451
503
|
// fail here, and both causes are reported: the `Service not found`
|
|
452
504
|
// defect the empty context produced is useless on its own, and the
|
|
453
505
|
// build failure that explains it would be lost if it replaced the
|
|
454
|
-
//
|
|
506
|
+
// Flags cause outright. Combining them also keeps a Flags Effect
|
|
455
507
|
// that fails for its own unrelated reason visible instead of
|
|
456
508
|
// attributing its defect to the Layer. Interrupts propagate
|
|
457
509
|
// untouched on both sides, because dispose racing either the build
|
|
458
|
-
// or the
|
|
510
|
+
// or the Flags run is not a failure to recover from, and
|
|
459
511
|
// `Effect.catchCause` hands the handler interrupt causes too.
|
|
460
512
|
const provideResources = (effect) => Option.match(maybeAcquireResourceContext, {
|
|
461
513
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
@@ -471,23 +523,73 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
471
523
|
onSuccess: resourceContext => Effect.provideContext(effect, resourceContext),
|
|
472
524
|
}),
|
|
473
525
|
});
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
onNone: () =>
|
|
526
|
+
const maybeResolveFreshFlags = Option.orElse(Option.fromNullishOr(bootFlags), () => configuredFlags);
|
|
527
|
+
const resolveFreshFlags = Option.match(maybeResolveFreshFlags, {
|
|
528
|
+
onNone: () => isFlagsRequired
|
|
529
|
+
? Effect.die(new Error('[foldkit] This application declares Flags. Pass its ' +
|
|
530
|
+
'Flags Effect to Runtime.run or Runtime.embed.'))
|
|
531
|
+
: /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
532
|
+
Effect.succeed(undefined),
|
|
477
533
|
onSome: provideResources,
|
|
478
534
|
});
|
|
535
|
+
const decodeFlagsPayload = (payload, runtimeId) => Effect.try({
|
|
536
|
+
try: () => {
|
|
537
|
+
const parsedPayload = JSON.parse(payload);
|
|
538
|
+
return pipe(
|
|
539
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
540
|
+
Schema.toCodecJson(FlagsCodec), Schema.decodeUnknownSync, decode => decode(parsedPayload));
|
|
541
|
+
},
|
|
542
|
+
catch: cause => new Error('[foldkit] Runtime.hydrate could not decode the server ' +
|
|
543
|
+
`Flags payload for application "${runtimeId}". The HTML ` +
|
|
544
|
+
'and client bundle must use the same Flags Schema.', { cause }),
|
|
545
|
+
}).pipe(Effect.orDie);
|
|
546
|
+
const maybeRequestedHydration = bootMode === 'Hydrate'
|
|
547
|
+
? Option.fromNullishOr(hydration)
|
|
548
|
+
: Option.none();
|
|
549
|
+
if (bootMode === 'Hydrate' && Option.isNone(maybeRequestedHydration)) {
|
|
550
|
+
return yield* Effect.die(new Error('[foldkit] Runtime.hydrate could not find a server-rendered ' +
|
|
551
|
+
`root stamped with \`${FOLDKIT_APP_ATTRIBUTE}\`. Use ` +
|
|
552
|
+
'Runtime.run for a fresh client boot.'));
|
|
553
|
+
}
|
|
554
|
+
// NOTE: an HMR-restored Model wins over DOM adoption because the
|
|
555
|
+
// server DOM reflects older code. The hydration handoff is still
|
|
556
|
+
// required, but the restored Model gets a fresh patch against its
|
|
557
|
+
// stamped root.
|
|
558
|
+
const maybeHydrationRoot = Predicate.isUndefined(hmrModel)
|
|
559
|
+
? Option.map(maybeRequestedHydration, requestedHydration => requestedHydration.root)
|
|
560
|
+
: Option.none();
|
|
561
|
+
const maybeHydrationFlags = yield* Option.match(maybeRequestedHydration, {
|
|
562
|
+
onNone: () => Effect.succeed(Option.none()),
|
|
563
|
+
onSome: requestedHydration => Effect.map(requestedHydration.isFlagsRequired
|
|
564
|
+
? Array.match(requestedHydration.flagsPayloads, {
|
|
565
|
+
onEmpty: () => Effect.die(new Error('[foldkit] Runtime.hydrate found application ' +
|
|
566
|
+
`"${requestedHydration.runtimeId}" but its ` +
|
|
567
|
+
'server Flags payload is missing.')),
|
|
568
|
+
onNonEmpty: ([payload, ...remainingPayloads]) => Array.isArrayNonEmpty(remainingPayloads)
|
|
569
|
+
? Effect.die(new Error('[foldkit] Runtime.hydrate found multiple ' +
|
|
570
|
+
'server Flags payloads for application ' +
|
|
571
|
+
`"${requestedHydration.runtimeId}".`))
|
|
572
|
+
: decodeFlagsPayload(payload, requestedHydration.runtimeId),
|
|
573
|
+
})
|
|
574
|
+
: /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
575
|
+
Effect.succeed(undefined), Option.some),
|
|
576
|
+
});
|
|
577
|
+
const resolveFlags = Option.match(maybeHydrationFlags, {
|
|
578
|
+
onNone: () => resolveFreshFlags,
|
|
579
|
+
onSome: Effect.succeed,
|
|
580
|
+
});
|
|
479
581
|
const ModelJsonCodec = Schema.toCodecJson(
|
|
480
582
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
481
583
|
Model);
|
|
482
584
|
const decodeHmrModel = Schema.decodeUnknownExit(ModelJsonCodec);
|
|
483
585
|
const encodeHmrModel = Schema.encodeUnknownSync(ModelJsonCodec);
|
|
484
586
|
const currentUrl = Option.fromNullishOr(routingConfig).pipe(Option.flatMap(() => urlFromString(window.location.href)));
|
|
485
|
-
// NOTE: a restored Model skips `init`, so resolving
|
|
587
|
+
// NOTE: a restored Model skips `init`, so resolving Flags on that
|
|
486
588
|
// path would build the `resources` Layer only to discard what it
|
|
487
589
|
// produced. Gating the resolution on the restore decision is what
|
|
488
590
|
// stops a reload from reconnecting whatever the Layer holds. It has
|
|
489
591
|
// to stay ahead of the preserve-scheduler and HMR finalizers: a
|
|
490
|
-
//
|
|
592
|
+
// Flags Effect that fails after those are registered tears down more
|
|
491
593
|
// than it used to, and their release defects would bury its cause.
|
|
492
594
|
const runInit = Effect.map(resolveFlags, flags => init(flags, Option.getOrUndefined(currentUrl)));
|
|
493
595
|
const [initModelRaw, initCommands] = yield* hmrModel !== undefined
|
|
@@ -637,6 +739,10 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
637
739
|
}
|
|
638
740
|
};
|
|
639
741
|
const vnodeSlot = { maybeCurrentVNode: Option.none() };
|
|
742
|
+
// NOTE: consumed by the first render only. Set when this boot found
|
|
743
|
+
// an adoptable server-rendered root; the first patch then goes
|
|
744
|
+
// through `__hydrateVNode` instead of replacing the container.
|
|
745
|
+
let pendingHydrationRoot = Option.getOrNull(maybeHydrationRoot);
|
|
640
746
|
// NOTE: registered before any perpetual fiber is forked so it runs
|
|
641
747
|
// after they are interrupted (scope finalizers are LIFO). Patching to
|
|
642
748
|
// an empty tree fires snabbdom destroy hooks, which is what releases
|
|
@@ -941,7 +1047,24 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
941
1047
|
thresholdMs,
|
|
942
1048
|
}));
|
|
943
1049
|
const maybeCurrentVNode = vnodeSlot.maybeCurrentVNode;
|
|
944
|
-
const [patchedVNode, maybePatchDuration] = yield* Effect.sync(() => measureSlowPhase(maybeLiveSlowPatch, () =>
|
|
1050
|
+
const [patchedVNode, maybePatchDuration] = yield* Effect.sync(() => measureSlowPhase(maybeLiveSlowPatch, () => {
|
|
1051
|
+
if (Option.isNone(maybeCurrentVNode) &&
|
|
1052
|
+
pendingHydrationRoot !== null) {
|
|
1053
|
+
const hydrationRoot = pendingHydrationRoot;
|
|
1054
|
+
pendingHydrationRoot = null;
|
|
1055
|
+
// NOTE: strip the stamp before the patch, not after, so the
|
|
1056
|
+
// patch is the sole owner of the root's attributes. It has
|
|
1057
|
+
// already served its purpose of locating the root, and
|
|
1058
|
+
// removing it after would delete a `data-foldkit-app` the view
|
|
1059
|
+
// itself declares, which a later equal-vnode patch would not
|
|
1060
|
+
// restore. Removing it here also stops a later boot on the same
|
|
1061
|
+
// container (a dispose-then-embed remount) from re-detecting
|
|
1062
|
+
// this now-consumed root as hydratable.
|
|
1063
|
+
hydrationRoot.removeAttribute(FOLDKIT_APP_ATTRIBUTE);
|
|
1064
|
+
return __hydrateVNode(hydrationRoot, nextVNode, boundaryRegistry.dedupeSeen);
|
|
1065
|
+
}
|
|
1066
|
+
return __patchVNode(maybeCurrentVNode, nextVNode, container, boundaryRegistry.dedupeSeen);
|
|
1067
|
+
}));
|
|
945
1068
|
vnodeSlot.maybeCurrentVNode = Option.some(patchedVNode);
|
|
946
1069
|
reportSlowPhase(maybeLiveSlowPatch, maybePatchDuration, (durationMs, thresholdMs) => ({
|
|
947
1070
|
_tag: 'Patch',
|
|
@@ -1372,10 +1495,15 @@ const makeRuntime = ({ ports, Model, flags: maybeResolveFlags, init, update, vie
|
|
|
1372
1495
|
yield* Effect.never;
|
|
1373
1496
|
})).pipe(Effect.provideService(RenderCommit, commitNotifier.service));
|
|
1374
1497
|
};
|
|
1375
|
-
const start = (hmrModel) => startWith(Option.none(), hmrModel);
|
|
1376
|
-
const program = {
|
|
1498
|
+
const start = (hmrModel) => startWith(Option.none(), hmrModel, 'Fresh');
|
|
1499
|
+
const program = {
|
|
1500
|
+
runtimeId,
|
|
1501
|
+
start,
|
|
1502
|
+
ports,
|
|
1503
|
+
};
|
|
1377
1504
|
runtimeInternals.set(program, {
|
|
1378
|
-
startWith,
|
|
1505
|
+
startWith: (maybeConnector, hmrModel, bootMode, flags) => startWith(maybeConnector, hmrModel, bootMode, flags),
|
|
1506
|
+
kind,
|
|
1379
1507
|
isEmbedActive: false,
|
|
1380
1508
|
maybeActiveFiber: Option.none(),
|
|
1381
1509
|
});
|
|
@@ -1390,11 +1518,6 @@ const currentLocationUrl = () => {
|
|
|
1390
1518
|
const { origin, pathname, search } = window.location;
|
|
1391
1519
|
return `${origin}${pathname}${search}`;
|
|
1392
1520
|
};
|
|
1393
|
-
const textDirectionForHtmlElement = {
|
|
1394
|
-
Ltr: 'ltr',
|
|
1395
|
-
Rtl: 'rtl',
|
|
1396
|
-
Auto: 'auto',
|
|
1397
|
-
};
|
|
1398
1521
|
const documentMetadataElements = new WeakMap();
|
|
1399
1522
|
const metadataElementsForDocument = () => {
|
|
1400
1523
|
let elements = documentMetadataElements.get(document);
|
|
@@ -1431,7 +1554,7 @@ const applyDocumentMetadata = (nextDocument, mountedRoot) => {
|
|
|
1431
1554
|
documentElement.lang = nextDocument.lang;
|
|
1432
1555
|
}
|
|
1433
1556
|
if (nextDocument.dir !== undefined) {
|
|
1434
|
-
const dir =
|
|
1557
|
+
const dir = textDirectionToAttribute(nextDocument.dir);
|
|
1435
1558
|
if (documentElement.dir !== dir) {
|
|
1436
1559
|
documentElement.dir = dir;
|
|
1437
1560
|
}
|
|
@@ -1503,24 +1626,29 @@ const renderCrashView = (context, crash, container, vnodeSlot, manageDocument) =
|
|
|
1503
1626
|
};
|
|
1504
1627
|
export function makeApplication(config) {
|
|
1505
1628
|
const { container } = config;
|
|
1506
|
-
|
|
1629
|
+
const hasRouting = 'routing' in config;
|
|
1630
|
+
const hasFlags = 'Flags' in config;
|
|
1631
|
+
const hydration = findDocumentHydration(container, hasFlags);
|
|
1632
|
+
const resolvedContainer = hydration?.root ?? container;
|
|
1633
|
+
if (resolvedContainer === null) {
|
|
1507
1634
|
throw new Error('[foldkit] Container is null. Make sure the element exists in the DOM ' +
|
|
1508
1635
|
'before calling makeApplication (e.g. that your <div id="root"></div> has ' +
|
|
1509
|
-
'rendered, and your script runs after it).'
|
|
1636
|
+
'rendered, and your script runs after it). On a server-rendered page ' +
|
|
1637
|
+
'the runtime instead finds the root by its `data-foldkit-app` stamp.');
|
|
1510
1638
|
}
|
|
1511
|
-
const hasRouting = 'routing' in config;
|
|
1512
|
-
const hasFlags = 'Flags' in config;
|
|
1513
1639
|
const currentUrl = hasRouting
|
|
1514
1640
|
? Option.getOrThrow(urlFromString(window.location.href))
|
|
1515
1641
|
: undefined;
|
|
1516
1642
|
const baseConfig = {
|
|
1643
|
+
kind: 'Application',
|
|
1517
1644
|
Model: config.Model,
|
|
1518
1645
|
update: config.update,
|
|
1519
1646
|
view: config.view,
|
|
1520
1647
|
manageDocument: true,
|
|
1521
1648
|
ports: config.ports,
|
|
1522
1649
|
...(config.subscriptions && { subscriptions: config.subscriptions }),
|
|
1523
|
-
container,
|
|
1650
|
+
container: resolvedContainer,
|
|
1651
|
+
...(hydration && { hydration }),
|
|
1524
1652
|
...(hasRouting && { routing: config.routing }),
|
|
1525
1653
|
...(config.crash && { crash: config.crash }),
|
|
1526
1654
|
...(Predicate.isNotUndefined(config.slow) && {
|
|
@@ -1548,7 +1676,8 @@ export function makeApplication(config) {
|
|
|
1548
1676
|
return makeRuntime({
|
|
1549
1677
|
...baseConfig,
|
|
1550
1678
|
Flags: config.Flags,
|
|
1551
|
-
|
|
1679
|
+
configuredFlags: Option.none(),
|
|
1680
|
+
isFlagsRequired: true,
|
|
1552
1681
|
init: (flags, url) => config.init(flags, url ?? currentUrl),
|
|
1553
1682
|
});
|
|
1554
1683
|
}
|
|
@@ -1556,7 +1685,8 @@ export function makeApplication(config) {
|
|
|
1556
1685
|
return makeRuntime({
|
|
1557
1686
|
...baseConfig,
|
|
1558
1687
|
Flags: Schema.Void,
|
|
1559
|
-
|
|
1688
|
+
configuredFlags: Option.none(),
|
|
1689
|
+
isFlagsRequired: false,
|
|
1560
1690
|
init: (_flags, url) => config.init(url ?? currentUrl),
|
|
1561
1691
|
});
|
|
1562
1692
|
}
|
|
@@ -1564,7 +1694,8 @@ export function makeApplication(config) {
|
|
|
1564
1694
|
return makeRuntime({
|
|
1565
1695
|
...baseConfig,
|
|
1566
1696
|
Flags: config.Flags,
|
|
1567
|
-
|
|
1697
|
+
configuredFlags: Option.none(),
|
|
1698
|
+
isFlagsRequired: true,
|
|
1568
1699
|
init: (flags) => config.init(flags),
|
|
1569
1700
|
});
|
|
1570
1701
|
}
|
|
@@ -1572,7 +1703,8 @@ export function makeApplication(config) {
|
|
|
1572
1703
|
return makeRuntime({
|
|
1573
1704
|
...baseConfig,
|
|
1574
1705
|
Flags: Schema.Void,
|
|
1575
|
-
|
|
1706
|
+
configuredFlags: Option.none(),
|
|
1707
|
+
isFlagsRequired: false,
|
|
1576
1708
|
init: () => config.init(),
|
|
1577
1709
|
});
|
|
1578
1710
|
}
|
|
@@ -1610,6 +1742,7 @@ export function makeElement(config) {
|
|
|
1610
1742
|
});
|
|
1611
1743
|
const crash = toCrashConfig(config.crash);
|
|
1612
1744
|
const baseConfig = {
|
|
1745
|
+
kind: 'Element',
|
|
1613
1746
|
Model: config.Model,
|
|
1614
1747
|
update: config.update,
|
|
1615
1748
|
view,
|
|
@@ -1640,7 +1773,8 @@ export function makeElement(config) {
|
|
|
1640
1773
|
return makeRuntime({
|
|
1641
1774
|
...baseConfig,
|
|
1642
1775
|
Flags: config.Flags,
|
|
1643
|
-
|
|
1776
|
+
configuredFlags: Option.some(config.flags),
|
|
1777
|
+
isFlagsRequired: true,
|
|
1644
1778
|
init: (flags) => config.init(flags),
|
|
1645
1779
|
});
|
|
1646
1780
|
}
|
|
@@ -1648,7 +1782,8 @@ export function makeElement(config) {
|
|
|
1648
1782
|
return makeRuntime({
|
|
1649
1783
|
...baseConfig,
|
|
1650
1784
|
Flags: Schema.Void,
|
|
1651
|
-
|
|
1785
|
+
configuredFlags: Option.none(),
|
|
1786
|
+
isFlagsRequired: false,
|
|
1652
1787
|
init: () => config.init(),
|
|
1653
1788
|
});
|
|
1654
1789
|
}
|
|
@@ -1716,6 +1851,20 @@ const resolveHmrModel = (runtimeId) => {
|
|
|
1716
1851
|
return Effect.succeed(undefined);
|
|
1717
1852
|
}));
|
|
1718
1853
|
};
|
|
1854
|
+
/** Starts a program Effect with explicit boot inputs for runtime tests.
|
|
1855
|
+
* @internal */
|
|
1856
|
+
export const __startProgram = (program, hmrModel, bootMode, flags) => {
|
|
1857
|
+
const internals = runtimeInternals.get(program);
|
|
1858
|
+
if (Predicate.isUndefined(internals)) {
|
|
1859
|
+
return Effect.die(new Error('[foldkit] Runtime boot expects a program created by ' +
|
|
1860
|
+
'makeApplication or makeElement.'));
|
|
1861
|
+
}
|
|
1862
|
+
if (bootMode === 'Hydrate' && internals.kind !== 'Application') {
|
|
1863
|
+
return Effect.die(new Error('[foldkit] Runtime.hydrate expects a program created by ' +
|
|
1864
|
+
'makeApplication.'));
|
|
1865
|
+
}
|
|
1866
|
+
return internals.startWith(Option.none(), hmrModel, bootMode, flags);
|
|
1867
|
+
};
|
|
1719
1868
|
// NOTE: deliberately not `BrowserRuntime.runMain`, which interrupts the
|
|
1720
1869
|
// runtime on `beforeunload`. `beforeunload` is a question, not a commitment:
|
|
1721
1870
|
// the browser also fires it for a click on a download link, for a navigation
|
|
@@ -1727,11 +1876,25 @@ const resolveHmrModel = (runtimeId) => {
|
|
|
1727
1876
|
// interrupt at all and lets the document take the runtime with it. Error
|
|
1728
1877
|
// reporting and the keep-alive interval come from `makeRunMain` either way.
|
|
1729
1878
|
const runMainWithoutUnloadInterrupt = Runtime.makeRunMain(Function.constVoid);
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
export
|
|
1734
|
-
|
|
1879
|
+
const startProgram = (program, bootMode, flags) => {
|
|
1880
|
+
runMainWithoutUnloadInterrupt(provideBrowserScheduler(Effect.flatMap(resolveHmrModel(program.runtimeId), hmrModel => __startProgram(program, hmrModel, bootMode, flags))));
|
|
1881
|
+
};
|
|
1882
|
+
export function run(program, options) {
|
|
1883
|
+
startProgram(program, 'Fresh', options?.flags);
|
|
1884
|
+
}
|
|
1885
|
+
/** Starts a Foldkit runtime by adopting a server-rendered DOM in place instead
|
|
1886
|
+
* of building it fresh. Use this as the client entry for a page served by
|
|
1887
|
+
* `renderToString`: the first render attaches to the stamped root, keeps the
|
|
1888
|
+
* existing nodes, and reconstructs the Model from the Flags the server
|
|
1889
|
+
* embedded. The handoff is strict: a missing server root, missing Flags
|
|
1890
|
+
* payload, or undecodable payload terminates startup and leaves the server
|
|
1891
|
+
* HTML visible but inert. Use `run` in a separate client-only entry when the
|
|
1892
|
+
* page should boot without server output.
|
|
1893
|
+
*
|
|
1894
|
+
* @experimental Server rendering and hydration are experimental while their
|
|
1895
|
+
* contracts settle. */
|
|
1896
|
+
export const hydrate = (program) => {
|
|
1897
|
+
startProgram(program, 'Hydrate');
|
|
1735
1898
|
};
|
|
1736
1899
|
const buildPortHandles = (ports, connector) => {
|
|
1737
1900
|
const handles = {};
|
|
@@ -1750,32 +1913,7 @@ const buildPortHandles = (ports, connector) => {
|
|
|
1750
1913
|
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
1751
1914
|
return handles;
|
|
1752
1915
|
};
|
|
1753
|
-
|
|
1754
|
-
* Starts a Foldkit runtime under a host-controlled lifecycle and returns an
|
|
1755
|
-
* `EmbedHandle`. This is the entry point for embedding a Foldkit app inside
|
|
1756
|
-
* another application: the host pushes values in through the handle's inbound
|
|
1757
|
-
* Ports, listens to outbound Ports, and calls `dispose` when it unmounts the
|
|
1758
|
-
* app. The host never touches the Model or dispatches Messages directly; the
|
|
1759
|
-
* Schema-typed Ports are the whole boundary.
|
|
1760
|
-
*
|
|
1761
|
-
* Works with programs from both `makeApplication` and `makeElement`; for a
|
|
1762
|
-
* widget on a page the host owns, `makeElement` is the natural fit.
|
|
1763
|
-
*
|
|
1764
|
-
* A program can be embedded once at a time (it owns one container). After
|
|
1765
|
-
* `dispose`, the same container can be embedded again with a fresh program.
|
|
1766
|
-
*
|
|
1767
|
-
* ```ts
|
|
1768
|
-
* const handle = Runtime.embed(element)
|
|
1769
|
-
*
|
|
1770
|
-
* handle.ports.stepChanged.send(5)
|
|
1771
|
-
* const unsubscribe = handle.ports.countChanged.subscribe(count => {
|
|
1772
|
-
* console.log(count)
|
|
1773
|
-
* })
|
|
1774
|
-
*
|
|
1775
|
-
* handle.dispose()
|
|
1776
|
-
* ```
|
|
1777
|
-
*/
|
|
1778
|
-
export const embed = (program) => {
|
|
1916
|
+
export function embed(program, options) {
|
|
1779
1917
|
const internals = runtimeInternals.get(program);
|
|
1780
1918
|
if (Predicate.isUndefined(internals)) {
|
|
1781
1919
|
throw new Error('[foldkit] embed expects a program created by makeApplication or makeElement.');
|
|
@@ -1795,7 +1933,7 @@ export const embed = (program) => {
|
|
|
1795
1933
|
const startEffect = pipe(Option.match(internals.maybeActiveFiber, {
|
|
1796
1934
|
onNone: () => Effect.void,
|
|
1797
1935
|
onSome: previousFiber => Effect.asVoid(Fiber.await(previousFiber)),
|
|
1798
|
-
}), Effect.andThen(resolveHmrModel(program.runtimeId)), Effect.flatMap(hmrModel => internals.startWith(Option.some(connector), hmrModel)));
|
|
1936
|
+
}), Effect.andThen(resolveHmrModel(program.runtimeId)), Effect.flatMap(hmrModel => internals.startWith(Option.some(connector), hmrModel, 'Fresh', options?.flags)));
|
|
1799
1937
|
const fiber = Effect.runFork(provideBrowserScheduler(startEffect));
|
|
1800
1938
|
internals.maybeActiveFiber = Option.some(fiber);
|
|
1801
1939
|
let isHandleDisposed = false;
|
|
@@ -1810,4 +1948,4 @@ export const embed = (program) => {
|
|
|
1810
1948
|
};
|
|
1811
1949
|
const ports = buildPortHandles(program.ports, connector);
|
|
1812
1950
|
return { ports, dispose };
|
|
1813
|
-
}
|
|
1951
|
+
}
|
package/dist/snabbdom/h.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type VNodeChildElement = VNode | string | number | String | Number | unde
|
|
|
4
4
|
export type ArrayOrElement<T> = T | Array<T>;
|
|
5
5
|
export type VNodeChildren = ArrayOrElement<VNodeChildElement>;
|
|
6
6
|
export declare function addNS(data: any, children: Array<VNode | string> | undefined, sel: string | undefined): void;
|
|
7
|
+
export declare function addMathmlNS(data: any, children: Array<VNode | string> | undefined, sel: string | undefined): void;
|
|
7
8
|
export declare function h(sel: string): VNode;
|
|
8
9
|
export declare function h(sel: string, data: VNodeData | null): VNode;
|
|
9
10
|
export declare function h(sel: string, children: VNodeChildren): VNode;
|
package/dist/snabbdom/h.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"h.d.ts","sourceRoot":"","sources":["../../src/snabbdom/h.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"h.d.ts","sourceRoot":"","sources":["../../src/snabbdom/h.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAS,MAAM,YAAY,CAAA;AAE9D,MAAM,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;AACjC,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,SAAS,GACT,IAAI,CAAA;AACR,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;AAC5C,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAA;AAsD7D,wBAAgB,KAAK,CACnB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,SAAS,EAC3C,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,IAAI,CAQN;AA6DD,wBAAgB,WAAW,CACzB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,SAAS,EAC3C,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,IAAI,CAEN;AAED,wBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;AACrC,wBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,KAAK,CAAA;AAC7D,wBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,KAAK,CAAA;AAC9D,wBAAgB,CAAC,CACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,SAAS,GAAG,IAAI,EACtB,QAAQ,EAAE,aAAa,GACtB,KAAK,CAAA"}
|
package/dist/snabbdom/h.js
CHANGED
|
@@ -1,18 +1,95 @@
|
|
|
1
|
+
import { tagNameFromSelector } from '../tagName.js';
|
|
1
2
|
import * as is from './is.js';
|
|
2
3
|
import { vnode } from './vnode.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
5
|
+
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
6
|
+
// NOTE: inside SVG, the content of foreignObject, desc, and title is parsed in
|
|
7
|
+
// the HTML namespace (SVG's HTML integration points), so the SVG namespace must
|
|
8
|
+
// not propagate into their children.
|
|
9
|
+
const SVG_HTML_INTEGRATION_POINTS = new Set(['foreignObject', 'desc', 'title']);
|
|
10
|
+
// NOTE: inside a MathML text integration point (mi, mo, mn, ms, mtext) the
|
|
11
|
+
// content is parsed as HTML, so the MathML namespace stops there, except for
|
|
12
|
+
// mglyph and malignmark, which the parser keeps in the MathML namespace. A
|
|
13
|
+
// MathML annotation-xml element is an HTML integration point when its encoding
|
|
14
|
+
// is text/html or application/xhtml+xml, so its children are HTML too.
|
|
15
|
+
const MATHML_TEXT_INTEGRATION_POINTS = new Set([
|
|
16
|
+
'mi',
|
|
17
|
+
'mo',
|
|
18
|
+
'mn',
|
|
19
|
+
'ms',
|
|
20
|
+
'mtext',
|
|
21
|
+
]);
|
|
22
|
+
const MATHML_TEXT_INTEGRATION_EXCEPTIONS = new Set(['mglyph', 'malignmark']);
|
|
23
|
+
const MATHML_HTML_ENCODINGS = new Set(['text/html', 'application/xhtml+xml']);
|
|
24
|
+
const propagateNamespace = (data, children, sel, namespace, integrationPoints) => {
|
|
25
|
+
data.ns = namespace;
|
|
26
|
+
if ((sel === undefined || !integrationPoints.has(sel)) &&
|
|
27
|
+
children !== undefined) {
|
|
6
28
|
for (let i = 0; i < children.length; ++i) {
|
|
7
29
|
const child = children[i];
|
|
8
30
|
if (typeof child === 'string')
|
|
9
31
|
continue;
|
|
10
32
|
const childData = child.data;
|
|
11
33
|
if (childData !== undefined) {
|
|
12
|
-
|
|
34
|
+
propagateNamespace(childData, child.children, child.sel, namespace, integrationPoints);
|
|
13
35
|
}
|
|
14
36
|
}
|
|
15
37
|
}
|
|
38
|
+
};
|
|
39
|
+
export function addNS(data, children, sel) {
|
|
40
|
+
propagateNamespace(data, children, sel, SVG_NAMESPACE, SVG_HTML_INTEGRATION_POINTS);
|
|
41
|
+
}
|
|
42
|
+
// NOTE: an annotation-xml is an HTML integration point when its encoding
|
|
43
|
+
// attribute is text/html or application/xhtml+xml. HTML attribute names are
|
|
44
|
+
// case-insensitive, so the name is matched case-insensitively as well as the
|
|
45
|
+
// value.
|
|
46
|
+
const isHtmlIntegrationAnnotationXml = (data) => {
|
|
47
|
+
const attrs = data?.attrs;
|
|
48
|
+
if (attrs === undefined || attrs === null) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
for (const name of Object.keys(attrs)) {
|
|
52
|
+
if (name.toLowerCase() === 'encoding') {
|
|
53
|
+
const value = attrs[name];
|
|
54
|
+
return (typeof value === 'string' &&
|
|
55
|
+
MATHML_HTML_ENCODINGS.has(value.toLowerCase()));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
// NOTE: MathML namespace propagation carries the integration-point exceptions
|
|
61
|
+
// the generic walk cannot express: children of a text integration point are
|
|
62
|
+
// HTML except mglyph and malignmark, and children of an annotation-xml with an
|
|
63
|
+
// HTML encoding are HTML. Everything else inherits the MathML namespace.
|
|
64
|
+
const propagateMathmlNamespace = (data, children, sel) => {
|
|
65
|
+
data.ns = MATHML_NAMESPACE;
|
|
66
|
+
if (children === undefined) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const tag = sel === undefined ? undefined : tagNameFromSelector(sel);
|
|
70
|
+
if (tag === 'annotation-xml' && isHtmlIntegrationAnnotationXml(data)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const isTextIntegrationPoint = tag !== undefined && MATHML_TEXT_INTEGRATION_POINTS.has(tag);
|
|
74
|
+
for (let i = 0; i < children.length; ++i) {
|
|
75
|
+
const child = children[i];
|
|
76
|
+
if (typeof child === 'string')
|
|
77
|
+
continue;
|
|
78
|
+
const childData = child.data;
|
|
79
|
+
if (childData === undefined)
|
|
80
|
+
continue;
|
|
81
|
+
if (isTextIntegrationPoint) {
|
|
82
|
+
const childTag = child.sel === undefined ? undefined : tagNameFromSelector(child.sel);
|
|
83
|
+
if (childTag === undefined ||
|
|
84
|
+
!MATHML_TEXT_INTEGRATION_EXCEPTIONS.has(childTag)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
propagateMathmlNamespace(childData, child.children, child.sel);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
export function addMathmlNS(data, children, sel) {
|
|
92
|
+
propagateMathmlNamespace(data, children, sel);
|
|
16
93
|
}
|
|
17
94
|
export function h(sel, b, c) {
|
|
18
95
|
let data = {};
|
|
@@ -57,5 +134,9 @@ export function h(sel, b, c) {
|
|
|
57
134
|
(sel.length === 3 || sel[3] === '.' || sel[3] === '#')) {
|
|
58
135
|
addNS(data, children, sel);
|
|
59
136
|
}
|
|
137
|
+
else if (sel.startsWith('math') &&
|
|
138
|
+
(sel.length === 4 || sel[4] === '.' || sel[4] === '#')) {
|
|
139
|
+
addMathmlNS(data, children, sel);
|
|
140
|
+
}
|
|
60
141
|
return vnode(sel, data, children, text, undefined);
|
|
61
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tovnode.d.ts","sourceRoot":"","sources":["../../src/snabbdom/tovnode.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAc,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,KAAK,KAAK,EAAS,MAAM,YAAY,CAAA;AAc9C,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,
|
|
1
|
+
{"version":3,"file":"tovnode.d.ts","sourceRoot":"","sources":["../../src/snabbdom/tovnode.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAc,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,KAAK,KAAK,EAAS,MAAM,YAAY,CAAA;AAc9C,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAsD1D"}
|
package/dist/snabbdom/tovnode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
2
|
-
import { addNS } from './h.js';
|
|
2
|
+
import { addMathmlNS, addNS } from './h.js';
|
|
3
3
|
import { htmlDomApi } from './htmldomapi.js';
|
|
4
4
|
import { vnode } from './vnode.js';
|
|
5
5
|
/**
|
|
@@ -53,6 +53,10 @@ export function toVNode(node, domApi) {
|
|
|
53
53
|
(sel.length === 3 || sel[3] === '.' || sel[3] === '#')) {
|
|
54
54
|
addNS(data, children, sel);
|
|
55
55
|
}
|
|
56
|
+
else if (sel.startsWith('math') &&
|
|
57
|
+
(sel.length === 4 || sel[4] === '.' || sel[4] === '#')) {
|
|
58
|
+
addMathmlNS(data, children, sel);
|
|
59
|
+
}
|
|
56
60
|
return vnode(sel, data, children, undefined, node);
|
|
57
61
|
}
|
|
58
62
|
else if (api.isText(node)) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Extracts the tag name from a snabbdom selector, dropping any `#id` or
|
|
2
|
+
* `.class` suffix. Foldkit builds bare-tag selectors, so in practice this
|
|
3
|
+
* returns the selector unchanged, but the id/class handling keeps it correct
|
|
4
|
+
* for any selector snabbdom itself would accept. */
|
|
5
|
+
export declare const tagNameFromSelector: (selector: string) => string;
|
|
6
|
+
//# sourceMappingURL=tagName.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tagName.d.ts","sourceRoot":"","sources":["../src/tagName.ts"],"names":[],"mappings":"AAAA;;;qDAGqD;AACrD,eAAO,MAAM,mBAAmB,GAAI,UAAU,MAAM,KAAG,MAMtD,CAAA"}
|