@nldd/design-system 0.8.49 → 0.8.51
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/components/actions/button/button.styles.d.ts.map +1 -1
- package/dist/components/actions/button/button.styles.js +1 -0
- package/dist/components/actions/button/button.styles.js.map +1 -1
- package/dist/components/actions/icon-button/icon-button.styles.d.ts.map +1 -1
- package/dist/components/actions/icon-button/icon-button.styles.js +1 -0
- package/dist/components/actions/icon-button/icon-button.styles.js.map +1 -1
- package/dist/components/components.js +93 -86
- package/dist/components/content/code-viewer/code-viewer.d.ts +37 -0
- package/dist/components/content/code-viewer/code-viewer.d.ts.map +1 -1
- package/dist/components/content/code-viewer/code-viewer.i18n.d.ts +8 -0
- package/dist/components/content/code-viewer/code-viewer.i18n.d.ts.map +1 -0
- package/dist/components/content/code-viewer/code-viewer.i18n.js +7 -0
- package/dist/components/content/code-viewer/code-viewer.i18n.js.map +1 -0
- package/dist/components/content/code-viewer/code-viewer.js +104 -1
- package/dist/components/content/code-viewer/code-viewer.js.map +1 -1
- package/dist/components/content/code-viewer/code-viewer.styles.d.ts.map +1 -1
- package/dist/components/content/code-viewer/code-viewer.styles.js +112 -1
- package/dist/components/content/code-viewer/code-viewer.styles.js.map +1 -1
- package/dist/components/content/code-viewer/code-viewer.template.d.ts.map +1 -1
- package/dist/components/content/code-viewer/code-viewer.template.js +50 -3
- package/dist/components/content/code-viewer/code-viewer.template.js.map +1 -1
- package/dist/components/content/icon/icon-aliases.d.ts.map +1 -1
- package/dist/components/content/icon/icon-aliases.js +17 -0
- package/dist/components/content/icon/icon-aliases.js.map +1 -1
- package/dist/components/content/icon/icon-registry.d.ts.map +1 -1
- package/dist/components/content/icon/icon-registry.js +12 -0
- package/dist/components/content/icon/icon-registry.js.map +1 -1
- package/dist/components/content/image/image.d.ts +151 -0
- package/dist/components/content/image/image.d.ts.map +1 -0
- package/dist/components/content/image/image.i18n.d.ts +8 -0
- package/dist/components/content/image/image.i18n.d.ts.map +1 -0
- package/dist/components/content/image/image.i18n.js +7 -0
- package/dist/components/content/image/image.i18n.js.map +1 -0
- package/dist/components/content/image/image.js +320 -0
- package/dist/components/content/image/image.js.map +1 -0
- package/dist/components/content/image/image.styles.d.ts +2 -0
- package/dist/components/content/image/image.styles.d.ts.map +1 -0
- package/dist/components/content/image/image.styles.js +402 -0
- package/dist/components/content/image/image.styles.js.map +1 -0
- package/dist/components/content/image/image.template.d.ts +3 -0
- package/dist/components/content/image/image.template.d.ts.map +1 -0
- package/dist/components/content/image/image.template.js +109 -0
- package/dist/components/content/image/image.template.js.map +1 -0
- package/dist/components/content/image/lqip-encoder-element.d.ts +39 -0
- package/dist/components/content/image/lqip-encoder-element.d.ts.map +1 -0
- package/dist/components/content/image/lqip-encoder-element.js +240 -0
- package/dist/components/content/image/lqip-encoder-element.js.map +1 -0
- package/dist/components/content/image/lqip-encoder.d.ts +59 -0
- package/dist/components/content/image/lqip-encoder.d.ts.map +1 -0
- package/dist/components/content/image/lqip-encoder.js +279 -0
- package/dist/components/content/image/lqip-encoder.js.map +1 -0
- package/dist/components/content/rich-text/rich-text.d.ts +9 -0
- package/dist/components/content/rich-text/rich-text.d.ts.map +1 -1
- package/dist/components/content/rich-text/rich-text.i18n.d.ts +5 -0
- package/dist/components/content/rich-text/rich-text.i18n.d.ts.map +1 -0
- package/dist/components/content/rich-text/rich-text.i18n.js +4 -0
- package/dist/components/content/rich-text/rich-text.i18n.js.map +1 -0
- package/dist/components/content/rich-text/rich-text.js +61 -0
- package/dist/components/content/rich-text/rich-text.js.map +1 -1
- package/dist/components/content/tooltip/tooltip.d.ts +10 -0
- package/dist/components/content/tooltip/tooltip.d.ts.map +1 -1
- package/dist/components/content/tooltip/tooltip.js +74 -2
- package/dist/components/content/tooltip/tooltip.js.map +1 -1
- package/dist/components/{index-BVOcPb8I.js → index-DYnIl3ts.js} +5435 -2205
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/inputs/checkbox/checkbox.styles.d.ts.map +1 -1
- package/dist/components/inputs/checkbox/checkbox.styles.js +1 -0
- package/dist/components/inputs/checkbox/checkbox.styles.js.map +1 -1
- package/dist/components/inputs/combo-box/combo-box.styles.d.ts.map +1 -1
- package/dist/components/inputs/combo-box/combo-box.styles.js +4 -1
- package/dist/components/inputs/combo-box/combo-box.styles.js.map +1 -1
- package/dist/components/inputs/dropdown/dropdown.styles.d.ts.map +1 -1
- package/dist/components/inputs/dropdown/dropdown.styles.js +1 -0
- package/dist/components/inputs/dropdown/dropdown.styles.js.map +1 -1
- package/dist/components/inputs/multi-line-text-field/multi-line-text-field.styles.d.ts.map +1 -1
- package/dist/components/inputs/multi-line-text-field/multi-line-text-field.styles.js +4 -1
- package/dist/components/inputs/multi-line-text-field/multi-line-text-field.styles.js.map +1 -1
- package/dist/components/inputs/password-field/password-field.styles.d.ts.map +1 -1
- package/dist/components/inputs/password-field/password-field.styles.js +4 -1
- package/dist/components/inputs/password-field/password-field.styles.js.map +1 -1
- package/dist/components/inputs/radio-button/radio-button.styles.d.ts.map +1 -1
- package/dist/components/inputs/radio-button/radio-button.styles.js +1 -0
- package/dist/components/inputs/radio-button/radio-button.styles.js.map +1 -1
- package/dist/components/inputs/search-field/search-field.styles.d.ts.map +1 -1
- package/dist/components/inputs/search-field/search-field.styles.js +4 -1
- package/dist/components/inputs/search-field/search-field.styles.js.map +1 -1
- package/dist/components/inputs/segmented-control/segmented-control.styles.d.ts.map +1 -1
- package/dist/components/inputs/segmented-control/segmented-control.styles.js +1 -0
- package/dist/components/inputs/segmented-control/segmented-control.styles.js.map +1 -1
- package/dist/components/inputs/stepper/stepper.styles.d.ts.map +1 -1
- package/dist/components/inputs/stepper/stepper.styles.js +1 -0
- package/dist/components/inputs/stepper/stepper.styles.js.map +1 -1
- package/dist/components/inputs/switch/switch.styles.d.ts.map +1 -1
- package/dist/components/inputs/switch/switch.styles.js +1 -0
- package/dist/components/inputs/switch/switch.styles.js.map +1 -1
- package/dist/components/inputs/text-field/text-field.styles.d.ts.map +1 -1
- package/dist/components/inputs/text-field/text-field.styles.js +4 -1
- package/dist/components/inputs/text-field/text-field.styles.js.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.d.ts +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.d.ts.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.js +22 -14
- package/dist/components/inputs/toggle-button/toggle-button.js.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.styles.d.ts.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.styles.js +16 -11
- package/dist/components/inputs/toggle-button/toggle-button.styles.js.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.template.d.ts.map +1 -1
- package/dist/components/inputs/toggle-button/toggle-button.template.js +32 -16
- package/dist/components/inputs/toggle-button/toggle-button.template.js.map +1 -1
- package/dist/components/inputs/token/token.styles.d.ts.map +1 -1
- package/dist/components/inputs/token/token.styles.js +1 -0
- package/dist/components/inputs/token/token.styles.js.map +1 -1
- package/dist/components/layout/box/box.d.ts +6 -0
- package/dist/components/layout/box/box.d.ts.map +1 -1
- package/dist/components/layout/box/box.js +12 -1
- package/dist/components/layout/box/box.js.map +1 -1
- package/dist/components/layout/box/box.styles.d.ts.map +1 -1
- package/dist/components/layout/box/box.styles.js +40 -1
- package/dist/components/layout/box/box.styles.js.map +1 -1
- package/dist/components/layout/collection/collection.d.ts +1 -0
- package/dist/components/layout/collection/collection.d.ts.map +1 -1
- package/dist/components/layout/collection/collection.i18n.d.ts +1 -0
- package/dist/components/layout/collection/collection.i18n.d.ts.map +1 -1
- package/dist/components/layout/collection/collection.i18n.js +1 -0
- package/dist/components/layout/collection/collection.i18n.js.map +1 -1
- package/dist/components/layout/collection/collection.js +14 -0
- package/dist/components/layout/collection/collection.js.map +1 -1
- package/dist/components/layout/collection/collection.styles.d.ts.map +1 -1
- package/dist/components/layout/collection/collection.styles.js +27 -0
- package/dist/components/layout/collection/collection.styles.js.map +1 -1
- package/dist/components/layout/collection/collection.template.d.ts.map +1 -1
- package/dist/components/layout/collection/collection.template.js +12 -4
- package/dist/components/layout/collection/collection.template.js.map +1 -1
- package/dist/components/lists-and-menus/list/list.d.ts +10 -3
- package/dist/components/lists-and-menus/list/list.d.ts.map +1 -1
- package/dist/components/lists-and-menus/list/list.js +8 -3
- package/dist/components/lists-and-menus/list/list.js.map +1 -1
- package/dist/components/lists-and-menus/list/list.styles.d.ts.map +1 -1
- package/dist/components/lists-and-menus/list/list.styles.js +33 -6
- package/dist/components/lists-and-menus/list/list.styles.js.map +1 -1
- package/dist/components/lists-and-menus/list-item/list-item.js +1 -1
- package/dist/components/lists-and-menus/list-item/list-item.js.map +1 -1
- package/dist/components/lists-and-menus/menu/menu.styles.d.ts.map +1 -1
- package/dist/components/lists-and-menus/menu/menu.styles.js +1 -0
- package/dist/components/lists-and-menus/menu/menu.styles.js.map +1 -1
- package/dist/components/navigation/document-tab-bar/document-tab-bar.styles.d.ts.map +1 -1
- package/dist/components/navigation/document-tab-bar/document-tab-bar.styles.js +1 -0
- package/dist/components/navigation/document-tab-bar/document-tab-bar.styles.js.map +1 -1
- package/dist/components/navigation/menu-bar/menu-bar.styles.d.ts.map +1 -1
- package/dist/components/navigation/menu-bar/menu-bar.styles.js +1 -0
- package/dist/components/navigation/menu-bar/menu-bar.styles.js.map +1 -1
- package/dist/components/navigation/menu-bar-item/menu-bar-item.styles.d.ts.map +1 -1
- package/dist/components/navigation/menu-bar-item/menu-bar-item.styles.js +1 -0
- package/dist/components/navigation/menu-bar-item/menu-bar-item.styles.js.map +1 -1
- package/dist/components/navigation/pagination/pagination.styles.d.ts.map +1 -1
- package/dist/components/navigation/pagination/pagination.styles.js +1 -0
- package/dist/components/navigation/pagination/pagination.styles.js.map +1 -1
- package/dist/components/navigation/tab-bar/tab-bar.styles.d.ts.map +1 -1
- package/dist/components/navigation/tab-bar/tab-bar.styles.js +1 -0
- package/dist/components/navigation/tab-bar/tab-bar.styles.js.map +1 -1
- package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.d.ts.map +1 -1
- package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.js +10 -1
- package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.js.map +1 -1
- package/dist/components/{prism-python-C1D7CYBc.js → prism-python-C9GXiQLy.js} +1 -1
- package/dist/components/{prism-rust-DI5vrP6V.js → prism-rust-De_U8Otq.js} +1 -1
- package/dist/components/{prism-typescript-DBgOPJ4M.js → prism-typescript-BJbUDHsa.js} +1 -1
- package/dist/components/sample-images/butterfly-1200.jpg +0 -0
- package/dist/components/sample-images/butterfly-1600.jpg +0 -0
- package/dist/components/sample-images/butterfly-480.jpg +0 -0
- package/dist/components/sample-images/butterfly-960.jpg +0 -0
- package/dist/components/status-and-feedback/badge/badge.d.ts +2 -2
- package/dist/components/status-and-feedback/badge/badge.d.ts.map +1 -1
- package/dist/components/status-and-feedback/badge/badge.js +1 -1
- package/dist/components/status-and-feedback/badge/badge.js.map +1 -1
- package/dist/components/status-and-feedback/badge/badge.styles.d.ts.map +1 -1
- package/dist/components/status-and-feedback/badge/badge.styles.js +126 -1
- package/dist/components/status-and-feedback/badge/badge.styles.js.map +1 -1
- package/dist/components/status-and-feedback/banner/banner.d.ts +89 -0
- package/dist/components/status-and-feedback/banner/banner.d.ts.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.i18n.d.ts +5 -0
- package/dist/components/status-and-feedback/banner/banner.i18n.d.ts.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.i18n.js +4 -0
- package/dist/components/status-and-feedback/banner/banner.i18n.js.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.js +206 -0
- package/dist/components/status-and-feedback/banner/banner.js.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.styles.d.ts +2 -0
- package/dist/components/status-and-feedback/banner/banner.styles.d.ts.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.styles.js +160 -0
- package/dist/components/status-and-feedback/banner/banner.styles.js.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.template.d.ts +3 -0
- package/dist/components/status-and-feedback/banner/banner.template.d.ts.map +1 -0
- package/dist/components/status-and-feedback/banner/banner.template.js +51 -0
- package/dist/components/status-and-feedback/banner/banner.template.js.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.d.ts +77 -0
- package/dist/components/status-and-feedback/progress/progress.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.i18n.d.ts +5 -0
- package/dist/components/status-and-feedback/progress/progress.i18n.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.i18n.js +4 -0
- package/dist/components/status-and-feedback/progress/progress.i18n.js.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.js +137 -0
- package/dist/components/status-and-feedback/progress/progress.js.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.styles.d.ts +2 -0
- package/dist/components/status-and-feedback/progress/progress.styles.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.styles.js +57 -0
- package/dist/components/status-and-feedback/progress/progress.styles.js.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.template.d.ts +4 -0
- package/dist/components/status-and-feedback/progress/progress.template.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress/progress.template.js +26 -0
- package/dist/components/status-and-feedback/progress/progress.template.js.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.d.ts +131 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.i18n.d.ts +8 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.i18n.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.i18n.js +7 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.i18n.js.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.js +426 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.js.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.styles.d.ts +3 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.styles.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.styles.js +400 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.styles.js.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.template.d.ts +3 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.template.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.template.js +60 -0
- package/dist/components/status-and-feedback/progress-bar/progress-bar.template.js.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.d.ts +132 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.i18n.d.ts +8 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.i18n.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.i18n.js +7 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.i18n.js.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.js +437 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.js.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.d.ts +3 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.js +245 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.js.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.template.d.ts +14 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.template.d.ts.map +1 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.template.js +115 -0
- package/dist/components/status-and-feedback/progress-circle/progress-circle.template.js.map +1 -0
- package/dist/css/settings.css +346 -18
- package/package.json +21 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storybook UI element wrapping `encodeLqip()` in a file-picker. Kept in a
|
|
3
|
+
* separate module from the pure encoder so consumers importing just the
|
|
4
|
+
* functions (e.g. a Node build pipeline) don't accidentally register the
|
|
5
|
+
* `nldd-lqip-encoder` custom element into their registry.
|
|
6
|
+
*
|
|
7
|
+
* Intentionally NOT exported from `src/components/index.ts` — this is a
|
|
8
|
+
* developer tool, not a design-system component.
|
|
9
|
+
*/
|
|
10
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
11
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
12
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
13
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
14
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
15
|
+
};
|
|
16
|
+
import { LitElement, html, css } from 'lit';
|
|
17
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
18
|
+
import { encodeLqip } from './lqip-encoder.js';
|
|
19
|
+
import './image.js';
|
|
20
|
+
/* --------------------------------------------------------------------- *
|
|
21
|
+
* i18n
|
|
22
|
+
* --------------------------------------------------------------------- */
|
|
23
|
+
export const nlddLqipEncoderTranslations = {
|
|
24
|
+
'components.lqip-encoder.upload-label': 'Kies een afbeelding',
|
|
25
|
+
'components.lqip-encoder.file-prefix-text': 'Bestand:',
|
|
26
|
+
'components.lqip-encoder.copy-instruction-text': 'Kopieer deze waarde naar je lqip attribuut:',
|
|
27
|
+
'components.lqip-encoder.preview-heading-text': 'Visuele controle:',
|
|
28
|
+
'components.lqip-encoder.preview-lqip-label': 'LQIP placeholder',
|
|
29
|
+
'components.lqip-encoder.preview-image-label': 'Originele afbeelding',
|
|
30
|
+
};
|
|
31
|
+
/* --------------------------------------------------------------------- *
|
|
32
|
+
* Element
|
|
33
|
+
* --------------------------------------------------------------------- */
|
|
34
|
+
let NLDDLqipEncoder = class NLDDLqipEncoder extends LitElement {
|
|
35
|
+
constructor() {
|
|
36
|
+
super(...arguments);
|
|
37
|
+
this.translations = {};
|
|
38
|
+
this._lqip = null;
|
|
39
|
+
this._imageUrl = '';
|
|
40
|
+
this._filename = '';
|
|
41
|
+
this._aspectRatio = '16/9';
|
|
42
|
+
this._error = '';
|
|
43
|
+
this._handleFileChange = async (e) => {
|
|
44
|
+
const input = e.target;
|
|
45
|
+
const file = input.files?.[0];
|
|
46
|
+
if (!file)
|
|
47
|
+
return;
|
|
48
|
+
this._error = '';
|
|
49
|
+
try {
|
|
50
|
+
// Free the previous object URL before allocating a new one.
|
|
51
|
+
if (this._imageUrl)
|
|
52
|
+
URL.revokeObjectURL(this._imageUrl);
|
|
53
|
+
this._imageUrl = URL.createObjectURL(file);
|
|
54
|
+
this._filename = file.name;
|
|
55
|
+
// Decode once to read dimensions for the comparison preview, then
|
|
56
|
+
// reuse the bitmap for the actual encode so the file isn't decoded
|
|
57
|
+
// twice. We pass an ImageBitmap (not the File) so encodeLqip treats
|
|
58
|
+
// it as caller-owned and won't close it — hence the try/finally
|
|
59
|
+
// here closes it ourselves, including when encodeLqip throws.
|
|
60
|
+
const bitmap = await createImageBitmap(file);
|
|
61
|
+
try {
|
|
62
|
+
this._aspectRatio = `${bitmap.width}/${bitmap.height}`;
|
|
63
|
+
this._lqip = await encodeLqip(bitmap);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
bitmap.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
this._error = err instanceof Error ? err.message : String(err);
|
|
71
|
+
this._lqip = null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
_t(key) {
|
|
76
|
+
return this.translations[key] ?? nlddLqipEncoderTranslations[key];
|
|
77
|
+
}
|
|
78
|
+
disconnectedCallback() {
|
|
79
|
+
super.disconnectedCallback();
|
|
80
|
+
if (this._imageUrl)
|
|
81
|
+
URL.revokeObjectURL(this._imageUrl);
|
|
82
|
+
}
|
|
83
|
+
render() {
|
|
84
|
+
return html `
|
|
85
|
+
<div>
|
|
86
|
+
<label class="encoder__upload-label">
|
|
87
|
+
${this._t('components.lqip-encoder.upload-label')}
|
|
88
|
+
<input class="encoder__upload-input"
|
|
89
|
+
type="file"
|
|
90
|
+
accept="image/*"
|
|
91
|
+
@change=${this._handleFileChange}
|
|
92
|
+
>
|
|
93
|
+
</label>
|
|
94
|
+
</div>
|
|
95
|
+
${this._error ? html `<div class="encoder__error" role="alert">${this._error}</div>` : ''}
|
|
96
|
+
${this._lqip !== null ? html `
|
|
97
|
+
<div class="encoder__result">
|
|
98
|
+
<div>${this._t('components.lqip-encoder.file-prefix-text')} <strong>${this._filename}</strong></div>
|
|
99
|
+
<div>${this._t('components.lqip-encoder.copy-instruction-text')}</div>
|
|
100
|
+
<div class="encoder__code">lqip="${this._lqip}"</div>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="encoder__preview">
|
|
103
|
+
<div>${this._t('components.lqip-encoder.preview-heading-text')}</div>
|
|
104
|
+
<div class="encoder__preview-pair">
|
|
105
|
+
<div class="encoder__preview-item">
|
|
106
|
+
<nldd-image
|
|
107
|
+
alt=${this._t('components.lqip-encoder.preview-lqip-label')}
|
|
108
|
+
aspect-ratio=${this._aspectRatio}
|
|
109
|
+
lqip=${this._lqip}
|
|
110
|
+
></nldd-image>
|
|
111
|
+
<span class="encoder__preview-item-label">${this._t('components.lqip-encoder.preview-lqip-label')}</span>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="encoder__preview-item">
|
|
114
|
+
<nldd-image
|
|
115
|
+
src=${this._imageUrl}
|
|
116
|
+
alt=${this._filename}
|
|
117
|
+
aspect-ratio=${this._aspectRatio}
|
|
118
|
+
lqip=${this._lqip}
|
|
119
|
+
></nldd-image>
|
|
120
|
+
<span class="encoder__preview-item-label">${this._t('components.lqip-encoder.preview-image-label')}</span>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
` : ''}
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
NLDDLqipEncoder.styles = css `
|
|
129
|
+
:host {
|
|
130
|
+
box-sizing: border-box;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
gap: var(--primitives-space-16);
|
|
134
|
+
padding: var(--primitives-space-16);
|
|
135
|
+
border: var(--primitives-border-width-thin) solid var(--semantics-content-secondary-color);
|
|
136
|
+
border-radius: var(--primitives-corner-radius-md);
|
|
137
|
+
background-color: var(--semantics-surfaces-background-color);
|
|
138
|
+
color: var(--semantics-content-color);
|
|
139
|
+
font: var(--primitives-font-body-md-regular-snug);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.encoder__upload-label {
|
|
143
|
+
display: inline-block;
|
|
144
|
+
padding: var(--primitives-space-8) var(--primitives-space-16);
|
|
145
|
+
border-radius: var(--primitives-corner-radius-md);
|
|
146
|
+
background-color: var(--semantics-buttons-accent-filled-background-color);
|
|
147
|
+
color: var(--semantics-buttons-accent-filled-content-color);
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
font: var(--primitives-font-body-md-regular-snug);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* The native <input type="file"> is visually hidden but still focusable;
|
|
153
|
+
reflect its focus state on the surrounding label so keyboard users
|
|
154
|
+
see where focus is. Same focus-ring tokens the rest of the design
|
|
155
|
+
system uses on buttons. */
|
|
156
|
+
.encoder__upload-label:focus-within {
|
|
157
|
+
outline: var(--semantics-focus-ring-outline);
|
|
158
|
+
outline-offset: var(--semantics-focus-ring-outline-offset);
|
|
159
|
+
box-shadow: var(--semantics-focus-ring-box-shadow);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.encoder__upload-input {
|
|
163
|
+
position: absolute;
|
|
164
|
+
width: 1px;
|
|
165
|
+
height: 1px;
|
|
166
|
+
overflow: hidden;
|
|
167
|
+
clip-path: inset(50%);
|
|
168
|
+
white-space: nowrap;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.encoder__result {
|
|
172
|
+
display: flex;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
gap: var(--primitives-space-8);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.encoder__code {
|
|
178
|
+
padding: var(--primitives-space-8) var(--primitives-space-12);
|
|
179
|
+
border-radius: var(--primitives-corner-radius-sm);
|
|
180
|
+
background-color: var(--semantics-surfaces-tinted-background-color);
|
|
181
|
+
font: var(--primitives-font-monospace-sm-regular-snug);
|
|
182
|
+
user-select: all;
|
|
183
|
+
word-break: break-all;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.encoder__preview {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-direction: column;
|
|
189
|
+
gap: var(--primitives-space-8);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.encoder__preview-pair {
|
|
193
|
+
display: grid;
|
|
194
|
+
grid-template-columns: 1fr 1fr;
|
|
195
|
+
gap: var(--primitives-space-16);
|
|
196
|
+
max-width: calc(var(--primitives-area-480) * 2 + var(--primitives-space-16));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.encoder__preview-item {
|
|
200
|
+
display: flex;
|
|
201
|
+
flex-direction: column;
|
|
202
|
+
gap: var(--primitives-space-4);
|
|
203
|
+
min-width: 0;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.encoder__preview-item-label {
|
|
207
|
+
font: var(--primitives-font-body-sm-regular-tight);
|
|
208
|
+
color: var(--semantics-content-secondary-color);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.encoder__error {
|
|
212
|
+
color: var(--semantics-content-color);
|
|
213
|
+
background-color: var(--components-banner-critical-background-color);
|
|
214
|
+
padding: var(--primitives-space-8) var(--primitives-space-12);
|
|
215
|
+
border-radius: var(--primitives-corner-radius-sm);
|
|
216
|
+
}
|
|
217
|
+
`;
|
|
218
|
+
__decorate([
|
|
219
|
+
property({ type: Object })
|
|
220
|
+
], NLDDLqipEncoder.prototype, "translations", void 0);
|
|
221
|
+
__decorate([
|
|
222
|
+
state()
|
|
223
|
+
], NLDDLqipEncoder.prototype, "_lqip", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
state()
|
|
226
|
+
], NLDDLqipEncoder.prototype, "_imageUrl", void 0);
|
|
227
|
+
__decorate([
|
|
228
|
+
state()
|
|
229
|
+
], NLDDLqipEncoder.prototype, "_filename", void 0);
|
|
230
|
+
__decorate([
|
|
231
|
+
state()
|
|
232
|
+
], NLDDLqipEncoder.prototype, "_aspectRatio", void 0);
|
|
233
|
+
__decorate([
|
|
234
|
+
state()
|
|
235
|
+
], NLDDLqipEncoder.prototype, "_error", void 0);
|
|
236
|
+
NLDDLqipEncoder = __decorate([
|
|
237
|
+
customElement('nldd-lqip-encoder')
|
|
238
|
+
], NLDDLqipEncoder);
|
|
239
|
+
export { NLDDLqipEncoder };
|
|
240
|
+
//# sourceMappingURL=lqip-encoder-element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lqip-encoder-element.js","sourceRoot":"","sources":["../../../../src/components/content/image/lqip-encoder-element.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encoder for the CSS-only multi-color LQIP technique used by nldd-image.
|
|
3
|
+
*
|
|
4
|
+
* Takes an image (File, ImageBitmap, or HTMLImageElement) and returns the
|
|
5
|
+
* comma-separated string the `lqip` attribute expects:
|
|
6
|
+
*
|
|
7
|
+
* "base,c1,c2,c3,c4,c5,c6"
|
|
8
|
+
*
|
|
9
|
+
* — seven 0-255 bytes, each packing an 8-bit Oklab triplet (2 bits L,
|
|
10
|
+
* 3 bits a, 3 bits b). The first byte is the base color shown behind /
|
|
11
|
+
* outside the cell gradients; the other six are per-cell colors laid out
|
|
12
|
+
* row-major in a 3×2 grid (c1 top-left, c6 bottom-right).
|
|
13
|
+
*
|
|
14
|
+
* Inspired by Lean Rada's CSS-only LQIP technique
|
|
15
|
+
* (https://leanrada.com/notes/css-only-lqip/) but intentionally
|
|
16
|
+
* incompatible with his wire format: his 20-bit packed integer carries
|
|
17
|
+
* only grayscale per cell, whereas this 56-bit CSV carries one quantized
|
|
18
|
+
* Oklab color per cell so multi-hue subjects survive the placeholder.
|
|
19
|
+
* Decoder lives in image.styles.ts and renders 7 background layers
|
|
20
|
+
* (6 radial-gradient cells + base) natively, no JS / blend modes.
|
|
21
|
+
*
|
|
22
|
+
* This module is intentionally pure — no Lit imports, no custom-element
|
|
23
|
+
* registration side effects. Consumers (Node build pipelines, Workers,
|
|
24
|
+
* tests) can import just the encoder without dragging in the Storybook
|
|
25
|
+
* UI. The file-picker UI lives in `lqip-encoder-element.ts` and registers
|
|
26
|
+
* `<nldd-lqip-encoder>` separately.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Pure LQIP encoder. Operates on a raw RGBA pixel buffer (no DOM, no Node
|
|
30
|
+
* APIs) so the same function can be called from a browser, a Node script,
|
|
31
|
+
* a Worker, or any other runtime.
|
|
32
|
+
*
|
|
33
|
+
* Returns a comma-separated string `"base,c1,c2,c3,c4,c5,c6"` where each
|
|
34
|
+
* value is an integer 0-255 packing 2 bits L + 3 bits a + 3 bits b. The
|
|
35
|
+
* `nldd-image` component parses this string into seven CSS variables; its
|
|
36
|
+
* decoder turns each one back into an `oklab()` color.
|
|
37
|
+
*
|
|
38
|
+
* Buffer layout matches ImageData.data: 4 bytes per pixel in RGBA, row-major.
|
|
39
|
+
*
|
|
40
|
+
* Algorithm:
|
|
41
|
+
* 1. Per cell: linear-light average → Oklab → findOklabBits → packed byte.
|
|
42
|
+
* 2. Base: histogram-dominant linear-RGB → Oklab → findOklabBits → packed
|
|
43
|
+
* byte. The base shows through cell-gradient transparent edges and
|
|
44
|
+
* sets the placeholder's overall mood; the cells carry the per-zone
|
|
45
|
+
* hue variation.
|
|
46
|
+
*/
|
|
47
|
+
export declare function encodePixelDataToLqip(data: Uint8ClampedArray | Uint8Array, width: number, height: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* Browser-friendly wrapper around `encodePixelDataToLqip`. Accepts a File
|
|
50
|
+
* (e.g. from <input type="file">), an HTMLImageElement, or an ImageBitmap;
|
|
51
|
+
* decodes it to pixels via the Canvas API; and forwards to the pure encoder.
|
|
52
|
+
*
|
|
53
|
+
* When passing an HTMLImageElement loaded from a different origin, set
|
|
54
|
+
* `img.crossOrigin = 'anonymous'` BEFORE assigning `src` — otherwise the
|
|
55
|
+
* underlying canvas read taints and throws a SecurityError. Files and
|
|
56
|
+
* same-origin ImageBitmaps are unaffected.
|
|
57
|
+
*/
|
|
58
|
+
export declare function encodeLqip(source: File | HTMLImageElement | ImageBitmap): Promise<string>;
|
|
59
|
+
//# sourceMappingURL=lqip-encoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lqip-encoder.d.ts","sourceRoot":"","sources":["../../../../src/components/content/image/lqip-encoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAiLH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,iBAAiB,GAAG,UAAU,EACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACZ,MAAM,CAoCR;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,IAAI,GAAG,gBAAgB,GAAG,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAuB/F"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encoder for the CSS-only multi-color LQIP technique used by nldd-image.
|
|
3
|
+
*
|
|
4
|
+
* Takes an image (File, ImageBitmap, or HTMLImageElement) and returns the
|
|
5
|
+
* comma-separated string the `lqip` attribute expects:
|
|
6
|
+
*
|
|
7
|
+
* "base,c1,c2,c3,c4,c5,c6"
|
|
8
|
+
*
|
|
9
|
+
* — seven 0-255 bytes, each packing an 8-bit Oklab triplet (2 bits L,
|
|
10
|
+
* 3 bits a, 3 bits b). The first byte is the base color shown behind /
|
|
11
|
+
* outside the cell gradients; the other six are per-cell colors laid out
|
|
12
|
+
* row-major in a 3×2 grid (c1 top-left, c6 bottom-right).
|
|
13
|
+
*
|
|
14
|
+
* Inspired by Lean Rada's CSS-only LQIP technique
|
|
15
|
+
* (https://leanrada.com/notes/css-only-lqip/) but intentionally
|
|
16
|
+
* incompatible with his wire format: his 20-bit packed integer carries
|
|
17
|
+
* only grayscale per cell, whereas this 56-bit CSV carries one quantized
|
|
18
|
+
* Oklab color per cell so multi-hue subjects survive the placeholder.
|
|
19
|
+
* Decoder lives in image.styles.ts and renders 7 background layers
|
|
20
|
+
* (6 radial-gradient cells + base) natively, no JS / blend modes.
|
|
21
|
+
*
|
|
22
|
+
* This module is intentionally pure — no Lit imports, no custom-element
|
|
23
|
+
* registration side effects. Consumers (Node build pipelines, Workers,
|
|
24
|
+
* tests) can import just the encoder without dragging in the Storybook
|
|
25
|
+
* UI. The file-picker UI lives in `lqip-encoder-element.ts` and registers
|
|
26
|
+
* `<nldd-lqip-encoder>` separately.
|
|
27
|
+
*/
|
|
28
|
+
/* --------------------------------------------------------------------- *
|
|
29
|
+
* Encoder
|
|
30
|
+
*
|
|
31
|
+
* Extends Lean Rada's CSS-only LQIP technique with per-cell color.
|
|
32
|
+
* Lean's original format packs 6 × 2-bit grayscale cells + 1 × 8-bit
|
|
33
|
+
* Oklab base color into 20 bits, then uses CSS blend modes to fake
|
|
34
|
+
* multi-color from a grayscale payload. The cells can only modulate
|
|
35
|
+
* the base's lightness — there is no actual hue variation across the
|
|
36
|
+
* placeholder, so a photo with blue sky + warm lights collapses to "a
|
|
37
|
+
* bit darker / a bit lighter than that one dominant blue".
|
|
38
|
+
*
|
|
39
|
+
* This encoder gives every cell its own 8-bit Oklab triplet (2 bits L,
|
|
40
|
+
* 3 bits a, 3 bits b) — the same resolution Lean uses for his single
|
|
41
|
+
* global base — plus an 8-bit base color for pixels outside the cell
|
|
42
|
+
* gradients. Total payload: 7 × 8 = 56 bits, serialised as a
|
|
43
|
+
* comma-separated string "base,c1,c2,c3,c4,c5,c6" (each int 0-255).
|
|
44
|
+
*
|
|
45
|
+
* Trade-off: wire-incompatible with Lean's reference tool. In exchange
|
|
46
|
+
* the CSS decoder is simpler (no blend modes), and the placeholder
|
|
47
|
+
* carries genuine multi-hue information.
|
|
48
|
+
*
|
|
49
|
+
* Key implementation choices:
|
|
50
|
+
*
|
|
51
|
+
* 1. Per cell: linear-light average → Oklab → findOklabBits. Same
|
|
52
|
+
* brute-force scaled-Euclidean quantizer used for the base, applied
|
|
53
|
+
* 6 more times.
|
|
54
|
+
*
|
|
55
|
+
* 2. Base color: histogram-dominant Oklab bucket → findOklabBits.
|
|
56
|
+
* The base shows through cell-gradient edges and outside the
|
|
57
|
+
* gradient radii, so it sets the "overall mood" of the placeholder.
|
|
58
|
+
*
|
|
59
|
+
* 3. Linear-light averaging via a 256-entry LUT keeps per-cell mean
|
|
60
|
+
* color photonically correct.
|
|
61
|
+
*
|
|
62
|
+
* Pure entry point: `encodePixelDataToLqip(data, width, height)` →
|
|
63
|
+
* string. Async `encodeLqip(source)` is a browser wrapper that gets
|
|
64
|
+
* pixels via canvas getImageData. Node users can build their own
|
|
65
|
+
* wrapper using sharp / pngjs / etc.
|
|
66
|
+
* --------------------------------------------------------------------- */
|
|
67
|
+
/** sRGB byte (0-255) → linear-light (0-1) lookup table. Precomputed because
|
|
68
|
+
* large images run this hundreds of thousands of times. */
|
|
69
|
+
const SRGB_TO_LINEAR_LUT = new Float32Array(256);
|
|
70
|
+
for (let i = 0; i < 256; i++) {
|
|
71
|
+
const n = i / 255;
|
|
72
|
+
SRGB_TO_LINEAR_LUT[i] = n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|
|
73
|
+
}
|
|
74
|
+
/** Linear-light RGB triplet (0-1 per channel) → Oklab. Same constants as the
|
|
75
|
+
* spec, but skips the sRGB→linear step since the input is already linear. */
|
|
76
|
+
function linearRgbToOklab(rl, gl, bl) {
|
|
77
|
+
const l = 0.4122214708 * rl + 0.5363325363 * gl + 0.0514459929 * bl;
|
|
78
|
+
const m = 0.2119034982 * rl + 0.6806995451 * gl + 0.1073969566 * bl;
|
|
79
|
+
const s = 0.0883024619 * rl + 0.2817188376 * gl + 0.6299787005 * bl;
|
|
80
|
+
const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
|
|
81
|
+
return {
|
|
82
|
+
L: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,
|
|
83
|
+
a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
|
|
84
|
+
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function clamp(v, lo, hi) {
|
|
88
|
+
return Math.max(lo, Math.min(hi, v));
|
|
89
|
+
}
|
|
90
|
+
/** Decode an 8-bit color triplet (2 + 3 + 3 bits) back to the Oklab L/a/b
|
|
91
|
+
* values the CSS decoder will reconstruct. Used by the brute-force quantizer
|
|
92
|
+
* to evaluate candidates and by the cell encoder for the cell's own bits.
|
|
93
|
+
*
|
|
94
|
+
* Per-byte L/a/b decoding matches Lean Rada's reference implementation
|
|
95
|
+
* exactly — the same formulas produce the same colors. The overall wire
|
|
96
|
+
* format is NOT interchangeable though: Lean packs 6 grayscale cells + a
|
|
97
|
+
* single base color into one 20-bit integer; we ship 7 independent bytes
|
|
98
|
+
* in a CSV string. So an individual byte can be decoded with either
|
|
99
|
+
* decoder, but the LQIP attribute strings can't be swapped between tools. */
|
|
100
|
+
function bitsToLab(ll, aaa, bbb) {
|
|
101
|
+
return {
|
|
102
|
+
L: (ll / 0b11) * 0.6 + 0.2,
|
|
103
|
+
a: (aaa / 0b1000) * 0.7 - 0.35,
|
|
104
|
+
b: ((bbb + 1) / 0b1000) * 0.7 - 0.35,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Find the 2 + 3 + 3 bit Oklab triplet whose decoded color is visually
|
|
108
|
+
* closest to the target. Brute-forces all 256 combinations because the
|
|
109
|
+
* search space is tiny and round-to-nearest under-performs near the
|
|
110
|
+
* quantization boundaries.
|
|
111
|
+
*
|
|
112
|
+
* Distance is *scaled* Euclidean: a/b are divided by sqrt(chroma) before
|
|
113
|
+
* comparison so that vivid targets aren't crushed in favour of nearby
|
|
114
|
+
* lower-chroma buckets that happen to have a smaller raw delta. Matches
|
|
115
|
+
* Lean's reference implementation. */
|
|
116
|
+
function findOklabBits(targetL, targetA, targetB) {
|
|
117
|
+
const targetChroma = Math.hypot(targetA, targetB);
|
|
118
|
+
const scaledTargetA = targetA / (1e-6 + Math.pow(targetChroma, 0.5));
|
|
119
|
+
const scaledTargetB = targetB / (1e-6 + Math.pow(targetChroma, 0.5));
|
|
120
|
+
let bestBits = [0, 0, 0];
|
|
121
|
+
let bestDifference = Infinity;
|
|
122
|
+
for (let lli = 0; lli <= 0b11; lli++) {
|
|
123
|
+
for (let aaai = 0; aaai <= 0b111; aaai++) {
|
|
124
|
+
for (let bbbi = 0; bbbi <= 0b111; bbbi++) {
|
|
125
|
+
const { L, a, b } = bitsToLab(lli, aaai, bbbi);
|
|
126
|
+
const chroma = Math.hypot(a, b);
|
|
127
|
+
const scaledA = a / (1e-6 + Math.pow(chroma, 0.5));
|
|
128
|
+
const scaledB = b / (1e-6 + Math.pow(chroma, 0.5));
|
|
129
|
+
const difference = Math.hypot(L - targetL, scaledA - scaledTargetA, scaledB - scaledTargetB);
|
|
130
|
+
if (difference < bestDifference) {
|
|
131
|
+
bestDifference = difference;
|
|
132
|
+
bestBits = [lli, aaai, bbbi];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { ll: bestBits[0], aaa: bestBits[1], bbb: bestBits[2] };
|
|
138
|
+
}
|
|
139
|
+
/** Find the dominant color in the image by histogram bucketing in Oklab
|
|
140
|
+
* space. Quantises every pixel into an 8×8×8 grid (512 buckets), then
|
|
141
|
+
* returns the linear-RGB mean of the most-populated bucket.
|
|
142
|
+
*
|
|
143
|
+
* Using "dominant" instead of "average" is what makes the placeholder pick
|
|
144
|
+
* up the subject's color (sky blue, foliage green, the pier's amber
|
|
145
|
+
* lights) rather than collapsing foreground and background into a muddy
|
|
146
|
+
* midpoint. The bucket grid resolution is intentionally coarse so that
|
|
147
|
+
* perceptually-similar tones share a bucket — fine quantization would
|
|
148
|
+
* scatter near-identical pixels across many tiny buckets and lose the
|
|
149
|
+
* dominance signal we want. */
|
|
150
|
+
function findDominantColor(data, width, height) {
|
|
151
|
+
const L_BUCKETS = 8, A_BUCKETS = 8, B_BUCKETS = 8;
|
|
152
|
+
const TOTAL = L_BUCKETS * A_BUCKETS * B_BUCKETS;
|
|
153
|
+
const counts = new Uint32Array(TOTAL);
|
|
154
|
+
const sumR = new Float64Array(TOTAL);
|
|
155
|
+
const sumG = new Float64Array(TOTAL);
|
|
156
|
+
const sumB = new Float64Array(TOTAL);
|
|
157
|
+
const pixelCount = width * height;
|
|
158
|
+
for (let p = 0; p < pixelCount; p++) {
|
|
159
|
+
const i = p * 4;
|
|
160
|
+
const rl = SRGB_TO_LINEAR_LUT[data[i]];
|
|
161
|
+
const gl = SRGB_TO_LINEAR_LUT[data[i + 1]];
|
|
162
|
+
const bl = SRGB_TO_LINEAR_LUT[data[i + 2]];
|
|
163
|
+
const { L, a, b } = linearRgbToOklab(rl, gl, bl);
|
|
164
|
+
// L is roughly [0, 1]; a/b for sRGB stay roughly within [-0.4, 0.4].
|
|
165
|
+
const li = clamp(Math.floor(L * L_BUCKETS), 0, L_BUCKETS - 1);
|
|
166
|
+
const ai = clamp(Math.floor((a + 0.4) / 0.8 * A_BUCKETS), 0, A_BUCKETS - 1);
|
|
167
|
+
const bi = clamp(Math.floor((b + 0.4) / 0.8 * B_BUCKETS), 0, B_BUCKETS - 1);
|
|
168
|
+
const idx = li * A_BUCKETS * B_BUCKETS + ai * B_BUCKETS + bi;
|
|
169
|
+
counts[idx]++;
|
|
170
|
+
sumR[idx] += rl;
|
|
171
|
+
sumG[idx] += gl;
|
|
172
|
+
sumB[idx] += bl;
|
|
173
|
+
}
|
|
174
|
+
let bestIdx = 0, bestCount = 0;
|
|
175
|
+
for (let i = 0; i < TOTAL; i++) {
|
|
176
|
+
if (counts[i] > bestCount) {
|
|
177
|
+
bestCount = counts[i];
|
|
178
|
+
bestIdx = i;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const n = counts[bestIdx];
|
|
182
|
+
return { rl: sumR[bestIdx] / n, gl: sumG[bestIdx] / n, bl: sumB[bestIdx] / n };
|
|
183
|
+
}
|
|
184
|
+
/** Pack a quantized Oklab triplet into a single byte: 2 bits L (high), 3 bits
|
|
185
|
+
* a, 3 bits b (low). Matches the format Lean uses for his global base
|
|
186
|
+
* color, so the CSS decoder for each cell uses the same math as Lean's
|
|
187
|
+
* base decoder — just one byte at a time, seven times. */
|
|
188
|
+
function packLab(ll, aaa, bbb) {
|
|
189
|
+
return (ll << 6) | (aaa << 3) | bbb;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Pure LQIP encoder. Operates on a raw RGBA pixel buffer (no DOM, no Node
|
|
193
|
+
* APIs) so the same function can be called from a browser, a Node script,
|
|
194
|
+
* a Worker, or any other runtime.
|
|
195
|
+
*
|
|
196
|
+
* Returns a comma-separated string `"base,c1,c2,c3,c4,c5,c6"` where each
|
|
197
|
+
* value is an integer 0-255 packing 2 bits L + 3 bits a + 3 bits b. The
|
|
198
|
+
* `nldd-image` component parses this string into seven CSS variables; its
|
|
199
|
+
* decoder turns each one back into an `oklab()` color.
|
|
200
|
+
*
|
|
201
|
+
* Buffer layout matches ImageData.data: 4 bytes per pixel in RGBA, row-major.
|
|
202
|
+
*
|
|
203
|
+
* Algorithm:
|
|
204
|
+
* 1. Per cell: linear-light average → Oklab → findOklabBits → packed byte.
|
|
205
|
+
* 2. Base: histogram-dominant linear-RGB → Oklab → findOklabBits → packed
|
|
206
|
+
* byte. The base shows through cell-gradient transparent edges and
|
|
207
|
+
* sets the placeholder's overall mood; the cells carry the per-zone
|
|
208
|
+
* hue variation.
|
|
209
|
+
*/
|
|
210
|
+
export function encodePixelDataToLqip(data, width, height) {
|
|
211
|
+
if (width < 3 || height < 2) {
|
|
212
|
+
throw new Error(`encodePixelDataToLqip: image must be at least 3×2, got ${width}×${height}`);
|
|
213
|
+
}
|
|
214
|
+
// Per-cell quantized Oklab bytes.
|
|
215
|
+
const cellBytes = [];
|
|
216
|
+
for (let cellRow = 0; cellRow < 2; cellRow++) {
|
|
217
|
+
const yStart = Math.floor(cellRow * height / 2);
|
|
218
|
+
const yEnd = Math.floor((cellRow + 1) * height / 2);
|
|
219
|
+
for (let cellCol = 0; cellCol < 3; cellCol++) {
|
|
220
|
+
const xStart = Math.floor(cellCol * width / 3);
|
|
221
|
+
const xEnd = Math.floor((cellCol + 1) * width / 3);
|
|
222
|
+
let cellR = 0, cellG = 0, cellB = 0, cellCount = 0;
|
|
223
|
+
for (let y = yStart; y < yEnd; y++) {
|
|
224
|
+
for (let x = xStart; x < xEnd; x++) {
|
|
225
|
+
const i = (y * width + x) * 4;
|
|
226
|
+
cellR += SRGB_TO_LINEAR_LUT[data[i]];
|
|
227
|
+
cellG += SRGB_TO_LINEAR_LUT[data[i + 1]];
|
|
228
|
+
cellB += SRGB_TO_LINEAR_LUT[data[i + 2]];
|
|
229
|
+
cellCount++;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const { L, a, b } = linearRgbToOklab(cellR / cellCount, cellG / cellCount, cellB / cellCount);
|
|
233
|
+
const { ll, aaa, bbb } = findOklabBits(L, a, b);
|
|
234
|
+
cellBytes.push(packLab(ll, aaa, bbb));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Base: dominant Oklab bucket → quantized byte.
|
|
238
|
+
const dom = findDominantColor(data, width, height);
|
|
239
|
+
const domLab = linearRgbToOklab(dom.rl, dom.gl, dom.bl);
|
|
240
|
+
const base = findOklabBits(domLab.L, domLab.a, domLab.b);
|
|
241
|
+
const baseByte = packLab(base.ll, base.aaa, base.bbb);
|
|
242
|
+
return [baseByte, ...cellBytes].join(',');
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Browser-friendly wrapper around `encodePixelDataToLqip`. Accepts a File
|
|
246
|
+
* (e.g. from <input type="file">), an HTMLImageElement, or an ImageBitmap;
|
|
247
|
+
* decodes it to pixels via the Canvas API; and forwards to the pure encoder.
|
|
248
|
+
*
|
|
249
|
+
* When passing an HTMLImageElement loaded from a different origin, set
|
|
250
|
+
* `img.crossOrigin = 'anonymous'` BEFORE assigning `src` — otherwise the
|
|
251
|
+
* underlying canvas read taints and throws a SecurityError. Files and
|
|
252
|
+
* same-origin ImageBitmaps are unaffected.
|
|
253
|
+
*/
|
|
254
|
+
export async function encodeLqip(source) {
|
|
255
|
+
// When we create the bitmap from a File / HTMLImageElement we own its
|
|
256
|
+
// lifecycle and must close it. When the caller passes an ImageBitmap they
|
|
257
|
+
// own it (the Storybook encoder element, for one, reuses + closes its own),
|
|
258
|
+
// so we leave that case untouched.
|
|
259
|
+
const ownsBitmap = source instanceof File || source instanceof HTMLImageElement;
|
|
260
|
+
const bitmap = ownsBitmap ? await createImageBitmap(source) : source;
|
|
261
|
+
try {
|
|
262
|
+
const canvas = document.createElement('canvas');
|
|
263
|
+
canvas.width = bitmap.width;
|
|
264
|
+
canvas.height = bitmap.height;
|
|
265
|
+
const ctx = canvas.getContext('2d');
|
|
266
|
+
if (!ctx)
|
|
267
|
+
throw new Error('encodeLqip: could not acquire a 2D canvas context');
|
|
268
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
269
|
+
const { data } = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
|
|
270
|
+
return encodePixelDataToLqip(data, bitmap.width, bitmap.height);
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
// Close only the bitmap we allocated; never the caller's. Runs on the
|
|
274
|
+
// success path and on a thrown SecurityError / context failure.
|
|
275
|
+
if (ownsBitmap)
|
|
276
|
+
bitmap.close();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=lqip-encoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lqip-encoder.js","sourceRoot":"","sources":["../../../../src/components/content/image/lqip-encoder.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,13 +9,22 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @attr {string} spacing - Spacing between elements: 'flat' | 'tight' | 'snug' (default) | 'loose'
|
|
11
11
|
* @attr {boolean} centered - Centers the main column inside the container; without it, content is left-aligned
|
|
12
|
+
* @attr {object} translations - Override translation keys; unset keys fall back to Dutch
|
|
12
13
|
*/
|
|
13
14
|
import { LitElement } from 'lit';
|
|
15
|
+
import type { NLDDRichTextTranslations } from './rich-text.i18n.js';
|
|
14
16
|
type Spacing = 'flat' | 'tight' | 'snug' | 'loose';
|
|
15
17
|
export declare class NLDDRichText extends LitElement {
|
|
16
18
|
spacing: Spacing;
|
|
17
19
|
centered: boolean;
|
|
20
|
+
translations: Partial<NLDDRichTextTranslations>;
|
|
21
|
+
_t(key: keyof NLDDRichTextTranslations): string;
|
|
22
|
+
private _mutationObserver?;
|
|
23
|
+
private _resizeObserver?;
|
|
18
24
|
createRenderRoot(): this;
|
|
25
|
+
connectedCallback(): void;
|
|
26
|
+
disconnectedCallback(): void;
|
|
27
|
+
private _syncTables;
|
|
19
28
|
}
|
|
20
29
|
declare global {
|
|
21
30
|
interface HTMLElementTagNameMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../../../../src/components/content/rich-text/rich-text.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../../../../src/components/content/rich-text/rich-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAGjC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAInD,qBACa,YAAa,SAAQ,UAAU;IAE3C,OAAO,EAAE,OAAO,CAAU;IAG1B,QAAQ,UAAS;IAGjB,YAAY,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAM;IAE9C,EAAE,CAAC,GAAG,EAAE,MAAM,wBAAwB,GAAG,MAAM;IAItD,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAC7C,OAAO,CAAC,eAAe,CAAC,CAAiB;IAEhC,gBAAgB;IAIhB,iBAAiB,IAAI,IAAI;IAezB,oBAAoB,IAAI,IAAI;IAQrC,OAAO,CAAC,WAAW;CA+BnB;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,YAAY,CAAC;KAC/B;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text.i18n.d.ts","sourceRoot":"","sources":["../../../../src/components/content/rich-text/rich-text.i18n.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB;;CAEpC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,OAAO,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text.i18n.js","sourceRoot":"","sources":["../../../../src/components/content/rich-text/rich-text.i18n.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACvC,yCAAyC,EAAE,kBAAkB;CAC7D,CAAC"}
|