Skip to content

Commit 3ff2a35

Browse files
authored
Feature/update template (#451)
~~We hebben een type Page en Category uit theme-wizard-templates, en die werd geimporteerd in theme-wizard-app. Maar theme-wizard-app importeert ook uit theme-wizard-templates, wat een build cycle error veroorzaakte.~~ ~~Dit heb ik tijdelijk opgelost door de type toe te voegen in theme-wizard-app, waardoor theme-wizard-app niet meer afhankelijk is van de build van theme-wizard-templates.~~ ~~Vraag is of dit zo moet blijven, of een andere richting kiezen, voor bijvoorbeeld een "shared" types package? Betekent wel dat je yet another package hebt en de vraag is: hoevaak gaat dit nog voorkomen?~~ ~~Dit heb ik gedaan, zodat de templates standalone kunnen draaien op de theme-wizard-app url, dus lokaal bijvoorbeeld: http://localhost:9492/templates/my-environment/overview~~ - [x] Typing van `TemplateGroup` in `wizard-preview-picker` - [x] Componenten die in `theme-wizard-app` stonden en enkel in `theme-wizard-templates` werden gebruikt, verplaatst naar `theme-wizard-templates` - [x] `template-heading `vervangen door `clippy-heading` en deze in `packages/clippy-components` geplaatst - [x] In deze PR (anders werd de huidige PR te groot), `template-link` vervangen door `clippy-link` en deze in `packages/clippy-components` geplaatst. [Clippy Link Webcomponent PR](#454)
1 parent 9c443f4 commit 3ff2a35

File tree

43 files changed

+372
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+372
-132
lines changed

packages/clippy-components/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"@nl-design-system-candidate/button-css": "1.0.0",
4848
"@nl-design-system-candidate/code-css": "2.0.3",
4949
"@nl-design-system-candidate/color-sample-css": "1.0.4",
50+
"@nl-design-system-candidate/heading-css": "1.1.3",
5051
"@utrecht/button-css": "3.0.1",
5152
"@utrecht/combobox-css": "2.0.1",
5253
"@utrecht/listbox-css": "2.0.1",
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import codeCss from '@nl-design-system-candidate/code-css/code.css?inline';
22
import { LitElement, html, unsafeCSS } from 'lit';
3-
import { customElement } from 'lit/decorators.js';
3+
const tag = 'clippy-code';
44

5-
@customElement('clippy-code')
65
export class ClippyCode extends LitElement {
76
static override readonly styles = [unsafeCSS(codeCss)];
87

@@ -11,8 +10,13 @@ export class ClippyCode extends LitElement {
1110
}
1211
}
1312

13+
const registry = globalThis.customElements;
14+
if (registry && !registry.get(tag)) {
15+
registry.define(tag, ClippyCode);
16+
}
17+
1418
declare global {
1519
interface HTMLElementTagNameMap {
16-
'clippy-code': ClippyCode;
20+
[tag]: ClippyCode;
1721
}
1822
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# `<clippy-heading>`
2+
3+
Koptekst, met NL Design System heading styles.
4+
5+
Gebruik `level` (standaard `1`) om het heading level (`h1``h6`) te kiezen.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
import { beforeEach, describe, expect, it } from 'vitest';
3+
import './index';
4+
5+
const tag = 'clippy-heading';
6+
7+
describe(`<${tag}>`, () => {
8+
beforeEach(() => {
9+
document.body.innerHTML = '';
10+
});
11+
12+
it('renders an h1 by default', async () => {
13+
document.body.innerHTML = `<${tag}>Hello</${tag}>`;
14+
const component = document.querySelector(tag) as unknown as {
15+
updateComplete: Promise<void>;
16+
shadowRoot?: ShadowRoot;
17+
};
18+
await component.updateComplete;
19+
20+
const h1 = component.shadowRoot?.querySelector('h1');
21+
expect(h1).toBeTruthy();
22+
expect(h1?.classList.contains('nl-heading')).toBe(true);
23+
expect(h1?.classList.contains('nl-heading--level-1')).toBe(true);
24+
25+
const slot = h1?.querySelector('slot');
26+
const slottedText =
27+
slot instanceof HTMLSlotElement
28+
? slot
29+
.assignedNodes({ flatten: true })
30+
.map((n) => n.textContent ?? '')
31+
.join('')
32+
: '';
33+
expect(slottedText).toContain('Hello');
34+
});
35+
36+
it('renders the requested heading level when setting the level property', async () => {
37+
document.body.innerHTML = `<${tag}>Hello</${tag}>`;
38+
const component = document.querySelector(tag) as unknown as {
39+
level: number;
40+
updateComplete: Promise<void>;
41+
shadowRoot?: ShadowRoot;
42+
};
43+
44+
component.level = 2;
45+
await component.updateComplete;
46+
47+
const h2 = component.shadowRoot?.querySelector('h2');
48+
expect(h2).toBeTruthy();
49+
expect(h2?.classList.contains('nl-heading')).toBe(true);
50+
expect(h2?.classList.contains('nl-heading--level-2')).toBe(true);
51+
expect(component.shadowRoot?.querySelector('h1')).toBeFalsy();
52+
});
53+
54+
it('accepts the level attribute', async () => {
55+
document.body.innerHTML = `<${tag} level="3">Hello</${tag}>`;
56+
const component = document.querySelector(tag) as unknown as {
57+
updateComplete: Promise<void>;
58+
shadowRoot?: ShadowRoot;
59+
};
60+
await component.updateComplete;
61+
62+
const h3 = component.shadowRoot?.querySelector('h3');
63+
expect(h3).toBeTruthy();
64+
expect(h3?.classList.contains('nl-heading--level-3')).toBe(true);
65+
});
66+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import headingCss from '@nl-design-system-candidate/heading-css/heading.css?inline';
2+
import { LitElement, unsafeCSS } from 'lit';
3+
import { property } from 'lit/decorators.js';
4+
import { html, unsafeStatic } from 'lit/static-html.js';
5+
6+
const tag = 'clippy-heading';
7+
8+
export class ClippyHeading extends LitElement {
9+
@property({ type: Number }) level = 1;
10+
11+
static override readonly styles = [unsafeCSS(headingCss)];
12+
13+
override render() {
14+
const safeLevel = Math.min(6, Math.max(1, Number(this.level) || 1));
15+
const tag = unsafeStatic(`h${safeLevel}`);
16+
return html`<${tag} class="nl-heading nl-heading--level-${safeLevel}"><slot></slot></${tag}>`;
17+
}
18+
}
19+
20+
const registry = globalThis.customElements;
21+
if (registry && !registry.get(tag)) {
22+
registry.define(tag, ClippyHeading);
23+
}
24+
25+
declare global {
26+
interface HTMLElementTagNameMap {
27+
[tag]: ClippyHeading;
28+
}
29+
}

packages/clippy-components/src/clippy-html-image/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { LitElement, html } from 'lit';
2-
import { customElement, query } from 'lit/decorators.js';
2+
import { query } from 'lit/decorators.js';
33
import styles from './styles';
44

55
let labelCounter = 0;
66

7-
@customElement('clippy-html-image')
7+
const tag = 'clippy-html-image';
8+
89
export class ClippyHtmlImage extends LitElement {
910
static override readonly styles = [styles];
1011

@@ -69,3 +70,8 @@ export class ClippyHtmlImage extends LitElement {
6970
<slot id=${this.labelId} name="label" @slotchange=${this.onLabelSlotChange}></slot>`;
7071
}
7172
}
73+
74+
const registry = globalThis.customElements;
75+
if (registry && !registry.get(tag)) {
76+
registry.define(tag, ClippyHtmlImage);
77+
}

packages/clippy-components/src/clippy-modal/index.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ import amsDialogStyles from '@amsterdam/design-system-css/dist/dialog/dialog.css
22
import amsVisuallyHiddenStyles from '@amsterdam/design-system-css/dist/visually-hidden/visually-hidden.css?inline';
33
import utrechtButtonStyles from '@utrecht/button-css/dist/index.css?inline';
44
import { LitElement, html, unsafeCSS, nothing } from 'lit';
5-
import { customElement, property, query } from 'lit/decorators.js';
5+
import { property, query } from 'lit/decorators.js';
66
import { dialogStyles } from './styles';
77

88
let dialogInstanceCounter = 0;
99

10+
const tag = 'clippy-modal';
11+
1012
export const DIALOG_BUTTON_VALUES = {
1113
cancel: 'cancel',
1214
confirm: 'confirm',
1315
};
1416

15-
@customElement('clippy-modal')
1617
export class ClippyModal extends LitElement {
1718
/**
1819
* Id of an element that describes the dialog, used for aria-describedby.
@@ -120,9 +121,9 @@ export class ClippyModal extends LitElement {
120121
>
121122
<form method="dialog" novalidate>
122123
<header class="ams-dialog__header">
123-
<h1 id=${this.titleId}>
124+
<clippy-heading level={1} id=${this.titleId}>
124125
<slot name="title">${this.title}</slot>
125-
</h1>
126+
</clippy-heading>
126127
<button class="utrecht-button utrecht-button--primary-action" type="button" @click=${this.onCloseClick}>
127128
<span class="ams-visually-hidden">Sluiten</span>
128129
<div style=" --utrecht-icon-size: 8px;">
@@ -155,3 +156,8 @@ export class ClippyModal extends LitElement {
155156
`;
156157
}
157158
}
159+
160+
const registry = globalThis.customElements;
161+
if (registry && !registry.get(tag)) {
162+
registry.define(tag, ClippyModal);
163+
}

packages/clippy-storybook/src/GemeenteVoorbeeldHome.stories.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react-vite';
2-
import GemeenteVoorbeeldHome, {
3-
type GemeenteVoorbeeldHomeProps,
4-
} from '@nl-design-system-community/theme-wizard-templates/src/pages/gemeentevoorbeeld/GemeenteVoorbeeldHome';
2+
import { GemeenteVoorbeeldHome, type GemeenteVoorbeeldHomeProps } from '@nl-design-system-community/theme-wizard-templates/react';
53
import * as React from 'react';
64
import '@utrecht/component-library-css';
75
import documentation from '../docs/templates/gemeente-voorbeeld-documentatie.md?raw';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite';
2+
import '@nl-design-system-community/clippy-components/clippy-heading';
3+
import readme from '@nl-design-system-community/clippy-components/src/clippy-heading/README.md?raw';
4+
import { html } from 'lit';
5+
import React from 'react';
6+
import { templateToHtml } from '../utils/templateToHtml';
7+
8+
interface HeadingStoryArgs {
9+
content: string;
10+
level: number;
11+
}
12+
13+
// Docs template builds a full <clippy-heading> element for the Source block.
14+
const createTemplate = (level: number, content: string) => html`<clippy-heading level="${level}">${content}</clippy-heading>`;
15+
16+
const meta = {
17+
id: 'clippy-heading',
18+
args: {
19+
content: 'Pagina titel',
20+
level: 1,
21+
},
22+
argTypes: {
23+
content: {
24+
name: 'Content',
25+
defaultValue: '',
26+
description: 'Text',
27+
type: {
28+
name: 'string',
29+
required: true,
30+
},
31+
},
32+
level: {
33+
name: 'Level',
34+
control: { max: 6, min: 1, step: 1, type: 'number' },
35+
defaultValue: 1,
36+
description: 'Heading level (1–6)',
37+
type: {
38+
name: 'number',
39+
required: true,
40+
},
41+
},
42+
},
43+
parameters: {
44+
docs: {
45+
description: {
46+
component: readme,
47+
},
48+
},
49+
},
50+
render: ({ content, level }: HeadingStoryArgs) => React.createElement('clippy-heading', { level }, content),
51+
tags: ['autodocs'],
52+
title: 'Clippy/Heading',
53+
} satisfies Meta<HeadingStoryArgs>;
54+
55+
export default meta;
56+
57+
type Story = StoryObj<typeof meta>;
58+
59+
export const Default: Story = {
60+
name: 'Heading',
61+
parameters: {
62+
docs: {
63+
source: {
64+
transform: (_code: string, storyContext: { args: HeadingStoryArgs }) => {
65+
const template = createTemplate(storyContext.args.level, storyContext.args.content);
66+
return templateToHtml(template);
67+
},
68+
type: 'code',
69+
},
70+
},
71+
},
72+
};

packages/theme-wizard-app/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import './src/components/app/app';
1+
import './src/components/app/app';

0 commit comments

Comments
 (0)