@studiometa/js-toolkit 4.0.0-alpha.1 → 4.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/Base.d.ts +0 -2
- package/dist/Base.js +1 -2
- package/dist/Base.js.map +1 -1
- package/dist/attribute-namespaces.d.ts +0 -2
- package/dist/attribute-namespaces.js +1 -2
- package/dist/attributes.d.ts +0 -2
- package/dist/attributes.js +1 -2
- package/dist/children-watchers.d.ts +0 -2
- package/dist/children-watchers.js +1 -2
- package/dist/component-brand.d.ts +0 -2
- package/dist/component-brand.js +1 -2
- package/dist/component-declarations.d.ts +0 -2
- package/dist/component-declarations.js +1 -2
- package/dist/context-subscription.d.ts +0 -2
- package/dist/context-subscription.js +1 -2
- package/dist/context.d.ts +0 -2
- package/dist/context.js +1 -2
- package/dist/decorators.d.ts +0 -2
- package/dist/decorators.js +1 -2
- package/dist/diagnostic-contract.d.ts +0 -2
- package/dist/diagnostic-contract.js +1 -2
- package/dist/diagnostics.d.ts +0 -2
- package/dist/diagnostics.js +1 -2
- package/dist/document-order.d.ts +0 -2
- package/dist/document-order.js +1 -2
- package/dist/dom-mutations.d.ts +0 -2
- package/dist/dom-mutations.js +1 -2
- package/dist/events.d.ts +0 -2
- package/dist/events.js +1 -2
- package/dist/group.d.ts +0 -2
- package/dist/group.js +1 -2
- package/dist/instances.d.ts +0 -2
- package/dist/instances.js +1 -2
- package/dist/manifest.d.ts +0 -2
- package/dist/manifest.js +1 -2
- package/dist/mount-strategies.d.ts +0 -2
- package/dist/mount-strategies.js +1 -2
- package/dist/negotiated-events.d.ts +0 -2
- package/dist/negotiated-events.js +1 -2
- package/dist/protocol-symbols.d.ts +0 -2
- package/dist/protocol-symbols.js +1 -2
- package/dist/registry.d.ts +0 -2
- package/dist/registry.js +1 -2
- package/dist/responsive-options.d.ts +0 -2
- package/dist/responsive-options.js +1 -2
- package/dist/scheduler.d.ts +0 -2
- package/dist/scheduler.js +1 -2
- package/dist/scheduler.js.map +1 -1
- package/dist/services/breakpoint.d.ts +0 -2
- package/dist/services/breakpoint.js +1 -2
- package/dist/services/drag.d.ts +0 -2
- package/dist/services/drag.js +1 -2
- package/dist/services/in-view.d.ts +0 -2
- package/dist/services/in-view.js +1 -2
- package/dist/services/key.d.ts +0 -2
- package/dist/services/key.js +1 -2
- package/dist/services/media.d.ts +0 -2
- package/dist/services/media.js +1 -2
- package/dist/services/mixin.d.ts +0 -2
- package/dist/services/mixin.js +1 -2
- package/dist/services/mutation.d.ts +0 -2
- package/dist/services/mutation.js +1 -2
- package/dist/services/pointer.d.ts +0 -2
- package/dist/services/pointer.js +1 -2
- package/dist/services/raf.d.ts +0 -2
- package/dist/services/raf.js +1 -2
- package/dist/services/resize.d.ts +0 -2
- package/dist/services/resize.js +1 -2
- package/dist/services/scroll-progress-offset.d.ts +0 -2
- package/dist/services/scroll-progress-offset.js +1 -2
- package/dist/services/scroll-progress.d.ts +0 -2
- package/dist/services/scroll-progress.js +1 -2
- package/dist/services/scroll.d.ts +0 -2
- package/dist/services/scroll.js +1 -2
- package/dist/services/service.d.ts +0 -2
- package/dist/services/service.js +1 -2
- package/dist/services/toggle.d.ts +0 -2
- package/dist/services/toggle.js +1 -2
- package/dist/services/until.d.ts +0 -2
- package/dist/services/until.js +1 -2
- package/dist/shared-runtime.d.ts +0 -2
- package/dist/shared-runtime.js +1 -2
- package/dist/storage/createStorage.d.ts +0 -2
- package/dist/storage/createStorage.js +1 -2
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.js +1 -2
- package/dist/storage/providers.d.ts +0 -2
- package/dist/storage/providers.js +1 -2
- package/dist/storage/serializers.d.ts +0 -2
- package/dist/storage/serializers.js +1 -2
- package/dist/storage/sync.d.ts +0 -2
- package/dist/storage/sync.js +1 -2
- package/dist/storage/types.d.ts +0 -2
- package/dist/subpaths/BREAKPOINTS.js +1 -2
- package/dist/subpaths/Base.js +1 -2
- package/dist/subpaths/DIAGNOSTICS.js +1 -2
- package/dist/subpaths/DRAG_MODES.js +1 -2
- package/dist/subpaths/EVENTS.js +1 -2
- package/dist/subpaths/MOUNT_ATTRIBUTE.js +1 -2
- package/dist/subpaths/SWAP_MODES.js +1 -2
- package/dist/subpaths/children.js +1 -2
- package/dist/subpaths/component.js +1 -2
- package/dist/subpaths/createContext.js +1 -2
- package/dist/subpaths/createFallbackProvider.js +1 -2
- package/dist/subpaths/createGroup.js +1 -2
- package/dist/subpaths/createLocalStorage.js +1 -2
- package/dist/subpaths/createMemoryStorageProvider.js +1 -2
- package/dist/subpaths/createService.js +1 -2
- package/dist/subpaths/createServiceMixin.js +1 -2
- package/dist/subpaths/createSessionStorage.js +1 -2
- package/dist/subpaths/createStorage.js +1 -2
- package/dist/subpaths/createUrlSearchParamsInHashProvider.js +1 -2
- package/dist/subpaths/createUrlSearchParamsInHashStorage.js +1 -2
- package/dist/subpaths/createUrlSearchParamsProvider.js +1 -2
- package/dist/subpaths/createUrlSearchParamsStorage.js +1 -2
- package/dist/subpaths/defaultScheduler.js +1 -2
- package/dist/subpaths/defineManifest.js +1 -2
- package/dist/subpaths/domUpdate.js +1 -2
- package/dist/subpaths/emitExtendable.js +1 -2
- package/dist/subpaths/fromMetaGlob.js +1 -2
- package/dist/subpaths/fromWebpackContext.js +1 -2
- package/dist/subpaths/getBreakpoints.js +1 -2
- package/dist/subpaths/getInstance.js +1 -2
- package/dist/subpaths/getInstances.js +1 -2
- package/dist/subpaths/getMountedInstances.js +1 -2
- package/dist/subpaths/getUnmountedInstances.js +1 -2
- package/dist/subpaths/inject.js +1 -2
- package/dist/subpaths/injectContext.js +1 -2
- package/dist/subpaths/injectContextSync.js +1 -2
- package/dist/subpaths/jsonSerializer.js +1 -2
- package/dist/subpaths/localStorageProvider.js +1 -2
- package/dist/subpaths/memoryStorageProvider.js +1 -2
- package/dist/subpaths/namespaceQualifier.js +1 -2
- package/dist/subpaths/nextFrame.js +1 -2
- package/dist/subpaths/on.js +1 -2
- package/dist/subpaths/perTarget.js +1 -2
- package/dist/subpaths/provide.js +1 -2
- package/dist/subpaths/provideContext.js +1 -2
- package/dist/subpaths/provideRootContext.js +1 -2
- package/dist/subpaths/read.js +1 -2
- package/dist/subpaths/registerComponent.js +1 -2
- package/dist/subpaths/registerComponents.js +1 -2
- package/dist/subpaths/registerManifest.js +1 -2
- package/dist/subpaths/reportDiagnostic.js +1 -2
- package/dist/subpaths/sessionStorageProvider.js +1 -2
- package/dist/subpaths/setBreakpoints.js +1 -2
- package/dist/subpaths/signal.js +1 -2
- package/dist/subpaths/subscribeContext.js +1 -2
- package/dist/subpaths/swap.js +1 -2
- package/dist/subpaths/toggle.js +1 -2
- package/dist/subpaths/until.js +1 -2
- package/dist/subpaths/urlSearchParamsInHashProvider.js +1 -2
- package/dist/subpaths/urlSearchParamsProvider.js +1 -2
- package/dist/subpaths/useBreakpoint.js +1 -2
- package/dist/subpaths/useDrag.js +1 -2
- package/dist/subpaths/useInView.js +1 -2
- package/dist/subpaths/useKey.js +1 -2
- package/dist/subpaths/useMediaQuery.js +1 -2
- package/dist/subpaths/useMutation.js +1 -2
- package/dist/subpaths/usePointer.js +1 -2
- package/dist/subpaths/usePrefersReducedMotion.js +1 -2
- package/dist/subpaths/useRaf.js +1 -2
- package/dist/subpaths/useResize.js +1 -2
- package/dist/subpaths/useScroll.js +1 -2
- package/dist/subpaths/useScrollProgress.js +1 -2
- package/dist/subpaths/useWindowScroll.js +1 -2
- package/dist/subpaths/useWindowSize.js +1 -2
- package/dist/subpaths/utils/DEFAULT_DAMP_FACTOR.js +1 -2
- package/dist/subpaths/utils/INERTIA_FRAME.js +1 -2
- package/dist/subpaths/utils/MAX_SPRING_RATIO.js +1 -2
- package/dist/subpaths/utils/SCROLL_ALIGNMENTS.js +1 -2
- package/dist/subpaths/utils/SCROLL_AXES.js +1 -2
- package/dist/subpaths/utils/TRANSFORM_PROPS.js +1 -2
- package/dist/subpaths/utils/TRANSITION_OPTIONS.js +1 -2
- package/dist/subpaths/utils/camelCase.js +1 -2
- package/dist/subpaths/utils/capitalize.js +1 -2
- package/dist/subpaths/utils/clamp.js +1 -2
- package/dist/subpaths/utils/clamp01.js +1 -2
- package/dist/subpaths/utils/clampDampFactor.js +1 -2
- package/dist/subpaths/utils/createEaseInOut.js +1 -2
- package/dist/subpaths/utils/createEaseOut.js +1 -2
- package/dist/subpaths/utils/createElement.js +1 -2
- package/dist/subpaths/utils/createRange.js +1 -2
- package/dist/subpaths/utils/damp.js +1 -2
- package/dist/subpaths/utils/debounce.js +1 -2
- package/dist/subpaths/utils/decayOver.js +1 -2
- package/dist/subpaths/utils/deepmerge.js +1 -2
- package/dist/subpaths/utils/easeInCirc.js +1 -2
- package/dist/subpaths/utils/easeInCubic.js +1 -2
- package/dist/subpaths/utils/easeInExpo.js +1 -2
- package/dist/subpaths/utils/easeInOutCirc.js +1 -2
- package/dist/subpaths/utils/easeInOutCubic.js +1 -2
- package/dist/subpaths/utils/easeInOutExpo.js +1 -2
- package/dist/subpaths/utils/easeInOutQuad.js +1 -2
- package/dist/subpaths/utils/easeInOutQuart.js +1 -2
- package/dist/subpaths/utils/easeInOutQuint.js +1 -2
- package/dist/subpaths/utils/easeInOutSine.js +1 -2
- package/dist/subpaths/utils/easeInQuad.js +1 -2
- package/dist/subpaths/utils/easeInQuart.js +1 -2
- package/dist/subpaths/utils/easeInQuint.js +1 -2
- package/dist/subpaths/utils/easeInSine.js +1 -2
- package/dist/subpaths/utils/easeLinear.js +1 -2
- package/dist/subpaths/utils/easeOutCirc.js +1 -2
- package/dist/subpaths/utils/easeOutCubic.js +1 -2
- package/dist/subpaths/utils/easeOutExpo.js +1 -2
- package/dist/subpaths/utils/easeOutQuad.js +1 -2
- package/dist/subpaths/utils/easeOutQuart.js +1 -2
- package/dist/subpaths/utils/easeOutQuint.js +1 -2
- package/dist/subpaths/utils/easeOutSine.js +1 -2
- package/dist/subpaths/utils/enterTransition.js +1 -2
- package/dist/subpaths/utils/fold.js +1 -2
- package/dist/subpaths/utils/getOffsetSizes.js +1 -2
- package/dist/subpaths/utils/historyPush.js +1 -2
- package/dist/subpaths/utils/historyReplace.js +1 -2
- package/dist/subpaths/utils/inertiaDecay.js +1 -2
- package/dist/subpaths/utils/inertiaFinalValue.js +1 -2
- package/dist/subpaths/utils/inertiaStep.js +1 -2
- package/dist/subpaths/utils/inertiaTimeConstant.js +1 -2
- package/dist/subpaths/utils/isBoolean.js +1 -2
- package/dist/subpaths/utils/isDefined.js +1 -2
- package/dist/subpaths/utils/isFunction.js +1 -2
- package/dist/subpaths/utils/isNull.js +1 -2
- package/dist/subpaths/utils/isNumber.js +1 -2
- package/dist/subpaths/utils/isObject.js +1 -2
- package/dist/subpaths/utils/isString.js +1 -2
- package/dist/subpaths/utils/kebabCase.js +1 -2
- package/dist/subpaths/utils/leaveTransition.js +1 -2
- package/dist/subpaths/utils/lerp.js +1 -2
- package/dist/subpaths/utils/loadImage.js +1 -2
- package/dist/subpaths/utils/loadLink.js +1 -2
- package/dist/subpaths/utils/loadScript.js +1 -2
- package/dist/subpaths/utils/lockScroll.js +1 -2
- package/dist/subpaths/utils/lowerCase.js +1 -2
- package/dist/subpaths/utils/map.js +1 -2
- package/dist/subpaths/utils/matrix.js +1 -2
- package/dist/subpaths/utils/mean.js +1 -2
- package/dist/subpaths/utils/memo.js +1 -2
- package/dist/subpaths/utils/noop.js +1 -2
- package/dist/subpaths/utils/noopValue.js +1 -2
- package/dist/subpaths/utils/objectToURLSearchParams.js +1 -2
- package/dist/subpaths/utils/pascalCase.js +1 -2
- package/dist/subpaths/utils/random.js +1 -2
- package/dist/subpaths/utils/randomInt.js +1 -2
- package/dist/subpaths/utils/randomItem.js +1 -2
- package/dist/subpaths/utils/round.js +1 -2
- package/dist/subpaths/utils/saveActiveElement.js +1 -2
- package/dist/subpaths/utils/scrollPosition.js +1 -2
- package/dist/subpaths/utils/scrollTo.js +1 -2
- package/dist/subpaths/utils/selectorFor.js +1 -2
- package/dist/subpaths/utils/setClassesOrStyles.js +1 -2
- package/dist/subpaths/utils/smoothTo.js +1 -2
- package/dist/subpaths/utils/snakeCase.js +1 -2
- package/dist/subpaths/utils/spring.js +1 -2
- package/dist/subpaths/utils/throttle.js +1 -2
- package/dist/subpaths/utils/transform.js +1 -2
- package/dist/subpaths/utils/transition.js +1 -2
- package/dist/subpaths/utils/trapFocus.js +1 -2
- package/dist/subpaths/utils/untrapFocus.js +1 -2
- package/dist/subpaths/utils/upperCase.js +1 -2
- package/dist/subpaths/utils/wait.js +1 -2
- package/dist/subpaths/utils/withLeadingCharacters.js +1 -2
- package/dist/subpaths/utils/withLeadingSlash.js +1 -2
- package/dist/subpaths/utils/withTrailingCharacters.js +1 -2
- package/dist/subpaths/utils/withTrailingSlash.js +1 -2
- package/dist/subpaths/utils/withoutLeadingCharacters.js +1 -2
- package/dist/subpaths/utils/withoutLeadingCharactersRecursive.js +1 -2
- package/dist/subpaths/utils/withoutLeadingSlash.js +1 -2
- package/dist/subpaths/utils/withoutTrailingCharacters.js +1 -2
- package/dist/subpaths/utils/withoutTrailingCharactersRecursive.js +1 -2
- package/dist/subpaths/utils/withoutTrailingSlash.js +1 -2
- package/dist/subpaths/utils/wrap.js +1 -2
- package/dist/subpaths/viewTransition.js +1 -2
- package/dist/subpaths/warn.js +1 -2
- package/dist/subpaths/watchAttributeNamespace.js +1 -2
- package/dist/subpaths/watchAttributes.js +1 -2
- package/dist/subpaths/whenDOMSettled.js +1 -2
- package/dist/subpaths/withDrag.js +1 -2
- package/dist/subpaths/withInView.js +1 -2
- package/dist/subpaths/withKey.js +1 -2
- package/dist/subpaths/withMutation.js +1 -2
- package/dist/subpaths/withPointer.js +1 -2
- package/dist/subpaths/withRaf.js +1 -2
- package/dist/subpaths/withResize.js +1 -2
- package/dist/subpaths/withScroll.js +1 -2
- package/dist/subpaths/withScrollProgress.js +1 -2
- package/dist/subpaths/write.js +1 -2
- package/dist/swap.d.ts +0 -2
- package/dist/swap.js +1 -2
- package/dist/test/index.d.ts +0 -2
- package/dist/test/index.js +1 -2
- package/dist/utils/deepmerge.d.ts +0 -2
- package/dist/utils/deepmerge.js +1 -2
- package/dist/utils/dom.d.ts +0 -2
- package/dist/utils/dom.js +1 -2
- package/dist/utils/easings.d.ts +0 -2
- package/dist/utils/easings.js +1 -2
- package/dist/utils/focus.d.ts +0 -2
- package/dist/utils/focus.js +1 -2
- package/dist/utils/history.d.ts +0 -2
- package/dist/utils/history.js +1 -2
- package/dist/utils/is.d.ts +0 -2
- package/dist/utils/is.js +1 -2
- package/dist/utils/load.d.ts +0 -2
- package/dist/utils/load.js +1 -2
- package/dist/utils/maths.d.ts +0 -2
- package/dist/utils/maths.js +1 -2
- package/dist/utils/memo.d.ts +0 -2
- package/dist/utils/memo.js +1 -2
- package/dist/utils/noop.d.ts +0 -2
- package/dist/utils/noop.js +1 -2
- package/dist/utils/random.d.ts +0 -2
- package/dist/utils/random.js +1 -2
- package/dist/utils/scroll-lock.d.ts +0 -2
- package/dist/utils/scroll-lock.js +1 -2
- package/dist/utils/scrollTo.d.ts +0 -2
- package/dist/utils/scrollTo.js +1 -2
- package/dist/utils/selectors.d.ts +0 -2
- package/dist/utils/selectors.js +1 -2
- package/dist/utils/smoothTo.d.ts +0 -2
- package/dist/utils/smoothTo.js +1 -2
- package/dist/utils/strings.d.ts +0 -2
- package/dist/utils/strings.js +1 -2
- package/dist/utils/timing.d.ts +0 -2
- package/dist/utils/timing.js +1 -2
- package/dist/utils/transform.d.ts +0 -2
- package/dist/utils/transform.js +1 -2
- package/dist/utils/transition.d.ts +0 -2
- package/dist/utils/transition.js +1 -2
- package/dist/viewTransition.d.ts +0 -2
- package/dist/viewTransition.js +1 -2
- package/package.json +6 -3
- package/skills/studiometa-js-toolkit/SKILL.md +87 -0
- package/skills/studiometa-js-toolkit/references/api/configuration.md +169 -0
- package/skills/studiometa-js-toolkit/references/api/context/createContext.md +46 -0
- package/skills/studiometa-js-toolkit/references/api/context/createGroup.md +67 -0
- package/skills/studiometa-js-toolkit/references/api/context/index.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/context/injectContext.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/context/injectContextSync.md +44 -0
- package/skills/studiometa-js-toolkit/references/api/context/provideContext.md +61 -0
- package/skills/studiometa-js-toolkit/references/api/context/provideRootContext.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/context/signal.md +85 -0
- package/skills/studiometa-js-toolkit/references/api/context/subscribeContext.md +71 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/children.md +92 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/component.md +75 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/index.md +41 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/inject.md +73 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/on.md +149 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/provide.md +77 -0
- package/skills/studiometa-js-toolkit/references/api/decorators/read-write.md +93 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/DIAGNOSTICS.md +137 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/EVENTS.md +45 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/index.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/reportDiagnostic.md +67 -0
- package/skills/studiometa-js-toolkit/references/api/diagnostics/warn.md +54 -0
- package/skills/studiometa-js-toolkit/references/api/dom/breakpoints.md +81 -0
- package/skills/studiometa-js-toolkit/references/api/dom/domUpdate.md +70 -0
- package/skills/studiometa-js-toolkit/references/api/dom/emitExtendable.md +68 -0
- package/skills/studiometa-js-toolkit/references/api/dom/index.md +26 -0
- package/skills/studiometa-js-toolkit/references/api/dom/swap.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/dom/watchAttributeNamespace.md +96 -0
- package/skills/studiometa-js-toolkit/references/api/dom/watchAttributes.md +56 -0
- package/skills/studiometa-js-toolkit/references/api/dom/whenDOMSettled.md +41 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-component.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-mount.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-option.md +106 -0
- package/skills/studiometa-js-toolkit/references/api/html/data-ref.md +63 -0
- package/skills/studiometa-js-toolkit/references/api/html/index.md +32 -0
- package/skills/studiometa-js-toolkit/references/api/index.md +73 -0
- package/skills/studiometa-js-toolkit/references/api/instance-events.md +75 -0
- package/skills/studiometa-js-toolkit/references/api/instance-methods.md +267 -0
- package/skills/studiometa-js-toolkit/references/api/instance-properties.md +90 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-events.md +149 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-lifecycle.md +90 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-options.md +96 -0
- package/skills/studiometa-js-toolkit/references/api/methods-hooks-services.md +164 -0
- package/skills/studiometa-js-toolkit/references/api/registry/defineManifest.md +57 -0
- package/skills/studiometa-js-toolkit/references/api/registry/fromMetaGlob.md +33 -0
- package/skills/studiometa-js-toolkit/references/api/registry/fromWebpackContext.md +37 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getInstance.md +52 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getInstances.md +48 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getMountedInstances.md +39 -0
- package/skills/studiometa-js-toolkit/references/api/registry/getUnmountedInstances.md +46 -0
- package/skills/studiometa-js-toolkit/references/api/registry/index.md +49 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerComponent.md +93 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerComponents.md +37 -0
- package/skills/studiometa-js-toolkit/references/api/registry/registerManifest.md +72 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/defaultScheduler.md +104 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/index.md +27 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/nextFrame.md +31 -0
- package/skills/studiometa-js-toolkit/references/api/scheduler/viewTransition.md +53 -0
- package/skills/studiometa-js-toolkit/references/api/services/createService.md +95 -0
- package/skills/studiometa-js-toolkit/references/api/services/createServiceMixin.md +81 -0
- package/skills/studiometa-js-toolkit/references/api/services/index.md +94 -0
- package/skills/studiometa-js-toolkit/references/api/services/mixins.md +148 -0
- package/skills/studiometa-js-toolkit/references/api/services/perTarget.md +65 -0
- package/skills/studiometa-js-toolkit/references/api/services/toggle.md +80 -0
- package/skills/studiometa-js-toolkit/references/api/services/until.md +44 -0
- package/skills/studiometa-js-toolkit/references/api/services/useBreakpoint.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/services/useDrag.md +119 -0
- package/skills/studiometa-js-toolkit/references/api/services/useInView.md +64 -0
- package/skills/studiometa-js-toolkit/references/api/services/useKey.md +105 -0
- package/skills/studiometa-js-toolkit/references/api/services/useMediaQuery.md +45 -0
- package/skills/studiometa-js-toolkit/references/api/services/useMutation.md +69 -0
- package/skills/studiometa-js-toolkit/references/api/services/usePointer.md +91 -0
- package/skills/studiometa-js-toolkit/references/api/services/usePrefersReducedMotion.md +42 -0
- package/skills/studiometa-js-toolkit/references/api/services/useRaf.md +91 -0
- package/skills/studiometa-js-toolkit/references/api/services/useResize.md +60 -0
- package/skills/studiometa-js-toolkit/references/api/services/useScroll.md +88 -0
- package/skills/studiometa-js-toolkit/references/api/services/useScrollProgress.md +88 -0
- package/skills/studiometa-js-toolkit/references/api/services/useWindowScroll.md +25 -0
- package/skills/studiometa-js-toolkit/references/api/services/useWindowSize.md +25 -0
- package/skills/studiometa-js-toolkit/references/api/storage/createStorage.md +126 -0
- package/skills/studiometa-js-toolkit/references/api/storage/index.md +33 -0
- package/skills/studiometa-js-toolkit/references/api/storage/presets.md +58 -0
- package/skills/studiometa-js-toolkit/references/api/storage/providers.md +109 -0
- package/skills/studiometa-js-toolkit/references/api/test/index.md +214 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/attribute-grammar.md +93 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/mutation-engine.md +71 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/philosophy.md +78 -0
- package/skills/studiometa-js-toolkit/references/guide/concepts/the-registry.md +110 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/autoloading.md +104 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/handling-diagnostics.md +104 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/mount-strategies.md +95 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/scheduling-work.md +124 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/sharing-state.md +218 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/swapping-content.md +92 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/testing-components.md +137 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/typing-components.md +190 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/using-decorators.md +168 -0
- package/skills/studiometa-js-toolkit/references/guide/going-further/using-storage.md +125 -0
- package/skills/studiometa-js-toolkit/references/guide/index.md +163 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/installation.md +144 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/lifecycle-hooks.md +174 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-components.md +229 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-options.md +235 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/managing-refs.md +174 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/using-services.md +218 -0
- package/skills/studiometa-js-toolkit/references/guide/introduction/working-with-events.md +251 -0
- package/skills/studiometa-js-toolkit/references/guide/migration/v3-to-v4.md +373 -0
- package/skills/studiometa-js-toolkit/references/utils/css.md +98 -0
- package/skills/studiometa-js-toolkit/references/utils/dom.md +54 -0
- package/skills/studiometa-js-toolkit/references/utils/easings.md +217 -0
- package/skills/studiometa-js-toolkit/references/utils/focus.md +84 -0
- package/skills/studiometa-js-toolkit/references/utils/history.md +69 -0
- package/skills/studiometa-js-toolkit/references/utils/index.md +53 -0
- package/skills/studiometa-js-toolkit/references/utils/is.md +84 -0
- package/skills/studiometa-js-toolkit/references/utils/load.md +59 -0
- package/skills/studiometa-js-toolkit/references/utils/math.md +129 -0
- package/skills/studiometa-js-toolkit/references/utils/motion.md +218 -0
- package/skills/studiometa-js-toolkit/references/utils/objects.md +68 -0
- package/skills/studiometa-js-toolkit/references/utils/scroll.md +128 -0
- package/skills/studiometa-js-toolkit/references/utils/strings.md +176 -0
- package/skills/studiometa-js-toolkit/references/utils/timing.md +111 -0
- package/skills/studiometa-js-toolkit/references/utils/transitions.md +122 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# The attribute grammar
|
|
2
|
+
|
|
3
|
+
Every attribute the framework reads has one shape, and one module owns it:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
data-<namespace>[:<qualifier>[.<part>…]]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## A namespace is a whole name
|
|
10
|
+
|
|
11
|
+
There are two kinds.
|
|
12
|
+
|
|
13
|
+
**A fixed namespace is written in a module** — `data-component`, `data-mount`, `data-ref`, and in `@studiometa/ui` `data-on`, `data-track`, `data-bind`.
|
|
14
|
+
|
|
15
|
+
**A generated namespace comes from a declaration.** Every declared option owns the one built for it, so `columns` owns `data-option-columns`, and `data-option-` is a namespace _family_ rather than a namespace.
|
|
16
|
+
|
|
17
|
+
An option's name is therefore **inside** its namespace, never a qualifier of a shared one: `data-option-columns:s`, never `data-option:columns:s`.
|
|
18
|
+
|
|
19
|
+
## The colon has one meaning
|
|
20
|
+
|
|
21
|
+
It selects one member of the vocabulary the namespace declares.
|
|
22
|
+
|
|
23
|
+
`data-option-columns:s` and `data-on:click` are not two meanings of the separator. They differ in what the _namespace_ is — one already-declared option against an open family of bindings — and in both cases the colon picks one member.
|
|
24
|
+
|
|
25
|
+
So **an attribute the framework reads holds at most one colon**, which is a rule you can check, and `attributes.spec.ts` does.
|
|
26
|
+
|
|
27
|
+
`data-on:click:s` is not an attribute. Responsiveness belongs to declared options, the only vocabulary that is finite, ordered, and has a value to resolve through a cascade.
|
|
28
|
+
|
|
29
|
+
## A dot splits the qualifier, and core reads none of it
|
|
30
|
+
|
|
31
|
+
Whether the first part names what a binding writes to (`data-bind:prop.value`) or modifies how it fires (`data-on:click.prevent`) is the business of whoever declared the namespace.
|
|
32
|
+
|
|
33
|
+
Core reads the qualifier's **head** only, to check it against a vocabulary the caller handed over, and never past it.
|
|
34
|
+
|
|
35
|
+
> **Core owns when a declaration is re-parsed and how the attribute is observed. The namespace's owner owns what the string means.**
|
|
36
|
+
|
|
37
|
+
## The kind of namespace decides the mechanism
|
|
38
|
+
|
|
39
|
+
What matters is whether the _whole set of names_ can be listed in advance — not whether the qualifier vocabulary is finite.
|
|
40
|
+
|
|
41
|
+
| Namespace | Names | Mechanism |
|
|
42
|
+
| ----------------------- | ------------------------------------------- | --------------------------------------- |
|
|
43
|
+
| `data-option-columns` | `attribute × breakpoint` — enumerable | registered in the one `attributeFilter` |
|
|
44
|
+
| `data-component` | fixed plus one per breakpoint — enumerable | registered in the one `attributeFilter` |
|
|
45
|
+
| `data-on`, `data-track` | any DOM event — open | `watchAttributeNamespace()` |
|
|
46
|
+
| `data-bind` | finite head, open name — **not** enumerable | `watchAttributeNamespace()` |
|
|
47
|
+
|
|
48
|
+
A generated namespace is enumerable _because_ it comes from a declaration, which is why the page-wide filter stays precise and no option costs a second observer.
|
|
49
|
+
|
|
50
|
+
`data-bind` shows why "finite or open" is the wrong axis on its own: its binding types are finite, but the class, property or attribute name after the dot is not — so the names cannot be listed and the namespace must be watched. Validating a finite head is an **independent** capability, available to a watched namespace and a registered one alike.
|
|
51
|
+
|
|
52
|
+
## The two escape hatches
|
|
53
|
+
|
|
54
|
+
`attributeFilter` takes exact names and the DOM has no wildcard, so the engine cannot see an attribute the framework cannot name.
|
|
55
|
+
|
|
56
|
+
### `watchAttributes(element, callback)`
|
|
57
|
+
|
|
58
|
+
Observes **every** attribute of that element, through a second, unfiltered observer. The page pays for the elements that ask.
|
|
59
|
+
|
|
60
|
+
- **The caller owns it.** It returns one idempotent cleanup and knows nothing about `Base`.
|
|
61
|
+
- **The records join the shared queue**, so they are drained wherever the engine drains its own, `whenDOMSettled()` included.
|
|
62
|
+
- **A callback runs after the framework work of the batch.**
|
|
63
|
+
- **Changes are coalesced**, with the rule of `option<Name>Changed()`.
|
|
64
|
+
- **The payload is one object**: `{ name, value, previousValue }`, with raw attribute strings and `null` for an absent attribute. It covers the element's whole attribute set, framework names included, so a caller narrows by prefix.
|
|
65
|
+
|
|
66
|
+
See [`watchAttributes()`](../../api/dom/watchAttributes.md).
|
|
67
|
+
|
|
68
|
+
### `watchAttributeNamespace(element, namespace, bind, options?)`
|
|
69
|
+
|
|
70
|
+
The mechanism for a namespace whose names cannot be enumerated. Declare the prefix, hand over a binder, and get the per-element observation, the keyed bindings and the teardown.
|
|
71
|
+
|
|
72
|
+
- **One binding per attribute, keyed by the name that produced it.** That is what lets one code path cover all three shapes a change takes: **added** attaches with nothing to release, **changed** releases then attaches, **removed** releases with nothing to attach. A memoised parse cannot express the middle one — and rewriting an attribute in place is not hypothetical, since `swap({ mode: 'morph' })` does it.
|
|
73
|
+
- **The binder returns that binding's release**, or nothing when the declaration produced no binding, so a malformed value costs no bookkeeping.
|
|
74
|
+
- **Declaration order survives a rewrite.** The bindings are a `Map` keyed by attribute, and `set` on a key already there keeps its position.
|
|
75
|
+
- **An optional finite vocabulary validates the qualifier's head.** Given one, an unknown head warns once per element and per name with `attribute.unknown-qualifier` and binds nothing — so `data-bind:prpo.value` stops being an attribute that silently does nothing. Omitted, the vocabulary is open and anything binds, which is the only honest answer for `data-on`.
|
|
76
|
+
- **It is built on `watchAttributes()`**, so `whenDOMSettled()`, and therefore `swap()`, covers a namespaced declaration the way it covers a mount.
|
|
77
|
+
- `Base` has no wrapper and owns no cleanup. A component calls it from `mounted()` and returns its cleanup.
|
|
78
|
+
|
|
79
|
+
See [`watchAttributeNamespace()`](../../api/dom/watchAttributeNamespace.md).
|
|
80
|
+
|
|
81
|
+
To watch a subtree, character data, or a node the framework does not know, use [`useMutation()`](../../api/services/useMutation.md).
|
|
82
|
+
|
|
83
|
+
## The one module that owns the vocabulary
|
|
84
|
+
|
|
85
|
+
`attributes.ts` owns every name in the filter and every test against one: `data-component`, `data-mount`, `data-ref`, the `data-option-` prefix with `optionAttributeFor()` and `isOptionAttribute()`, the responsive separator, and the coalescing rule. **It imports nothing from core.**
|
|
86
|
+
|
|
87
|
+
`component-declarations.ts` consumes that vocabulary and reads the DOM through the responsive cascade.
|
|
88
|
+
|
|
89
|
+
## The coalescing rule, written once
|
|
90
|
+
|
|
91
|
+
Several writes to one attribute in a batch give **one** change, from the value before the first write to the value at the end of the batch. A write that ends where it started is not a change.
|
|
92
|
+
|
|
93
|
+
`rememberPreviousValue()` and `isNetChange()` hold the rule. The comparison uses **raw strings**, so a breakpoint crossing and an attribute write are the same kind of event.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# The mutation engine
|
|
2
|
+
|
|
3
|
+
One internal engine owns **one** MutationObserver, for component discovery, lifecycle, mount strategies, ref invalidation and declared options.
|
|
4
|
+
|
|
5
|
+
## What it watches
|
|
6
|
+
|
|
7
|
+
Its `attributeFilter` holds:
|
|
8
|
+
|
|
9
|
+
- the fixed framework attributes — `data-component`, `data-mount`, `data-ref`;
|
|
10
|
+
- the exact responsive `data-component:<breakpoint>` spellings of the configured breakpoints;
|
|
11
|
+
- the option names of every registered config, and the negated spelling of each boolean option, with one scoped spelling per breakpoint.
|
|
12
|
+
|
|
13
|
+
Writes to `class`, `style` and ARIA attributes create **no record**. That is the point of an exact filter: the attributes a page churns are not the attributes the framework reads.
|
|
14
|
+
|
|
15
|
+
**The `attributeFilter` and the relevance test of the engine are one set.** A record is relevant if and only if it names an attribute the observer holds. A change to that set drains the records of the previous filter first.
|
|
16
|
+
|
|
17
|
+
## The fixed order of a batch
|
|
18
|
+
|
|
19
|
+
The engine snapshots the membership of a removed subtree when the records enter its queue, then processes each batch in a fixed order:
|
|
20
|
+
|
|
21
|
+
1. **unmount** removed subtrees and dispose their strategies;
|
|
22
|
+
2. **reconcile** the final plain and scoped `data-component` attributes, and `data-mount`;
|
|
23
|
+
3. **deliver** coalesced declared-option changes to the mounted instances that stay;
|
|
24
|
+
4. **scan** added subtrees once and schedule their registered component tokens;
|
|
25
|
+
5. **report** coalesced attribute changes to the elements that asked to watch them.
|
|
26
|
+
|
|
27
|
+
Teardown before setup, and the elements that stay hear about their options before anything new is built. Step 5 is last, which is why a component that stops its watcher during the same batch in which its own declaration is withdrawn hears nothing about the attribute change.
|
|
28
|
+
|
|
29
|
+
## What each transition means
|
|
30
|
+
|
|
31
|
+
| Transition | Effect |
|
|
32
|
+
| --------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
33
|
+
| the element is **disconnected** | `$unmount()`, and the instance stays on its element for a later insertion |
|
|
34
|
+
| a component token is **removed** from a connected element | `$unmount()`, then the instance is dropped from the element |
|
|
35
|
+
| a breakpoint **withdraws** a declaration | the same: unmount, then drop |
|
|
36
|
+
| the node is **moved** | one unmount and one mount cycle, same identity |
|
|
37
|
+
|
|
38
|
+
The token later declared again gives a **new** instance, because the DOM no longer declared that identity.
|
|
39
|
+
|
|
40
|
+
## Ref invalidation
|
|
41
|
+
|
|
42
|
+
Ref lookups are cached, and the cache is invalidated by a counter this observer increases. Reading that counter drains the pending records with `takeRecords()`, so a read is current even inside the same task as the mutation. Detached elements are never cached.
|
|
43
|
+
|
|
44
|
+
That is the whole implementation of "refs are live", and it is why there is no `$update()`.
|
|
45
|
+
|
|
46
|
+
## `whenDOMSettled()`
|
|
47
|
+
|
|
48
|
+
It is the completion boundary for morphing, fetch updates and breakpoint crossings. It:
|
|
49
|
+
|
|
50
|
+
- drains the pending records;
|
|
51
|
+
- follows the mutation chains of eager lifecycle work, so markup a `mounted()` inserts is covered too;
|
|
52
|
+
- resolves after the eager mounts and the teardown.
|
|
53
|
+
|
|
54
|
+
It does **not** wait for visibility, interaction, idle or media conditions, and it does **not** await the promises returned by `mounted()`. An eager lazy component _is_ covered: the import promise joins the lifecycle-work set for the eager trigger only.
|
|
55
|
+
|
|
56
|
+
## The lanes it runs in
|
|
57
|
+
|
|
58
|
+
Framework work runs through the scheduler's **background** lane: a 5 ms slice per turn, posted through `scheduler.postTask({ priority: 'background' })` with a `MessageChannel` fallback. Background work alone never requests an animation frame.
|
|
59
|
+
|
|
60
|
+
Breakpoint work runs there too, so `whenDOMSettled()` includes the teardown, import and mount work of a crossing.
|
|
61
|
+
|
|
62
|
+
See [The scheduler](../going-further/scheduling-work.md).
|
|
63
|
+
|
|
64
|
+
## Watching something else
|
|
65
|
+
|
|
66
|
+
The engine sees only what it can name. Two opt-ins cover the rest, and both are described in [The attribute grammar](attribute-grammar.md):
|
|
67
|
+
|
|
68
|
+
- [`watchAttributes()`](../../api/dom/watchAttributes.md) — every attribute of one element, through a second observer, with the records joining the same queue.
|
|
69
|
+
- [`watchAttributeNamespace()`](../../api/dom/watchAttributeNamespace.md) — a namespace whose names cannot be enumerated, with keyed bindings and per-declaration teardown.
|
|
70
|
+
|
|
71
|
+
For a subtree, character data, or a node the framework does not know, [`useMutation()`](../../api/services/useMutation.md) is a general `MutationObserver` as a service. It delivers on the platform's timing; a subscriber that needs the framework's order awaits `whenDOMSettled()` in its callback.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Philosophy
|
|
2
|
+
|
|
3
|
+
> **The registry is the framework. The DOM is the component tree.**
|
|
4
|
+
|
|
5
|
+
An instance exists because its element is in the document and its class is registered. Nothing else creates or unmounts an instance. Parent and child are DOM ancestry only, never ownership. Components find each other through queries and events.
|
|
6
|
+
|
|
7
|
+
## Five objectives
|
|
8
|
+
|
|
9
|
+
1. **Components are independent.** No component constructs another.
|
|
10
|
+
2. **One registry.** One map from name to source, and one scheduling algorithm.
|
|
11
|
+
3. **The DOM drives mount and unmount.** One MutationObserver, and the element is the truth.
|
|
12
|
+
4. **Parents listen to child events.** A bubbling `CustomEvent` is the upward channel.
|
|
13
|
+
5. **Children announce their existence to parents.** A mount is an announcement, not a registration.
|
|
14
|
+
|
|
15
|
+
## The three forks
|
|
16
|
+
|
|
17
|
+
| Fork | Decision |
|
|
18
|
+
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| **Mount primitive** | `data-component` and one record-based MutationObserver. No tag names, no arbitrary selectors, no custom elements, no directive system. |
|
|
20
|
+
| **Shared state** | provide/inject in core, with the shape of Vue and the mechanics of the WICG context protocol. `provideRootContext()` covers the page-wide case. |
|
|
21
|
+
| **Child events** | The `on<Child><Event>` method names stay. Delegation resolves them against the names in `config.components`. |
|
|
22
|
+
|
|
23
|
+
Custom elements were considered as the mount and lifecycle primitive and refused. So was a separate directive registry: a behaviour is a component on the one registry, so nothing more is needed.
|
|
24
|
+
|
|
25
|
+
## What was removed, and what replaces it
|
|
26
|
+
|
|
27
|
+
| Removed | Replacement |
|
|
28
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
29
|
+
| `$parent`, `$children`, `$root`, `createApp()` | `$query()`, `$closest()`, `$watchChildren()`, `registerComponent()` |
|
|
30
|
+
| `$update()` | nothing — refs are live |
|
|
31
|
+
| `config.emits` | the `$emits` props type, which leaves no runtime trace |
|
|
32
|
+
| `withExtraConfig()` | a class, since `$config` merges along the prototype chain |
|
|
33
|
+
| `withMountWhenInView` and friends | [mount strategies](../going-further/mount-strategies.md) |
|
|
34
|
+
| `data-load` and `loadStrategy` | one knob: `data-mount` |
|
|
35
|
+
| `withGroup` | `provideRootContext()` and `createGroup()` |
|
|
36
|
+
| `LoadService` | nothing — it was not ported |
|
|
37
|
+
| `domScheduler`, `SmartQueue`, the `RafService` loop | [one scheduler](../going-further/scheduling-work.md) |
|
|
38
|
+
| `EVENTS.error` and its detail types | [one diagnostic protocol](../going-further/handling-diagnostics.md) |
|
|
39
|
+
| `tween` and `animate` | not shipped — a separate `ui-animation` package |
|
|
40
|
+
| the `<tk-name>` tag sugar and arbitrary-selector registrations | `data-component` only |
|
|
41
|
+
|
|
42
|
+
`config.use` and `config.siblings` are not planned.
|
|
43
|
+
|
|
44
|
+
## Why "one" keeps recurring
|
|
45
|
+
|
|
46
|
+
Three subsystems of v3 each had their own copy of the same work. v4 replaces each set with one.
|
|
47
|
+
|
|
48
|
+
**One registry** replaces three mounting systems: the global registry observer, `ChildrenManager` and the autoload loader. A name resolves to one source, and one controller holds the current decision for an element/component pair. The arrival of a lazy class is a _change of source_, which is why an import trigger and a mount trigger are the same code.
|
|
49
|
+
|
|
50
|
+
**One mutation engine** owns one MutationObserver for component discovery, lifecycle, mount strategies, ref invalidation and declared options. Its `attributeFilter` and its relevance test are the same set, so a record is relevant if and only if it names an attribute the observer holds.
|
|
51
|
+
|
|
52
|
+
**One scheduler** is the clock. `RafService` subscribes to the tick instead of owning a loop; the scroll service coalesces into one `read` per frame; the view-transition helper batches within a flush. No service owns a loop.
|
|
53
|
+
|
|
54
|
+
## Sugar is never a requirement
|
|
55
|
+
|
|
56
|
+
Every decorator is a thin wrapper over a function API that works without it, because no engine ships stage-3 decorators. A page loaded from an ESM CDN with no build step keeps `registerComponent`, `$provide`, `$watchChildren`, `$read`, `$write` and the `on<Child><Event>` names.
|
|
57
|
+
|
|
58
|
+
The same principle sets the limit of the sugar. A mixin names **one** hook per class; `on<Event>` names one handler per class. A component whose subscriptions are one per markup declaration has no method to name and no fixed count, so it subscribes itself and returns the release from `mounted()`. Reaching for that deliberately is cheaper than discovering that a hook cannot be dynamic.
|
|
59
|
+
|
|
60
|
+
## Inputs and state are different things
|
|
61
|
+
|
|
62
|
+
An option is an **input**. `$options` is a read-only view whose every property derives its value from the element and the viewport on access. Refs are live for the same reason: the DOM is the source, so reading it is the honest implementation and a cache that has to be refreshed is not.
|
|
63
|
+
|
|
64
|
+
What follows from that: to change what the DOM says, write the attribute — the same statement the markup makes. To keep what the component has worked out, keep a field. The two are never the same value.
|
|
65
|
+
|
|
66
|
+
## Failures are a channel, not a print
|
|
67
|
+
|
|
68
|
+
Everything the framework recovers from is dispatched as one cancelable event before any console output, and nothing in core calls `console.warn()` or `console.error()` directly. Monitoring can read every code and suppress the noise without changing a single framework decision.
|
|
69
|
+
|
|
70
|
+
Failures a **caller** owns stay throws and rejections: decorator misuse, a manifest adapter given the wrong shape, `swap()`, `viewTransition()`. A channel is for what the framework decided to survive.
|
|
71
|
+
|
|
72
|
+
## Read next
|
|
73
|
+
|
|
74
|
+
- [The registry](the-registry.md) — how one map and one controller cover eager, lazy and conditional mounting.
|
|
75
|
+
- [The attribute grammar](attribute-grammar.md) — one shape for every attribute the framework reads.
|
|
76
|
+
- [The mutation engine](mutation-engine.md) — the fixed order of one batch.
|
|
77
|
+
|
|
78
|
+
The full design document and the decision record live in the repository: [DESIGN.md](https://github.com/studiometa/js-toolkit/blob/main/packages/js-toolkit/DESIGN.md) states what v4 does, [RATIONALE.md](https://github.com/studiometa/js-toolkit/blob/main/packages/js-toolkit/RATIONALE.md) states why, which options were refused, and what the measurements are.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# The registry
|
|
2
|
+
|
|
3
|
+
One registry replaces the three mounting systems of v3: the global registry observer, `ChildrenManager` and the autoload loader.
|
|
4
|
+
|
|
5
|
+
## The entry
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
RegistryEntry = {
|
|
9
|
+
name,
|
|
10
|
+
source: constructor | lazy loader (manifest entry),
|
|
11
|
+
mountStrategy, // when to mount each instance
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- `registerComponent(Ctor)` registers an **eager** entry.
|
|
16
|
+
- `registerManifest(…)` registers **lazy** entries in the same map.
|
|
17
|
+
- A thunk in `config.components` becomes a lazy entry under its key.
|
|
18
|
+
|
|
19
|
+
**One name gives one entry**, as with `customElements.define()`. A collision gives a `registry.conflict` warning and the entry is ignored — except for a lazy child declared by several parents, which is the normal case and wins quietly.
|
|
20
|
+
|
|
21
|
+
## The controller
|
|
22
|
+
|
|
23
|
+
**One element and component pair gives one controller.** The controller holds the strategy of the pair and the source it was scheduled against.
|
|
24
|
+
|
|
25
|
+
That single object is what makes eager, lazy and conditional mounting one algorithm:
|
|
26
|
+
|
|
27
|
+
- The arrival of a lazy class is a **change of source**, so the pass that replaces a controller turns a spent import trigger into a mount.
|
|
28
|
+
- A trigger stands down without a teardown of its own: a controller marks itself spent, a spent controller is not the current pair, and so a second trigger is inert. The teardown runs from the ordinary controller replacement.
|
|
29
|
+
- Controller identity guards a queued callback of a disposed strategy.
|
|
30
|
+
|
|
31
|
+
There is no `loadStrategy` and no `data-load`. Deferring the import and deferring the mount are one decision:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
data-mount > manifest entry mountStrategy > config.mountStrategy > 'eager'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What the registry constructs, and what it does not
|
|
38
|
+
|
|
39
|
+
**The registry is the only code that constructs an instance.** `ChildrenManager` is gone and constructs nothing, because it does not exist. Autoload never touches `new`, the instance map, or a mount hook — an import ends in `registerComponent(ComponentClass)` and then the ordinary pipeline runs.
|
|
40
|
+
|
|
41
|
+
`registerComponent()` walks `config.components` in one `registerFamily()` loop, so one call covers a whole tree. The recursive registration of v3's manifest `children` arrays is dead data.
|
|
42
|
+
|
|
43
|
+
## Where the instances live
|
|
44
|
+
|
|
45
|
+
An element publishes its instances under `Symbol.for('@studiometa/js-toolkit/instances')`. It is **not public API** — the four lookups are, and between them they express every read the map answers.
|
|
46
|
+
|
|
47
|
+
In a console, one line reads it:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
$0[Symbol.for('@studiometa/js-toolkit/instances')];
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### The four lookups
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
getMountedInstances('Dialog'); // the live ones
|
|
57
|
+
getInstances('Dialog', section); // every one built in a region
|
|
58
|
+
getUnmountedInstances('Dialog'); // built, then stood down
|
|
59
|
+
getInstance(el, 'Dialog'); // the one on this element, mounted or not
|
|
60
|
+
getInstances(el); // everything on one element
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
They derive the answer from the DOM and keep **no registry of instances**.
|
|
64
|
+
|
|
65
|
+
- **The name says which population it answers.** `getInstances()` returns every instance that exists; `getMountedInstances()` is the safe list to call a method on; `getUnmountedInstances()` is what a reversible `in-view` or `media:` strategy has stood down, plus a construct-then-mount-failure.
|
|
66
|
+
- **A matching element with no instance is skipped, and that is the whole narrowing.** `selectorFor(name)` over-matches on purpose — it lists the responsive spellings of `data-component` too — and the instance-map read is what removes an inactive declaration, because a breakpoint-withdrawn component is destroyed _and_ deleted from the map.
|
|
67
|
+
- **There is no `getMountedInstance`.** The singular returns one object; a caller reads `.$isMounted` on it.
|
|
68
|
+
- `root` is a `ParentNode` and the call is `querySelectorAll`, so an element root searches its **descendants** and never matches itself.
|
|
69
|
+
- The element overload is the only form that reaches a **detached** element, since `querySelectorAll()` does not see one.
|
|
70
|
+
|
|
71
|
+
## Responsive declarations
|
|
72
|
+
|
|
73
|
+
The plain `data-component` token set is always active. One responsive set is added with the spelling of responsive options:
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<div
|
|
77
|
+
data-component="Action Analytics"
|
|
78
|
+
data-component:xxs="MobileMenu MobileSearch"
|
|
79
|
+
data-component:m="DesktopMenu DesktopSearch"></div>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- At the active breakpoint the registry walks from the widest active suffix **down** and takes the first attribute present.
|
|
83
|
+
- That value is the **complete** responsive set. A wider value replaces every lower value; it does not merge. An empty value is a stop: `data-component:s="TabletFeature" data-component:l=""` runs `TabletFeature` at `s` and `m`, and removes it at `l`.
|
|
84
|
+
- The effective declaration is the **union** of the unconditional set and the selected responsive set, without duplicates.
|
|
85
|
+
- A crossing compares that effective set against the element's current state. A shared name keeps its controller and its instance. A name no longer declared is unmounted and dropped from the element, so a crossing back gives a new identity. A new name enters the normal pipeline, so mount strategies, `data-mount`, lazy entries and lifecycle events keep their meaning. An inactive lazy declaration imports nothing.
|
|
86
|
+
- The document observer registers the exact `data-component:<breakpoint>` names and replaces that slice of the filter after `setBreakpoints()`.
|
|
87
|
+
- Connected elements with a scoped declaration share **one** reference-counted `useBreakpoint()` subscription. A page with plain declarations opens none.
|
|
88
|
+
- Breakpoint work runs through the background lane, so `whenDOMSettled()` includes the teardown, import and mount work of a crossing.
|
|
89
|
+
- A suffix naming no configured breakpoint is ignored with one warning. That includes the v3 list syntax `data-component:xxs:xs:s`. There is no range form and no breakpoint-list form.
|
|
90
|
+
|
|
91
|
+
## The matching surface
|
|
92
|
+
|
|
93
|
+
It is smaller than v3's, on purpose. Only plain and configured scoped `data-component` declarations are discovered, with whitespace-separated tokens for several components on one element.
|
|
94
|
+
|
|
95
|
+
Removed: the `<tk-name>` tag sugar, the breakpoint-list suffixes, and the lowercase arbitrary-selector registrations.
|
|
96
|
+
|
|
97
|
+
`data-component` still improves native elements — `<form>`, `<a>`, `<details>` and table markup all take it.
|
|
98
|
+
|
|
99
|
+
## Duplicate copies of the package
|
|
100
|
+
|
|
101
|
+
`shared-runtime.ts` owns `globalThis[Symbol.for('@studiometa/js-toolkit/runtime')]` and gives each subsystem a typed slot with a revision. Independently evaluated copies reuse the canonical `defaultScheduler`, the registry maps and controllers, the DOM mutation observer and queue, the root-context state, the breakpoint state and every built-in service cache.
|
|
102
|
+
|
|
103
|
+
`Base` carries a separate inherited `Symbol.for` brand on its constructor, so family and imported-module resolution recognise a component from another copy. An incompatible root or slot revision throws. This is same-realm coordination only, and a `createService()` or `perTarget()` call of a consumer stays owned by that consumer.
|
|
104
|
+
|
|
105
|
+
## What is not built
|
|
106
|
+
|
|
107
|
+
- **Composing and overriding manifests.** v4 is first-wins-and-warn. An `{ override: true }` option is about five lines; the decision is the expensive part.
|
|
108
|
+
- **A scoped `root`.** The registry is document-wide by construction, and no consumer has asked.
|
|
109
|
+
- **Informational manifest metadata** (`packageName`, `subpath`, `exportName`, `group`, `styles`, `integrations`). It belongs in the output type of the generator, not in core.
|
|
110
|
+
- **A `data-load` compatibility shim.** A page that used `data-load` renames one attribute.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Autoloading
|
|
2
|
+
|
|
3
|
+
A page that declares its components in the markup does not have to import them all up front. Map each `data-component` token to a dynamic import and the registry downloads a chunk when an element needs one.
|
|
4
|
+
|
|
5
|
+
## `registerManifest()`
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { registerManifest } from '@studiometa/js-toolkit';
|
|
9
|
+
|
|
10
|
+
registerManifest({
|
|
11
|
+
Accordion: () => import('./components/Accordion.js'),
|
|
12
|
+
Slider: () => import('./components/Slider.js'),
|
|
13
|
+
Map: { load: () => import('./components/Map.js'), mountStrategy: 'visible' },
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
An entry is either the importer itself, or an object with `load` and an optional `mountStrategy`.
|
|
18
|
+
|
|
19
|
+
- **One name, one entry**, across eager classes and manifests alike. A token an eager class or an earlier manifest owns gives a `manifest.duplicate-token` warning and is ignored.
|
|
20
|
+
- **No dependency and no bundler knowledge.** The value is a function that returns a promise. `import.meta.glob`, `import.meta.webpackContext` and a generated manifest all produce that shape.
|
|
21
|
+
- **The registry stays the only constructor.** The import ends in `registerComponent(ComponentClass)`.
|
|
22
|
+
- **One import per name, one failure report per name.** A failure emits one `component.load-failed` diagnostic and is never retried.
|
|
23
|
+
- **A class whose `config.name` differs from its token** gives a `registry.lazy-name-mismatch` warning.
|
|
24
|
+
- The class is resolved out of the imported module for you, so a hand-written entry is `Slider: () => import('./Slider.js')` with nothing to unwrap.
|
|
25
|
+
|
|
26
|
+
## One knob, not two
|
|
27
|
+
|
|
28
|
+
Deferring the import and deferring the mount are **one decision**:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
data-mount > manifest entry mountStrategy > 'eager'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The manifest entry stands in the middle slot for the `config.mountStrategy` of a class that cannot be read yet. Once the class registers, the chain reads `config.mountStrategy` and the entry is deleted from the map.
|
|
35
|
+
|
|
36
|
+
There is **no `data-load`** and no compatibility shim for it. A page that used `data-load` renames one attribute.
|
|
37
|
+
|
|
38
|
+
### What that buys
|
|
39
|
+
|
|
40
|
+
One scheduling algorithm covers both halves. A name resolves to one source, and one controller holds the current decision of the element/component pair. The arrival of the class is a _change of source_, so the pass that replaces a controller turns a spent import trigger into a mount:
|
|
41
|
+
|
|
42
|
+
- a **one-shot** trigger (`visible`, `idle`, `interaction`) mounts on the import that proved its condition;
|
|
43
|
+
- a **reversible** one (`in-view`, `media:`) is observed again.
|
|
44
|
+
|
|
45
|
+
An unloaded declaration is invisible to `$query()`, `$closest()`, `$watchChildren()` and `getInstances()`, because nothing is constructed at discovery.
|
|
46
|
+
|
|
47
|
+
`whenDOMSettled()` covers an **eager** lazy component: the import promise joins the lifecycle-work set only for the eager trigger, so [`swap()`](../../api/dom/swap.md) waits for download, registration and mount — and still never waits on a viewport, an idle callback, an interaction or a media query.
|
|
48
|
+
|
|
49
|
+
## Generating a manifest from a glob
|
|
50
|
+
|
|
51
|
+
`defineManifest()` turns a bundler glob into a manifest, deriving each token from the path:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import { defineManifest, fromMetaGlob } from '@studiometa/js-toolkit';
|
|
55
|
+
|
|
56
|
+
registerManifest(
|
|
57
|
+
defineManifest({
|
|
58
|
+
modules: fromMetaGlob(import.meta.glob('./components/*/index.js')),
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `index.js` falls back to the parent directory name, so `./components/Slider/index.js` is `Slider`.
|
|
64
|
+
- A package-wide `mountStrategy` emits entry wrappers only when it is not `eager`.
|
|
65
|
+
- Duplicate tokens give a warning and keep the first path.
|
|
66
|
+
|
|
67
|
+
For webpack, [`fromWebpackContext()`](../../api/registry/fromWebpackContext.md) takes an `import.meta.webpackContext` result. Neither adapter adds a bundler dependency — core names none of them.
|
|
68
|
+
|
|
69
|
+
## Lazy children
|
|
70
|
+
|
|
71
|
+
`config.components` takes a dynamic import too, and the key supplies the name:
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
static config = {
|
|
75
|
+
name: 'Accordion',
|
|
76
|
+
components: {
|
|
77
|
+
AccordionItem: () => import('./AccordionItem.js'),
|
|
78
|
+
Icon: IconClass,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`registerComponent()` defers a thunk instead of resolving it, and the value becomes a lazy entry of the same registry under its key. Everything after that is identical to a manifest entry.
|
|
84
|
+
|
|
85
|
+
- **The key supplies the name**, so a lazy child is a name the registry knows with nothing downloaded — and `on<Child><Event>` resolution works on it immediately.
|
|
86
|
+
- **A manifest can declare the parent only.** A child behind a thunk is its own chunk, so a family splits where the author splits it.
|
|
87
|
+
- **First wins, quietly**, unlike `registerManifest()`. Several parents declaring the same lazy child is the normal case.
|
|
88
|
+
- **The entry gets no `mountStrategy` field.** Until the class arrives the chain is `data-mount > eager`; after it, the usual chain reads the merged config, so a lazy child that is a subclass inherits the strategy of its base.
|
|
89
|
+
- A value written with `class` that does not extend `Base` is reported as `component.invalid-family-declaration`, where it is declared.
|
|
90
|
+
|
|
91
|
+
## What v3's autoload did that v4 does not need
|
|
92
|
+
|
|
93
|
+
v3 shipped 1033 source lines of autoload across seven modules. The registry and the mount strategies absorb almost all of it:
|
|
94
|
+
|
|
95
|
+
| v3 | v4 |
|
|
96
|
+
| ------------------------------------------------------ | ------------------------------------------------------------- |
|
|
97
|
+
| `ComponentLoader.start()` discovery observer | the one document observer |
|
|
98
|
+
| the four load triggers of `__schedule()` | `mount-strategies.ts` |
|
|
99
|
+
| per-element and per-record cleanup bookkeeping | one controller map holding both halves |
|
|
100
|
+
| recursive registration of configured children | one `registerFamily()` loop over `config.components` |
|
|
101
|
+
| the `ComponentRecord` state machine | one `Map<string, Promise<void>>` — the promise _is_ the state |
|
|
102
|
+
| `readEagerTokens` and `<meta name="js-toolkit:eager">` | `data-mount` on the element |
|
|
103
|
+
|
|
104
|
+
The `children` arrays of a v3 manifest are dead data.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Diagnostics
|
|
2
|
+
|
|
3
|
+
Everything the framework recovers from is reported on **one** cancelable event, and nothing in core calls `console.warn()` or `console.error()` directly.
|
|
4
|
+
|
|
5
|
+
## The protocol
|
|
6
|
+
|
|
7
|
+
`EVENTS.diagnostic` is `'js-toolkit:diagnostic'`. It carries a `ToolkitDiagnosticDetail`:
|
|
8
|
+
|
|
9
|
+
| Field | Type | Notes |
|
|
10
|
+
| ----------- | ----------------------- | ------------------------------------------------- |
|
|
11
|
+
| `severity` | `'warning' \| 'error'` | |
|
|
12
|
+
| `code` | `ToolkitDiagnosticCode` | a namespaced string from `DIAGNOSTICS` |
|
|
13
|
+
| `message` | `string` | |
|
|
14
|
+
| `component` | `string \| undefined` | the reporting component's name, when there is one |
|
|
15
|
+
| `error` | `unknown` | **required** for `error`, absent for `warning` |
|
|
16
|
+
|
|
17
|
+
Every diagnostic starts on its relevant connected element, or on `document` when there is none, and is dispatched with `{ bubbles: true, composed: true, cancelable: true }`.
|
|
18
|
+
|
|
19
|
+
## Listening
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { DIAGNOSTICS, EVENTS, type ToolkitDiagnosticDetail } from '@studiometa/js-toolkit';
|
|
23
|
+
|
|
24
|
+
declare function monitor(code: string, detail: ToolkitDiagnosticDetail): void;
|
|
25
|
+
document.addEventListener(EVENTS.diagnostic, (rawEvent) => {
|
|
26
|
+
const event = rawEvent as CustomEvent<ToolkitDiagnosticDetail>;
|
|
27
|
+
monitor(event.detail.code, event.detail);
|
|
28
|
+
|
|
29
|
+
if (event.detail.code === DIAGNOSTICS.responsive.unknownBreakpoint) {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Dispatch always happens before the default output.**
|
|
36
|
+
|
|
37
|
+
- An uncancelled **warning** calls `console.warn()` once with exactly `[js-toolkit:<code>] <message>`.
|
|
38
|
+
- An uncancelled **error** calls `reportError(detail.error)` with the original value.
|
|
39
|
+
- `preventDefault()` suppresses that output **only**. It changes no framework decision.
|
|
40
|
+
|
|
41
|
+
## The codes
|
|
42
|
+
|
|
43
|
+
`DIAGNOSTICS` is a deeply frozen object, and `ToolkitDiagnosticCode` is the exact union of its strings:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { DIAGNOSTICS } from '@studiometa/js-toolkit';
|
|
47
|
+
|
|
48
|
+
DIAGNOSTICS.component.loadFailed; // 'component.load-failed'
|
|
49
|
+
DIAGNOSTICS.callback.serviceFailed; // 'callback.service-failed'
|
|
50
|
+
DIAGNOSTICS.protocol.lateRegistration; // 'protocol.late-registration'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See the [full list](../../api/diagnostics/DIAGNOSTICS.md).
|
|
54
|
+
|
|
55
|
+
## Report once, or report and continue
|
|
56
|
+
|
|
57
|
+
| Behaviour | Cases |
|
|
58
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| **Reported exactly once** | recovered load, mount, invalid-strategy and `Base` lifecycle failures |
|
|
60
|
+
| **Report and continue** | isolated signal, context subscription and teardown, attribute watcher, service, scheduler tick and task, DOM-update runner and extendable-event callbacks |
|
|
61
|
+
| **Thrown or rejected** | decorator and manifest-adapter misuse, shared-runtime incompatibility, service startup rollback, caller-owned teardown, `viewTransition()` and `swap()` |
|
|
62
|
+
|
|
63
|
+
A scheduled task also **rejects its own promise** with the same value. Direct, caller-owned failures stay throws: they are the caller's to handle, not a channel's.
|
|
64
|
+
|
|
65
|
+
Warning deduplication is stored in a revisioned shared-runtime slot, keyed by weak owner plus a misuse key, so it works across independently evaluated copies of the package without retaining instances, elements, declarations, runners or manifest inputs.
|
|
66
|
+
|
|
67
|
+
## Reporting your own
|
|
68
|
+
|
|
69
|
+
`warn()` and `reportDiagnostic()` are public, and a consumer code is any `'<namespace>.<name>'` string:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { reportDiagnostic, warn } from '@studiometa/js-toolkit';
|
|
73
|
+
|
|
74
|
+
warn('carousel.no-slides', 'A Carousel with no slide does nothing.', { component: 'Carousel' });
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
JSON.parse('{');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
reportDiagnostic('carousel.bad-config', 'The config attribute is not valid JSON.', error);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
From inside a component, `$warn()` and `$error()` fill the component name in for you:
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
this.$warn('carousel.no-slides', 'A Carousel with no slide does nothing.');
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## What was removed
|
|
90
|
+
|
|
91
|
+
`EVENTS.error`, `ToolkitErrorDetail` and `ToolkitErrorStage` are removed with **no alias**. `DIAGNOSTICS`, `ToolkitDiagnosticSeverity`, `ToolkitDiagnosticCode` and `ToolkitDiagnosticDetail` replace them.
|
|
92
|
+
|
|
93
|
+
## In tests
|
|
94
|
+
|
|
95
|
+
Asserting on `console.warn` cannot see the code, the severity or the reporting component, and it passes for the wrong diagnostic. [`captureDiagnostics()`](../../api/test/index.md) reads the channel instead — and cancelling each event as it arrives is the same act that silences the console, so collecting and silencing are one step:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import { captureDiagnostics } from '@studiometa/js-toolkit/test';
|
|
99
|
+
|
|
100
|
+
const diagnostics = captureDiagnostics();
|
|
101
|
+
// … exercise the component
|
|
102
|
+
expect(diagnostics.codes).toContain('ref.mismatch');
|
|
103
|
+
diagnostics.stop();
|
|
104
|
+
```
|