@sken-ds/primitives 0.3.0 → 0.3.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/decorate-D4FKzyDw.js +9 -0
- package/dist/directive-BcLtPdVO.js +263 -0
- package/dist/directive-BcLtPdVO.js.map +1 -0
- package/dist/index.js +14 -0
- package/dist/ix-bridge.css +608 -0
- package/dist/sken-button.js +125 -0
- package/dist/sken-button.js.map +1 -0
- package/dist/sken-checkbox.js +218 -0
- package/dist/sken-checkbox.js.map +1 -0
- package/dist/sken-combobox-group.js +20 -0
- package/dist/sken-combobox-group.js.map +1 -0
- package/dist/sken-combobox-item.js +20 -0
- package/dist/sken-combobox-item.js.map +1 -0
- package/dist/sken-combobox.js +590 -0
- package/dist/sken-combobox.js.map +1 -0
- package/dist/sken-datatable-BtR-NwRN.js +1563 -0
- package/dist/sken-datatable-BtR-NwRN.js.map +1 -0
- package/dist/sken-datatable.js +2 -0
- package/dist/sken-date-picker.js +42 -0
- package/dist/sken-date-picker.js.map +1 -0
- package/dist/sken-dialog-hRtML2jW.js +243 -0
- package/dist/sken-dialog-hRtML2jW.js.map +1 -0
- package/dist/sken-dialog.js +2 -0
- package/dist/sken-filter-chip.js +111 -0
- package/dist/sken-filter-chip.js.map +1 -0
- package/dist/sken-input.js +270 -0
- package/dist/sken-input.js.map +1 -0
- package/dist/sken-number-input.js +538 -0
- package/dist/sken-number-input.js.map +1 -0
- package/dist/sken-switch.js +196 -0
- package/dist/sken-switch.js.map +1 -0
- package/dist/sken-textarea.js +237 -0
- package/dist/sken-textarea.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
+
import { LitElement as t, css as n, html as r } from "lit";
|
|
3
|
+
import { customElement as i, property as a } from "lit/decorators.js";
|
|
4
|
+
//#region src/components/sken-button.ts
|
|
5
|
+
var o = class extends t {
|
|
6
|
+
constructor(...e) {
|
|
7
|
+
super(...e), this.variant = "primary", this.size = "md", this.disabled = !1, this.type = "button", this.ariaLabel = null, this.#e = (e) => {
|
|
8
|
+
if (this.disabled) {
|
|
9
|
+
e.preventDefault(), e.stopImmediatePropagation();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
this.dispatchEvent(new CustomEvent("sken-click", {
|
|
13
|
+
detail: { originalEvent: e },
|
|
14
|
+
bubbles: !0,
|
|
15
|
+
composed: !0
|
|
16
|
+
}));
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
static {
|
|
20
|
+
this.styles = n`
|
|
21
|
+
:host {
|
|
22
|
+
display: inline-block;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
button {
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
gap: var(--sken-2);
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
border: 1px solid transparent;
|
|
32
|
+
border-radius: var(--sken-md);
|
|
33
|
+
background: transparent;
|
|
34
|
+
color: inherit;
|
|
35
|
+
font-family: var(--sken-family-sans);
|
|
36
|
+
font-size: var(--sken-size-md);
|
|
37
|
+
font-weight: 500;
|
|
38
|
+
line-height: 1.25;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
transition:
|
|
43
|
+
background-color 120ms ease,
|
|
44
|
+
border-color 120ms ease,
|
|
45
|
+
color 120ms ease;
|
|
46
|
+
padding: var(--sken-2) var(--sken-4);
|
|
47
|
+
min-height: 2.25rem;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* ── Sizes ────────────────────────────────────────────────── */
|
|
51
|
+
:host([size='sm']) button {
|
|
52
|
+
padding: var(--sken-1) var(--sken-3);
|
|
53
|
+
font-size: var(--sken-size-sm);
|
|
54
|
+
min-height: 1.75rem;
|
|
55
|
+
}
|
|
56
|
+
:host([size='md']) button {
|
|
57
|
+
/* Default styles above. */
|
|
58
|
+
}
|
|
59
|
+
:host([size='lg']) button {
|
|
60
|
+
padding: var(--sken-3) var(--sken-5);
|
|
61
|
+
font-size: var(--sken-size-lg);
|
|
62
|
+
min-height: 2.75rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ── Variants ─────────────────────────────────────────────── */
|
|
66
|
+
:host([variant='primary']) button {
|
|
67
|
+
background: var(--sken-primary);
|
|
68
|
+
color: var(--sken-primary-foreground);
|
|
69
|
+
}
|
|
70
|
+
:host([variant='primary']) button:hover:not(:disabled) {
|
|
71
|
+
background: var(--sken-primary-hover);
|
|
72
|
+
}
|
|
73
|
+
:host([variant='primary']) button:active:not(:disabled) {
|
|
74
|
+
background: var(--sken-primary-active);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:host([variant='secondary']) button {
|
|
78
|
+
background: var(--sken-transparent);
|
|
79
|
+
color: var(--sken-foreground);
|
|
80
|
+
border-color: var(--sken-border);
|
|
81
|
+
}
|
|
82
|
+
:host([variant='secondary']) button:hover:not(:disabled) {
|
|
83
|
+
background: var(--sken-muted);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:host([variant='ghost']) button {
|
|
87
|
+
color: var(--sken-foreground);
|
|
88
|
+
}
|
|
89
|
+
:host([variant='ghost']) button:hover:not(:disabled) {
|
|
90
|
+
background: var(--sken-muted);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* ── States ───────────────────────────────────────────────── */
|
|
94
|
+
button:focus-visible {
|
|
95
|
+
outline: 2px solid var(--sken-ring, currentColor);
|
|
96
|
+
outline-offset: 2px;
|
|
97
|
+
}
|
|
98
|
+
button:disabled {
|
|
99
|
+
cursor: not-allowed;
|
|
100
|
+
opacity: var(--sken-disabled);
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
render() {
|
|
105
|
+
return r`
|
|
106
|
+
<button
|
|
107
|
+
part="button"
|
|
108
|
+
?disabled=${this.disabled}
|
|
109
|
+
type=${this.type}
|
|
110
|
+
@click=${this.#e}
|
|
111
|
+
>
|
|
112
|
+
<slot></slot>
|
|
113
|
+
</button>
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
#e;
|
|
117
|
+
};
|
|
118
|
+
e([a({ reflect: !0 })], o.prototype, "variant", void 0), e([a({ reflect: !0 })], o.prototype, "size", void 0), e([a({
|
|
119
|
+
reflect: !0,
|
|
120
|
+
type: Boolean
|
|
121
|
+
})], o.prototype, "disabled", void 0), e([a()], o.prototype, "type", void 0), e([a({ attribute: "aria-label" })], o.prototype, "ariaLabel", void 0), o = e([i("sken-button")], o);
|
|
122
|
+
//#endregion
|
|
123
|
+
export { o as SkenButton };
|
|
124
|
+
|
|
125
|
+
//# sourceMappingURL=sken-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sken-button.js","names":["#handleClick"],"sources":["../src/components/sken-button.ts"],"sourcesContent":["// ── <sken-button> — framework-ready Web Component ────────────────────\n// Wraps a native <button> with token-driven styles. Contract lives in\n// @sken-ds/contracts; this file is the implementation.\n//\n// Requires @sken-ds/theme/css loaded: every --sken-* variable this\n// component reads comes from the theme. If the theme is missing,\n// styles fall back to initial / inherited values and the button\n// looks broken — intentional, not silent. ADR-0006 / ADR-0004.\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport type { SkenButtonVariant, SkenButtonSize } from '@sken-ds/contracts'\n\n@customElement('sken-button')\nexport class SkenButton extends LitElement {\n @property({ reflect: true }) variant: SkenButtonVariant = 'primary'\n @property({ reflect: true }) size: SkenButtonSize = 'md'\n @property({ reflect: true, type: Boolean }) disabled = false\n @property() type: 'button' | 'submit' | 'reset' = 'button'\n\n // `string | null` matches `lib.dom.d.ts`; the contract normalizes\n // to `string | undefined` for the public API.\n @property({ attribute: 'aria-label' }) override ariaLabel: string | null = null\n\n static styles = css`\n :host {\n display: inline-block;\n }\n\n button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--sken-2);\n box-sizing: border-box;\n border: 1px solid transparent;\n border-radius: var(--sken-md);\n background: transparent;\n color: inherit;\n font-family: var(--sken-family-sans);\n font-size: var(--sken-size-md);\n font-weight: 500;\n line-height: 1.25;\n text-decoration: none;\n white-space: nowrap;\n cursor: pointer;\n transition:\n background-color 120ms ease,\n border-color 120ms ease,\n color 120ms ease;\n padding: var(--sken-2) var(--sken-4);\n min-height: 2.25rem;\n }\n\n /* ── Sizes ────────────────────────────────────────────────── */\n :host([size='sm']) button {\n padding: var(--sken-1) var(--sken-3);\n font-size: var(--sken-size-sm);\n min-height: 1.75rem;\n }\n :host([size='md']) button {\n /* Default styles above. */\n }\n :host([size='lg']) button {\n padding: var(--sken-3) var(--sken-5);\n font-size: var(--sken-size-lg);\n min-height: 2.75rem;\n }\n\n /* ── Variants ─────────────────────────────────────────────── */\n :host([variant='primary']) button {\n background: var(--sken-primary);\n color: var(--sken-primary-foreground);\n }\n :host([variant='primary']) button:hover:not(:disabled) {\n background: var(--sken-primary-hover);\n }\n :host([variant='primary']) button:active:not(:disabled) {\n background: var(--sken-primary-active);\n }\n\n :host([variant='secondary']) button {\n background: var(--sken-transparent);\n color: var(--sken-foreground);\n border-color: var(--sken-border);\n }\n :host([variant='secondary']) button:hover:not(:disabled) {\n background: var(--sken-muted);\n }\n\n :host([variant='ghost']) button {\n color: var(--sken-foreground);\n }\n :host([variant='ghost']) button:hover:not(:disabled) {\n background: var(--sken-muted);\n }\n\n /* ── States ───────────────────────────────────────────────── */\n button:focus-visible {\n outline: 2px solid var(--sken-ring, currentColor);\n outline-offset: 2px;\n }\n button:disabled {\n cursor: not-allowed;\n opacity: var(--sken-disabled);\n }\n `\n\n protected override render() {\n return html`\n <button\n part=\"button\"\n ?disabled=${this.disabled}\n type=${this.type}\n @click=${this.#handleClick}\n >\n <slot></slot>\n </button>\n `\n }\n\n // `composed: true` is required for the event to cross the shadow\n // boundary; `preventDefault` + `stopImmediatePropagation` on a\n // disabled button suppresses the native submit-on-Enter behavior.\n #handleClick = (event: MouseEvent | KeyboardEvent) => {\n if (this.disabled) {\n event.preventDefault()\n event.stopImmediatePropagation()\n return\n }\n this.dispatchEvent(\n new CustomEvent('sken-click', {\n detail: { originalEvent: event },\n bubbles: true,\n composed: true,\n }),\n )\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-button': SkenButton\n }\n}\n"],"mappings":";;;;AAcO,IAAM,IAAN,cAAyB,EAAW;;EA8GzB,aA7G0C,KAAA,UAAA,WACN,KAAA,OAAA,MACG,KAAA,WAAA,IACL,KAAA,OAAA,UAIyB,KAAA,YAAA,MAsG3D,KAAA,MAAA,MAAsC;GACpD,IAAI,KAAK,UAAU;IAEjB,AADA,EAAM,eAAe,GACrB,EAAM,yBAAyB;IAC/B;GACF;GACA,KAAK,cACH,IAAI,YAAY,cAAc;IAC5B,QAAQ,EAAE,eAAe,EAAM;IAC/B,SAAS;IACT,UAAU;GACZ,CAAC,CACH;EACF;;;EAjHgB,KAAA,SAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFnB,SAA4B;EAC1B,OAAO,CAAI;;;oBAGK,KAAK,SAAS;eACnB,KAAK,KAAK;iBACR,KAAKA,GAAa;;;;;CAKjC;CAKA;AAcF;AA3HG,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAIT,EAAA,CAAA,EAAS,EAAE,WAAW,aAAa,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GATtC,IAAA,EAAA,CAAA,EAAc,aAAa,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
+
import { LitElement as t, css as n, html as r } from "lit";
|
|
3
|
+
import { customElement as i, property as a, state as o } from "lit/decorators.js";
|
|
4
|
+
//#region src/components/sken-checkbox.ts
|
|
5
|
+
var s = class extends t {
|
|
6
|
+
constructor(...e) {
|
|
7
|
+
super(...e), this._checked = void 0, this._checkedSet = !1, this.defaultChecked = void 0, this.indeterminate = !1, this.disabled = !1, this.required = !1, this.invalid = !1, this.describedById = void 0, this.name = void 0, this.value = void 0, this._uncontrolled = !1, this.#t = (e) => {
|
|
8
|
+
let t = e.target, n = t.checked;
|
|
9
|
+
if (this.disabled) {
|
|
10
|
+
t.checked = this.#e ? this.checked === !0 : this._uncontrolled;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
this.indeterminate &&= !1, this.#e || (this._uncontrolled = n), this.dispatchEvent(new CustomEvent("sken-change", {
|
|
14
|
+
detail: n,
|
|
15
|
+
bubbles: !0,
|
|
16
|
+
composed: !0
|
|
17
|
+
}));
|
|
18
|
+
}, this.#n = (e) => {
|
|
19
|
+
this.dispatchEvent(new CustomEvent("sken-focus", {
|
|
20
|
+
detail: e,
|
|
21
|
+
bubbles: !0,
|
|
22
|
+
composed: !0
|
|
23
|
+
}));
|
|
24
|
+
}, this.#r = (e) => {
|
|
25
|
+
this.dispatchEvent(new CustomEvent("sken-blur", {
|
|
26
|
+
detail: e,
|
|
27
|
+
bubbles: !0,
|
|
28
|
+
composed: !0
|
|
29
|
+
}));
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
set checked(e) {
|
|
33
|
+
this._checked = e, this._checkedSet = e !== void 0, this.requestUpdate();
|
|
34
|
+
}
|
|
35
|
+
get checked() {
|
|
36
|
+
return this._checked;
|
|
37
|
+
}
|
|
38
|
+
get #e() {
|
|
39
|
+
return this._checkedSet;
|
|
40
|
+
}
|
|
41
|
+
static {
|
|
42
|
+
this.styles = n`
|
|
43
|
+
:host {
|
|
44
|
+
display: inline-block;
|
|
45
|
+
vertical-align: middle;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:host([disabled]) {
|
|
49
|
+
cursor: not-allowed;
|
|
50
|
+
opacity: var(--sken-disabled);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* The <label> wraps the hidden input + visible box + slot
|
|
54
|
+
label. It carries the layout styles so the whole control
|
|
55
|
+
looks like a single inline-flex row. */
|
|
56
|
+
label {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: var(--sken-2);
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
color: var(--sken-foreground);
|
|
62
|
+
font-family: var(--sken-family-sans);
|
|
63
|
+
font-size: var(--sken-size-md);
|
|
64
|
+
line-height: 1.25;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:host([disabled]) label {
|
|
68
|
+
cursor: not-allowed;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
input {
|
|
72
|
+
position: absolute;
|
|
73
|
+
inline-size: 1px;
|
|
74
|
+
block-size: 1px;
|
|
75
|
+
padding: 0;
|
|
76
|
+
margin: -1px;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
clip: rect(0, 0, 0, 0);
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
border: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.box {
|
|
84
|
+
box-sizing: border-box;
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
inline-size: 1.125rem;
|
|
89
|
+
block-size: 1.125rem;
|
|
90
|
+
border: 1px solid var(--sken-border);
|
|
91
|
+
border-radius: var(--sken-sm);
|
|
92
|
+
background: var(--sken-input);
|
|
93
|
+
color: var(--sken-primary-foreground);
|
|
94
|
+
transition:
|
|
95
|
+
background-color 120ms ease,
|
|
96
|
+
border-color 120ms ease;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
:host([data-checked]) .box,
|
|
100
|
+
:host([data-indeterminate]) .box {
|
|
101
|
+
background: var(--sken-primary);
|
|
102
|
+
border-color: var(--sken-primary);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
:host([data-indeterminate]) .box::after {
|
|
106
|
+
content: '';
|
|
107
|
+
inline-size: 0.625rem;
|
|
108
|
+
block-size: 0.125rem;
|
|
109
|
+
background: var(--sken-primary-foreground);
|
|
110
|
+
border-radius: 1px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.box svg {
|
|
114
|
+
inline-size: 100%;
|
|
115
|
+
block-size: 100%;
|
|
116
|
+
fill: none;
|
|
117
|
+
stroke: currentColor;
|
|
118
|
+
stroke-width: 3;
|
|
119
|
+
stroke-linecap: round;
|
|
120
|
+
stroke-linejoin: round;
|
|
121
|
+
}
|
|
122
|
+
.box svg path {
|
|
123
|
+
stroke-dasharray: 24;
|
|
124
|
+
stroke-dashoffset: 24;
|
|
125
|
+
transition: stroke-dashoffset 120ms ease;
|
|
126
|
+
}
|
|
127
|
+
:host([data-checked]) .box svg path {
|
|
128
|
+
stroke-dashoffset: 0;
|
|
129
|
+
}
|
|
130
|
+
:host([data-indeterminate]) .box svg {
|
|
131
|
+
display: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
:host([invalid]) .box {
|
|
135
|
+
border-color: var(--sken-destructive);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:host(:focus-within) .box {
|
|
139
|
+
outline: 2px solid var(--sken-ring, currentColor);
|
|
140
|
+
outline-offset: 2px;
|
|
141
|
+
}
|
|
142
|
+
:host(:focus-within) {
|
|
143
|
+
outline: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.label {
|
|
147
|
+
user-select: none;
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
}
|
|
151
|
+
connectedCallback() {
|
|
152
|
+
super.connectedCallback(), this.#e || (this._uncontrolled = this.defaultChecked ?? !1);
|
|
153
|
+
}
|
|
154
|
+
updated() {
|
|
155
|
+
let e = this.#i();
|
|
156
|
+
if (!e) return;
|
|
157
|
+
let t = (this.#e ? this.checked : this._uncontrolled) ?? !1;
|
|
158
|
+
e.indeterminate = this.indeterminate, e.checked = t, t ? this.setAttribute("data-checked", "") : this.removeAttribute("data-checked"), this.indeterminate ? this.setAttribute("data-indeterminate", "") : this.removeAttribute("data-indeterminate");
|
|
159
|
+
}
|
|
160
|
+
render() {
|
|
161
|
+
return r`
|
|
162
|
+
<label>
|
|
163
|
+
<input
|
|
164
|
+
part="input"
|
|
165
|
+
type="checkbox"
|
|
166
|
+
aria-checked=${this.#e ? String(this.checked) : String(this._uncontrolled)}
|
|
167
|
+
?disabled=${this.disabled}
|
|
168
|
+
?required=${this.required}
|
|
169
|
+
aria-invalid=${this.invalid ? "true" : "false"}
|
|
170
|
+
aria-describedby=${this.describedById ?? ""}
|
|
171
|
+
name=${this.name ?? ""}
|
|
172
|
+
value=${this.value ?? "on"}
|
|
173
|
+
@change=${this.#t}
|
|
174
|
+
@focus=${this.#n}
|
|
175
|
+
@blur=${this.#r}
|
|
176
|
+
/>
|
|
177
|
+
<span class="box" part="box" aria-hidden="true">
|
|
178
|
+
<svg viewBox="0 0 16 16">
|
|
179
|
+
<path d="M3 8.5l3 3 7-7" />
|
|
180
|
+
</svg>
|
|
181
|
+
</span>
|
|
182
|
+
<span class="label" part="label">
|
|
183
|
+
<slot></slot>
|
|
184
|
+
</span>
|
|
185
|
+
</label>
|
|
186
|
+
`;
|
|
187
|
+
}
|
|
188
|
+
#t;
|
|
189
|
+
#n;
|
|
190
|
+
#r;
|
|
191
|
+
#i() {
|
|
192
|
+
return this.shadowRoot?.querySelector("input") ?? null;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
e([a({
|
|
196
|
+
attribute: "checked",
|
|
197
|
+
converter: {
|
|
198
|
+
fromAttribute: (e) => e !== null || void 0,
|
|
199
|
+
toAttribute: (e) => e ? "" : null
|
|
200
|
+
},
|
|
201
|
+
hasChanged: () => !0
|
|
202
|
+
})], s.prototype, "checked", null), e([a({
|
|
203
|
+
attribute: "default-checked",
|
|
204
|
+
type: Boolean
|
|
205
|
+
})], s.prototype, "defaultChecked", void 0), e([a({ type: Boolean })], s.prototype, "indeterminate", void 0), e([a({
|
|
206
|
+
reflect: !0,
|
|
207
|
+
type: Boolean
|
|
208
|
+
})], s.prototype, "disabled", void 0), e([a({
|
|
209
|
+
reflect: !0,
|
|
210
|
+
type: Boolean
|
|
211
|
+
})], s.prototype, "required", void 0), e([a({
|
|
212
|
+
reflect: !0,
|
|
213
|
+
type: Boolean
|
|
214
|
+
})], s.prototype, "invalid", void 0), e([a({ attribute: "described-by-id" })], s.prototype, "describedById", void 0), e([a()], s.prototype, "name", void 0), e([a()], s.prototype, "value", void 0), e([o()], s.prototype, "_uncontrolled", void 0), s = e([i("sken-checkbox")], s);
|
|
215
|
+
//#endregion
|
|
216
|
+
export { s as SkenCheckbox };
|
|
217
|
+
|
|
218
|
+
//# sourceMappingURL=sken-checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sken-checkbox.js","names":["#controlled","#getInput","#handleChange","#handleFocus","#handleBlur"],"sources":["../src/components/sken-checkbox.ts"],"sourcesContent":["// ── <sken-checkbox> — framework-ready Web Component ──────────────────\n// Wraps a native <input type=\"checkbox\"> with a custom-styled box.\n// Three states: checked, unchecked, indeterminate. The indeterminate\n// flag is visual-only (parent checkbox with some children); the\n// form value stays boolean. Requires @sken-ds/theme/css (ADR-0006).\n\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\n@customElement('sken-checkbox')\nexport class SkenCheckbox extends LitElement {\n // `checked` distinguishes \"uncontrolled\" (consumer never\n // assigns the prop) from \"controlled\" (consumer assigns `true`\n // or `false`). Lit's `@property({ type: Boolean })` collapses\n // \"absent\" to `false`, which makes the two cases\n // indistinguishable. We use a custom converter that maps the\n // attribute presence to `true` and the attribute absence to\n // `undefined`, and the prop setter distinguishes `undefined`\n // (\"uncontrolled\") from `true`/`false` (\"controlled\"). The Vue\n // adapter must NOT bind the `checked` prop when the consumer\n // did not pass `:checked`, so the setter is never called and\n // the primitive stays uncontrolled.\n private _checked: boolean | undefined = undefined\n private _checkedSet: boolean = false\n @property({\n attribute: 'checked',\n converter: {\n fromAttribute: (value: string | null) => (value === null ? undefined : true),\n toAttribute: (value: boolean | undefined) => (value ? '' : null),\n },\n hasChanged: () => true,\n })\n set checked(v: boolean | undefined) {\n this._checked = v\n this._checkedSet = v !== undefined\n this.requestUpdate()\n }\n get checked(): boolean | undefined {\n return this._checked\n }\n get #controlled(): boolean {\n return this._checkedSet\n }\n\n @property({ attribute: 'default-checked', type: Boolean })\n defaultChecked: boolean | undefined = undefined\n @property({ type: Boolean }) indeterminate = false\n @property({ reflect: true, type: Boolean }) disabled = false\n @property({ reflect: true, type: Boolean }) required = false\n @property({ reflect: true, type: Boolean }) invalid = false\n @property({ attribute: 'described-by-id' }) describedById: string | undefined = undefined\n @property() name: string | undefined = undefined\n @property() value: string | undefined = undefined\n\n // We use @state (not a private field) for the uncontrolled value so\n // Lit's reactivity picks up changes — without @state, Lit does not\n // re-render or re-run updated() on assignment, and the visual\n // state would not refresh on click.\n @state() private _uncontrolled: boolean = false\n\n static styles = css`\n :host {\n display: inline-block;\n vertical-align: middle;\n }\n\n :host([disabled]) {\n cursor: not-allowed;\n opacity: var(--sken-disabled);\n }\n\n /* The <label> wraps the hidden input + visible box + slot\n label. It carries the layout styles so the whole control\n looks like a single inline-flex row. */\n label {\n display: inline-flex;\n align-items: center;\n gap: var(--sken-2);\n cursor: pointer;\n color: var(--sken-foreground);\n font-family: var(--sken-family-sans);\n font-size: var(--sken-size-md);\n line-height: 1.25;\n }\n\n :host([disabled]) label {\n cursor: not-allowed;\n }\n\n input {\n position: absolute;\n inline-size: 1px;\n block-size: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .box {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: 1.125rem;\n block-size: 1.125rem;\n border: 1px solid var(--sken-border);\n border-radius: var(--sken-sm);\n background: var(--sken-input);\n color: var(--sken-primary-foreground);\n transition:\n background-color 120ms ease,\n border-color 120ms ease;\n }\n\n :host([data-checked]) .box,\n :host([data-indeterminate]) .box {\n background: var(--sken-primary);\n border-color: var(--sken-primary);\n }\n\n :host([data-indeterminate]) .box::after {\n content: '';\n inline-size: 0.625rem;\n block-size: 0.125rem;\n background: var(--sken-primary-foreground);\n border-radius: 1px;\n }\n\n .box svg {\n inline-size: 100%;\n block-size: 100%;\n fill: none;\n stroke: currentColor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n .box svg path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n transition: stroke-dashoffset 120ms ease;\n }\n :host([data-checked]) .box svg path {\n stroke-dashoffset: 0;\n }\n :host([data-indeterminate]) .box svg {\n display: none;\n }\n\n :host([invalid]) .box {\n border-color: var(--sken-destructive);\n }\n\n :host(:focus-within) .box {\n outline: 2px solid var(--sken-ring, currentColor);\n outline-offset: 2px;\n }\n :host(:focus-within) {\n outline: none;\n }\n\n .label {\n user-select: none;\n }\n `\n\n // Seed _uncontrolled from defaultChecked on first connection. Fires\n // only in uncontrolled mode (consumer has not passed `checked`).\n override connectedCallback(): void {\n super.connectedCallback()\n if (!this.#controlled) {\n this._uncontrolled = this.defaultChecked ?? false\n }\n }\n\n // `indeterminate` is a DOM property only (no HTML attribute); we\n // mirror the prop onto the input in updated() so the visual state\n // matches the prop across re-renders.\n protected override updated(): void {\n const input = this.#getInput()\n if (!input) return\n const isChecked = (this.#controlled ? this.checked : this._uncontrolled) ?? false\n input.indeterminate = this.indeterminate\n input.checked = isChecked\n if (isChecked) this.setAttribute('data-checked', '')\n else this.removeAttribute('data-checked')\n if (this.indeterminate) this.setAttribute('data-indeterminate', '')\n else this.removeAttribute('data-indeterminate')\n }\n\n protected override render() {\n // The visible UI (box + label) is wrapped in a `<label>` element\n // so clicking anywhere on it toggles the hidden input. This is\n // the standard WAI-ARIA pattern for a custom-styled checkbox.\n // Without the label, the visually-hidden input would never\n // receive a click event and the checkbox would look inert.\n return html`\n <label>\n <input\n part=\"input\"\n type=\"checkbox\"\n aria-checked=${this.#controlled ? String(this.checked) : String(this._uncontrolled)}\n ?disabled=${this.disabled}\n ?required=${this.required}\n aria-invalid=${this.invalid ? 'true' : 'false'}\n aria-describedby=${this.describedById ?? ''}\n name=${this.name ?? ''}\n value=${this.value ?? 'on'}\n @change=${this.#handleChange}\n @focus=${this.#handleFocus}\n @blur=${this.#handleBlur}\n />\n <span class=\"box\" part=\"box\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\">\n <path d=\"M3 8.5l3 3 7-7\" />\n </svg>\n </span>\n <span class=\"label\" part=\"label\">\n <slot></slot>\n </span>\n </label>\n `\n }\n\n #handleChange = (event: Event) => {\n const target = event.target as HTMLInputElement\n const newValue = target.checked\n // Disabled: the browser already blocks the change, but we\n // double-check here in case `disabled` was toggled\n // programmatically (no click event reaches the input) or\n // mid-flight. Either way, do not advance state.\n if (this.disabled) {\n target.checked = this.#controlled ? this.checked === true : this._uncontrolled\n return\n }\n // Indeterminate → checked: when the user clicks an\n // indeterminate checkbox, the visual should resolve to the\n // checked state. The native browser drops `indeterminate` on\n // the input but our `@property` prop keeps it set, which\n // would otherwise re-apply `indeterminate` on the next\n // `updated()` and leave the visual stuck on the dash. We\n // clear our own prop so the next render is consistent. The\n // consumer is informed via `sken-change` (and can re-set\n // `indeterminate` if their logic calls for it).\n const wasIndeterminate = this.indeterminate\n if (wasIndeterminate) {\n this.indeterminate = false\n }\n // Uncontrolled: update @state, Lit re-renders. Controlled: do\n // nothing locally; the consumer's `:checked` prop change drives\n // the next render and updated() syncs the DOM input.\n if (!this.#controlled) {\n this._uncontrolled = newValue\n }\n this.dispatchEvent(\n new CustomEvent<boolean>('sken-change', { detail: newValue, bubbles: true, composed: true }),\n )\n }\n\n #handleFocus = (event: FocusEvent) => {\n this.dispatchEvent(\n new CustomEvent<FocusEvent>('sken-focus', { detail: event, bubbles: true, composed: true }),\n )\n }\n\n #handleBlur = (event: FocusEvent) => {\n this.dispatchEvent(\n new CustomEvent<FocusEvent>('sken-blur', { detail: event, bubbles: true, composed: true }),\n )\n }\n\n #getInput(): HTMLInputElement | null {\n return this.shadowRoot?.querySelector('input') ?? null\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-checkbox': SkenCheckbox\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
+
import { LitElement as t } from "lit";
|
|
3
|
+
import { customElement as n, property as r } from "lit/decorators.js";
|
|
4
|
+
//#region src/components/sken-combobox-group.ts
|
|
5
|
+
var i = class extends t {
|
|
6
|
+
constructor(...e) {
|
|
7
|
+
super(...e), this.label = "", this.disabled = !1;
|
|
8
|
+
}
|
|
9
|
+
createRenderRoot() {
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
e([r()], i.prototype, "label", void 0), e([r({
|
|
14
|
+
type: Boolean,
|
|
15
|
+
reflect: !0
|
|
16
|
+
})], i.prototype, "disabled", void 0), i = e([n("sken-combobox-group")], i);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { i as SkenComboboxGroup };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=sken-combobox-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sken-combobox-group.js","names":[],"sources":["../src/components/sken-combobox-group.ts"],"sourcesContent":["/**\n * `<sken-combobox-group>` — Sken combobox group primitive.\n *\n * Group container for `<sken-combobox-item>` children. Same\n * marker pattern as `<sken-combobox-item>`: this element does\n * NOT render anything. The parent `<sken-combobox>` introspects\n * the host's children to build a nested listbox model where\n * each item knows which group it belongs to.\n *\n * <sken-combobox label=\"Hardware\">\n * <sken-combobox-group label=\"Detectores\">\n * <sken-combobox-item value=\"humo\" label=\"Detector de humo\"></sken-combobox-item>\n * <sken-combobox-item value=\"caida\" label=\"Detector de caída\"></sken-combobox-item>\n * </sken-combobox-group>\n * <sken-combobox-group label=\"Comunicadores\">\n * <sken-combobox-item value=\"gsm\" label=\"Comunicador GSM\"></sken-combobox-item>\n * </sken-combobox-group>\n * </sken-combobox>\n *\n * The parent introspects the host with\n * `host.querySelectorAll('sken-combobox-group')` and walks each\n * group's children to associate items with their group. Items\n * that are direct children of the combobox (not inside a group)\n * belong to an implicit \"ungrouped\" bucket.\n *\n * Filter behaviour: when the combobox filters, a group hides\n * itself when ALL of its items are filtered out. A group with\n * at least one visible item stays visible. An ungrouped item\n * follows the same rule (it's its own \"group of one\").\n *\n * ARIA: the parent projects the rendered listbox with\n * `role=\"group\"` + `aria-labelledby` pointing to the group's\n * label. The group itself is a marker; the rendered ARIA\n * surface lives in the parent's Shadow DOM.\n */\nimport { LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('sken-combobox-group')\nexport class SkenComboboxGroup extends LitElement {\n /** Group header text. Rendered as the group's accessible name. */\n @property() label = ''\n\n /**\n * Disabled state. When true, the entire group and all its\n * descendant items are non-selectable. The combobox still\n * renders them (so the user can see the structure) but skips\n * them in the keyboard navigation model.\n * @default false\n */\n @property({ type: Boolean, reflect: true })\n disabled = false\n\n /**\n * Marker element. Renders nothing. The parent\n * `<sken-combobox>` introspects this element via\n * `host.querySelectorAll('sken-combobox-group')` and walks\n * its children to associate items with the group.\n */\n protected override createRenderRoot(): HTMLElement {\n return this as unknown as HTMLElement\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-combobox-group': SkenComboboxGroup\n }\n}\n"],"mappings":";;;;AAuCO,IAAM,IAAN,cAAgC,EAAW;;EAYrC,aAVS,KAAA,QAAA,IAUT,KAAA,WAAA;;CAQX,mBAAmD;EACjD,OAAO;CACT;AACF;AArBG,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,SAAA,KAAA,CAAA,GAST,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAZ3C,IAAA,EAAA,CAAA,EAAc,qBAAqB,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as e } from "./decorate-D4FKzyDw.js";
|
|
2
|
+
import { LitElement as t } from "lit";
|
|
3
|
+
import { customElement as n, property as r } from "lit/decorators.js";
|
|
4
|
+
//#region src/components/sken-combobox-item.ts
|
|
5
|
+
var i = class extends t {
|
|
6
|
+
constructor(...e) {
|
|
7
|
+
super(...e), this.value = "", this.label = "", this.disabled = !1;
|
|
8
|
+
}
|
|
9
|
+
createRenderRoot() {
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
e([r()], i.prototype, "value", void 0), e([r()], i.prototype, "label", void 0), e([r({
|
|
14
|
+
type: Boolean,
|
|
15
|
+
reflect: !0
|
|
16
|
+
})], i.prototype, "disabled", void 0), i = e([n("sken-combobox-item")], i);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { i as SkenComboboxItem };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=sken-combobox-item.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sken-combobox-item.js","names":[],"sources":["../src/components/sken-combobox-item.ts"],"sourcesContent":["/**\n * `<sken-combobox-item>` — Sken combobox option primitive.\n *\n * This element does NOT render anything. It is a \"marker\" Web\n * Component that the parent `<sken-combobox>` introspects to\n * build its internal listbox model. The marker pattern matches\n * the upstream iX 5 `<ix-select-item>` and keeps the slot/portal\n * /Shadow-DOM choreography out of the way of a simple\n * declarative API:\n *\n * <sken-combobox label=\"Hardware\">\n * <sken-combobox-item value=\"humo\" label=\"Detector de humo\"></sken-combobox-item>\n * <sken-combobox-item value=\"caida\" label=\"Detector de caída\"></sken-combobox-item>\n * </sken-combobox>\n *\n * Why a custom element at all if it doesn't render anything?\n * Three reasons, in priority order:\n *\n * 1. **Type safety.** The props (`value`, `label`, `disabled`)\n * are checked by TypeScript on the consumer side. A typo\n * `sken-combobox-item lablel=\"x\"` is a compile error, not a\n * silent runtime miss.\n *\n * 2. **Discoverability.** The element shows up in the Sken catalog\n * (`COMPONENTS.md`) and in Storybook's sidebar. The consumer\n * finds it via search / autocomplete.\n *\n * 3. **Framework adapter parity.** The Vue adapter renders the\n * same `<sken-combobox-item>` element via Vue's templating;\n * no special path needed.\n *\n * The \"marker\" pattern is documented in the iX 5 reference\n * implementation (`<ix-select-item>`). The trade-off is that\n * `<sken-combobox-item>` does not appear in the rendered DOM tree\n * as itself — the parent `<sken-combobox>` projects the items\n * into its own Shadow DOM listbox. This is by design: the\n * listbox is a Sken concern, not a per-item concern.\n *\n * The props mirror the `SkenComboboxItemProps` contract in\n * `@sken-ds/contracts`. The contract is the source of truth; this\n * class is the runtime implementation.\n */\nimport { LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('sken-combobox-item')\nexport class SkenComboboxItem extends LitElement {\n /** Stable identifier. Forwarded to the parent on selection. */\n @property() value = ''\n\n /** Human-readable text shown in the trigger and the dropdown. */\n @property() label = ''\n\n /** Disabled state. @default false */\n @property({ type: Boolean, reflect: true })\n disabled = false\n\n /**\n * Marker element. Renders nothing. The parent\n * `<sken-combobox>` introspects this element via\n * `host.querySelectorAll('sken-combobox-item')` and projects\n * the items into its own Shadow DOM listbox.\n */\n protected override createRenderRoot(): HTMLElement {\n return this as unknown as HTMLElement\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-combobox-item': SkenComboboxItem\n }\n}\n"],"mappings":";;;;AA8CO,IAAM,IAAN,cAA+B,EAAW;;EASpC,aAPS,KAAA,QAAA,IAGA,KAAA,QAAA,IAIT,KAAA,WAAA;;CAQX,mBAAmD;EACjD,OAAO;CACT;AACF;AAlBG,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,SAAA,KAAA,CAAA,GAGT,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,SAAA,KAAA,CAAA,GAGT,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAT3C,IAAA,EAAA,CAAA,EAAc,oBAAoB,CAAA,GAAA,CAAA"}
|