@sken-ds/primitives 0.3.5 → 0.3.6
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/sken-button.js +15 -5
- package/dist/sken-button.js.map +1 -1
- package/package.json +1 -1
package/dist/sken-button.js
CHANGED
|
@@ -3,18 +3,28 @@ import { LitElement as t, css as n, html as r } from "lit";
|
|
|
3
3
|
import { customElement as i, property as a } from "lit/decorators.js";
|
|
4
4
|
//#region src/components/sken-button.ts
|
|
5
5
|
var o = class extends t {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
static {
|
|
7
|
+
this.formAssociated = !0;
|
|
8
|
+
}
|
|
9
|
+
#e;
|
|
10
|
+
constructor() {
|
|
11
|
+
super(), this.#e = null, this.variant = "primary", this.size = "md", this.disabled = !1, this.type = "button", this.ariaLabel = null, this.#t = (e) => {
|
|
8
12
|
if (this.disabled) {
|
|
9
13
|
e.preventDefault(), e.stopImmediatePropagation();
|
|
10
14
|
return;
|
|
11
15
|
}
|
|
12
|
-
|
|
16
|
+
let t = this.#e?.form;
|
|
17
|
+
this.type === "submit" && t ? (e.preventDefault(), t.requestSubmit()) : this.type === "reset" && t && (e.preventDefault(), t.reset()), this.dispatchEvent(new CustomEvent("sken-click", {
|
|
13
18
|
detail: { originalEvent: e },
|
|
14
19
|
bubbles: !0,
|
|
15
20
|
composed: !0
|
|
16
21
|
}));
|
|
17
22
|
};
|
|
23
|
+
try {
|
|
24
|
+
this.#e = this.attachInternals();
|
|
25
|
+
} catch {
|
|
26
|
+
this.#e = null;
|
|
27
|
+
}
|
|
18
28
|
}
|
|
19
29
|
static {
|
|
20
30
|
this.styles = n`
|
|
@@ -107,13 +117,13 @@ var o = class extends t {
|
|
|
107
117
|
part="button"
|
|
108
118
|
?disabled=${this.disabled}
|
|
109
119
|
type=${this.type}
|
|
110
|
-
@click=${this.#
|
|
120
|
+
@click=${this.#t}
|
|
111
121
|
>
|
|
112
122
|
<slot></slot>
|
|
113
123
|
</button>
|
|
114
124
|
`;
|
|
115
125
|
}
|
|
116
|
-
#
|
|
126
|
+
#t;
|
|
117
127
|
};
|
|
118
128
|
e([a({ reflect: !0 })], o.prototype, "variant", void 0), e([a({ reflect: !0 })], o.prototype, "size", void 0), e([a({
|
|
119
129
|
reflect: !0,
|
package/dist/sken-button.js.map
CHANGED
|
@@ -1 +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
|
|
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 { 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 // 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"}
|