@redvars/peacock 3.8.2 → 3.8.4
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/accordion-item.js +15 -6
- package/dist/accordion-item.js.map +1 -1
- package/dist/accordion.js +12 -11
- package/dist/accordion.js.map +1 -1
- package/dist/alert.js +1 -0
- package/dist/alert.js.map +1 -1
- package/dist/app-bar.js +1 -0
- package/dist/app-bar.js.map +1 -1
- package/dist/assets/components.css +1 -1
- package/dist/assets/components.css.map +1 -1
- package/dist/assets/styles.css +1 -1
- package/dist/assets/styles.css.map +1 -1
- package/dist/avatar.js +1 -0
- package/dist/avatar.js.map +1 -1
- package/dist/babel-DBsfpl3B.js +18 -0
- package/dist/babel-DBsfpl3B.js.map +1 -0
- package/dist/badge.js +1 -0
- package/dist/badge.js.map +1 -1
- package/dist/bottom-sheet.js +1 -0
- package/dist/bottom-sheet.js.map +1 -1
- package/dist/breadcrumb-item.js +1 -0
- package/dist/breadcrumb-item.js.map +1 -1
- package/dist/breadcrumb.js +1 -0
- package/dist/breadcrumb.js.map +1 -1
- package/dist/button-group.js +5 -4
- package/dist/button-group.js.map +1 -1
- package/dist/button.js +9 -8
- package/dist/button.js.map +1 -1
- package/dist/calendar-column-view.js +1 -0
- package/dist/calendar-column-view.js.map +1 -1
- package/dist/calendar-month-view.js +1 -0
- package/dist/calendar-month-view.js.map +1 -1
- package/dist/calendar.js +1 -0
- package/dist/calendar.js.map +1 -1
- package/dist/canvas.js +1 -0
- package/dist/canvas.js.map +1 -1
- package/dist/card.js +23 -7
- package/dist/card.js.map +1 -1
- package/dist/cb-compound-expression.js +1 -0
- package/dist/cb-compound-expression.js.map +1 -1
- package/dist/cb-divider.js +1 -0
- package/dist/cb-divider.js.map +1 -1
- package/dist/cb-expression.js +1 -0
- package/dist/cb-expression.js.map +1 -1
- package/dist/cb-predicate.js +1 -0
- package/dist/cb-predicate.js.map +1 -1
- package/dist/{chart-bar-CYoGNXnK.js → chart-bar-CapLbc2e.js} +2 -1
- package/dist/{chart-bar-CYoGNXnK.js.map → chart-bar-CapLbc2e.js.map} +1 -1
- package/dist/chart-bar.js +1 -1
- package/dist/chart-doughnut.js +1 -0
- package/dist/chart-doughnut.js.map +1 -1
- package/dist/chart-pie.js +1 -0
- package/dist/chart-pie.js.map +1 -1
- package/dist/chart-stacked-bar.js +1 -1
- package/dist/checkbox.js +1 -0
- package/dist/checkbox.js.map +1 -1
- package/dist/chip.js +1 -0
- package/dist/chip.js.map +1 -1
- package/dist/clock.js +1 -0
- package/dist/clock.js.map +1 -1
- package/dist/code-editor.js +1 -0
- package/dist/code-editor.js.map +1 -1
- package/dist/code-highlighter.js +75 -11212
- package/dist/code-highlighter.js.map +1 -1
- package/dist/color-picker.js +701 -0
- package/dist/color-picker.js.map +1 -0
- package/dist/condition-builder.js +1 -0
- package/dist/condition-builder.js.map +1 -1
- package/dist/container.js +1 -0
- package/dist/container.js.map +1 -1
- package/dist/custom-elements-jsdocs.json +103 -10
- package/dist/custom-elements.json +1212 -586
- package/dist/divider.js +1 -0
- package/dist/divider.js.map +1 -1
- package/dist/dropdown-button.js +1 -0
- package/dist/dropdown-button.js.map +1 -1
- package/dist/elevation.js +1 -0
- package/dist/elevation.js.map +1 -1
- package/dist/empty-state.js +1 -0
- package/dist/empty-state.js.map +1 -1
- package/dist/estree-C2LDzX4U.js +47 -0
- package/dist/estree-C2LDzX4U.js.map +1 -0
- package/dist/fab.js +2 -3
- package/dist/fab.js.map +1 -1
- package/dist/field.js +1 -0
- package/dist/field.js.map +1 -1
- package/dist/{flow-designer-node-DsVwQTac.js → flow-designer-node-CGSm6cUH.js} +2 -1
- package/dist/{flow-designer-node-DsVwQTac.js.map → flow-designer-node-CGSm6cUH.js.map} +1 -1
- package/dist/flow-designer-node.js +1 -1
- package/dist/flow-designer.js +1 -1
- package/dist/html-D22sQuVy.js +27 -0
- package/dist/html-D22sQuVy.js.map +1 -0
- package/dist/html-editor.js +1 -0
- package/dist/html-editor.js.map +1 -1
- package/dist/icon-button.js +6 -5
- package/dist/icon-button.js.map +1 -1
- package/dist/icon.js +1 -0
- package/dist/icon.js.map +1 -1
- package/dist/index-_g_oLekF.js +14095 -0
- package/dist/index-_g_oLekF.js.map +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/item.js +4 -2
- package/dist/item.js.map +1 -1
- package/dist/link.js +1 -0
- package/dist/link.js.map +1 -1
- package/dist/{list-D6JLh1uh.js → list-BBmnHm8f.js} +196 -20
- package/dist/list-BBmnHm8f.js.map +1 -0
- package/dist/list.js +2 -2
- package/dist/loader.js +6 -2
- package/dist/loader.js.map +1 -1
- package/dist/menu-item.js +104 -33
- package/dist/menu-item.js.map +1 -1
- package/dist/menu.js +5 -18
- package/dist/menu.js.map +1 -1
- package/dist/modal.js +1 -0
- package/dist/modal.js.map +1 -1
- package/dist/navigation-rail-item.js +22 -6
- package/dist/navigation-rail-item.js.map +1 -1
- package/dist/navigation-rail.js +23 -20
- package/dist/navigation-rail.js.map +1 -1
- package/dist/notification-manager.js +1 -0
- package/dist/notification-manager.js.map +1 -1
- package/dist/notification.js +1 -0
- package/dist/notification.js.map +1 -1
- package/dist/number-counter.js +1 -0
- package/dist/number-counter.js.map +1 -1
- package/dist/pagination.js +1 -0
- package/dist/pagination.js.map +1 -1
- package/dist/pierre-dark-DFWl0m-C.js +4 -0
- package/dist/pierre-dark-DFWl0m-C.js.map +1 -0
- package/dist/pierre-light-BEkAPImt.js +4 -0
- package/dist/pierre-light-BEkAPImt.js.map +1 -0
- package/dist/popover-content.js +1 -0
- package/dist/popover-content.js.map +1 -1
- package/dist/popover.js +1 -0
- package/dist/popover.js.map +1 -1
- package/dist/postcss-BhbitHaI.js +64 -0
- package/dist/postcss-BhbitHaI.js.map +1 -0
- package/dist/radio.js +1 -0
- package/dist/radio.js.map +1 -1
- package/dist/search.js +1 -0
- package/dist/search.js.map +1 -1
- package/dist/segmented-button-group.js +1 -0
- package/dist/segmented-button-group.js.map +1 -1
- package/dist/segmented-button.js +1 -0
- package/dist/segmented-button.js.map +1 -1
- package/dist/{select-Dwtk0RIU.js → select-D85kpjUt.js} +28 -7
- package/dist/{select-Dwtk0RIU.js.map → select-D85kpjUt.js.map} +1 -1
- package/dist/side-sheet.js +2 -1
- package/dist/side-sheet.js.map +1 -1
- package/dist/skeleton.js +1 -0
- package/dist/skeleton.js.map +1 -1
- package/dist/snackbar.js +1 -0
- package/dist/snackbar.js.map +1 -1
- package/dist/spinner.js +1 -0
- package/dist/spinner.js.map +1 -1
- package/dist/split-button.js +1 -0
- package/dist/split-button.js.map +1 -1
- package/dist/src/accordion/accordion-item.d.ts +1 -1
- package/dist/src/accordion/accordion.d.ts +3 -3
- package/dist/src/button/button/button.d.ts +2 -2
- package/dist/src/button/button-group/button-group.d.ts +4 -4
- package/dist/src/code-highlighter/code-highlighter.d.ts +2 -2
- package/dist/src/color-picker/color-picker.d.ts +85 -0
- package/dist/src/color-picker/index.d.ts +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/item/item.d.ts +0 -1
- package/dist/src/list/list-item.d.ts +3 -1
- package/dist/src/list/list.d.ts +24 -0
- package/dist/src/menu/menu-item/menu-item.d.ts +1 -2
- package/dist/standalone-Ccq0tWwA.js +32 -0
- package/dist/standalone-Ccq0tWwA.js.map +1 -0
- package/dist/sub-menu.js +7 -1
- package/dist/sub-menu.js.map +1 -1
- package/dist/svg.js +1 -0
- package/dist/svg.js.map +1 -1
- package/dist/tab-group.js +1 -0
- package/dist/tab-group.js.map +1 -1
- package/dist/tab-panel.js +1 -0
- package/dist/tab-panel.js.map +1 -1
- package/dist/tab.js +1 -0
- package/dist/tab.js.map +1 -1
- package/dist/table.js +1 -0
- package/dist/table.js.map +1 -1
- package/dist/tabs.js +1 -0
- package/dist/tabs.js.map +1 -1
- package/dist/toolbar.js +1 -0
- package/dist/toolbar.js.map +1 -1
- package/dist/tooltip.js +1 -0
- package/dist/tooltip.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/readme.md +3 -3
- package/scss/mixin.scss +2 -0
- package/src/accordion/accordion-item.ts +16 -6
- package/src/accordion/accordion.scss +2 -2
- package/src/accordion/accordion.ts +7 -7
- package/src/button/button/button-base.scss +2 -1
- package/src/button/button/button-layers.scss +2 -6
- package/src/button/button/button.ts +3 -3
- package/src/button/button-group/button-group.ts +4 -4
- package/src/button/fab/fab.ts +0 -4
- package/src/card/card.scss +18 -5
- package/src/code-highlighter/code-highlighter.ts +94 -39
- package/src/color-picker/color-picker.scss +217 -0
- package/src/color-picker/color-picker.ts +478 -0
- package/src/color-picker/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/item/item.scss +3 -1
- package/src/item/item.ts +0 -1
- package/src/list/list-item.scss +5 -1
- package/src/list/list-item.ts +40 -14
- package/src/list/list.ts +164 -2
- package/src/loader.ts +4 -0
- package/src/menu/menu/menu.scss +4 -18
- package/src/menu/menu/menu.ts +0 -1
- package/src/menu/menu-item/menu-item.scss +73 -43
- package/src/menu/menu-item/menu-item.ts +60 -27
- package/src/menu/sub-menu/sub-menu.scss +5 -1
- package/src/navigation-rail/navigation-rail-item.scss +25 -8
- package/src/navigation-rail/navigation-rail.scss +25 -22
- package/src/side-sheet/side-sheet.ts +1 -1
- package/src/sidebar-menu/sidebar-menu-item.scss +14 -7
- package/dist/list-D6JLh1uh.js.map +0 -1
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import { LitElement, html, nothing } from 'lit';
|
|
2
|
+
import { property, state, query } from 'lit/decorators.js';
|
|
3
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
4
|
+
import styles from './color-picker.scss';
|
|
5
|
+
import IndividualComponent from '@/IndividualComponent.js';
|
|
6
|
+
|
|
7
|
+
// ── Color utilities ───────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
10
|
+
const clean = hex.replace('#', '');
|
|
11
|
+
const full = clean.length === 3
|
|
12
|
+
? clean.split('').map(c => c + c).join('')
|
|
13
|
+
: clean.slice(0, 6);
|
|
14
|
+
const n = parseInt(full, 16);
|
|
15
|
+
return { r: (n >> 16) & 0xff, g: (n >> 8) & 0xff, b: n & 0xff };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function rgbToHex(r: number, g: number, b: number): string {
|
|
19
|
+
return '#' + [r, g, b].map(v => Math.round(v).toString(16).padStart(2, '0')).join('');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function rgbToHsv(r: number, g: number, b: number): { h: number; s: number; v: number } {
|
|
23
|
+
const r1 = r / 255, g1 = g / 255, b1 = b / 255;
|
|
24
|
+
const max = Math.max(r1, g1, b1);
|
|
25
|
+
const min = Math.min(r1, g1, b1);
|
|
26
|
+
const delta = max - min;
|
|
27
|
+
|
|
28
|
+
let h = 0;
|
|
29
|
+
if (delta !== 0) {
|
|
30
|
+
if (max === r1) h = ((g1 - b1) / delta) % 6;
|
|
31
|
+
else if (max === g1) h = (b1 - r1) / delta + 2;
|
|
32
|
+
else h = (r1 - g1) / delta + 4;
|
|
33
|
+
h = Math.round(h * 60);
|
|
34
|
+
if (h < 0) h += 360;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { h, s: max === 0 ? 0 : delta / max, v: max };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function hsvToRgb(h: number, s: number, v: number): { r: number; g: number; b: number } {
|
|
41
|
+
const c = v * s;
|
|
42
|
+
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
|
|
43
|
+
const m = v - c;
|
|
44
|
+
let r1 = 0, g1 = 0, b1 = 0;
|
|
45
|
+
|
|
46
|
+
if (h < 60) { r1 = c; g1 = x; }
|
|
47
|
+
else if (h < 120) { r1 = x; g1 = c; }
|
|
48
|
+
else if (h < 180) { g1 = c; b1 = x; }
|
|
49
|
+
else if (h < 240) { g1 = x; b1 = c; }
|
|
50
|
+
else if (h < 300) { r1 = x; b1 = c; }
|
|
51
|
+
else { r1 = c; b1 = x; }
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
r: Math.round((r1 + m) * 255),
|
|
55
|
+
g: Math.round((g1 + m) * 255),
|
|
56
|
+
b: Math.round((b1 + m) * 255),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isValidHex(s: string): boolean {
|
|
61
|
+
return /^[0-9a-fA-F]{6}$/.test(s);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Component ─────────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @label Color Picker
|
|
68
|
+
* @tag wc-color-picker
|
|
69
|
+
* @rawTag color-picker
|
|
70
|
+
*
|
|
71
|
+
* @summary A color picker component for selecting colors via a hue/saturation/value interface.
|
|
72
|
+
*
|
|
73
|
+
* @overview
|
|
74
|
+
* <p>The color picker presents a 2D saturation–brightness panel with a hue slider below it.
|
|
75
|
+
* An optional alpha slider allows controlling opacity. The current hex value is displayed in
|
|
76
|
+
* an editable text field.</p>
|
|
77
|
+
*
|
|
78
|
+
* @cssprop --color-picker-width - Overall width of the component. Defaults to 240px.
|
|
79
|
+
* @cssprop --color-picker-sv-height - Height of the saturation/brightness panel. Defaults to 160px.
|
|
80
|
+
*
|
|
81
|
+
* @fires {CustomEvent<{value: string, alpha: number}>} input - Dispatched continuously while the color is being changed.
|
|
82
|
+
* @fires {CustomEvent<{value: string, alpha: number}>} change - Dispatched when a color change is committed (pointer up, key, or input blur).
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```html
|
|
86
|
+
* <wc-color-picker value="#2352d5"></wc-color-picker>
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```html
|
|
91
|
+
* <wc-color-picker value="#ff573380" alpha></wc-color-picker>
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
@IndividualComponent
|
|
95
|
+
export class ColorPicker extends LitElement {
|
|
96
|
+
// ── Static ────────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
static styles = [styles];
|
|
99
|
+
|
|
100
|
+
// ── Properties ───────────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The current color as a 6-digit hex string (e.g. `"#ff5733"`).
|
|
104
|
+
*/
|
|
105
|
+
@property({ type: String, reflect: true }) value = '#2352d5';
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Whether to show the alpha (opacity) slider and input.
|
|
109
|
+
*/
|
|
110
|
+
@property({ type: Boolean }) alpha = false;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Whether the color picker is disabled.
|
|
114
|
+
*/
|
|
115
|
+
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
116
|
+
|
|
117
|
+
// ── State ─────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
/** Current hue, 0–360. */
|
|
120
|
+
@state() private _hue = 0;
|
|
121
|
+
|
|
122
|
+
/** Current saturation, 0–1 (x-axis of the SV panel). */
|
|
123
|
+
@state() private _sat = 0;
|
|
124
|
+
|
|
125
|
+
/** Current brightness (value in HSV), 0–1 (y-axis, 1 = bright). */
|
|
126
|
+
@state() private _bri = 1;
|
|
127
|
+
|
|
128
|
+
/** Current opacity, 0–1. */
|
|
129
|
+
@state() private _opacity = 1;
|
|
130
|
+
|
|
131
|
+
/** Intermediate value for the hex text input (without `#`). */
|
|
132
|
+
@state() private _hexInput = '';
|
|
133
|
+
|
|
134
|
+
// ── Queries ───────────────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
@query('.sv-panel') private _svPanel?: HTMLElement;
|
|
137
|
+
@query('.hue-track') private _hueTrack?: HTMLElement;
|
|
138
|
+
@query('.alpha-track') private _alphaTrack?: HTMLElement;
|
|
139
|
+
|
|
140
|
+
// ── Private fields ────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
/** Tracks which drag handle is currently active. */
|
|
143
|
+
private _dragging: 'sv' | 'hue' | 'alpha' | null = null;
|
|
144
|
+
|
|
145
|
+
/** The last `value` we set ourselves, used to skip redundant re-syncs in `updated`. */
|
|
146
|
+
private _lastEmittedValue = '';
|
|
147
|
+
|
|
148
|
+
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
connectedCallback() {
|
|
151
|
+
super.connectedCallback();
|
|
152
|
+
this._syncFromValue();
|
|
153
|
+
this._lastEmittedValue = this.value;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
updated(changed: Map<PropertyKey, unknown>) {
|
|
157
|
+
if (changed.has('value') && this.value !== this._lastEmittedValue) {
|
|
158
|
+
this._syncFromValue();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Private methods ───────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
private _syncFromValue() {
|
|
165
|
+
const clean = this.value.startsWith('#') ? this.value.slice(1) : this.value;
|
|
166
|
+
if (!isValidHex(clean)) return;
|
|
167
|
+
const { r, g, b } = hexToRgb('#' + clean);
|
|
168
|
+
const { h, s, v } = rgbToHsv(r, g, b);
|
|
169
|
+
this._hue = h;
|
|
170
|
+
this._sat = s;
|
|
171
|
+
this._bri = v;
|
|
172
|
+
this._hexInput = clean.toUpperCase();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private _computeHex(): string {
|
|
176
|
+
const { r, g, b } = hsvToRgb(this._hue, this._sat, this._bri);
|
|
177
|
+
return rgbToHex(r, g, b);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private _emitValue(type: 'input' | 'change') {
|
|
181
|
+
const hex = this._computeHex();
|
|
182
|
+
this._lastEmittedValue = hex;
|
|
183
|
+
this.value = hex;
|
|
184
|
+
this._hexInput = hex.slice(1).toUpperCase();
|
|
185
|
+
this.dispatchEvent(new CustomEvent(type, {
|
|
186
|
+
detail: { value: hex, alpha: this._opacity },
|
|
187
|
+
bubbles: true,
|
|
188
|
+
composed: true,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// SV panel
|
|
193
|
+
private _onSvPointerDown(e: PointerEvent) {
|
|
194
|
+
if (this.disabled) return;
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
this._dragging = 'sv';
|
|
197
|
+
(e.currentTarget as Element).setPointerCapture(e.pointerId);
|
|
198
|
+
this._updateSv(e);
|
|
199
|
+
this._emitValue('input');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private _onSvPointerMove(e: PointerEvent) {
|
|
203
|
+
if (this._dragging !== 'sv') return;
|
|
204
|
+
this._updateSv(e);
|
|
205
|
+
this._emitValue('input');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private _onSvPointerUp() {
|
|
209
|
+
if (this._dragging !== 'sv') return;
|
|
210
|
+
this._dragging = null;
|
|
211
|
+
this._emitValue('change');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _updateSv(e: PointerEvent) {
|
|
215
|
+
const rect = this._svPanel!.getBoundingClientRect();
|
|
216
|
+
this._sat = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
217
|
+
this._bri = 1 - Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private _onSvKeyDown(e: KeyboardEvent) {
|
|
221
|
+
if (this.disabled) return;
|
|
222
|
+
const step = e.shiftKey ? 0.1 : 0.01;
|
|
223
|
+
let changed = false;
|
|
224
|
+
|
|
225
|
+
if (e.key === 'ArrowRight') { this._sat = Math.min(1, this._sat + step); changed = true; }
|
|
226
|
+
else if (e.key === 'ArrowLeft') { this._sat = Math.max(0, this._sat - step); changed = true; }
|
|
227
|
+
else if (e.key === 'ArrowUp') { this._bri = Math.min(1, this._bri + step); changed = true; }
|
|
228
|
+
else if (e.key === 'ArrowDown') { this._bri = Math.max(0, this._bri - step); changed = true; }
|
|
229
|
+
|
|
230
|
+
if (changed) {
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
this._emitValue('input');
|
|
233
|
+
this._emitValue('change');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Hue slider
|
|
238
|
+
private _onHuePointerDown(e: PointerEvent) {
|
|
239
|
+
if (this.disabled) return;
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
this._dragging = 'hue';
|
|
242
|
+
(e.currentTarget as Element).setPointerCapture(e.pointerId);
|
|
243
|
+
this._updateHue(e);
|
|
244
|
+
this._emitValue('input');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private _onHuePointerMove(e: PointerEvent) {
|
|
248
|
+
if (this._dragging !== 'hue') return;
|
|
249
|
+
this._updateHue(e);
|
|
250
|
+
this._emitValue('input');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private _onHuePointerUp() {
|
|
254
|
+
if (this._dragging !== 'hue') return;
|
|
255
|
+
this._dragging = null;
|
|
256
|
+
this._emitValue('change');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private _updateHue(e: PointerEvent) {
|
|
260
|
+
const rect = this._hueTrack!.getBoundingClientRect();
|
|
261
|
+
this._hue = Math.round(Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)) * 360);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private _onHueKeyDown(e: KeyboardEvent) {
|
|
265
|
+
if (this.disabled) return;
|
|
266
|
+
const step = e.shiftKey ? 10 : 1;
|
|
267
|
+
let changed = false;
|
|
268
|
+
|
|
269
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { this._hue = Math.min(360, this._hue + step); changed = true; }
|
|
270
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { this._hue = Math.max(0, this._hue - step); changed = true; }
|
|
271
|
+
|
|
272
|
+
if (changed) {
|
|
273
|
+
e.preventDefault();
|
|
274
|
+
this._emitValue('input');
|
|
275
|
+
this._emitValue('change');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Alpha slider
|
|
280
|
+
private _onAlphaPointerDown(e: PointerEvent) {
|
|
281
|
+
if (this.disabled) return;
|
|
282
|
+
e.preventDefault();
|
|
283
|
+
this._dragging = 'alpha';
|
|
284
|
+
(e.currentTarget as Element).setPointerCapture(e.pointerId);
|
|
285
|
+
this._updateAlpha(e);
|
|
286
|
+
this._emitValue('input');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private _onAlphaPointerMove(e: PointerEvent) {
|
|
290
|
+
if (this._dragging !== 'alpha') return;
|
|
291
|
+
this._updateAlpha(e);
|
|
292
|
+
this._emitValue('input');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
private _onAlphaPointerUp() {
|
|
296
|
+
if (this._dragging !== 'alpha') return;
|
|
297
|
+
this._dragging = null;
|
|
298
|
+
this._emitValue('change');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private _updateAlpha(e: PointerEvent) {
|
|
302
|
+
const rect = this._alphaTrack!.getBoundingClientRect();
|
|
303
|
+
this._opacity = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private _onAlphaKeyDown(e: KeyboardEvent) {
|
|
307
|
+
if (this.disabled) return;
|
|
308
|
+
const step = e.shiftKey ? 0.1 : 0.01;
|
|
309
|
+
let changed = false;
|
|
310
|
+
|
|
311
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { this._opacity = Math.min(1, this._opacity + step); changed = true; }
|
|
312
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { this._opacity = Math.max(0, this._opacity - step); changed = true; }
|
|
313
|
+
|
|
314
|
+
if (changed) {
|
|
315
|
+
e.preventDefault();
|
|
316
|
+
this._emitValue('input');
|
|
317
|
+
this._emitValue('change');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Hex input
|
|
322
|
+
private _onHexInput(e: InputEvent) {
|
|
323
|
+
const raw = (e.target as HTMLInputElement).value.toUpperCase().replace(/[^0-9A-F]/g, '');
|
|
324
|
+
this._hexInput = raw;
|
|
325
|
+
if (isValidHex(raw)) {
|
|
326
|
+
const { r, g, b } = hexToRgb('#' + raw);
|
|
327
|
+
const { h, s, v } = rgbToHsv(r, g, b);
|
|
328
|
+
this._hue = h;
|
|
329
|
+
this._sat = s;
|
|
330
|
+
this._bri = v;
|
|
331
|
+
this._emitValue('input');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private _onHexChange() {
|
|
336
|
+
if (isValidHex(this._hexInput)) {
|
|
337
|
+
this._emitValue('change');
|
|
338
|
+
} else {
|
|
339
|
+
this._hexInput = this.value.slice(1).toUpperCase();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
private _onAlphaNumberChange(e: Event) {
|
|
344
|
+
const raw = parseInt((e.target as HTMLInputElement).value, 10);
|
|
345
|
+
this._opacity = Math.max(0, Math.min(100, isNaN(raw) ? 100 : raw)) / 100;
|
|
346
|
+
this._emitValue('change');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ── Render ────────────────────────────────────────────────────────────────
|
|
350
|
+
|
|
351
|
+
render() {
|
|
352
|
+
const hueColor = `hsl(${this._hue}, 100%, 50%)`;
|
|
353
|
+
const currentHex = this._computeHex();
|
|
354
|
+
const { r, g, b } = hsvToRgb(this._hue, this._sat, this._bri);
|
|
355
|
+
const previewColor = `rgba(${r}, ${g}, ${b}, ${this._opacity})`;
|
|
356
|
+
|
|
357
|
+
return html`
|
|
358
|
+
<div class="color-picker ${this.disabled ? 'disabled' : ''}">
|
|
359
|
+
|
|
360
|
+
<!-- Saturation / Brightness 2D panel -->
|
|
361
|
+
<div
|
|
362
|
+
class="sv-panel"
|
|
363
|
+
style=${styleMap({ '--hue-color': hueColor })}
|
|
364
|
+
@pointerdown=${this._onSvPointerDown}
|
|
365
|
+
@pointermove=${this._onSvPointerMove}
|
|
366
|
+
@pointerup=${this._onSvPointerUp}
|
|
367
|
+
@pointercancel=${this._onSvPointerUp}
|
|
368
|
+
>
|
|
369
|
+
<div
|
|
370
|
+
class="sv-cursor"
|
|
371
|
+
role="slider"
|
|
372
|
+
tabindex=${this.disabled ? '-1' : '0'}
|
|
373
|
+
aria-label="Saturation and brightness"
|
|
374
|
+
aria-valuetext="Saturation ${Math.round(this._sat * 100)}%, Brightness ${Math.round(this._bri * 100)}%"
|
|
375
|
+
style=${styleMap({
|
|
376
|
+
left: `${this._sat * 100}%`,
|
|
377
|
+
top: `${(1 - this._bri) * 100}%`,
|
|
378
|
+
})}
|
|
379
|
+
@keydown=${this._onSvKeyDown}
|
|
380
|
+
></div>
|
|
381
|
+
</div>
|
|
382
|
+
|
|
383
|
+
<!-- Preview swatch + sliders -->
|
|
384
|
+
<div class="controls-row">
|
|
385
|
+
<div class="color-preview">
|
|
386
|
+
<div class="preview-inner" style=${styleMap({ background: previewColor })}></div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<div class="sliders">
|
|
390
|
+
<!-- Hue slider -->
|
|
391
|
+
<div
|
|
392
|
+
class="slider-track hue-track"
|
|
393
|
+
@pointerdown=${this._onHuePointerDown}
|
|
394
|
+
@pointermove=${this._onHuePointerMove}
|
|
395
|
+
@pointerup=${this._onHuePointerUp}
|
|
396
|
+
@pointercancel=${this._onHuePointerUp}
|
|
397
|
+
>
|
|
398
|
+
<div
|
|
399
|
+
class="slider-thumb"
|
|
400
|
+
role="slider"
|
|
401
|
+
tabindex=${this.disabled ? '-1' : '0'}
|
|
402
|
+
aria-label="Hue"
|
|
403
|
+
aria-valuemin="0"
|
|
404
|
+
aria-valuemax="360"
|
|
405
|
+
aria-valuenow=${this._hue}
|
|
406
|
+
style=${styleMap({ left: `${(this._hue / 360) * 100}%` })}
|
|
407
|
+
@keydown=${this._onHueKeyDown}
|
|
408
|
+
></div>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
${this.alpha ? html`
|
|
412
|
+
<!-- Alpha slider -->
|
|
413
|
+
<div
|
|
414
|
+
class="slider-track alpha-track"
|
|
415
|
+
style=${styleMap({ '--current-color': currentHex })}
|
|
416
|
+
@pointerdown=${this._onAlphaPointerDown}
|
|
417
|
+
@pointermove=${this._onAlphaPointerMove}
|
|
418
|
+
@pointerup=${this._onAlphaPointerUp}
|
|
419
|
+
@pointercancel=${this._onAlphaPointerUp}
|
|
420
|
+
>
|
|
421
|
+
<div
|
|
422
|
+
class="slider-thumb"
|
|
423
|
+
role="slider"
|
|
424
|
+
tabindex=${this.disabled ? '-1' : '0'}
|
|
425
|
+
aria-label="Opacity"
|
|
426
|
+
aria-valuemin="0"
|
|
427
|
+
aria-valuemax="100"
|
|
428
|
+
aria-valuenow=${Math.round(this._opacity * 100)}
|
|
429
|
+
style=${styleMap({ left: `${this._opacity * 100}%` })}
|
|
430
|
+
@keydown=${this._onAlphaKeyDown}
|
|
431
|
+
></div>
|
|
432
|
+
</div>
|
|
433
|
+
` : nothing}
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
|
|
437
|
+
<!-- Hex + alpha inputs -->
|
|
438
|
+
<div class="inputs-row">
|
|
439
|
+
<div class="hex-input-wrapper">
|
|
440
|
+
<span class="input-label">HEX</span>
|
|
441
|
+
<span class="hex-prefix">#</span>
|
|
442
|
+
<input
|
|
443
|
+
class="hex-input"
|
|
444
|
+
type="text"
|
|
445
|
+
inputmode="text"
|
|
446
|
+
maxlength="6"
|
|
447
|
+
spellcheck="false"
|
|
448
|
+
autocomplete="off"
|
|
449
|
+
.value=${this._hexInput}
|
|
450
|
+
?disabled=${this.disabled}
|
|
451
|
+
aria-label="Hex color value"
|
|
452
|
+
@input=${this._onHexInput}
|
|
453
|
+
@change=${this._onHexChange}
|
|
454
|
+
/>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
${this.alpha ? html`
|
|
458
|
+
<div class="alpha-input-wrapper">
|
|
459
|
+
<input
|
|
460
|
+
class="alpha-input"
|
|
461
|
+
type="number"
|
|
462
|
+
min="0"
|
|
463
|
+
max="100"
|
|
464
|
+
step="1"
|
|
465
|
+
.value=${String(Math.round(this._opacity * 100))}
|
|
466
|
+
?disabled=${this.disabled}
|
|
467
|
+
aria-label="Opacity percentage"
|
|
468
|
+
@change=${this._onAlphaNumberChange}
|
|
469
|
+
/>
|
|
470
|
+
<span class="input-label">%</span>
|
|
471
|
+
</div>
|
|
472
|
+
` : nothing}
|
|
473
|
+
</div>
|
|
474
|
+
|
|
475
|
+
</div>
|
|
476
|
+
`;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ColorPicker } from './color-picker.js';
|
package/src/index.ts
CHANGED
|
@@ -51,6 +51,7 @@ export { Image } from './image/index.js';
|
|
|
51
51
|
export { Svg } from './svg/index.js';
|
|
52
52
|
export { Tab, TabGroup, TabPanel, Tabs } from './tabs/index.js';
|
|
53
53
|
export { Slider } from './slider/index.js';
|
|
54
|
+
export { ColorPicker } from './color-picker/index.js';
|
|
54
55
|
export { ChartDoughnut } from './chart-doughnut/index.js';
|
|
55
56
|
export { ChartPie } from './chart-pie/index.js';
|
|
56
57
|
export { ChartBar, ChartStackedBar } from './chart-bar/index.js';
|
package/src/item/item.scss
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
--item-container-color: transparent;
|
|
7
7
|
--item-height: 3rem;
|
|
8
8
|
--item-multiline-height: 4rem;
|
|
9
|
+
--item-label-text-color: var(--color-on-surface);
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
:host {
|
|
@@ -25,7 +26,8 @@
|
|
|
25
26
|
|
|
26
27
|
overflow: hidden;
|
|
27
28
|
|
|
28
|
-
color: var(--item-label-text-color
|
|
29
|
+
color: var(--item-label-text-color);
|
|
30
|
+
--icon-color: var(--item-label-text-color);
|
|
29
31
|
opacity: var(--item-label-text-opacity, 1);
|
|
30
32
|
|
|
31
33
|
font-family: var(
|
package/src/item/item.ts
CHANGED
|
@@ -19,7 +19,6 @@ import { hasMeaningfulContent } from '@/__internal/utils/observe-slot-change.js'
|
|
|
19
19
|
* <wc-item>
|
|
20
20
|
* <wc-icon slot="start" name="notifications"></wc-icon>
|
|
21
21
|
*
|
|
22
|
-
* <span slot="overline">Settings</span>
|
|
23
22
|
* <span slot="headline">Notifications</span>
|
|
24
23
|
* <span slot="supporting-text">Manage alerts and reminders</span>
|
|
25
24
|
*
|
package/src/list/list-item.scss
CHANGED
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
.list-item {
|
|
20
20
|
position: relative;
|
|
21
21
|
width: 100%;
|
|
22
|
-
cursor: pointer;
|
|
23
22
|
text-align: start;
|
|
24
23
|
|
|
25
24
|
.list-item-content {
|
|
@@ -81,6 +80,11 @@
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
|
|
83
|
+
:host([actionable]:not([disabled]):not([soft-disabled])),
|
|
84
|
+
:host([href]:not([disabled]):not([soft-disabled])) {
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
}
|
|
87
|
+
|
|
84
88
|
:host(:not([skeleton])) {
|
|
85
89
|
.skeleton {
|
|
86
90
|
display: none;
|
package/src/list/list-item.ts
CHANGED
|
@@ -49,6 +49,9 @@ export class ListItem extends mixinBaseButton(
|
|
|
49
49
|
/** When true, renders the list-item in a loading skeleton state. */
|
|
50
50
|
@property({ type: Boolean, reflect: true }) skeleton: boolean = false;
|
|
51
51
|
|
|
52
|
+
@property({ type: Boolean, reflect: true })
|
|
53
|
+
actionable: boolean = false;
|
|
54
|
+
|
|
52
55
|
@query('#list-item') readonly itemElement!: HTMLElement | null;
|
|
53
56
|
|
|
54
57
|
constructor() {
|
|
@@ -99,8 +102,13 @@ export class ListItem extends mixinBaseButton(
|
|
|
99
102
|
);
|
|
100
103
|
}
|
|
101
104
|
|
|
105
|
+
isClickable() {
|
|
106
|
+
return this.actionable || isLink(this);
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
render() {
|
|
103
110
|
const isElementLink = isLink(this);
|
|
111
|
+
const clickable = this.isClickable();
|
|
104
112
|
|
|
105
113
|
const cssClasses = {
|
|
106
114
|
'list-item': true,
|
|
@@ -111,6 +119,18 @@ export class ListItem extends mixinBaseButton(
|
|
|
111
119
|
// Needed for closure conformance
|
|
112
120
|
const { ariaLabel } = this as ARIAMixinStrict;
|
|
113
121
|
|
|
122
|
+
if (!clickable) {
|
|
123
|
+
return html`
|
|
124
|
+
<div
|
|
125
|
+
id="list-item"
|
|
126
|
+
class=${classMap(cssClasses)}
|
|
127
|
+
aria-label="${ariaLabel || nothing}"
|
|
128
|
+
>
|
|
129
|
+
${this.renderContent(clickable)}
|
|
130
|
+
</div>
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
|
|
114
134
|
if (!isElementLink) {
|
|
115
135
|
return html`
|
|
116
136
|
<button
|
|
@@ -121,7 +141,7 @@ export class ListItem extends mixinBaseButton(
|
|
|
121
141
|
?aria-disabled=${this.softDisabled}
|
|
122
142
|
@click=${this.__dispatchClick}
|
|
123
143
|
>
|
|
124
|
-
${this.renderContent()}
|
|
144
|
+
${this.renderContent(clickable)}
|
|
125
145
|
</button>
|
|
126
146
|
`;
|
|
127
147
|
}
|
|
@@ -132,18 +152,18 @@ export class ListItem extends mixinBaseButton(
|
|
|
132
152
|
class=${classMap(cssClasses)}
|
|
133
153
|
href=${this.href}
|
|
134
154
|
target=${this.target}
|
|
135
|
-
rel=${
|
|
136
|
-
download=${
|
|
155
|
+
?rel=${this.rel}
|
|
156
|
+
?download=${this.download}
|
|
137
157
|
tabindex=${this.disabled ? '-1' : '0'}
|
|
138
158
|
aria-disabled=${String(this.disabled || this.softDisabled)}
|
|
139
159
|
@click=${this.__dispatchClick}
|
|
140
160
|
>
|
|
141
|
-
${this.renderContent()}
|
|
161
|
+
${this.renderContent(clickable)}
|
|
142
162
|
</a>
|
|
143
163
|
`;
|
|
144
164
|
}
|
|
145
165
|
|
|
146
|
-
renderContent() {
|
|
166
|
+
renderContent(clickable: boolean) {
|
|
147
167
|
const hasLeading = this.__hasNamedSlot('leading');
|
|
148
168
|
const hasTrailingSupportingText = this.__hasNamedSlot(
|
|
149
169
|
'trailing-supporting-text',
|
|
@@ -151,15 +171,21 @@ export class ListItem extends mixinBaseButton(
|
|
|
151
171
|
const hasTrailing = this.__hasNamedSlot('trailing');
|
|
152
172
|
|
|
153
173
|
return html`
|
|
154
|
-
<wc-item class="list-item-content">
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
174
|
+
<wc-item class="list-item-content" ?inert=${clickable}>
|
|
175
|
+
${clickable
|
|
176
|
+
? html`<wc-focus-ring
|
|
177
|
+
class="focus-ring"
|
|
178
|
+
for="list-item"
|
|
179
|
+
slot="container"
|
|
180
|
+
></wc-focus-ring>
|
|
181
|
+
<div class="background" slot="container"></div>
|
|
182
|
+
<wc-ripple
|
|
183
|
+
class="ripple"
|
|
184
|
+
for="list-item"
|
|
185
|
+
slot="container"
|
|
186
|
+
></wc-ripple>
|
|
187
|
+
<wc-skeleton class="skeleton" slot="container"></wc-skeleton> `
|
|
188
|
+
: null}
|
|
163
189
|
|
|
164
190
|
<slot name="leading" slot="start" ?hidden=${!hasLeading}></slot>
|
|
165
191
|
<slot name="overline" slot="overline"></slot>
|