@massimo-cassandro/minimo 1.4.12 → 1.5.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.
@@ -0,0 +1,38 @@
1
+ // -----------------------------------------------------------------------
2
+ // Generated file — do not edit manually.
3
+ // This file is produced by the design-token build pipeline.
4
+ // Source of truth: the token files in the project source directory.
5
+ // Re-generate with: node build-tokens.mjs --config <path/to/config>
6
+ // -----------------------------------------------------------------------
7
+ {
8
+ "modal-popup": {
9
+ "drop-shadow": {
10
+ "$type": "shadow",
11
+ "$value": [
12
+ {
13
+ "offsetX": "0",
14
+ "offsetY": "0",
15
+ "blur": "12px",
16
+ "spread": "2px",
17
+ "color": "rgba(0 0 0 / .25)"
18
+ }
19
+ ]
20
+ },
21
+ "backdrop-color": {
22
+ "$type": "color",
23
+ "$value": "rgb(0 0 0 / .6)"
24
+ },
25
+ "border": {
26
+ "radius": {
27
+ "$type": "dimension",
28
+ "$value": "{size.base}"
29
+ }
30
+ },
31
+ "btn-close": {
32
+ "size": {
33
+ "$type": "dimension",
34
+ "$value": "1.6rem"
35
+ }
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,32 @@
1
+ // -----------------------------------------------------------------------
2
+ // Generated file — do not edit manually.
3
+ // This file is produced by the design-token build pipeline.
4
+ // Source of truth: the token files in the project source directory.
5
+ // Re-generate with: node build-tokens.mjs --config <path/to/config>
6
+ // -----------------------------------------------------------------------
7
+ {
8
+ "switch": {
9
+ "background": {
10
+ "color": {
11
+ "$type": "color",
12
+ "$value": "{neutral.100}"
13
+ }
14
+ },
15
+ "cursor": {
16
+ "background": {
17
+ "color": {
18
+ "$type": "color",
19
+ "$value": "{body.background.color}"
20
+ }
21
+ }
22
+ },
23
+ "checked": {
24
+ "background": {
25
+ "color": {
26
+ "$type": "color",
27
+ "$value": "{primary.100}"
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,34 @@
1
+ export default {
2
+ 'modal-popup': {
3
+ 'drop-shadow': {
4
+ $type: 'shadow',
5
+ $value: [
6
+ {
7
+ offsetX: '0',
8
+ offsetY: '0',
9
+ blur: '12px',
10
+ spread: '2px',
11
+ color: 'rgba(0 0 0 / .25)'
12
+ }
13
+ ]
14
+ },
15
+ 'backdrop-color': {
16
+ $value: 'rgb(0 0 0 / .6)',
17
+ $type: 'color',
18
+ },
19
+ border: {
20
+ radius: {
21
+ $type: 'dimension',
22
+ $value: '{size.base}',
23
+ }
24
+ },
25
+
26
+ 'btn-close': {
27
+ size: {
28
+ $type: 'dimension',
29
+ $value: '1.6rem'
30
+ }
31
+
32
+ }
33
+ }
34
+ };
@@ -0,0 +1,29 @@
1
+ export default {
2
+ switch: {
3
+ background: {
4
+ color: {
5
+ $value: '{neutral.100}',
6
+ $type: 'color'
7
+ }
8
+ },
9
+
10
+ cursor: {
11
+ background: {
12
+ color: {
13
+ $value: '{body.background.color}',
14
+ $type: 'color'
15
+ }
16
+ },
17
+ },
18
+
19
+ checked: {
20
+ background: {
21
+ color: {
22
+ $value: '{primary.100}',
23
+ $type: 'color'
24
+ }
25
+ },
26
+ }
27
+
28
+ }
29
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.4.12",
3
+ "version": "1.5.0",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/massimo-cassandro/minimo#readme",
@@ -46,6 +46,7 @@
46
46
  "devDependencies": {
47
47
  "@massimo-cassandro/dev-updater": "^3.0.6",
48
48
  "@massimo-cassandro/eslint-config": "^3.0.9",
49
- "@massimo-cassandro/stylelint-config": "^2.3.9"
49
+ "@massimo-cassandro/stylelint-config": "^2.3.9",
50
+ "style-dictionary": "^5.4.4"
50
51
  }
51
52
  }
@@ -0,0 +1,200 @@
1
+ import { domBuilder } from '../../utilities/dom-builder/dom-builder.js';
2
+ import { classnames } from '../../utilities/classnames.js';
3
+ import { spinner } from '../spinner/spinner.js';
4
+ import * as styles from './modal-popup.module.css';
5
+
6
+
7
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement
8
+
9
+ let dialogEl, dialogContentEl;
10
+
11
+ function closeDialog() {
12
+ dialogEl.classList.remove(styles.on);
13
+
14
+ dialogEl.addEventListener('transitionend', () => {
15
+ dialogEl.close();
16
+ }, { once: true });
17
+ }
18
+
19
+ /**
20
+ * modalPopup
21
+ * Mostra un popup con il contenuto indicato
22
+ * il contentuo può essere in forma di:
23
+ * - array domBuilder oppure plain text oppure HTML (parametro `content`)
24
+ * - contenuto caricato via Ajax (parametri `ajaxUrl` e `ajaxCallback`)
25
+ * - iframe (parametro `iframeUrl`)
26
+ *
27
+ * in presenza di più impostazioni in conflitto, viene scelta la prima opzione utile
28
+ * nell'ordine di priorità riportato nella lista precedente.
29
+ */
30
+
31
+ export function modalPopup({
32
+
33
+ /** dialog extra class */
34
+ dialogExtraClassName = null,
35
+
36
+ /** extra classname added to dialogInner */
37
+ contentExtraClassName = null,
38
+
39
+ /** iframe url */
40
+ iframeUrl = null,
41
+
42
+ /** content: plain text, html or domBuilder array */
43
+ content = null,
44
+
45
+ /** url ajax e relatuva funzione di callback.
46
+ * Quest'ultima viene invocata con argomenti i dati restituiti dalla chiamata ajax
47
+ * e con l''elemento contenitore (`ajaxCallback(data, dialogContentEl)`)
48
+ */
49
+ ajaxUrl = null,
50
+ ajaxCallback = null,
51
+
52
+ /** eventuale callback da invocare alla chiusra del dialog
53
+ * Viene invocato con il le'elento dialog (`closeCallback(dialogEl)`)
54
+ * NB: `dialogEl` viene eliminato subito dopo
55
+ */
56
+ closeCallback = null,
57
+ addScrollbarPadding = false, // aggiunge un padding extra a destra per la barra di scorrimento
58
+
59
+ /** header content: plain text or HTML */
60
+ headerContent = null,
61
+
62
+ /** footer content: plain text or HTML */
63
+ footerContent = null,
64
+ }) {
65
+
66
+
67
+
68
+ if(content == null && (ajaxUrl == null || ajaxCallback == null) && iframeUrl == null) {
69
+ throw '[modalContent] parametri `content`, `ajaxUrl`/ `ajaxCallback` e `iframeUrl` mancanti';
70
+ }
71
+
72
+ let mode;
73
+ if(content != null && Array.isArray(content)) {
74
+ mode = 'domBuilder';
75
+
76
+ } else if (content != null) {
77
+ mode = 'html';
78
+
79
+ } else if (ajaxUrl != null && ajaxCallback != null) {
80
+ mode = 'ajax';
81
+
82
+ } else {
83
+ mode = 'iframe';
84
+ }
85
+
86
+ domBuilder([
87
+ {
88
+ tag: 'dialog',
89
+ className: classnames(styles.dialog, dialogExtraClassName, addScrollbarPadding && styles.scrollBarPadding),
90
+ attrs: {
91
+ 'closedby': 'any'
92
+ },
93
+ callback: el => dialogEl = el,
94
+ children: [
95
+ {
96
+ tag: 'button',
97
+ className: classnames('btn-close', styles.closeButton),
98
+ attrs: {
99
+ type: 'button',
100
+ 'aria-label': 'Chiudi'
101
+ }
102
+ },
103
+ {
104
+ className: styles.contentWrapper,
105
+ children: [
106
+ {
107
+ classname: styles.header,
108
+ condition: headerContent != null,
109
+ content: headerContent
110
+ },
111
+ {
112
+ className: classnames(styles.content, contentExtraClassName),
113
+
114
+ content: mode === 'html'
115
+ ? content
116
+ : mode === 'ajax'
117
+ ? spinner()
118
+ : null,
119
+
120
+ children: [
121
+ ...(mode === 'domBuilder'? content : []),
122
+ {
123
+ condition: mode === 'iframe',
124
+ className: styles.iframe,
125
+ tag: 'iframe',
126
+ attrs: {
127
+ src: iframeUrl
128
+ }
129
+ }
130
+ ],
131
+ callback: el => {
132
+ dialogContentEl = el;
133
+
134
+ if(mode === 'ajax') {
135
+ try {
136
+
137
+ (async () => {
138
+ const response = await fetch(ajaxUrl),
139
+ data = await response.json();
140
+
141
+ ajaxCallback(data, dialogContentEl);
142
+ })();
143
+
144
+ } catch(err) {
145
+ /* eslint-disable no-console */
146
+ console.error(ajaxUrl);
147
+ console.error(err);
148
+ /* eslint-enable no-console */
149
+ }
150
+ }
151
+
152
+ },
153
+ },
154
+ {
155
+ classname: styles.footer,
156
+ condition: footerContent != null,
157
+ content: footerContent
158
+ },
159
+ ]
160
+ }
161
+ ]
162
+ }
163
+ ], document.body);
164
+
165
+
166
+ // listener sul pulsante di chiusura
167
+ dialogEl.querySelector(`.${styles.closeButton}`).addEventListener('click', () => {
168
+ closeDialog();
169
+ }, false);
170
+
171
+ // // Esc e clic sul backdrop
172
+ // dialogEl.addEventListener('cancel', (e) => {
173
+ // e.preventDefault();
174
+ // closeDialog();
175
+ // }, false);
176
+
177
+
178
+
179
+ dialogEl.addEventListener('close', () => {
180
+
181
+ document.body.classList.remove('overflow-hidden');
182
+
183
+ if(closeCallback) {
184
+ closeCallback(dialogEl);
185
+ }
186
+ dialogEl.remove();
187
+
188
+ }, false);
189
+
190
+
191
+ document.body.classList.add('overflow-hidden');
192
+ dialogEl.showModal();
193
+ dialogEl.focus();
194
+
195
+ dialogEl.classList.add(styles.on);
196
+
197
+
198
+ return dialogEl;
199
+
200
+ }
@@ -0,0 +1,88 @@
1
+ /*
2
+ NB:
3
+ `--_modal-popup-width` and `--_modal-popup-height` are used with a fallback value
4
+ but can be set with a desired value caso per caso
5
+
6
+ */
7
+ .dialog {
8
+
9
+ position: fixed;
10
+
11
+ display: block;
12
+
13
+ width: var(--_modal-popup-width, max-content);
14
+ min-width: 400px;
15
+ max-width: 98dvw;
16
+ height: var(--_modal-popup-height, max-content);
17
+ min-height: 300px;
18
+ max-height: 90dvh;
19
+ padding: 0;
20
+ margin: auto;
21
+ overflow: visible;
22
+ background-color: var(--body-background-color);
23
+ border: none;
24
+ border-radius: var(--modal-popup-border-radius);
25
+ box-shadow: var(--modal-popup-drop-shadow);
26
+ scale: 0;
27
+ transition: scale .2s ease-out;
28
+
29
+ &::backdrop {
30
+ overscroll-behavior: contain;
31
+ background-color: var(--modal-popup-backdrop-color);
32
+ }
33
+
34
+ &.on {
35
+ scale: 1;
36
+ }
37
+
38
+ }
39
+
40
+ .closeButton {
41
+
42
+ position: absolute;
43
+ top: calc(-1 * var(--modal-popup-btn-close-size) / 3);
44
+ right: calc(-1 * var(--modal-popup-btn-close-size) / 3);
45
+ }
46
+
47
+ .contentWrapper {
48
+ display: flex;
49
+ flex-flow: column nowrap;
50
+ gap: 0;
51
+ align-items: flex-start;
52
+ justify-content: flex-start;
53
+ }
54
+
55
+
56
+ .content {
57
+ flex: 1;
58
+ width: 100%;
59
+ height: 100%;
60
+ min-height: 0;
61
+ padding: var(--size-base) var(--size-sm) var(--size-sm);
62
+ overflow-x: hidden;
63
+ overflow-y: auto;
64
+ scrollbar-gutter: stable;
65
+
66
+ .scrollBarPadding & {
67
+ padding-inline-end: var(--size-md);
68
+ }
69
+
70
+ }
71
+
72
+ .iframe {
73
+ width: 100%;
74
+ height: 100%;
75
+ padding: 0;
76
+ margin: 0;
77
+ overscroll-behavior: contain;
78
+ border: none;
79
+ }
80
+
81
+
82
+ .header {
83
+
84
+ }
85
+
86
+ .footer {
87
+
88
+ }
@@ -0,0 +1,8 @@
1
+ import * as styles from './spinner.module.css';
2
+
3
+ // NB la classe spinner è legata al tipo di spinner che si decide di usare, il cui file va incluso
4
+ // TODO sistema per coinfigurare il tipo di spinner da utilizzare, per permettere l'uso di più tipi di spinner nello stesso progetto
5
+
6
+ export function spinner() {
7
+ return `<div class="${styles.spinnerWrapper}"><div class="spinner">Loading...</div></div>`;
8
+ }
@@ -0,0 +1,5 @@
1
+ .spinnerWrapper {
2
+ display: grid;
3
+ place-content: center;
4
+ padding: 2rem;
5
+ }
@@ -119,6 +119,7 @@ input[type='checkbox'] {
119
119
 
120
120
  /* da bs5 */
121
121
  /* versione con label a destra */
122
+ /* TODO rivedere. sostituire float con flex? */
122
123
  .form-check {
123
124
  display: block;
124
125
  padding-left: 1.5em;
@@ -128,7 +129,7 @@ input[type='checkbox'] {
128
129
  float: left;
129
130
  display: inline-block;
130
131
  width: auto;
131
- margin: 4px 0 0 -1.5em;
132
+ margin: 4px 0 0 -1.5em;
132
133
  }
133
134
  }
134
135
 
@@ -0,0 +1,105 @@
1
+ /* TODO completare, aggiungere focus, vedere soluzione bootstrap
2
+
3
+
4
+ .form-switch {
5
+ padding-left: $form-switch-padding-start;
6
+
7
+ .form-check-input {
8
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};
9
+
10
+ width: $form-switch-width;
11
+ margin-left: $form-switch-padding-start * -1;
12
+ background-image: var(--#{$prefix}form-switch-bg);
13
+ background-position: left center;
14
+ @include border-radius($form-switch-border-radius, 0);
15
+ @include transition($form-switch-transition);
16
+
17
+ &:focus {
18
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)};
19
+ }
20
+
21
+ &:checked {
22
+ background-position: $form-switch-checked-bg-position;
23
+
24
+ @if $enable-gradients {
25
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient);
26
+ } @else {
27
+ --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)};
28
+ }
29
+ }
30
+ }
31
+
32
+ &.form-check-reverse {
33
+ padding-right: $form-switch-padding-start;
34
+ padding-left: 0;
35
+
36
+ .form-check-input {
37
+ margin-right: $form-switch-padding-start * -1;
38
+ margin-left: 0;
39
+ }
40
+ }
41
+ }
42
+
43
+
44
+ */
45
+
46
+ /*
47
+ <div class="switch">
48
+ <input type="checkbox">
49
+ <span class="switch-track"></span>
50
+ <label>Abilita notifiche</label>
51
+ </div>
52
+ */
53
+
54
+ .switch {
55
+ display: inline-flex;
56
+ align-items: center;
57
+ cursor: pointer;
58
+ }
59
+
60
+ .switch input {
61
+ position: absolute;
62
+ opacity: 0;
63
+ width: 0;
64
+ height: 0;
65
+ }
66
+
67
+ .switch-track {
68
+ position: relative;
69
+ width: 2.5em;
70
+ height: 1.5em;
71
+ background-color: var(--switch-background-color);
72
+ border-radius: 1.5em;
73
+ transition: background-color 0.2s;
74
+ }
75
+
76
+ .switch label {
77
+ margin-left: .5em;
78
+ user-select: none;
79
+ }
80
+
81
+ .switch-track::after {
82
+ content: '';
83
+ position: absolute;
84
+ top: 2px;
85
+ left: 2px;
86
+ width: 2em;
87
+ height: 2em;
88
+ background: var(--switch-cursor-background-color);
89
+ border-radius: 50%;
90
+ transition: translate 0.2s;
91
+ }
92
+
93
+ .switch input:checked + .switch-track {
94
+ background-color: var(--switch-checked-background-color);
95
+ }
96
+
97
+ .switch input:checked + .switch-track::after {
98
+ translate: 20px 0;
99
+ }
100
+
101
+ /* accessibilità */
102
+ .switch input:focus-visible + .switch-track {
103
+ outline: 2px solid var(--switch-checked-background-color);
104
+ outline-offset: 2px;
105
+ }
@@ -64,6 +64,9 @@
64
64
  .mie {
65
65
  margin-inline-end: var(--size-base) !important;
66
66
  }
67
+ .mie-auto {
68
+ margin-inline-end: auto !important;
69
+ }
67
70
  .mie-xs {
68
71
  margin-inline-end: var(--size-xs) !important;
69
72
  }
package/src/css/table.css CHANGED
@@ -59,7 +59,7 @@
59
59
  vertical-align: top;
60
60
  text-align: start;
61
61
 
62
- .valign-middle & {
62
+ .valign-middle &, &.valign-middle {
63
63
  vertical-align: middle;
64
64
  }
65
65
  }
@@ -190,6 +190,10 @@
190
190
  --link-focus-outline-color: var(--link-color);
191
191
  --link-focus-outline-width: .125rem;
192
192
  --link-visited-color: #ae0da3;
193
+ --modal-popup-backdrop-color: rgb(0 0 0 / .6);
194
+ --modal-popup-border-radius: var(--size-base);
195
+ --modal-popup-btn-close-size: 1.6rem;
196
+ --modal-popup-drop-shadow: 0 0 .75rem .125rem rgb(0 0 0 / .25);
193
197
  --neutral-100: #666;
194
198
  --neutral-100-fg: #fff;
195
199
  --overlay-color: rgb(0 0 0 / .6);
@@ -273,6 +277,9 @@
273
277
  --status-warning-border-color: var(--status-warning-color);
274
278
  --status-warning-color: #fc0;
275
279
  --status-warning-fg: #4f2900;
280
+ --switch-background-color: var(--neutral-100);
281
+ --switch-checked-background-color: var(--primary-100);
282
+ --switch-cursor-background-color: var(--body-background-color);
276
283
  --table-body-border-width: .0625rem;
277
284
  --table-body-tr-alt-bg-color: #efefef;
278
285
  --table-body-tr-hover-bg-color: #cbcbcb;
package/src/minimo.css CHANGED
@@ -41,3 +41,6 @@
41
41
  @import '@minimo/css/position.css';
42
42
  @import '@minimo/css/visibility.css';
43
43
 
44
+
45
+ /* spinner: include the css of the choosen spinner only */
46
+ @import '@minimo/components/spinner/spinner-circle-basic.css';
@@ -1,6 +1,6 @@
1
1
 
2
2
  // uso
3
- // throw new ValidationError('Sono presenti cicli duplicati', campiErrore );
3
+ // throw new ValidationError('Sono presenti valori duplicati', campiErrore );
4
4
 
5
5
  /*
6
6
  esempio:
@@ -120,7 +120,7 @@ export function parseCols(col_obj){
120
120
 
121
121
  } else if(col_obj._renderMode === 'numeric') {
122
122
  return {
123
-
123
+ // TODO implementare merge con classi presenti nei parametri definiti dall'utente
124
124
  cellClass: 'text-end text-numeric',
125
125
  headerClass: 'text-end text-numeric', // NB: usata anche per il footer
126
126
  };