@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,190 @@
|
|
|
1
|
+
# TypeScript
|
|
2
|
+
|
|
3
|
+
`Base` takes an optional props type. It types `$refs` and `$options`, and it checks the event names and payloads of `$emit()`.
|
|
4
|
+
|
|
5
|
+
## The props type
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Base } from '@studiometa/js-toolkit';
|
|
9
|
+
|
|
10
|
+
class Slider extends Base<{
|
|
11
|
+
$el: HTMLDivElement;
|
|
12
|
+
$refs: {
|
|
13
|
+
next: HTMLButtonElement;
|
|
14
|
+
items: HTMLElement[];
|
|
15
|
+
};
|
|
16
|
+
$options: {
|
|
17
|
+
speed: number;
|
|
18
|
+
loop: boolean;
|
|
19
|
+
};
|
|
20
|
+
$emits: {
|
|
21
|
+
goto: { index: number };
|
|
22
|
+
stop: void;
|
|
23
|
+
};
|
|
24
|
+
}> {
|
|
25
|
+
static config = {
|
|
26
|
+
name: 'Slider',
|
|
27
|
+
refs: ['next', 'items[]'],
|
|
28
|
+
options: {
|
|
29
|
+
speed: { type: Number, default: 1 },
|
|
30
|
+
loop: { type: Boolean, default: true },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
mounted() {
|
|
35
|
+
this.$refs.next.disabled = true;
|
|
36
|
+
this.$refs.items[0];
|
|
37
|
+
this.$options.speed;
|
|
38
|
+
this.$emit('goto', { index: 1 });
|
|
39
|
+
this.$emit('stop');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Four keys, all optional:
|
|
45
|
+
|
|
46
|
+
| Key | Types |
|
|
47
|
+
| ---------- | --------------------------------------------------------- |
|
|
48
|
+
| `$el` | the root element |
|
|
49
|
+
| `$refs` | each declared ref — an array for a list ref |
|
|
50
|
+
| `$options` | each declared option |
|
|
51
|
+
| `$emits` | each event name to its payload object, or `void` for none |
|
|
52
|
+
|
|
53
|
+
`$emits` replaces the runtime `config.emits` of v3. **Nothing of it stays in the bundle.**
|
|
54
|
+
|
|
55
|
+
## Extending a component
|
|
56
|
+
|
|
57
|
+
A component can take a props parameter of its own. This is how one component extends another:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { Base, type BaseConfig, type BaseProps } from '@studiometa/js-toolkit';
|
|
61
|
+
|
|
62
|
+
interface ActionProps extends BaseProps {
|
|
63
|
+
$options: { target: string };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class Action<T extends BaseProps = BaseProps> extends Base<ActionProps & T> {
|
|
67
|
+
// Annotated, so a subclass is free to declare a different config.
|
|
68
|
+
static config: BaseConfig = {
|
|
69
|
+
name: 'Action',
|
|
70
|
+
options: { target: String },
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
mounted() {
|
|
74
|
+
this.$options.target; // string
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class SafeAction extends Action<{ $options: { confirm: boolean } }> {
|
|
79
|
+
static config = {
|
|
80
|
+
name: 'SafeAction',
|
|
81
|
+
options: { confirm: Boolean },
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
mounted() {
|
|
85
|
+
this.$options.target; // still string
|
|
86
|
+
this.$options.confirm; // boolean
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Each prop is read as an intersection with its default, such as `T['$options'] & Record<string, unknown>`.
|
|
92
|
+
|
|
93
|
+
**The price of the intersection**
|
|
94
|
+
|
|
95
|
+
An option or a ref a component does **not** declare reads as `unknown`, or as `HTMLElement | HTMLElement[]`, rather than as an error. Declared props keep their exact types. This is the cost of making extension work, and it was chosen deliberately over a conditional type.
|
|
96
|
+
|
|
97
|
+
`$options` is read through the same intersection and then mapped to `Readonly<…>`, which has one price of its own: a mapped type over a props parameter is deferred, so inside a class **generic in its props** a declared option is a usable value of its declared type rather than a type identical to it. Reading it, passing it and annotating it all work; asserting its identity, or assigning one option to a variable inferred from another, needs an annotation.
|
|
98
|
+
|
|
99
|
+
`src/props.spec.ts` holds the assertions, and `npm run lint:types` enforces them.
|
|
100
|
+
|
|
101
|
+
## Handler payloads
|
|
102
|
+
|
|
103
|
+
A method named by convention is **not typed by convention** — the name is resolved at runtime. Annotate the payload:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { Base, type DelegatedEvent, type GlobalEvent, type RefEvent } from '@studiometa/js-toolkit';
|
|
107
|
+
|
|
108
|
+
class Child extends Base<{ $emits: { open: { height: number } } }> {
|
|
109
|
+
static config = { name: 'Child' };
|
|
110
|
+
}
|
|
111
|
+
class Parent extends Base {
|
|
112
|
+
static config = { name: 'Parent', components: { Child }, refs: ['dots[]'] };
|
|
113
|
+
|
|
114
|
+
onChildOpen({ target, payload }: DelegatedEvent<Child, 'open'>) {}
|
|
115
|
+
|
|
116
|
+
onDotsClick({ target, index }: RefEvent<HTMLButtonElement>) {}
|
|
117
|
+
|
|
118
|
+
onWindowResize({ event, target }: GlobalEvent<UIEvent>) {}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The [`@on` decorator](../../api/decorators/on.md) does not remove the annotation — it **checks** it. The decorator derives the payload type its target implies and the method signature has to match, so a wrong annotation is a type error rather than a silent mismatch:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { Base, component, on, type DelegatedEvent } from '@studiometa/js-toolkit';
|
|
126
|
+
|
|
127
|
+
class Child extends Base<{ $emits: { open: { height: number } } }> {
|
|
128
|
+
static config = { name: 'Child' };
|
|
129
|
+
}
|
|
130
|
+
@component({ name: 'Parent', components: { Child } })
|
|
131
|
+
class Parent extends Base {
|
|
132
|
+
@on(Child, 'open')
|
|
133
|
+
onOpen({ payload }: DelegatedEvent<Child, 'open'>) {
|
|
134
|
+
payload.height; // number
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A decorator cannot infer a method's own parameters — the method signature is checked _against_ what the decorator expects, not derived from it. Annotate the payload either way; with `@on` the annotation is verified against a real target.
|
|
140
|
+
|
|
141
|
+
## Config typing
|
|
142
|
+
|
|
143
|
+
`$config` walks the prototype chain and merges every config it finds, so an intermediate class must not narrow the type its subclasses need.
|
|
144
|
+
|
|
145
|
+
Left alone, `static config = { … }` infers a **literal** type, and every subclass has to match it — a subclass that adds an option gets `Class static side 'typeof SafeAction' incorrectly extends base class static side 'typeof Action'`. Annotate the intermediate class instead:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { Base, type BaseConfig } from '@studiometa/js-toolkit';
|
|
149
|
+
|
|
150
|
+
class AbstractControl extends Base {
|
|
151
|
+
static config: BaseConfig = {
|
|
152
|
+
name: 'AbstractControl',
|
|
153
|
+
refs: ['button'],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Compiler options
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"compilerOptions": {
|
|
163
|
+
"target": "ES2022",
|
|
164
|
+
"module": "Preserve",
|
|
165
|
+
"moduleResolution": "bundler",
|
|
166
|
+
"experimentalDecorators": false,
|
|
167
|
+
"useDefineForClassFields": true,
|
|
168
|
+
"strict": true
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Stage-3 decorators need no flag on TypeScript 5. `experimentalDecorators` must be **off**.
|
|
174
|
+
|
|
175
|
+
## JSDoc
|
|
176
|
+
|
|
177
|
+
The props type works from JSDoc too, for a project with no `.ts` files:
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
/**
|
|
181
|
+
* @extends {Base<{ $refs: { output: HTMLElement }, $options: { step: number } }>}
|
|
182
|
+
*/
|
|
183
|
+
class Counter extends Base {
|
|
184
|
+
static config = {
|
|
185
|
+
name: 'Counter',
|
|
186
|
+
refs: ['output'],
|
|
187
|
+
options: { step: { type: Number, default: 1 } },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
```
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Decorators
|
|
2
|
+
|
|
3
|
+
**Every decorator is a thin wrapper over a function API that works without it.** No engine ships stage-3 decorators, so a page that loads the package from an ESM CDN keeps `registerComponent`, `$provide`, `$watchChildren`, `$read`, `$write` and the `on<Child><Event>` method names.
|
|
4
|
+
|
|
5
|
+
Decorators are sugar. They are never a requirement.
|
|
6
|
+
|
|
7
|
+
## The six
|
|
8
|
+
|
|
9
|
+
| Decorator | Wraps | Notes |
|
|
10
|
+
| ----------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------- |
|
|
11
|
+
| `@component({ name })` | `static config` + `registerComponent()` | Registers as soon as the class is defined. |
|
|
12
|
+
| `@on(target, type)` / `@on(type)` | the `on<Child><Event>` names | The target is a name or a value. |
|
|
13
|
+
| `@provide(key)` / `@inject(key)` | `$provide()` / `$inject()` | The shape of Lit's `@provide` and `@consume`. |
|
|
14
|
+
| `@children(nameOrClass, callbacks)` | `$watchChildren()` | Exact name, or constructor and subclasses. Callbacks are bound to the instance. |
|
|
15
|
+
| `@read` / `@write` | `$read()` / `$write()` | Runs the method body in that phase, cancelled on unmount. |
|
|
16
|
+
|
|
17
|
+
Each value decorator works on a plain field and on an `accessor` field.
|
|
18
|
+
|
|
19
|
+
## A component with decorators
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
Base,
|
|
24
|
+
children,
|
|
25
|
+
component,
|
|
26
|
+
on,
|
|
27
|
+
type ChildrenCollection,
|
|
28
|
+
type DelegatedEvent,
|
|
29
|
+
} from '@studiometa/js-toolkit';
|
|
30
|
+
|
|
31
|
+
@component({ name: 'AccordionItem' })
|
|
32
|
+
class AccordionItem extends Base<{ $emits: { open: void } }> {
|
|
33
|
+
@on('click')
|
|
34
|
+
toggle() {
|
|
35
|
+
this.$emit('open');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@component({ name: 'Accordion', components: { AccordionItem } })
|
|
40
|
+
class Accordion extends Base {
|
|
41
|
+
@children(AccordionItem)
|
|
42
|
+
items!: ChildrenCollection<AccordionItem>;
|
|
43
|
+
|
|
44
|
+
@on(AccordionItem, 'open')
|
|
45
|
+
closeOthers({ target }: DelegatedEvent<AccordionItem, 'open'>) {
|
|
46
|
+
for (const item of this.items) {
|
|
47
|
+
if (item !== target) item.$el.removeAttribute('data-option-open');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## `@component` and `static config` merge
|
|
54
|
+
|
|
55
|
+
They merge in a class initializer, which runs after the fields and inside the class definition, so `registerComponent()` on the next line reads the finished config. The rules are the rules of `$config`: `refs` union, `options` and `components` merge entry by entry, a declared value overrides.
|
|
56
|
+
|
|
57
|
+
A key both sides declare differently is reported as `component.config-conflict`.
|
|
58
|
+
|
|
59
|
+
**The decorator is applied last**, so it registers a finished class.
|
|
60
|
+
|
|
61
|
+
## `@on` — a name or a value
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { Base, component, on } from '@studiometa/js-toolkit';
|
|
65
|
+
|
|
66
|
+
class AccordionItem extends Base {
|
|
67
|
+
static config = { name: 'AccordionItem' };
|
|
68
|
+
}
|
|
69
|
+
@component({ name: 'Demo', components: { AccordionItem }, refs: ['dots[]'] })
|
|
70
|
+
class Demo extends Base {
|
|
71
|
+
@on('click') a(event: MouseEvent) {} // own element, typed from HTMLElementEventMap
|
|
72
|
+
@on('submit') b(event: SubmitEvent) {} // idem
|
|
73
|
+
@on('dots[]', 'click') c() {} // a ref, named as declared
|
|
74
|
+
@on('AccordionItem', 'open') d() {} // a child, by name — imports nothing
|
|
75
|
+
@on(AccordionItem, 'open') e() {} // a child, by class — the class is the type
|
|
76
|
+
@on(window, 'load') f() {} // a global
|
|
77
|
+
@on(document, 'click') g() {} // a global
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **The one-argument form types its event from `HTMLElementEventMap`**, so `@on('click')` hands over a `MouseEvent` and `@on('submit')` a `SubmitEvent`. A name outside that map is a component event, whose detail only its emitter knows, so the handler declares the type it expects: `@on('content') inject(event: CustomEvent<{ content: string }>)`.
|
|
82
|
+
- **A class resolves to its merged `config.name`** and lands on the same delegated entry as the string form. The class is the type, so `target` is the component and `payload` comes from its `$emits`.
|
|
83
|
+
- **A lazy child needs the string form.** `@on('Child', 'open')` imports nothing; a thunk is not a target and both the overloads and the runtime refuse it.
|
|
84
|
+
- **A name is a child or a ref**, resolved children-first, so the handler is typed as `DelegatedEvent` or `RefEvent`.
|
|
85
|
+
- **A ref is named as it is declared**: `@on('dots[]', 'click')` for `config.refs: ['dots[]']`. A mismatched `@on('dots', 'click')` warns at bind time when the other spelling is declared. A name that matches nothing stays silent.
|
|
86
|
+
- **A global target goes through the same binding `onWindow<Event>` uses**: bubble phase, one listener per mount cycle, removed by `$unmount()`. `@on(window, 'click')` types the event from `WindowEventMap` and falls back to `Event`.
|
|
87
|
+
- **Nothing is reserved in its string space**: `'Window'` means the child and `window` means the global.
|
|
88
|
+
- **Any other `EventTarget` is refused**, by the overloads and by a `TypeError`. A decorator is evaluated once, at class definition, so an arbitrary target can only be a module-scope value.
|
|
89
|
+
|
|
90
|
+
## `@read` and `@write`
|
|
91
|
+
|
|
92
|
+
They are **leaf-method sugar: the phase belongs to the call site.**
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { Base, component, read, write } from '@studiometa/js-toolkit';
|
|
96
|
+
|
|
97
|
+
@component({ name: 'Measure' })
|
|
98
|
+
class Measure extends Base {
|
|
99
|
+
#height = 0;
|
|
100
|
+
|
|
101
|
+
@read
|
|
102
|
+
measure() {
|
|
103
|
+
this.#height = this.$el.scrollHeight;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@write
|
|
107
|
+
apply() {
|
|
108
|
+
this.$el.style.setProperty('--height', `${this.#height}px`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Decorate a method nobody overrides**
|
|
114
|
+
|
|
115
|
+
A phase decorator returns a wrapper around the method it decorates, and that wrapper is a property of **that class**. A subclass that overrides the method defines its own, undecorated, and `this.method()` resolves to it — so the base's scheduling disappears and the body runs in whatever phase the caller was in.
|
|
116
|
+
|
|
117
|
+
A **template method** — a base that schedules work its subclasses implement — schedules at the call site instead:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
// in the base, where the call is
|
|
121
|
+
state.subscribe((value) => this.$write(() => this.update(value)));
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The alternative, dispatching a decorated method through something a subclass cannot replace, was refused: it would make a decorator's behaviour depend on inheritance depth, which nothing else in v4 does.
|
|
125
|
+
|
|
126
|
+
### Stacking with `@on`
|
|
127
|
+
|
|
128
|
+
The skip is keyed by the method name, so `@on` and `@read`/`@write` stack in either order. The order decides what the listener calls:
|
|
129
|
+
|
|
130
|
+
- a phase decorator written **below** the `@on`, nearest the method, schedules the body of the handler;
|
|
131
|
+
- one written **above** it schedules direct calls only.
|
|
132
|
+
|
|
133
|
+
Write `@read` and `@write` closest to the method body.
|
|
134
|
+
|
|
135
|
+
## Build setup
|
|
136
|
+
|
|
137
|
+
Vite 8 transforms TypeScript with Oxc, which passes decorators through untouched. The package itself compiles them with `@rollup/plugin-swc` and `decoratorVersion: '2023-11'`, filtered to the files that contain a decorator. See [Installation](../introduction/installation.md#with-a-build-step).
|
|
138
|
+
|
|
139
|
+
## The same component, without any of them
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { Base, registerComponent, type DelegatedEvent } from '@studiometa/js-toolkit';
|
|
143
|
+
|
|
144
|
+
class AccordionItem extends Base<{ $emits: { open: void } }> {
|
|
145
|
+
static config = { name: 'AccordionItem' };
|
|
146
|
+
|
|
147
|
+
onClick() {
|
|
148
|
+
this.$emit('open');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
class Accordion extends Base {
|
|
153
|
+
static config = {
|
|
154
|
+
name: 'Accordion',
|
|
155
|
+
components: { AccordionItem },
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
items = this.$watchChildren(AccordionItem);
|
|
159
|
+
|
|
160
|
+
onAccordionItemOpen({ target }: DelegatedEvent<AccordionItem, 'open'>) {
|
|
161
|
+
for (const item of this.items) {
|
|
162
|
+
if (item !== target) item.$el.removeAttribute('data-option-open');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
registerComponent(Accordion);
|
|
168
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Storage
|
|
2
|
+
|
|
3
|
+
`createStorage()` is a typed, observable key-value store over a `StorageProvider`. **One seam, six adapters.**
|
|
4
|
+
|
|
5
|
+
## The store
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createLocalStorage } from '@studiometa/js-toolkit';
|
|
9
|
+
|
|
10
|
+
interface Prefs {
|
|
11
|
+
theme: 'light' | 'dark';
|
|
12
|
+
seen: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const prefs = createLocalStorage<Prefs>({ prefix: 'app:' });
|
|
16
|
+
|
|
17
|
+
prefs.set('theme', 'dark');
|
|
18
|
+
prefs.get('theme'); // 'light' | 'dark' | undefined
|
|
19
|
+
prefs.get('theme', 'light'); // 'light' | 'dark'
|
|
20
|
+
prefs.has('seen');
|
|
21
|
+
prefs.keys();
|
|
22
|
+
prefs.delete('seen');
|
|
23
|
+
prefs.clear();
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`createStorage()` owns everything a consumer thinks of as storage: key namespacing through `prefix`, serialization in both directions, a `Signal` per key created on the first subscription, and the reference-counted wiring that keeps keys in sync. **A provider moves strings only.**
|
|
27
|
+
|
|
28
|
+
## Observing a key
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { createLocalStorage } from '@studiometa/js-toolkit';
|
|
32
|
+
|
|
33
|
+
interface Prefs {
|
|
34
|
+
theme: 'light' | 'dark';
|
|
35
|
+
}
|
|
36
|
+
const prefs = createLocalStorage<Prefs>();
|
|
37
|
+
const unsubscribe = prefs.subscribe(
|
|
38
|
+
'theme',
|
|
39
|
+
(value) => {
|
|
40
|
+
document.documentElement.dataset.theme = value ?? 'light';
|
|
41
|
+
},
|
|
42
|
+
{ immediate: true },
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`destroy()` releases every subscription and the shared listeners at once.
|
|
47
|
+
|
|
48
|
+
In a component, hand the unsubscribe back from `mounted()`:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
mounted() {
|
|
52
|
+
return prefs.subscribe('theme', (value) => this.apply(value));
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## The six adapters
|
|
57
|
+
|
|
58
|
+
| Adapter | Backed by |
|
|
59
|
+
| --------------------------------------------------------- | ------------------------------------------------------ |
|
|
60
|
+
| `localStorageProvider` | `localStorage` |
|
|
61
|
+
| `sessionStorageProvider` | `sessionStorage` |
|
|
62
|
+
| `memoryStorageProvider` / `createMemoryStorageProvider()` | a `Map` |
|
|
63
|
+
| `createFallbackProvider(...providers)` | reads from the first that holds the key, writes to all |
|
|
64
|
+
| `urlSearchParamsProvider` | `location.search` |
|
|
65
|
+
| `urlSearchParamsInHashProvider` | `location.hash`, read as search params |
|
|
66
|
+
|
|
67
|
+
The two URL adapters rebuild the whole location on each write, so a search write keeps the hash and a hash write keeps the query string. They take one option, `push`, which chooses `history.pushState` over the default `replaceState`.
|
|
68
|
+
|
|
69
|
+
Four presets remove an argument from every call site: `createLocalStorage()`, `createSessionStorage()`, `createUrlSearchParamsStorage()` and `createUrlSearchParamsInHashStorage()`.
|
|
70
|
+
|
|
71
|
+
**A factory exists only where its product has state**
|
|
72
|
+
|
|
73
|
+
`createMemoryStorageProvider()` holds a `Map`. `createFallbackProvider()` and the two URL factories take arguments. There is no `createLocalStorageProvider()` — the instance is enough.
|
|
74
|
+
|
|
75
|
+
## Failures are diagnostics, never throws
|
|
76
|
+
|
|
77
|
+
**A built-in provider reports its own failures and never throws.** A full quota or a refused storage area becomes a `storage.access-failed` diagnostic and the method returns its fallback: `null`, `false`, `[]` or `undefined`. It reports once per operation, not once per area.
|
|
78
|
+
|
|
79
|
+
The store's own failures have their own codes:
|
|
80
|
+
|
|
81
|
+
- `storage.serialize-failed` — nothing is written.
|
|
82
|
+
- `storage.deserialize-failed` — the default is returned.
|
|
83
|
+
|
|
84
|
+
`types.ts` states the same contract for a custom provider.
|
|
85
|
+
|
|
86
|
+
## Syncing with the outside
|
|
87
|
+
|
|
88
|
+
`syncEvents` is a list of window event names and nothing more. A provider declares how a change made outside this instance announces itself:
|
|
89
|
+
|
|
90
|
+
| Provider | `syncEvents` |
|
|
91
|
+
| ----------------- | ------------------------ |
|
|
92
|
+
| web storage | `storage` (another tab) |
|
|
93
|
+
| URL search params | `popstate` |
|
|
94
|
+
| URL hash | `popstate`, `hashchange` |
|
|
95
|
+
|
|
96
|
+
`createStorage()` subscribes **one shared, reference-counted listener per name** while at least one key is observed, and re-reads every observed key when it fires. The event carries no usable state, so the subscriber re-reads.
|
|
97
|
+
|
|
98
|
+
**A known gap**
|
|
99
|
+
|
|
100
|
+
A provider whose changes arrive on a `BroadcastChannel` or through an observer has no way to announce them yet.
|
|
101
|
+
|
|
102
|
+
## A custom backend
|
|
103
|
+
|
|
104
|
+
Six synchronous string methods, plus an optional `syncEvents`:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { createStorage, type StorageProvider } from '@studiometa/js-toolkit';
|
|
108
|
+
|
|
109
|
+
const cookieProvider: StorageProvider = {
|
|
110
|
+
get: (key) => new URLSearchParams(document.cookie.replaceAll('; ', '&')).get(key),
|
|
111
|
+
set: (key, value) => {
|
|
112
|
+
document.cookie = `${key}=${value};path=/`;
|
|
113
|
+
},
|
|
114
|
+
remove: (key) => {
|
|
115
|
+
document.cookie = `${key}=;path=/;max-age=0`;
|
|
116
|
+
},
|
|
117
|
+
has: (key) => document.cookie.includes(`${key}=`),
|
|
118
|
+
keys: () => [...new URLSearchParams(document.cookie.replaceAll('; ', '&')).keys()],
|
|
119
|
+
clear: () => {},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const store = createStorage({ provider: cookieProvider });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
One storage instance runs in Node over the memory provider, which is what `test/package-node-consumer.js` exercises.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
`@studiometa/js-toolkit` v4 is a data-attributes driven micro-framework. You write classes, you add `data-*` attributes to your HTML, and one registry mounts the two together.
|
|
4
|
+
|
|
5
|
+
One sentence carries the whole design:
|
|
6
|
+
|
|
7
|
+
> **The registry is the framework. The DOM is the component tree.**
|
|
8
|
+
|
|
9
|
+
An instance exists because its element is in the document **and** its class is registered. Nothing else creates or unmounts an instance.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @studiometa/js-toolkit@next
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Hello world
|
|
18
|
+
|
|
19
|
+
Declare the component in the markup with `data-component`, and expose the elements it needs with `data-ref`:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<div data-component="Hello">
|
|
23
|
+
<button data-ref="btn">Say hello</button>
|
|
24
|
+
</div>
|
|
25
|
+
<script type="module" src="./main.js"></script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Write the class, and register it:
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { Base, registerComponent } from '@studiometa/js-toolkit';
|
|
32
|
+
|
|
33
|
+
class Hello extends Base {
|
|
34
|
+
static config = {
|
|
35
|
+
name: 'Hello',
|
|
36
|
+
refs: ['btn'],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
onBtnClick() {
|
|
40
|
+
alert('Hello, world!');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
registerComponent(Hello);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
That is the whole setup. `registerComponent()` puts the name in the registry, and every `[data-component="Hello"]` element in the document gets an instance — including the elements added to the page afterwards, by a template, a `fetch` or another component.
|
|
48
|
+
|
|
49
|
+
## The four things to know
|
|
50
|
+
|
|
51
|
+
### 1. Mount and unmount follow the element
|
|
52
|
+
|
|
53
|
+
The element enters the document, the instance mounts. The element leaves, the instance unmounts and stays on its element, ready for a re-insertion. A **move** is one unmount and one mount of the same instance, exactly like `disconnectedCallback` and `connectedCallback` on a custom element.
|
|
54
|
+
|
|
55
|
+
There is no third state. A component never declares that its work is over.
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
import { Base } from '@studiometa/js-toolkit';
|
|
59
|
+
|
|
60
|
+
class Once extends Base {
|
|
61
|
+
static config = { name: 'Once' };
|
|
62
|
+
|
|
63
|
+
hasLoaded = false;
|
|
64
|
+
|
|
65
|
+
mounted() {
|
|
66
|
+
if (this.hasLoaded) return;
|
|
67
|
+
// … the work that must run once per element
|
|
68
|
+
this.hasLoaded = true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Read more in [Lifecycle](introduction/lifecycle-hooks.md).
|
|
74
|
+
|
|
75
|
+
### 2. Refs are live, and handlers are delegated
|
|
76
|
+
|
|
77
|
+
Each `$refs` property reads the DOM on access, so markup that arrives later is found with no refresh and no `$update()`. `on<Ref><Event>` handlers are delegated from the root element, so a ref that appears later needs no new binding.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
import { Base } from '@studiometa/js-toolkit';
|
|
81
|
+
|
|
82
|
+
class List extends Base {
|
|
83
|
+
static config = {
|
|
84
|
+
name: 'List',
|
|
85
|
+
refs: ['items[]'], // the `[]` is part of the attribute: data-ref="items[]"
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
onItemsClick({ index }) {
|
|
89
|
+
console.log(`clicked item ${index}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Read more in [Refs](introduction/managing-refs.md).
|
|
95
|
+
|
|
96
|
+
### 3. Options are a read-only view over the attributes
|
|
97
|
+
|
|
98
|
+
An option is an **input**, never a store. Every property of `$options` is a getter that derives its value from the element and the viewport on each access.
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<div data-component="Grid" data-option-columns="1" data-option-columns:l="4"></div>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
import { Base } from '@studiometa/js-toolkit';
|
|
106
|
+
|
|
107
|
+
class Grid extends Base {
|
|
108
|
+
static config = {
|
|
109
|
+
name: 'Grid',
|
|
110
|
+
options: {
|
|
111
|
+
columns: { type: Number, default: 1 },
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
mounted() {
|
|
116
|
+
console.log(this.$options.columns); // 1, or 4 from the `l` breakpoint up
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Every option is responsive with no flag to declare, and to change one you write the attribute. Read more in [Options](introduction/managing-options.md).
|
|
122
|
+
|
|
123
|
+
### 4. Children announce themselves, parents listen
|
|
124
|
+
|
|
125
|
+
A child never reaches for its parent. It emits, and the parent hears it through the `on<Child><Event>` convention, resolved against the names in `config.components`:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { Base, type DelegatedEvent } from '@studiometa/js-toolkit';
|
|
129
|
+
|
|
130
|
+
class SliderItem extends Base<{ $emits: { select: { index: number } } }> {
|
|
131
|
+
static config = { name: 'SliderItem' };
|
|
132
|
+
|
|
133
|
+
onClick() {
|
|
134
|
+
this.$emit('select', { index: 0 });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
class Slider extends Base {
|
|
139
|
+
static config = {
|
|
140
|
+
name: 'Slider',
|
|
141
|
+
components: { SliderItem },
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
onSliderItemSelect({ payload }: DelegatedEvent<SliderItem, 'select'>) {
|
|
145
|
+
console.log(payload.index);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`$emit()` dispatches a real, bubbling `CustomEvent`, so a plain listener hears it too.
|
|
151
|
+
|
|
152
|
+
**A handler named by convention is not typed by convention**
|
|
153
|
+
|
|
154
|
+
The `on<Child><Event>` name is resolved at runtime, so TypeScript cannot infer the parameter for you. Annotate it with `DelegatedEvent`, `RefEvent` or `GlobalEvent`. The [`@on` decorator](../api/decorators/on.md) does not remove the annotation either — it checks it against a real target.
|
|
155
|
+
|
|
156
|
+
Read more in [Events](introduction/working-with-events.md).
|
|
157
|
+
|
|
158
|
+
## Where to go next
|
|
159
|
+
|
|
160
|
+
- [Installation](introduction/installation.md) — build tools, CDN and the subpath layout.
|
|
161
|
+
- [Components](introduction/managing-components.md) — declaring, registering and nesting components.
|
|
162
|
+
- [Philosophy](concepts/philosophy.md) — why one registry, and what was removed to get it.
|
|
163
|
+
- [Migrating from v3](migration/v3-to-v4.md) — every breaking change, with the replacement for each.
|