@kubex/zinc 1.1.48 → 1.1.49

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.
@@ -0,0 +1,34 @@
1
+ ---
2
+ meta:
3
+ title: Color Select
4
+ description: A simple color picker. The dropdown lists color swatches with names; the closed control shows only the selected color's swatch.
5
+ layout: component
6
+ ---
7
+
8
+ ```html:preview
9
+ <zn-color-select label="Color" name="color"></zn-color-select>
10
+ ```
11
+
12
+ ## Examples
13
+
14
+ ### With a Default Value
15
+
16
+ Set the selected color with the `value` attribute (lowercase color name).
17
+
18
+ ```html:preview
19
+ <zn-color-select label="Color" name="color" value="blue"></zn-color-select>
20
+ ```
21
+
22
+ ### Clearable
23
+
24
+ Add the `clearable` attribute to show a clear button when a color is selected.
25
+
26
+ ```html:preview
27
+ <zn-color-select label="Color" name="color" value="green" clearable></zn-color-select>
28
+ ```
29
+
30
+ ### Help Text
31
+
32
+ ```html:preview
33
+ <zn-color-select label="Color" name="color" help-text="Pick a color for the label."></zn-color-select>
34
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubex/zinc",
3
- "version": "1.1.48",
3
+ "version": "1.1.49",
4
4
  "description": "A collection of web components for building web applications based off of @shoelace-style/Shoelace",
5
5
  "keywords": [
6
6
  "web components",
@@ -224,8 +224,12 @@ export default class ZnChannelTile extends ZincElement {
224
224
  ${this._renderLeading()}
225
225
  <div class="channel-tile__content">
226
226
  ${remaining !== null
227
- ? html`
228
- <h3 class="channel-tile__title">${this.subtitle} (${remaining}s)</h3>`
227
+ ? this.title
228
+ ? html`
229
+ <h3 class="channel-tile__title"><slot name="title">${this.title}</slot></h3>
230
+ <p class="channel-tile__subtitle">${this.subtitle} (${remaining}s)</p>`
231
+ : html`
232
+ <h3 class="channel-tile__title">${this.subtitle} (${remaining}s)</h3>`
229
233
  : html`
230
234
  <h3 class="channel-tile__title"><slot name="title">${title}</slot></h3>
231
235
  <p class="channel-tile__subtitle"><slot name="subtitle">${this.subtitle}</slot></p>`}
@@ -0,0 +1,123 @@
1
+ import {colors} from "../data-select/providers/color-data-provider";
2
+ import {type CSSResultGroup, html, nothing, unsafeCSS} from 'lit';
3
+ import {FormControlController} from "../../internal/form";
4
+ import {property, query} from 'lit/decorators.js';
5
+ import {watch} from "../../internal/watch";
6
+ import ZincElement from '../../internal/zinc-element';
7
+ import ZnOption from "../option";
8
+ import ZnSelect from "../select";
9
+ import type {ZincFormControl} from '../../internal/zinc-element';
10
+
11
+ import styles from './color-select.scss';
12
+
13
+ /**
14
+ * @summary A simple color picker. The dropdown lists color swatches with names; the closed control shows only the selected color's swatch.
15
+ * @documentation https://zinc.style/components/color-select
16
+ * @status experimental
17
+ * @since 1.0
18
+ *
19
+ * @dependency zn-select
20
+ * @dependency zn-option
21
+ *
22
+ * @event zn-input - Emitted when the selected color changes.
23
+ * @event zn-clear - Emitted when the clear button is activated.
24
+ *
25
+ * @csspart swatch - The color swatch shown in the closed control.
26
+ * @csspart combobox - The container that wraps the swatch and expand button (forwarded from zn-select).
27
+ * @csspart form-control-help-text - The help text's wrapper (forwarded from zn-select).
28
+ * @csspart form-control-input - The select's wrapper (forwarded from zn-select).
29
+ */
30
+ export default class ZnColorSelect extends ZincElement implements ZincFormControl {
31
+ static styles: CSSResultGroup = unsafeCSS(styles);
32
+ static dependencies = {
33
+ 'zn-select': ZnSelect,
34
+ 'zn-option': ZnOption,
35
+ };
36
+
37
+ @query('#select') select: ZnSelect;
38
+
39
+ /** The name of the select. Used for form submission. */
40
+ @property() name: string;
41
+
42
+ /** The selected color (lowercase name, e.g. "red"). Used for form submission. */
43
+ @property() value = '';
44
+
45
+ /** The select's label. */
46
+ @property() label = '';
47
+
48
+ /** The select's help text. */
49
+ @property({attribute: 'help-text'}) helpText = '';
50
+
51
+ /** Disables the select. */
52
+ @property({type: Boolean, reflect: true}) disabled = false;
53
+
54
+ /** Makes the select a required field. */
55
+ @property({type: Boolean, reflect: true}) required = false;
56
+
57
+ /** Shows a clear button when a color is selected. */
58
+ @property({type: Boolean}) clearable = false;
59
+
60
+ private readonly formControlController = new FormControlController(this);
61
+
62
+ get validity(): ValidityState {
63
+ return this.select.validity;
64
+ }
65
+
66
+ get validationMessage(): string {
67
+ return this.select.validationMessage;
68
+ }
69
+
70
+ checkValidity(): boolean {
71
+ return this.select.checkValidity();
72
+ }
73
+
74
+ getForm(): HTMLFormElement | null {
75
+ return this.formControlController.getForm();
76
+ }
77
+
78
+ reportValidity(): boolean {
79
+ return this.select.reportValidity();
80
+ }
81
+
82
+ setCustomValidity(message: string): void {
83
+ this.select.setCustomValidity(message);
84
+ }
85
+
86
+ @watch('value', {waitUntilFirstUpdate: true})
87
+ handleValueChange() {
88
+ this.formControlController.updateValidity();
89
+ }
90
+
91
+ private handleInput = (e: Event) => {
92
+ const target = e.target as ZnSelect;
93
+ this.value = (target.value as string) ?? '';
94
+ };
95
+
96
+ private handleClear = () => {
97
+ this.value = '';
98
+ };
99
+
100
+ protected render() {
101
+ return html`
102
+ <zn-select id="select"
103
+ placement="bottom-start"
104
+ label="${this.label}"
105
+ help-text="${this.helpText}"
106
+ name="${this.name}"
107
+ clearable=${this.clearable || nothing}
108
+ required=${this.required || nothing}
109
+ ?disabled="${this.disabled}"
110
+ .value="${this.value}"
111
+ @zn-input="${this.handleInput}"
112
+ @zn-clear="${this.handleClear}"
113
+ exportparts="combobox,form-control-help-text,form-control-input">
114
+ <div slot="prefix" part="swatch"
115
+ class="color-swatch ${this.value ? `color-swatch--${this.value}` : 'color-swatch--empty'}"></div>
116
+ ${colors.map(color => html`
117
+ <zn-option value="${color.toLowerCase()}">
118
+ <div slot="prefix" class="color-swatch color-swatch--${color.toLowerCase()}"></div>
119
+ ${color}
120
+ </zn-option>`)}
121
+ </zn-select>`;
122
+ }
123
+ }
@@ -0,0 +1,78 @@
1
+ @use "../../wc";
2
+
3
+ // Same palette as data-select's color provider
4
+ $colors: (
5
+ red: var(--zn-color-red-500),
6
+ blue: var(--zn-color-blue-500),
7
+ orange: var(--zn-color-orange-500),
8
+ yellow: var(--zn-color-yellow-400),
9
+ indigo: var(--zn-color-indigo-500),
10
+ violet: var(--zn-color-violet-500),
11
+ green: var(--zn-color-green-500),
12
+ pink: var(--zn-color-pink-500),
13
+ gray: var(--zn-color-gray-500)
14
+ );
15
+
16
+ // Only wide enough for the swatch and the expand icon
17
+ :host {
18
+ display: inline-block;
19
+ }
20
+
21
+ .color-swatch {
22
+ width: var(--zn-spacing-small);
23
+ height: var(--zn-spacing-small);
24
+ display: block;
25
+ border-radius: var(--zn-border-radius-circle);
26
+ flex-shrink: 0;
27
+
28
+ @each $name, $color in $colors {
29
+ &--#{"" + $name} {
30
+ background-color: #{$color};
31
+ }
32
+ }
33
+
34
+ &--empty {
35
+ border: 1px dashed var(--zn-color-neutral-400);
36
+ }
37
+ }
38
+
39
+ // Never stretch to label/help-text width — only fit the swatch and controls
40
+ zn-select::part(combobox) {
41
+ width: fit-content;
42
+ padding-inline-end: var(--zn-spacing-2x-small);
43
+ }
44
+
45
+ // Preview shows only the swatch — collapse the text input entirely
46
+ zn-select::part(display-input) {
47
+ width: 0;
48
+ min-width: 0;
49
+ color: transparent;
50
+ caret-color: transparent;
51
+ }
52
+
53
+ // Let the dropdown grow to fit swatch + name instead of matching the control's width
54
+ zn-select::part(listbox) {
55
+ min-width: max-content;
56
+ max-height: 300px;
57
+ padding-block: 0;
58
+ }
59
+
60
+ // Tighten the combobox: small, even gaps between swatch, clear button and chevron
61
+ .color-swatch[part="swatch"] {
62
+ margin-inline-start: var(--zn-spacing-x-small);
63
+ margin-inline-end: 0;
64
+ }
65
+
66
+ // Gap between swatch and name in the dropdown list
67
+ zn-option .color-swatch {
68
+ margin-inline-end: var(--zn-spacing-x-small);
69
+ }
70
+
71
+ zn-select::part(clear-button),
72
+ zn-select::part(expand-icon) {
73
+ margin-inline-start: var(--zn-spacing-2x-small);
74
+ }
75
+
76
+ zn-select::part(clear-button) {
77
+ margin-inline-start: var(--zn-spacing-x-small);
78
+ }
@@ -0,0 +1,28 @@
1
+ import '../../../dist/zn.min.js';
2
+ import {expect, fixture, html} from '@open-wc/testing';
3
+
4
+ describe('<zn-color-select>', () => {
5
+ it('should render a component', async () => {
6
+ const el = await fixture(html`<zn-color-select></zn-color-select>`);
7
+ expect(el).to.exist;
8
+ expect(el.shadowRoot).to.exist;
9
+ });
10
+
11
+ it('should list the nine built-in colors', async () => {
12
+ const el = await fixture(html`<zn-color-select></zn-color-select>`);
13
+ const options = el.shadowRoot!.querySelectorAll('zn-option');
14
+ expect(options.length).to.equal(9);
15
+ });
16
+
17
+ it('should show the selected color swatch in the preview', async () => {
18
+ const el = await fixture(html`<zn-color-select value="red"></zn-color-select>`);
19
+ const swatch = el.shadowRoot!.querySelector('[slot="prefix"]')!;
20
+ expect(swatch.classList.contains('color-swatch--red')).to.be.true;
21
+ });
22
+
23
+ it('should show an empty swatch when no color is selected', async () => {
24
+ const el = await fixture(html`<zn-color-select></zn-color-select>`);
25
+ const swatch = el.shadowRoot!.querySelector('[slot="prefix"]')!;
26
+ expect(swatch.classList.contains('color-swatch--empty')).to.be.true;
27
+ });
28
+ });
@@ -0,0 +1,12 @@
1
+ import ZnColorSelect from './color-select.component';
2
+
3
+ export * from './color-select.component';
4
+ export default ZnColorSelect;
5
+
6
+ ZnColorSelect.define('zn-color-select');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-color-select': ZnColorSelect;
11
+ }
12
+ }
package/src/zinc.ts CHANGED
@@ -73,6 +73,7 @@ export { default as File } from './components/file';
73
73
  export { default as CheckboxGroup } from './components/checkbox-group';
74
74
  export { default as Item } from './components/item';
75
75
  export { default as DataSelect } from './components/data-select';
76
+ export { default as ColorSelect } from './components/color-select';
76
77
  export { default as ButtonMenu } from './components/button-menu';
77
78
  export { default as HoverContainer } from './components/hover-container';
78
79
  export { default as Slideout } from './components/slideout';