mypgs 1.6.0 → 2.1.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.
- package/AGENTS.md +2 -2
- package/README.md +25 -25
- package/assets/javascript/components/_accordion.js +2 -2
- package/assets/javascript/components/_modals.js +159 -136
- package/assets/javascript/components/_notifications.js +19 -9
- package/assets/javascript/components/_search.js +2 -2
- package/assets/javascript/components/_slides.js +66 -32
- package/assets/javascript/components/_stepTabs.js +4 -4
- package/assets/javascript/components/_steps.js +2 -2
- package/assets/javascript/components/_summary.js +2 -2
- package/assets/javascript/functions/_formValidate.js +97 -53
- package/assets/javascript/functions/_scrollY.js +10 -10
- package/assets/javascript/layout/_header.js +3 -0
- package/assets/scss/base/_html.scss +2 -2
- package/assets/scss/base/_variables.scss +2 -2
- package/assets/scss/components/_accordion.scss +0 -2
- package/assets/scss/components/_button.scss +1 -1
- package/assets/scss/components/_form.scss +2 -18
- package/assets/scss/components/_formAddon.scss +18 -0
- package/assets/scss/components/_modals.scss +5 -3
- package/assets/scss/components/_notification.scss +23 -30
- package/assets/scss/components/_search.scss +29 -23
- package/assets/scss/components/_slides.scss +0 -1
- package/assets/scss/components/_tooltip.scss +0 -1
- package/assets/scss/index.scss +1 -0
- package/assets/scss/layout/_footer.scss +0 -2
- package/assets/scss/layout/_header.scss +9 -1
- package/assets/scss/layout/_pageShell.scss +24 -17
- package/assets/scss/mixin/_mx-button.scss +30 -76
- package/assets/scss/mixin/_mx-card.scss +11 -9
- package/assets/scss/mixin/_mx-form.scss +10 -12
- package/assets/scss/mixin/{_mx-form-addon.scss → _mx-formAddon.scss} +23 -26
- package/assets/scss/mixin/_mx-hover.scss +75 -0
- package/assets/scss/mixin/_settings.scss +2 -1
- package/assets/scss/mixin/mixin.scss +2 -1
- package/{templates/html → demo}/demo.html +1 -1
- package/demo/demo.js +241 -0
- package/dist/css/index.css +1317 -1674
- package/dist/css/index.css.map +1 -1
- package/dist/css/index.min.css +1 -1
- package/dist/javascript/index.js +356 -255
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/index.min.js +1 -1
- package/docs/componenti-e-markup.md +32 -32
- package/docs/components/accordion.md +61 -0
- package/docs/components/badges.md +67 -0
- package/docs/components/breadcumbs.md +43 -0
- package/docs/components/button.md +59 -0
- package/docs/components/card.md +50 -0
- package/docs/components/dropdown.md +135 -0
- package/docs/components/form.md +136 -0
- package/docs/components/formAddon.md +79 -0
- package/docs/components/logo.md +36 -0
- package/docs/components/menu.md +90 -0
- package/docs/components/modal.md +131 -0
- package/docs/components/notification.md +81 -0
- package/docs/components/search.md +118 -0
- package/docs/components/slides.md +85 -0
- package/docs/components/stepTabs.md +93 -0
- package/docs/components/steps.md +56 -0
- package/docs/components/summary.md +49 -0
- package/docs/components/table.md +42 -0
- package/docs/components/tooltip.md +53 -0
- package/docs/convenzioni.md +11 -11
- package/docs/export-e-sviluppo.md +3 -3
- package/docs/helper-javascript.md +73 -8
- package/docs/layout/body.md +41 -0
- package/docs/layout/flex.md +116 -0
- package/docs/layout/footer.md +71 -0
- package/docs/layout/grid.md +116 -0
- package/docs/layout/header.md +116 -0
- package/docs/layout/pageShell.md +94 -0
- package/docs/layout/section.md +69 -0
- package/docs/patterns/cookieConsent.md +89 -0
- package/docs/utilizzo-css-scss.md +8 -8
- package/package.json +2 -1
- package/scripts/generate-component-docs.js +557 -0
- package/templates/html/components/accordion.html +36 -7
- package/templates/html/components/badges.html +28 -5
- package/templates/html/components/breadcumbs.html +15 -1
- package/templates/html/components/button.html +28 -6
- package/templates/html/components/card.html +28 -8
- package/templates/html/components/dropdown.html +42 -8
- package/templates/html/components/form.html +110 -9
- package/templates/html/components/formAddon.html +72 -0
- package/templates/html/components/logo.html +22 -1
- package/templates/html/components/menu.html +33 -6
- package/templates/html/components/modal.html +58 -14
- package/templates/html/components/notification.html +68 -32
- package/templates/html/components/search.html +85 -8
- package/templates/html/components/slides.html +46 -3
- package/templates/html/components/stepTabs.html +55 -8
- package/templates/html/components/steps.html +24 -0
- package/templates/html/components/summary.html +30 -3
- package/templates/html/components/table.html +14 -2
- package/templates/html/components/tooltip.html +35 -0
- package/templates/html/layout/body.html +20 -6
- package/templates/html/layout/flex.html +53 -33
- package/templates/html/layout/footer.html +32 -4
- package/templates/html/layout/grid.html +53 -33
- package/templates/html/layout/header.html +47 -6
- package/templates/html/layout/pageShell.html +19 -0
- package/templates/html/layout/section.html +41 -19
- package/templates/html/patterns/cookieConsent.html +44 -13
- package/templates/react/components/accordion.jsx +4 -4
- package/templates/react/components/breadcumbs.jsx +1 -1
- package/templates/react/components/button.jsx +5 -5
- package/templates/react/components/card.jsx +4 -4
- package/templates/react/components/dropdown.jsx +8 -8
- package/templates/react/components/form.jsx +5 -5
- package/templates/react/components/modal.jsx +14 -14
- package/templates/react/components/notification.jsx +7 -7
- package/templates/react/components/search.jsx +5 -5
- package/templates/react/components/slides.jsx +3 -3
- package/templates/react/components/stepTabs.jsx +8 -8
- package/templates/react/components/summary.jsx +3 -3
- package/templates/react/components/table.jsx +2 -2
- package/templates/react/layout/flex.jsx +8 -8
- package/templates/react/layout/grid.jsx +8 -8
- package/templates/react/layout/section.jsx +12 -12
- package/templates/react/patterns/cookieConsent.jsx +8 -8
- package/templates/react/patterns/footer.jsx +4 -4
- package/templates/react/patterns/header.jsx +3 -3
- package/templates/html/demo.js +0 -130
- /package/{templates/html → demo}/demo.css +0 -0
package/AGENTS.md
CHANGED
|
@@ -71,7 +71,7 @@ Patterns found:
|
|
|
71
71
|
|
|
72
72
|
- `pgs` is the main attribute: tokens are separated by spaces, for example `pgs="button modal-button"`.
|
|
73
73
|
- `assets/scss/index.scss` imports base, layout, components, and patterns; layouts/components/patterns are almost all scoped under `[pgs~=initP]`.
|
|
74
|
-
- The main markup must enable the library with `htmlBase initP`, and the body with base body tokens. Use `
|
|
74
|
+
- The main markup must enable the library with `htmlBase initP`, and the body with base body tokens. Use `demo/demo.html` and `templates/html/layout/body.html` as the canonical references.
|
|
75
75
|
- Components use a root token and child tokens with a consistent prefix. Use `templates/html/components/` as the canonical markup source.
|
|
76
76
|
|
|
77
77
|
- Runtime states use `pgs-state`, for example `open`, `is-active`, `is-completed`, `is-locked`, `success`, `error`, `warning`, and `info`.
|
|
@@ -229,7 +229,7 @@ Canonical template references:
|
|
|
229
229
|
- Layouts: `templates/html/layout/body.html`, `templates/html/layout/flex.html`, `templates/html/layout/grid.html`, `templates/html/layout/pageShell.html`, `templates/html/layout/section.html`
|
|
230
230
|
- Components: `templates/html/components/accordion.html`, `templates/html/components/breadcumbs.html`, `templates/html/components/button.html`, `templates/html/components/card.html`, `templates/html/components/dropdown.html`, `templates/html/components/form.html`, `templates/html/components/logo.html`, `templates/html/components/menu.html`, `templates/html/components/modal.html`, `templates/html/components/notification.html`, `templates/html/components/search.html`, `templates/html/components/slides.html`, `templates/html/components/stepTabs.html`, `templates/html/components/steps.html`, `templates/html/components/table.html`, `templates/html/components/tooltip.html`
|
|
231
231
|
- Patterns: `templates/html/patterns/cookieConsent.html`, `templates/html/patterns/footer.html`, `templates/html/patterns/header.html`
|
|
232
|
-
- Complete demo assembly. DO NOT use this for inspiration. It is only used to show all the modules: `
|
|
232
|
+
- Complete demo assembly. DO NOT use this for inspiration. It is only used to show all the modules: `demo/demo.html`
|
|
233
233
|
|
|
234
234
|
Before creating markup, open the relevant template and reuse its current structure, tokens, ARIA attributes, and `pgs-option` syntax.
|
|
235
235
|
|
package/README.md
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# MyPGS
|
|
2
2
|
|
|
3
|
-
`mypgs`
|
|
3
|
+
`mypgs` is a shared frontend library for building consistent interfaces through `pgs` attributes, SCSS sources, UI components, and reusable JavaScript behaviors.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The library provides a design-system foundation: layouts, spacing, colors, buttons, forms, menus, modals, dropdowns, suggestion search, slides, notifications, and recurring patterns are defined once and reused across projects.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## What it includes
|
|
8
8
|
|
|
9
|
-
- `assets/scss/`: SCSS
|
|
10
|
-
- `assets/javascript/`:
|
|
11
|
-
- `templates/`:
|
|
12
|
-
- `dist/css/`: CSS
|
|
13
|
-
- `dist/javascript/`:
|
|
14
|
-
- `dist/index.d.ts`:
|
|
15
|
-
- `AGENTS.md`:
|
|
9
|
+
- `assets/scss/`: SCSS sources divided into base, layouts, components, patterns, and mixins.
|
|
10
|
+
- `assets/javascript/`: the `pgs` helper, JavaScript components, functions, and patterns.
|
|
11
|
+
- `templates/`: ready-to-use HTML examples for components and layouts.
|
|
12
|
+
- `dist/css/`: compiled CSS.
|
|
13
|
+
- `dist/javascript/`: compiled JavaScript bundle.
|
|
14
|
+
- `dist/index.d.ts`: TypeScript declarations exported by the package.
|
|
15
|
+
- `AGENTS.md`: operating guide for AI agents.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Installation
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
From the **npm** registry:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
npm install mypgs
|
|
@@ -28,15 +28,15 @@ npm install mypgs
|
|
|
28
28
|
import "mypgs";
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
To access the helper directly:
|
|
32
32
|
|
|
33
33
|
```js
|
|
34
34
|
import { pgs } from "mypgs";
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
**React/TSX
|
|
37
|
+
**React/TSX with Vite:**
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Configure the plugin that converts `pgsHtml` into `pgs`:
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
// vite.config.ts
|
|
@@ -51,7 +51,7 @@ export default {
|
|
|
51
51
|
|
|
52
52
|
### SCSS
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
To compile a single CSS file, import the SCSS sources:
|
|
55
55
|
|
|
56
56
|
```scss
|
|
57
57
|
@use "sass:meta";
|
|
@@ -59,7 +59,7 @@ Se il progetto vuole compilare un CSS unico, importa gli SCSS sorgenti:
|
|
|
59
59
|
@include meta.load-css("../../node_modules/mypgs/assets/scss/index.scss");
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
To import only the mixins:
|
|
63
63
|
|
|
64
64
|
```scss
|
|
65
65
|
@use "../../node_modules/mypgs/assets/scss/mixin/mixin.scss" as * ;
|
|
@@ -67,20 +67,20 @@ Se servono solo i mixin:
|
|
|
67
67
|
|
|
68
68
|
### Markup
|
|
69
69
|
|
|
70
|
-
`initP`
|
|
70
|
+
`initP` is required: every SCSS layout, component, and pattern is scoped under `[pgs~=initP]`.
|
|
71
71
|
|
|
72
72
|
```html
|
|
73
|
-
<html lang="
|
|
73
|
+
<html lang="en" pgs="htmlBase initP">
|
|
74
74
|
<body pgs="bodyBase bodyImg bodyText bodyHeading">
|
|
75
75
|
<main pgs="main"></main>
|
|
76
76
|
</body>
|
|
77
77
|
</html>
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
##
|
|
80
|
+
## Documentation
|
|
81
81
|
|
|
82
|
-
- [
|
|
83
|
-
- [
|
|
84
|
-
- [
|
|
85
|
-
- [
|
|
86
|
-
- [
|
|
82
|
+
- [CSS/SCSS usage](docs/utilizzo-css-scss.md)
|
|
83
|
+
- [JavaScript helper](docs/helper-javascript.md)
|
|
84
|
+
- [Components and markup](docs/componenti-e-markup.md)
|
|
85
|
+
- [npm exports and development](docs/export-e-sviluppo.md)
|
|
86
|
+
- [Conventions](docs/convenzioni.md)
|
|
@@ -11,7 +11,7 @@ function directPgsChild(element, token) {
|
|
|
11
11
|
return Array.from(element.children).find(child => pgs(child).contains(token));
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
function PGS_accordion_init(root = document) {
|
|
15
15
|
pgs(root).querySelectorAll("accordion").forEach((accordion) => {
|
|
16
16
|
if (API.has(accordion)) return;
|
|
17
17
|
|
|
@@ -115,7 +115,7 @@ export function PGS_accordion_init(root = document) {
|
|
|
115
115
|
PGS_accordion_init();
|
|
116
116
|
|
|
117
117
|
//# API
|
|
118
|
-
|
|
118
|
+
function PGS_accordion_api(selector) {
|
|
119
119
|
return API.get(selector);
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -1,161 +1,184 @@
|
|
|
1
1
|
//# MODAL
|
|
2
2
|
const API = new WeakMap();
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
pgs(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const DIALOG = MODAL.querySelector("dialog");
|
|
10
|
-
if (!BUTTON_OPEN || !DIALOG) return;
|
|
11
|
-
|
|
12
|
-
//== SELECTOR
|
|
13
|
-
const DOMButtonClose = '<button pgs="buttonClose modal-close" type="button" tabindex="0" aria-label="Chiudi"><i class="fa-solid fa-close"></i></button>';
|
|
14
|
-
const modalContentHeader = pgs(MODAL)?.querySelector("modal-dialog-content-header")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//== OPTION ATTRIBUTES MODAL
|
|
18
|
-
const disableBackdropClose = pgs(MODAL).option.contains("disableBackdropClose")
|
|
19
|
-
const data_history = pgs(MODAL).option.contains("history");
|
|
20
|
-
const data_container = pgs(MODAL).option.getValueBrackets("containerID");
|
|
21
|
-
const data_containerPGS = pgs(MODAL).option.getValueBrackets("containerPGS");
|
|
22
|
-
|
|
23
|
-
//== OPTION ATTRIBUTES DIALOG
|
|
24
|
-
const topLevel = pgs(DIALOG).option.contains("topLevel")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//== BUTTON CLOSE
|
|
28
|
-
if (pgs(MODAL).querySelector("modal-close")) null
|
|
29
|
-
else if (modalContentHeader) modalContentHeader.insertAdjacentHTML("beforeend", DOMButtonClose)
|
|
30
|
-
else DIALOG.insertAdjacentHTML("beforeend", DOMButtonClose)
|
|
31
|
-
const BUTTON_CLOSE = pgs(MODAL).querySelector("modal-close")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//== SET
|
|
35
|
-
pgs(DIALOG).add("dialog modal-dialog");
|
|
36
|
-
|
|
37
|
-
//== BUTTON OPEN
|
|
38
|
-
BUTTON_OPEN.setAttribute("role", "button");
|
|
39
|
-
BUTTON_OPEN.setAttribute("aria-label", "apri modale");
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
//== POSITION
|
|
43
|
-
if(!topLevel){
|
|
44
|
-
if (data_container) document.querySelector("#" + data_container)?.append(DIALOG);
|
|
45
|
-
else if (data_containerPGS) pgs(document).querySelector(data_containerPGS)?.append(DIALOG);
|
|
46
|
-
else document.body.append(DIALOG);
|
|
47
|
-
}
|
|
4
|
+
function getModals(root) {
|
|
5
|
+
const modals = root instanceof Element && pgs(root).contains("modal") ? [root] : [];
|
|
6
|
+
modals.push(...pgs(root).querySelectorAll("modal"));
|
|
7
|
+
return modals;
|
|
8
|
+
}
|
|
48
9
|
|
|
10
|
+
function initializeModal(MODAL, existingDialog = null) {
|
|
11
|
+
if (API.has(MODAL)) return;
|
|
49
12
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
13
|
+
const BUTTON_OPEN = pgs(MODAL).querySelector("modal-button");
|
|
14
|
+
const DIALOG = existingDialog || MODAL.querySelector("dialog");
|
|
15
|
+
if (!BUTTON_OPEN || !DIALOG) return;
|
|
16
|
+
const eventController = new AbortController();
|
|
17
|
+
const { signal } = eventController;
|
|
18
|
+
let historyObserver = null;
|
|
19
|
+
let historyTimeout = null;
|
|
55
20
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (DIALOG.open) {
|
|
60
|
-
closeModal(e);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
|
|
65
|
-
statusModal(true);
|
|
66
|
-
topLevel ? DIALOG.showModal() : DIALOG.show();
|
|
67
|
-
// modalCustomEvents('modal:open', { event: e });
|
|
68
|
-
MODAL.dispatchEvent(new CustomEvent('modal:open'));
|
|
69
|
-
DIALOG.dispatchEvent(new CustomEvent('modal:open'));
|
|
70
|
-
}
|
|
21
|
+
//== SELECTOR
|
|
22
|
+
const DOMButtonClose = '<button pgs="buttonClose modal-close" type="button" tabindex="0" aria-label="Chiudi"><i class="fa-solid fa-close"></i></button>';
|
|
23
|
+
const modalContentHeader = pgs(DIALOG).querySelector("modal-dialog-content-header");
|
|
71
24
|
|
|
72
|
-
//+ FN CLOSE
|
|
73
|
-
function closeModal(e) {
|
|
74
|
-
e?.stopImmediatePropagation()
|
|
75
|
-
statusModal(false);
|
|
76
|
-
DIALOG.close();
|
|
77
|
-
// modalCustomEvents('modal:close', { event: e });
|
|
78
|
-
MODAL.dispatchEvent(new CustomEvent('modal:close'));
|
|
79
|
-
DIALOG.dispatchEvent(new CustomEvent('modal:close'));
|
|
80
|
-
}
|
|
81
25
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
26
|
+
//== OPTION ATTRIBUTES MODAL
|
|
27
|
+
const disableBackdropClose = pgs(MODAL).option.contains("disableBackdropClose");
|
|
28
|
+
const data_history = pgs(MODAL).option.contains("history");
|
|
29
|
+
const data_container = pgs(MODAL).option.getValueBrackets("containerID");
|
|
30
|
+
const data_containerPGS = pgs(MODAL).option.getValueBrackets("containerPGS");
|
|
85
31
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
32
|
+
//== OPTION ATTRIBUTES DIALOG
|
|
33
|
+
const topLevel = pgs(DIALOG).option.contains("topLevel");
|
|
89
34
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
35
|
+
|
|
36
|
+
//== BUTTON CLOSE
|
|
37
|
+
if (!pgs(DIALOG).querySelector("modal-close") && !pgs(MODAL).querySelector("modal-close")) {
|
|
38
|
+
if (modalContentHeader) modalContentHeader.insertAdjacentHTML("beforeend", DOMButtonClose);
|
|
39
|
+
else DIALOG.insertAdjacentHTML("beforeend", DOMButtonClose);
|
|
40
|
+
}
|
|
41
|
+
const BUTTON_CLOSE = pgs(DIALOG).querySelector("modal-close") || pgs(MODAL).querySelector("modal-close");
|
|
97
42
|
|
|
98
43
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const params = new URLSearchParams(window.location.search);
|
|
129
|
-
const shouldOpen = params.get('modal') === BUTTON_OPEN.id;
|
|
130
|
-
if (shouldOpen && !DIALOG.open) DIALOG.showModal();
|
|
131
|
-
if (!shouldOpen && DIALOG.open) closeModal()
|
|
132
|
-
} catch (_) { }
|
|
133
|
-
});
|
|
44
|
+
//== SET
|
|
45
|
+
pgs(DIALOG).add("dialog modal-dialog");
|
|
46
|
+
|
|
47
|
+
//== BUTTON OPEN
|
|
48
|
+
BUTTON_OPEN.setAttribute("role", "button");
|
|
49
|
+
BUTTON_OPEN.setAttribute("aria-label", "apri modale");
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
//== POSITION
|
|
53
|
+
if (topLevel && !MODAL.contains(DIALOG)) MODAL.append(DIALOG);
|
|
54
|
+
else if (!topLevel) {
|
|
55
|
+
if (data_container) document.querySelector("#" + data_container)?.append(DIALOG);
|
|
56
|
+
else if (data_containerPGS) pgs(document).querySelector(data_containerPGS)?.append(DIALOG);
|
|
57
|
+
else document.body.append(DIALOG);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
//+ FN STATUS
|
|
62
|
+
function statusModal(status = true) {
|
|
63
|
+
BUTTON_OPEN?.setAttribute("aria-expanded", status);
|
|
64
|
+
DIALOG?.setAttribute("aria-expanded", status);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//+ FN OPEN
|
|
68
|
+
function openModal(e) {
|
|
69
|
+
e?.stopImmediatePropagation();
|
|
70
|
+
if (DIALOG.open) {
|
|
71
|
+
closeModal(e);
|
|
72
|
+
return;
|
|
134
73
|
}
|
|
135
74
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
75
|
+
if (!DIALOG.open) document.querySelectorAll("dialog[open]").forEach((dlg) => dlg.close());
|
|
76
|
+
statusModal(true);
|
|
77
|
+
topLevel ? DIALOG.showModal() : DIALOG.show();
|
|
78
|
+
// modalCustomEvents('modal:open', { event: e });
|
|
79
|
+
MODAL.dispatchEvent(new CustomEvent('modal:open'));
|
|
80
|
+
DIALOG.dispatchEvent(new CustomEvent('modal:open'));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//+ FN CLOSE
|
|
84
|
+
function closeModal(e) {
|
|
85
|
+
e?.stopImmediatePropagation()
|
|
86
|
+
statusModal(false);
|
|
87
|
+
DIALOG.close();
|
|
88
|
+
// modalCustomEvents('modal:close', { event: e });
|
|
89
|
+
MODAL.dispatchEvent(new CustomEvent('modal:close'));
|
|
90
|
+
DIALOG.dispatchEvent(new CustomEvent('modal:close'));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function forceOpen(e) {
|
|
94
|
+
if (!DIALOG.open) openModal(e);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function forceClose(e) {
|
|
98
|
+
if (DIALOG.open) closeModal(e);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//+ fn OPEN ON HISTORY
|
|
102
|
+
function openModalOnHistory() {
|
|
103
|
+
const params = new URLSearchParams(window.location.search);
|
|
104
|
+
if (params.get('modal') !== BUTTON_OPEN.id) return;
|
|
105
|
+
document.getElementById(BUTTON_OPEN.id)?.scrollIntoView({ behavior: 'smooth' });
|
|
106
|
+
openModal();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
//= OPEN
|
|
111
|
+
BUTTON_OPEN.addEventListener("click", (e) => openModal(e), { signal });
|
|
112
|
+
BUTTON_OPEN.addEventListener("keypress", (e) => !DIALOG.open && (e.key === "Enter" || e.key === " ") && openModal(e), { signal });
|
|
113
|
+
|
|
114
|
+
//= CLOSE
|
|
115
|
+
DIALOG.addEventListener("close", () => statusModal(false), { signal });
|
|
116
|
+
DIALOG.addEventListener("click", e => { if (e.target == DIALOG && !disableBackdropClose) closeModal(e) }, { signal });
|
|
117
|
+
BUTTON_CLOSE?.addEventListener("click", e => closeModal(e), { signal });
|
|
118
|
+
|
|
119
|
+
//= UPDATE HISTORY
|
|
120
|
+
if (data_history && BUTTON_OPEN.id) {
|
|
121
|
+
historyTimeout = window.setTimeout(openModalOnHistory, 1);
|
|
122
|
+
|
|
123
|
+
//== Aggiorna URL quando cambia l'attributo "open" del dialog
|
|
124
|
+
historyObserver = new MutationObserver(() => {
|
|
125
|
+
let isOpen = DIALOG.hasAttribute("open");
|
|
126
|
+
try {
|
|
127
|
+
const url = new URL(window.location.href);
|
|
128
|
+
const params = new URLSearchParams(url.search);
|
|
129
|
+
isOpen ? params.set('modal', BUTTON_OPEN.id) : params.delete('modal');
|
|
130
|
+
url.search = params.toString() ? `?${params.toString()}` : "";
|
|
131
|
+
window.history.pushState({ modal: BUTTON_OPEN.id, open: isOpen }, "", url);
|
|
132
|
+
} catch (_) { }
|
|
149
133
|
});
|
|
134
|
+
historyObserver.observe(DIALOG, { attributes: true, attributeFilter: ["open"] });
|
|
135
|
+
|
|
136
|
+
//== Gestisce back/forward del browser per aprire/chiudere il dialog coerentemente
|
|
137
|
+
window.addEventListener("popstate", () => {
|
|
138
|
+
try {
|
|
139
|
+
const params = new URLSearchParams(window.location.search);
|
|
140
|
+
const shouldOpen = params.get('modal') === BUTTON_OPEN.id;
|
|
141
|
+
if (shouldOpen && !DIALOG.open) DIALOG.showModal();
|
|
142
|
+
if (!shouldOpen && DIALOG.open) closeModal()
|
|
143
|
+
} catch (_) { }
|
|
144
|
+
}, { signal });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function destroy() {
|
|
148
|
+
eventController.abort();
|
|
149
|
+
historyObserver?.disconnect();
|
|
150
|
+
if (historyTimeout !== null) window.clearTimeout(historyTimeout);
|
|
151
|
+
API.delete(MODAL);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
API.set(MODAL, {
|
|
155
|
+
element: MODAL,
|
|
156
|
+
button: BUTTON_OPEN,
|
|
157
|
+
dialog: DIALOG,
|
|
158
|
+
closeButton: BUTTON_CLOSE,
|
|
159
|
+
open: forceOpen,
|
|
160
|
+
close: forceClose,
|
|
161
|
+
toggle: openModal,
|
|
162
|
+
refresh: () => {
|
|
163
|
+
const nextDialog = MODAL.querySelector("dialog") || DIALOG;
|
|
164
|
+
destroy();
|
|
165
|
+
initializeModal(MODAL, nextDialog);
|
|
166
|
+
return API.get(MODAL);
|
|
167
|
+
},
|
|
168
|
+
isOpen: () => DIALOG.open,
|
|
150
169
|
});
|
|
151
170
|
}
|
|
152
171
|
|
|
172
|
+
function PGS_modal_init(root = document) {
|
|
173
|
+
getModals(root).forEach(MODAL => initializeModal(MODAL));
|
|
174
|
+
}
|
|
175
|
+
|
|
153
176
|
//# INIT PGS_modal
|
|
154
177
|
PGS_modal_init()
|
|
155
178
|
|
|
156
179
|
//# API
|
|
157
|
-
|
|
158
|
-
return API.get(
|
|
180
|
+
function PGS_modal_api(element) {
|
|
181
|
+
return API.get(element);
|
|
159
182
|
}
|
|
160
183
|
|
|
161
184
|
export const PGS_modal = {
|
|
@@ -24,10 +24,12 @@ const fn_notification = {
|
|
|
24
24
|
},
|
|
25
25
|
|
|
26
26
|
_getData(root) {
|
|
27
|
+
const rawNotification = pgs(root).option.getValueBrackets("notification") || "{}";
|
|
28
|
+
|
|
27
29
|
try {
|
|
28
|
-
return JSON.parse(
|
|
30
|
+
return JSON.parse(rawNotification);
|
|
29
31
|
} catch (error) {
|
|
30
|
-
console.warn("PGS notification:
|
|
32
|
+
console.warn("PGS notification: configurazione JSON non valida", error);
|
|
31
33
|
return {};
|
|
32
34
|
}
|
|
33
35
|
},
|
|
@@ -46,13 +48,21 @@ const fn_notification = {
|
|
|
46
48
|
`;
|
|
47
49
|
},
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
_getContainer(containerType) {
|
|
52
|
+
return Array.from(pgs(document).querySelectorAll("notification")).find(container => {
|
|
53
|
+
const isToast = pgs(container).option.contains("toast");
|
|
54
|
+
return containerType === "toast" ? isToast : !isToast;
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
initNotification(type, containerType, icon, text, timeout, methodDelete = "replace", link = null) {
|
|
59
|
+
let containerNotification = this._getContainer(containerType);
|
|
51
60
|
|
|
52
61
|
//== Create Container
|
|
53
62
|
if (!containerNotification) {
|
|
54
63
|
const newContainer = document.createElement("div");
|
|
55
|
-
pgs(newContainer).add(
|
|
64
|
+
pgs(newContainer).add("notification");
|
|
65
|
+
if (containerType === "toast") pgs(newContainer).option.add("toast");
|
|
56
66
|
newContainer.setAttribute("aria-live", "polite");
|
|
57
67
|
newContainer.setAttribute("aria-relevant", "additions");
|
|
58
68
|
document.body.appendChild(newContainer);
|
|
@@ -98,8 +108,8 @@ const fn_notification = {
|
|
|
98
108
|
});
|
|
99
109
|
},
|
|
100
110
|
|
|
101
|
-
deleteAll(
|
|
102
|
-
let containerNotification =
|
|
111
|
+
deleteAll(containerType) {
|
|
112
|
+
let containerNotification = this._getContainer(containerType);
|
|
103
113
|
if (containerNotification) containerNotification.innerHTML = "";
|
|
104
114
|
},
|
|
105
115
|
|
|
@@ -133,8 +143,8 @@ const fn_notification = {
|
|
|
133
143
|
}
|
|
134
144
|
};
|
|
135
145
|
|
|
136
|
-
//#
|
|
137
|
-
|
|
146
|
+
//# TRIGGER
|
|
147
|
+
function PGS_notificationTrigger_init(root = document) {
|
|
138
148
|
return fn_notification.trigger(root);
|
|
139
149
|
}
|
|
140
150
|
|
|
@@ -5,7 +5,7 @@ let searchId = 0;
|
|
|
5
5
|
const DEFAULT_OPTIONS = {
|
|
6
6
|
minLength: 2,
|
|
7
7
|
debounce: 200,
|
|
8
|
-
limit:
|
|
8
|
+
limit: 6,
|
|
9
9
|
submitOnSelect: false,
|
|
10
10
|
searchOnFocus: true,
|
|
11
11
|
source: null,
|
|
@@ -381,7 +381,7 @@ document.addEventListener("pointerdown", event => {
|
|
|
381
381
|
|
|
382
382
|
PGS_search_init();
|
|
383
383
|
|
|
384
|
-
|
|
384
|
+
function PGS_search_api(selector) {
|
|
385
385
|
return API.get(selector);
|
|
386
386
|
}
|
|
387
387
|
|