@santi020k/lumen-elements 3.0.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +518 -5
  2. package/dist/bullet-chart-html.d.ts +5 -0
  3. package/dist/bullet-chart-html.d.ts.map +1 -0
  4. package/dist/bullet-chart-html.js +56 -0
  5. package/dist/chart-activation.d.ts +15 -0
  6. package/dist/chart-activation.d.ts.map +1 -0
  7. package/dist/chart-activation.js +93 -0
  8. package/dist/chart-html.d.ts +22 -0
  9. package/dist/chart-html.d.ts.map +1 -0
  10. package/dist/chart-html.js +1 -0
  11. package/dist/comparison-chart-html.d.ts +4 -0
  12. package/dist/comparison-chart-html.d.ts.map +1 -0
  13. package/dist/comparison-chart-html.js +36 -0
  14. package/dist/components/ai-surfaces.d.ts +115 -0
  15. package/dist/components/ai-surfaces.d.ts.map +1 -0
  16. package/dist/components/ai-surfaces.js +270 -0
  17. package/dist/components/button.d.ts +55 -2
  18. package/dist/components/button.d.ts.map +1 -1
  19. package/dist/components/button.js +110 -2
  20. package/dist/components/card.d.ts +6 -0
  21. package/dist/components/card.d.ts.map +1 -1
  22. package/dist/components/card.js +6 -1
  23. package/dist/components/combobox.d.ts +1 -2
  24. package/dist/components/combobox.d.ts.map +1 -1
  25. package/dist/components/combobox.js +27 -121
  26. package/dist/components/dashboard.d.ts +41 -0
  27. package/dist/components/dashboard.d.ts.map +1 -0
  28. package/dist/components/dashboard.js +88 -0
  29. package/dist/components/device-frame.d.ts +31 -0
  30. package/dist/components/device-frame.d.ts.map +1 -0
  31. package/dist/components/device-frame.js +95 -0
  32. package/dist/components/foundations.d.ts +58 -18
  33. package/dist/components/foundations.d.ts.map +1 -1
  34. package/dist/components/foundations.js +160 -9
  35. package/dist/components/image-comparison.d.ts +33 -0
  36. package/dist/components/image-comparison.d.ts.map +1 -0
  37. package/dist/components/image-comparison.js +144 -0
  38. package/dist/components/media-selection.d.ts +41 -0
  39. package/dist/components/media-selection.d.ts.map +1 -0
  40. package/dist/components/media-selection.js +114 -0
  41. package/dist/components/media-viewport.d.ts +30 -0
  42. package/dist/components/media-viewport.d.ts.map +1 -0
  43. package/dist/components/media-viewport.js +108 -0
  44. package/dist/components/virtual-list.d.ts +38 -0
  45. package/dist/components/virtual-list.d.ts.map +1 -0
  46. package/dist/components/virtual-list.js +30 -0
  47. package/dist/components/visual-interactions.d.ts +65 -0
  48. package/dist/components/visual-interactions.d.ts.map +1 -0
  49. package/dist/components/visual-interactions.js +91 -0
  50. package/dist/components/world-map.d.ts +46 -0
  51. package/dist/components/world-map.d.ts.map +1 -0
  52. package/dist/components/world-map.js +312 -0
  53. package/dist/consumer-behaviors.d.ts +36 -0
  54. package/dist/consumer-behaviors.d.ts.map +1 -0
  55. package/dist/consumer-behaviors.js +1 -0
  56. package/dist/define.d.ts +229 -6
  57. package/dist/define.d.ts.map +1 -1
  58. package/dist/define.js +1 -1
  59. package/dist/element-base.js +1 -1
  60. package/dist/expanded-chart-html.d.ts +9 -0
  61. package/dist/expanded-chart-html.d.ts.map +1 -0
  62. package/dist/expanded-chart-html.js +61 -0
  63. package/dist/index.d.ts +2 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/package.json +34 -6
  66. package/styles/critical.css +696 -66
@@ -1,8 +1,124 @@
1
- import { createLumenElementClass, defineLumenElement } from '../element-base.js';
2
- const createFoundation = (config) => ({
3
- config,
4
- element: createLumenElementClass(config)
5
- });
1
+ import { resolveLumenLoadingSemantics, resolveLumenSkeletonSize } from '@santi020k/lumen-core';
2
+ import { createLumenElementClass, defineLumenElement, LumenElement } from '../element-base.js';
3
+ const createFoundation = (config, element = createLumenElementClass(config)) => ({ config, element });
4
+ const loadingSemanticAttributes = ['aria-hidden', 'aria-label', 'aria-labelledby', 'role'];
5
+ const loadingOwnershipAttribute = 'data-ui-loading-managed';
6
+ const generatedLoadingValues = { 'aria-hidden': 'true', role: 'status' };
7
+ const isManagedLoadingAttribute = (value) => value === 'aria-hidden' || value === 'role';
8
+ const skeletonSizeProperties = { height: '--ui-skeleton-height', width: '--ui-skeleton-width' };
9
+ class LumenLoadingIndicatorElement extends LumenElement {
10
+ #applied = new Set();
11
+ #applying = false;
12
+ connectedCallback() {
13
+ super.connectedCallback();
14
+ this.#restoreOwnership();
15
+ this.syncLoadingState();
16
+ }
17
+ attributeChangedCallback(name, previousValue, value) {
18
+ super.attributeChangedCallback(name, previousValue, value);
19
+ if (this.#applying)
20
+ return;
21
+ if (name === 'aria-hidden' || name === 'role') {
22
+ this.#applied.delete(name);
23
+ if (previousValue !== null && previousValue !== undefined)
24
+ this.#forgetOwnership(name);
25
+ }
26
+ if (this.isConnected)
27
+ this.syncLoadingState();
28
+ }
29
+ #restoreOwnership() {
30
+ const recorded = this.getAttribute(loadingOwnershipAttribute)?.split(' ') ?? [];
31
+ for (const name of recorded) {
32
+ if (isManagedLoadingAttribute(name) && this.getAttribute(name) === generatedLoadingValues[name]) {
33
+ this.#applied.add(name);
34
+ }
35
+ }
36
+ }
37
+ #recordOwnership() {
38
+ this.#writeOwnership([...this.#applied]);
39
+ }
40
+ #forgetOwnership(name) {
41
+ const recorded = this.getAttribute(loadingOwnershipAttribute)?.split(' ') ?? [];
42
+ const owned = [...recorded.filter(isManagedLoadingAttribute), ...this.#applied];
43
+ this.#writeOwnership(owned.filter(token => token !== name));
44
+ }
45
+ #writeOwnership(tokens) {
46
+ const owned = [...new Set(tokens)].sort().join(' ');
47
+ if ((this.getAttribute(loadingOwnershipAttribute) ?? '') === owned)
48
+ return;
49
+ this.#applying = true;
50
+ try {
51
+ if (owned)
52
+ this.setAttribute(loadingOwnershipAttribute, owned);
53
+ else
54
+ this.removeAttribute(loadingOwnershipAttribute);
55
+ }
56
+ finally {
57
+ this.#applying = false;
58
+ }
59
+ }
60
+ syncLoadingState() {
61
+ const semantics = resolveLumenLoadingSemantics({
62
+ ariaHidden: this.#readExplicit('aria-hidden'),
63
+ ariaLabel: this.getAttribute('aria-label'),
64
+ ariaLabelledby: this.getAttribute('aria-labelledby'),
65
+ role: this.#readExplicit('role')
66
+ });
67
+ this.#manage('aria-hidden', semantics.ariaHidden);
68
+ this.#manage('role', semantics.role);
69
+ }
70
+ #readExplicit(name) {
71
+ return this.#applied.has(name) ? null : this.getAttribute(name);
72
+ }
73
+ #manage(name, value) {
74
+ if (!this.#applied.has(name) && this.hasAttribute(name))
75
+ return;
76
+ this.#applying = true;
77
+ try {
78
+ if (value === undefined) {
79
+ this.removeAttribute(name);
80
+ this.#applied.delete(name);
81
+ }
82
+ else {
83
+ this.setAttribute(name, value);
84
+ this.#applied.add(name);
85
+ }
86
+ }
87
+ finally {
88
+ this.#applying = false;
89
+ }
90
+ this.#recordOwnership();
91
+ }
92
+ }
93
+ class LumenSkeletonBehaviorElement extends LumenLoadingIndicatorElement {
94
+ #appliedSizes = new Map();
95
+ syncLoadingState() {
96
+ super.syncLoadingState();
97
+ for (const [attribute, property] of Object.entries(skeletonSizeProperties)) {
98
+ const size = resolveLumenSkeletonSize(this.getAttribute(attribute));
99
+ const current = this.style.getPropertyValue(property);
100
+ const ownership = `data-ui-skeleton-${attribute}`;
101
+ if (!this.#appliedSizes.has(property) && current && current === this.getAttribute(ownership)) {
102
+ this.#appliedSizes.set(property, current);
103
+ }
104
+ const applied = this.#appliedSizes.get(property);
105
+ if (current && current !== applied) {
106
+ this.#appliedSizes.delete(property);
107
+ this.removeAttribute(ownership);
108
+ continue;
109
+ }
110
+ if (size) {
111
+ this.style.setProperty(property, size);
112
+ this.#appliedSizes.set(property, size);
113
+ this.setAttribute(ownership, size);
114
+ }
115
+ else if (this.#appliedSizes.delete(property)) {
116
+ this.style.removeProperty(property);
117
+ this.removeAttribute(ownership);
118
+ }
119
+ }
120
+ }
121
+ }
6
122
  export const lumenCardContentElementConfig = {
7
123
  baseClassName: 'ui-card__content',
8
124
  defaults: { 'data-slot': 'card-content' },
@@ -58,6 +174,12 @@ export const lumenGridElementConfig = {
58
174
  auto: 'ui-grid--columns-auto'
59
175
  },
60
176
  gap: {
177
+ '2xl': 'ui-grid--gap-2xl',
178
+ '3xl': 'ui-grid--gap-3xl',
179
+ group: 'ui-grid--gap-group',
180
+ related: 'ui-grid--gap-related',
181
+ section: 'ui-grid--gap-section',
182
+ xs: 'ui-grid--gap-xs',
61
183
  lg: 'ui-grid--gap-lg',
62
184
  md: 'ui-grid--gap-md',
63
185
  none: 'ui-grid--gap-none',
@@ -66,7 +188,7 @@ export const lumenGridElementConfig = {
66
188
  }
67
189
  },
68
190
  baseClassName: 'ui-grid',
69
- defaults: { 'data-ui-grid': '', columns: 'auto', gap: 'md' },
191
+ defaults: { 'data-ui-grid': '', columns: 'auto', gap: 'group' },
70
192
  tagName: 'lumen-grid'
71
193
  };
72
194
  export const lumenLabelElementConfig = {
@@ -85,20 +207,45 @@ export const lumenSeparatorElementConfig = {
85
207
  tagName: 'lumen-separator'
86
208
  };
87
209
  export const lumenSkeletonElementConfig = {
210
+ attributeClasses: {
211
+ animation: { none: 'ui-skeleton--static', pulse: 'ui-skeleton--pulse' },
212
+ shape: { circle: 'ui-skeleton--circle', text: 'ui-skeleton--text' }
213
+ },
88
214
  baseClassName: 'ui-skeleton',
215
+ observedAttributes: ['animation', 'height', 'shape', 'width', ...loadingSemanticAttributes],
89
216
  tagName: 'lumen-skeleton'
90
217
  };
91
218
  export const lumenSpinnerElementConfig = {
92
219
  baseClassName: 'ui-spinner',
220
+ observedAttributes: loadingSemanticAttributes,
93
221
  tagName: 'lumen-spinner'
94
222
  };
95
223
  export const lumenStackElementConfig = {
96
224
  attributeClasses: {
225
+ align: {
226
+ center: 'ui-stack--align-center',
227
+ end: 'ui-stack--align-end',
228
+ start: 'ui-stack--align-start',
229
+ stretch: 'ui-stack--align-stretch'
230
+ },
97
231
  direction: {
98
232
  horizontal: 'ui-stack--horizontal',
99
233
  vertical: 'ui-stack--vertical'
100
234
  },
235
+ justify: {
236
+ between: 'ui-stack--justify-between',
237
+ center: 'ui-stack--justify-center',
238
+ end: 'ui-stack--justify-end',
239
+ start: 'ui-stack--justify-start'
240
+ },
241
+ wrap: { '': 'ui-stack--wrap', true: 'ui-stack--wrap' },
101
242
  gap: {
243
+ '2xl': 'ui-stack--gap-2xl',
244
+ '3xl': 'ui-stack--gap-3xl',
245
+ group: 'ui-stack--gap-group',
246
+ related: 'ui-stack--gap-related',
247
+ section: 'ui-stack--gap-section',
248
+ xs: 'ui-stack--gap-xs',
102
249
  lg: 'ui-stack--gap-lg',
103
250
  md: 'ui-stack--gap-md',
104
251
  none: 'ui-stack--gap-none',
@@ -107,7 +254,7 @@ export const lumenStackElementConfig = {
107
254
  }
108
255
  },
109
256
  baseClassName: 'ui-stack',
110
- defaults: { 'data-ui-stack': '', direction: 'vertical', gap: 'md' },
257
+ defaults: { 'data-ui-stack': '', direction: 'vertical', gap: 'group' },
111
258
  tagName: 'lumen-stack'
112
259
  };
113
260
  export const lumenTypographyElementConfig = {
@@ -129,8 +276,12 @@ const direction = createFoundation(lumenDirectionElementConfig);
129
276
  const grid = createFoundation(lumenGridElementConfig);
130
277
  const label = createFoundation(lumenLabelElementConfig);
131
278
  const separator = createFoundation(lumenSeparatorElementConfig);
132
- const skeleton = createFoundation(lumenSkeletonElementConfig);
133
- const spinner = createFoundation(lumenSpinnerElementConfig);
279
+ const skeleton = createFoundation(lumenSkeletonElementConfig, class extends LumenSkeletonBehaviorElement {
280
+ static config = lumenSkeletonElementConfig;
281
+ });
282
+ const spinner = createFoundation(lumenSpinnerElementConfig, class extends LumenLoadingIndicatorElement {
283
+ static config = lumenSpinnerElementConfig;
284
+ });
134
285
  const stack = createFoundation(lumenStackElementConfig);
135
286
  const typography = createFoundation(lumenTypographyElementConfig);
136
287
  const visuallyHidden = createFoundation(lumenVisuallyHiddenElementConfig);
@@ -0,0 +1,33 @@
1
+ import { type LumenCustomElementRegistry, LumenElement } from '../element-base.js';
2
+ export declare const lumenImageComparisonElementConfig: {
3
+ readonly baseClassName: "ui-image-comparison";
4
+ readonly observedAttributes: readonly ["after-label", "before-label", "disabled", "fit", "label", "lang", "locale", "mode", "name", "ratio", "value"];
5
+ readonly tagName: "lumen-image-comparison";
6
+ };
7
+ export declare class LumenImageComparisonElement extends LumenElement {
8
+ static config: {
9
+ readonly baseClassName: "ui-image-comparison";
10
+ readonly observedAttributes: readonly ["after-label", "before-label", "disabled", "fit", "label", "lang", "locale", "mode", "name", "ratio", "value"];
11
+ readonly tagName: "lumen-image-comparison";
12
+ };
13
+ private abortController;
14
+ private frame;
15
+ private range;
16
+ private beforeLabel;
17
+ private afterLabel;
18
+ private controlLabel;
19
+ private reflectingInput;
20
+ get value(): number;
21
+ set value(value: number);
22
+ connectedCallback(): void;
23
+ disconnectedCallback(): void;
24
+ attributeChangedCallback(name: string): void;
25
+ private connect;
26
+ private createContent;
27
+ private get afterText();
28
+ private get locale();
29
+ private disabledForMode;
30
+ private update;
31
+ }
32
+ export declare const defineLumenImageComparison: (registry?: LumenCustomElementRegistry) => void;
33
+ //# sourceMappingURL=image-comparison.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-comparison.d.ts","sourceRoot":"","sources":["../../src/components/image-comparison.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,YAAY,EAEb,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,iCAAiC;;;;CAIP,CAAA;AAEvC,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,OAAgB,MAAM;;;;MAAoC;IAE1D,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,eAAe,CAAQ;IAE/B,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAEQ,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;IAM5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQrD,OAAO,CAAC,OAAO;IA6Cf,OAAO,CAAC,aAAa;IAiErB,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,MAAM;CA8Bf;AAED,eAAO,MAAM,0BAA0B,GAAI,WAAW,0BAA0B,KAAG,IAElF,CAAA"}
@@ -0,0 +1,144 @@
1
+ import { formatLumenImageComparisonValue, normalizeLumenImageComparisonMode, normalizeLumenImageComparisonRatio, normalizeLumenImageComparisonValue, syncLumenImageComparisonMode } from '@santi020k/lumen-core';
2
+ import { defineLumenElement, LumenElement } from '../element-base.js';
3
+ export const lumenImageComparisonElementConfig = {
4
+ baseClassName: 'ui-image-comparison',
5
+ observedAttributes: ['after-label', 'before-label', 'disabled', 'fit', 'label', 'lang', 'locale', 'mode', 'name', 'ratio', 'value'],
6
+ tagName: 'lumen-image-comparison'
7
+ };
8
+ export class LumenImageComparisonElement extends LumenElement {
9
+ static config = lumenImageComparisonElementConfig;
10
+ abortController;
11
+ frame;
12
+ range;
13
+ beforeLabel;
14
+ afterLabel;
15
+ controlLabel;
16
+ reflectingInput = false;
17
+ get value() {
18
+ return normalizeLumenImageComparisonValue(this.getAttribute('value'));
19
+ }
20
+ set value(value) {
21
+ this.setAttribute('value', String(normalizeLumenImageComparisonValue(value)));
22
+ }
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+ this.connect();
26
+ queueMicrotask(() => {
27
+ if (this.isConnected && !this.range)
28
+ this.connect();
29
+ });
30
+ }
31
+ disconnectedCallback() {
32
+ this.abortController?.abort();
33
+ this.abortController = undefined;
34
+ }
35
+ attributeChangedCallback(name) {
36
+ super.attributeChangedCallback();
37
+ if (name === 'value' && this.range && !this.reflectingInput)
38
+ this.range.defaultValue = String(this.value);
39
+ this.update();
40
+ }
41
+ connect() {
42
+ if (!this.range)
43
+ this.createContent();
44
+ if (!this.range)
45
+ return;
46
+ this.abortController?.abort();
47
+ this.abortController = new AbortController();
48
+ const { signal } = this.abortController;
49
+ this.range.addEventListener('input', () => {
50
+ if (!this.range || this.range.disabled)
51
+ return;
52
+ this.reflectingInput = true;
53
+ try {
54
+ this.value = this.range.valueAsNumber;
55
+ }
56
+ finally {
57
+ this.reflectingInput = false;
58
+ }
59
+ this.dispatchEvent(new CustomEvent('ui:image-comparison-change', {
60
+ bubbles: true,
61
+ detail: { value: this.value }
62
+ }));
63
+ }, { signal });
64
+ this.ownerDocument.addEventListener('reset', event => {
65
+ const range = this.range;
66
+ if (!range)
67
+ return;
68
+ if (event.target !== range.form)
69
+ return;
70
+ window.setTimeout(() => {
71
+ if (signal.aborted || event.defaultPrevented || !this.isConnected)
72
+ return;
73
+ this.value = normalizeLumenImageComparisonValue(range.defaultValue);
74
+ });
75
+ }, { capture: true, signal });
76
+ this.update();
77
+ }
78
+ createContent() {
79
+ const before = this.querySelector(':scope > [slot="before"]');
80
+ const after = this.querySelector(':scope > [slot="after"]');
81
+ if (!before || !after)
82
+ return;
83
+ this.frame = this.ownerDocument.createElement('div');
84
+ this.frame.className = 'ui-image-comparison__frame';
85
+ const beforeLayer = this.ownerDocument.createElement('div');
86
+ const afterLayer = this.ownerDocument.createElement('div');
87
+ const divider = this.ownerDocument.createElement('div');
88
+ beforeLayer.className = 'ui-image-comparison__before';
89
+ afterLayer.className = 'ui-image-comparison__after';
90
+ divider.className = 'ui-image-comparison__divider';
91
+ divider.setAttribute('aria-hidden', 'true');
92
+ beforeLayer.append(before);
93
+ afterLayer.append(after);
94
+ this.frame.append(beforeLayer, afterLayer, divider);
95
+ const labels = this.ownerDocument.createElement('div');
96
+ labels.className = 'ui-image-comparison__labels';
97
+ labels.setAttribute('aria-hidden', 'true');
98
+ this.beforeLabel = this.ownerDocument.createElement('span');
99
+ this.afterLabel = this.ownerDocument.createElement('span');
100
+ labels.append(this.beforeLabel, this.afterLabel);
101
+ const control = this.ownerDocument.createElement('label');
102
+ control.className = 'ui-image-comparison__control';
103
+ this.controlLabel = this.ownerDocument.createElement('span');
104
+ this.range = this.ownerDocument.createElement('input');
105
+ this.range.className = 'ui-slider ui-image-comparison__range';
106
+ this.range.type = 'range';
107
+ this.range.min = '0';
108
+ this.range.max = '100';
109
+ this.range.step = '1';
110
+ this.range.defaultValue = String(this.value);
111
+ control.append(this.controlLabel, this.range);
112
+ this.prepend(this.frame, labels, control);
113
+ }
114
+ get afterText() {
115
+ return this.getAttribute('after-label') ?? 'After';
116
+ }
117
+ get locale() {
118
+ return this.getAttribute('locale') || this.closest('[lang]')?.getAttribute('lang') || undefined;
119
+ }
120
+ disabledForMode(mode) {
121
+ return this.hasAttribute('disabled') || mode !== 'reveal';
122
+ }
123
+ update() {
124
+ if (!this.range || !this.frame || !this.beforeLabel || !this.afterLabel || !this.controlLabel)
125
+ return;
126
+ const mode = normalizeLumenImageComparisonMode(this.getAttribute('mode'));
127
+ syncLumenImageComparisonMode(this, mode);
128
+ const afterLabel = this.afterText;
129
+ const locale = this.locale;
130
+ this.beforeLabel.textContent = this.getAttribute('before-label') ?? 'Before';
131
+ this.afterLabel.textContent = afterLabel;
132
+ this.controlLabel.textContent = this.getAttribute('label') ?? 'Compare images';
133
+ this.dataset.fit = this.getAttribute('fit') === 'contain' ? 'contain' : 'cover';
134
+ this.frame.style.setProperty('--ui-image-comparison-ratio', String(normalizeLumenImageComparisonRatio(this.getAttribute('ratio'))));
135
+ this.frame.style.setProperty('--ui-image-comparison-position', `${this.value}%`);
136
+ this.range.value = String(this.value);
137
+ this.range.disabled = this.disabledForMode(mode);
138
+ this.range.name = this.getAttribute('name') ?? '';
139
+ this.range.ariaValueText = formatLumenImageComparisonValue(this.value, afterLabel, locale);
140
+ }
141
+ }
142
+ export const defineLumenImageComparison = (registry) => {
143
+ defineLumenElement(lumenImageComparisonElementConfig, LumenImageComparisonElement, registry);
144
+ };
@@ -0,0 +1,41 @@
1
+ import { type LumenCustomElementRegistry, LumenElement } from '../element-base.js';
2
+ export declare const lumenMediaThumbnailElementConfig: {
3
+ readonly baseClassName: "ui-media-thumbnail";
4
+ readonly observedAttributes: readonly ["label", "media-id", "selected", "order", "state", "state-label", "disabled"];
5
+ readonly tagName: "lumen-media-thumbnail";
6
+ };
7
+ export declare class LumenMediaThumbnailElement extends LumenElement {
8
+ static config: {
9
+ readonly baseClassName: "ui-media-thumbnail";
10
+ readonly observedAttributes: readonly ["label", "media-id", "selected", "order", "state", "state-label", "disabled"];
11
+ readonly tagName: "lumen-media-thumbnail";
12
+ };
13
+ private button;
14
+ private labelNode;
15
+ private orderNode;
16
+ private stateNode;
17
+ connectedCallback(): void;
18
+ attributeChangedCallback(): void;
19
+ private createContent;
20
+ private update;
21
+ }
22
+ export declare const lumenMediaFilmstripElementConfig: {
23
+ readonly baseClassName: "ui-media-filmstrip";
24
+ readonly observedAttributes: readonly ["label", "selection-label"];
25
+ readonly tagName: "lumen-media-filmstrip";
26
+ };
27
+ export declare class LumenMediaFilmstripElement extends LumenElement {
28
+ static config: {
29
+ readonly baseClassName: "ui-media-filmstrip";
30
+ readonly observedAttributes: readonly ["label", "selection-label"];
31
+ readonly tagName: "lumen-media-filmstrip";
32
+ };
33
+ private labelNode;
34
+ private summary;
35
+ connectedCallback(): void;
36
+ attributeChangedCallback(): void;
37
+ private update;
38
+ }
39
+ export declare const defineLumenMediaThumbnail: (registry?: LumenCustomElementRegistry) => void;
40
+ export declare const defineLumenMediaFilmstrip: (registry?: LumenCustomElementRegistry) => void;
41
+ //# sourceMappingURL=media-selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-selection.d.ts","sourceRoot":"","sources":["../../src/components/media-selection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,0BAA0B,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAA;AAE/H,eAAO,MAAM,gCAAgC;;;;CAIN,CAAA;AAEvC,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D,OAAgB,MAAM;;;;MAAmC;IACzD,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAErC,iBAAiB,IAAI,IAAI;IAQzB,wBAAwB,IAAI,IAAI;IAMzC,OAAO,CAAC,aAAa;IAgDrB,OAAO,CAAC,MAAM;CAyBf;AAED,eAAO,MAAM,gCAAgC;;;;CAIN,CAAA;AAEvC,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D,OAAgB,MAAM;;;;MAAmC;IACzD,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,OAAO,CAA6B;IAEnC,iBAAiB,IAAI,IAAI;IA2BzB,wBAAwB,IAAI,IAAI;IAMzC,OAAO,CAAC,MAAM;CAWf;AAED,eAAO,MAAM,yBAAyB,GAAI,WAAW,0BAA0B,KAAG,IAEjF,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,WAAW,0BAA0B,KAAG,IAEjF,CAAA"}
@@ -0,0 +1,114 @@
1
+ import { formatLumenMediaThumbnailState, resolveLumenMediaOrder, resolveLumenMediaThumbnailState } from '@santi020k/lumen-core/media-workspace';
2
+ import { defineLumenElement, LumenElement } from '../element-base.js';
3
+ export const lumenMediaThumbnailElementConfig = {
4
+ baseClassName: 'ui-media-thumbnail',
5
+ observedAttributes: ['label', 'media-id', 'selected', 'order', 'state', 'state-label', 'disabled'],
6
+ tagName: 'lumen-media-thumbnail'
7
+ };
8
+ export class LumenMediaThumbnailElement extends LumenElement {
9
+ static config = lumenMediaThumbnailElementConfig;
10
+ button;
11
+ labelNode;
12
+ orderNode;
13
+ stateNode;
14
+ connectedCallback() {
15
+ super.connectedCallback();
16
+ if (!this.button)
17
+ this.createContent();
18
+ this.update();
19
+ }
20
+ attributeChangedCallback() {
21
+ super.attributeChangedCallback();
22
+ this.update();
23
+ }
24
+ createContent() {
25
+ const button = this.ownerDocument.createElement('button');
26
+ const media = this.ownerDocument.createElement('span');
27
+ const content = this.ownerDocument.createElement('span');
28
+ button.className = 'ui-button ui-button--outline ui-media-thumbnail';
29
+ button.type = 'button';
30
+ content.className = 'ui-button__content';
31
+ media.className = 'ui-media-thumbnail__media';
32
+ media.setAttribute('aria-hidden', 'true');
33
+ media.append(...this.childNodes);
34
+ this.labelNode = this.ownerDocument.createElement('span');
35
+ this.labelNode.className = 'ui-media-thumbnail__label';
36
+ this.orderNode = this.ownerDocument.createElement('span');
37
+ this.orderNode.className = 'ui-media-thumbnail__order';
38
+ this.stateNode = this.ownerDocument.createElement('span');
39
+ this.stateNode.className = 'ui-media-thumbnail__state';
40
+ content.append(media, this.labelNode, this.orderNode, this.stateNode);
41
+ button.append(content);
42
+ button.addEventListener('click', () => {
43
+ const id = this.getAttribute('media-id');
44
+ if (button.disabled || !id)
45
+ return;
46
+ this.dispatchEvent(new CustomEvent('ui:media-selection-request', {
47
+ bubbles: true, detail: { id, selected: !this.hasAttribute('selected') }
48
+ }));
49
+ });
50
+ this.append(button);
51
+ this.button = button;
52
+ }
53
+ update() {
54
+ if (!this.button || !this.labelNode || !this.orderNode || !this.stateNode)
55
+ return;
56
+ const rawState = this.getAttribute('state');
57
+ const state = resolveLumenMediaThumbnailState(rawState);
58
+ const order = resolveLumenMediaOrder(Number(this.getAttribute('order')));
59
+ this.button.dataset.state = state;
60
+ this.button.disabled = this.hasAttribute('disabled') || state !== 'ready';
61
+ this.button.setAttribute('aria-pressed', String(this.hasAttribute('selected')));
62
+ this.button.setAttribute('aria-busy', String(state === 'loading'));
63
+ this.labelNode.textContent = this.getAttribute('label') ?? '';
64
+ this.orderNode.hidden = order === undefined;
65
+ this.orderNode.textContent = this.orderNode.hidden ? '' : String(order);
66
+ this.stateNode.hidden = state === 'ready';
67
+ this.stateNode.textContent = formatLumenMediaThumbnailState(state, this.getAttribute('state-label') ?? undefined);
68
+ }
69
+ }
70
+ export const lumenMediaFilmstripElementConfig = {
71
+ baseClassName: 'ui-media-filmstrip',
72
+ observedAttributes: ['label', 'selection-label'],
73
+ tagName: 'lumen-media-filmstrip'
74
+ };
75
+ export class LumenMediaFilmstripElement extends LumenElement {
76
+ static config = lumenMediaFilmstripElementConfig;
77
+ labelNode;
78
+ summary;
79
+ connectedCallback() {
80
+ super.connectedCallback();
81
+ if (!this.summary) {
82
+ const heading = this.ownerDocument.createElement('div');
83
+ const list = this.ownerDocument.createElement('ol');
84
+ heading.className = 'ui-media-filmstrip__heading';
85
+ list.className = 'ui-media-filmstrip__items';
86
+ this.labelNode = this.ownerDocument.createElement('span');
87
+ this.summary = this.ownerDocument.createElement('span');
88
+ this.summary.setAttribute('role', 'status');
89
+ heading.append(this.labelNode, this.summary);
90
+ list.append(...this.childNodes);
91
+ this.append(heading, list);
92
+ }
93
+ this.update();
94
+ }
95
+ attributeChangedCallback() {
96
+ super.attributeChangedCallback();
97
+ this.update();
98
+ }
99
+ update() {
100
+ const label = this.getAttribute('label') ?? 'Media selection';
101
+ this.setAttribute('role', 'region');
102
+ this.setAttribute('aria-label', label);
103
+ if (this.labelNode)
104
+ this.labelNode.textContent = label;
105
+ if (this.summary)
106
+ this.summary.textContent = this.getAttribute('selection-label') ?? '';
107
+ }
108
+ }
109
+ export const defineLumenMediaThumbnail = (registry) => {
110
+ defineLumenElement(lumenMediaThumbnailElementConfig, LumenMediaThumbnailElement, registry);
111
+ };
112
+ export const defineLumenMediaFilmstrip = (registry) => {
113
+ defineLumenElement(lumenMediaFilmstripElementConfig, LumenMediaFilmstripElement, registry);
114
+ };
@@ -0,0 +1,30 @@
1
+ import { type LumenMediaViewportLabels } from '@santi020k/lumen-core/media-viewport';
2
+ import { type LumenMediaViewportValue } from '@santi020k/lumen-core/media-workspace';
3
+ import { type LumenCustomElementRegistry, LumenElement } from '../element-base.js';
4
+ export declare const lumenMediaViewportElementConfig: {
5
+ readonly baseClassName: "ui-media-viewport";
6
+ readonly observedAttributes: readonly ["label", "disabled", "max-zoom", "zoom", "pan-x", "pan-y", "ratio", "locale", "lang"];
7
+ readonly tagName: "lumen-media-viewport";
8
+ };
9
+ export declare class LumenMediaViewportElement extends LumenElement {
10
+ static config: {
11
+ readonly baseClassName: "ui-media-viewport";
12
+ readonly observedAttributes: readonly ["label", "disabled", "max-zoom", "zoom", "pan-x", "pan-y", "ratio", "locale", "lang"];
13
+ readonly tagName: "lumen-media-viewport";
14
+ };
15
+ private cleanup;
16
+ private stage;
17
+ private copy;
18
+ get value(): LumenMediaViewportValue;
19
+ set value(value: LumenMediaViewportValue);
20
+ set labels(value: Partial<LumenMediaViewportLabels>);
21
+ private get maxZoom();
22
+ connectedCallback(): void;
23
+ disconnectedCallback(): void;
24
+ attributeChangedCallback(): void;
25
+ private createContent;
26
+ private get locale();
27
+ private update;
28
+ }
29
+ export declare const defineLumenMediaViewport: (registry?: LumenCustomElementRegistry) => void;
30
+ //# sourceMappingURL=media-viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-viewport.d.ts","sourceRoot":"","sources":["../../src/components/media-viewport.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,wBAAwB,EAG9B,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,KAAK,uBAAuB,EAA+B,MAAM,uCAAuC,CAAA;AAEjH,OAAO,EAAsB,KAAK,0BAA0B,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAA;AAE/H,eAAO,MAAM,+BAA+B;;;;CAIL,CAAA;AAEvC,qBAAa,yBAA0B,SAAQ,YAAY;IACzD,OAAgB,MAAM;;;;MAAkC;IACxD,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,IAAI,CAAqD;IAEjE,IAAI,KAAK,IAAI,uBAAuB,CAEnC;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,uBAAuB,EAQvC;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,wBAAwB,CAAC,EAIlD;IAED,OAAO,KAAK,OAAO,GAElB;IAEQ,iBAAiB,IAAI,IAAI;IAqBzB,oBAAoB,IAAI,IAAI;IAM5B,wBAAwB,IAAI,IAAI;IAMzC,OAAO,CAAC,aAAa;IA0DrB,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,CAAC,MAAM;CAoBf;AAED,eAAO,MAAM,wBAAwB,GAAI,WAAW,0BAA0B,KAAG,IAEhF,CAAA"}