@massimo-cassandro/minimo 1.21.7 → 1.21.9
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/dev-tools/starter-kit/starter-install.sh +66 -27
- package/dev-tools/starter-kit/templates/__project__.code-workspace +2 -1
- package/dev-tools/starter-kit/templates/jsconfig.json +9 -8
- package/dev-tools/starter-kit/templates/package-tpl.json +3 -3
- package/dev-tools/starter-kit/webpack-template.ejs +5 -4
- package/dev-tools/starter-kit/webpack.config.mjs +40 -117
- package/package.json +5 -1
- package/src/web-components/s-datatable-component/docs.md +27 -3
- package/src/web-components/s-datatable-component/s-datatable-component.js +14 -16
- package/src/web-components/s-datatable-component/src/parse-cols.js +8 -5
- package/src/web-components/s-datatable-component/src/search-method.js +84 -0
|
@@ -19,11 +19,16 @@ if [ -z "$ZSH_VERSION" ]; then
|
|
|
19
19
|
fi
|
|
20
20
|
|
|
21
21
|
# --no-npm: salta le installazioni npm (utile per testare rapidamente lo script)
|
|
22
|
+
# --root / --frontend: posizione della configurazione frontend (salta il prompt,
|
|
23
|
+
# utile per esecuzioni non interattive)
|
|
22
24
|
SKIP_NPM=0
|
|
25
|
+
FRONTEND_CHOICE=""
|
|
23
26
|
for ARG in "$@"; do
|
|
24
|
-
|
|
25
|
-
SKIP_NPM=1
|
|
26
|
-
|
|
27
|
+
case "$ARG" in
|
|
28
|
+
--no-npm) SKIP_NPM=1 ;;
|
|
29
|
+
--root) FRONTEND_CHOICE=1 ;;
|
|
30
|
+
--frontend) FRONTEND_CHOICE=2 ;;
|
|
31
|
+
esac
|
|
27
32
|
done
|
|
28
33
|
|
|
29
34
|
# Wrapper: esegue "npm i ..." a meno che SKIP_NPM sia attivo
|
|
@@ -105,11 +110,15 @@ fi
|
|
|
105
110
|
echo -e "${GREEN}...gitignore${NC}"
|
|
106
111
|
safe_cat "${TEMPLATES_DIR}/_gitignore" .gitignore new
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
if [ -n "$FRONTEND_CHOICE" ]; then
|
|
114
|
+
choice="$FRONTEND_CHOICE"
|
|
115
|
+
else
|
|
116
|
+
echo -e "\n${GREEN}Where do you want to install the frontend configuration?${NC}"
|
|
117
|
+
echo "1) Root directory"
|
|
118
|
+
echo "2) 'frontend' Directory"
|
|
119
|
+
read "?Choose (1 or 2) [default: 1]: " choice < /dev/tty
|
|
120
|
+
choice=${choice:-1}
|
|
121
|
+
fi
|
|
113
122
|
|
|
114
123
|
if [ "$choice" = "2" ]; then
|
|
115
124
|
FRONTEND_INSTALL_PATH="./frontend"
|
|
@@ -129,11 +138,27 @@ echo -e "\n${GREEN}...config files & utilities${NC}"
|
|
|
129
138
|
safe_cat "${TEMPLATES_DIR}/_browserslistrc" .browserslistrc new
|
|
130
139
|
safe_cat "${TEMPLATES_DIR}/_editorconfig" .editorconfig new
|
|
131
140
|
safe_cat "${TEMPLATES_DIR}/_prettierrc" .prettierrc new
|
|
132
|
-
safe_cat "${TEMPLATES_DIR}/jsconfig.json" jsconfig.json new
|
|
133
|
-
safe_cat "${BASE_URL}/../../design-tokens/tokens-config-sample.mjs" tokens-config.mjs new
|
|
134
141
|
safe_cat "${TEMPLATES_DIR}/_root_htaccess" _root_htaccess
|
|
135
142
|
safe_cat "${TEMPLATES_DIR}/_root_robots.txt" _root_robots.txt
|
|
136
143
|
|
|
144
|
+
# jsconfig.json: va installato ACCANTO a webpack.config.mjs (che legge gli alias
|
|
145
|
+
# con `path.resolve(__dirname, './jsconfig.json')`), non necessariamente in root.
|
|
146
|
+
# Il placeholder __NODE_MODULES__ viene risolto in base alla posizione scelta.
|
|
147
|
+
if [ "$FRONTEND_INSTALL_PATH" = "." ]; then
|
|
148
|
+
NODE_MODULES_REL="./node_modules"
|
|
149
|
+
else
|
|
150
|
+
NODE_MODULES_REL="../node_modules"
|
|
151
|
+
fi
|
|
152
|
+
JSCONFIG_TPL="${TEMPLATES_DIR}/jsconfig.json"
|
|
153
|
+
if [ ! -f "$JSCONFIG_TPL" ]; then
|
|
154
|
+
echo -e "${RED}Sorgente mancante: ${JSCONFIG_TPL}${NC}"
|
|
155
|
+
else
|
|
156
|
+
JSCONFIG_TMP="$(mktemp)"
|
|
157
|
+
sed "s|__NODE_MODULES__|${NODE_MODULES_REL}|g" "$JSCONFIG_TPL" >| "$JSCONFIG_TMP"
|
|
158
|
+
safe_cat "$JSCONFIG_TMP" "${FRONTEND_INSTALL_PATH}/jsconfig.json" new
|
|
159
|
+
rm -f "$JSCONFIG_TMP"
|
|
160
|
+
fi
|
|
161
|
+
|
|
137
162
|
# code-workspace: se un file .code-workspace esiste già (qualunque sia il nome),
|
|
138
163
|
# le chiavi del template vengono aggiunte in fondo con prefisso '_'
|
|
139
164
|
WORKSPACE_TPL="${TEMPLATES_DIR}/__project__.code-workspace"
|
|
@@ -155,6 +180,9 @@ else
|
|
|
155
180
|
fi
|
|
156
181
|
|
|
157
182
|
|
|
183
|
+
echo -e "\n${GREEN}...minimo${NC}"
|
|
184
|
+
npm_i -S @massimo-cassandro/minimo
|
|
185
|
+
|
|
158
186
|
echo -e "\n${GREEN}...eslint${NC}"
|
|
159
187
|
npm_i -D @massimo-cassandro/eslint-config
|
|
160
188
|
safe_cat "${TEMPLATES_DIR}/eslint.config.mjs" eslint.config.mjs new
|
|
@@ -167,6 +195,7 @@ echo -e "\n${GREEN}...webpack${NC}"
|
|
|
167
195
|
npm_i -D webpack-cli webpack-dev-server webpack-manifest-plugin webpack
|
|
168
196
|
npm_i -D @babel/core @babel/preset-env babel-loader terser-webpack-plugin
|
|
169
197
|
npm_i -D webpack-remove-empty-scripts copy-webpack-plugin html-loader html-webpack-plugin
|
|
198
|
+
# npm_i -D @principalstudio/html-webpack-inject-preload file-loader # da installare solo se necessario
|
|
170
199
|
npm_i -D postcss autoprefixer postcss-custom-media @csstools/postcss-global-data postcss-loader postcss-preset-env
|
|
171
200
|
# NB: niente cssnano: la minificazione è di css-minimizer-webpack-plugin e cssnano
|
|
172
201
|
# nel loader postcss eliminerebbe i commenti `purgecss ignore` prima di PurgeCSS
|
|
@@ -180,7 +209,6 @@ npm_i -D purgecss-webpack-plugin glob
|
|
|
180
209
|
npm_i -D style-dictionary
|
|
181
210
|
|
|
182
211
|
safe_cat "${WEBPACK_SOURCE_DIR}/webpack.config.mjs" "${FRONTEND_INSTALL_PATH}/webpack.config.mjs"
|
|
183
|
-
safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/webpack-template.ejs"
|
|
184
212
|
|
|
185
213
|
# cartella webpack
|
|
186
214
|
WEBPACK_LOCAL_DIR="${FRONTEND_INSTALL_PATH}/webpack-modules"
|
|
@@ -202,28 +230,39 @@ for FILE in "${WEBPACK_MODULES_REMOTE_URL}"/*; do
|
|
|
202
230
|
safe_cat "$FILE" "${WEBPACK_LOCAL_DIR}/$(basename "$FILE")"
|
|
203
231
|
done
|
|
204
232
|
|
|
205
|
-
echo -e "\n${GREEN}Creating
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
233
|
+
echo -e "\n${GREEN}Creating your frontend application's folder structure${NC}"
|
|
234
|
+
|
|
235
|
+
# La struttura viene creata nella posizione scelta a inizio script, coerente con
|
|
236
|
+
# i percorsi attesi da webpack.config.mjs (`./src/...`, `./favicons/output`,
|
|
237
|
+
# `./error-pages/...`), da jsconfig.json (@css, @src, @icons, @imgs) e da
|
|
238
|
+
# postcss.config.mjs (`../src/css/custom-media.css`)
|
|
239
|
+
mkdir -p \
|
|
240
|
+
"${FRONTEND_INSTALL_PATH}/src/css" \
|
|
241
|
+
"${FRONTEND_INSTALL_PATH}/src/tpl" \
|
|
242
|
+
"${FRONTEND_INSTALL_PATH}/icons" \
|
|
243
|
+
"${FRONTEND_INSTALL_PATH}/imgs" \
|
|
244
|
+
"${FRONTEND_INSTALL_PATH}/favicons" \
|
|
245
|
+
"${FRONTEND_INSTALL_PATH}/error-pages"
|
|
246
|
+
|
|
247
|
+
# template html di webpack (HtmlWebpackPlugin: `./src/tpl/index.ejs`)
|
|
248
|
+
safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/src/tpl/index.ejs"
|
|
249
|
+
|
|
250
|
+
# css di partenza del progetto: solo i file destinati a essere personalizzati.
|
|
251
|
+
# minimo.css NON viene copiato: i moduli css del framework vanno importati dal
|
|
252
|
+
# pacchetto (`@import '@minimo/css/...'`, vedi entry-tpl.css)
|
|
215
253
|
MINIMO_ROOT_CSS_DIR="${BASE_URL}/../../src"
|
|
216
|
-
for FILE in
|
|
217
|
-
safe_cat "$FILE" "${
|
|
254
|
+
for FILE in custom-properties.css custom-media.css fonts.css; do
|
|
255
|
+
safe_cat "${MINIMO_ROOT_CSS_DIR}/${FILE}" "${FRONTEND_INSTALL_PATH}/src/css/${FILE}"
|
|
218
256
|
done
|
|
219
257
|
|
|
220
|
-
#
|
|
221
|
-
|
|
258
|
+
# config di build-tokens: collocato accanto al css generato (custom-properties.css).
|
|
259
|
+
# NB: i percorsi relativi nel file vanno adattati alla sua posizione effettiva
|
|
260
|
+
safe_cat "${BASE_URL}/../../design-tokens/tokens-config-sample.mjs" "${FRONTEND_INSTALL_PATH}/src/css/tokens-config.mjs"
|
|
222
261
|
|
|
223
262
|
# template delle entry css (globale/di pagina e critical): ogni entry deve
|
|
224
263
|
# importare direttamente custom-properties.css (vedi commenti nei file stessi)
|
|
225
|
-
safe_cat "${TEMPLATES_DIR}/entry-tpl.css" "${
|
|
226
|
-
safe_cat "${TEMPLATES_DIR}/entry-tpl.critical.css" "${
|
|
264
|
+
safe_cat "${TEMPLATES_DIR}/entry-tpl.css" "${FRONTEND_INSTALL_PATH}/src/entry-tpl.css"
|
|
265
|
+
safe_cat "${TEMPLATES_DIR}/entry-tpl.critical.css" "${FRONTEND_INSTALL_PATH}/src/entry-tpl.critical.css"
|
|
227
266
|
|
|
228
267
|
set +C
|
|
229
268
|
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
"settings": {
|
|
8
8
|
|
|
9
9
|
"cssvar.files": [
|
|
10
|
-
"frontend/css/custom-properties.css", // project props
|
|
10
|
+
"frontend/src/css/custom-properties.css", // project props (frontend in sottodirectory)
|
|
11
|
+
// "src/css/custom-properties.css", // project props (frontend nella root)
|
|
11
12
|
|
|
12
13
|
// OPEN PROPS
|
|
13
14
|
// "./node_modules/open-props/open-props.min.css", // all open-props
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"__help": "https://code.visualstudio.com/docs/languages/jsconfig",
|
|
3
|
+
"__note": "Tenere questo file ACCANTO a webpack.config.mjs: gli alias webpack sono ricavati da qui (get-jsConfig-aliases.mjs) e risolti a partire dalla posizione di questo file",
|
|
3
4
|
"compilerOptions": {
|
|
4
5
|
"ignoreDeprecations": "6.0",
|
|
5
6
|
"baseUrl": ".",
|
|
@@ -8,14 +9,14 @@
|
|
|
8
9
|
"target": "es2023",
|
|
9
10
|
"module": "ES6",
|
|
10
11
|
"paths": {
|
|
11
|
-
"@css/*": ["./
|
|
12
|
-
"@src/*": ["./
|
|
13
|
-
"@icons/*": ["./
|
|
14
|
-
"@imgs/*": ["./
|
|
15
|
-
"@frontend/*": ["
|
|
16
|
-
"@minimo/*": ["
|
|
17
|
-
"@minimoCharts/*": ["
|
|
12
|
+
"@css/*": ["./src/css/*"],
|
|
13
|
+
"@src/*": ["./src/*"],
|
|
14
|
+
"@icons/*": ["./icons/*"],
|
|
15
|
+
"@imgs/*": ["./imgs/*"],
|
|
16
|
+
"@frontend/*": ["./*"],
|
|
17
|
+
"@minimo/*": ["__NODE_MODULES__/@massimo-cassandro/minimo/src/*"],
|
|
18
|
+
"@minimoCharts/*": ["__NODE_MODULES__/@massimo-cassandro/minimo/charts/*"]
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
|
-
"exclude": ["
|
|
21
|
+
"exclude": ["__NODE_MODULES__", "dist", "docs", "build", "public"]
|
|
21
22
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"webpack PROD": "npm run 'UPD-version' && NODE_ENV=production webpack --config ./webpack.config.mjs --stats minimal",
|
|
23
23
|
"eslint-check": "npx eslint app/ # or src/, frontend/src/ ...",
|
|
24
24
|
"create-favicons INIT": "npx create-favicons init",
|
|
25
|
-
"create-favicons": "npx create-favicons --dir=./
|
|
25
|
+
"create-favicons": "npx create-favicons --dir=./favicons # o ./frontend/favicons",
|
|
26
26
|
"UPD-version": "npx update-version # --log-file=./frontend/changelog.md --log-patch --pkg=alt/path/to/package.json",
|
|
27
27
|
"upd@m": "npx upd@m",
|
|
28
28
|
"launchChrome": "open -n -a 'Google Chrome' --args --profile-directory='Profile 3'",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"php server": "php -S localhost:8000 # -t root_dir/",
|
|
31
31
|
"symfony server": "symfony serve --port=8100 --listen-ip=0.0.0.0 # symfony server:stop # http://192.168.1.135:8100 # -d (deamon): rimane aperto anche dopo la chiusra del terminale",
|
|
32
32
|
"node server": "node serve # richiede ‘npm i serve’",
|
|
33
|
-
"build tokens": "npx buildTokens --config ./
|
|
34
|
-
"check unresolved props": "npx checkUnresolvedProps --config ./
|
|
33
|
+
"build tokens": "npx buildTokens --config ./src/css/tokens-config.mjs # o ./frontend/src/css/tokens-config.mjs",
|
|
34
|
+
"check unresolved props": "npx checkUnresolvedProps --config ./src/css/tokens-config.mjs # o ./frontend/src/css/tokens-config.mjs",
|
|
35
35
|
"npm-outdated": "npm outdated",
|
|
36
36
|
"npm-upd": "npm update --save"
|
|
37
37
|
},
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
+
<!-- template html di webpack: installato in <frontend>/src/tpl/index.ejs
|
|
3
|
+
(vedi HtmlWebpackPlugin in webpack.config.mjs).
|
|
4
|
+
I require sono relativi a QUESTO file. -->
|
|
2
5
|
<html lang="it">
|
|
3
6
|
<head>
|
|
4
7
|
<meta charset="utf-8">
|
|
5
8
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
6
9
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
7
10
|
|
|
8
|
-
<!-- favicons -->
|
|
9
|
-
<%= require('
|
|
10
|
-
<!-- <%= require('./app/favicons/output/favicons.incl.ejs')({}) %> -->
|
|
11
|
-
<!-- <%= require('./frontend/favicons/output/favicons.incl.ejs')({}) %> -->
|
|
11
|
+
<!-- favicons (generate da `npx create-favicons`, vedi package.json) -->
|
|
12
|
+
<%= require('../../favicons/output/favicons.incl.ejs')({}) %>
|
|
12
13
|
|
|
13
14
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
|
14
15
|
<!-- <base href="<%= htmlWebpackPlugin.options.base %>"> -->
|
|
@@ -24,21 +24,41 @@ import { getJsConfigAliases } from './webpack-modules/get-jsConfig-aliases.mjs';
|
|
|
24
24
|
import { svgRules } from './webpack-modules/svg-rules.mjs';
|
|
25
25
|
|
|
26
26
|
// --- config ---
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
28
|
+
,__dirname = path.dirname(__filename);
|
|
29
|
+
|
|
30
|
+
// Risolve un percorso a partire dalla root del progetto, che coincide con la dir
|
|
31
|
+
// di questo file solo se il frontend NON è in una sottodirectory (es. ./frontend):
|
|
32
|
+
// vengono provate entrambe le posizioni, in fallback la prima
|
|
33
|
+
const fromProjectRoot = (relPath) => {
|
|
34
|
+
const candidates = ['./', '../'].map(p => path.resolve(__dirname, p, relPath));
|
|
35
|
+
return candidates.find(p => fs.existsSync(p)) ?? candidates[0];
|
|
36
|
+
};
|
|
37
|
+
|
|
27
38
|
const isDevelopment = process.env.NODE_ENV === 'development'
|
|
28
|
-
,__filename = fileURLToPath(import.meta.url)
|
|
29
|
-
,__dirname = path.dirname(__filename)
|
|
30
39
|
,useSass = false
|
|
31
40
|
,inlineCssInDevMode = true
|
|
32
41
|
,useSvgo = true
|
|
33
42
|
,useSvgr = false // svg per react
|
|
34
43
|
,svgoConfig = useSvgo? (await import('./webpack-modules/svgo.config.mjs')).default : null
|
|
35
44
|
,postcssConfig_path = path.resolve(__dirname, './webpack-modules/postcss.config.mjs')
|
|
45
|
+
// dir di output: relativa a QUESTO file ('../build' se il frontend è in una
|
|
46
|
+
// sottodirectory, './build' se webpack.config.mjs è nella root del progetto)
|
|
36
47
|
,output_dir = path.resolve(__dirname, '../build')
|
|
37
48
|
// ,output_dir = isDevelopment? '_dev' : 'build' // symfony
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
// dir delle favicons generate da `npx create-favicons` (vedi package.json):
|
|
50
|
+
// il path assoluto serve a CopyWebpackPlugin/HtmlWebpackPlugin (i path
|
|
51
|
+
// relativi sarebbero risolti dal cwd, non da questo file), mentre la regexp
|
|
52
|
+
// resta relativa perché viene confrontata con i path dei moduli
|
|
53
|
+
,favicons_path = path.resolve(__dirname, './favicons/output')
|
|
54
|
+
,favicons_path_regexp = /favicons\/output/ // source pattern per le favicons (regexp o null)
|
|
55
|
+
// NB: jsconfig.json va tenuto in questa stessa dir (gli alias sono risolti
|
|
56
|
+
// a partire dalla sua posizione)
|
|
40
57
|
,jsConfigAliases = getJsConfigAliases(path.resolve(__dirname, './jsconfig.json'))
|
|
41
|
-
,packageJson = JSON.parse(fs.readFileSync(
|
|
58
|
+
,packageJson = JSON.parse(fs.readFileSync(fromProjectRoot('package.json'), 'utf-8'))
|
|
59
|
+
// path del pacchetto minimo (il suo js genera markup con classi proprie e il
|
|
60
|
+
// suo css dichiara custom properties: entrambi vanno visti da PurgeCSS)
|
|
61
|
+
,minimo_path = fromProjectRoot('node_modules/@massimo-cassandro/minimo')
|
|
42
62
|
,usePurgeCss = true // false per disattivare PurgeCSS (debug rapido di problemi legati al purge)
|
|
43
63
|
,purgeCSSOptions = {
|
|
44
64
|
variables: false, // rimuove le custom properties non usate (sostituisce jit-props)
|
|
@@ -91,7 +111,7 @@ const shared_chunk_paths = (module) => {
|
|
|
91
111
|
// https://github.com/webpack/copy-webpack-plugin/tree/main?tab=readme-ov-file#copy-webpack-plugin
|
|
92
112
|
const CopyWebpackPluginPatterns = [
|
|
93
113
|
{
|
|
94
|
-
from:
|
|
114
|
+
from: `${favicons_path}/icon-*.png`,
|
|
95
115
|
to: '[name][ext]'
|
|
96
116
|
},
|
|
97
117
|
// {
|
|
@@ -115,110 +135,9 @@ const CopyWebpackPluginPatterns = [
|
|
|
115
135
|
// }
|
|
116
136
|
];
|
|
117
137
|
|
|
118
|
-
// =>> PurgeCSS
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
// così i problemi di purge emergono subito durante lo sviluppo:
|
|
122
|
-
// - `purgeCSSPluginCritical`: solo le entry `*.critical` (purge stretto, gli asset
|
|
123
|
-
// devono essere autosufficienti e minimi perché inlinati nei template html)
|
|
124
|
-
// - `purgeCSSPlugin`: tutti gli asset (il doppio passaggio sui critical è idempotente)
|
|
125
|
-
//
|
|
126
|
-
// NB (watch mode): i template twig NON sono osservati da webpack: dopo aver
|
|
127
|
-
// aggiunto una classe solo in un twig occorre rilanciare la build (o toccare
|
|
128
|
-
// un file js/css) perché il purge venga ricalcolato.
|
|
129
|
-
// NB (dev): il plugin agisce solo sugli asset css emessi; con
|
|
130
|
-
// `inlineCssInDevMode: true` i css non-critical in dev sono iniettati da
|
|
131
|
-
// style-loader e non vengono purgati (i critical passano comunque da
|
|
132
|
-
// MiniCssExtract e sono sempre purgati)
|
|
133
|
-
|
|
134
|
-
// `paths`: SOLO file che generano markup o classi (html/ejs, twig, php, js);
|
|
135
|
-
// NIENTE file css tra i paths: verrebbero letti come "contenuto" e ogni selettore
|
|
136
|
-
// risulterebbe usato, vanificando il purge
|
|
137
|
-
const purgeCSSCommonOptions = {
|
|
138
|
-
paths: () => globSync(
|
|
139
|
-
[
|
|
140
|
-
path.resolve(__dirname, './src/**/*.{js,mjs,jsx}'),
|
|
141
|
-
path.resolve(__dirname, './*.ejs'), // template html di webpack
|
|
142
|
-
path.resolve(__dirname, './src/**/*.ejs'),
|
|
143
|
-
// progetti symfony: template twig e classi generate lato php
|
|
144
|
-
// path.resolve(__dirname, '../templates/**/*.twig'),
|
|
145
|
-
// path.resolve(__dirname, '../src/**/*.php'),
|
|
146
|
-
// il js di minimo genera markup con classi proprie (snackbar, unsplash-page, ecc.)
|
|
147
|
-
// NB: adattare il percorso di node_modules se questo config è in una
|
|
148
|
-
// sottodirectory del progetto (es. frontend/ → '../node_modules/...')
|
|
149
|
-
path.resolve(__dirname, './node_modules/@massimo-cassandro/minimo/src/**/*.{js,mjs}'),
|
|
150
|
-
],
|
|
151
|
-
{ nodir: true }
|
|
152
|
-
),
|
|
153
|
-
|
|
154
|
-
// extractor di default (/[A-Za-z0-9_-]+/g): adeguato a classi/tag/id,
|
|
155
|
-
// NON definire extractors custom (il vecchio /[A-z0-9-:/]+/ era buggato:
|
|
156
|
-
// il range [A-z] include caratteri non voluti come `[`, `\`, `^`, ...)
|
|
157
|
-
|
|
158
|
-
variables: true, // rimuove le custom properties non usate (sostituisce postcss-jit-props)
|
|
159
|
-
keyframes: true, // rimuove i @keyframes non referenziati
|
|
160
|
-
// fontFace resta false (default): i font sono referenziati solo tramite
|
|
161
|
-
// var(--font-family) e purgecss non risolve le custom properties nei valori,
|
|
162
|
-
// quindi con `true` i @font-face verrebbero rimossi anche se usati
|
|
163
|
-
|
|
164
|
-
rejected: purgeCSSDebug // popola purgedStats per il log di debug
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// safelist base minima, comune alle due istanze
|
|
168
|
-
const purgeCSSSafelistBase = {
|
|
169
|
-
standard: [
|
|
170
|
-
// classi costruite dinamicamente nei template o lato server, invisibili
|
|
171
|
-
// all'analisi statica dei paths. Esempio (da adattare al progetto):
|
|
172
|
-
// flash messages twig con class="alert alert-{{ label }}"
|
|
173
|
-
/^alert-(success|notice|error|warning)$/
|
|
174
|
-
],
|
|
175
|
-
deep: [
|
|
176
|
-
// css modules: prefisso `m_` presente in dev e prod (vedi css-rules.mjs),
|
|
177
|
-
// le classi hashate non possono comparire nei file scansionati
|
|
178
|
-
/^m_/
|
|
179
|
-
],
|
|
180
|
-
greedy: [
|
|
181
|
-
// INDISPENSABILE: purgecss non riconosce il nesting selector nativo e senza
|
|
182
|
-
// questo pattern i selettori annidati composti solo da `&` + pseudo classi
|
|
183
|
-
// (&:hover, &:focus-visible, `&` semplice, ecc.) verrebbero SEMPRE rimossi
|
|
184
|
-
/^&$/
|
|
185
|
-
]
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
// css della pagina critici (inlinati nei template): purge stretto,
|
|
189
|
-
// devono essere autosufficienti e minimi
|
|
190
|
-
const purgeCSSPluginCritical = new PurgeCSSPlugin({
|
|
191
|
-
...purgeCSSCommonOptions,
|
|
192
|
-
only: ['.critical'],
|
|
193
|
-
safelist: purgeCSSSafelistBase
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// tutti gli altri asset (il purge è idempotente: il secondo passaggio
|
|
197
|
-
// sui critical non rimuove altro)
|
|
198
|
-
const purgeCSSPlugin = new PurgeCSSPlugin({
|
|
199
|
-
...purgeCSSCommonOptions,
|
|
200
|
-
safelist: {
|
|
201
|
-
...purgeCSSSafelistBase,
|
|
202
|
-
// elenco generato: usi di var() nei blocchi `purgecss ignore` e nei css
|
|
203
|
-
// shadow-DOM/`?raw`, override cross-asset (seeds), con chiusura transitiva
|
|
204
|
-
// delle dipendenze (vedi webpack-modules/purgecss-variables-safelist.mjs)
|
|
205
|
-
variables: purgecssVariablesSafelist({
|
|
206
|
-
declarationGlobs: [
|
|
207
|
-
path.resolve(__dirname, './src/**/*.css'),
|
|
208
|
-
path.resolve(__dirname, './node_modules/@massimo-cassandro/minimo/src/**/*.css'),
|
|
209
|
-
],
|
|
210
|
-
shadowGlobs: [
|
|
211
|
-
path.resolve(__dirname, './src/web-components/**/*.css'),
|
|
212
|
-
path.resolve(__dirname, './node_modules/@massimo-cassandro/minimo/src/web-components/**/*.css'),
|
|
213
|
-
],
|
|
214
|
-
seeds: [
|
|
215
|
-
// props dichiarate in un asset ma consumate in un altro (es. override
|
|
216
|
-
// di tema definiti nel css di una pagina e consumati dal css globale):
|
|
217
|
-
// indicarle qui per nome ('--btn-primary-bg') o pattern (/^--btn-/)
|
|
218
|
-
]
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
});
|
|
138
|
+
// =>> PurgeCSS
|
|
139
|
+
// Istanze e opzioni sono in webpack-modules/purgecss-setup.mjs: qui restano
|
|
140
|
+
// solo i flag e i dati di progetto (vedi createPurgeCSSPlugins nei `plugins`).
|
|
222
141
|
|
|
223
142
|
// recupero metadata immagini
|
|
224
143
|
// const require = createRequire(import.meta.url);
|
|
@@ -235,7 +154,7 @@ const entries = {
|
|
|
235
154
|
|
|
236
155
|
// css critici inlinati nei template html: il suffisso `.critical` nel nome
|
|
237
156
|
// della entry attiva l'istanza PurgeCSS dedicata con purge stretto
|
|
238
|
-
// (vedi
|
|
157
|
+
// (vedi purgecss-setup.mjs) e la regola dedicata in css-rules.mjs
|
|
239
158
|
// ,'xxxxxx.critical': './src/xxxxxx.critical.css'
|
|
240
159
|
};
|
|
241
160
|
|
|
@@ -393,7 +312,7 @@ const config = {
|
|
|
393
312
|
// =>> plugins: HtmlWebpackPlugin (manifest)
|
|
394
313
|
new HtmlWebpackPlugin({
|
|
395
314
|
filename: 'manifest.webmanifest',
|
|
396
|
-
template: path.resolve(
|
|
315
|
+
template: path.resolve(favicons_path, './manifest.webmanifest.ejs'),
|
|
397
316
|
inject: false,
|
|
398
317
|
minify: false //!isDevelopment
|
|
399
318
|
}),
|
|
@@ -487,12 +406,16 @@ const config = {
|
|
|
487
406
|
// SOLO file che generano markup o classi (twig, php, js);
|
|
488
407
|
// i file di stile vengono comunque scartati dal plugin
|
|
489
408
|
contentGlobs: [
|
|
490
|
-
|
|
491
|
-
|
|
409
|
+
// progetti symfony: template twig e classi generate lato php
|
|
410
|
+
// (percorsi relativi alla root del progetto: adattare il `../` se
|
|
411
|
+
// webpack.config.mjs NON è in una sottodirectory)
|
|
412
|
+
// path.resolve(__dirname, '../templates/**/*.twig'),
|
|
413
|
+
// path.resolve(__dirname, '../src/**/*.php'),
|
|
492
414
|
path.resolve(__dirname, './src/**/*.{js,mjs,jsx}'),
|
|
415
|
+
path.resolve(__dirname, './src/**/*.ejs'), // template html di webpack
|
|
493
416
|
path.resolve(__dirname, './error-pages/**/*.js'),
|
|
494
417
|
// il js di minimo genera markup con classi proprie (snackbar, unsplash-page, ecc.)
|
|
495
|
-
|
|
418
|
+
`${minimo_path}/src/**/*.{js,mjs}`,
|
|
496
419
|
],
|
|
497
420
|
|
|
498
421
|
safelist: {
|
|
@@ -529,11 +452,11 @@ const config = {
|
|
|
529
452
|
declarationGlobs: [
|
|
530
453
|
path.resolve(__dirname, './src/**/*.css'),
|
|
531
454
|
path.resolve(__dirname, './error-pages/**/*.css'),
|
|
532
|
-
|
|
455
|
+
`${minimo_path}/src/**/*.css`,
|
|
533
456
|
],
|
|
534
457
|
shadowGlobs: [
|
|
535
458
|
path.resolve(__dirname, './src/web-components/**/*.css'),
|
|
536
|
-
|
|
459
|
+
`${minimo_path}/src/web-components/**/*.css`,
|
|
537
460
|
],
|
|
538
461
|
seeds: [
|
|
539
462
|
// override di .login-group (login.css) consumati dai buttons minimo (css globale)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massimo-cassandro/minimo",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.9",
|
|
4
4
|
"description": "Light css framework & utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"@svgdotjs/svg.js": "^3.2.7",
|
|
76
76
|
"blurhash": "^2.0.5",
|
|
77
|
+
"simple-datatables": "^10.3.0",
|
|
77
78
|
"style-dictionary": "^5.0.0"
|
|
78
79
|
},
|
|
79
80
|
"peerDependenciesMeta": {
|
|
@@ -83,6 +84,9 @@
|
|
|
83
84
|
"blurhash": {
|
|
84
85
|
"optional": true
|
|
85
86
|
},
|
|
87
|
+
"simple-datatables": {
|
|
88
|
+
"optional": true
|
|
89
|
+
},
|
|
86
90
|
"style-dictionary": {
|
|
87
91
|
"optional": true
|
|
88
92
|
}
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<https://fiduswriter.github.io/simple-datatables/documentation/>
|
|
4
4
|
|
|
5
|
+
## Installazione
|
|
6
|
+
|
|
7
|
+
`simple-datatables` è una **peer dependency opzionale** di minimo: va installata
|
|
8
|
+
solo nei progetti che usano questo componente.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i simple-datatables
|
|
12
|
+
```
|
|
5
13
|
|
|
6
14
|
## Utilizzo da markup
|
|
7
15
|
|
|
@@ -211,13 +219,29 @@ cols: [
|
|
|
211
219
|
// _sortValue: 'owner.cognome' → ordina per cognome
|
|
212
220
|
|
|
213
221
|
_searchValue, // Percorso/i del campo da usare per la RICERCA al posto del contenuto
|
|
214
|
-
// visualizzato. Accetta uno o più percorsi separati da spazio
|
|
222
|
+
// visualizzato. Accetta uno o più percorsi separati da spazio,
|
|
223
|
+
// oppure una funzione (row) => string|number|boolean.
|
|
215
224
|
// Supporta notazione punto.
|
|
216
|
-
// Implementato tramite searchMethod di colonna (API simple-datatables)
|
|
217
|
-
//
|
|
225
|
+
// Implementato tramite searchMethod di colonna (API simple-datatables):
|
|
226
|
+
// il valore viene scritto in attributes['data-search'] della cella e
|
|
227
|
+
// la searchMethod lo legge dall'OGGETTO DATI INTERNO di
|
|
228
|
+
// simple-datatables (cellType: { data, text?, order?, attributes? }),
|
|
229
|
+
// NON dal nodo DOM <td> (la libreria passa alla callback
|
|
230
|
+
// `searchRow[index]`, non l'elemento renderizzato).
|
|
231
|
+
// Ordine di lettura: attributes['data-search'] → text → data.
|
|
232
|
+
// Il valore viene convertito con String(), quindi sono ammessi
|
|
233
|
+
// numeri e booleani (es. `_searchValue: row => row.id`).
|
|
218
234
|
// La ricerca è di tipo AND: tutti i termini digitati devono essere
|
|
219
235
|
// presenti nel valore del campo (o dei campi) indicati.
|
|
220
236
|
//
|
|
237
|
+
// Normalizzazione: simple-datatables normalizza solo i termini
|
|
238
|
+
// digitati (default `sensitivity: 'base'`, `ignorePunctuation: true`).
|
|
239
|
+
// La searchMethod applica la stessa catena anche al contenuto della
|
|
240
|
+
// cella (minuscole + NFD senza diacritici + rimozione punteggiatura),
|
|
241
|
+
// così "citta" trova "Città" e "spa" trova "S.p.A.".
|
|
242
|
+
// Se sulla colonna sono impostate `sensitivity` / `ignorePunctuation`,
|
|
243
|
+
// vengono rispettate.
|
|
244
|
+
//
|
|
221
245
|
// Esempio: _searchValue: 'owner.cognome owner.nome'
|
|
222
246
|
// cerca su entrambi i campi concatenati; "rossi mario" trova solo
|
|
223
247
|
// le righe che contengono entrambe le parole, in qualsiasi ordine.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { DataTable } from 'simple-datatables';
|
|
6
6
|
|
|
7
7
|
import { parseCols } from './src/parse-cols.js';
|
|
8
|
+
import { makeSearchMethod } from './src/search-method.js';
|
|
8
9
|
|
|
9
10
|
import * as styles from './s-datatable-component.module.css';
|
|
10
11
|
|
|
@@ -640,10 +641,13 @@ class SimpleDatatableAdapter extends HTMLElement {
|
|
|
640
641
|
value = nullAs;
|
|
641
642
|
}
|
|
642
643
|
|
|
643
|
-
// _searchValue: valore alternativo per la ricerca
|
|
644
|
-
// Viene scritto
|
|
645
|
-
//
|
|
646
|
-
//
|
|
644
|
+
// _searchValue: valore alternativo per la ricerca.
|
|
645
|
+
// Viene scritto in `attributes['data-search']` della cella: la
|
|
646
|
+
// searchMethod di colonna lo legge dall'oggetto dati interno di
|
|
647
|
+
// simple-datatables (cellType), non dal DOM.
|
|
648
|
+
// Accetta un percorso (o più percorsi separati da spazio) oppure una
|
|
649
|
+
// funzione (row) => string|number: il valore viene normalizzato con
|
|
650
|
+
// String() al momento del confronto.
|
|
647
651
|
const searchValue = col_item._searchValue
|
|
648
652
|
? typeof col_item._searchValue === 'function'
|
|
649
653
|
? (col_item._searchValue(row) ?? '')
|
|
@@ -702,20 +706,14 @@ class SimpleDatatableAdapter extends HTMLElement {
|
|
|
702
706
|
// data-search invece che sul testo visualizzato.
|
|
703
707
|
// L'API simple-datatables prevede: (terms, cell, row, colIdx, source)
|
|
704
708
|
// - terms: array di stringhe (uno per parola cercata)
|
|
705
|
-
// - cell:
|
|
709
|
+
// - cell: oggetto dati interno `cellType` ({ data, text?, order?, attributes? }),
|
|
710
|
+
// NON il nodo DOM <td>: la libreria passa `searchRow[index]`
|
|
711
|
+
// (vedi `multiSearch` in src/datatable.ts).
|
|
706
712
|
// La funzione deve restituire true se la riga è da includere.
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
// come plain object, restituendo sempre undefined).
|
|
710
|
-
// Comportamento AND: tutti i termini devono essere presenti (come
|
|
711
|
-
// nella demo https://fiduswriter.github.io/simple-datatables/demos/22-and-search/).
|
|
713
|
+
// Vedi ./src/search-method.js per la lettura del valore e la
|
|
714
|
+
// normalizzazione (allineata a quella che la libreria applica ai termini).
|
|
712
715
|
if (col_settings._searchValue) {
|
|
713
|
-
colObj.searchMethod = (
|
|
714
|
-
const haystack = (
|
|
715
|
-
cell.getAttribute?.('data-search') ?? cell.textContent ?? ''
|
|
716
|
-
).toLowerCase();
|
|
717
|
-
return terms.every(term => haystack.includes(term.toLowerCase()));
|
|
718
|
-
};
|
|
716
|
+
colObj.searchMethod = makeSearchMethod(col_settings);
|
|
719
717
|
}
|
|
720
718
|
|
|
721
719
|
return colObj;
|
|
@@ -121,13 +121,15 @@ export function parseCols(col_obj){
|
|
|
121
121
|
|
|
122
122
|
} else if(col_obj._renderMode === 'numeric') {
|
|
123
123
|
return {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
...col_obj,
|
|
125
|
+
// le classi definite dall'utente vengono unite, non sostituite
|
|
126
|
+
cellClass: classnames('text-end text-numeric', col_obj.cellClass),
|
|
127
|
+
headerClass: classnames('text-end text-numeric', col_obj.headerClass), // NB: usata anche per il footer
|
|
127
128
|
};
|
|
128
129
|
|
|
129
130
|
} else if(col_obj._renderMode === 'euro_no_dec') {
|
|
130
131
|
return {
|
|
132
|
+
...col_obj,
|
|
131
133
|
render: (value, cell) => {
|
|
132
134
|
// console.log(value);
|
|
133
135
|
if(value == null || isNaN(value)) {
|
|
@@ -143,8 +145,9 @@ export function parseCols(col_obj){
|
|
|
143
145
|
});
|
|
144
146
|
}
|
|
145
147
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
// le classi definite dall'utente vengono unite, non sostituite
|
|
149
|
+
cellClass: classnames('text-nowrap text-end text-numeric', col_obj.cellClass),
|
|
150
|
+
headerClass: classnames('text-nowrap text-end text-numeric', col_obj.headerClass), // NB: usata anche per il footer
|
|
148
151
|
type: 'number'
|
|
149
152
|
};
|
|
150
153
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
// Generazione della `searchMethod` di colonna usata da `_searchValue`.
|
|
4
|
+
//
|
|
5
|
+
// simple-datatables NON passa alla searchMethod il nodo DOM della cella, ma
|
|
6
|
+
// l'oggetto dati interno `cellType` ({ data, text?, order?, attributes? }):
|
|
7
|
+
// vedi `multiSearch` in `src/datatable.ts` (`customSearchMethod(queryColumnWord,
|
|
8
|
+
// searchRow[index], row, index, source)`). Gli `attributes` sono conservati
|
|
9
|
+
// nell'oggetto dati (`readDataCell` in `src/read_data.ts` ammette le chiavi
|
|
10
|
+
// "text", "order", "data", "attributes"), quindi `data-search` va letto da
|
|
11
|
+
// `cell.attributes['data-search']`, non con `cell.getAttribute()`.
|
|
12
|
+
|
|
13
|
+
// Punteggiatura rimossa quando `ignorePunctuation` è attivo
|
|
14
|
+
const PUNCTUATION_RX = /[.,/#!$%^&*;:{}=\-_`~()]/g;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Normalizza una stringa replicando il trattamento che simple-datatables
|
|
18
|
+
* applica ai termini di ricerca quando è attiva una `searchMethod` personalizzata.
|
|
19
|
+
*
|
|
20
|
+
* La libreria normalizza solo i termini digitati (non il contenuto della cella),
|
|
21
|
+
* con i default `sensitivity: 'base'` e `ignorePunctuation: true`: se l'haystack
|
|
22
|
+
* non riceve lo stesso trattamento, "citta" non troverebbe "Città" e "spa" non
|
|
23
|
+
* troverebbe "S.p.A.".
|
|
24
|
+
*
|
|
25
|
+
* @param {*} str Valore da normalizzare (convertito con String()).
|
|
26
|
+
* @param {object} [opts]
|
|
27
|
+
* @param {'base'|'accent'|'case'|'variant'} [opts.sensitivity='base']
|
|
28
|
+
* 'base' → ignora maiuscole/minuscole e diacritici
|
|
29
|
+
* 'accent' → ignora maiuscole/minuscole, mantiene i diacritici
|
|
30
|
+
* 'case' → distingue maiuscole/minuscole, ignora i diacritici
|
|
31
|
+
* 'variant' → distingue tutto
|
|
32
|
+
* @param {boolean} [opts.ignorePunctuation=true]
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
export function normalizeSearchString(str, opts = {}) {
|
|
36
|
+
const sensitivity = opts.sensitivity ?? 'base';
|
|
37
|
+
const ignorePunctuation = opts.ignorePunctuation ?? true;
|
|
38
|
+
|
|
39
|
+
// String() anche su numeri/booleani: `_searchValue` come funzione può
|
|
40
|
+
// restituire un id numerico o un flag
|
|
41
|
+
let out = String(str ?? '');
|
|
42
|
+
|
|
43
|
+
if (sensitivity === 'base' || sensitivity === 'accent') {
|
|
44
|
+
out = out.toLowerCase();
|
|
45
|
+
}
|
|
46
|
+
if (sensitivity === 'base' || sensitivity === 'case') {
|
|
47
|
+
out = out.normalize('NFD').replace(/\p{Diacritic}/gu, '');
|
|
48
|
+
}
|
|
49
|
+
if (ignorePunctuation) {
|
|
50
|
+
out = out.replace(PUNCTUATION_RX, '');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Restituisce la `searchMethod` di colonna per le colonne con `_searchValue`.
|
|
58
|
+
*
|
|
59
|
+
* API simple-datatables: (terms, cell, row, colIdx, source) => boolean
|
|
60
|
+
* - `terms` array di stringhe (una per parola cercata), già normalizzate dalla libreria
|
|
61
|
+
* - `cell` oggetto dati `cellType` ({ data, text?, order?, attributes? })
|
|
62
|
+
*
|
|
63
|
+
* Comportamento AND: tutti i termini devono essere presenti
|
|
64
|
+
* (come nella demo https://fiduswriter.github.io/simple-datatables/demos/22-and-search/).
|
|
65
|
+
*
|
|
66
|
+
* @param {object} [colSettings] Definizione della colonna (per `sensitivity` / `ignorePunctuation`).
|
|
67
|
+
* @returns {(terms: string[], cell: object) => boolean}
|
|
68
|
+
*/
|
|
69
|
+
export function makeSearchMethod(colSettings = {}) {
|
|
70
|
+
const opts = {
|
|
71
|
+
sensitivity: colSettings.sensitivity,
|
|
72
|
+
ignorePunctuation: colSettings.ignorePunctuation,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return (terms, cell) => {
|
|
76
|
+
const raw = cell?.attributes?.['data-search']
|
|
77
|
+
?? cell?.text
|
|
78
|
+
?? (typeof cell?.data === 'string' || typeof cell?.data === 'number' ? cell.data : '');
|
|
79
|
+
|
|
80
|
+
const haystack = normalizeSearchString(raw, opts);
|
|
81
|
+
|
|
82
|
+
return terms.every(term => haystack.includes(normalizeSearchString(term, opts)));
|
|
83
|
+
};
|
|
84
|
+
}
|