@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,402 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const imageStyles = css `
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/* # Host */
|
|
6
|
+
|
|
7
|
+
:host {
|
|
8
|
+
--_corner-radius: var(--components-image-corner-radius);
|
|
9
|
+
--_background-color: var(--components-image-background-color);
|
|
10
|
+
--_caption-gap: var(--components-image-caption-gap);
|
|
11
|
+
--_caption-color: var(--components-image-caption-color);
|
|
12
|
+
--_caption-font: var(--components-image-caption-font);
|
|
13
|
+
--_credit-color: var(--components-image-credit-color);
|
|
14
|
+
--_credit-font: var(--components-image-credit-font);
|
|
15
|
+
--_error-text-color: var(--components-image-error-text-color);
|
|
16
|
+
--_error-font: var(--components-image-error-font);
|
|
17
|
+
--_error-padding: var(--primitives-space-8);
|
|
18
|
+
--_error-card-padding-block: var(--primitives-space-12);
|
|
19
|
+
--_error-card-padding-inline: var(--primitives-space-16);
|
|
20
|
+
--_error-card-gap: var(--primitives-space-2);
|
|
21
|
+
--_error-card-corner-radius: var(--primitives-corner-radius-md);
|
|
22
|
+
--_caption-row-gap: var(--primitives-space-8);
|
|
23
|
+
--_object-fit: cover;
|
|
24
|
+
--_object-position: center;
|
|
25
|
+
--_max-width: 100%;
|
|
26
|
+
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
display: block;
|
|
29
|
+
max-width: var(--_max-width);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:host([hidden]) {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/* ## Object-fit variants
|
|
38
|
+
Driven by the reflected attribute so we can also style slotted img/picture
|
|
39
|
+
via ::slotted() with the same CSS var. */
|
|
40
|
+
|
|
41
|
+
:host([object-fit="contain"]) { --_object-fit: contain; }
|
|
42
|
+
:host([object-fit="fill"]) { --_object-fit: fill; }
|
|
43
|
+
:host([object-fit="scale-down"]) { --_object-fit: scale-down; }
|
|
44
|
+
:host([object-fit="none"]) { --_object-fit: none; }
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
/* ## Object-position variants */
|
|
48
|
+
|
|
49
|
+
:host([object-position="top"]) { --_object-position: top; }
|
|
50
|
+
:host([object-position="bottom"]) { --_object-position: bottom; }
|
|
51
|
+
:host([object-position="left"]) { --_object-position: left; }
|
|
52
|
+
:host([object-position="right"]) { --_object-position: right; }
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/* ## Shape variants
|
|
56
|
+
Rounded is the default (already set via the --_corner-radius in :host
|
|
57
|
+
pointing at the design-system token). Square overrides to 0, circle to
|
|
58
|
+
50% for avatar-style use (combine with aspect-ratio 1/1 for a true circle). */
|
|
59
|
+
|
|
60
|
+
:host([shape="square"]) { --_corner-radius: 0; }
|
|
61
|
+
:host([shape="circle"]) { --_corner-radius: 50%; }
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/* # Figure
|
|
65
|
+
Only rendered when caption or credit is present. Acts as the layout
|
|
66
|
+
wrapper holding image + figcaption with a small gap. */
|
|
67
|
+
|
|
68
|
+
.image__figure {
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
margin: 0;
|
|
73
|
+
gap: var(--_caption-gap);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/* # Media wrapper
|
|
78
|
+
The box that constrains the image. aspect-ratio is set as an inline style
|
|
79
|
+
from the component when provided, so we don't need a CSS var. The
|
|
80
|
+
background acts as a placeholder while the image loads. */
|
|
81
|
+
|
|
82
|
+
.image__media {
|
|
83
|
+
display: block;
|
|
84
|
+
position: relative;
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
background-color: var(--_background-color);
|
|
87
|
+
max-width: 100%;
|
|
88
|
+
border-radius: var(--_corner-radius);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/* # Image element
|
|
93
|
+
Both the internal img and any slotted img get the same styling so the
|
|
94
|
+
wrapper behaves identically in both cases. ::slotted() can't reach
|
|
95
|
+
descendants, so a slotted <picture> works for source switching but
|
|
96
|
+
consumers must put any extra styling on the inner <img> themselves —
|
|
97
|
+
object-fit / object-position aren't inheritable into <picture>'s child
|
|
98
|
+
<img>, so we don't bother targeting <picture> here. */
|
|
99
|
+
|
|
100
|
+
.image__img,
|
|
101
|
+
::slotted(img) {
|
|
102
|
+
display: block;
|
|
103
|
+
width: 100%;
|
|
104
|
+
height: 100%;
|
|
105
|
+
max-width: 100%;
|
|
106
|
+
object-fit: var(--_object-fit);
|
|
107
|
+
object-position: var(--_object-position);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* <picture> is a wrapper that picks the right <source>; layout properties
|
|
111
|
+
like width/height DO apply to it directly even though object-fit doesn't.
|
|
112
|
+
Size it so the slotted picture fills the media wrapper, then let the
|
|
113
|
+
consumer style the inner <img> for fit/position. */
|
|
114
|
+
::slotted(picture) {
|
|
115
|
+
display: block;
|
|
116
|
+
width: 100%;
|
|
117
|
+
height: 100%;
|
|
118
|
+
max-width: 100%;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
/* # LQIP placeholder
|
|
123
|
+
Per-cell Oklab LQIP — extends Lean Rada's CSS-only LQIP technique
|
|
124
|
+
(https://leanrada.com/notes/css-only-lqip/) with one quantized
|
|
125
|
+
color per cell instead of grayscale-only cells. The component
|
|
126
|
+
parses lqip="base,c1,c2,c3,c4,c5,c6" and forwards each byte as an
|
|
127
|
+
inline --context-lqip-* variable (crosses the shadow boundary;
|
|
128
|
+
hence the --context-* prefix, not --_).
|
|
129
|
+
Each byte packs 2 bits L + 3 bits a + 3 bits b — the same format
|
|
130
|
+
Lean uses for his single base color, applied 7 times. The base
|
|
131
|
+
shows through cell-gradient transparent edges; the six cells carry
|
|
132
|
+
the per-zone hue. No blend modes are needed because every cell
|
|
133
|
+
already has its own real color — overlap zones blend naturally
|
|
134
|
+
through the smooth alpha falloff (stop10/20/30/40).
|
|
135
|
+
Browser support: depends on CSS mod() (Chrome 113+, Safari 15.4+,
|
|
136
|
+
Firefox 118+, May 2023 baseline), CSS round(down, ...) (Chrome 111+,
|
|
137
|
+
Safari 15.4+, Firefox 118+), oklab() (Chrome 111+, Safari 15.4+,
|
|
138
|
+
Firefox 113+), and the relative-color syntax rgb(from … r g b / α)
|
|
139
|
+
used in the gradient stops (Chrome 119+, Safari 16.4+, Firefox 128+,
|
|
140
|
+
mid-2024 baseline). The @supports gate probes all three of the
|
|
141
|
+
youngest-per-engine capabilities — without the relative-color probe,
|
|
142
|
+
Firefox 113-127 would pass the gate but render transparent/black
|
|
143
|
+
stops because rgb(from …) wouldn't parse. Older engines drop the
|
|
144
|
+
LQIP gradient entirely and fall through to the neutral
|
|
145
|
+
--_background-color set on .image__media. Degraded but harmless:
|
|
146
|
+
the placeholder is a "nice to have", not a load-bearing element. */
|
|
147
|
+
|
|
148
|
+
@supports (left: mod(1px, 1px)) and (background: oklab(0 0 0)) and (color: rgb(from red r g b)) {
|
|
149
|
+
|
|
150
|
+
.image__media--lqip {
|
|
151
|
+
--_lqip-base-ll: mod(round(down, var(--context-lqip-base) / 64), 4);
|
|
152
|
+
--_lqip-base-aaa: mod(round(down, var(--context-lqip-base) / 8), 8);
|
|
153
|
+
--_lqip-base-bbb: mod(var(--context-lqip-base), 8);
|
|
154
|
+
--_lqip-c1-ll: mod(round(down, var(--context-lqip-c1) / 64), 4);
|
|
155
|
+
--_lqip-c1-aaa: mod(round(down, var(--context-lqip-c1) / 8), 8);
|
|
156
|
+
--_lqip-c1-bbb: mod(var(--context-lqip-c1), 8);
|
|
157
|
+
--_lqip-c2-ll: mod(round(down, var(--context-lqip-c2) / 64), 4);
|
|
158
|
+
--_lqip-c2-aaa: mod(round(down, var(--context-lqip-c2) / 8), 8);
|
|
159
|
+
--_lqip-c2-bbb: mod(var(--context-lqip-c2), 8);
|
|
160
|
+
--_lqip-c3-ll: mod(round(down, var(--context-lqip-c3) / 64), 4);
|
|
161
|
+
--_lqip-c3-aaa: mod(round(down, var(--context-lqip-c3) / 8), 8);
|
|
162
|
+
--_lqip-c3-bbb: mod(var(--context-lqip-c3), 8);
|
|
163
|
+
--_lqip-c4-ll: mod(round(down, var(--context-lqip-c4) / 64), 4);
|
|
164
|
+
--_lqip-c4-aaa: mod(round(down, var(--context-lqip-c4) / 8), 8);
|
|
165
|
+
--_lqip-c4-bbb: mod(var(--context-lqip-c4), 8);
|
|
166
|
+
--_lqip-c5-ll: mod(round(down, var(--context-lqip-c5) / 64), 4);
|
|
167
|
+
--_lqip-c5-aaa: mod(round(down, var(--context-lqip-c5) / 8), 8);
|
|
168
|
+
--_lqip-c5-bbb: mod(var(--context-lqip-c5), 8);
|
|
169
|
+
--_lqip-c6-ll: mod(round(down, var(--context-lqip-c6) / 64), 4);
|
|
170
|
+
--_lqip-c6-aaa: mod(round(down, var(--context-lqip-c6) / 8), 8);
|
|
171
|
+
--_lqip-c6-bbb: mod(var(--context-lqip-c6), 8);
|
|
172
|
+
|
|
173
|
+
--_lqip-base-clr: oklab(
|
|
174
|
+
calc(var(--_lqip-base-ll) / 3 * 0.6 + 0.2)
|
|
175
|
+
calc(var(--_lqip-base-aaa) / 8 * 0.7 - 0.35)
|
|
176
|
+
calc((var(--_lqip-base-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
177
|
+
);
|
|
178
|
+
--_lqip-c1-clr: oklab(
|
|
179
|
+
calc(var(--_lqip-c1-ll) / 3 * 0.6 + 0.2)
|
|
180
|
+
calc(var(--_lqip-c1-aaa) / 8 * 0.7 - 0.35)
|
|
181
|
+
calc((var(--_lqip-c1-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
182
|
+
);
|
|
183
|
+
--_lqip-c2-clr: oklab(
|
|
184
|
+
calc(var(--_lqip-c2-ll) / 3 * 0.6 + 0.2)
|
|
185
|
+
calc(var(--_lqip-c2-aaa) / 8 * 0.7 - 0.35)
|
|
186
|
+
calc((var(--_lqip-c2-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
187
|
+
);
|
|
188
|
+
--_lqip-c3-clr: oklab(
|
|
189
|
+
calc(var(--_lqip-c3-ll) / 3 * 0.6 + 0.2)
|
|
190
|
+
calc(var(--_lqip-c3-aaa) / 8 * 0.7 - 0.35)
|
|
191
|
+
calc((var(--_lqip-c3-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
192
|
+
);
|
|
193
|
+
--_lqip-c4-clr: oklab(
|
|
194
|
+
calc(var(--_lqip-c4-ll) / 3 * 0.6 + 0.2)
|
|
195
|
+
calc(var(--_lqip-c4-aaa) / 8 * 0.7 - 0.35)
|
|
196
|
+
calc((var(--_lqip-c4-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
197
|
+
);
|
|
198
|
+
--_lqip-c5-clr: oklab(
|
|
199
|
+
calc(var(--_lqip-c5-ll) / 3 * 0.6 + 0.2)
|
|
200
|
+
calc(var(--_lqip-c5-aaa) / 8 * 0.7 - 0.35)
|
|
201
|
+
calc((var(--_lqip-c5-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
202
|
+
);
|
|
203
|
+
--_lqip-c6-clr: oklab(
|
|
204
|
+
calc(var(--_lqip-c6-ll) / 3 * 0.6 + 0.2)
|
|
205
|
+
calc(var(--_lqip-c6-aaa) / 8 * 0.7 - 0.35)
|
|
206
|
+
calc((var(--_lqip-c6-bbb) + 1) / 8 * 0.7 - 0.35)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
--_lqip-stop10: 2%;
|
|
210
|
+
--_lqip-stop20: 8%;
|
|
211
|
+
--_lqip-stop30: 18%;
|
|
212
|
+
--_lqip-stop40: 32%;
|
|
213
|
+
|
|
214
|
+
background-color: transparent;
|
|
215
|
+
background-image:
|
|
216
|
+
radial-gradient(50% 75% at 16.67% 25%,
|
|
217
|
+
var(--_lqip-c1-clr),
|
|
218
|
+
rgb(from var(--_lqip-c1-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
219
|
+
rgb(from var(--_lqip-c1-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
220
|
+
rgb(from var(--_lqip-c1-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
221
|
+
rgb(from var(--_lqip-c1-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
222
|
+
rgb(from var(--_lqip-c1-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
223
|
+
rgb(from var(--_lqip-c1-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
224
|
+
rgb(from var(--_lqip-c1-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
225
|
+
rgb(from var(--_lqip-c1-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
226
|
+
transparent),
|
|
227
|
+
radial-gradient(50% 75% at 50% 25%,
|
|
228
|
+
var(--_lqip-c2-clr),
|
|
229
|
+
rgb(from var(--_lqip-c2-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
230
|
+
rgb(from var(--_lqip-c2-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
231
|
+
rgb(from var(--_lqip-c2-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
232
|
+
rgb(from var(--_lqip-c2-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
233
|
+
rgb(from var(--_lqip-c2-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
234
|
+
rgb(from var(--_lqip-c2-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
235
|
+
rgb(from var(--_lqip-c2-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
236
|
+
rgb(from var(--_lqip-c2-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
237
|
+
transparent),
|
|
238
|
+
radial-gradient(50% 75% at 83.33% 25%,
|
|
239
|
+
var(--_lqip-c3-clr),
|
|
240
|
+
rgb(from var(--_lqip-c3-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
241
|
+
rgb(from var(--_lqip-c3-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
242
|
+
rgb(from var(--_lqip-c3-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
243
|
+
rgb(from var(--_lqip-c3-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
244
|
+
rgb(from var(--_lqip-c3-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
245
|
+
rgb(from var(--_lqip-c3-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
246
|
+
rgb(from var(--_lqip-c3-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
247
|
+
rgb(from var(--_lqip-c3-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
248
|
+
transparent),
|
|
249
|
+
radial-gradient(50% 75% at 16.67% 75%,
|
|
250
|
+
var(--_lqip-c4-clr),
|
|
251
|
+
rgb(from var(--_lqip-c4-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
252
|
+
rgb(from var(--_lqip-c4-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
253
|
+
rgb(from var(--_lqip-c4-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
254
|
+
rgb(from var(--_lqip-c4-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
255
|
+
rgb(from var(--_lqip-c4-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
256
|
+
rgb(from var(--_lqip-c4-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
257
|
+
rgb(from var(--_lqip-c4-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
258
|
+
rgb(from var(--_lqip-c4-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
259
|
+
transparent),
|
|
260
|
+
radial-gradient(50% 75% at 50% 75%,
|
|
261
|
+
var(--_lqip-c5-clr),
|
|
262
|
+
rgb(from var(--_lqip-c5-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
263
|
+
rgb(from var(--_lqip-c5-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
264
|
+
rgb(from var(--_lqip-c5-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
265
|
+
rgb(from var(--_lqip-c5-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
266
|
+
rgb(from var(--_lqip-c5-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
267
|
+
rgb(from var(--_lqip-c5-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
268
|
+
rgb(from var(--_lqip-c5-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
269
|
+
rgb(from var(--_lqip-c5-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
270
|
+
transparent),
|
|
271
|
+
radial-gradient(50% 75% at 83.33% 75%,
|
|
272
|
+
var(--_lqip-c6-clr),
|
|
273
|
+
rgb(from var(--_lqip-c6-clr) r g b / calc(100% - var(--_lqip-stop10))) 10%,
|
|
274
|
+
rgb(from var(--_lqip-c6-clr) r g b / calc(100% - var(--_lqip-stop20))) 20%,
|
|
275
|
+
rgb(from var(--_lqip-c6-clr) r g b / calc(100% - var(--_lqip-stop30))) 30%,
|
|
276
|
+
rgb(from var(--_lqip-c6-clr) r g b / calc(100% - var(--_lqip-stop40))) 40%,
|
|
277
|
+
rgb(from var(--_lqip-c6-clr) r g b / var(--_lqip-stop40)) 60%,
|
|
278
|
+
rgb(from var(--_lqip-c6-clr) r g b / var(--_lqip-stop30)) 70%,
|
|
279
|
+
rgb(from var(--_lqip-c6-clr) r g b / var(--_lqip-stop20)) 80%,
|
|
280
|
+
rgb(from var(--_lqip-c6-clr) r g b / var(--_lqip-stop10)) 90%,
|
|
281
|
+
transparent),
|
|
282
|
+
linear-gradient(0deg, var(--_lqip-base-clr), var(--_lqip-base-clr));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
} /* end @supports for LQIP gradient */
|
|
286
|
+
|
|
287
|
+
/* Fade-in transitions live OUTSIDE the @supports — they only run when the
|
|
288
|
+
--lqip class is present and the engine renders the gradient anyway. */
|
|
289
|
+
|
|
290
|
+
.image__media--lqip .image__img {
|
|
291
|
+
opacity: 0;
|
|
292
|
+
transition: opacity 300ms ease-out;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.image__media--lqip .image__img--loaded {
|
|
296
|
+
opacity: 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
/* # Errored image
|
|
301
|
+
Hide the broken <img> entirely so the browser's native fallback rendering
|
|
302
|
+
(alt text leaking out + broken-image icon/border) doesn't show through
|
|
303
|
+
underneath our own error overlay. display:none also drops the element
|
|
304
|
+
from the accessibility tree, so its alt isn't announced alongside the
|
|
305
|
+
visible .image__error-text in the overlay (the overlay wrapper itself
|
|
306
|
+
carries no role/aria-label — the visible text serves AT users too, so a
|
|
307
|
+
duplicate label there would just announce the alt twice). Box dimensions
|
|
308
|
+
are preserved by aspect-ratio on .image__media, not by the img itself.
|
|
309
|
+
Listeners stay attached — only DOM removal detaches them — so the next
|
|
310
|
+
src change still triggers load/error. */
|
|
311
|
+
|
|
312
|
+
.image__img--errored {
|
|
313
|
+
display: none;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
/* # Live region for dynamic load failures
|
|
318
|
+
Visually-hidden span sits inside .image__media and announces the
|
|
319
|
+
translated "image could not be loaded" message + alt text via
|
|
320
|
+
aria-live="polite" when _imageErrored flips mid-session. The element
|
|
321
|
+
is always rendered (so AT subscribes from first paint) but the
|
|
322
|
+
content only flows in on the error transition, which is what fires
|
|
323
|
+
the announcement. Standard visually-hidden recipe. */
|
|
324
|
+
|
|
325
|
+
.image__status {
|
|
326
|
+
position: absolute;
|
|
327
|
+
width: 1px;
|
|
328
|
+
height: 1px;
|
|
329
|
+
overflow: hidden;
|
|
330
|
+
clip-path: inset(50%);
|
|
331
|
+
white-space: nowrap;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
/* # Error state
|
|
336
|
+
Centred card with icon + alt-text shown when the image fails to load.
|
|
337
|
+
Sits over whatever background --_background-color provides (the LQIP
|
|
338
|
+
gradient when present, otherwise the neutral fallback color). The
|
|
339
|
+
card has its own neutral background so the icon + label stay legible
|
|
340
|
+
against the LQIP behind it. */
|
|
341
|
+
|
|
342
|
+
.image__error {
|
|
343
|
+
position: absolute;
|
|
344
|
+
inset: 0;
|
|
345
|
+
display: flex;
|
|
346
|
+
align-items: center;
|
|
347
|
+
justify-content: center;
|
|
348
|
+
padding: var(--_error-padding);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.image__error-card {
|
|
352
|
+
box-sizing: border-box;
|
|
353
|
+
display: flex;
|
|
354
|
+
flex-direction: column;
|
|
355
|
+
align-items: center;
|
|
356
|
+
max-width: 100%;
|
|
357
|
+
padding: var(--_error-card-padding-block) var(--_error-card-padding-inline);
|
|
358
|
+
gap: var(--_error-card-gap);
|
|
359
|
+
background-color: var(--_background-color);
|
|
360
|
+
border-radius: var(--_error-card-corner-radius);
|
|
361
|
+
color: var(--_error-text-color);
|
|
362
|
+
font: var(--_error-font);
|
|
363
|
+
text-align: center;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.image__error-text {
|
|
367
|
+
max-width: 100%;
|
|
368
|
+
overflow-wrap: anywhere;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
/* # Caption */
|
|
373
|
+
|
|
374
|
+
.image__caption {
|
|
375
|
+
display: flex;
|
|
376
|
+
flex-wrap: wrap;
|
|
377
|
+
gap: var(--_caption-row-gap);
|
|
378
|
+
color: var(--_caption-color);
|
|
379
|
+
font: var(--_caption-font);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.image__credit {
|
|
383
|
+
color: var(--_credit-color);
|
|
384
|
+
font: var(--_credit-font);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
/* # Accessibility */
|
|
389
|
+
|
|
390
|
+
@media (prefers-reduced-motion: reduce) {
|
|
391
|
+
.image__media--lqip .image__img {
|
|
392
|
+
transition: none;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@media (forced-colors: active) {
|
|
397
|
+
.image__media {
|
|
398
|
+
border: 1px solid CanvasText;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
`;
|
|
402
|
+
//# sourceMappingURL=image.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.styles.js","sourceRoot":"","sources":["../../../../src/components/content/image/image.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Y7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.template.d.ts","sourceRoot":"","sources":["../../../../src/components/content/image/image.template.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,wCA8GjD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { html, nothing } from 'lit';
|
|
2
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
3
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
4
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
5
|
+
export function imageTemplate(component) {
|
|
6
|
+
// aspect-ratio is applied to the media wrapper (not the img) so it
|
|
7
|
+
// reserves space in the layout *before* the image loads, avoiding CLS.
|
|
8
|
+
// Slotted img/picture also fills this wrapper.
|
|
9
|
+
// --context-lqip-base / --context-lqip-c1..c6 carry the seven quantised
|
|
10
|
+
// Oklab bytes from the parsed lqip attribute across the shadow boundary
|
|
11
|
+
// into the stylesheet. Each byte decodes back into an oklab() colour at
|
|
12
|
+
// render time. Uses the --context-* prefix because the inline style and
|
|
13
|
+
// the consuming CSS live in different scopes.
|
|
14
|
+
const parsedLqip = component._parsedLqip;
|
|
15
|
+
const hasLqip = parsedLqip !== null;
|
|
16
|
+
const mediaStyles = {};
|
|
17
|
+
if (component._cssAspectRatio)
|
|
18
|
+
mediaStyles.aspectRatio = component._cssAspectRatio;
|
|
19
|
+
if (hasLqip) {
|
|
20
|
+
mediaStyles['--context-lqip-base'] = String(parsedLqip.base);
|
|
21
|
+
parsedLqip.cells.forEach((cell, i) => {
|
|
22
|
+
mediaStyles[`--context-lqip-c${i + 1}`] = String(cell);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const mediaClasses = classMap({
|
|
26
|
+
'image__media': true,
|
|
27
|
+
// LQIP only renders while the image is in-flight. Once it errors we
|
|
28
|
+
// fall back to the neutral background so the error card sits on a
|
|
29
|
+
// calm surface instead of a distracting gradient.
|
|
30
|
+
'image__media--lqip': hasLqip && !component._imageErrored,
|
|
31
|
+
});
|
|
32
|
+
const imgClasses = classMap({
|
|
33
|
+
'image__img': true,
|
|
34
|
+
'image__img--loaded': component._imageLoaded,
|
|
35
|
+
'image__img--errored': component._imageErrored,
|
|
36
|
+
});
|
|
37
|
+
const fallbackImg = html `
|
|
38
|
+
<img class=${imgClasses}
|
|
39
|
+
src=${component.src || nothing}
|
|
40
|
+
alt=${component.decorative ? '' : component.alt}
|
|
41
|
+
aria-hidden=${component.decorative ? 'true' : nothing}
|
|
42
|
+
srcset=${component.srcset || nothing}
|
|
43
|
+
sizes=${component.sizes || nothing}
|
|
44
|
+
width=${ifDefined(component._numericWidth)}
|
|
45
|
+
height=${ifDefined(component.height)}
|
|
46
|
+
loading=${component.loading}
|
|
47
|
+
decoding=${component.decoding}
|
|
48
|
+
fetchpriority=${ifDefined(component.fetchPriority)}
|
|
49
|
+
@load=${component._onImageLoad}
|
|
50
|
+
@error=${component._onImageError}
|
|
51
|
+
>
|
|
52
|
+
`;
|
|
53
|
+
// Error overlay: shown when the fallback img fires an error. Sits centred
|
|
54
|
+
// over the media area on top of the LQIP gradient (or the neutral fallback
|
|
55
|
+
// background when no LQIP is provided).
|
|
56
|
+
// A11y: the visible .image__error-text already carries the alt as readable
|
|
57
|
+
// text for both sighted and screen-reader users, so the wrapper does NOT
|
|
58
|
+
// repeat it via role="img" + aria-label — that produced a duplicate
|
|
59
|
+
// announcement ("image: X" followed by "X"). Decorative images skip the
|
|
60
|
+
// text entirely and aria-hidden the whole overlay so AT users don't get a
|
|
61
|
+
// spurious failure announcement for an image that conveyed nothing anyway.
|
|
62
|
+
const errorOverlay = component._imageErrored ? html `
|
|
63
|
+
<div class="image__error"
|
|
64
|
+
aria-hidden=${component.decorative ? 'true' : nothing}
|
|
65
|
+
>
|
|
66
|
+
<div class="image__error-card">
|
|
67
|
+
<nldd-icon name="broken-image" size="32" color="secondary-content"></nldd-icon>
|
|
68
|
+
${component.decorative ? nothing : html `<span class="image__error-text">${component.alt}</span>`}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
` : nothing;
|
|
72
|
+
// Visually-hidden live region announces "image failed to load" once the
|
|
73
|
+
// internal img errors mid-session (gallery swap, lazy reload, etc.). The
|
|
74
|
+
// element is always rendered (so AT subscribes to it from first paint),
|
|
75
|
+
// but populated only on error so the announcement fires when the text
|
|
76
|
+
// flips from empty to non-empty. Decorative images stay silent — they
|
|
77
|
+
// convey nothing, so a failure isn't worth announcing.
|
|
78
|
+
// Append the alt only — never the raw src. A CDN URL with a long path
|
|
79
|
+
// and query string is noise to AT users; when alt is empty (valid in
|
|
80
|
+
// production, DEV-warned) we announce the plain translated message.
|
|
81
|
+
const errorBase = component._t('components.image.error-status-message');
|
|
82
|
+
const errorStatusMessage = component._imageErrored && !component.decorative
|
|
83
|
+
? (component.alt ? `${errorBase}: ${component.alt}` : errorBase)
|
|
84
|
+
: '';
|
|
85
|
+
const liveRegion = html `<span class="image__status" aria-live="polite">${errorStatusMessage}</span>`;
|
|
86
|
+
const media = html `
|
|
87
|
+
<div class=${mediaClasses}
|
|
88
|
+
style=${styleMap(mediaStyles)}
|
|
89
|
+
>
|
|
90
|
+
<slot>${fallbackImg}</slot>
|
|
91
|
+
${errorOverlay}
|
|
92
|
+
${liveRegion}
|
|
93
|
+
</div>
|
|
94
|
+
`;
|
|
95
|
+
if (!component._hasCaption) {
|
|
96
|
+
return media;
|
|
97
|
+
}
|
|
98
|
+
return html `
|
|
99
|
+
<figure class="image__figure">
|
|
100
|
+
${media}
|
|
101
|
+
<figcaption class="image__caption">
|
|
102
|
+
<slot name="caption" @slotchange=${component._onCaptionSlotChange}
|
|
103
|
+
>${component.caption}</slot>
|
|
104
|
+
${component.credit ? html `<span class="image__credit">${component.credit}</span>` : nothing}
|
|
105
|
+
</figcaption>
|
|
106
|
+
</figure>
|
|
107
|
+
`;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=image.template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.template.js","sourceRoot":"","sources":["../../../../src/components/content/image/image.template.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
import { LitElement } from 'lit';
|
|
11
|
+
import './image.js';
|
|
12
|
+
export declare const nlddLqipEncoderTranslations: {
|
|
13
|
+
'components.lqip-encoder.upload-label': string;
|
|
14
|
+
'components.lqip-encoder.file-prefix-text': string;
|
|
15
|
+
'components.lqip-encoder.copy-instruction-text': string;
|
|
16
|
+
'components.lqip-encoder.preview-heading-text': string;
|
|
17
|
+
'components.lqip-encoder.preview-lqip-label': string;
|
|
18
|
+
'components.lqip-encoder.preview-image-label': string;
|
|
19
|
+
};
|
|
20
|
+
export type NLDDLqipEncoderTranslations = typeof nlddLqipEncoderTranslations;
|
|
21
|
+
export declare class NLDDLqipEncoder extends LitElement {
|
|
22
|
+
translations: Partial<NLDDLqipEncoderTranslations>;
|
|
23
|
+
private _lqip;
|
|
24
|
+
private _imageUrl;
|
|
25
|
+
private _filename;
|
|
26
|
+
private _aspectRatio;
|
|
27
|
+
private _error;
|
|
28
|
+
_t(key: keyof NLDDLqipEncoderTranslations): string;
|
|
29
|
+
static styles: import("lit").CSSResult;
|
|
30
|
+
private _handleFileChange;
|
|
31
|
+
disconnectedCallback(): void;
|
|
32
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
33
|
+
}
|
|
34
|
+
declare global {
|
|
35
|
+
interface HTMLElementTagNameMap {
|
|
36
|
+
'nldd-lqip-encoder': NLDDLqipEncoder;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=lqip-encoder-element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lqip-encoder-element.d.ts","sourceRoot":"","sources":["../../../../src/components/content/image/lqip-encoder-element.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAG5C,OAAO,YAAY,CAAC;AAMpB,eAAO,MAAM,2BAA2B;;;;;;;CAOvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,OAAO,2BAA2B,CAAC;AAM7E,qBACa,eAAgB,SAAQ,UAAU;IAE9C,YAAY,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAM;IAE/C,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,MAAM,CAAM;IAEtB,EAAE,CAAC,GAAG,EAAE,MAAM,2BAA2B,GAAG,MAAM;IAIzD,OAAgB,MAAM,0BAyFpB;IAEF,OAAO,CAAC,iBAAiB,CA0BvB;IAEO,oBAAoB,IAAI,IAAI;IAK5B,MAAM;CA4Cf;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,mBAAmB,EAAE,eAAe,CAAC;KACrC;CACD"}
|