weg-shared-layout 0.0.3 → 0.0.4

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.
Files changed (48) hide show
  1. package/dist/types/components/weg-footer/weg-footer.d.ts +32 -47
  2. package/dist/types/components.d.ts +5 -79
  3. package/dist/weg-shared-layout/index-C8BdwtPR.js +4625 -0
  4. package/dist/weg-shared-layout/index-C8BdwtPR.js.map +1 -0
  5. package/dist/weg-shared-layout/index.esm.js +14 -1
  6. package/dist/weg-shared-layout/index.esm.js.map +1 -0
  7. package/dist/weg-shared-layout/my-component.entry.js +34 -0
  8. package/dist/weg-shared-layout/my-component.entry.js.map +1 -0
  9. package/dist/{cjs/index.cjs.js → weg-shared-layout/utils-DhW431pq.js} +4 -3
  10. package/dist/weg-shared-layout/utils-DhW431pq.js.map +1 -0
  11. package/dist/{esm/my-component_2.entry.js → weg-shared-layout/weg-footer.entry.js} +62 -138
  12. package/dist/weg-shared-layout/weg-footer.entry.js.map +1 -0
  13. package/dist/weg-shared-layout/weg-shared-layout.esm.js +50 -1
  14. package/dist/weg-shared-layout/weg-shared-layout.esm.js.map +1 -0
  15. package/package.json +1 -1
  16. package/readme.md +242 -70
  17. package/dist/cjs/app-globals-V2Kpy_OQ.js +0 -5
  18. package/dist/cjs/index-CmiaQ_Dj.js +0 -1612
  19. package/dist/cjs/loader.cjs.js +0 -13
  20. package/dist/cjs/my-component_2.cjs.entry.js +0 -249
  21. package/dist/cjs/weg-shared-layout.cjs.js +0 -25
  22. package/dist/collection/collection-manifest.json +0 -14
  23. package/dist/collection/components/my-component/my-component.cmp.test.js +0 -27
  24. package/dist/collection/components/my-component/my-component.css +0 -3
  25. package/dist/collection/components/my-component/my-component.js +0 -95
  26. package/dist/collection/components/weg-footer/icons/instagram.svg +0 -5
  27. package/dist/collection/components/weg-footer/icons/linkedin.svg +0 -3
  28. package/dist/collection/components/weg-footer/icons/tiktok.svg +0 -3
  29. package/dist/collection/components/weg-footer/icons/youtube.svg +0 -4
  30. package/dist/collection/components/weg-footer/weg-footer.css +0 -236
  31. package/dist/collection/components/weg-footer/weg-footer.js +0 -412
  32. package/dist/collection/index.js +0 -10
  33. package/dist/collection/utils/utils.js +0 -3
  34. package/dist/collection/utils/utils.unit.test.js +0 -16
  35. package/dist/components/index.js +0 -1
  36. package/dist/components/my-component.js +0 -1
  37. package/dist/components/p-BTQYW5OR.js +0 -1
  38. package/dist/components/weg-footer.js +0 -1
  39. package/dist/esm/app-globals-DQuL1Twl.js +0 -3
  40. package/dist/esm/index-QiJxC4Ow.js +0 -1606
  41. package/dist/esm/index.js +0 -5
  42. package/dist/esm/loader.js +0 -11
  43. package/dist/esm/weg-shared-layout.js +0 -21
  44. package/dist/index.cjs.js +0 -1
  45. package/dist/index.js +0 -1
  46. package/dist/weg-shared-layout/p-67d9c345.entry.js +0 -1
  47. package/dist/weg-shared-layout/p-DQuL1Twl.js +0 -1
  48. package/dist/weg-shared-layout/p-QiJxC4Ow.js +0 -2
package/readme.md CHANGED
@@ -10,52 +10,206 @@ Install:
10
10
  npm i weg-shared-layout
11
11
  ```
12
12
 
13
+ ## How it works
14
+
15
+ `<weg-footer>` is a **dumb / presentational** Web Component. It does **not** fetch data itself. Your host app calls the layout API, then passes the resulting object into the component via the `data` prop.
16
+
17
+ This keeps the component framework-agnostic, lets you share the same response with `<weg-header>` (coming soon), and means HTTP concerns like auth, caching, retries, SSR, and error handling live in your app — where they belong.
18
+
19
+ ## Layout API
20
+
21
+ Call this endpoint from your host app to retrieve the data:
22
+
23
+ ```
24
+ GET https://weg-payload-test.vercel.app/api/layout
25
+ ```
26
+
27
+ Response shape:
28
+
29
+ ```json
30
+ {
31
+ "header": {},
32
+ "footer": {
33
+ "social": [
34
+ { "platform": "LinkedIn", "href": "https://www.linkedin.com/" },
35
+ { "platform": "Instagram", "href": "https://www.instagram.com/" },
36
+ { "platform": "TikTok", "href": "https://www.tiktok.com/" },
37
+ { "platform": "YouTube", "href": "https://www.youtube.com/" }
38
+ ],
39
+ "standardLinks": [
40
+ { "label": "About Us", "href": "/about" },
41
+ { "label": "Privacy Policy", "href": "/privacy" },
42
+ { "label": "Terms of Use", "href": "/terms" },
43
+ { "label": "Cookie Policy", "href": "/cookies" },
44
+ { "label": "Accessibility Statement", "href": "/accessibility" }
45
+ ],
46
+ "credits": "Warwick Employment Group is a department of the Campus and Commercial Services Group at the University of Warwick.",
47
+ "copyright": "Copyright © Warwick Employment Group."
48
+ }
49
+ }
50
+ ```
51
+
52
+ Only `social.platform` values of `LinkedIn`, `Instagram`, `TikTok`, and `YouTube` render an icon. Items with missing/invalid fields are silently dropped.
53
+
13
54
  ## Using in Angular
14
55
 
15
- Register custom elements (recommended in `main.ts`):
56
+ This guide assumes a modern Angular project (v17+, **standalone components**) — the default for `ng new`. There's an `NgModule` section further down for older apps.
57
+
58
+ ### 1. Install the package
59
+
60
+ ```bash
61
+ npm i weg-shared-layout
62
+ # or: pnpm add weg-shared-layout
63
+ # or: yarn add weg-shared-layout
64
+ ```
65
+
66
+ ### 2. Register the custom elements (once, at startup)
67
+
68
+ Stencil ships a loader that calls `customElements.define()` for every component in the package. Call it **once** before Angular bootstraps your app, otherwise the browser sees `<weg-footer>` as an unknown element and renders nothing.
69
+
70
+ Edit `src/main.ts`:
16
71
 
17
72
  ```ts
73
+ import { bootstrapApplication } from '@angular/platform-browser';
18
74
  import { defineCustomElements } from 'weg-shared-layout/loader';
19
75
 
76
+ import { appConfig } from './app/app.config';
77
+ import { App } from './app/app';
78
+
79
+ // MUST run before bootstrapApplication so the browser recognises <weg-footer>
80
+ // by the time Angular's renderer touches the DOM.
20
81
  defineCustomElements();
82
+
83
+ bootstrapApplication(App, appConfig).catch((err) => console.error(err));
84
+ ```
85
+
86
+ > If you don't see your footer in the page, 9 times out of 10 it's because this step was skipped. Verify by typing `customElements.get('weg-footer')` in the browser DevTools console — it should return a class, not `undefined`.
87
+
88
+ ### 3. Provide `HttpClient`
89
+
90
+ You need `HttpClient` to call the layout API. In `src/app/app.config.ts`:
91
+
92
+ ```ts
93
+ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
94
+ import { provideHttpClient } from '@angular/common/http';
95
+ import { provideRouter } from '@angular/router';
96
+
97
+ import { routes } from './app.routes';
98
+
99
+ export const appConfig: ApplicationConfig = {
100
+ providers: [
101
+ provideBrowserGlobalErrorListeners(),
102
+ provideRouter(routes),
103
+ provideHttpClient(),
104
+ ],
105
+ };
21
106
  ```
22
107
 
23
- Allow custom elements in the module that uses them:
108
+ ### 4. Tell Angular to allow unknown elements
109
+
110
+ Without this, Angular's template compiler throws:
111
+
112
+ > `'weg-footer' is not a known element: ... If 'weg-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message.`
113
+
114
+ In **standalone components** (default in Angular 17+), add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` to the `@Component` decorator of **every component that uses `<weg-footer>` in its template**. Easiest is to add it to your root `App` component:
24
115
 
25
116
  ```ts
26
- import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
117
+ // src/app/app.ts
118
+ import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit, signal } from '@angular/core';
119
+ import { HttpClient } from '@angular/common/http';
120
+ import { RouterOutlet } from '@angular/router';
27
121
 
28
- @NgModule({
29
- // ...
122
+ const LAYOUT_API = 'https://weg-payload-test.vercel.app/api/layout';
123
+
124
+ @Component({
125
+ selector: 'app-root',
126
+ imports: [RouterOutlet],
30
127
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
128
+ templateUrl: './app.html',
129
+ styleUrl: './app.css',
31
130
  })
32
- export class AppModule {}
131
+ export class App implements OnInit {
132
+ protected readonly layoutData = signal<unknown>(null);
133
+
134
+ private readonly http = inject(HttpClient);
135
+
136
+ ngOnInit(): void {
137
+ this.http.get(LAYOUT_API).subscribe({
138
+ next: (data) => this.layoutData.set(data),
139
+ error: (err) => console.error('Failed to load layout data', err),
140
+ });
141
+ }
142
+ }
33
143
  ```
34
144
 
35
- Use in a template (standard):
145
+ > `CUSTOM_ELEMENTS_SCHEMA` is **per-component** in standalone Angular. If you use `<weg-footer>` inside a child component's template, that child must declare `schemas: [CUSTOM_ELEMENTS_SCHEMA]` too. It does **not** cascade through `<router-outlet />`.
146
+
147
+ ### 5. Pass the data into `<weg-footer>` via the `[data]` binding
148
+
149
+ In `src/app/app.html`:
36
150
 
37
151
  ```html
38
- <weg-footer
39
- variant="standard"
40
- company-name="WEG"
41
- company-number="12345678"
42
- social-links-src="/assets/footer-social-links.json"
43
- standard-links-src="/assets/footer-standard-links.json"
44
- ></weg-footer>
152
+ <router-outlet />
153
+
154
+ <weg-footer [data]="layoutData()"></weg-footer>
45
155
  ```
46
156
 
47
- Use in a template (additional):
157
+ That's the whole integration. `<weg-footer>` watches its `data` prop and re-renders when the signal value changes (e.g. when the HTTP response arrives), so an initial `null` is fine — the footer will simply render empty until the data lands.
48
158
 
49
- ```html
50
- <weg-footer
51
- variant="additional"
52
- company-name="WEG"
53
- company-number="12345678"
54
- social-links-src="/assets/footer-social-links.json"
55
- additional-groups-src="/assets/footer-additional-groups.json"
56
- ></weg-footer>
159
+ #### Why `[data]` and not `data-src` or `[attr.data]`
160
+
161
+ - `[data]="..."` is Angular's **property binding** — it sets the JS property `data` on the underlying DOM element. Stencil exposes `@Prop()` values as JS properties, so this passes the object straight through. **This is what you want.**
162
+ - `[attr.data]="..."` would set an HTML attribute, which is always a string — Angular would call `JSON.stringify(layoutData)` for you, the component would have to parse it back, and you'd lose type fidelity. Avoid unless you have a reason.
163
+ - Plain `data="..."` only works for a static string literal and would have the same parsing cost — fine for testing, not for real data.
164
+
165
+ ### 6. Verify it works
166
+
167
+ After running `ng serve`, open the page and check:
168
+
169
+ 1. The dark footer bar renders at the bottom of the page.
170
+ 2. DevTools → Network tab shows a `200 OK` to `https://weg-payload-test.vercel.app/api/layout`.
171
+ 3. DevTools → Elements → click `<weg-footer>` → in the Console, type `$0.data` — you should see the JSON object you fetched.
172
+ 4. Expand `<weg-footer>` in the Elements panel — you should see a `#shadow-root (open)` containing the actual `<footer>` markup.
173
+
174
+ ### Troubleshooting
175
+
176
+ | Symptom | Cause / fix |
177
+ | --- | --- |
178
+ | `'weg-footer' is not a known element` build error | Add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` to the `@Component` decorator of the component whose template uses `<weg-footer>`. |
179
+ | Element renders as plain inline text / empty box | `defineCustomElements()` was never called. Add it to `main.ts` **before** `bootstrapApplication`. |
180
+ | Footer is in the DOM but blank | The HTTP request failed or returned the wrong shape. Check DevTools → Network → confirm the response matches the [API shape](#layout-api). Also inspect `$0.data` in the console to confirm the binding made it onto the element. |
181
+ | `NullInjectorError: No provider for HttpClient` | You forgot `provideHttpClient()` in `app.config.ts`. |
182
+ | CORS error in the console | The API host must allow your origin. Either fix CORS on the backend, or proxy through Angular's dev proxy (`proxy.conf.json`) so the call becomes same-origin. |
183
+ | Footer doesn't update after data changes | Make sure you're using `[data]="layoutData()"` with a signal (or `[data]="layoutData$ | async"` with an Observable) so Angular pushes new values into the element. |
184
+ | Works locally, fails in SSR (`document is not defined`) | `defineCustomElements()` touches `window` / `customElements`. Wrap in `if (typeof window !== 'undefined') { ... }` or use `isPlatformBrowser(platformId)` in `main.ts`. |
185
+ | TypeScript: `Property 'weg-footer' does not exist on type 'HTMLElementTagNameMap'` | See the typings section below. |
186
+
187
+ ### TypeScript typings (Angular)
188
+
189
+ If your editor / TS service complains about the unknown element or the `[data]` binding, add this to `src/global.d.ts` (creating the file if needed) and make sure it's included by `tsconfig.json`:
190
+
191
+ ```ts
192
+ /// <reference types="weg-shared-layout/dist/types/components" />
193
+ ```
194
+
195
+ ### Legacy: using with `NgModule`
196
+
197
+ If your app is still using `NgModule` (pre-Angular 17 default), add `CUSTOM_ELEMENTS_SCHEMA` once at the module level instead of per component:
198
+
199
+ ```ts
200
+ // src/app/app.module.ts
201
+ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
202
+ import { HttpClientModule } from '@angular/common/http';
203
+
204
+ @NgModule({
205
+ imports: [HttpClientModule /* ... */],
206
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
207
+ })
208
+ export class AppModule {}
57
209
  ```
58
210
 
211
+ `defineCustomElements()` in `main.ts` is still required either way. Inject `HttpClient` in your component the same way as the standalone example above.
212
+
59
213
  ## Using in React
60
214
 
61
215
  Install:
@@ -80,70 +234,66 @@ Or:
80
234
  import 'weg-shared-layout';
81
235
  ```
82
236
 
83
- ### Next.js (App Router) note
237
+ Then fetch the data in your component and pass it in via a ref (because the `data` prop is an object, not a string attribute):
84
238
 
85
- Stencil custom elements must be registered **in the browser**. If you’re using Next.js `app/` (App Router), don’t import/register Stencil components from a Server Component.
239
+ ```tsx
240
+ import { useEffect, useRef, useState } from 'react';
241
+ import 'weg-shared-layout/weg-footer';
86
242
 
87
- Instead, register them in a Client Component, for example:
243
+ const LAYOUT_API = 'https://weg-payload-test.vercel.app/api/layout';
88
244
 
89
- ```tsx
90
- // app/components/WegFooterClient.tsx
91
- "use client";
245
+ export function SiteFooter() {
246
+ const ref = useRef<HTMLElement>(null);
247
+ const [layout, setLayout] = useState<unknown>(null);
248
+
249
+ useEffect(() => {
250
+ fetch(LAYOUT_API).then((r) => r.json()).then(setLayout);
251
+ }, []);
92
252
 
93
- import "weg-shared-layout/weg-footer";
94
-
95
- export function WegFooterClient() {
96
- return (
97
- <weg-footer
98
- variant="standard"
99
- company-name="WEG"
100
- company-number="12345678"
101
- social-links-src="/assets/footer-social-links.json"
102
- standard-links-src="/assets/footer-standard-links.json"
103
- />
104
- );
253
+ useEffect(() => {
254
+ if (ref.current) (ref.current as any).data = layout;
255
+ }, [layout]);
256
+
257
+ return <weg-footer ref={ref} />;
105
258
  }
106
259
  ```
107
260
 
108
- Use the footer (standard):
261
+ > React (pre-19) sets unknown JSX attributes as HTML attributes, which would stringify your object. Assigning via a ref guarantees you set the JS property. React 19+ handles this correctly without the ref dance.
109
262
 
110
- ```tsx
111
- import 'weg-shared-layout/weg-footer';
263
+ ### Next.js (App Router) note
112
264
 
113
- export function App() {
114
- return (
115
- <weg-footer
116
- variant="standard"
117
- company-name="WEG"
118
- company-number="12345678"
119
- social-links-src="/assets/footer-social-links.json"
120
- standard-links-src="/assets/footer-standard-links.json"
121
- />
122
- );
123
- }
124
- ```
265
+ Stencil custom elements must be registered **in the browser**. In Next.js `app/` (App Router), don't import/register Stencil components from a Server Component.
125
266
 
126
- Use the footer (additional):
267
+ Instead, register them in a Client Component, for example:
127
268
 
128
269
  ```tsx
270
+ // app/components/SiteFooter.tsx
271
+ "use client";
272
+
273
+ import { useEffect, useRef, useState } from 'react';
129
274
  import 'weg-shared-layout/weg-footer';
130
275
 
131
- export function App() {
132
- return (
133
- <weg-footer
134
- variant="additional"
135
- company-name="WEG"
136
- company-number="12345678"
137
- social-links-src="/assets/footer-social-links.json"
138
- additional-groups-src="/assets/footer-additional-groups.json"
139
- />
140
- );
276
+ export function SiteFooter() {
277
+ const ref = useRef<HTMLElement>(null);
278
+ const [layout, setLayout] = useState<unknown>(null);
279
+
280
+ useEffect(() => {
281
+ fetch('/api/layout').then((r) => r.json()).then(setLayout);
282
+ }, []);
283
+
284
+ useEffect(() => {
285
+ if (ref.current) (ref.current as any).data = layout;
286
+ }, [layout]);
287
+
288
+ return <weg-footer ref={ref} />;
141
289
  }
142
290
  ```
143
291
 
292
+ (You can also fetch in a Server Component and pass `layout` down as a prop to the Client Component — but the actual `data` assignment still has to happen in the browser.)
293
+
144
294
  ### React TypeScript typings
145
295
 
146
- Stencil generates `components.d.ts` in this repo, but React does not automatically pick up custom element typings. In consuming React apps, add a `global.d.ts` (or similar) that references your package’s generated types:
296
+ Stencil generates `components.d.ts`, but React doesn't pick up custom element typings automatically. Add a `global.d.ts` that references the generated types:
147
297
 
148
298
  ```ts
149
299
  /// <reference types="weg-shared-layout/dist/types/components" />
@@ -151,6 +301,28 @@ Stencil generates `components.d.ts` in this repo, but React does not automatical
151
301
 
152
302
  If your app still complains about JSX intrinsic elements, you can also augment `JSX.IntrinsicElements` in that same file (varies by React/TS setup).
153
303
 
154
- ### Note on `*-src` JSON URLs
304
+ ## Plain HTML / vanilla JS
305
+
306
+ For a quick smoke test outside of a framework, fetch the JSON and assign it to the element's `data` property:
307
+
308
+ ```html
309
+ <weg-footer id="footer"></weg-footer>
310
+
311
+ <script type="module">
312
+ const res = await fetch('https://weg-payload-test.vercel.app/api/layout');
313
+ document.getElementById('footer').data = await res.json();
314
+ </script>
315
+ ```
316
+
317
+ You can also pass the JSON as a string attribute — useful for SSR or static HTML where you don't want a runtime fetch:
318
+
319
+ ```html
320
+ <weg-footer data='{"footer":{"social":[],"standardLinks":[],"credits":"","copyright":"Copyright © WEG."}}'></weg-footer>
321
+ ```
322
+
323
+ ## CORS
324
+
325
+ Because the host app calls the API directly, **the API must respond with `Access-Control-Allow-Origin` headers** that include your app's origin. If you hit a CORS error in the browser console, either:
155
326
 
156
- `social-links-src`, `standard-links-src`, and `additional-groups-src` are fetched by the component at runtime, so the JSON files must be **served by the host app** (e.g. Angular’s `src/assets/`), or be a full `https://...` URL.
327
+ - Fix CORS on the API host, **or**
328
+ - Proxy the call through your own host. Angular: configure `proxy.conf.json` so `/api/layout` is rewritten to the production URL. Next.js: add a route handler that re-fetches and returns the JSON.
@@ -1,5 +0,0 @@
1
- 'use strict';
2
-
3
- const globalScripts = () => {};
4
-
5
- exports.globalScripts = globalScripts;