@vettvangur/vanilla 0.0.50 → 0.0.56

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/dist/index.esm.js CHANGED
@@ -416,379 +416,4 @@ function getCulture(path) {
416
416
  return match ? match[1].toLowerCase() : null;
417
417
  }
418
418
 
419
- /**
420
- * Init hyphenation.
421
- *
422
- * @param {Document | ParentNode} [root=document]
423
- * Root node to scope the query to.
424
- *
425
- * - Use `document` to scan the whole page.
426
- * - Use an element (or other `ParentNode`) to scope hyphenation to a subtree.
427
- * @param {{ classes?: string[] }} [options={}]
428
- * Configuration options.
429
- *
430
- * - `options.classes`: array of class tokens or prefixes to match.
431
- * Each token matches either an exact class or a prefix (e.g. `headline` matches `headline` and `headline-xl`).
432
- * If omitted, defaults to targeting elements matching `[class*="headline"]`.
433
- * @returns {Promise<void>} Nothing.
434
- */
435
- async function initHyphenation$1(root = document, options = {}) {
436
- const mod = await Promise.resolve().then(function () { return hyphen; });
437
- return mod.initHyphenation(root, options);
438
- }
439
-
440
- /**
441
- * Lazy-loaded hyphenation functions. Loaded on-demand so consumers that
442
- * do not use hyphenation do not pay the bundle cost.
443
- */
444
-
445
- /** @type {Promise<((word: string) => Promise<string>) | null> | null} */
446
- let hyphenateEnPromise = null;
447
- /** @type {Promise<((word: string) => Promise<string>) | null> | null} */
448
- let hyphenateIsPromise = null;
449
-
450
- /**
451
- * Stores the original (non-hyphenated) text content for elements.
452
- * Used to ensure idempotent re-runs on resize/font load.
453
- * @type {WeakMap<HTMLElement, string>}
454
- */
455
- const originalText = new WeakMap();
456
- let resizeListenerBound = false;
457
- let resizeTimer;
458
- /** @type {HyphenationOptions | undefined} */
459
- let resizeOptions;
460
- let fontsListenerBound = false;
461
- const HYHEN_CLASS_MANUAL = 'js-hyphen-manual';
462
- const HYPHEN_CLASS_EMERGENCY = 'js-hyphen-emergency';
463
-
464
- /** @type {CanvasRenderingContext2D | null} */
465
- let measureCtx = null;
466
-
467
- /**
468
- * Gets (and lazily creates) the canvas context used for text measurement.
469
- *
470
- * @returns {CanvasRenderingContext2D | null}
471
- */
472
- function getMeasureCtx() {
473
- if (measureCtx) {
474
- return measureCtx;
475
- }
476
- if (typeof document === 'undefined') {
477
- return null;
478
- }
479
- const canvas = document.createElement('canvas');
480
- measureCtx = canvas.getContext('2d');
481
- return measureCtx;
482
- }
483
-
484
- /**
485
- * Loads the `hyphen` package module and extracts a `hyphenate()` function,
486
- * handling common CJS/ESM interop shapes.
487
- *
488
- * @param {string} moduleId
489
- * @returns {Promise<((word: string) => Promise<string>) | null>}
490
- */
491
- async function loadHyphenate(moduleId) {
492
- try {
493
- var _ref, _mod$hyphenate, _mod$default, _mod$default2;
494
- const mod = await import(moduleId);
495
- const hyphenate = (_ref = (_mod$hyphenate = mod === null || mod === void 0 ? void 0 : mod.hyphenate) !== null && _mod$hyphenate !== void 0 ? _mod$hyphenate : mod === null || mod === void 0 || (_mod$default = mod.default) === null || _mod$default === void 0 ? void 0 : _mod$default.hyphenate) !== null && _ref !== void 0 ? _ref : mod === null || mod === void 0 || (_mod$default2 = mod.default) === null || _mod$default2 === void 0 || (_mod$default2 = _mod$default2.default) === null || _mod$default2 === void 0 ? void 0 : _mod$default2.hyphenate;
496
- if (typeof hyphenate === 'function') {
497
- return hyphenate;
498
- }
499
- console.error('[vanilla] initHyphenation: hyphenate() export not found (CJS/ESM interop issue).', {
500
- moduleId,
501
- availableKeys: mod ? Object.keys(mod) : null,
502
- defaultKeys: mod !== null && mod !== void 0 && mod.default && typeof mod.default === 'object' ? Object.keys(mod.default) : null
503
- });
504
- return null;
505
- } catch (error) {
506
- console.error('[vanilla] initHyphenation: failed to load hyphenation module.', {
507
- moduleId,
508
- error
509
- });
510
- return null;
511
- }
512
- }
513
-
514
- /**
515
- * @param {string} lang
516
- * @returns {Promise<((word: string) => Promise<string>) | null>}
517
- */
518
- function getHyphenateForLang(lang) {
519
- const isIcelandic = lang.startsWith('is');
520
- if (isIcelandic) {
521
- if (!hyphenateIsPromise) {
522
- hyphenateIsPromise = loadHyphenate('hyphen/is/index.js');
523
- }
524
- return hyphenateIsPromise;
525
- }
526
- if (!hyphenateEnPromise) {
527
- hyphenateEnPromise = loadHyphenate('hyphen/en/index.js');
528
- }
529
- return hyphenateEnPromise;
530
- }
531
-
532
- /**
533
- * Applies a CSS-like text-transform to a string.
534
- *
535
- * @param {string} text
536
- * @param {string} transform
537
- * @returns {string}
538
- */
539
- function applyTextTransform(text, transform) {
540
- switch (transform) {
541
- case 'uppercase':
542
- return text.toUpperCase();
543
- case 'lowercase':
544
- return text.toLowerCase();
545
- default:
546
- return text;
547
- }
548
- }
549
-
550
- /**
551
- * Measures rendered text width using canvas, approximating letter-spacing.
552
- *
553
- * @param {string} text
554
- * @param {CSSStyleDeclaration} style
555
- * @returns {number}
556
- */
557
- function measureTextWidth(text, style) {
558
- const ctx = getMeasureCtx();
559
- if (!ctx) {
560
- return 0;
561
- }
562
-
563
- // `style.font` is a computed shorthand like "700 16px/20px Foo".
564
- ctx.font = style.font;
565
- const transformed = applyTextTransform(text, style.textTransform);
566
- const metrics = ctx.measureText(transformed);
567
- let width = metrics.width;
568
-
569
- // Canvas does not support letter-spacing; approximate when it's a pixel value.
570
- if (style.letterSpacing && style.letterSpacing !== 'normal') {
571
- const ls = Number.parseFloat(style.letterSpacing);
572
- if (Number.isFinite(ls) && transformed.length > 1) {
573
- width += (transformed.length - 1) * ls;
574
- }
575
- }
576
- return width;
577
- }
578
-
579
- /**
580
- * Options for initHyphenation.
581
- *
582
- * @typedef {Object} HyphenationOptions
583
- * @property {string[]} [classes]
584
- * Class names or prefixes to target. If omitted, defaults to `[class*="headline"]`.
585
- */
586
-
587
- /**
588
- * Escapes a string for use inside a CSS attribute selector.
589
- *
590
- * @param {string} value
591
- * @returns {string}
592
- */
593
- function escapeForCssAttrValue(value) {
594
- return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
595
- }
596
-
597
- /**
598
- * Normalizes a class token by trimming and removing a leading dot.
599
- *
600
- * @param {string} className
601
- * @returns {string}
602
- */
603
- function normalizeClassToken(className) {
604
- return className.trim().replace(/^\./, '');
605
- }
606
-
607
- /**
608
- * Finds the element that defines the usable line width.
609
- * Inline elements are walked upward until a non-inline ancestor is found.
610
- *
611
- * @param {HTMLElement} el
612
- * @returns {HTMLElement}
613
- */
614
- function findLineWidthElement(el) {
615
- let current = el;
616
- while (current) {
617
- const display = getComputedStyle(current).display;
618
- if (display !== 'inline') {
619
- return current;
620
- }
621
- current = current.parentElement;
622
- }
623
- return el;
624
- }
625
-
626
- /**
627
- * Computes the available line width for an element, excluding horizontal padding.
628
- *
629
- * @param {HTMLElement} el
630
- * @returns {number}
631
- */
632
- function getAvailableLineWidth(el) {
633
- const widthEl = findLineWidthElement(el);
634
- const rectWidth = widthEl.getBoundingClientRect().width;
635
- const base = widthEl.clientWidth || rectWidth;
636
- if (!base) {
637
- return 0;
638
- }
639
- const style = getComputedStyle(widthEl);
640
- const paddingLeft = Number.parseFloat(style.paddingLeft) || 0;
641
- const paddingRight = Number.parseFloat(style.paddingRight) || 0;
642
- return Math.max(0, Math.floor(base - paddingLeft - paddingRight));
643
- }
644
-
645
- /**
646
- * Removes legacy inline hyphenation styles so class-based styling can take over.
647
- *
648
- * @param {HTMLElement} el
649
- */
650
- function removeLegacyInlineHyphenStyles(el) {
651
- el.style.removeProperty('hyphens');
652
- el.style.removeProperty('overflow-wrap');
653
- el.style.removeProperty('word-break');
654
- const styleAttr = el.getAttribute('style');
655
- if (styleAttr != null && styleAttr.trim() === '') {
656
- el.removeAttribute('style');
657
- }
658
- }
659
-
660
- /**
661
- * Initializes responsive, language-aware hyphenation for text elements.
662
- *
663
- * - Inserts soft hyphens for words that cannot fit on a line by themselves.
664
- * - Re-runs on window resize and font loading when called on `document`.
665
- * - Adds `js-hyphen-manual` when soft hyphens are inserted.
666
- * - Adds `js-hyphen-emergency` as a last-resort overflow fallback.
667
- *
668
- * @param {Document | ParentNode} [root=document]
669
- * Root node to scope the query to.
670
- *
671
- * - Use `document` to scan the whole page and enable auto re-runs on resize/font load.
672
- * - Use an element (or other `ParentNode`) to scope hyphenation to a subtree (no global listeners).
673
- * @param {HyphenationOptions} [options={}]
674
- * Configuration options.
675
- *
676
- * - `options.classes`: array of class tokens or prefixes to match.
677
- * Each token matches either an exact class or a prefix (e.g. `headline` matches `headline` and `headline-xl`).
678
- * If omitted, defaults to targeting elements matching `[class*="headline"]`.
679
- * @returns {Promise<void>}
680
- */
681
- async function initHyphenation(root = document, options = {}) {
682
- var _options$classes;
683
- if (typeof document === 'undefined') {
684
- return;
685
- }
686
- if (root === document) {
687
- resizeOptions = options;
688
- if (!resizeListenerBound) {
689
- resizeListenerBound = true;
690
- window.addEventListener('resize', () => {
691
- if (resizeTimer) {
692
- window.clearTimeout(resizeTimer);
693
- }
694
- resizeTimer = window.setTimeout(() => {
695
- initHyphenation(document, resizeOptions || {}).catch(e => console.error('hyphenation', e));
696
- }, 150);
697
- });
698
- }
699
- if (!fontsListenerBound && 'fonts' in document) {
700
- var _fontSet$ready;
701
- fontsListenerBound = true;
702
- const fontSet = document.fonts;
703
- fontSet === null || fontSet === void 0 || (_fontSet$ready = fontSet.ready) === null || _fontSet$ready === void 0 || _fontSet$ready.then(() => initHyphenation(document, resizeOptions || {})).catch(e => console.error('hyphenation fonts', e));
704
- try {
705
- var _fontSet$addEventList;
706
- fontSet === null || fontSet === void 0 || (_fontSet$addEventList = fontSet.addEventListener) === null || _fontSet$addEventList === void 0 || _fontSet$addEventList.call(fontSet, 'loadingdone', () => {
707
- initHyphenation(document, resizeOptions || {}).catch(e => console.error('hyphenation fonts', e));
708
- });
709
- } catch (_unused) {
710
- // ignore
711
- }
712
- }
713
- }
714
- const candidates = (_options$classes = options.classes) !== null && _options$classes !== void 0 && _options$classes.length ? Array.from(options.classes.reduce((acc, className) => {
715
- const token = normalizeClassToken(className);
716
- if (!token) {
717
- return acc;
718
- }
719
- const escaped = escapeForCssAttrValue(token);
720
- root.querySelectorAll(`[class*="${escaped}"]`).forEach(el => {
721
- const matches = Array.from(el.classList).some(cls => cls === token || cls.startsWith(token));
722
- if (matches) {
723
- acc.add(el);
724
- }
725
- });
726
- return acc;
727
- }, new Set())) : Array.from(root.querySelectorAll('[class*="headline"]'));
728
- if (candidates.length === 0) {
729
- return;
730
- }
731
- await Promise.all(candidates.map(async el => {
732
- var _el$closest;
733
- removeLegacyInlineHyphenStyles(el);
734
- el.classList.remove(HYHEN_CLASS_MANUAL, HYPHEN_CLASS_EMERGENCY);
735
- const current = (el.textContent || '').replace(/\u00ad/g, '');
736
- const stored = originalText.get(el);
737
- const text = stored && stored === current ? stored : current;
738
- originalText.set(el, text);
739
- if (!text.trim()) {
740
- return;
741
- }
742
- if (el.textContent !== text) {
743
- el.textContent = text;
744
- }
745
- const availableWidth = getAvailableLineWidth(el);
746
- if (!availableWidth) {
747
- return;
748
- }
749
- const lang = (((_el$closest = el.closest('[lang]')) === null || _el$closest === void 0 ? void 0 : _el$closest.lang) || document.documentElement.lang || 'en-us').toLowerCase();
750
- const style = getComputedStyle(el);
751
- const parts = text.split(/(\s+)/);
752
- let didChange = false;
753
- let needsEmergencyBreak = false;
754
-
755
- /** @type {((word: string) => Promise<string>) | null} */
756
- let hyphenFn = null;
757
- for (let i = 0; i < parts.length; i++) {
758
- const part = parts[i];
759
- if (!part || /^\s+$/.test(part)) {
760
- continue;
761
- }
762
- if (measureTextWidth(part, style) <= availableWidth) {
763
- continue;
764
- }
765
- if (!hyphenFn) {
766
- hyphenFn = await getHyphenateForLang(lang);
767
- if (!hyphenFn) {
768
- return;
769
- }
770
- }
771
- const hyphenatedWord = await hyphenFn(part);
772
- if (hyphenatedWord !== part) {
773
- parts[i] = hyphenatedWord;
774
- didChange = true;
775
- } else {
776
- needsEmergencyBreak = true;
777
- }
778
- }
779
- if (didChange) {
780
- el.classList.add(HYHEN_CLASS_MANUAL);
781
- el.textContent = parts.join('');
782
- }
783
- if (needsEmergencyBreak) {
784
- el.classList.add(HYPHEN_CLASS_EMERGENCY);
785
- }
786
- }));
787
- }
788
-
789
- var hyphen = /*#__PURE__*/Object.freeze({
790
- __proto__: null,
791
- initHyphenation: initHyphenation
792
- });
793
-
794
- export { Umbraco, capitalize, clickOutside, getBlock as default, dictionary, fetcher, flatten, getBlock, getCulture, getTemplate, getTranslation, initHyphenation$1 as initHyphenation, isEmpty, preloadTimeout, regexr };
419
+ export { Umbraco, capitalize, clickOutside, getBlock as default, dictionary, fetcher, flatten, getBlock, getCulture, getTemplate, getTranslation, isEmpty, preloadTimeout, regexr };
@@ -154,25 +154,6 @@ export function getTranslation(key: any, translations: any): any;
154
154
  * getCulture(path)
155
155
  */
156
156
  export function getCulture(path: any): any;
157
- /**
158
- * Init hyphenation.
159
- *
160
- * @param {Document | ParentNode} [root=document]
161
- * Root node to scope the query to.
162
- *
163
- * - Use `document` to scan the whole page.
164
- * - Use an element (or other `ParentNode`) to scope hyphenation to a subtree.
165
- * @param {{ classes?: string[] }} [options={}]
166
- * Configuration options.
167
- *
168
- * - `options.classes`: array of class tokens or prefixes to match.
169
- * Each token matches either an exact class or a prefix (e.g. `headline` matches `headline` and `headline-xl`).
170
- * If omitted, defaults to targeting elements matching `[class*="headline"]`.
171
- * @returns {Promise<void>} Nothing.
172
- */
173
- export function initHyphenation(root?: Document | ParentNode, options?: {
174
- classes?: string[];
175
- }): Promise<void>;
176
157
  export namespace regexr {
177
158
  /**
178
159
  * Tests whether a given value matches a regex pattern.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vettvangur/vanilla",
3
- "version": "0.0.50",
3
+ "version": "0.0.56",
4
4
  "description": "Vettvangur | Vanilla JS Utility Library",
5
5
  "access": "public",
6
6
  "type": "module",
@@ -30,18 +30,13 @@
30
30
  "types": "./dist/types/data.d.ts",
31
31
  "default": "./dist/data.esm.js"
32
32
  },
33
- "./hyphenation": {
34
- "types": "./dist/types/hyphenation.d.ts",
35
- "default": "./dist/hyphenation.esm.js"
36
- },
37
33
  "./server": {
38
34
  "types": "./dist/types/server.d.ts",
39
35
  "default": "./dist/server.esm.js"
40
36
  }
41
37
  },
42
38
  "dependencies": {
43
- "dotenv": "17.2.3",
44
- "hyphen": "1.10.6"
39
+ "dotenv": "17.2.3"
45
40
  },
46
41
  "devDependencies": {
47
42
  "@babel/plugin-syntax-dynamic-import": "7.8.3",
@@ -51,14 +46,14 @@
51
46
  "@rollup/plugin-node-resolve": "16.0.3",
52
47
  "@rollup/plugin-typescript": "12.3.0",
53
48
  "@rollup/pluginutils": "5.3.0",
49
+ "@rollup/plugin-terser": "0.4.4",
54
50
  "rollup": "4.53.3",
55
- "rollup-plugin-terser": "7.0.2",
56
51
  "shx": "0.4.0",
57
52
  "typescript": "5.9.3"
58
53
  },
59
54
  "scripts": {
60
55
  "bundle": "pnpm types & rollup -c",
61
56
  "dist": "pnpm publish",
62
- "types": "tsc -p tsconfig.json && shx mv dist/types/index.d.mts dist/types/index.d.ts && shx mv dist/types/dom.d.mts dist/types/dom.d.ts && shx mv dist/types/string.d.mts dist/types/string.d.ts && shx mv dist/types/data.d.mts dist/types/data.d.ts && shx mv dist/types/hyphenation.d.mts dist/types/hyphenation.d.ts && shx mv dist/types/server/index.d.mts dist/types/server.d.ts"
57
+ "types": "tsc -p tsconfig.json && shx mv dist/types/index.d.mts dist/types/index.d.ts && shx mv dist/types/dom.d.mts dist/types/dom.d.ts && shx mv dist/types/string.d.mts dist/types/string.d.ts && shx mv dist/types/data.d.mts dist/types/data.d.ts && shx mv dist/types/server/index.d.mts dist/types/server.d.ts"
63
58
  }
64
59
  }