├── .gitignore
├── LICENSE
├── README.md
├── builds
├── cdn.js
└── module.js
├── dist
├── component.esm.js
└── component.min.js
├── package-lock.json
├── package.json
├── scripts
└── build.js
└── src
├── index.js
├── initStyles.js
└── initTemplate.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # misc
9 | .DS_Store
10 | *.pem
11 |
12 | # debug
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 |
17 | # local env files
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | # testing
24 | index.html
25 | /public
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Mark Mead
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Alpine JS Component
2 |
3 | Reusable HTML components powered by Alpine JS reactivity 🛸
4 |
5 | ## Install
6 |
7 | ### With a CDN
8 |
9 | ```html
10 |
14 |
15 |
16 | ```
17 |
18 | ### With a Package Manager
19 |
20 | ```shell
21 | npm install -D alpinejs-component
22 |
23 | yarn add -D alpinejs-component
24 | ```
25 |
26 | ```js
27 | import Alpine from 'alpinejs'
28 | import component from 'alpinejs-component'
29 |
30 | Alpine.plugin(component)
31 |
32 | Alpine.start()
33 | ```
34 |
35 | ## Example
36 |
37 | ### On Page Components
38 |
39 | You can render on page components by using a `` with an `id` that
40 | matches the `template` attribute on the component.
41 |
42 | Here we are rendering the component HTML found in ``
43 | element.
44 |
45 | ```html
46 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
72 |
73 |
74 | ```
75 |
76 | ### Global Components
77 |
78 | If you don't want on page components you can use the `url` attribute which
79 | accepts a path to the HTML component.
80 |
81 | Here we are telling Alpine JS to fetch the HTML from `/public/person.html`
82 | within the codebase.
83 |
84 | ```html
85 |
102 | ```
103 |
104 | Then we'd have a file `/public/person.html` which could look like this.
105 |
106 | ```html
107 |
108 |
109 |
110 |
111 |
112 |
117 |
118 | ```
119 |
120 | ## Dynamic Templates
121 |
122 | You can pass `template` or `url` as a dynamic value, here's an example.
123 |
124 | ```html
125 |
139 |
140 |
141 |
145 |
146 | // Or
147 |
148 |
152 |
153 |
154 |
155 | ```
156 |
157 | ## Styling Components
158 |
159 | ### Including Stylesheets
160 |
161 | You can use `styles` attribute to specify which stylesheets to include.
162 |
163 | ```html
164 |
167 |
168 |
173 | ```
174 |
175 | You can also include multiple stylesheets by separating them with a comma.
176 |
177 | ```html
178 |
181 |
182 |
185 |
186 |
191 | ```
192 |
193 | Or, if you want to include all stylesheets you can use `styles="global"`
194 |
195 | ### Inline Stylesheet
196 |
197 | You can add a `
206 |
207 |
208 |
209 | ```
210 |
211 | ## Renaming Component
212 |
213 | If you need to change the name `x-component`, you can do so by setting the
214 | global `xComponent` object. This is necessary because blade components start
215 | with `x-`, which can cause conflicts.
216 |
217 | ```js
218 | window.xComponent = {
219 | name: 'a-component',
220 | }
221 | ```
222 |
223 | You will then call components like this:
224 |
225 | ```html
226 |
243 | ```
244 |
245 | ### Stats
246 |
247 | 
248 | 
249 | 
250 | 
251 |
--------------------------------------------------------------------------------
/builds/cdn.js:
--------------------------------------------------------------------------------
1 | import component from '../src/index.js'
2 |
3 | document.addEventListener('alpine:init', () => window.Alpine.plugin(component))
4 |
--------------------------------------------------------------------------------
/builds/module.js:
--------------------------------------------------------------------------------
1 | import component from '../src/index.js'
2 |
3 | export default component
4 |
--------------------------------------------------------------------------------
/dist/component.esm.js:
--------------------------------------------------------------------------------
1 | function u(e,n){let l=(n.includes("global")?[...document.styleSheets]:[...document.styleSheets].filter(({title:t})=>n.includes(t))).filter(({href:t})=>t?t?.includes(window.location.host):!0).flatMap(({cssRules:t})=>[...t]),i=new CSSStyleSheet;for(let t of l)t instanceof CSSStyleRule&&t.selectorText===":root"||i.insertRule(t.cssText);e.adoptedStyleSheets=[i]}async function h(e,n,o){function r(l){let i=document.getElementById(l),a=new DOMParser().parseFromString(i.innerHTML,"text/html").body.firstChild;return Promise.resolve(a)}let s=await r(n);o.appendChild(s),e.initTree(o)}async function d(e,n,o){let s=await(await fetch(n)).text(),i=new DOMParser().parseFromString(s,"text/html").body.firstChild;o.appendChild(i),e.initTree(o)}function f(e){class n extends HTMLElement{connectedCallback(){if(this._hasInit)return;let s=this.attachShadow({mode:"open"}),l=this.hasAttribute(":template"),i=this.hasAttribute(":url");(l||i)&&e.initTree(this);let{template:t,url:a,styles:S}=this.attributes||{},m=t?.value||"",c=a?.value||"",p=S?.value.split(",")||"";m.length&&h(e,m,s),c.length&&d(e,c,s),p.length&&u(s,p),this._hasInit=!0}}let{name:o}=window?.xComponent||{name:"x-component"};window.customElements.get(o)||(customElements.define(o,n),new n)}var g=f;export{g as default};
2 |
--------------------------------------------------------------------------------
/dist/component.min.js:
--------------------------------------------------------------------------------
1 | (()=>{function u(e,n){let l=(n.includes("global")?[...document.styleSheets]:[...document.styleSheets].filter(({title:t})=>n.includes(t))).filter(({href:t})=>t?t?.includes(window.location.host):!0).flatMap(({cssRules:t})=>[...t]),i=new CSSStyleSheet;for(let t of l)t instanceof CSSStyleRule&&t.selectorText===":root"||i.insertRule(t.cssText);e.adoptedStyleSheets=[i]}async function d(e,n,o){function r(l){let i=document.getElementById(l),a=new DOMParser().parseFromString(i.innerHTML,"text/html").body.firstChild;return Promise.resolve(a)}let s=await r(n);o.appendChild(s),e.initTree(o)}async function h(e,n,o){let s=await(await fetch(n)).text(),i=new DOMParser().parseFromString(s,"text/html").body.firstChild;o.appendChild(i),e.initTree(o)}function f(e){class n extends HTMLElement{connectedCallback(){if(this._hasInit)return;let s=this.attachShadow({mode:"open"}),l=this.hasAttribute(":template"),i=this.hasAttribute(":url");(l||i)&&e.initTree(this);let{template:t,url:a,styles:S}=this.attributes||{},m=t?.value||"",c=a?.value||"",p=S?.value.split(",")||"";m.length&&d(e,m,s),c.length&&h(e,c,s),p.length&&u(s,p),this._hasInit=!0}}let{name:o}=window?.xComponent||{name:"x-component"};window.customElements.get(o)||(customElements.define(o,n),new n)}document.addEventListener("alpine:init",()=>window.Alpine.plugin(f));})();
2 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alpinejs-component",
3 | "version": "1.2.10",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "alpinejs-component",
9 | "version": "1.2.10",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "esbuild": "^0.25.0"
13 | }
14 | },
15 | "node_modules/@esbuild/aix-ppc64": {
16 | "version": "0.25.0",
17 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
18 | "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
19 | "cpu": [
20 | "ppc64"
21 | ],
22 | "dev": true,
23 | "license": "MIT",
24 | "optional": true,
25 | "os": [
26 | "aix"
27 | ],
28 | "engines": {
29 | "node": ">=18"
30 | }
31 | },
32 | "node_modules/@esbuild/android-arm": {
33 | "version": "0.25.0",
34 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
35 | "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
36 | "cpu": [
37 | "arm"
38 | ],
39 | "dev": true,
40 | "license": "MIT",
41 | "optional": true,
42 | "os": [
43 | "android"
44 | ],
45 | "engines": {
46 | "node": ">=18"
47 | }
48 | },
49 | "node_modules/@esbuild/android-arm64": {
50 | "version": "0.25.0",
51 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
52 | "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
53 | "cpu": [
54 | "arm64"
55 | ],
56 | "dev": true,
57 | "license": "MIT",
58 | "optional": true,
59 | "os": [
60 | "android"
61 | ],
62 | "engines": {
63 | "node": ">=18"
64 | }
65 | },
66 | "node_modules/@esbuild/android-x64": {
67 | "version": "0.25.0",
68 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
69 | "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
70 | "cpu": [
71 | "x64"
72 | ],
73 | "dev": true,
74 | "license": "MIT",
75 | "optional": true,
76 | "os": [
77 | "android"
78 | ],
79 | "engines": {
80 | "node": ">=18"
81 | }
82 | },
83 | "node_modules/@esbuild/darwin-arm64": {
84 | "version": "0.25.0",
85 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
86 | "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
87 | "cpu": [
88 | "arm64"
89 | ],
90 | "dev": true,
91 | "license": "MIT",
92 | "optional": true,
93 | "os": [
94 | "darwin"
95 | ],
96 | "engines": {
97 | "node": ">=18"
98 | }
99 | },
100 | "node_modules/@esbuild/darwin-x64": {
101 | "version": "0.25.0",
102 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
103 | "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
104 | "cpu": [
105 | "x64"
106 | ],
107 | "dev": true,
108 | "license": "MIT",
109 | "optional": true,
110 | "os": [
111 | "darwin"
112 | ],
113 | "engines": {
114 | "node": ">=18"
115 | }
116 | },
117 | "node_modules/@esbuild/freebsd-arm64": {
118 | "version": "0.25.0",
119 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
120 | "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
121 | "cpu": [
122 | "arm64"
123 | ],
124 | "dev": true,
125 | "license": "MIT",
126 | "optional": true,
127 | "os": [
128 | "freebsd"
129 | ],
130 | "engines": {
131 | "node": ">=18"
132 | }
133 | },
134 | "node_modules/@esbuild/freebsd-x64": {
135 | "version": "0.25.0",
136 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
137 | "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
138 | "cpu": [
139 | "x64"
140 | ],
141 | "dev": true,
142 | "license": "MIT",
143 | "optional": true,
144 | "os": [
145 | "freebsd"
146 | ],
147 | "engines": {
148 | "node": ">=18"
149 | }
150 | },
151 | "node_modules/@esbuild/linux-arm": {
152 | "version": "0.25.0",
153 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
154 | "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
155 | "cpu": [
156 | "arm"
157 | ],
158 | "dev": true,
159 | "license": "MIT",
160 | "optional": true,
161 | "os": [
162 | "linux"
163 | ],
164 | "engines": {
165 | "node": ">=18"
166 | }
167 | },
168 | "node_modules/@esbuild/linux-arm64": {
169 | "version": "0.25.0",
170 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
171 | "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
172 | "cpu": [
173 | "arm64"
174 | ],
175 | "dev": true,
176 | "license": "MIT",
177 | "optional": true,
178 | "os": [
179 | "linux"
180 | ],
181 | "engines": {
182 | "node": ">=18"
183 | }
184 | },
185 | "node_modules/@esbuild/linux-ia32": {
186 | "version": "0.25.0",
187 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
188 | "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
189 | "cpu": [
190 | "ia32"
191 | ],
192 | "dev": true,
193 | "license": "MIT",
194 | "optional": true,
195 | "os": [
196 | "linux"
197 | ],
198 | "engines": {
199 | "node": ">=18"
200 | }
201 | },
202 | "node_modules/@esbuild/linux-loong64": {
203 | "version": "0.25.0",
204 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
205 | "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
206 | "cpu": [
207 | "loong64"
208 | ],
209 | "dev": true,
210 | "license": "MIT",
211 | "optional": true,
212 | "os": [
213 | "linux"
214 | ],
215 | "engines": {
216 | "node": ">=18"
217 | }
218 | },
219 | "node_modules/@esbuild/linux-mips64el": {
220 | "version": "0.25.0",
221 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
222 | "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
223 | "cpu": [
224 | "mips64el"
225 | ],
226 | "dev": true,
227 | "license": "MIT",
228 | "optional": true,
229 | "os": [
230 | "linux"
231 | ],
232 | "engines": {
233 | "node": ">=18"
234 | }
235 | },
236 | "node_modules/@esbuild/linux-ppc64": {
237 | "version": "0.25.0",
238 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
239 | "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
240 | "cpu": [
241 | "ppc64"
242 | ],
243 | "dev": true,
244 | "license": "MIT",
245 | "optional": true,
246 | "os": [
247 | "linux"
248 | ],
249 | "engines": {
250 | "node": ">=18"
251 | }
252 | },
253 | "node_modules/@esbuild/linux-riscv64": {
254 | "version": "0.25.0",
255 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
256 | "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
257 | "cpu": [
258 | "riscv64"
259 | ],
260 | "dev": true,
261 | "license": "MIT",
262 | "optional": true,
263 | "os": [
264 | "linux"
265 | ],
266 | "engines": {
267 | "node": ">=18"
268 | }
269 | },
270 | "node_modules/@esbuild/linux-s390x": {
271 | "version": "0.25.0",
272 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
273 | "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
274 | "cpu": [
275 | "s390x"
276 | ],
277 | "dev": true,
278 | "license": "MIT",
279 | "optional": true,
280 | "os": [
281 | "linux"
282 | ],
283 | "engines": {
284 | "node": ">=18"
285 | }
286 | },
287 | "node_modules/@esbuild/linux-x64": {
288 | "version": "0.25.0",
289 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
290 | "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
291 | "cpu": [
292 | "x64"
293 | ],
294 | "dev": true,
295 | "license": "MIT",
296 | "optional": true,
297 | "os": [
298 | "linux"
299 | ],
300 | "engines": {
301 | "node": ">=18"
302 | }
303 | },
304 | "node_modules/@esbuild/netbsd-arm64": {
305 | "version": "0.25.0",
306 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
307 | "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
308 | "cpu": [
309 | "arm64"
310 | ],
311 | "dev": true,
312 | "license": "MIT",
313 | "optional": true,
314 | "os": [
315 | "netbsd"
316 | ],
317 | "engines": {
318 | "node": ">=18"
319 | }
320 | },
321 | "node_modules/@esbuild/netbsd-x64": {
322 | "version": "0.25.0",
323 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
324 | "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
325 | "cpu": [
326 | "x64"
327 | ],
328 | "dev": true,
329 | "license": "MIT",
330 | "optional": true,
331 | "os": [
332 | "netbsd"
333 | ],
334 | "engines": {
335 | "node": ">=18"
336 | }
337 | },
338 | "node_modules/@esbuild/openbsd-arm64": {
339 | "version": "0.25.0",
340 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
341 | "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
342 | "cpu": [
343 | "arm64"
344 | ],
345 | "dev": true,
346 | "license": "MIT",
347 | "optional": true,
348 | "os": [
349 | "openbsd"
350 | ],
351 | "engines": {
352 | "node": ">=18"
353 | }
354 | },
355 | "node_modules/@esbuild/openbsd-x64": {
356 | "version": "0.25.0",
357 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
358 | "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
359 | "cpu": [
360 | "x64"
361 | ],
362 | "dev": true,
363 | "license": "MIT",
364 | "optional": true,
365 | "os": [
366 | "openbsd"
367 | ],
368 | "engines": {
369 | "node": ">=18"
370 | }
371 | },
372 | "node_modules/@esbuild/sunos-x64": {
373 | "version": "0.25.0",
374 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
375 | "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
376 | "cpu": [
377 | "x64"
378 | ],
379 | "dev": true,
380 | "license": "MIT",
381 | "optional": true,
382 | "os": [
383 | "sunos"
384 | ],
385 | "engines": {
386 | "node": ">=18"
387 | }
388 | },
389 | "node_modules/@esbuild/win32-arm64": {
390 | "version": "0.25.0",
391 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
392 | "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
393 | "cpu": [
394 | "arm64"
395 | ],
396 | "dev": true,
397 | "license": "MIT",
398 | "optional": true,
399 | "os": [
400 | "win32"
401 | ],
402 | "engines": {
403 | "node": ">=18"
404 | }
405 | },
406 | "node_modules/@esbuild/win32-ia32": {
407 | "version": "0.25.0",
408 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
409 | "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
410 | "cpu": [
411 | "ia32"
412 | ],
413 | "dev": true,
414 | "license": "MIT",
415 | "optional": true,
416 | "os": [
417 | "win32"
418 | ],
419 | "engines": {
420 | "node": ">=18"
421 | }
422 | },
423 | "node_modules/@esbuild/win32-x64": {
424 | "version": "0.25.0",
425 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
426 | "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
427 | "cpu": [
428 | "x64"
429 | ],
430 | "dev": true,
431 | "license": "MIT",
432 | "optional": true,
433 | "os": [
434 | "win32"
435 | ],
436 | "engines": {
437 | "node": ">=18"
438 | }
439 | },
440 | "node_modules/esbuild": {
441 | "version": "0.25.0",
442 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
443 | "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
444 | "dev": true,
445 | "hasInstallScript": true,
446 | "license": "MIT",
447 | "bin": {
448 | "esbuild": "bin/esbuild"
449 | },
450 | "engines": {
451 | "node": ">=18"
452 | },
453 | "optionalDependencies": {
454 | "@esbuild/aix-ppc64": "0.25.0",
455 | "@esbuild/android-arm": "0.25.0",
456 | "@esbuild/android-arm64": "0.25.0",
457 | "@esbuild/android-x64": "0.25.0",
458 | "@esbuild/darwin-arm64": "0.25.0",
459 | "@esbuild/darwin-x64": "0.25.0",
460 | "@esbuild/freebsd-arm64": "0.25.0",
461 | "@esbuild/freebsd-x64": "0.25.0",
462 | "@esbuild/linux-arm": "0.25.0",
463 | "@esbuild/linux-arm64": "0.25.0",
464 | "@esbuild/linux-ia32": "0.25.0",
465 | "@esbuild/linux-loong64": "0.25.0",
466 | "@esbuild/linux-mips64el": "0.25.0",
467 | "@esbuild/linux-ppc64": "0.25.0",
468 | "@esbuild/linux-riscv64": "0.25.0",
469 | "@esbuild/linux-s390x": "0.25.0",
470 | "@esbuild/linux-x64": "0.25.0",
471 | "@esbuild/netbsd-arm64": "0.25.0",
472 | "@esbuild/netbsd-x64": "0.25.0",
473 | "@esbuild/openbsd-arm64": "0.25.0",
474 | "@esbuild/openbsd-x64": "0.25.0",
475 | "@esbuild/sunos-x64": "0.25.0",
476 | "@esbuild/win32-arm64": "0.25.0",
477 | "@esbuild/win32-ia32": "0.25.0",
478 | "@esbuild/win32-x64": "0.25.0"
479 | }
480 | }
481 | }
482 | }
483 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alpinejs-component",
3 | "version": "1.2.10",
4 | "description": "Reusable HTML components powered by Alpine JS reactivity 🛸",
5 | "keywords": [
6 | "Alpine",
7 | "Alpine JS",
8 | "Alpine JS Plugin",
9 | "Alpine JS Plugins",
10 | "Alpine JS Component",
11 | "Alpine JS Components",
12 | "HTML Components"
13 | ],
14 | "author": "Mark Mead",
15 | "license": "MIT",
16 | "module": "dist/component.esm.js",
17 | "unpkg": "dist/component.min.js",
18 | "scripts": {
19 | "build": "node scripts/build.js"
20 | },
21 | "devDependencies": {
22 | "esbuild": "^0.25.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/scripts/build.js:
--------------------------------------------------------------------------------
1 | buildPlugin({
2 | entryPoints: ['builds/cdn.js'],
3 | outfile: 'dist/component.min.js',
4 | })
5 |
6 | buildPlugin({
7 | entryPoints: ['builds/module.js'],
8 | outfile: 'dist/component.esm.js',
9 | platform: 'neutral',
10 | mainFields: ['main', 'module'],
11 | })
12 |
13 | function buildPlugin(buildOptions) {
14 | return require('esbuild').buildSync({
15 | ...buildOptions,
16 | minify: true,
17 | bundle: true,
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { initStyles } from './initStyles'
2 | import { initTemplate, initUrl } from './initTemplate'
3 |
4 | export default function (Alpine) {
5 | class ComponentWrapper extends HTMLElement {
6 | connectedCallback() {
7 | // We prevent the component from being
8 | // initialized more than once
9 | if (this._hasInit) {
10 | return
11 | }
12 |
13 | const shadowDom = this.attachShadow({ mode: 'open' })
14 |
15 | const hasDynamicTemplate = this.hasAttribute(':template')
16 | const hasDynamicUrl = this.hasAttribute(':url')
17 |
18 | if (hasDynamicTemplate || hasDynamicUrl) {
19 | Alpine.initTree(this)
20 | }
21 |
22 | const {
23 | template: componentTemplate,
24 | url: componentUrl,
25 | styles: componentStyles,
26 | } = this.attributes || {}
27 |
28 | const templateName = componentTemplate?.value || ''
29 | const urlName = componentUrl?.value || ''
30 | const styleNames = componentStyles?.value.split(',') || ''
31 |
32 | if (templateName.length) {
33 | initTemplate(Alpine, templateName, shadowDom)
34 | }
35 |
36 | if (urlName.length) {
37 | initUrl(Alpine, urlName, shadowDom)
38 | }
39 |
40 | if (styleNames.length) {
41 | initStyles(shadowDom, styleNames)
42 | }
43 |
44 | this._hasInit = true
45 | }
46 | }
47 |
48 | const { name: componentName } = window?.xComponent || { name: 'x-component' }
49 |
50 | if (window.customElements.get(componentName)) {
51 | return
52 | }
53 |
54 | customElements.define(componentName, ComponentWrapper)
55 |
56 | new ComponentWrapper()
57 | }
58 |
--------------------------------------------------------------------------------
/src/initStyles.js:
--------------------------------------------------------------------------------
1 | export function initStyles(shadowDom, styleTargets) {
2 | const useGlobal = styleTargets.includes('global')
3 |
4 | const documentSheets = useGlobal
5 | ? [...document.styleSheets]
6 | : [...document.styleSheets].filter(({ title: styleTitle }) =>
7 | styleTargets.includes(styleTitle)
8 | )
9 |
10 | const filteredDocumentSheets = documentSheets.filter(
11 | ({ href: styleHref }) => {
12 | // We keep inline styles
13 | if (!styleHref) {
14 | return true
15 | }
16 |
17 | // We remove external stylesheets
18 | return styleHref?.includes(window.location.host)
19 | }
20 | )
21 |
22 | const documentStyles = filteredDocumentSheets.flatMap(({ cssRules }) => [
23 | ...cssRules,
24 | ])
25 |
26 | const newStyle = new CSSStyleSheet()
27 |
28 | for (const styleRule of documentStyles) {
29 | if (
30 | styleRule instanceof CSSStyleRule &&
31 | styleRule.selectorText === ':root'
32 | ) {
33 | continue
34 | }
35 |
36 | newStyle.insertRule(styleRule.cssText)
37 | }
38 |
39 | shadowDom.adoptedStyleSheets = [newStyle]
40 | }
41 |
--------------------------------------------------------------------------------
/src/initTemplate.js:
--------------------------------------------------------------------------------
1 | export async function initTemplate(Alpine, templateName, shadowDom) {
2 | function generateComponent(targetHtml) {
3 | const htmlTemplate = document.getElementById(targetHtml)
4 |
5 | const domParser = new DOMParser()
6 |
7 | const newComponent = domParser.parseFromString(
8 | htmlTemplate.innerHTML,
9 | 'text/html'
10 | ).body.firstChild
11 |
12 | return Promise.resolve(newComponent)
13 | }
14 |
15 | const alpineComponent = await generateComponent(templateName)
16 |
17 | shadowDom.appendChild(alpineComponent)
18 |
19 | Alpine.initTree(shadowDom)
20 | }
21 |
22 | export async function initUrl(Alpine, urlName, shadowDom) {
23 | const htmlResponse = await fetch(urlName)
24 | const htmlTemplate = await htmlResponse.text()
25 |
26 | const domParser = new DOMParser()
27 |
28 | const newComponent = domParser.parseFromString(htmlTemplate, 'text/html').body
29 | .firstChild
30 |
31 | shadowDom.appendChild(newComponent)
32 |
33 | Alpine.initTree(shadowDom)
34 | }
35 |
--------------------------------------------------------------------------------