@progressive-development/pd-page 0.9.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -2
  2. package/README.md +34 -57
  3. package/dist/generated/locales/be.d.ts +19 -1
  4. package/dist/generated/locales/be.d.ts.map +1 -1
  5. package/dist/generated/locales/de.d.ts +19 -1
  6. package/dist/generated/locales/de.d.ts.map +1 -1
  7. package/dist/generated/locales/en.d.ts +19 -1
  8. package/dist/generated/locales/en.d.ts.map +1 -1
  9. package/dist/index.d.ts +6 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +7 -0
  12. package/dist/locales/be.js +19 -1
  13. package/dist/locales/de.js +19 -1
  14. package/dist/locales/en.js +19 -1
  15. package/dist/pd-contact-us/PdContactUs.d.ts +15 -5
  16. package/dist/pd-contact-us/PdContactUs.d.ts.map +1 -1
  17. package/dist/pd-contact-us/PdContactUs.js +94 -134
  18. package/dist/pd-contact-us/pd-contact-us.stories.d.ts +36 -5
  19. package/dist/pd-contact-us/pd-contact-us.stories.d.ts.map +1 -1
  20. package/dist/pd-content/dist/pd-notice-box/PdNoticeBox.js +224 -0
  21. package/dist/pd-content/dist/pd-notice-box/pd-notice-box.js +8 -0
  22. package/dist/pd-footer/PdFooter.d.ts +27 -15
  23. package/dist/pd-footer/PdFooter.d.ts.map +1 -1
  24. package/dist/pd-footer/PdFooter.js +122 -74
  25. package/dist/pd-footer/pd-footer.stories.d.ts +47 -7
  26. package/dist/pd-footer/pd-footer.stories.d.ts.map +1 -1
  27. package/dist/pd-login/PdLogin.d.ts +59 -0
  28. package/dist/pd-login/PdLogin.d.ts.map +1 -0
  29. package/dist/pd-login/PdLogin.js +292 -0
  30. package/dist/pd-login/pd-login.d.ts +3 -0
  31. package/dist/pd-login/pd-login.d.ts.map +1 -0
  32. package/dist/pd-login/pd-login.stories.d.ts +55 -0
  33. package/dist/pd-login/pd-login.stories.d.ts.map +1 -0
  34. package/dist/pd-login.d.ts +2 -0
  35. package/dist/pd-login.js +8 -0
  36. package/dist/pd-menu/PdMenu.d.ts +72 -40
  37. package/dist/pd-menu/PdMenu.d.ts.map +1 -1
  38. package/dist/pd-menu/PdMenu.js +384 -276
  39. package/dist/pd-menu/pd-menu.stories.d.ts +59 -17
  40. package/dist/pd-menu/pd-menu.stories.d.ts.map +1 -1
  41. package/dist/pd-socialmedia/PdSocialmedia.d.ts +56 -0
  42. package/dist/pd-socialmedia/PdSocialmedia.d.ts.map +1 -0
  43. package/dist/pd-socialmedia/PdSocialmedia.js +426 -0
  44. package/dist/pd-socialmedia/pd-socialmedia-model.d.ts +16 -0
  45. package/dist/pd-socialmedia/pd-socialmedia-model.d.ts.map +1 -0
  46. package/dist/pd-socialmedia/pd-socialmedia-model.js +240 -0
  47. package/dist/pd-socialmedia/pd-socialmedia.d.ts +3 -0
  48. package/dist/pd-socialmedia/pd-socialmedia.d.ts.map +1 -0
  49. package/dist/pd-socialmedia/pd-socialmedia.stories.d.ts +53 -0
  50. package/dist/pd-socialmedia/pd-socialmedia.stories.d.ts.map +1 -0
  51. package/dist/pd-socialmedia.d.ts +2 -0
  52. package/dist/pd-socialmedia.js +7 -0
  53. package/dist/pd-toast/PdToast.d.ts +23 -0
  54. package/dist/pd-toast/PdToast.d.ts.map +1 -0
  55. package/dist/pd-toast/PdToast.js +222 -0
  56. package/dist/pd-toast/pd-toast.d.ts +3 -0
  57. package/dist/pd-toast/pd-toast.d.ts.map +1 -0
  58. package/dist/pd-toast/pd-toast.stories.d.ts +47 -0
  59. package/dist/pd-toast/pd-toast.stories.d.ts.map +1 -0
  60. package/dist/pd-toast.d.ts +2 -0
  61. package/dist/pd-toast.js +8 -0
  62. package/dist/stories/01_index.stories.d.ts +36 -4
  63. package/dist/stories/01_index.stories.d.ts.map +1 -1
  64. package/dist/toast-bus/toast-bus.d.ts +61 -0
  65. package/dist/toast-bus/toast-bus.d.ts.map +1 -0
  66. package/dist/toast-bus/toast-bus.js +42 -0
  67. package/dist/types.d.ts +18 -0
  68. package/dist/types.d.ts.map +1 -1
  69. package/package.json +14 -8
@@ -0,0 +1,240 @@
1
+ const trim = (s) => s.trim();
2
+ const stripAt = (s) => s.replace(/^@/, "");
3
+ const ensureHttps = (url) => /^https?:\/\//i.test(url) ? url : `https://${url}`;
4
+ const SOCIAL_PROVIDERS = [
5
+ // --- Social ---
6
+ {
7
+ id: "instagram",
8
+ label: "Instagram",
9
+ aliases: ["insta", "ig"],
10
+ category: "Social",
11
+ icon: "📸",
12
+ brandColor: "#E4405F",
13
+ inputKind: "username",
14
+ placeholder: "@deinname",
15
+ pattern: /^[A-Za-z0-9._]{1,30}$/,
16
+ normalize: (raw) => stripAt(trim(raw)),
17
+ toUrl: (input) => `https://instagram.com/${stripAt(trim(input))}`
18
+ },
19
+ {
20
+ id: "tiktok",
21
+ label: "TikTok",
22
+ aliases: ["tiktok"],
23
+ category: "Social",
24
+ icon: "🎵",
25
+ brandColor: "#000000",
26
+ inputKind: "username",
27
+ placeholder: "@deinname",
28
+ pattern: /^[A-Za-z0-9._]{2,24}$/,
29
+ normalize: (raw) => stripAt(trim(raw)),
30
+ toUrl: (input) => `https://www.tiktok.com/@${stripAt(trim(input))}`
31
+ },
32
+ {
33
+ id: "facebook",
34
+ label: "Facebook",
35
+ aliases: ["fb", "facebook page"],
36
+ category: "Social",
37
+ icon: "📘",
38
+ brandColor: "#1877F2",
39
+ inputKind: "url",
40
+ placeholder: "facebook.com/deinprofil",
41
+ pattern: /^https?:\/\/(www\.)?facebook\.com\/.+/i,
42
+ toUrl: (input) => ensureHttps(trim(input))
43
+ },
44
+ {
45
+ id: "x",
46
+ label: "X (Twitter)",
47
+ aliases: ["twitter"],
48
+ category: "Social",
49
+ icon: "X",
50
+ brandColor: "#000000",
51
+ inputKind: "username",
52
+ placeholder: "@deinname",
53
+ pattern: /^[A-Za-z0-9_]{1,15}$/,
54
+ normalize: (raw) => stripAt(trim(raw)),
55
+ toUrl: (input) => `https://x.com/${stripAt(trim(input))}`
56
+ },
57
+ {
58
+ id: "youtube",
59
+ label: "YouTube",
60
+ aliases: ["yt", "youtube channel"],
61
+ category: "Streaming",
62
+ icon: "▶️",
63
+ brandColor: "#FF0000",
64
+ inputKind: "url",
65
+ placeholder: "youtube.com/@deinname oder Kanal-URL",
66
+ pattern: /^https?:\/\/(www\.)?youtube\.com\/.+/i,
67
+ toUrl: (input) => ensureHttps(trim(input))
68
+ },
69
+ {
70
+ id: "twitch",
71
+ label: "Twitch",
72
+ aliases: ["twitch tv"],
73
+ category: "Streaming",
74
+ icon: "🎮",
75
+ brandColor: "#9146FF",
76
+ inputKind: "username",
77
+ placeholder: "deinname",
78
+ pattern: /^[A-Za-z0-9_]{4,25}$/,
79
+ normalize: (raw) => trim(raw),
80
+ toUrl: (input) => `https://twitch.tv/${trim(input)}`
81
+ },
82
+ // --- Music / DJ ---
83
+ {
84
+ id: "soundcloud",
85
+ label: "SoundCloud",
86
+ aliases: ["sc"],
87
+ category: "Music",
88
+ icon: "☁️",
89
+ brandColor: "#FF5500",
90
+ inputKind: "username",
91
+ placeholder: "deinname",
92
+ pattern: /^[A-Za-z0-9-_.]{3,40}$/,
93
+ normalize: (raw) => trim(raw).replace(/^https?:\/\/(www\.)?soundcloud\.com\//i, ""),
94
+ toUrl: (input) => `https://soundcloud.com/${trim(input)}`
95
+ },
96
+ {
97
+ id: "mixcloud",
98
+ label: "Mixcloud",
99
+ aliases: ["mix cloud"],
100
+ category: "Music",
101
+ icon: "📻",
102
+ brandColor: "#5000FF",
103
+ inputKind: "username",
104
+ placeholder: "deinname",
105
+ pattern: /^[A-Za-z0-9-_.]{3,40}$/,
106
+ normalize: (raw) => trim(raw).replace(/^https?:\/\/(www\.)?mixcloud\.com\//i, ""),
107
+ toUrl: (input) => `https://www.mixcloud.com/${trim(input)}/`
108
+ },
109
+ {
110
+ id: "hearthis",
111
+ label: "HearThis.at",
112
+ aliases: ["hearthis"],
113
+ category: "Music",
114
+ icon: "🔊",
115
+ brandColor: "#D61C1C",
116
+ inputKind: "username",
117
+ placeholder: "deinname",
118
+ pattern: /^[A-Za-z0-9-_.]{3,40}$/,
119
+ normalize: (raw) => trim(raw).replace(/^https?:\/\/(www\.)?hearthis\.at\//i, ""),
120
+ toUrl: (input) => `https://hearthis.at/${trim(input)}/`
121
+ },
122
+ {
123
+ id: "beatport",
124
+ label: "Beatport (Artist)",
125
+ aliases: ["beat port"],
126
+ category: "DJ/Booking",
127
+ icon: "🎧",
128
+ brandColor: "#A8E00F",
129
+ inputKind: "url",
130
+ placeholder: "beatport.com/artist/... oder /profile/...",
131
+ pattern: /^https?:\/\/(www\.)?beatport\.com\/(artist|profile)\/.+/i,
132
+ toUrl: (input) => ensureHttps(trim(input))
133
+ },
134
+ {
135
+ id: "residentadvisor",
136
+ label: "Resident Advisor",
137
+ aliases: ["ra", "ra.co"],
138
+ category: "DJ/Booking",
139
+ icon: "🟢",
140
+ brandColor: "#BADA55",
141
+ inputKind: "url",
142
+ placeholder: "ra.co/dj/deinname",
143
+ pattern: /^https?:\/\/(www\.)?ra\.co\/dj\/.+/i,
144
+ toUrl: (input) => ensureHttps(trim(input))
145
+ },
146
+ {
147
+ id: "spotify",
148
+ label: "Spotify (Artist)",
149
+ aliases: ["spotify artist"],
150
+ category: "Music",
151
+ icon: "🟢",
152
+ brandColor: "#1DB954",
153
+ inputKind: "id",
154
+ placeholder: "Artist-ID oder vollständige URL",
155
+ pattern: /^[0-9A-Za-z]{22}$|^https?:\/\/open\.spotify\.com\/artist\/[0-9A-Za-z]{22}/i,
156
+ normalize: (raw) => {
157
+ const s = trim(raw);
158
+ const m = s.match(/artist\/([0-9A-Za-z]{22})/);
159
+ return m ? m[1] : s;
160
+ },
161
+ toUrl: (input) => {
162
+ const id = trim(input).match(/^[0-9A-Za-z]{22}$/) ? input : input.match(/artist\/([0-9A-Za-z]{22})/)?.[1] ?? input;
163
+ return `https://open.spotify.com/artist/${id}`;
164
+ }
165
+ },
166
+ {
167
+ id: "applemusic",
168
+ label: "Apple Music",
169
+ aliases: ["itunes", "apple music artist"],
170
+ category: "Music",
171
+ icon: "🎵",
172
+ brandColor: "#FA2D48",
173
+ inputKind: "url",
174
+ placeholder: "music.apple.com/... (Artist-Link)",
175
+ pattern: /^https?:\/\/music\.apple\.com\/.+/i,
176
+ toUrl: (input) => ensureHttps(trim(input))
177
+ },
178
+ {
179
+ id: "deezer",
180
+ label: "Deezer (Artist)",
181
+ aliases: ["deezer"],
182
+ category: "Music",
183
+ icon: "🎶",
184
+ brandColor: "#00C7F2",
185
+ inputKind: "url",
186
+ placeholder: "deezer.com/artist/...",
187
+ pattern: /^https?:\/\/(www\.)?deezer\.com\/.+/i,
188
+ toUrl: (input) => ensureHttps(trim(input))
189
+ },
190
+ {
191
+ id: "bandcamp",
192
+ label: "Bandcamp",
193
+ aliases: ["band camp"],
194
+ category: "Music",
195
+ icon: "💿",
196
+ brandColor: "#629AA9",
197
+ inputKind: "url",
198
+ placeholder: "deinname.bandcamp.com",
199
+ pattern: /^https?:\/\/[A-Za-z0-9-]+\.bandcamp\.com(\/.*)?$/i,
200
+ toUrl: (input) => ensureHttps(trim(input))
201
+ },
202
+ {
203
+ id: "discogs",
204
+ label: "Discogs",
205
+ aliases: ["disc ogs"],
206
+ category: "Catalog",
207
+ icon: "📀",
208
+ brandColor: "#333333",
209
+ inputKind: "url",
210
+ placeholder: "discogs.com/artist/... oder /user/...",
211
+ pattern: /^https?:\/\/(www\.)?discogs\.com\/(artist|user)\/.+/i,
212
+ toUrl: (input) => ensureHttps(trim(input))
213
+ },
214
+ {
215
+ id: "mixesdb",
216
+ label: "MixesDB",
217
+ aliases: ["mixes db"],
218
+ category: "Catalog",
219
+ icon: "📂",
220
+ brandColor: "#FFB000",
221
+ inputKind: "url",
222
+ placeholder: "mixesdb.com/... (Profil-URL)",
223
+ pattern: /^https?:\/\/(www\.)?mixesdb\.com\/.+/i,
224
+ toUrl: (input) => ensureHttps(trim(input))
225
+ },
226
+ {
227
+ id: "linkedin",
228
+ label: "LinkedIn",
229
+ aliases: ["li"],
230
+ category: "Social",
231
+ icon: "🔗",
232
+ brandColor: "#0A66C2",
233
+ inputKind: "url",
234
+ placeholder: "linkedin.com/in/deinname",
235
+ pattern: /^https?:\/\/(www\.)?linkedin\.com\/.+/i,
236
+ toUrl: (input) => ensureHttps(trim(input))
237
+ }
238
+ ];
239
+
240
+ export { SOCIAL_PROVIDERS };
@@ -0,0 +1,3 @@
1
+ import { PdSocialmedia } from './PdSocialmedia.js';
2
+ export { PdSocialmedia };
3
+ //# sourceMappingURL=pd-socialmedia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-socialmedia.d.ts","sourceRoot":"","sources":["../../src/pd-socialmedia/pd-socialmedia.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnD,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
2
+ import { SocialProvider } from './pd-socialmedia-model.js';
3
+ import { SocialEntry } from '../types.js';
4
+ /**
5
+ * Story arguments interface for pd-socialmedia component.
6
+ * Maps to the component's public API.
7
+ */
8
+ interface PdSocialmediaArgs {
9
+ /** View mode (icons) or edit mode (list with delete) */
10
+ summary: boolean;
11
+ /** Social media entries */
12
+ items: SocialEntry[];
13
+ /** Provider metadata definitions */
14
+ providers: SocialProvider[];
15
+ /** Show label below icon in view mode */
16
+ showLabelBelowIcon: boolean;
17
+ /** Open links in new tab */
18
+ openLinksInNewTab: boolean;
19
+ }
20
+ /**
21
+ * ## pd-socialmedia
22
+ *
23
+ * Social media profiles display and editor component.
24
+ *
25
+ * ### Features
26
+ * - **View Mode** (`summary`): Displays social icons with optional labels below
27
+ * - **Edit Mode**: Suggestion box for adding providers and list with delete for removing
28
+ * - **Provider Injection**: Custom provider definitions can be injected via `providers` property
29
+ * - **Link Behavior**: Configurable to open in same or new tab
30
+ * - **Responsive**: Icons wrap on smaller screens
31
+ *
32
+ * ### Accessibility
33
+ * - View mode renders a `<ul>` list with `aria-label`
34
+ * - Icons are clickable links with `aria-label` per provider
35
+ * - Edit mode uses `<button>` elements with `aria-label` for delete actions
36
+ * - Focus-visible styling on delete buttons
37
+ */
38
+ declare const meta: Meta<PdSocialmediaArgs>;
39
+ export default meta;
40
+ type Story = StoryObj<PdSocialmediaArgs>;
41
+ /** Default view with social icons. Interactive via Controls panel. */
42
+ export declare const Default: Story;
43
+ /** All view mode configurations at a glance. */
44
+ export declare const AllVariants: Story;
45
+ /** Many entries demonstrating wrapping behavior. */
46
+ export declare const LongList: Story;
47
+ /** Edit mode with suggestion box for adding and delete buttons for removing entries. */
48
+ export declare const EditMode: Story;
49
+ /** Injecting custom provider definitions alongside the defaults. */
50
+ export declare const CustomProviders: Story;
51
+ /** CSS Custom Properties — Branded and Redesigned variants. */
52
+ export declare const CustomStyling: Story;
53
+ //# sourceMappingURL=pd-socialmedia.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-socialmedia.stories.d.ts","sourceRoot":"","sources":["../../src/pd-socialmedia/pd-socialmedia.stories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,0CAA0C,CAAC;AAClD,OAAO,qDAAqD,CAAC;AAC7D,OAAO,+CAA+C,CAAC;AAEvD,OAAO,EAAoB,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,qBAAqB,CAAC;AAM7B;;;GAGG;AACH,UAAU,iBAAiB;IACzB,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,oCAAoC;IACpC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,yCAAyC;IACzC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,4BAA4B;IAC5B,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAiCD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,iBAAiB,CA6EjC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAMzC,sEAAsE;AACtE,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAMjC,gDAAgD;AAChD,eAAO,MAAM,WAAW,EAAE,KA8CzB,CAAC;AAMF,oDAAoD;AACpD,eAAO,MAAM,QAAQ,EAAE,KAmCtB,CAAC;AAMF,wFAAwF;AACxF,eAAO,MAAM,QAAQ,EAAE,KAmBtB,CAAC;AAMF,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,KA0C7B,CAAC;AAMF,+DAA+D;AAC/D,eAAO,MAAM,aAAa,EAAE,KA2F3B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './pd-socialmedia/pd-socialmedia'
2
+ export {}
@@ -0,0 +1,7 @@
1
+ import { PdSocialmedia } from './pd-socialmedia/PdSocialmedia.js';
2
+
3
+ if (!customElements.get("pd-socialmedia")) {
4
+ customElements.define("pd-socialmedia", PdSocialmedia);
5
+ }
6
+
7
+ export { PdSocialmedia };
@@ -0,0 +1,23 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class PdToast extends LitElement {
3
+ private _message;
4
+ /** Whether the current toast is an error */
5
+ isError: boolean;
6
+ /** Whether the current toast is a success */
7
+ isSuccess: boolean;
8
+ private _queue;
9
+ private _isProcessing;
10
+ private _autoCloseTimer?;
11
+ private _boundHandleToast;
12
+ static styles: import('lit').CSSResult;
13
+ connectedCallback(): void;
14
+ disconnectedCallback(): void;
15
+ render(): import('lit').TemplateResult<1>;
16
+ private _onCloseKeyDown;
17
+ private _handleToast;
18
+ private _processQueue;
19
+ private _showToast;
20
+ private _close;
21
+ private _clearTimer;
22
+ }
23
+ //# sourceMappingURL=PdToast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PdToast.d.ts","sourceRoot":"","sources":["../../src/pd-toast/PdToast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAqB5C,qBACa,OAAQ,SAAQ,UAAU;IAK5B,OAAO,CAAC,QAAQ,CAAM;IAE/B,4CAA4C;IAE5C,OAAO,UAAS;IAEhB,6CAA6C;IAE7C,SAAS,UAAS;IAMlB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,iBAAiB,CAAgC;IAMzD,MAAM,CAAC,MAAM,0BAsFX;IAMF,iBAAiB,IAAI,IAAI;IAQzB,oBAAoB,IAAI,IAAI;IAa5B,MAAM;IAeN,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,WAAW;CAMpB"}
@@ -0,0 +1,222 @@
1
+ import { css, LitElement, html } from 'lit';
2
+ import { state, property } from 'lit/decorators.js';
3
+ import { localized, msg } from '@lit/localize';
4
+ import { pdIcons } from '@progressive-development/pd-icon';
5
+ import { toastBus } from '../toast-bus/toast-bus.js';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __decorateClass = (decorators, target, key, kind) => {
10
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
11
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
12
+ if (decorator = decorators[i])
13
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
14
+ if (kind && result) __defProp(target, key, result);
15
+ return result;
16
+ };
17
+ const DEFAULT_DURATION = 6e3;
18
+ const ANIMATION_DURATION = 300;
19
+ let PdToast = class extends LitElement {
20
+ constructor() {
21
+ super(...arguments);
22
+ this._message = "";
23
+ this.isError = false;
24
+ this.isSuccess = false;
25
+ // ---------------------------------------------------------------------------
26
+ // Private
27
+ // ---------------------------------------------------------------------------
28
+ this._queue = [];
29
+ this._isProcessing = false;
30
+ this._boundHandleToast = this._handleToast.bind(this);
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Lifecycle
34
+ // ---------------------------------------------------------------------------
35
+ connectedCallback() {
36
+ super.connectedCallback();
37
+ this.setAttribute("aria-live", "polite");
38
+ toastBus.addEventListener("toast", this._boundHandleToast);
39
+ }
40
+ disconnectedCallback() {
41
+ super.disconnectedCallback();
42
+ this._clearTimer();
43
+ toastBus.removeEventListener(
44
+ "toast",
45
+ this._boundHandleToast
46
+ );
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Render
50
+ // ---------------------------------------------------------------------------
51
+ render() {
52
+ return html`
53
+ <div class="content" part="content">${this._message}</div>
54
+ <pd-icon
55
+ icon=${pdIcons.ICON_CLOSE}
56
+ class="close-icon"
57
+ tabindex="0"
58
+ role="button"
59
+ aria-label="${msg("Schließen", { id: "pdPage.toast.ariaClose" })}"
60
+ @click=${this._close}
61
+ @keydown=${this._onCloseKeyDown}
62
+ ></pd-icon>
63
+ `;
64
+ }
65
+ _onCloseKeyDown(e) {
66
+ if (e.key === "Enter" || e.key === " ") {
67
+ e.preventDefault();
68
+ this._close();
69
+ }
70
+ }
71
+ // ---------------------------------------------------------------------------
72
+ // Queue Processing
73
+ // ---------------------------------------------------------------------------
74
+ _handleToast(event) {
75
+ const detail = event.detail;
76
+ this._queue.push(detail);
77
+ this._processQueue();
78
+ }
79
+ _processQueue() {
80
+ if (this._isProcessing || this._queue.length === 0) {
81
+ return;
82
+ }
83
+ const item = this._queue.shift();
84
+ this._showToast(item);
85
+ }
86
+ _showToast(detail) {
87
+ this._isProcessing = true;
88
+ this._message = detail.message;
89
+ this.isError = detail.type === "error";
90
+ this.isSuccess = detail.type === "success";
91
+ if (this.isError) {
92
+ this.setAttribute("role", "alert");
93
+ } else {
94
+ this.removeAttribute("role");
95
+ }
96
+ this.classList.add("visible");
97
+ const duration = detail.duration ?? DEFAULT_DURATION;
98
+ if (duration > 0) {
99
+ this._autoCloseTimer = window.setTimeout(() => {
100
+ this._close();
101
+ }, duration);
102
+ }
103
+ }
104
+ _close() {
105
+ this._clearTimer();
106
+ this.classList.remove("visible");
107
+ this._isProcessing = false;
108
+ window.setTimeout(() => {
109
+ this._processQueue();
110
+ }, ANIMATION_DURATION);
111
+ }
112
+ _clearTimer() {
113
+ if (this._autoCloseTimer !== void 0) {
114
+ window.clearTimeout(this._autoCloseTimer);
115
+ this._autoCloseTimer = void 0;
116
+ }
117
+ }
118
+ };
119
+ // ---------------------------------------------------------------------------
120
+ // Styles
121
+ // ---------------------------------------------------------------------------
122
+ PdToast.styles = css`
123
+ :host {
124
+ --pd-icon-size: 1rem;
125
+ --_toast-transition-duration: 300ms;
126
+
127
+ /* Mobile first: smaller margins */
128
+ --_toast-margin: 12px;
129
+
130
+ position: fixed;
131
+ bottom: var(--pd-toast-bottom, var(--_toast-margin));
132
+ left: var(--pd-toast-left, var(--_toast-margin));
133
+ width: calc(100% - var(--_toast-margin) * 2);
134
+ max-width: var(--pd-toast-max-width, 400px);
135
+
136
+ z-index: var(--pd-toast-z-index, 105);
137
+
138
+ background: var(--pd-toast-bg, var(--app-primary-color, #ebcf57));
139
+ color: var(--pd-toast-color, #0a3a48);
140
+ padding: var(--pd-toast-padding, 0.6rem);
141
+ padding-right: calc(var(--pd-toast-padding, 0.6rem) + 1.4rem);
142
+ border-radius: var(
143
+ --pd-toast-border-radius,
144
+ var(--item-border-radius, 2px)
145
+ );
146
+ box-shadow: var(--pd-toast-shadow, 3px 5px 5px 3px lightgrey);
147
+
148
+ display: flex;
149
+ align-items: center;
150
+ gap: 0.5rem;
151
+
152
+ transform: translateX(-150%);
153
+ opacity: 0;
154
+ transition:
155
+ transform var(--_toast-transition-duration) ease-out,
156
+ opacity var(--_toast-transition-duration) ease-out;
157
+
158
+ pointer-events: none;
159
+ }
160
+
161
+ /* Tablet and up: more spacing */
162
+ @media (min-width: 768px) {
163
+ :host {
164
+ --_toast-margin: 30px;
165
+ }
166
+ }
167
+
168
+ :host([isError]) {
169
+ background: var(--pd-toast-error-bg, darkred);
170
+ color: var(--pd-toast-error-color, #fff);
171
+ }
172
+
173
+ :host([isSuccess]) {
174
+ background: var(--pd-toast-success-bg, green);
175
+ color: var(--pd-toast-success-color, #fff);
176
+ }
177
+
178
+ :host(.visible) {
179
+ transform: translateX(0);
180
+ opacity: 1;
181
+ pointer-events: auto;
182
+ }
183
+
184
+ .content {
185
+ flex: 1;
186
+ word-wrap: break-word;
187
+ overflow-wrap: break-word;
188
+ }
189
+
190
+ .close-icon {
191
+ position: absolute;
192
+ cursor: pointer;
193
+ right: var(--pd-spacing-sm, 0.5rem);
194
+ top: var(--pd-spacing-sm, 0.5rem);
195
+ }
196
+
197
+ .close-icon:focus {
198
+ outline: 2px solid currentColor;
199
+ outline-offset: 2px;
200
+ border-radius: var(--pd-radius-sm, 2px);
201
+ }
202
+
203
+ @media (prefers-reduced-motion: reduce) {
204
+ :host {
205
+ --_toast-transition-duration: 0ms;
206
+ }
207
+ }
208
+ `;
209
+ __decorateClass([
210
+ state()
211
+ ], PdToast.prototype, "_message", 2);
212
+ __decorateClass([
213
+ property({ type: Boolean, reflect: true })
214
+ ], PdToast.prototype, "isError", 2);
215
+ __decorateClass([
216
+ property({ type: Boolean, reflect: true })
217
+ ], PdToast.prototype, "isSuccess", 2);
218
+ PdToast = __decorateClass([
219
+ localized()
220
+ ], PdToast);
221
+
222
+ export { PdToast };
@@ -0,0 +1,3 @@
1
+ import { PdToast } from './PdToast.js';
2
+ export { PdToast };
3
+ //# sourceMappingURL=pd-toast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-toast.d.ts","sourceRoot":"","sources":["../../src/pd-toast/pd-toast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAOvC,OAAO,EAAE,OAAO,EAAE,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
2
+ import { ToastType } from '../toast-bus/toast-bus.js';
3
+ /**
4
+ * Story arguments interface for pd-toast component.
5
+ * Maps to the toastBus API since pd-toast has no direct properties.
6
+ */
7
+ interface PdToastArgs {
8
+ /** Message to display */
9
+ message: string;
10
+ /** Toast type (success, error, info) */
11
+ type: ToastType;
12
+ /** Duration in ms (-1 for persistent, no auto-close) */
13
+ duration: number;
14
+ }
15
+ /**
16
+ * ## pd-toast
17
+ *
18
+ * Toast notification component with internal queue management, triggered via the global toastBus singleton.
19
+ *
20
+ * ### Features
21
+ * - Three toast types: success (green), error (red), info (yellow)
22
+ * - Internal queue management for sequential display of multiple toasts
23
+ * - Auto-close with configurable duration (errors are persistent by default)
24
+ * - Manual close via X icon (click or keyboard)
25
+ * - Slide-in animation with prefers-reduced-motion support
26
+ * - Responsive positioning (smaller margins on mobile)
27
+ * - Global singleton pattern via toastBus EventTarget
28
+ *
29
+ * ### Accessibility
30
+ * - Uses `aria-live="polite"` for screen reader announcements
31
+ * - Error toasts use `role="alert"` for immediate announcement
32
+ * - Close button has `role="button"` and `aria-label`
33
+ * - Keyboard support: Tab to focus close button, Enter/Space to close
34
+ * - Respects `prefers-reduced-motion` media query
35
+ */
36
+ declare const meta: Meta<PdToastArgs>;
37
+ export default meta;
38
+ type Story = StoryObj<PdToastArgs>;
39
+ /** Interactive demo — click buttons to trigger different toast types. */
40
+ export declare const Default: Story;
41
+ /** All three toast types side by side — click each button to see the corresponding toast. */
42
+ export declare const AllTypes: Story;
43
+ /** Demonstrates the internal queue — multiple toasts are shown sequentially. */
44
+ export declare const QueueDemo: Story;
45
+ /** CSS Custom Properties -- Branded and Redesigned variants. */
46
+ export declare const CustomStyling: Story;
47
+ //# sourceMappingURL=pd-toast.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-toast.stories.d.ts","sourceRoot":"","sources":["../../src/pd-toast/pd-toast.stories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAY,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,eAAe,CAAC;AAMvB;;;GAGG;AACH,UAAU,WAAW;IACnB,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,IAAI,EAAE,SAAS,CAAC;IAChB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,WAAW,CA2D3B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AAMnC,yEAAyE;AACzE,eAAO,MAAM,OAAO,EAAE,KAyGrB,CAAC;AAMF,6FAA6F;AAC7F,eAAO,MAAM,QAAQ,EAAE,KAmDtB,CAAC;AAMF,gFAAgF;AAChF,eAAO,MAAM,SAAS,EAAE,KAmCvB,CAAC;AAMF,gEAAgE;AAChE,eAAO,MAAM,aAAa,EAAE,KAoH3B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './pd-toast/pd-toast'
2
+ export {}
@@ -0,0 +1,8 @@
1
+ import { PdToast } from './pd-toast/PdToast.js';
2
+
3
+ const tag = "pd-toast";
4
+ if (!customElements.get(tag)) {
5
+ customElements.define(tag, PdToast);
6
+ }
7
+
8
+ export { PdToast };
@@ -1,5 +1,37 @@
1
- import { Meta, StoryObj } from '@storybook/web-components';
2
- declare const _default: Meta;
3
- export default _default;
4
- export declare const PageExamples: StoryObj;
1
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
2
+ import { PdMenuItem } from '../types.js';
3
+ /**
4
+ * Story arguments interface for the pd-page examples.
5
+ * Combines arguments from multiple pd-page sub-components.
6
+ */
7
+ interface PageExampleArgs {
8
+ /** Main navigation items */
9
+ menuItems: PdMenuItem[];
10
+ /** Top menu items (profile, settings, etc.) */
11
+ topMenuItems: PdMenuItem[];
12
+ /** Whether the teaser/hero section is collapsed */
13
+ teaserClosed: boolean;
14
+ }
15
+ /**
16
+ * ## pd-page / examples
17
+ *
18
+ * Full-page composition examples showing how pd-page sub-components work together.
19
+ *
20
+ * These examples demonstrate realistic page layouts combining:
21
+ * - **pd-menu**: Navigation header with logo, menu items, and top actions
22
+ * - **pd-contact-us**: Contact section with address card and form
23
+ * - **pd-footer**: Footer with legal links and version info
24
+ *
25
+ * Each story shows a different page configuration to illustrate
26
+ * the flexibility of the pd-page component system.
27
+ */
28
+ declare const meta: Meta<PageExampleArgs>;
29
+ export default meta;
30
+ type Story = StoryObj<PageExampleArgs>;
31
+ /** Complete page layout with menu, content sections, contact form, and footer. */
32
+ export declare const FullPage: Story;
33
+ /** Page layout with the menu teaser/hero section collapsed. */
34
+ export declare const TeaserClosed: Story;
35
+ /** Minimal page with just menu and footer — no contact section. */
36
+ export declare const MinimalPage: Story;
5
37
  //# sourceMappingURL=01_index.stories.d.ts.map