@zeix/le-truc 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai-context.md +234 -0
- package/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
- package/.editorconfig +12 -0
- package/.github/copilot-instructions.md +62 -0
- package/.github/workflows/codeql.yml +108 -0
- package/.github/workflows/static.yml +43 -0
- package/.prettierrc +17 -0
- package/CLAUDE.md +215 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +160 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/biome.json +295 -0
- package/bun.lock +239 -0
- package/docs/about.html +105 -0
- package/docs/assets/main.css +1 -0
- package/docs/assets/main.js +10 -0
- package/docs/assets/main.js.map +66 -0
- package/docs/components.html +293 -0
- package/docs/data-flow.html +308 -0
- package/docs/examples/basic-button.html +367 -0
- package/docs/examples/basic-counter.html +188 -0
- package/docs/examples/basic-hello.html +138 -0
- package/docs/examples/basic-number.html +271 -0
- package/docs/examples/basic-pluralize.html +214 -0
- package/docs/examples/card-callout.html +152 -0
- package/docs/examples/card-mediaqueries.html +138 -0
- package/docs/examples/context-media.html +198 -0
- package/docs/examples/empty.html +37 -0
- package/docs/examples/form-checkbox.html +233 -0
- package/docs/examples/form-combobox.html +420 -0
- package/docs/examples/form-listbox.html +434 -0
- package/docs/examples/form-radiogroup.html +296 -0
- package/docs/examples/form-spinbutton.html +402 -0
- package/docs/examples/form-textbox.html +361 -0
- package/docs/examples/layout.html +67 -0
- package/docs/examples/module-carousel.html +552 -0
- package/docs/examples/module-catalog.html +241 -0
- package/docs/examples/module-codeblock.html +270 -0
- package/docs/examples/module-dialog.html +343 -0
- package/docs/examples/module-lazyload.html +289 -0
- package/docs/examples/module-list.html +197 -0
- package/docs/examples/module-pagination.html +283 -0
- package/docs/examples/module-scrollarea.html +447 -0
- package/docs/examples/module-tabgroup.html +526 -0
- package/docs/examples/module-todo.html +367 -0
- package/docs/examples/module-with-type.html +63 -0
- package/docs/examples/nested-components.html +88 -0
- package/docs/examples/recursive.html +56 -0
- package/docs/examples/simple-text.html +39 -0
- package/docs/examples/snippet.html +93 -0
- package/docs/examples/with-styles.html +75 -0
- package/docs/getting-started.html +143 -0
- package/docs/index.html +112 -0
- package/docs/sitemap.xml +28 -0
- package/docs/styling.html +160 -0
- package/docs/sw.js +112 -0
- package/docs-src/api/README.md +478 -0
- package/docs-src/api/_media/LICENSE +21 -0
- package/docs-src/api/classes/CircularDependencyError.md +299 -0
- package/docs-src/api/classes/CircularMutationError.md +301 -0
- package/docs-src/api/classes/ContextRequestEvent.md +590 -0
- package/docs-src/api/classes/DependencyTimeoutError.md +301 -0
- package/docs-src/api/classes/InvalidCallbackError.md +303 -0
- package/docs-src/api/classes/InvalidComponentNameError.md +295 -0
- package/docs-src/api/classes/InvalidCustomElementError.md +301 -0
- package/docs-src/api/classes/InvalidEffectsError.md +301 -0
- package/docs-src/api/classes/InvalidPropertyNameError.md +307 -0
- package/docs-src/api/classes/InvalidReactivesError.md +307 -0
- package/docs-src/api/classes/InvalidSignalValueError.md +303 -0
- package/docs-src/api/classes/MissingElementError.md +307 -0
- package/docs-src/api/classes/NullishSignalValueError.md +299 -0
- package/docs-src/api/classes/StoreKeyExistsError.md +303 -0
- package/docs-src/api/classes/StoreKeyRangeError.md +299 -0
- package/docs-src/api/classes/StoreKeyReadonlyError.md +303 -0
- package/docs-src/api/functions/asBoolean.md +21 -0
- package/docs-src/api/functions/asEnum.md +31 -0
- package/docs-src/api/functions/asInteger.md +39 -0
- package/docs-src/api/functions/asJSON.md +49 -0
- package/docs-src/api/functions/asNumber.md +37 -0
- package/docs-src/api/functions/asString.md +37 -0
- package/docs-src/api/functions/createCollection.md +83 -0
- package/docs-src/api/functions/createSensor.md +71 -0
- package/docs-src/api/functions/dangerouslySetInnerHTML.md +48 -0
- package/docs-src/api/functions/defineComponent.md +65 -0
- package/docs-src/api/functions/isCollection.md +37 -0
- package/docs-src/api/functions/isParser.md +41 -0
- package/docs-src/api/functions/match.md +47 -0
- package/docs-src/api/functions/on.md +58 -0
- package/docs-src/api/functions/pass.md +53 -0
- package/docs-src/api/functions/provideContexts.md +47 -0
- package/docs-src/api/functions/read.md +47 -0
- package/docs-src/api/functions/requestContext.md +51 -0
- package/docs-src/api/functions/resolve.md +40 -0
- package/docs-src/api/functions/runEffects.md +51 -0
- package/docs-src/api/functions/runElementEffects.md +57 -0
- package/docs-src/api/functions/schedule.md +33 -0
- package/docs-src/api/functions/setAttribute.md +48 -0
- package/docs-src/api/functions/setProperty.md +52 -0
- package/docs-src/api/functions/setStyle.md +48 -0
- package/docs-src/api/functions/setText.md +42 -0
- package/docs-src/api/functions/show.md +42 -0
- package/docs-src/api/functions/toSignal.md +37 -0
- package/docs-src/api/functions/toggleAttribute.md +48 -0
- package/docs-src/api/functions/toggleClass.md +48 -0
- package/docs-src/api/functions/updateElement.md +53 -0
- package/docs-src/api/globals.md +131 -0
- package/docs-src/api/type-aliases/Cleanup.md +27 -0
- package/docs-src/api/type-aliases/Collection.md +91 -0
- package/docs-src/api/type-aliases/CollectionListener.md +27 -0
- package/docs-src/api/type-aliases/Component.md +17 -0
- package/docs-src/api/type-aliases/ComponentProp.md +11 -0
- package/docs-src/api/type-aliases/ComponentProps.md +11 -0
- package/docs-src/api/type-aliases/ComponentSetup.md +31 -0
- package/docs-src/api/type-aliases/ComponentUI.md +27 -0
- package/docs-src/api/type-aliases/Computed.md +49 -0
- package/docs-src/api/type-aliases/ComputedCallback.md +29 -0
- package/docs-src/api/type-aliases/Context.md +33 -0
- package/docs-src/api/type-aliases/ContextType.md +19 -0
- package/docs-src/api/type-aliases/DangerouslySetInnerHTMLOptions.md +27 -0
- package/docs-src/api/type-aliases/DiffResult.md +61 -0
- package/docs-src/api/type-aliases/Effect.md +35 -0
- package/docs-src/api/type-aliases/EffectCallback.md +23 -0
- package/docs-src/api/type-aliases/Effects.md +21 -0
- package/docs-src/api/type-aliases/ElementEffects.md +21 -0
- package/docs-src/api/type-aliases/ElementFromKey.md +21 -0
- package/docs-src/api/type-aliases/ElementQueries.md +27 -0
- package/docs-src/api/type-aliases/ElementUpdater.md +131 -0
- package/docs-src/api/type-aliases/EventHandler.md +31 -0
- package/docs-src/api/type-aliases/EventType.md +17 -0
- package/docs-src/api/type-aliases/Fallback.md +21 -0
- package/docs-src/api/type-aliases/Initializers.md +21 -0
- package/docs-src/api/type-aliases/LooseReader.md +31 -0
- package/docs-src/api/type-aliases/MatchHandlers.md +77 -0
- package/docs-src/api/type-aliases/MaybeCleanup.md +23 -0
- package/docs-src/api/type-aliases/MaybeSignal.md +17 -0
- package/docs-src/api/type-aliases/Parser.md +39 -0
- package/docs-src/api/type-aliases/ParserOrFallback.md +21 -0
- package/docs-src/api/type-aliases/PassedProp.md +25 -0
- package/docs-src/api/type-aliases/PassedProps.md +21 -0
- package/docs-src/api/type-aliases/Reactive.md +25 -0
- package/docs-src/api/type-aliases/Reader.md +31 -0
- package/docs-src/api/type-aliases/ReservedWords.md +11 -0
- package/docs-src/api/type-aliases/ResolveResult.md +29 -0
- package/docs-src/api/type-aliases/SensorEvents.md +25 -0
- package/docs-src/api/type-aliases/Signal.md +41 -0
- package/docs-src/api/type-aliases/State.md +85 -0
- package/docs-src/api/type-aliases/Store.md +29 -0
- package/docs-src/api/type-aliases/UI.md +11 -0
- package/docs-src/api/type-aliases/UnknownContext.md +13 -0
- package/docs-src/api/variables/CONTEXT_REQUEST.md +11 -0
- package/docs-src/api/variables/UNSET.md +23 -0
- package/docs-src/api/variables/batch.md +25 -0
- package/docs-src/api/variables/createComputed.md +41 -0
- package/docs-src/api/variables/createEffect.md +35 -0
- package/docs-src/api/variables/createState.md +37 -0
- package/docs-src/api/variables/createStore.md +42 -0
- package/docs-src/api/variables/diff.md +43 -0
- package/docs-src/api/variables/isAbortError.md +33 -0
- package/docs-src/api/variables/isAsyncFunction.md +39 -0
- package/docs-src/api/variables/isComputed.md +37 -0
- package/docs-src/api/variables/isEqual.md +49 -0
- package/docs-src/api/variables/isFunction.md +39 -0
- package/docs-src/api/variables/isMutableSignal.md +37 -0
- package/docs-src/api/variables/isNumber.md +33 -0
- package/docs-src/api/variables/isRecord.md +39 -0
- package/docs-src/api/variables/isRecordOrArray.md +39 -0
- package/docs-src/api/variables/isSignal.md +37 -0
- package/docs-src/api/variables/isState.md +37 -0
- package/docs-src/api/variables/isStore.md +37 -0
- package/docs-src/api/variables/isString.md +33 -0
- package/docs-src/api/variables/isSymbol.md +33 -0
- package/docs-src/api/variables/toError.md +33 -0
- package/docs-src/api/variables/valueString.md +33 -0
- package/docs-src/includes/menu.html +44 -0
- package/docs-src/pages/about.md +89 -0
- package/docs-src/pages/components.md +437 -0
- package/docs-src/pages/data-flow.md +449 -0
- package/docs-src/pages/getting-started.md +170 -0
- package/docs-src/pages/index.md +98 -0
- package/docs-src/pages/styling.md +165 -0
- package/eslint.config.js +64 -0
- package/examples/_common/clear.ts +49 -0
- package/examples/_common/fetch.ts +160 -0
- package/examples/_common/focus.ts +45 -0
- package/examples/_common/highlight.ts +5 -0
- package/examples/_global.css +463 -0
- package/examples/basic-button/basic-button.css +176 -0
- package/examples/basic-button/basic-button.html +46 -0
- package/examples/basic-button/basic-button.spec.ts +160 -0
- package/examples/basic-button/basic-button.ts +45 -0
- package/examples/basic-button/copyToClipboard.ts +37 -0
- package/examples/basic-counter/basic-counter.css +21 -0
- package/examples/basic-counter/basic-counter.html +24 -0
- package/examples/basic-counter/basic-counter.spec.ts +85 -0
- package/examples/basic-counter/basic-counter.ts +43 -0
- package/examples/basic-hello/basic-hello.html +34 -0
- package/examples/basic-hello/basic-hello.spec.ts +110 -0
- package/examples/basic-hello/basic-hello.ts +36 -0
- package/examples/basic-number/basic-number.html +79 -0
- package/examples/basic-number/basic-number.spec.ts +175 -0
- package/examples/basic-number/basic-number.ts +124 -0
- package/examples/basic-pluralize/basic-pluralize.html +64 -0
- package/examples/basic-pluralize/basic-pluralize.spec.ts +258 -0
- package/examples/basic-pluralize/basic-pluralize.ts +82 -0
- package/examples/card-callout/card-callout.css +79 -0
- package/examples/card-callout/card-callout.html +5 -0
- package/examples/card-mediaqueries/card-mediaqueries.html +29 -0
- package/examples/card-mediaqueries/card-mediaqueries.spec.ts +300 -0
- package/examples/card-mediaqueries/card-mediaqueries.ts +41 -0
- package/examples/context-media/context-media.html +3 -0
- package/examples/context-media/context-media.ts +127 -0
- package/examples/form-checkbox/form-checkbox.css +70 -0
- package/examples/form-checkbox/form-checkbox.html +13 -0
- package/examples/form-checkbox/form-checkbox.spec.ts +357 -0
- package/examples/form-checkbox/form-checkbox.ts +50 -0
- package/examples/form-checkbox/vanilla-checkbox.ts +101 -0
- package/examples/form-combobox/form-combobox.css +118 -0
- package/examples/form-combobox/form-combobox.html +74 -0
- package/examples/form-combobox/form-combobox.spec.ts +977 -0
- package/examples/form-combobox/form-combobox.ts +128 -0
- package/examples/form-listbox/form-listbox.css +71 -0
- package/examples/form-listbox/form-listbox.html +67 -0
- package/examples/form-listbox/form-listbox.spec.ts +1050 -0
- package/examples/form-listbox/form-listbox.ts +196 -0
- package/examples/form-listbox/mocks/timezones.json +495 -0
- package/examples/form-radiogroup/form-radiogroup.css +87 -0
- package/examples/form-radiogroup/form-radiogroup.html +51 -0
- package/examples/form-radiogroup/form-radiogroup.spec.ts +515 -0
- package/examples/form-radiogroup/form-radiogroup.ts +58 -0
- package/examples/form-spinbutton/form-spinbutton.css +95 -0
- package/examples/form-spinbutton/form-spinbutton.html +96 -0
- package/examples/form-spinbutton/form-spinbutton.spec.ts +688 -0
- package/examples/form-spinbutton/form-spinbutton.ts +111 -0
- package/examples/form-textbox/form-textbox.css +104 -0
- package/examples/form-textbox/form-textbox.html +53 -0
- package/examples/form-textbox/form-textbox.spec.ts +542 -0
- package/examples/form-textbox/form-textbox.ts +104 -0
- package/examples/main.css +22 -0
- package/examples/main.ts +23 -0
- package/examples/module-carousel/module-carousel.css +113 -0
- package/examples/module-carousel/module-carousel.html +208 -0
- package/examples/module-carousel/module-carousel.spec.ts +523 -0
- package/examples/module-carousel/module-carousel.ts +131 -0
- package/examples/module-catalog/module-catalog.css +22 -0
- package/examples/module-catalog/module-catalog.html +82 -0
- package/examples/module-catalog/module-catalog.spec.ts +396 -0
- package/examples/module-catalog/module-catalog.ts +37 -0
- package/examples/module-codeblock/module-codeblock.css +95 -0
- package/examples/module-codeblock/module-codeblock.html +28 -0
- package/examples/module-codeblock/module-codeblock.ts +47 -0
- package/examples/module-demo/module-demo.css +13 -0
- package/examples/module-dialog/module-dialog.css +96 -0
- package/examples/module-dialog/module-dialog.html +66 -0
- package/examples/module-dialog/module-dialog.spec.ts +557 -0
- package/examples/module-dialog/module-dialog.ts +81 -0
- package/examples/module-lazyload/mocks/empty.html +1 -0
- package/examples/module-lazyload/mocks/module-with-type.html +27 -0
- package/examples/module-lazyload/mocks/nested-components.html +52 -0
- package/examples/module-lazyload/mocks/recursive.html +20 -0
- package/examples/module-lazyload/mocks/simple-text.html +3 -0
- package/examples/module-lazyload/mocks/snippet.html +57 -0
- package/examples/module-lazyload/mocks/with-styles.html +39 -0
- package/examples/module-lazyload/module-lazyload.html +132 -0
- package/examples/module-lazyload/module-lazyload.spec.ts +734 -0
- package/examples/module-lazyload/module-lazyload.ts +89 -0
- package/examples/module-list/module-list.html +30 -0
- package/examples/module-list/module-list.spec.ts +592 -0
- package/examples/module-list/module-list.ts +99 -0
- package/examples/module-pagination/module-pagination.css +79 -0
- package/examples/module-pagination/module-pagination.html +16 -0
- package/examples/module-pagination/module-pagination.spec.ts +701 -0
- package/examples/module-pagination/module-pagination.ts +88 -0
- package/examples/module-scrollarea/module-scrollarea.css +77 -0
- package/examples/module-scrollarea/module-scrollarea.html +189 -0
- package/examples/module-scrollarea/module-scrollarea.spec.ts +445 -0
- package/examples/module-scrollarea/module-scrollarea.ts +81 -0
- package/examples/module-tabgroup/module-tabgroup.css +55 -0
- package/examples/module-tabgroup/module-tabgroup.html +269 -0
- package/examples/module-tabgroup/module-tabgroup.spec.ts +631 -0
- package/examples/module-tabgroup/module-tabgroup.ts +102 -0
- package/examples/module-toc/module-toc.css +34 -0
- package/examples/module-todo/module-todo.css +84 -0
- package/examples/module-todo/module-todo.html +92 -0
- package/examples/module-todo/module-todo.spec.ts +528 -0
- package/examples/module-todo/module-todo.ts +91 -0
- package/examples/section-hero/section-hero.css +37 -0
- package/examples/section-menu/section-menu.css +81 -0
- package/examples/server.ts +95 -0
- package/examples/test-setup.md +314 -0
- package/index.dev.js +1688 -0
- package/index.dev.ts +127 -0
- package/index.js +3 -0
- package/index.js.map +42 -0
- package/index.ts +127 -0
- package/package.json +64 -0
- package/playwright.config.ts +31 -0
- package/server/BUILD_SYSTEM.md +428 -0
- package/server/SERVER.md +286 -0
- package/server/build.ts +91 -0
- package/server/config.ts +130 -0
- package/server/effects/api.ts +28 -0
- package/server/effects/css.ts +31 -0
- package/server/effects/examples.ts +109 -0
- package/server/effects/js.ts +32 -0
- package/server/effects/menu.ts +34 -0
- package/server/effects/pages.ts +178 -0
- package/server/effects/service-worker.ts +57 -0
- package/server/effects/sitemap.ts +27 -0
- package/server/file-signals.ts +361 -0
- package/server/file-watcher.ts +77 -0
- package/server/io.ts +174 -0
- package/server/layout-engine.ts +470 -0
- package/server/layout-utils.ts +615 -0
- package/server/layouts/api.html +76 -0
- package/server/layouts/base.html +37 -0
- package/server/layouts/blog.html +115 -0
- package/server/layouts/example.html +104 -0
- package/server/layouts/overview.html +165 -0
- package/server/layouts/page.html +36 -0
- package/server/layouts/test.html +24 -0
- package/server/markdoc-helpers.ts +217 -0
- package/server/markdoc.config.ts +29 -0
- package/server/schema/callout.markdoc.ts +17 -0
- package/server/schema/carousel.markdoc.ts +118 -0
- package/server/schema/demo.markdoc.ts +74 -0
- package/server/schema/fence.markdoc.ts +84 -0
- package/server/schema/heading.markdoc.ts +23 -0
- package/server/schema/hero.markdoc.ts +59 -0
- package/server/schema/section.markdoc.ts +10 -0
- package/server/schema/slide.markdoc.ts +17 -0
- package/server/schema/source.markdoc.ts +53 -0
- package/server/schema/tabgroup.markdoc.ts +102 -0
- package/server/serve.ts +635 -0
- package/server/templates/README.md +352 -0
- package/server/templates/constants.ts +236 -0
- package/server/templates/fragments.ts +159 -0
- package/server/templates/hmr.ts +269 -0
- package/server/templates/menu.ts +33 -0
- package/server/templates/performance-hints.ts +94 -0
- package/server/templates/service-worker.ts +403 -0
- package/server/templates/sitemap.ts +57 -0
- package/server/templates/toc.ts +41 -0
- package/server/templates/utils.ts +378 -0
- package/src/component.ts +215 -0
- package/src/context.ts +156 -0
- package/src/effects/attribute.ts +82 -0
- package/src/effects/class.ts +28 -0
- package/src/effects/event.ts +67 -0
- package/src/effects/html.ts +60 -0
- package/src/effects/method.ts +57 -0
- package/src/effects/pass.ts +103 -0
- package/src/effects/property.ts +57 -0
- package/src/effects/style.ts +34 -0
- package/src/effects/text.ts +28 -0
- package/src/effects.ts +412 -0
- package/src/errors.ts +160 -0
- package/src/parsers/boolean.ts +14 -0
- package/src/parsers/json.ts +33 -0
- package/src/parsers/number.ts +55 -0
- package/src/parsers/string.ts +32 -0
- package/src/parsers.ts +90 -0
- package/src/scheduler.ts +47 -0
- package/src/signals/collection.ts +253 -0
- package/src/signals/sensor.ts +131 -0
- package/src/ui.ts +236 -0
- package/src/util.ts +187 -0
- package/tsconfig.json +34 -0
- package/types/examples/basic-button/basic-button.d.ts +16 -0
- package/types/examples/basic-hello/basic-hello.d.ts +18 -0
- package/types/index.d.ts +27 -0
- package/types/index.dev.d.ts +27 -0
- package/types/src/collection.d.ts +27 -0
- package/types/src/component.d.ts +32 -0
- package/types/src/context.d.ts +85 -0
- package/types/src/effects/attribute.d.ts +23 -0
- package/types/src/effects/callMethod.d.ts +23 -0
- package/types/src/effects/class.d.ts +13 -0
- package/types/src/effects/dangerouslySetInnerHTML.d.ts +18 -0
- package/types/src/effects/event.d.ts +18 -0
- package/types/src/effects/html.d.ts +17 -0
- package/types/src/effects/method.d.ts +22 -0
- package/types/src/effects/pass.d.ts +18 -0
- package/types/src/effects/property.d.ts +22 -0
- package/types/src/effects/setAttribute.d.ts +24 -0
- package/types/src/effects/setProperty.d.ts +23 -0
- package/types/src/effects/setStyle.d.ts +14 -0
- package/types/src/effects/setText.d.ts +13 -0
- package/types/src/effects/style.d.ts +13 -0
- package/types/src/effects/text.d.ts +12 -0
- package/types/src/effects/toggleClass.d.ts +14 -0
- package/types/src/effects.d.ts +153 -0
- package/types/src/errors.d.ts +99 -0
- package/types/src/events.d.ts +27 -0
- package/types/src/extractors.d.ts +23 -0
- package/types/src/parsers/boolean.d.ts +10 -0
- package/types/src/parsers/json.d.ts +13 -0
- package/types/src/parsers/number.d.ts +21 -0
- package/types/src/parsers/string.d.ts +19 -0
- package/types/src/parsers.d.ts +41 -0
- package/types/src/scheduler.d.ts +11 -0
- package/types/src/sensor.d.ts +27 -0
- package/types/src/signals/collection.d.ts +32 -0
- package/types/src/signals/sensor.d.ts +27 -0
- package/types/src/ui.d.ts +37 -0
- package/types/src/util.d.ts +65 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for tagged template literals including escaping,
|
|
5
|
+
* validation, and error handling functions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_RESOURCE_TYPE,
|
|
10
|
+
DEVELOPMENT_CONFIG,
|
|
11
|
+
ERROR_MESSAGES,
|
|
12
|
+
MIN_HASH_LENGTHS,
|
|
13
|
+
RESOURCE_TYPE_MAP,
|
|
14
|
+
SELF_CLOSING_TAGS,
|
|
15
|
+
VALIDATION_PATTERNS,
|
|
16
|
+
} from './constants'
|
|
17
|
+
|
|
18
|
+
// HTML template tag with automatic escaping
|
|
19
|
+
export function html(
|
|
20
|
+
strings: TemplateStringsArray,
|
|
21
|
+
...values: unknown[]
|
|
22
|
+
): string {
|
|
23
|
+
return processTemplate(strings, values, 'html')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// XML template tag with automatic escaping
|
|
27
|
+
export function xml(
|
|
28
|
+
strings: TemplateStringsArray,
|
|
29
|
+
...values: unknown[]
|
|
30
|
+
): string {
|
|
31
|
+
return processTemplate(strings, values, 'xml')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// CSS template tag (no escaping needed for CSS)
|
|
35
|
+
export function css(
|
|
36
|
+
strings: TemplateStringsArray,
|
|
37
|
+
...values: unknown[]
|
|
38
|
+
): string {
|
|
39
|
+
return processTemplate(strings, values, 'css')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// JavaScript template tag for code generation
|
|
43
|
+
export function js(
|
|
44
|
+
strings: TemplateStringsArray,
|
|
45
|
+
...values: unknown[]
|
|
46
|
+
): string {
|
|
47
|
+
return processTemplate(strings, values, 'js')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Core template processing function
|
|
51
|
+
function processTemplate(
|
|
52
|
+
strings: TemplateStringsArray,
|
|
53
|
+
values: unknown[],
|
|
54
|
+
type: 'html' | 'xml' | 'css' | 'js',
|
|
55
|
+
): string {
|
|
56
|
+
let result = ''
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < strings.length; i++) {
|
|
59
|
+
result += strings[i]
|
|
60
|
+
|
|
61
|
+
if (i < values.length) {
|
|
62
|
+
const value = values[i]
|
|
63
|
+
|
|
64
|
+
if (value === null || value === undefined) {
|
|
65
|
+
continue
|
|
66
|
+
} else if (Array.isArray(value)) {
|
|
67
|
+
// Handle arrays based on template type
|
|
68
|
+
if (type === 'js') {
|
|
69
|
+
result += value
|
|
70
|
+
.map(item =>
|
|
71
|
+
typeof item === 'string' ? `'${item}'` : String(item),
|
|
72
|
+
)
|
|
73
|
+
.join(',\n\t')
|
|
74
|
+
} else {
|
|
75
|
+
result += value.join('')
|
|
76
|
+
}
|
|
77
|
+
} else if (typeof value === 'string') {
|
|
78
|
+
// Add strings directly (assume they're already safe)
|
|
79
|
+
result += value
|
|
80
|
+
} else {
|
|
81
|
+
// Convert other types to string and escape if needed
|
|
82
|
+
const stringValue = String(value)
|
|
83
|
+
if (type === 'html') {
|
|
84
|
+
result += escapeHtml(stringValue)
|
|
85
|
+
} else if (type === 'xml') {
|
|
86
|
+
result += escapeXml(stringValue)
|
|
87
|
+
} else {
|
|
88
|
+
result += stringValue
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result.trim()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// HTML escaping function
|
|
98
|
+
export function escapeHtml(text: string): string {
|
|
99
|
+
return text
|
|
100
|
+
.replace(/&/g, '&')
|
|
101
|
+
.replace(/</g, '<')
|
|
102
|
+
.replace(/>/g, '>')
|
|
103
|
+
.replace(/"/g, '"')
|
|
104
|
+
.replace(/'/g, ''')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// XML escaping function
|
|
108
|
+
export function escapeXml(text: string): string {
|
|
109
|
+
return text
|
|
110
|
+
.replace(/&/g, '&')
|
|
111
|
+
.replace(/</g, '<')
|
|
112
|
+
.replace(/>/g, '>')
|
|
113
|
+
.replace(/"/g, '"')
|
|
114
|
+
.replace(/'/g, ''')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Generate URL-friendly slug from text
|
|
118
|
+
export function generateSlug(text: string): string {
|
|
119
|
+
return text
|
|
120
|
+
.toLowerCase()
|
|
121
|
+
.replace(/[^\w\s-]/g, '')
|
|
122
|
+
.replace(/\s+/g, '-')
|
|
123
|
+
.replace(/-+/g, '-')
|
|
124
|
+
.trim()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Common sorting utilities
|
|
128
|
+
export interface SortableItem {
|
|
129
|
+
filename: string
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function createOrderedSort<T extends SortableItem>(
|
|
133
|
+
order: string[],
|
|
134
|
+
): (a: T, b: T) => number {
|
|
135
|
+
return (a, b) => {
|
|
136
|
+
const aName = a.filename.replace('.html', '').replace('.md', '')
|
|
137
|
+
const bName = b.filename.replace('.html', '').replace('.md', '')
|
|
138
|
+
|
|
139
|
+
const aIndex = order.indexOf(aName)
|
|
140
|
+
const bIndex = order.indexOf(bName)
|
|
141
|
+
|
|
142
|
+
// If both items are in order, sort by their order
|
|
143
|
+
if (aIndex !== -1 && bIndex !== -1) {
|
|
144
|
+
return aIndex - bIndex
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// If only one item is in order, prioritize it
|
|
148
|
+
if (aIndex !== -1) return -1
|
|
149
|
+
if (bIndex !== -1) return 1
|
|
150
|
+
|
|
151
|
+
// If neither item is in order, sort alphabetically
|
|
152
|
+
return aName.localeCompare(bName)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Common validation patterns
|
|
157
|
+
export function validateHashString(
|
|
158
|
+
hash: string,
|
|
159
|
+
minLength: number = MIN_HASH_LENGTHS.ASSET_HASH,
|
|
160
|
+
): boolean {
|
|
161
|
+
return VALIDATION_PATTERNS.HEX_HASH.test(hash) && hash.length >= minLength
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function validateRequiredString(
|
|
165
|
+
value: unknown,
|
|
166
|
+
fieldName: string,
|
|
167
|
+
): string[] {
|
|
168
|
+
const errors: string[] = []
|
|
169
|
+
if (!value || typeof value !== 'string') {
|
|
170
|
+
errors.push(ERROR_MESSAGES.MISSING_REQUIRED_FIELD(fieldName))
|
|
171
|
+
}
|
|
172
|
+
return errors
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function validateArrayField<T>(
|
|
176
|
+
value: unknown,
|
|
177
|
+
fieldName: string,
|
|
178
|
+
validator?: (item: T) => boolean,
|
|
179
|
+
): string[] {
|
|
180
|
+
const errors: string[] = []
|
|
181
|
+
if (value !== undefined && !Array.isArray(value)) {
|
|
182
|
+
errors.push(ERROR_MESSAGES.INVALID_TYPE(fieldName, 'array'))
|
|
183
|
+
} else if (value && validator) {
|
|
184
|
+
const invalidItems = (value as T[]).filter(item => !validator(item))
|
|
185
|
+
if (invalidItems.length > 0) {
|
|
186
|
+
errors.push(`${fieldName} contains invalid items`)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return errors
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Error boundary wrapper for template functions
|
|
193
|
+
export function safeRender<T extends (...args: any[]) => string>(
|
|
194
|
+
templateFn: T,
|
|
195
|
+
fallback: string = '',
|
|
196
|
+
onError?: (error: Error) => void,
|
|
197
|
+
): T {
|
|
198
|
+
return ((...args: Parameters<T>) => {
|
|
199
|
+
try {
|
|
200
|
+
return templateFn(...args)
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('Template rendering error:', error)
|
|
203
|
+
onError?.(error as Error)
|
|
204
|
+
return fallback
|
|
205
|
+
}
|
|
206
|
+
}) as T
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Conditional rendering helper
|
|
210
|
+
export function when<T>(condition: boolean, template: () => T): T | '' {
|
|
211
|
+
return condition ? template() : ('' as T | '')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Inverse conditional rendering helper
|
|
215
|
+
export function unless<T>(condition: boolean, template: () => T): T | '' {
|
|
216
|
+
return !condition ? template() : ('' as T | '')
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Safe array mapping with error handling
|
|
220
|
+
export function mapSafe<T, R>(
|
|
221
|
+
items: T[],
|
|
222
|
+
mapper: (item: T, index: number) => R,
|
|
223
|
+
separator: string = '',
|
|
224
|
+
): string {
|
|
225
|
+
try {
|
|
226
|
+
return items.map(mapper).join(separator)
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('Template mapping error:', error)
|
|
229
|
+
return ''
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Template composition helper
|
|
234
|
+
export function fragment(...templates: string[]): string {
|
|
235
|
+
return templates.filter(Boolean).join('')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Indent template content
|
|
239
|
+
export function indent(template: string, spaces: number = 2): string {
|
|
240
|
+
const indentation = ' '.repeat(spaces)
|
|
241
|
+
return template
|
|
242
|
+
.split('\n')
|
|
243
|
+
.map(line => (line.trim() ? indentation + line : line))
|
|
244
|
+
.join('\n')
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Minify HTML/XML by removing extra whitespace
|
|
248
|
+
export function minify(template: string): string {
|
|
249
|
+
return template.replace(/\s+/g, ' ').replace(/>\s+</g, '><').trim()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Basic template validation
|
|
253
|
+
export interface ValidationResult {
|
|
254
|
+
valid: boolean
|
|
255
|
+
errors: string[]
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function validateHtml(template: string): ValidationResult {
|
|
259
|
+
const errors: string[] = []
|
|
260
|
+
|
|
261
|
+
// Basic validation checks
|
|
262
|
+
const openTags = template.match(/<[^/][^>]*>/g) || []
|
|
263
|
+
const closeTags = template.match(/<\/[^>]*>/g) || []
|
|
264
|
+
|
|
265
|
+
// Self-closing tags that don't need closing tags
|
|
266
|
+
const selfClosingTags = SELF_CLOSING_TAGS
|
|
267
|
+
|
|
268
|
+
// Check for unclosed tags (simplified check)
|
|
269
|
+
const openTagNames = openTags
|
|
270
|
+
.map(tag => tag.match(/<(\w+)/)?.[1])
|
|
271
|
+
.filter(Boolean)
|
|
272
|
+
.filter(tag => !selfClosingTags.includes(tag!))
|
|
273
|
+
|
|
274
|
+
const closeTagNames = closeTags
|
|
275
|
+
.map(tag => tag.match(/<\/(\w+)/)?.[1])
|
|
276
|
+
.filter(Boolean)
|
|
277
|
+
|
|
278
|
+
if (openTagNames.length !== closeTagNames.length) {
|
|
279
|
+
errors.push('Mismatched opening and closing tags')
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Check for common HTML issues
|
|
283
|
+
if (template.includes('< ')) {
|
|
284
|
+
errors.push('Space after opening bracket detected')
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (template.includes(' >')) {
|
|
288
|
+
errors.push('Space before closing bracket detected')
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return { valid: errors.length === 0, errors }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export function validateXml(template: string): ValidationResult {
|
|
295
|
+
const errors: string[] = []
|
|
296
|
+
|
|
297
|
+
// Check for XML declaration
|
|
298
|
+
if (!template.includes('<?xml')) {
|
|
299
|
+
errors.push('Missing XML declaration')
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Check for proper encoding
|
|
303
|
+
if (template.includes('<?xml') && !template.includes('encoding=')) {
|
|
304
|
+
errors.push('Missing encoding declaration in XML')
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Basic tag matching (reuse HTML validation logic)
|
|
308
|
+
const htmlValidation = validateHtml(template)
|
|
309
|
+
errors.push(...htmlValidation.errors)
|
|
310
|
+
|
|
311
|
+
return { valid: errors.length === 0, errors }
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Development helpers
|
|
315
|
+
export function debugTemplate(name: string, template: string): string {
|
|
316
|
+
if (DEVELOPMENT_CONFIG.ENABLE_LOGGING) {
|
|
317
|
+
console.log(
|
|
318
|
+
`Template [${name}]:`,
|
|
319
|
+
template.substring(0, DEVELOPMENT_CONFIG.MAX_TEMPLATE_LENGTH_FOR_LOGGING)
|
|
320
|
+
+ '...',
|
|
321
|
+
)
|
|
322
|
+
}
|
|
323
|
+
return template
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Performance measurement for template generation
|
|
327
|
+
export function measureTemplate<T extends (...args: any[]) => string>(
|
|
328
|
+
name: string,
|
|
329
|
+
templateFn: T,
|
|
330
|
+
): T {
|
|
331
|
+
return ((...args: Parameters<T>) => {
|
|
332
|
+
if (!DEVELOPMENT_CONFIG.ENABLE_PERFORMANCE_MONITORING) {
|
|
333
|
+
return templateFn(...args)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const start = performance.now()
|
|
337
|
+
const result = templateFn(...args)
|
|
338
|
+
const end = performance.now()
|
|
339
|
+
|
|
340
|
+
const renderTime = end - start
|
|
341
|
+
if (DEVELOPMENT_CONFIG.ENABLE_LOGGING) {
|
|
342
|
+
console.log(`Template [${name}] rendered in ${renderTime.toFixed(2)}ms`)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return result
|
|
346
|
+
}) as T
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Template composition with validation
|
|
350
|
+
export function composeTemplates(
|
|
351
|
+
...templates: Array<string | (() => string)>
|
|
352
|
+
): string {
|
|
353
|
+
return templates
|
|
354
|
+
.map(template => (typeof template === 'function' ? template() : template))
|
|
355
|
+
.filter(Boolean)
|
|
356
|
+
.join('')
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Enhanced validation with multiple checks
|
|
360
|
+
export function createValidator<T>(
|
|
361
|
+
checks: Array<(value: T) => string[]>,
|
|
362
|
+
): (value: T) => ValidationResult {
|
|
363
|
+
return (value: T) => {
|
|
364
|
+
const errors = checks.flatMap(check => check(value))
|
|
365
|
+
return { valid: errors.length === 0, errors }
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Resource type detection utility (moved from performance-hints)
|
|
370
|
+
export function getResourceType(url: string): string {
|
|
371
|
+
const extension = '.' + url.split('.').pop()?.toLowerCase()
|
|
372
|
+
return (RESOURCE_TYPE_MAP as any)[extension] || DEFAULT_RESOURCE_TYPE
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Check if resource requires crossorigin attribute
|
|
376
|
+
export function requiresCrossorigin(url: string): boolean {
|
|
377
|
+
return url.endsWith('.woff') || url.endsWith('.woff2')
|
|
378
|
+
}
|
package/src/component.ts
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ComputedCallback,
|
|
3
|
+
createComputed,
|
|
4
|
+
createState,
|
|
5
|
+
isComputed,
|
|
6
|
+
isComputedCallback,
|
|
7
|
+
isFunction,
|
|
8
|
+
isMutableSignal,
|
|
9
|
+
isSignal,
|
|
10
|
+
isState,
|
|
11
|
+
isStore,
|
|
12
|
+
type MaybeCleanup,
|
|
13
|
+
type Signal,
|
|
14
|
+
UNSET,
|
|
15
|
+
} from '@zeix/cause-effect'
|
|
16
|
+
|
|
17
|
+
import { type Effects, runEffects } from './effects'
|
|
18
|
+
import { InvalidComponentNameError, InvalidPropertyNameError } from './errors'
|
|
19
|
+
import { isParser, type Parser, type Reader } from './parsers'
|
|
20
|
+
import { type ElementQueries, getHelpers, type UI } from './ui'
|
|
21
|
+
import { validatePropertyName } from './util'
|
|
22
|
+
|
|
23
|
+
/* === Types === */
|
|
24
|
+
|
|
25
|
+
type ReservedWords =
|
|
26
|
+
| 'constructor'
|
|
27
|
+
| 'prototype'
|
|
28
|
+
| '__proto__'
|
|
29
|
+
| 'toString'
|
|
30
|
+
| 'valueOf'
|
|
31
|
+
| 'hasOwnProperty'
|
|
32
|
+
| 'isPrototypeOf'
|
|
33
|
+
| 'propertyIsEnumerable'
|
|
34
|
+
| 'toLocaleString'
|
|
35
|
+
|
|
36
|
+
type ComponentProp = Exclude<string, keyof HTMLElement | ReservedWords>
|
|
37
|
+
type ComponentProps = Record<ComponentProp, NonNullable<unknown>>
|
|
38
|
+
|
|
39
|
+
type Component<P extends ComponentProps> = HTMLElement & P
|
|
40
|
+
type ComponentUI<P extends ComponentProps, U extends UI> = U & {
|
|
41
|
+
host: Component<P>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type ComponentSetup<P extends ComponentProps, U extends UI> = (
|
|
45
|
+
ui: ComponentUI<P, U>,
|
|
46
|
+
) => Effects<P, ComponentUI<P, U>>
|
|
47
|
+
|
|
48
|
+
type MethodProducer<P extends ComponentProps, U extends UI> = (
|
|
49
|
+
ui: U & { host: Component<P> },
|
|
50
|
+
) => void
|
|
51
|
+
|
|
52
|
+
type Initializers<P extends ComponentProps, U extends UI> = {
|
|
53
|
+
[K in keyof P]?:
|
|
54
|
+
| P[K]
|
|
55
|
+
| Signal<P[K]>
|
|
56
|
+
| Parser<P[K], ComponentUI<P, U>>
|
|
57
|
+
| Reader<MaybeSignal<P[K]>, ComponentUI<P, U>>
|
|
58
|
+
| MethodProducer<P, ComponentUI<P, U>>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type MaybeSignal<T extends {}> = T | Signal<T> | ComputedCallback<T>
|
|
62
|
+
|
|
63
|
+
/* === Exported Functions === */
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Define a component with dependency resolution and setup function (connectedCallback)
|
|
67
|
+
*
|
|
68
|
+
* @since 0.15.0
|
|
69
|
+
* @param {string} name - Custom element name
|
|
70
|
+
* @param {object} props - Component properties
|
|
71
|
+
* @param {function} select - Function to select UI elements
|
|
72
|
+
* @param {function} setup - Setup function
|
|
73
|
+
* @throws {InvalidComponentNameError} If component name is invalid
|
|
74
|
+
* @throws {InvalidPropertyNameError} If property name is invalid
|
|
75
|
+
*/
|
|
76
|
+
function defineComponent<P extends ComponentProps, U extends UI = {}>(
|
|
77
|
+
name: string,
|
|
78
|
+
props: Initializers<P, U> = {} as Initializers<P, U>,
|
|
79
|
+
select: (elementQueries: ElementQueries) => U = () => ({}) as U,
|
|
80
|
+
setup: (ui: ComponentUI<P, U>) => Effects<P, ComponentUI<P, U>> = () => ({}),
|
|
81
|
+
): Component<P> {
|
|
82
|
+
if (!name.includes('-') || !name.match(/^[a-z][a-z0-9-]*$/))
|
|
83
|
+
throw new InvalidComponentNameError(name)
|
|
84
|
+
for (const prop of Object.keys(props)) {
|
|
85
|
+
const error = validatePropertyName(prop)
|
|
86
|
+
if (error) throw new InvalidPropertyNameError(name, prop, error)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
class Truc extends HTMLElement {
|
|
90
|
+
debug?: boolean
|
|
91
|
+
#ui: ComponentUI<P, U> | undefined
|
|
92
|
+
#signals = {} as { [K in keyof P]: Signal<P[K]> }
|
|
93
|
+
#cleanup: MaybeCleanup
|
|
94
|
+
|
|
95
|
+
static observedAttributes =
|
|
96
|
+
Object.entries(props)
|
|
97
|
+
?.filter(([, initializer]) => isParser(initializer))
|
|
98
|
+
.map(([prop]) => prop) ?? []
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Native callback when the custom element is first connected to the document
|
|
102
|
+
*/
|
|
103
|
+
connectedCallback() {
|
|
104
|
+
// Initialize UI
|
|
105
|
+
const [elementQueries, resolveDependencies] = getHelpers(this)
|
|
106
|
+
const ui = {
|
|
107
|
+
...select(elementQueries),
|
|
108
|
+
host: this as unknown as Component<P>,
|
|
109
|
+
}
|
|
110
|
+
this.#ui = ui
|
|
111
|
+
Object.freeze(this.#ui)
|
|
112
|
+
|
|
113
|
+
// Initialize signals
|
|
114
|
+
const isReaderOrMethodProducer = <K extends keyof P & string>(
|
|
115
|
+
value: unknown,
|
|
116
|
+
): value is
|
|
117
|
+
| Reader<P[K], ComponentUI<P, U>>
|
|
118
|
+
| MethodProducer<P, ComponentUI<P, U>> => {
|
|
119
|
+
return isFunction(value)
|
|
120
|
+
}
|
|
121
|
+
const createSignal = <K extends keyof P & string>(
|
|
122
|
+
key: K,
|
|
123
|
+
initializer: Initializers<P, U>[K],
|
|
124
|
+
) => {
|
|
125
|
+
const result = isParser<P[K], ComponentUI<P, U>>(initializer)
|
|
126
|
+
? initializer(ui, this.getAttribute(key))
|
|
127
|
+
: isReaderOrMethodProducer<K>(initializer)
|
|
128
|
+
? initializer(ui)
|
|
129
|
+
: (initializer as MaybeSignal<P[K]>)
|
|
130
|
+
if (result != null) this.#setAccessor(key, result)
|
|
131
|
+
}
|
|
132
|
+
for (const [prop, initializer] of Object.entries(props)) {
|
|
133
|
+
if (initializer == null || prop in this) continue
|
|
134
|
+
createSignal(prop, initializer)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Resolve dependencies and run setup function
|
|
138
|
+
resolveDependencies(() => {
|
|
139
|
+
this.#cleanup = runEffects(ui, setup(ui))
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Native callback when the custom element is disconnected from the document
|
|
145
|
+
*/
|
|
146
|
+
disconnectedCallback() {
|
|
147
|
+
if (isFunction(this.#cleanup)) this.#cleanup()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Native callback when an observed attribute of the custom element changes
|
|
152
|
+
*
|
|
153
|
+
* @param {K} name - Name of the modified attribute
|
|
154
|
+
* @param {string | null} oldValue - Old value of the modified attribute
|
|
155
|
+
* @param {string | null} newValue - New value of the modified attribute
|
|
156
|
+
*/
|
|
157
|
+
attributeChangedCallback<K extends keyof P>(
|
|
158
|
+
name: K,
|
|
159
|
+
oldValue: string | null,
|
|
160
|
+
newValue: string | null,
|
|
161
|
+
) {
|
|
162
|
+
// Not connected yet, unchanged value or controlled by computed
|
|
163
|
+
if (!this.#ui || newValue === oldValue || isComputed(this.#signals[name]))
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
// Check whether we have a parser for the attribute
|
|
167
|
+
const parser = props[name]
|
|
168
|
+
if (!isParser<P[K], ComponentUI<P, U>>(parser)) return
|
|
169
|
+
|
|
170
|
+
const parsed = parser(this.#ui, newValue, oldValue)
|
|
171
|
+
if (name in this) (this as unknown as P)[name] = parsed
|
|
172
|
+
else this.#setAccessor(name, parsed)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Set the signal for a given key
|
|
177
|
+
*
|
|
178
|
+
* @since 0.15.0
|
|
179
|
+
* @param {K} key - Key to set accessor for
|
|
180
|
+
* @param {MaybeSignal<P[K]>} value - Initial value, signal or computed callback to create signal
|
|
181
|
+
*/
|
|
182
|
+
#setAccessor<K extends keyof P>(key: K, value: MaybeSignal<P[K]>): void {
|
|
183
|
+
const signal = isSignal(value)
|
|
184
|
+
? value
|
|
185
|
+
: isComputedCallback(value)
|
|
186
|
+
? createComputed(value)
|
|
187
|
+
: createState(value)
|
|
188
|
+
const prev = this.#signals[key]
|
|
189
|
+
const mutable = isMutableSignal(signal)
|
|
190
|
+
this.#signals[key] = signal as Signal<P[K]>
|
|
191
|
+
Object.defineProperty(this, key, {
|
|
192
|
+
get: signal.get,
|
|
193
|
+
set: mutable ? signal.set : undefined,
|
|
194
|
+
enumerable: true,
|
|
195
|
+
configurable: mutable,
|
|
196
|
+
})
|
|
197
|
+
if ((prev && isState(prev)) || isStore(prev)) prev.set(UNSET)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
customElements.define(name, Truc)
|
|
202
|
+
return customElements.get(name) as unknown as Component<P>
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export {
|
|
206
|
+
type Component,
|
|
207
|
+
type ComponentProp,
|
|
208
|
+
type ComponentProps,
|
|
209
|
+
type ComponentUI,
|
|
210
|
+
type ComponentSetup,
|
|
211
|
+
type MaybeSignal,
|
|
212
|
+
type ReservedWords,
|
|
213
|
+
type Initializers,
|
|
214
|
+
defineComponent,
|
|
215
|
+
}
|