@massimo-cassandro/minimo 1.43.3 → 1.44.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.43.3",
3
+ "version": "1.44.0",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  /*! minimo - Better Text with places */
3
3
 
4
- import { betterText, NBSP_AFTER_PARTICLE_REGEX } from './better-text.js';
4
+ import { betterText, NBSP_AFTER_PARTICLE_REGEX, PARTICELLE } from './better-text.js';
5
5
 
6
6
  const places = [
7
7
  // EUROPA
@@ -467,6 +467,19 @@ function buildPlacesMatcher(list) {
467
467
 
468
468
  const defaultMatcher = buildPlacesMatcher(places);
469
469
 
470
+ /*
471
+ Corrisponde agli spazi (normali o non separabili) NON seguiti da una particella:
472
+ usata con l'opzione `addNbsp` per unire le parole dei nomi composti, lasciando
473
+ separabile lo spazio prima di una particella (es. "Lago di Como" → spazio normale
474
+ tra "Lago" e "di", mentre quello tra "di" e "Como" è già gestito da betterText())
475
+ */
476
+ const SPACE_BEFORE_NON_PARTICLE_REGEX = new RegExp(
477
+ '[ \\u00A0]+(?!(?:' +
478
+ PARTICELLE.map(p => p.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&')).join('|') +
479
+ ')(?![\\p{L}\\p{N}]))',
480
+ 'giu'
481
+ );
482
+
470
483
  /**
471
484
  * Versione di betterText() che normalizza anche le occorrenze di luoghi noti
472
485
  * (paesi, città, fiumi, monti, località turistiche) presenti nel testo:
@@ -480,18 +493,33 @@ const defaultMatcher = buildPlacesMatcher(places);
480
493
  * ovunque compaiano.
481
494
  *
482
495
  * @param {string} str - stringa da elaborare
483
- * @param {string[]} [custom_words] - elenco di parole di cui va mantenuta la capitalizzazione esatta (es. `['iPhone', 'macOS']`) (default: [])
484
- * @param {string[]} [extra_places] - luoghi aggiuntivi, uniti all'elenco predefinito (default: [])
496
+ * @param {object} [options] - opzioni (default: {})
497
+ * @param {string[]} [options.custom_words] - elenco di parole di cui va mantenuta la capitalizzazione esatta (es. `['iPhone', 'macOS']`) (default: [])
498
+ * @param {string[]} [options.extra_places] - luoghi aggiuntivi, uniti all'elenco predefinito (default: [])
499
+ * @param {boolean} [options.addNbsp] - se `true`, nei nomi di luogo composti da più parole gli spazi vengono
500
+ * sostituiti da spazi non separabili, tranne quelli che precedono una particella
501
+ * (es. in "Monte Bianco" lo spazio diventa non separabile, in "Lago di Como" solo quello dopo "di") (default: false)
485
502
  * @returns {string} stringa elaborata, oppure stringa vuota se l'input è falsy
486
503
  *
487
504
  * @example
488
505
  * betterTextWithPlaces("vacanza a new york e nel lago di como ,l'avana");
489
506
  * // → "vacanza a New York e nel Lago di Como, L’Avana"
490
507
  *
491
- * betterTextWithPlaces('gita a monte cervino', ['iPhone'], ['Monte Cervino']);
508
+ * betterTextWithPlaces('gita a monte cervino', { custom_words: ['iPhone'], extra_places: ['Monte Cervino'] });
492
509
  * // → 'gita a Monte Cervino'
510
+ *
511
+ * // opzioni con i valori di default
512
+ * betterTextWithPlaces('monte bianco e lago di como', {
513
+ * custom_words: [],
514
+ * extra_places: [],
515
+ * addNbsp: false
516
+ * });
517
+ * // → 'Monte Bianco e Lago di Como' (spazio non separabile solo dopo "di")
518
+ *
519
+ * betterTextWithPlaces('monte bianco e lago di como', { addNbsp: true });
520
+ * // → 'Monte Bianco e Lago di Como' (spazi non separabili tra "Monte" e "Bianco" e dopo "di")
493
521
  */
494
- export function betterTextWithPlaces(str, custom_words = [], extra_places = []) {
522
+ export function betterTextWithPlaces(str, { custom_words = [], extra_places = [], addNbsp = false } = {}) {
495
523
 
496
524
  str = betterText(str, custom_words);
497
525
 
@@ -503,7 +531,12 @@ export function betterTextWithPlaces(str, custom_words = [], extra_places = [])
503
531
  ? buildPlacesMatcher([...places, ...extra_places])
504
532
  : defaultMatcher;
505
533
 
506
- return matcher
507
- ? str.replace(matcher.regex, match => matcher.canonical.get(placeKey(match)) ?? match)
508
- : str;
534
+ if (!matcher) {
535
+ return str;
536
+ }
537
+
538
+ return str.replace(matcher.regex, match => {
539
+ const place = matcher.canonical.get(placeKey(match)) ?? match;
540
+ return addNbsp ? place.replace(SPACE_BEFORE_NON_PARTICLE_REGEX, '\u00A0') : place;
541
+ });
509
542
  }
@@ -9,7 +9,7 @@
9
9
  che nulla di tutto ciò dipende dagli argomenti della funzione e in precedenza veniva
10
10
  ricostruito a ogni singola chiamata di betterText().
11
11
  */
12
- const PARTICELLE = [
12
+ export const PARTICELLE = [
13
13
  'e', 'ed',
14
14
  'di', 'a', 'da', 'in', 'per', 'con', 'su', 'per', 'tra', 'fra',
15
15
  'il', 'lo', 'la', 'i', 'gli', 'le',
@@ -104,7 +104,7 @@ import { classnames } from '../classnames.js';
104
104
  * });
105
105
  *
106
106
  * @param {Object} args
107
- * @param {string} args.baseSrc - URL base dell'immagine (endpoint del viewer); i suoi parametri di query vengono conservati. Un URL relativo (es. `/img/abc123`) viene risolto rispetto alla location corrente.
107
+ * @param {string} args.baseSrc - URL base dell'immagine (endpoint del viewer); i suoi parametri di query vengono conservati. Un URL relativo (es. `/img/abc123`) viene risolto rispetto alla location corrente; se relativo alla root (inizia con `/`, ma non con `//`), resta tale anche negli URL generati.
108
108
  * @param {(number | [number, number] | PictureSizeEntry)[]} [args.sizes=[250]] - Dimensioni renderizzate dell'immagine, in qualsiasi ordine. Ogni entry è un oggetto `{from, size}` (vedi {@link PictureSizeEntry}); un numero semplice o una coppia `[width, height]` è la scorciatoia per l'entry predefinita mobile-first (quella senza `from`), attesa esattamente una volta (default: [250])
109
109
  * @param {number|null} [args.ratio=null] - Aspect ratio predefinito (larghezza / altezza, come nella proprietà CSS `aspect-ratio`) usato per calcolare l'altezza delle size numeriche. Se null, l'altezza non viene calcolata: gli output legati all'altezza (attributo `height`, altezza nel parametro `bb`) vengono omessi e il viewer mantiene il ratio originale dell'immagine (default: null)
110
110
  * @param {number} [args.dpr=2] - Densità di pixel massima (intero): i candidati di `srcset` vengono generati per ogni densità da 1 a `dpr` (default: 2)
@@ -183,6 +183,9 @@ export function buildPictureTag({
183
183
  const base_url = new URL(baseSrc, globalThis.location?.href)
184
184
  ,searchParams = new URLSearchParams(base_url.search)
185
185
 
186
+ // baseSrc relativo alla root: negli URL generati viene omessa l'origine aggiunta per la risoluzione
187
+ ,isRootRelative = baseSrc.startsWith('/') && !baseSrc.startsWith('//')
188
+
186
189
  // dimensioni dei candidati srcset (una per ogni densità da 1 a `dpr`),
187
190
  // senza duplicati (per larghezza), in ordine crescente
188
191
  ,srcsetSizes = sizeEntries
@@ -240,7 +243,7 @@ export function buildPictureTag({
240
243
  // TODO senza altezza `bb=<w>x` vale per il viewer di default: prevedere altre convenzioni (es. imgix)
241
244
  searchParams.set('bb', `${w}x${h ?? ''}`);
242
245
  base_url.search = searchParams.toString();
243
- srcsetArray.push(`${base_url.toString()} ${w}w`);
246
+ srcsetArray.push(`${isRootRelative? base_url.pathname + base_url.search : base_url.toString()} ${w}w`);
244
247
  });
245
248
 
246
249
  if(is_default_fmt) {