@sken-ds/primitives 0.3.7 → 0.3.8
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/index.js +7 -7
- package/dist/ix-bridge.css +20 -20
- package/dist/sken-button.js.map +1 -1
- package/dist/sken-checkbox.js.map +1 -1
- package/dist/sken-combobox.js +51 -42
- package/dist/sken-combobox.js.map +1 -1
- package/dist/{sken-datatable-BtR-NwRN.js → sken-datatable-ChDjB_T_.js} +7 -9
- package/dist/{sken-datatable-BtR-NwRN.js.map → sken-datatable-ChDjB_T_.js.map} +1 -1
- package/dist/sken-datatable.js +1 -1
- package/dist/sken-date-picker.js.map +1 -1
- package/dist/{sken-dialog-hRtML2jW.js → sken-dialog-CLqZu1WQ.js} +33 -18
- package/dist/sken-dialog-CLqZu1WQ.js.map +1 -0
- package/dist/sken-dialog.js +1 -1
- package/dist/sken-filter-chip.js +16 -10
- package/dist/sken-filter-chip.js.map +1 -1
- package/dist/sken-input.js.map +1 -1
- package/dist/sken-layout.js +110 -20
- package/dist/sken-layout.js.map +1 -1
- package/dist/sken-number-input.js +32 -42
- package/dist/sken-number-input.js.map +1 -1
- package/dist/sken-switch.js.map +1 -1
- package/dist/sken-textarea.js.map +1 -1
- package/package.json +2 -2
- package/dist/sken-dialog-hRtML2jW.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { t as e } from "./sken-datatable-
|
|
1
|
+
import { t as e } from "./sken-datatable-ChDjB_T_.js";
|
|
2
2
|
import { SkenButton as t } from "./sken-button.js";
|
|
3
3
|
import { SkenCheckbox as n } from "./sken-checkbox.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { SkenComboboxGroup as r } from "./sken-combobox-group.js";
|
|
5
|
+
import { SkenComboboxItem as i } from "./sken-combobox-item.js";
|
|
6
|
+
import { SkenFilterChip as a } from "./sken-filter-chip.js";
|
|
7
|
+
import { SkenCombobox as o } from "./sken-combobox.js";
|
|
8
8
|
import { SkenDatePicker as s } from "./sken-date-picker.js";
|
|
9
|
-
import { t as c } from "./sken-dialog-
|
|
9
|
+
import { t as c } from "./sken-dialog-CLqZu1WQ.js";
|
|
10
10
|
import { SkenInput as l } from "./sken-input.js";
|
|
11
11
|
import { SkenLayoutRegion as u } from "./sken-layout-region.js";
|
|
12
12
|
import { SkenLayout as d } from "./sken-layout.js";
|
|
13
13
|
import { SkenNumberInput as f } from "./sken-number-input.js";
|
|
14
14
|
import { SkenSwitch as p } from "./sken-switch.js";
|
|
15
15
|
import { SkenTextarea as m } from "./sken-textarea.js";
|
|
16
|
-
export { t as SkenButton, n as SkenCheckbox,
|
|
16
|
+
export { t as SkenButton, n as SkenCheckbox, o as SkenCombobox, r as SkenComboboxGroup, i as SkenComboboxItem, e as SkenDataTable, s as SkenDatePicker, c as SkenDialog, a as SkenFilterChip, l as SkenInput, d as SkenLayout, u as SkenLayoutRegion, f as SkenNumberInput, p as SkenSwitch, m as SkenTextarea };
|
package/dist/ix-bridge.css
CHANGED
|
@@ -158,7 +158,7 @@ ix-icon {
|
|
|
158
158
|
* shadow-DOM inheritance trap (see the docstring at the top
|
|
159
159
|
* of the file). Their values are kept here so the "literal
|
|
160
160
|
* hex" cost is paid once, not at every use site. */
|
|
161
|
-
html[data-theme=
|
|
161
|
+
html[data-theme='light'] {
|
|
162
162
|
/* iX-classic values that have no direct Sken token but are
|
|
163
163
|
* needed as the *resolved* colour of certain shadow-trap
|
|
164
164
|
* tokens. The shadow reads the value as a literal; we
|
|
@@ -180,7 +180,7 @@ html[data-theme="light"] {
|
|
|
180
180
|
* "TODO(ux-tokens" in this file to find both. */
|
|
181
181
|
--sken-bridge-ix-scrollbar-thumb-hover: #8a8f99;
|
|
182
182
|
}
|
|
183
|
-
html[data-theme=
|
|
183
|
+
html[data-theme='dark'] {
|
|
184
184
|
--sken-bridge-ix-select-icon: var(--sken-muted-foreground);
|
|
185
185
|
--sken-bridge-ix-primary: var(--sken-primary-hover);
|
|
186
186
|
--sken-bridge-ix-scrollbar-track: var(--sken-card);
|
|
@@ -191,7 +191,7 @@ html[data-theme="dark"] {
|
|
|
191
191
|
* above. Replace with a Sken token once UX ships it. */
|
|
192
192
|
--sken-bridge-ix-scrollbar-thumb-hover: #5a7ba8;
|
|
193
193
|
}
|
|
194
|
-
html[data-theme=
|
|
194
|
+
html[data-theme='hc-light'] {
|
|
195
195
|
--sken-bridge-ix-select-icon: var(--sken-foreground);
|
|
196
196
|
--sken-bridge-ix-primary: var(--sken-foreground);
|
|
197
197
|
--sken-bridge-ix-scrollbar-track: var(--sken-background);
|
|
@@ -200,7 +200,7 @@ html[data-theme="hc-light"] {
|
|
|
200
200
|
--sken-bridge-ix-scrollbar-thumb: var(--sken-foreground);
|
|
201
201
|
--sken-bridge-ix-scrollbar-thumb-hover: var(--sken-foreground);
|
|
202
202
|
}
|
|
203
|
-
html[data-theme=
|
|
203
|
+
html[data-theme='hc-dark'] {
|
|
204
204
|
--sken-bridge-ix-select-icon: var(--sken-background);
|
|
205
205
|
--sken-bridge-ix-primary: var(--sken-background);
|
|
206
206
|
--sken-bridge-ix-scrollbar-track: var(--sken-foreground);
|
|
@@ -211,10 +211,10 @@ html[data-theme="hc-dark"] {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
/* ── Theme: light ──────────────────────────────────────────── */
|
|
214
|
-
html[data-theme=
|
|
215
|
-
html[data-theme=
|
|
216
|
-
html[data-theme=
|
|
217
|
-
html[data-theme=
|
|
214
|
+
html[data-theme='light'] ix-select,
|
|
215
|
+
html[data-theme='light'] ix-date-input,
|
|
216
|
+
html[data-theme='light'] sken-combobox,
|
|
217
|
+
html[data-theme='light'] sken-date-picker {
|
|
218
218
|
--theme-color-1: var(--sken-card);
|
|
219
219
|
--theme-color-2: var(--sken-muted);
|
|
220
220
|
--theme-color-3: var(--sken-muted);
|
|
@@ -339,10 +339,10 @@ html[data-theme="light"] sken-date-picker {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
/* ── Theme: dark ───────────────────────────────────────────── */
|
|
342
|
-
html[data-theme=
|
|
343
|
-
html[data-theme=
|
|
344
|
-
html[data-theme=
|
|
345
|
-
html[data-theme=
|
|
342
|
+
html[data-theme='dark'] ix-select,
|
|
343
|
+
html[data-theme='dark'] ix-date-input,
|
|
344
|
+
html[data-theme='dark'] sken-combobox,
|
|
345
|
+
html[data-theme='dark'] sken-date-picker {
|
|
346
346
|
--theme-color-1: var(--sken-card);
|
|
347
347
|
--theme-color-2: var(--sken-muted);
|
|
348
348
|
--theme-color-3: var(--sken-muted);
|
|
@@ -434,10 +434,10 @@ html[data-theme="dark"] sken-date-picker {
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
/* ── Theme: hc-light (high contrast light) ────────────────── */
|
|
437
|
-
html[data-theme=
|
|
438
|
-
html[data-theme=
|
|
439
|
-
html[data-theme=
|
|
440
|
-
html[data-theme=
|
|
437
|
+
html[data-theme='hc-light'] ix-select,
|
|
438
|
+
html[data-theme='hc-light'] ix-date-input,
|
|
439
|
+
html[data-theme='hc-light'] sken-combobox,
|
|
440
|
+
html[data-theme='hc-light'] sken-date-picker {
|
|
441
441
|
--theme-color-1: var(--sken-background);
|
|
442
442
|
--theme-color-2: var(--sken-background);
|
|
443
443
|
--theme-color-3: var(--sken-background);
|
|
@@ -521,10 +521,10 @@ html[data-theme="hc-light"] sken-date-picker {
|
|
|
521
521
|
}
|
|
522
522
|
|
|
523
523
|
/* ── Theme: hc-dark (high contrast dark) ───────────────────── */
|
|
524
|
-
html[data-theme=
|
|
525
|
-
html[data-theme=
|
|
526
|
-
html[data-theme=
|
|
527
|
-
html[data-theme=
|
|
524
|
+
html[data-theme='hc-dark'] ix-select,
|
|
525
|
+
html[data-theme='hc-dark'] ix-date-input,
|
|
526
|
+
html[data-theme='hc-dark'] sken-combobox,
|
|
527
|
+
html[data-theme='hc-dark'] sken-date-picker {
|
|
528
528
|
--theme-color-1: var(--sken-foreground);
|
|
529
529
|
--theme-color-2: var(--sken-foreground);
|
|
530
530
|
--theme-color-3: var(--sken-foreground);
|
package/dist/sken-button.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sken-button.js","names":["#internals","#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 {
|
|
1
|
+
{"version":3,"file":"sken-button.js","names":["#internals","#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 type { SkenButtonSize, SkenButtonVariant } from '@sken-ds/contracts'\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('sken-button')\nexport class SkenButton extends LitElement {\n // Form-associated custom element: opt in to the ElementInternals\n // API so this primitive can reach its surrounding <form> via\n // `internals.form`. We do NOT publish a value to FormData\n // (this is a button, not an input), but we DO need form\n // access for the `submit` and `reset` click bridges below.\n // https://lit.dev/docs/components/form/\n static formAssociated = true\n\n // The ElementInternals instance. Created in the constructor\n // via attachInternals(), which the browser only makes\n // available because `formAssociated` is true. Nullable to\n // gracefully degrade in test environments without\n // ElementInternals.\n #internals: ElementInternals | null = null\n\n constructor() {\n super()\n try {\n this.#internals = this.attachInternals()\n } catch {\n this.#internals = null\n }\n }\n\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 `sken-click` event to\n // cross the shadow boundary; `preventDefault` +\n // `stopImmediatePropagation` on a disabled button suppresses the\n // native submit-on-Enter behavior.\n //\n // For `type=\"submit\"` and `type=\"reset\"` we ALSO bridge the\n // shadow boundary so the surrounding <form> receives the\n // submit / reset. Without this, the inner <button type=\"submit\">'s\n // default action submits the (notional) form inside the shadow\n // root, which doesn't exist — no `submit` event ever reaches the\n // outer light-DOM form. `internals.form.requestSubmit()` is the\n // modern, non-deprecated API; it dispatches a real `submit` event\n // on the form and runs constraint validation. `form.reset()` is\n // the standard form reset method. We `preventDefault()` to\n // suppress the inner button's default action (submit/reset the\n // shadow form) so the bridge is the only path. Without it we\n // would get a phantom submit to a nonexistent form AND a\n // requestSubmit to the real one. (Tested with happy-dom: phantom\n // submit is a no-op there because the shadow form doesn't exist,\n // but on a real browser it would dispatch a submit event to a\n // formless button — harmless but noisy.)\n //\n // The `sken-click` event is dispatched for every type so\n // consumers can listen to it regardless of whether they put the\n // handler on the button or on the form. Consumers that want\n // submit-only handling should listen to the form's `submit`\n // event, not the button's click — same as native HTML.\n #handleClick = (event: MouseEvent | KeyboardEvent) => {\n if (this.disabled) {\n event.preventDefault()\n event.stopImmediatePropagation()\n return\n }\n const form = this.#internals?.form\n if (this.type === 'submit' && form) {\n event.preventDefault()\n form.requestSubmit()\n } else if (this.type === 'reset' && form) {\n event.preventDefault()\n form.reset()\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;;EAOjB,KAAA,iBAAA;;CAOxB;CAEA,cAAc;EA8IE,AA7Id,MAAM,GAH8B,KAAA,KAAA,MAWoB,KAAA,UAAA,WACN,KAAA,OAAA,MACG,KAAA,WAAA,IACL,KAAA,OAAA,UAIyB,KAAA,YAAA,MA8H3D,KAAA,MAAA,MAAsC;GACpD,IAAI,KAAK,UAAU;IAEjB,AADA,EAAM,eAAe,GACrB,EAAM,yBAAyB;IAC/B;GACF;GACA,IAAM,IAAO,KAAKA,IAAY;GAQ9B,AAPI,KAAK,SAAS,YAAY,KAC5B,EAAM,eAAe,GACrB,EAAK,cAAc,KACV,KAAK,SAAS,WAAW,MAClC,EAAM,eAAe,GACrB,EAAK,MAAM,IAEb,KAAK,cACH,IAAI,YAAY,cAAc;IAC5B,QAAQ,EAAE,eAAe,EAAM;IAC/B,SAAS;IACT,UAAU;GACZ,CAAC,CACH;EACF;EAjKE,IAAI;GACF,KAAKA,KAAa,KAAK,gBAAgB;EACzC,QAAQ;GACN,KAAKA,KAAa;EACpB;CACF;;EAWgB,KAAA,SAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFnB,SAA4B;EAC1B,OAAO,CAAI;;;oBAGK,KAAK,SAAS;eACnB,KAAK,KAAK;iBACR,KAAKC,GAAa;;;;;CAKjC;CA6BA;AAsBF;AA3JG,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,GAjCtC,IAAA,EAAA,CAAA,EAAc,aAAa,CAAA,GAAA,CAAA"}
|
|
@@ -1 +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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"}
|
|
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, css, html } 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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"}
|
package/dist/sken-combobox.js
CHANGED
|
@@ -233,7 +233,9 @@ var c = class extends t {
|
|
|
233
233
|
color: var(--sken-foreground, #152b48);
|
|
234
234
|
font-size: var(--sken-size-md, 0.875rem);
|
|
235
235
|
cursor: pointer;
|
|
236
|
-
transition:
|
|
236
|
+
transition:
|
|
237
|
+
border-color 120ms ease,
|
|
238
|
+
box-shadow 120ms ease;
|
|
237
239
|
}
|
|
238
240
|
.trigger:hover:not([data-disabled='true']) {
|
|
239
241
|
border-color: var(--sken-foreground, #152b48);
|
|
@@ -281,7 +283,13 @@ var c = class extends t {
|
|
|
281
283
|
* two glyphs have similar visual weight, and drop to
|
|
282
284
|
* 0.75rem so the chevron's block shape does not eat
|
|
283
285
|
* the input's vertical padding. */
|
|
284
|
-
font-family:
|
|
286
|
+
font-family:
|
|
287
|
+
ui-sans-serif,
|
|
288
|
+
system-ui,
|
|
289
|
+
-apple-system,
|
|
290
|
+
'Segoe UI',
|
|
291
|
+
Roboto,
|
|
292
|
+
sans-serif;
|
|
285
293
|
font-size: 0.75rem;
|
|
286
294
|
user-select: none;
|
|
287
295
|
}
|
|
@@ -476,28 +484,24 @@ var c = class extends t {
|
|
|
476
484
|
data-disabled=${this.disabled}
|
|
477
485
|
@click=${() => !this.disabled && (this._open ? this._close() : this._open_())}
|
|
478
486
|
>
|
|
479
|
-
${o && s.length > 0 ? r`<div
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
label="+${l.length}"
|
|
494
|
-
data-sken-combobox-overflow=${l.length}
|
|
495
|
-
hide-close-button
|
|
496
|
-
@click=${(e) => {
|
|
487
|
+
${o && s.length > 0 ? r`<div class="chip-row" part="chip-row" data-overflow=${this.chipOverflow}>
|
|
488
|
+
${c.map((e) => r`
|
|
489
|
+
<sken-filter-chip
|
|
490
|
+
label=${e.label}
|
|
491
|
+
data-sken-combobox-chip-value=${e.value}
|
|
492
|
+
@sken-close=${(t) => this._removeChip(e.value, t)}
|
|
493
|
+
></sken-filter-chip>
|
|
494
|
+
`)}
|
|
495
|
+
${l.length > 0 && this.chipOverflow === "count" ? r`<sken-filter-chip
|
|
496
|
+
class="overflow"
|
|
497
|
+
label="+${l.length}"
|
|
498
|
+
data-sken-combobox-overflow=${l.length}
|
|
499
|
+
hide-close-button
|
|
500
|
+
@click=${(e) => {
|
|
497
501
|
e.stopPropagation(), this._open = !0;
|
|
498
502
|
}}
|
|
499
|
-
|
|
500
|
-
|
|
503
|
+
></sken-filter-chip>` : null}
|
|
504
|
+
</div>` : null}
|
|
501
505
|
<div class="input-row">
|
|
502
506
|
<input
|
|
503
507
|
id="trigger"
|
|
@@ -518,17 +522,26 @@ var c = class extends t {
|
|
|
518
522
|
@blur=${this._onBlur}
|
|
519
523
|
/>
|
|
520
524
|
${!this.disabled && this.value !== null && (!n || i.size > 0) ? r`<button
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
+
type="button"
|
|
526
|
+
class="clear"
|
|
527
|
+
aria-label="Clear selection"
|
|
528
|
+
@click=${(e) => {
|
|
525
529
|
e.stopPropagation();
|
|
526
530
|
let t = n ? [] : null;
|
|
527
531
|
this._setValue(t), this._query = "", this._input.focus();
|
|
528
532
|
}}
|
|
529
|
-
|
|
533
|
+
>
|
|
534
|
+
×
|
|
535
|
+
</button>` : null}
|
|
530
536
|
<span class="chevron" data-open=${this._open} aria-hidden="true">
|
|
531
|
-
<svg
|
|
537
|
+
<svg
|
|
538
|
+
viewBox="0 0 16 16"
|
|
539
|
+
fill="none"
|
|
540
|
+
stroke="currentColor"
|
|
541
|
+
stroke-width="1.5"
|
|
542
|
+
stroke-linecap="round"
|
|
543
|
+
stroke-linejoin="round"
|
|
544
|
+
>
|
|
532
545
|
<path d="M3.5 6.5 L8 11 L12.5 6.5"></path>
|
|
533
546
|
</svg>
|
|
534
547
|
</span>
|
|
@@ -536,17 +549,14 @@ var c = class extends t {
|
|
|
536
549
|
</div>
|
|
537
550
|
|
|
538
551
|
${this._open ? r`<ul
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
role="presentation"
|
|
548
|
-
>${t.label}</li>` : null}
|
|
549
|
-
${t.items.map((t) => {
|
|
552
|
+
id=${a}
|
|
553
|
+
class="listbox"
|
|
554
|
+
role="listbox"
|
|
555
|
+
aria-multiselectable=${n}
|
|
556
|
+
>
|
|
557
|
+
${e.length === 0 ? r`<li class="option" data-disabled="true">No matches</li>` : t.map((t) => r`
|
|
558
|
+
${t.label ? r`<li class="group-header" role="presentation">${t.label}</li>` : null}
|
|
559
|
+
${t.items.map((t) => {
|
|
550
560
|
let o = e.indexOf(t), s = o === this._activeIndex, c = i.has(t.value);
|
|
551
561
|
return r`<li
|
|
552
562
|
id=${`${a}-opt-${o}`}
|
|
@@ -566,9 +576,8 @@ var c = class extends t {
|
|
|
566
576
|
<span>${t.label}</span>
|
|
567
577
|
</li>`;
|
|
568
578
|
})}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
579
|
+
`)}
|
|
580
|
+
</ul>` : null}
|
|
572
581
|
${this.helperText ? r`<div class="helper">${this.helperText}</div>` : null}
|
|
573
582
|
</div>
|
|
574
583
|
`;
|