From 05b68f2c7e60540fef9b69981c5b342d57e90a65 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 18:30:38 +1000 Subject: [PATCH 1/8] update README.md: update links to make them absolute ensures links work when docs index page is generated from readme --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7414c2d..0b1c3ee 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ ## About This package provides support for writing reusable Alpine.js components in Typescript. Supporting Alpine's existing model of registering any generic object/type and user-defined -classes inheriting from the [AlpineComponent class](./src/Component.ts) which provides type +classes inheriting from the [AlpineComponent class](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/src/Component.ts) which provides type definitions for Alpine's magics. This enables your IDE to give useful auto-completion without any extra plugins/extensions and gives Typescript a better understanding of your component code, producing useful compilation/transpilation errors before testing. @@ -122,10 +122,10 @@ This package is designed to be easily integrated into existing projects. You can migrating complex, logic heavy components into classes without worrying about the simple stuff that makes Alpine so powerful. -Take a look at the provided example project [here.](./examples/project) +Take a look at the provided example project [here.](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/examples/project) ##### Project Setup -You'll want to start by [installing](#installation) the package then add these lines to your +You'll want to start by [installing](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/README.md#installation) the package then add these lines to your client script: ```typescript import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; @@ -174,10 +174,10 @@ You can now use the component in your HTML with `x-data="myComponent('Hello Worl #### In Packages The main purpose of this package is to easily distribute components in their own package. -Take a look at the provided example components package [here.](./examples/package) +Take a look at the provided example components package [here.](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/examples/package) ##### Package Setup -The easiest way to start distributing your components is to copy everything from the [package example](./examples/package) +The easiest way to start distributing your components is to copy everything from the [package example](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/examples/package) directory and start writing your components. Manual setup requires a project with `typescript` installed to compile the code to javascript: @@ -325,7 +325,7 @@ Any function that satisfies this type requirement: ```typescript type KnownGenericConstructor = (...args: any[]) => T; ``` -Will be accepted as a component constructor. The [signature](./src/Store.ts#L101) for registering components of this type is: +Will be accepted as a component constructor. The [signature](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/src/Store.ts#L101) for registering components of this type is: ```typescript /** * Register a generic object (alpine data) as a component. @@ -369,11 +369,11 @@ document.addEventListener('alpine-components:init', () => { ##### Typescript Classes The main purpose of this package is to use class definitions as Alpine components. Any class -inheriting from [AlpineComponent](./src/Component#L45) is accepted. +inheriting from [AlpineComponent](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/src/Component#L45) is accepted. Both register function definitions accept constructor functions for these classes. -Explicit register class constructor [signature](src/Store.ts#L109): +Explicit register class constructor [signature](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/src/Store.ts#L109): ```typescript /** * Register a class inheriting from {@link Impl.AlpineComponent} as a component. @@ -385,7 +385,7 @@ register(component: Impl.KnownClassConstructor(name: string, component: Impl.KnownConstructor): void; ``` -The component parameters prototype is checked for inheritance from the [AlpineComponent](./src/Component#L45) +The component parameters prototype is checked for inheritance from the [AlpineComponent](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/src/Component#L45) class and handled accordingly. #### Using Components From a150b81964f07bd2c77ff50d9c83a6aa12a07c30 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 22:17:34 +1000 Subject: [PATCH 2/8] Store.ts transformToAlpineData(): copy methods from inherited classes Allows extending components and inheriting their methods for the alpine component object. --- src/Store.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Store.ts b/src/Store.ts index a4ab9d3..e639d4d 100644 --- a/src/Store.ts +++ b/src/Store.ts @@ -200,8 +200,22 @@ export class ComponentStore { * @param instance The object to copy functions and properties from */ export function transformToAlpineData(instance: T): object { + let methodNames: string[] = []; + for ( + let prototype = Object.getPrototypeOf(instance); + prototype.constructor.name !== 'Object'; + prototype = Object.getPrototypeOf(prototype) + ) { + Object.getOwnPropertyNames(prototype).forEach((name: string) => { + if (methodNames.includes(name)) { + return; + } + methodNames.push(name); + }); + } + return [ - ...Object.getOwnPropertyNames(Object.getPrototypeOf(instance)), // methods + ...methodNames, // methods ...Object.getOwnPropertyNames(instance) // properties ].reduce((obj, name) => { // @ts-ignore From b3ba7b488e6d13b20d326d366d6760249a59375e Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 22:19:07 +1000 Subject: [PATCH 3/8] code cleanup --- examples/package/index.ts | 6 +++--- examples/package/src/Plugin.ts | 2 +- examples/package/src/components/AlertComponent.ts | 2 +- examples/package/src/components/ToggleComponent.ts | 2 +- examples/project/src/components/AlertComponent.ts | 2 +- examples/project/src/components/ToggleComponent.ts | 2 +- examples/project/src/index.ts | 4 ++-- index.ts | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/package/index.ts b/examples/package/index.ts index 0c14d09..c1dc15f 100644 --- a/examples/package/index.ts +++ b/examples/package/index.ts @@ -2,8 +2,8 @@ * Export functions and types. */ -export { AlertComponent } from './src/components/AlertComponent'; -export { ToggleComponent } from './src/components/ToggleComponent'; +export {AlertComponent} from './src/components/AlertComponent'; +export {ToggleComponent} from './src/components/ToggleComponent'; export { MyComponents, @@ -14,5 +14,5 @@ export { /** * Alpine plugin as default export. */ -import { myPlugin } from './src/Plugin'; +import {myPlugin} from './src/Plugin'; export default myPlugin; diff --git a/examples/package/src/Plugin.ts b/examples/package/src/Plugin.ts index 9b91822..61c0e09 100644 --- a/examples/package/src/Plugin.ts +++ b/examples/package/src/Plugin.ts @@ -92,7 +92,7 @@ export namespace MyComponents { if (opts.bootstrapComponents) { AlpineComponents.bootstrap(opts, alpine); } - }; + } } diff --git a/examples/package/src/components/AlertComponent.ts b/examples/package/src/components/AlertComponent.ts index ec96dbe..dfa7977 100644 --- a/examples/package/src/components/AlertComponent.ts +++ b/examples/package/src/components/AlertComponent.ts @@ -1,4 +1,4 @@ -import { AlpineComponent } from "@nxtlvlsoftware/alpine-typescript"; +import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; export const DefaultAlertComponentName = 'alert'; diff --git a/examples/package/src/components/ToggleComponent.ts b/examples/package/src/components/ToggleComponent.ts index 18e61ef..23c0ba8 100644 --- a/examples/package/src/components/ToggleComponent.ts +++ b/examples/package/src/components/ToggleComponent.ts @@ -1,4 +1,4 @@ -import { AlpineComponent } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponent} from '@nxtlvlsoftware/alpine-typescript'; export const DefaultToggleComponentName: string = 'toggle'; diff --git a/examples/project/src/components/AlertComponent.ts b/examples/project/src/components/AlertComponent.ts index 346f03f..47e5d74 100644 --- a/examples/project/src/components/AlertComponent.ts +++ b/examples/project/src/components/AlertComponent.ts @@ -1,4 +1,4 @@ -import { AlpineComponent } from "@nxtlvlsoftware/alpine-typescript"; +import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; /** * Simple alert component for closing the default alert. diff --git a/examples/project/src/components/ToggleComponent.ts b/examples/project/src/components/ToggleComponent.ts index 9ee77df..5de28f1 100644 --- a/examples/project/src/components/ToggleComponent.ts +++ b/examples/project/src/components/ToggleComponent.ts @@ -1,4 +1,4 @@ -import { AlpineComponent } from "@nxtlvlsoftware/alpine-typescript"; +import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; /** * Simple toggle that switches between on/off values. diff --git a/examples/project/src/index.ts b/examples/project/src/index.ts index 376e9a5..4100a85 100644 --- a/examples/project/src/index.ts +++ b/examples/project/src/index.ts @@ -4,10 +4,10 @@ import Alpine from 'alpinejs'; window.Alpine = Alpine; -import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponents} from '@nxtlvlsoftware/alpine-typescript'; import {AlertComponent} from "./components/AlertComponent"; -import { ToggleComponent } from "./components/ToggleComponent"; +import {ToggleComponent} from "./components/ToggleComponent"; AlpineComponents.bootstrap({ components: { diff --git a/index.ts b/index.ts index 7312553..cdd4f46 100644 --- a/index.ts +++ b/index.ts @@ -29,5 +29,5 @@ export { /** * Alpine plugin as default export. */ -import { componentsPlugin } from './src/Plugin'; +import {componentsPlugin} from './src/Plugin'; export default componentsPlugin; From 6f2b15c69006dd282fa044e19e3a987aaa0aa356 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 22:21:53 +1000 Subject: [PATCH 4/8] Component.ts - AlpineComponent: remove template Removes unnecessary class template param that was used for $data and $watch declarations. Makes defining component classes even easier. --- examples/package/src/components/AlertComponent.ts | 2 +- examples/package/src/components/ToggleComponent.ts | 2 +- examples/project/src/components/AlertComponent.ts | 2 +- examples/project/src/components/ToggleComponent.ts | 2 +- src/Component.ts | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/package/src/components/AlertComponent.ts b/examples/package/src/components/AlertComponent.ts index dfa7977..3df7285 100644 --- a/examples/package/src/components/AlertComponent.ts +++ b/examples/package/src/components/AlertComponent.ts @@ -8,7 +8,7 @@ export const DefaultAlertComponentName = 'alert'; * All properties and events are prefixed with 'alert' to make * it clear which variables belong to the component in the HTML. */ -export class AlertComponent extends AlpineComponent { +export class AlertComponent extends AlpineComponent { constructor( public alertState: boolean = false diff --git a/examples/package/src/components/ToggleComponent.ts b/examples/package/src/components/ToggleComponent.ts index 23c0ba8..d78aad4 100644 --- a/examples/package/src/components/ToggleComponent.ts +++ b/examples/package/src/components/ToggleComponent.ts @@ -8,7 +8,7 @@ export const DefaultToggleComponentName: string = 'toggle'; * All properties and events are prefixed with 'switch' to make * it clear which variables belong to the component in the HTML. */ -export class ToggleComponent extends AlpineComponent { +export class ToggleComponent extends AlpineComponent { constructor( public toggleState: boolean = false diff --git a/examples/project/src/components/AlertComponent.ts b/examples/project/src/components/AlertComponent.ts index 47e5d74..2b6ba6f 100644 --- a/examples/project/src/components/AlertComponent.ts +++ b/examples/project/src/components/AlertComponent.ts @@ -6,7 +6,7 @@ import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; * All properties and events are prefixed with 'alert' to make * it clear which variables belong to the component in the HTML. */ -export class AlertComponent extends AlpineComponent { +export class AlertComponent extends AlpineComponent { constructor( public alertState: boolean = false diff --git a/examples/project/src/components/ToggleComponent.ts b/examples/project/src/components/ToggleComponent.ts index 5de28f1..ceada28 100644 --- a/examples/project/src/components/ToggleComponent.ts +++ b/examples/project/src/components/ToggleComponent.ts @@ -6,7 +6,7 @@ import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; * All properties and events are prefixed with 'toggle' to make * it clear which variables belong to the component in the HTML. */ -export class ToggleComponent extends AlpineComponent { +export class ToggleComponent extends AlpineComponent { constructor( public toggleState: boolean = false diff --git a/src/Component.ts b/src/Component.ts index 3ff7809..c46d828 100644 --- a/src/Component.ts +++ b/src/Component.ts @@ -42,12 +42,12 @@ export declare type AlpineData = AlpineDataContext | string | number | boolean; * * Property declarations copied from @types/alpinejs. */ -export abstract class AlpineComponent implements AlpineDataContext { +export abstract class AlpineComponent implements AlpineDataContext { /** * Access to current Alpine data. */ - declare $data: T; + declare $data: this; /** * Retrieve the current DOM node. @@ -93,7 +93,7 @@ export abstract class AlpineComponent implements AlpineDataContext { * @param property the component property * @param callback a callback that will fire when a given property is changed */ - declare $watch: ( + declare $watch: ( property: K, callback: (newValue: V, oldValue: V) => void, ) => void; From 2bc60fe056c0d237639c5e1ecc3b25264c7af251 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 22:24:17 +1000 Subject: [PATCH 5/8] update README.md: update and cleanup examples * Update examples with latest API changes. * Formatting cleanup. * Add missing API usage alternatives. --- README.md | 81 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 0b1c3ee..98ec6b9 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,27 @@ import Alpine from 'alpinejs'; window.Alpine = Alpine; -import { componentPlugin } from '@nxtlvlsoftware/alpine-typescript'; +import {componentPlugin} from '@nxtlvlsoftware/alpine-typescript'; -Alpine.plugin(componentPlugin); -Alpine.start(); +window.addEventListener('alpine-components:init', () => { + // window.Alpine.Components.register(); +}); + +window.Alpine.plugin(componentPlugin); +window.Alpine.start(); +``` +Using the default export: +```typescript +import Alpine from 'alpinejs'; + +window.Alpine = Alpine; + +window.addEventListener('alpine-components:init', () => { + // window.Alpine.Components.register(); +}); + +window.Alpine.plugin(require('@nxtlvlsoftware/alpine-typescript')); +window.Alpine.start(); ``` This is the easiest way to get started in existing projects but doesn't offer a way to modify the default options provided the package. @@ -79,16 +96,22 @@ import Alpine from 'alpinejs'; window.Alpine = Alpine; -import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponents} from '@nxtlvlsoftware/alpine-typescript'; -AlpineComponents.bootstrap(); +AlpineComponents.bootstrap({ + components: { + // + }}); ``` The default options are best suited to new projects and automatically starts Alpine for you. To integrate into existing projects seamlessly, just pass in an options object: ```typescript -import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponents} from '@nxtlvlsoftware/alpine-typescript'; AlpineComponents.bootstrap({ + components: { + // + }, startAlpine: false, logErrors: true // should only enable this in dev enviroments for debugging }); // pass the Alpine object explicity if you aren't following the default convention @@ -102,10 +125,13 @@ import Alpine from 'alpinejs'; let myAlpine = Alpine; -import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponents} from '@nxtlvlsoftware/alpine-typescript'; const isProduction = () => false; // equivelent would be injected/definied server-side by your framework AlpineComponents.bootstrap({ + components: { + // + }, logErrors: !isProduction() }, myAlpine); @@ -128,7 +154,7 @@ Take a look at the provided example project [here.](https://github.com/NxtLvLSof You'll want to start by [installing](https://github.com/NxtLvLSoftware/alpine-typescript/blob/dev/README.md#installation) the package then add these lines to your client script: ```typescript -import { AlpineComponents } from '@nxtlvlsoftware/alpine-typescript'; +import {AlpineComponents} from '@nxtlvlsoftware/alpine-typescript'; AlpineComponents.bootstrap({ components: { @@ -142,9 +168,9 @@ AlpineComponents.bootstrap({ Now create a directory for your components, something like `components` and create a new Typescript file `components/MyComponent.ts` containing: ```typescript -import { AlpineComponent } from "@nxtlvlsoftware/alpine-typescript"; +import {AlpineComponent} from "@nxtlvlsoftware/alpine-typescript"; -export class MyComponent extends AlpineComponent { +export class MyComponent extends AlpineComponent { constructor( public required: string, @@ -161,7 +187,7 @@ export class MyComponent extends AlpineComponent { ``` Register your new component in the `AlpineComponents.bootstrap()` method call: ```typescript -import { MyComponent } from './components/MyComponent'; +import {MyComponent} from './components/MyComponent'; AlpineComponents.bootstrap({ components: { @@ -288,13 +314,12 @@ export namespace MyComponents { // Support loading our components with a standardized call to Alpine.plugin(). export function myPlugin(alpine: Globals.Alpine): void { - MyComponents.bootstrap( - { - // can't assume we're the only ones using the component library - bootstrapComponents: false, - // definitely not the only ones using alpine if we're being used as a plugin here - startAlpine: false - }, alpine); + MyComponents.bootstrap({ + // can't assume we're the only ones using the component library + bootstrapComponents: false, + // definitely not the only ones using alpine if we're being used as a plugin here + startAlpine: false + }, alpine); } ``` Export the `MyComponent` namespace and `myPlugin()` function as default from `index.ts`: @@ -307,7 +332,7 @@ export { /** * Alpine plugin as default export. */ -import { myPlugin } from './src/Plugin'; +import {myPlugin} from './src/Plugin'; export default myPlugin; ``` Now you can start writing your components. Remember to create the `src/components/MyComponent.ts` @@ -364,6 +389,11 @@ Or by listening for the `alpine-components:init` on the `document` global: document.addEventListener('alpine-components:init', () => { window.Alpine.Components.register('noArgs', noArgsComponent); window.Alpine.Components.register('singleValue', singleValueComponent); + // or registerAll() when component names are hardcoded + window.Alpine.Components.registerAll({ + noArgs: noArgsComponent, + singleValue: singleValueComponent + }); }); ``` @@ -417,21 +447,20 @@ Here's the contrived `dropdown` example re-written to use a class: window.Alpine = Alpine; - import { AlpineComponents, AlpineComponent } from '@nxtlvlsoftware/alpine-typescript'; + import {AlpineComponents, AlpineComponent} from '@nxtlvlsoftware/alpine-typescript'; class ToggleComponent extends AlpineComponent { constructor( - open: boolean = false + public open: boolean = false ) { super(); } - toggle() { this.open = !open; } + toggle(): void { this.open = !this.open; } } - window.addEventListener('alpine-components:init', () => { - window.Alpine.Components.register(ToggleComponent, 'toggle'); - }); - AlpineComponents.bootstrap({ + components: { + toggle: ToggleComponent + }, logErrors: true }); From 111728c95b8720f697160a158af8919c3e6b20b4 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 22:27:35 +1000 Subject: [PATCH 6/8] typedoc.json: Make home link absolute --- typedoc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typedoc.json b/typedoc.json index 99f1939..8f2746b 100644 --- a/typedoc.json +++ b/typedoc.json @@ -2,7 +2,7 @@ "sidebarLinks": { "GitHub": "https://github.com/NxtLvlSoftware/alpine-typescript", "Twitter": "https://twitter.com/NxtLvlSoftware", - "Home": "/index.html", + "Home": "https://nxtlvlsoftware.github.io/alpine-typescript/", "Example": "https://nxtlvlsoftware.github.io/alpine-typescript/example/" } } \ No newline at end of file From d27149cf0dc2a934ccb428cf5aed3db3af68aa75 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 23:02:42 +1000 Subject: [PATCH 7/8] add typedoc-plugin-extras * Set docs favicon * Include typedoc version in footer * Include generation date + time in footer --- package.json | 5 +++-- typedoc.json | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 881c750..6ebf4ef 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "build": "tsc --inlineSourceMap --removeComments -p ./", "build-ci": "tsc --pretty false --inlineSourceMap --removeComments --listEmittedFiles -p ./", "dev": "tsc --watch -p ./", - "docs": "npx typedoc --out docs-build --cacheBust index.ts", - "docs-ci": "npx typedoc --gitRemote dist --out docs-build --cacheBust index.ts" + "docs": "npx typedoc --plugin typedoc-plugin-extras --out docs-build --cacheBust index.ts", + "docs-ci": "npx typedoc --plugin typedoc-plugin-extras --gitRemote dist --out docs-build --cacheBust index.ts" }, "keywords": [ "alpine", @@ -31,6 +31,7 @@ }, "devDependencies": { "typedoc": "^0.25.1", + "typedoc-plugin-extras": "^3.0.0", "typescript": "^5.1.6" } } diff --git a/typedoc.json b/typedoc.json index 8f2746b..917daab 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,4 +1,8 @@ { + "favicon": "https://nxtlvlsoftware.github.io/alpine-typescript/favicon.ico", + "footerTypedocVersion": true, + "footerDate": true, + "footerTime": true, "sidebarLinks": { "GitHub": "https://github.com/NxtLvlSoftware/alpine-typescript", "Twitter": "https://twitter.com/NxtLvlSoftware", From a22f333e5b272fea09bca967f040072b4f9f4484 Mon Sep 17 00:00:00 2001 From: JackNoordhuis Date: Wed, 13 Sep 2023 13:04:20 +0000 Subject: [PATCH 8/8] [create-pull-request] update tsc build dist files --- index.d.ts | 6 ++ index.js | 7 ++ src/Component.d.ts | 19 ++++++ src/Component.js | 7 ++ src/Global.d.ts | 15 +++++ src/Global.js | 2 + src/Plugin.d.ts | 12 ++++ src/Plugin.js | 36 ++++++++++ src/Store.d.ts | 24 +++++++ src/Store.js | 159 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 287 insertions(+) create mode 100644 index.d.ts create mode 100644 index.js create mode 100644 src/Component.d.ts create mode 100644 src/Component.js create mode 100644 src/Global.d.ts create mode 100644 src/Global.js create mode 100644 src/Plugin.d.ts create mode 100644 src/Plugin.js create mode 100644 src/Store.d.ts create mode 100644 src/Store.js diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..0c7c6a7 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,6 @@ +export { type KnownClassConstructor, type KnownConstructor, type AlpineComponentConstructor, type AlpineDataContext, type AlpineData, AlpineComponent } from './src/Component'; +export { type ComponentList, ComponentStore, transformToAlpineData, makeAlpineConstructor } from './src/Store'; +export * as Globals from './src/Global'; +export { AlpineComponents, componentsPlugin } from './src/Plugin'; +import { componentsPlugin } from './src/Plugin'; +export default componentsPlugin; diff --git a/index.js b/index.js new file mode 100644 index 0000000..b3d2128 --- /dev/null +++ b/index.js @@ -0,0 +1,7 @@ +export { AlpineComponent } from './src/Component'; +export { ComponentStore, transformToAlpineData, makeAlpineConstructor } from './src/Store'; +export * as Globals from './src/Global'; +export { AlpineComponents, componentsPlugin } from './src/Plugin'; +import { componentsPlugin } from './src/Plugin'; +export default componentsPlugin; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBTU4sZUFBZSxFQUNmLE1BQU0saUJBQWlCLENBQUE7QUFFeEIsT0FBTyxFQUVOLGNBQWMsRUFDZCxxQkFBcUIsRUFDckIscUJBQXFCLEVBQ3JCLE1BQU0sYUFBYSxDQUFBO0FBRXBCLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE9BQU8sRUFDTixnQkFBZ0IsRUFDaEIsZ0JBQWdCLEVBQ2hCLE1BQU0sY0FBYyxDQUFDO0FBTXRCLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUM5QyxlQUFlLGdCQUFnQixDQUFDIn0= \ No newline at end of file diff --git a/src/Component.d.ts b/src/Component.d.ts new file mode 100644 index 0000000..9804e51 --- /dev/null +++ b/src/Component.d.ts @@ -0,0 +1,19 @@ +export type KnownClassConstructor = new (...args: any[]) => T; +export type KnownGenericConstructor = (...args: any[]) => T; +export type KnownConstructor = KnownGenericConstructor | KnownClassConstructor; +export type AlpineComponentConstructor = (...args: any[]) => any; +export declare interface AlpineDataContext { + init?(): void; + [stateKey: string]: any; +} +export declare type AlpineData = AlpineDataContext | string | number | boolean; +export declare abstract class AlpineComponent implements AlpineDataContext { + $data: this; + $el: HTMLElement; + $refs: Record; + $store: AlpineData; + $dispatch: (event: string, data?: any) => void; + $id: (name: string, key?: number | string) => string; + $nextTick: (callback?: () => void) => Promise; + $watch: (property: K, callback: (newValue: V, oldValue: V) => void) => void; +} diff --git a/src/Component.js b/src/Component.js new file mode 100644 index 0000000..f685936 --- /dev/null +++ b/src/Component.js @@ -0,0 +1,7 @@ +var AlpineComponent = (function () { + function AlpineComponent() { + } + return AlpineComponent; +}()); +export { AlpineComponent }; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiQ29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTRDQTtJQUFBO0lBd0RBLENBQUM7SUFBRCxzQkFBQztBQUFELENBQUMsQUF4REQsSUF3REMifQ== \ No newline at end of file diff --git a/src/Global.d.ts b/src/Global.d.ts new file mode 100644 index 0000000..bc06de1 --- /dev/null +++ b/src/Global.d.ts @@ -0,0 +1,15 @@ +import type { Alpine as AlpineType } from 'alpinejs'; +import type { ComponentStore } from "./Store"; +import type { AlpineComponentConstructor } from "./Component"; +export declare interface AlpineComponentMixins { + Components: ComponentStore; + component: (name: string) => AlpineComponentConstructor; +} +export declare type AlpineWithComponents = AlpineType & AlpineComponentMixins; +export declare type Alpine = AlpineType | AlpineWithComponents; +declare global { + interface Window { + Alpine: Alpine; + AlpineComponents: ComponentStore; + } +} diff --git a/src/Global.js b/src/Global.js new file mode 100644 index 0000000..9c3a2b4 --- /dev/null +++ b/src/Global.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiR2xvYmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiR2xvYmFsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/src/Plugin.d.ts b/src/Plugin.d.ts new file mode 100644 index 0000000..c488b53 --- /dev/null +++ b/src/Plugin.d.ts @@ -0,0 +1,12 @@ +import type * as Globals from './Global'; +import { type ComponentList } from "./Store"; +export declare namespace AlpineComponents { + interface Options { + components: ComponentList; + startAlpine: boolean; + logErrors: boolean; + } + const defaultOptions: Options; + function bootstrap(options?: Partial, alpine?: Globals.Alpine): void; +} +export declare function componentsPlugin(alpine: Globals.Alpine): void; diff --git a/src/Plugin.js b/src/Plugin.js new file mode 100644 index 0000000..ab8bbb0 --- /dev/null +++ b/src/Plugin.js @@ -0,0 +1,36 @@ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +import { ComponentStore } from "./Store"; +export var AlpineComponents; +(function (AlpineComponents) { + AlpineComponents.defaultOptions = { + components: {}, + startAlpine: true, + logErrors: false + }; + function bootstrap(options, alpine) { + if (options === void 0) { options = AlpineComponents.defaultOptions; } + if (alpine === void 0) { alpine = window.Alpine; } + var opts = __assign(__assign({}, AlpineComponents.defaultOptions), options); + window.AlpineComponents = new ComponentStore(alpine, opts.components, opts.logErrors); + if (opts.startAlpine) { + alpine.start(); + } + } + AlpineComponents.bootstrap = bootstrap; +})(AlpineComponents || (AlpineComponents = {})); +export function componentsPlugin(alpine) { + AlpineComponents.bootstrap({ + startAlpine: false + }, alpine); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiUGx1Z2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQ0EsT0FBTyxFQUVOLGNBQWMsRUFDZCxNQUFNLFNBQVMsQ0FBQztBQUVqQixNQUFNLEtBQVcsZ0JBQWdCLENBOEJoQztBQTlCRCxXQUFpQixnQkFBZ0I7SUFRbkIsK0JBQWMsR0FBWTtRQUN0QyxVQUFVLEVBQUUsRUFBRTtRQUNkLFdBQVcsRUFBRSxJQUFJO1FBQ2pCLFNBQVMsRUFBRSxLQUFLO0tBQ2hCLENBQUM7SUFFRixTQUFnQixTQUFTLENBQ3hCLE9BQTBDLEVBQzFDLE1BQXNDO1FBRHRDLHdCQUFBLEVBQUEsVUFBNEIsK0JBQWM7UUFDMUMsdUJBQUEsRUFBQSxTQUF5QixNQUFNLENBQUMsTUFBTTtRQUV0QyxJQUFNLElBQUkseUJBQ04saUJBQUEsY0FBYyxHQUNkLE9BQU8sQ0FDVixDQUFDO1FBRUYsTUFBTSxDQUFDLGdCQUFnQixHQUFHLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUV0RixJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDckIsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQ2Y7SUFDRixDQUFDO0lBZGUsMEJBQVMsWUFjeEIsQ0FBQTtBQUVGLENBQUMsRUE5QmdCLGdCQUFnQixLQUFoQixnQkFBZ0IsUUE4QmhDO0FBT0QsTUFBTSxVQUFVLGdCQUFnQixDQUFDLE1BQXNCO0lBQ3RELGdCQUFnQixDQUFDLFNBQVMsQ0FBQztRQUMxQixXQUFXLEVBQUUsS0FBSztLQUNsQixFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ1osQ0FBQyJ9 \ No newline at end of file diff --git a/src/Store.d.ts b/src/Store.d.ts new file mode 100644 index 0000000..44b541d --- /dev/null +++ b/src/Store.d.ts @@ -0,0 +1,24 @@ +import type * as Impl from "./Component"; +import type * as Globals from './Global'; +import { AlpineComponent } from "./Component"; +export type ComponentList = { + [name: string]: Impl.KnownConstructor; +}; +export declare class ComponentStore { + private alpine; + private logErrors; + private initialized; + private components; + constructor(alpine: Globals.Alpine, components?: ComponentList, logErrors?: boolean); + private init; + component(name: string): Impl.AlpineComponentConstructor; + registerAll(components: ComponentList): void; + register(name: string, component: Impl.KnownConstructor): void; + register(component: Impl.KnownClassConstructor, name?: string): void; + private registerConstructorAsAlpineData; + private static getObjectData; + private static getClassData; + private logRegisterFailure; +} +export declare function transformToAlpineData(instance: T): object; +export declare function makeAlpineConstructor(component: Impl.KnownClassConstructor): Impl.AlpineComponentConstructor; diff --git a/src/Store.js b/src/Store.js new file mode 100644 index 0000000..af07e10 --- /dev/null +++ b/src/Store.js @@ -0,0 +1,159 @@ +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +import { AlpineComponent } from "./Component"; +var ReservedNames = ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', + 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', + 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', + 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', + 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', + 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', + 'with', 'yield']; +var RegisterComponentFailure; +(function (RegisterComponentFailure) { + RegisterComponentFailure[RegisterComponentFailure["GenericMustHaveFunctionAsSecond"] = 0] = "GenericMustHaveFunctionAsSecond"; + RegisterComponentFailure[RegisterComponentFailure["NameMustBeProvidedForComponentWithNoDefault"] = 1] = "NameMustBeProvidedForComponentWithNoDefault"; + RegisterComponentFailure[RegisterComponentFailure["UnknownArgumentTypes"] = 2] = "UnknownArgumentTypes"; + RegisterComponentFailure[RegisterComponentFailure["ReservedName"] = 3] = "ReservedName"; +})(RegisterComponentFailure || (RegisterComponentFailure = {})); +var ComponentStore = (function () { + function ComponentStore(alpine, components, logErrors) { + var _this = this; + if (components === void 0) { components = {}; } + if (logErrors === void 0) { logErrors = false; } + this.alpine = alpine; + this.logErrors = logErrors; + this.initialized = false; + this.components = {}; + Object.entries(components).forEach(function (_a) { + var name = _a[0], component = _a[1]; + _this.register(name, component); + }); + window.addEventListener('alpine:init', function () { + _this.init(); + }); + } + ComponentStore.prototype.init = function () { + var _this = this; + if (this.initialized) { + return; + } + this.alpine.Components = this; + this.alpine.component = this.component; + document.dispatchEvent(new CustomEvent('alpine-components:init')); + Object.entries(this.components) + .forEach(function (_a) { + var name = _a[0]; + return _this.registerConstructorAsAlpineData(name); + }); + this.initialized = true; + }; + ComponentStore.prototype.component = function (name) { + return this.components[name]; + }; + ComponentStore.prototype.registerAll = function (components) { + var _this = this; + Object.entries(components) + .forEach(function (_a) { + var name = _a[0], component = _a[1]; + return _this.register(name, component); + }); + }; + ComponentStore.prototype.register = function (nameOrComponentClass, constructorOrComponentName) { + if (constructorOrComponentName === void 0) { constructorOrComponentName = ''; } + var component; + if (typeof nameOrComponentClass === 'string') { + if (typeof constructorOrComponentName === 'string') { + this.logRegisterFailure(RegisterComponentFailure.GenericMustHaveFunctionAsSecond); + return; + } + component = ComponentStore.getObjectData(nameOrComponentClass, constructorOrComponentName); + } + else if (typeof nameOrComponentClass === 'function') { + component = ComponentStore.getClassData(nameOrComponentClass, constructorOrComponentName); + if (component.name === "") { + this.logRegisterFailure(RegisterComponentFailure.NameMustBeProvidedForComponentWithNoDefault); + } + } + else { + this.logRegisterFailure(RegisterComponentFailure.UnknownArgumentTypes); + return; + } + if (ReservedNames.includes(component.name)) { + this.logRegisterFailure(RegisterComponentFailure.ReservedName); + } + this.components[component.name] = component.constructor; + if (this.initialized) { + this.registerConstructorAsAlpineData(component.name); + } + }; + ComponentStore.prototype.registerConstructorAsAlpineData = function (name) { + this.alpine.data(name, this.component(name)); + }; + ComponentStore.getObjectData = function (name, component) { + return { + name: name, + constructor: ((component.prototype instanceof AlpineComponent) ? + makeAlpineConstructor(component) : component) + }; + }; + ComponentStore.getClassData = function (component, name) { + var resolvedName = (name !== undefined ? name : component.prototype.name); + return { + name: resolvedName, + constructor: makeAlpineConstructor(component) + }; + }; + ComponentStore.prototype.logRegisterFailure = function (reason) { + if (!this.logErrors) { + return; + } + switch (reason) { + case RegisterComponentFailure.GenericMustHaveFunctionAsSecond: + console.error("Second argument must be a constructor function for component."); + break; + case RegisterComponentFailure.NameMustBeProvidedForComponentWithNoDefault: + console.error("Component name must be provided when class doesn't specify a default."); + break; + case RegisterComponentFailure.UnknownArgumentTypes: + console.error("Cannot register component with provided argument types. Check Typescript definitions for usage."); + break; + case RegisterComponentFailure.ReservedName: + console.error("Cannot register component with name matching a reserved keyword."); + break; + } + }; + return ComponentStore; +}()); +export { ComponentStore }; +export function transformToAlpineData(instance) { + var methodNames = []; + for (var prototype = Object.getPrototypeOf(instance); prototype.constructor.name !== 'Object'; prototype = Object.getPrototypeOf(prototype)) { + Object.getOwnPropertyNames(prototype).forEach(function (name) { + if (methodNames.includes(name)) { + return; + } + methodNames.push(name); + }); + } + return __spreadArray(__spreadArray([], methodNames, true), Object.getOwnPropertyNames(instance), true).reduce(function (obj, name) { + obj[name] = instance[name]; + return obj; + }, {}); +} +export function makeAlpineConstructor(component) { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return transformToAlpineData(new (component.bind.apply(component, __spreadArray([void 0], args, false)))()); + }; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJTdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFHQSxPQUFPLEVBQUMsZUFBZSxFQUFrQyxNQUFNLGFBQWEsQ0FBQztBQUs3RSxJQUFNLGFBQWEsR0FBRyxDQUFDLFVBQVUsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU07SUFDMUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU07SUFDdEcsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU07SUFDcEcsSUFBSSxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEtBQUs7SUFDcEcsTUFBTSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUcsV0FBVyxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsUUFBUTtJQUNwRyxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsT0FBTztJQUNuRyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFjbEIsSUFBSyx3QkFLSjtBQUxELFdBQUssd0JBQXdCO0lBQzVCLDZIQUErQixDQUFBO0lBQy9CLHFKQUEyQyxDQUFBO0lBQzNDLHVHQUFvQixDQUFBO0lB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 \ No newline at end of file