@progressive-development/pd-dialog 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 (35) hide show
  1. package/LICENSE +21 -2
  2. package/README.md +34 -57
  3. package/dist/index.d.ts +5 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -0
  6. package/dist/pd-confirm-dialog/PdConfirmDialog.d.ts +40 -0
  7. package/dist/pd-confirm-dialog/PdConfirmDialog.d.ts.map +1 -0
  8. package/dist/pd-confirm-dialog/PdConfirmDialog.js +108 -0
  9. package/dist/pd-confirm-dialog/pd-confirm-dialog.d.ts +7 -0
  10. package/dist/pd-confirm-dialog/pd-confirm-dialog.d.ts.map +1 -0
  11. package/dist/pd-confirm-dialog/pd-confirm-dialog.stories.d.ts +107 -0
  12. package/dist/pd-confirm-dialog/pd-confirm-dialog.stories.d.ts.map +1 -0
  13. package/dist/pd-form-dialog/PdFormDialog.d.ts +54 -0
  14. package/dist/pd-form-dialog/PdFormDialog.d.ts.map +1 -0
  15. package/dist/pd-form-dialog/PdFormDialog.js +181 -0
  16. package/dist/pd-form-dialog/pd-form-dialog.d.ts +6 -0
  17. package/dist/pd-form-dialog/pd-form-dialog.d.ts.map +1 -0
  18. package/dist/pd-form-dialog/pd-form-dialog.stories.d.ts +118 -0
  19. package/dist/pd-form-dialog/pd-form-dialog.stories.d.ts.map +1 -0
  20. package/dist/pd-popup/PdPopup.d.ts +36 -6
  21. package/dist/pd-popup/PdPopup.d.ts.map +1 -1
  22. package/dist/pd-popup/PdPopup.js +98 -29
  23. package/dist/pd-popup/pd-popup.stories.d.ts +56 -22
  24. package/dist/pd-popup/pd-popup.stories.d.ts.map +1 -1
  25. package/dist/pd-popup-dialog/PdPopupDialog.d.ts +36 -9
  26. package/dist/pd-popup-dialog/PdPopupDialog.d.ts.map +1 -1
  27. package/dist/pd-popup-dialog/PdPopupDialog.js +90 -50
  28. package/dist/pd-popup-dialog/pd-popup-dialog.stories.d.ts +52 -18
  29. package/dist/pd-popup-dialog/pd-popup-dialog.stories.d.ts.map +1 -1
  30. package/dist/pd-submit-dialog/PdSubmitDialog.d.ts +8 -4
  31. package/dist/pd-submit-dialog/PdSubmitDialog.d.ts.map +1 -1
  32. package/dist/pd-submit-dialog/PdSubmitDialog.js +0 -2
  33. package/dist/pd-submit-dialog/pd-submit-dialog.stories.d.ts +46 -29
  34. package/dist/pd-submit-dialog/pd-submit-dialog.stories.d.ts.map +1 -1
  35. package/package.json +10 -7
@@ -0,0 +1,181 @@
1
+ import { LitElement, css, html } from 'lit';
2
+ import { property, state, query } from 'lit/decorators.js';
3
+ import '@progressive-development/pd-forms/pd-form-container';
4
+ import '../pd-popup-dialog.js';
5
+ import { BUTTON_KEY_CONFIRM, EVENT_CANCEL, BUTTON_KEY_CANCEL } from '../pd-confirm-dialog/PdConfirmDialog.js';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __decorateClass = (decorators, target, key, kind) => {
9
+ var result = void 0 ;
10
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
11
+ if (decorator = decorators[i])
12
+ result = (decorator(target, key, result) ) || result;
13
+ if (result) __defProp(target, key, result);
14
+ return result;
15
+ };
16
+ const DEFAULT_SUBMIT_DISABLE_TIMEOUT = 5e3;
17
+ const EVENT_FORM_SUBMIT = "pd-form-submit";
18
+ class PdFormDialog extends LitElement {
19
+ // ---------------------------------------------------------------------------
20
+ // Lifecycle
21
+ // ---------------------------------------------------------------------------
22
+ constructor() {
23
+ super();
24
+ this.saveButtonText = "Save";
25
+ this.cancelButtonText = "Cancel";
26
+ this.showRequiredFieldInfo = true;
27
+ this.submitDisableTimeout = DEFAULT_SUBMIT_DISABLE_TIMEOUT;
28
+ this.closeByEscape = false;
29
+ this.closeByBackdrop = false;
30
+ this.blockScroll = false;
31
+ this._validForm = false;
32
+ this._buttons = [];
33
+ this._initializeButtons();
34
+ }
35
+ static {
36
+ // ---------------------------------------------------------------------------
37
+ // Styles
38
+ // ---------------------------------------------------------------------------
39
+ this.styles = css`
40
+ :host {
41
+ display: block;
42
+ --pd-popup-max-width: var(--pd-form-dialog-max-width, 700px);
43
+ }
44
+
45
+ @media (max-width: 767px) {
46
+ :host {
47
+ --pd-popup-max-width: 95%;
48
+ }
49
+ }
50
+ `;
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Render
54
+ // ---------------------------------------------------------------------------
55
+ render() {
56
+ return html`
57
+ <pd-popup-dialog
58
+ @submit-button-clicked="${this._handleButtonClick}"
59
+ title="${this._dialogTitle}"
60
+ .buttons="${this._getButtons()}"
61
+ ?closeByEscape="${this.closeByEscape}"
62
+ ?closeByBackdrop="${this.closeByBackdrop}"
63
+ ?blockScroll="${this.blockScroll}"
64
+ >
65
+ <pd-form-container
66
+ slot="content"
67
+ ?requiredFieldInfo="${this.showRequiredFieldInfo}"
68
+ commonError="${this._validationError || ""}"
69
+ @pd-form-change="${this._handleFormChange}"
70
+ >
71
+ ${this._renderContent()}
72
+ </pd-form-container>
73
+ </pd-popup-dialog>
74
+ `;
75
+ }
76
+ // ---------------------------------------------------------------------------
77
+ // Public Methods
78
+ // ---------------------------------------------------------------------------
79
+ /** Reset the form to initial state */
80
+ reset() {
81
+ this._formContainer?.reset();
82
+ this._validForm = false;
83
+ this._validationError = void 0;
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // Protected Methods
87
+ // ---------------------------------------------------------------------------
88
+ /**
89
+ * Handle button click events.
90
+ * Can be overridden for custom behavior.
91
+ */
92
+ _handleButtonClick(e) {
93
+ if (e.detail.button === BUTTON_KEY_CONFIRM && this._validForm) {
94
+ const formData = this._formContainer.getValues();
95
+ this._disableSaveButtonTemporarily();
96
+ this.dispatchEvent(
97
+ new CustomEvent(EVENT_FORM_SUBMIT, {
98
+ detail: formData,
99
+ bubbles: true,
100
+ composed: true
101
+ })
102
+ );
103
+ } else {
104
+ this.dispatchEvent(
105
+ new CustomEvent(EVENT_CANCEL, {
106
+ bubbles: true,
107
+ composed: true
108
+ })
109
+ );
110
+ }
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Private Methods
114
+ // ---------------------------------------------------------------------------
115
+ _initializeButtons() {
116
+ this._buttons = [
117
+ { key: BUTTON_KEY_CANCEL, name: this.cancelButtonText },
118
+ {
119
+ key: BUTTON_KEY_CONFIRM,
120
+ name: this.saveButtonText,
121
+ disabled: true,
122
+ primary: true
123
+ }
124
+ ];
125
+ }
126
+ _getButtons() {
127
+ return [
128
+ { ...this._buttons[0], name: this.cancelButtonText },
129
+ {
130
+ ...this._buttons[1],
131
+ name: this.saveButtonText,
132
+ disabled: !this._validForm
133
+ }
134
+ ];
135
+ }
136
+ _handleFormChange(e) {
137
+ this._validForm = e.detail.overallValidity && this._isValidFormData();
138
+ e.stopPropagation();
139
+ }
140
+ _disableSaveButtonTemporarily() {
141
+ this._validForm = false;
142
+ window.setTimeout(() => {
143
+ this._validForm = true;
144
+ }, this.submitDisableTimeout);
145
+ }
146
+ }
147
+ __decorateClass([
148
+ property({ type: String })
149
+ ], PdFormDialog.prototype, "saveButtonText");
150
+ __decorateClass([
151
+ property({ type: String })
152
+ ], PdFormDialog.prototype, "cancelButtonText");
153
+ __decorateClass([
154
+ property({ type: Boolean })
155
+ ], PdFormDialog.prototype, "showRequiredFieldInfo");
156
+ __decorateClass([
157
+ property({ type: Number })
158
+ ], PdFormDialog.prototype, "submitDisableTimeout");
159
+ __decorateClass([
160
+ property({ type: Boolean })
161
+ ], PdFormDialog.prototype, "closeByEscape");
162
+ __decorateClass([
163
+ property({ type: Boolean })
164
+ ], PdFormDialog.prototype, "closeByBackdrop");
165
+ __decorateClass([
166
+ property({ type: Boolean })
167
+ ], PdFormDialog.prototype, "blockScroll");
168
+ __decorateClass([
169
+ state()
170
+ ], PdFormDialog.prototype, "_validForm");
171
+ __decorateClass([
172
+ state()
173
+ ], PdFormDialog.prototype, "_validationError");
174
+ __decorateClass([
175
+ state()
176
+ ], PdFormDialog.prototype, "_buttons");
177
+ __decorateClass([
178
+ query("pd-form-container")
179
+ ], PdFormDialog.prototype, "_formContainer");
180
+
181
+ export { EVENT_FORM_SUBMIT, PdFormDialog };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * PdFormDialog barrel export
3
+ */
4
+ export { PdFormDialog } from './PdFormDialog.js';
5
+ export { EVENT_FORM_SUBMIT } from './PdFormDialog.js';
6
+ //# sourceMappingURL=pd-form-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-form-dialog.d.ts","sourceRoot":"","sources":["../../src/pd-form-dialog/pd-form-dialog.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { HTMLTemplateResult, CSSResultGroup } from 'lit';
2
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
3
+ import { PdFormDialog } from './PdFormDialog.js';
4
+ /**
5
+ * Example: Contact form data interface
6
+ */
7
+ interface ContactFormData {
8
+ name: string;
9
+ email: string;
10
+ message: string;
11
+ }
12
+ /**
13
+ * Example: Contact form dialog
14
+ */
15
+ declare class ExampleContactForm extends PdFormDialog<ContactFormData> {
16
+ protected _dialogTitle: string;
17
+ protected _formData: ContactFormData;
18
+ static styles: CSSResultGroup;
19
+ protected _isValidFormData(): boolean;
20
+ protected _renderContent(): HTMLTemplateResult;
21
+ }
22
+ /**
23
+ * Example: User profile form data interface
24
+ */
25
+ interface ProfileFormData {
26
+ displayName: string;
27
+ bio: string;
28
+ language: string;
29
+ }
30
+ /**
31
+ * Example: User profile form dialog
32
+ */
33
+ declare class ExampleProfileForm extends PdFormDialog<ProfileFormData> {
34
+ protected _dialogTitle: string;
35
+ protected _formData: ProfileFormData;
36
+ static styles: CSSResultGroup;
37
+ protected _isValidFormData(): boolean;
38
+ protected _renderContent(): HTMLTemplateResult;
39
+ }
40
+ /**
41
+ * Example: Simple feedback form data interface
42
+ */
43
+ interface FeedbackFormData {
44
+ rating: string;
45
+ feedback: string;
46
+ }
47
+ /**
48
+ * Example: Feedback form dialog with custom rating UI
49
+ */
50
+ declare class ExampleFeedbackForm extends PdFormDialog<FeedbackFormData> {
51
+ protected _dialogTitle: string;
52
+ protected _formData: FeedbackFormData;
53
+ static styles: CSSResultGroup;
54
+ protected _isValidFormData(): boolean;
55
+ private _selectRating;
56
+ protected _renderContent(): HTMLTemplateResult;
57
+ }
58
+ declare global {
59
+ interface HTMLElementTagNameMap {
60
+ "example-contact-form": ExampleContactForm;
61
+ "example-profile-form": ExampleProfileForm;
62
+ "example-feedback-form": ExampleFeedbackForm;
63
+ }
64
+ }
65
+ /**
66
+ * Story arguments interface for pd-form-dialog examples.
67
+ * Maps to the example components' properties.
68
+ */
69
+ interface PdFormDialogArgs {
70
+ /** Save button text */
71
+ saveButtonText: string;
72
+ /** Cancel button text */
73
+ cancelButtonText: string;
74
+ /** Show required field info text */
75
+ showRequiredFieldInfo: boolean;
76
+ /** Double-submit prevention timeout in ms */
77
+ submitDisableTimeout: number;
78
+ }
79
+ /**
80
+ * ## PdFormDialog<T> (Abstract Base Class)
81
+ *
82
+ * Generic abstract base class for form dialogs with integrated validation.
83
+ * Not used directly -- extend it with a type parameter for your form data.
84
+ *
85
+ * ### Features
86
+ * - Integrated form validation via `pd-form-container`
87
+ * - Save button automatically disabled until form is valid
88
+ * - Double-submit prevention with configurable timeout
89
+ * - Type-safe form data handling via generic `T` parameter
90
+ * - Standardized events: `pd-form-submit` (with typed payload) and `pd-dialog-cancel`
91
+ * - Required field info display (optional)
92
+ *
93
+ * ### How to Extend
94
+ * Implement these abstract members:
95
+ * - `_dialogTitle`: Dialog title string
96
+ * - `_formData`: Your typed form data object
97
+ * - `_isValidFormData()`: Additional validation beyond field-level validation
98
+ * - `_renderContent()`: Returns form fields as `HTMLTemplateResult`
99
+ *
100
+ * ### Validation Flow
101
+ * 1. Each form field validates individually (via pd-form-container)
102
+ * 2. `_isValidFormData()` runs additional cross-field validation
103
+ * 3. Save button enables only when both pass
104
+ */
105
+ declare const meta: Meta<PdFormDialogArgs>;
106
+ export default meta;
107
+ type Story = StoryObj<PdFormDialogArgs>;
108
+ /** Contact form dialog with name, email, and message fields. Interactive via Controls panel. */
109
+ export declare const Default: Story;
110
+ /** User profile form with display name, bio, and language selection. */
111
+ export declare const ProfileForm: Story;
112
+ /** Feedback form with custom rating buttons and optional text area. */
113
+ export declare const FeedbackForm: Story;
114
+ /** Overview of all three form dialog implementations side by side. */
115
+ export declare const AllForms: Story;
116
+ /** Demonstrates the validation flow: Save button is disabled until form is valid. */
117
+ export declare const ValidationBehavior: Story;
118
+ //# sourceMappingURL=pd-form-dialog.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-form-dialog.stories.d.ts","sourceRoot":"","sources":["../../src/pd-form-dialog/pd-form-dialog.stories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAa,kBAAkB,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAEpE,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,4CAA4C,CAAC;AACpD,OAAO,iDAAiD,CAAC;AACzD,OAAO,6CAA6C,CAAC;AAErD,OAAO,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAOpE;;GAEG;AACH,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,cACM,kBAAmB,SAAQ,YAAY,CAAC,eAAe,CAAC;IAC5D,SAAS,CAAC,YAAY,SAAgB;IAGtC,SAAS,CAAC,SAAS,EAAE,eAAe,CAIlC;IAEF,MAAM,CAAC,MAAM,EASR,cAAc,CAAC;IAEpB,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC,SAAS,CAAC,cAAc,IAAI,kBAAkB;CA4B/C;AAED;;GAEG;AACH,UAAU,eAAe;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,cACM,kBAAmB,SAAQ,YAAY,CAAC,eAAe,CAAC;IAC5D,SAAS,CAAC,YAAY,SAAkB;IAGxC,SAAS,CAAC,SAAS,EAAE,eAAe,CAIlC;IAEF,MAAM,CAAC,MAAM,EASR,cAAc,CAAC;IAEpB,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC,SAAS,CAAC,cAAc,IAAI,kBAAkB;CAgC/C;AAED;;GAEG;AACH,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,cACM,mBAAoB,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAC9D,SAAS,CAAC,YAAY,SAAqB;IAG3C,SAAS,CAAC,SAAS,EAAE,gBAAgB,CAGnC;IAEF,MAAM,CAAC,MAAM,EA6BR,cAAc,CAAC;IAEpB,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC,OAAO,CAAC,aAAa;IAKrB,SAAS,CAAC,cAAc,IAAI,kBAAkB;CAiC/C;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,sBAAsB,EAAE,kBAAkB,CAAC;QAC3C,sBAAsB,EAAE,kBAAkB,CAAC;QAC3C,uBAAuB,EAAE,mBAAmB,CAAC;KAC9C;CACF;AAMD;;;GAGG;AACH,UAAU,gBAAgB;IACxB,uBAAuB;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,6CAA6C;IAC7C,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,gBAAgB,CA0GhC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAMxC,gGAAgG;AAChG,eAAO,MAAM,OAAO,EAAE,KASrB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,KAoBzB,CAAC;AAMF,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,KAqB1B,CAAC;AAMF,sEAAsE;AACtE,eAAO,MAAM,QAAQ,EAAE,KAwCtB,CAAC;AAMF,qFAAqF;AACrF,eAAO,MAAM,kBAAkB,EAAE,KA6BhC,CAAC"}
@@ -1,17 +1,44 @@
1
1
  import { LitElement, CSSResultGroup } from 'lit';
2
2
  /**
3
+ * Modal popup triggered by clicking a slot element.
4
+ *
3
5
  * @tagname pd-popup
6
+ * @summary Modal popup with trigger element and content slot.
7
+ *
8
+ * @event popup-close - Fired when popup is closed.
4
9
  *
5
- * Popup-Komponente, die bei Klick auf ein Trigger-Element (Slot `small-view`)
6
- * ein modales Fenster (Slot `content`) öffnet.
10
+ * @slot small-view - Trigger content (e.g., icon, text).
11
+ * @slot content - Content displayed in the popup.
7
12
  *
8
- * @element pd-popup
9
- * @slot small-view - Inhalt, der das Popup triggert (z.B. Icon, Text)
10
- * @slot content - Inhalt, der im Popup angezeigt wird
11
- * @event popup-close - Wird ausgelöst, wenn das Popup geschlossen wurde
13
+ * @cssprop --pd-popup-modal-bg-rgba - Modal overlay background. Default: `--pd-modal-overlay-col`.
14
+ * @cssprop --pd-popup-default-display - Initial display state. Default: `none`.
15
+ * @cssprop --pd-popup-z-index - Z-index for modal overlay. Default: `100`.
16
+ * @cssprop --pd-popup-modal-padding - Modal content padding. Default: `--pd-spacing-md`.
17
+ * @cssprop --pd-popup-modal-padding-top - Top padding for vertical positioning. Default: `100px`.
18
+ * @cssprop --pd-popup-modal-padding-bottom - Bottom padding inside content. Default: `130px`.
19
+ * @cssprop --pd-popup-max-width - Maximum popup width. Default: `1200px`.
20
+ * @cssprop --pd-popup-width - Popup width. Default: `80%`.
21
+ * @cssprop --pd-popup-border-radius - Corner radius. Default: `--pd-radius-lg`.
22
+ * @cssprop --pd-popup-modal-slot-max-width - Max width of slot content. Default: `1000px`.
23
+ * @cssprop --pd-popup-modal-slot-margin - Slot content margin. Default: `0 --pd-spacing-lg`.
24
+ * @cssprop --pd-popup-content-bg - Modal content background color. Default: `--pd-default-bg-col`.
25
+ * @cssprop --pd-popup-content-height - Modal content height. Default: `auto`.
12
26
  */
13
27
  export declare class PdPopup extends LitElement {
28
+ /** Enable closing with Escape key. */
14
29
  closeByEscape: boolean;
30
+ /** Enable closing by clicking the backdrop overlay. */
31
+ closeByBackdrop: boolean;
32
+ /** Hide the built-in close icon. Useful when content provides its own close mechanism. */
33
+ hideCloseIcon: boolean;
34
+ /** Block body scroll when popup is open. */
35
+ blockScroll: boolean;
36
+ /** Accessible label for the popup (used for aria-label). */
37
+ popupLabel: string;
38
+ /** @ignore */
39
+ private _scrollBlocked;
40
+ /** @ignore */
41
+ private _modal;
15
42
  static styles: CSSResultGroup;
16
43
  connectedCallback(): void;
17
44
  disconnectedCallback(): void;
@@ -27,5 +54,8 @@ export declare class PdPopup extends LitElement {
27
54
  private _activatePopup;
28
55
  private _closePopup;
29
56
  private _handleKeyDown;
57
+ private _onBackdropClick;
58
+ private _stopPropagation;
59
+ private _onCloseIconKeyDown;
30
60
  }
31
61
  //# sourceMappingURL=PdPopup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PdPopup.d.ts","sourceRoot":"","sources":["../../src/pd-popup/PdPopup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAa,cAAc,EAAE,MAAM,KAAK,CAAC;AAM5D,OAAO,0CAA0C,CAAC;AAElD;;;;;;;;;;GAUG;AACH,qBAAa,OAAQ,SAAQ,UAAU;IAErC,aAAa,EAAE,OAAO,CAAS;IAE/B,OAAgB,MAAM,EAAE,cAAc,CA+CpC;IAEO,iBAAiB;IAOjB,oBAAoB;IAO7B;;OAEG;IACI,SAAS,IAAI,IAAI;IAIxB;;OAEG;IACI,SAAS,IAAI,IAAI;IAIxB,SAAS,CAAC,MAAM;IAqBhB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,cAAc,CAEpB;CACH"}
1
+ {"version":3,"file":"PdPopup.d.ts","sourceRoot":"","sources":["../../src/pd-popup/PdPopup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAsB,cAAc,EAAE,MAAM,KAAK,CAAC;AAKrE,OAAO,0CAA0C,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,OAAQ,SAAQ,UAAU;IACrC,sCAAsC;IAEtC,aAAa,EAAE,OAAO,CAAS;IAE/B,uDAAuD;IAEvD,eAAe,EAAE,OAAO,CAAS;IAEjC,0FAA0F;IAE1F,aAAa,EAAE,OAAO,CAAS;IAE/B,4CAA4C;IAE5C,WAAW,EAAE,OAAO,CAAS;IAE7B,4DAA4D;IAE5D,UAAU,EAAE,MAAM,CAAW;IAE7B,cAAc;IACd,OAAO,CAAC,cAAc,CAAS;IAE/B,cAAc;IAEd,OAAO,CAAC,MAAM,CAAkB;IAEhC,OAAgB,MAAM,EAAE,cAAc,CA0DpC;IAEO,iBAAiB;IAWjB,oBAAoB;IAW7B;;OAEG;IACI,SAAS,IAAI,IAAI;IAIxB;;OAEG;IACI,SAAS,IAAI,IAAI;IAIxB,SAAS,CAAC,MAAM;IAsChB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,cAAc,CAEpB;IAEF,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,mBAAmB;CAM5B"}
@@ -1,7 +1,6 @@
1
- import { LitElement, css, html } from 'lit';
2
- import { property } from 'lit/decorators.js';
1
+ import { LitElement, css, nothing, html } from 'lit';
2
+ import { property, query } from 'lit/decorators.js';
3
3
  import { pdIcons } from '@progressive-development/pd-icon';
4
- import { PdColorStyles } from '@progressive-development/pd-shared-styles';
5
4
  import '@progressive-development/pd-icon/pd-icon';
6
5
 
7
6
  var __defProp = Object.defineProperty;
@@ -17,13 +16,18 @@ class PdPopup extends LitElement {
17
16
  constructor() {
18
17
  super(...arguments);
19
18
  this.closeByEscape = false;
19
+ this.closeByBackdrop = false;
20
+ this.hideCloseIcon = false;
21
+ this.blockScroll = false;
22
+ this.popupLabel = "Popup";
23
+ /** @ignore */
24
+ this._scrollBlocked = false;
20
25
  this._handleKeyDown = (e) => {
21
26
  if (e.key === "Escape") this._closePopup();
22
27
  };
23
28
  }
24
29
  static {
25
30
  this.styles = [
26
- PdColorStyles,
27
31
  css`
28
32
  :host {
29
33
  display: block;
@@ -31,7 +35,8 @@ class PdPopup extends LitElement {
31
35
 
32
36
  .modal {
33
37
  position: fixed;
34
- z-index: 100;
38
+ box-sizing: border-box;
39
+ z-index: var(--pd-popup-z-index, 100);
35
40
  left: 0;
36
41
  top: 0;
37
42
  width: 100%;
@@ -39,34 +44,45 @@ class PdPopup extends LitElement {
39
44
  overflow: auto;
40
45
  background-color: var(
41
46
  --pd-popup-modal-bg-rgba,
42
- rgba(175, 193, 210, 0.8)
47
+ var(--pd-modal-overlay-col)
43
48
  );
44
49
  display: var(--pd-popup-default-display, none);
45
- padding-top: 100px;
50
+ padding-top: var(--pd-popup-modal-padding-top, 100px);
51
+ max-width: 100vw;
52
+ overflow-x: hidden;
46
53
  }
47
54
 
48
55
  .modal-content {
49
- background-color: var(--pd-default-bg-col);
50
- opacity: 1;
56
+ background-color: var(--pd-popup-content-bg, var(--pd-default-bg-col));
51
57
  margin: auto;
52
- padding: var(--pd-popup-modal-padding, 20px);
53
- padding-bottom: 130px;
54
- border: 2px solid var(--pd-default-col);
55
- width: 80%;
56
- max-width: 1200px;
58
+ padding: var(--pd-popup-modal-padding, var(--pd-spacing-md));
59
+ padding-bottom: var(--pd-popup-modal-padding-bottom, 130px);
60
+ border: var(--pd-border-width, 1px) solid var(--pd-default-col);
61
+ border-radius: var(--pd-popup-border-radius, var(--pd-radius-lg));
62
+ box-shadow: var(--pd-shadow-xl);
63
+ width: var(--pd-popup-width, 80%);
64
+ max-width: var(--pd-popup-max-width, 1200px);
65
+ height: var(--pd-popup-content-height, auto);
57
66
  position: relative;
58
67
  }
59
68
 
60
69
  .modal-content-slot {
61
70
  max-width: var(--pd-popup-modal-slot-max-width, 1000px);
62
- margin: var(--pd-popup-modal-slot-margin, 0 30px);
71
+ margin: var(--pd-popup-modal-slot-margin, 0 var(--pd-spacing-lg, 2rem));
72
+ height: 100%;
63
73
  }
64
74
 
65
75
  .close-icon {
66
76
  position: absolute;
67
77
  cursor: pointer;
68
- right: 1.2em;
69
- top: 1.2em;
78
+ right: var(--pd-spacing-md, 1rem);
79
+ top: var(--pd-spacing-md, 1rem);
80
+ }
81
+
82
+ .close-icon:focus {
83
+ outline: 2px solid var(--pd-default-col);
84
+ outline-offset: 2px;
85
+ border-radius: var(--pd-radius-sm, 2px);
70
86
  }
71
87
  `
72
88
  ];
@@ -76,12 +92,20 @@ class PdPopup extends LitElement {
76
92
  if (this.closeByEscape) {
77
93
  document.addEventListener("keydown", this._handleKeyDown);
78
94
  }
95
+ if (this.blockScroll) {
96
+ document.body.style.overflow = "hidden";
97
+ this._scrollBlocked = true;
98
+ }
79
99
  }
80
100
  disconnectedCallback() {
81
101
  super.disconnectedCallback();
82
102
  if (this.closeByEscape) {
83
103
  document.removeEventListener("keydown", this._handleKeyDown);
84
104
  }
105
+ if (this._scrollBlocked) {
106
+ document.body.style.overflow = "";
107
+ this._scrollBlocked = false;
108
+ }
85
109
  }
86
110
  /**
87
111
  * Öffnet das Popup programmatisch
@@ -96,19 +120,33 @@ class PdPopup extends LitElement {
96
120
  this._closePopup();
97
121
  }
98
122
  render() {
123
+ const popupId = `${this.id || "popup"}-content`;
99
124
  return html`
100
125
  <span @click=${this._activatePopup} @keypress=${this._activatePopup}>
101
126
  <slot name="small-view"></slot>
102
127
  </span>
103
128
 
104
- <div id="modalId" class="modal">
105
- <div class="modal-content">
106
- <pd-icon
107
- icon=${pdIcons.ICON_CLOSE}
108
- class="close-icon"
109
- @click=${this._closePopup}
110
- ></pd-icon>
111
- <div class="modal-content-slot">
129
+ <div
130
+ id="modalId"
131
+ class="modal"
132
+ role="dialog"
133
+ aria-modal="true"
134
+ aria-label="${this.popupLabel}"
135
+ @click=${this._onBackdropClick}
136
+ >
137
+ <div class="modal-content" @click=${this._stopPropagation}>
138
+ ${this.hideCloseIcon ? nothing : html`
139
+ <pd-icon
140
+ icon=${pdIcons.ICON_CLOSE}
141
+ class="close-icon"
142
+ tabindex="0"
143
+ role="button"
144
+ aria-label="Close popup"
145
+ @click=${this._closePopup}
146
+ @keydown=${this._onCloseIconKeyDown}
147
+ ></pd-icon>
148
+ `}
149
+ <div id="${popupId}" class="modal-content-slot">
112
150
  <slot name="content"></slot>
113
151
  </div>
114
152
  </div>
@@ -116,12 +154,14 @@ class PdPopup extends LitElement {
116
154
  `;
117
155
  }
118
156
  _activatePopup() {
119
- const modal = this.shadowRoot?.getElementById("modalId");
120
- if (modal) modal.style.display = "block";
157
+ if (this._modal) this._modal.style.display = "block";
121
158
  }
122
159
  _closePopup() {
123
- const modal = this.shadowRoot?.getElementById("modalId");
124
- if (modal) modal.style.display = "none";
160
+ if (this._modal) this._modal.style.display = "none";
161
+ if (this._scrollBlocked) {
162
+ document.body.style.overflow = "";
163
+ this._scrollBlocked = false;
164
+ }
125
165
  this.dispatchEvent(
126
166
  new CustomEvent("popup-close", {
127
167
  bubbles: true,
@@ -129,9 +169,38 @@ class PdPopup extends LitElement {
129
169
  })
130
170
  );
131
171
  }
172
+ _onBackdropClick() {
173
+ if (this.closeByBackdrop) {
174
+ this._closePopup();
175
+ }
176
+ }
177
+ _stopPropagation(e) {
178
+ e.stopPropagation();
179
+ }
180
+ _onCloseIconKeyDown(e) {
181
+ if (e.key === "Enter" || e.key === " ") {
182
+ e.preventDefault();
183
+ this._closePopup();
184
+ }
185
+ }
132
186
  }
133
187
  __decorateClass([
134
188
  property({ type: Boolean })
135
189
  ], PdPopup.prototype, "closeByEscape");
190
+ __decorateClass([
191
+ property({ type: Boolean })
192
+ ], PdPopup.prototype, "closeByBackdrop");
193
+ __decorateClass([
194
+ property({ type: Boolean })
195
+ ], PdPopup.prototype, "hideCloseIcon");
196
+ __decorateClass([
197
+ property({ type: Boolean })
198
+ ], PdPopup.prototype, "blockScroll");
199
+ __decorateClass([
200
+ property({ type: String })
201
+ ], PdPopup.prototype, "popupLabel");
202
+ __decorateClass([
203
+ query("#modalId")
204
+ ], PdPopup.prototype, "_modal");
136
205
 
137
206
  export { PdPopup };
@@ -1,24 +1,58 @@
1
- import { StoryObj } from '@storybook/web-components';
2
- declare const meta: {
3
- title: string;
4
- component: string;
5
- render: ({ smallViewSlot, contentSlot }: import('@storybook/web-components').Args) => import('lit').TemplateResult<1>;
6
- argTypes: {
7
- smallViewSlot: {
8
- control: "text";
9
- description: string;
10
- initValue: string;
11
- };
12
- contentSlot: {
13
- control: "text";
14
- description: string;
15
- initValue: string;
16
- };
17
- };
18
- };
1
+ import { Meta, StoryObj } from '@storybook/web-components-vite';
2
+ /**
3
+ * Story arguments interface for pd-popup component.
4
+ * Maps to the component's public API.
5
+ */
6
+ interface PdPopupArgs {
7
+ /** Content for the trigger slot */
8
+ smallViewSlot: string;
9
+ /** Content displayed in the popup */
10
+ contentSlot: string;
11
+ /** Enable closing with Escape key */
12
+ closeByEscape: boolean;
13
+ /** Enable closing by clicking the backdrop overlay */
14
+ closeByBackdrop: boolean;
15
+ /** Hide the built-in close icon */
16
+ hideCloseIcon: boolean;
17
+ /** Block body scroll when popup is open */
18
+ blockScroll: boolean;
19
+ /** Accessible label for the popup */
20
+ popupLabel: string;
21
+ }
22
+ /**
23
+ * ## pd-popup
24
+ *
25
+ * A modal popup component triggered by clicking a slot element.
26
+ *
27
+ * ### Features
28
+ * - Trigger element via `small-view` slot (click to open)
29
+ * - Full-screen modal overlay with centered content
30
+ * - Built-in close icon (keyboard accessible, can be hidden)
31
+ * - Optional close on Escape key press (`closeByEscape`)
32
+ * - Optional close on backdrop click (`closeByBackdrop`)
33
+ * - Programmatic control via `showPopup()` and `hidePopup()` methods
34
+ * - Body scroll blocking when open (`blockScroll`)
35
+ * - Accessibility: `role="dialog"`, `aria-modal="true"`, `aria-label`
36
+ *
37
+ * ### Accessibility
38
+ * - Uses `role="dialog"` and `aria-modal="true"` on the modal container
39
+ * - `aria-label` set via `popupLabel` property
40
+ * - Close icon is keyboard focusable with `role="button"` and `aria-label`
41
+ * - Supports Escape key and backdrop click for closing
42
+ */
43
+ declare const meta: Meta<PdPopupArgs>;
19
44
  export default meta;
20
- type Story = StoryObj;
21
- export declare const DefaultPopup: Story;
22
- export declare const LongContent: Story;
23
- export declare const CustomStyledContent: Story;
45
+ type Story = StoryObj<PdPopupArgs>;
46
+ /** Default popup with simple text content. Interactive via Controls panel. */
47
+ export declare const Default: Story;
48
+ /** Popup with structured HTML content including headings, text, and lists. */
49
+ export declare const RichContent: Story;
50
+ /** Demonstrates the three closing mechanisms: close icon, Escape key, and backdrop click. */
51
+ export declare const ClosingOptions: Story;
52
+ /** Popup with the built-in close icon hidden. Content provides its own close mechanism. */
53
+ export declare const HiddenCloseIcon: Story;
54
+ /** Demonstrates opening and closing the popup programmatically via `showPopup()` / `hidePopup()`. */
55
+ export declare const ProgrammaticControl: Story;
56
+ /** CSS Custom Properties -- Branded and Redesigned variants. */
57
+ export declare const CustomStyling: Story;
24
58
  //# sourceMappingURL=pd-popup.stories.d.ts.map