@sken-ds/primitives 0.5.0 → 0.6.1
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/catalog-y40FMic1-DY2BFupW.js +153 -0
- package/dist/catalog-y40FMic1-DY2BFupW.js.map +1 -0
- package/dist/{decorate-D4FKzyDw.js → decorate-C1e2sg49.js} +1 -1
- package/dist/index.js +9 -5
- package/dist/ix-bridge.css +53 -191
- package/dist/primitives.css +2 -0
- package/dist/sken-button.js +1 -1
- package/dist/sken-button.js.map +1 -1
- package/dist/sken-checkbox.js +14 -4
- package/dist/sken-checkbox.js.map +1 -1
- package/dist/sken-combobox-group.js +1 -1
- package/dist/sken-combobox-group.js.map +1 -1
- package/dist/sken-combobox-item.js +1 -1
- package/dist/sken-combobox-item.js.map +1 -1
- package/dist/sken-combobox.js +66 -36
- package/dist/sken-combobox.js.map +1 -1
- package/dist/{sken-datatable-jx_jh1Fu.js → sken-datatable-DSXSyrNf.js} +163 -135
- package/dist/sken-datatable-DSXSyrNf.js.map +1 -0
- package/dist/sken-datatable.js +1 -1
- package/dist/sken-date-picker.js +1 -1
- package/dist/sken-date-picker.js.map +1 -1
- package/dist/sken-dialog.js +62 -52
- package/dist/sken-dialog.js.map +1 -1
- package/dist/sken-filter-chip.js +1 -1
- package/dist/sken-filter-chip.js.map +1 -1
- package/dist/sken-input.js +67 -42
- package/dist/sken-input.js.map +1 -1
- package/dist/sken-layout-region.js +1 -1
- package/dist/sken-layout-region.js.map +1 -1
- package/dist/sken-layout.js +34 -31
- package/dist/sken-layout.js.map +1 -1
- package/dist/sken-nav-group.js +306 -0
- package/dist/sken-nav-group.js.map +1 -0
- package/dist/sken-nav-item.js +224 -0
- package/dist/sken-nav-item.js.map +1 -0
- package/dist/sken-nav.js +233 -0
- package/dist/sken-nav.js.map +1 -0
- package/dist/sken-number-input.js +10 -5
- package/dist/sken-number-input.js.map +1 -1
- package/dist/sken-switch.js +27 -7
- package/dist/sken-switch.js.map +1 -1
- package/dist/sken-textarea.js +107 -51
- package/dist/sken-textarea.js.map +1 -1
- package/dist/sken-tooltip.js +70 -0
- package/dist/sken-tooltip.js.map +1 -0
- package/package.json +33 -15
- package/dist/sken-datatable-jx_jh1Fu.js.map +0 -1
package/dist/sken-switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sken-switch.js","names":["#controlled","#getInput","#handleChange","#handleFocus","#handleBlur"],"sources":["../src/components/sken-switch.ts"],"sourcesContent":["// ── <sken-switch> — framework-ready Web Component ────────────────────\n// Wraps a native <input type=\"checkbox\"> with role=\"switch\" and a\n// custom track + thumb. For immediate-effect toggles (the action\n// applies on click, not at form submit). For selections that commit\n// on submit, use <sken-checkbox> instead.\n//\n// Contract uses `on` / `defaultOn` (not `checked` /\n// `defaultChecked`) to reinforce semantic intent: a switch is \"on\"\n// or \"off\", not \"checked\" or \"unchecked\". Requires @sken-ds/theme/css\n// (ADR-0006).\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\n@customElement('sken-switch')\nexport class SkenSwitch extends LitElement {\n // `on` distinguishes \"uncontrolled\" (consumer never assigns the\n // prop) from \"controlled\" (consumer assigns `true` or `false`).\n // Lit's `@property({ type: Boolean })` collapses \"absent\" to\n // `false`, which makes the two cases indistinguishable. We use\n // a custom converter that maps the attribute presence\n // (`<sken-switch on>`) 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 `on` prop when the consumer did\n // not pass `:on`, so the setter is never called and the\n // primitive stays uncontrolled.\n private _on: boolean | undefined = undefined\n private _onSet: boolean = false\n // The custom converter maps attribute absence to `undefined`\n // (the \"uncontrolled\" sentinel) and attribute presence to\n // `true`. The prop setter also accepts `false` (controlled-\n // with-false) and `true` (controlled-with-true).\n @property({\n attribute: 'on',\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 on(v: boolean | undefined) {\n this._on = v\n this._onSet = v !== undefined\n this.requestUpdate()\n }\n get on(): boolean | undefined {\n return this._on\n }\n /** True when the consumer has explicitly bound the `on` prop. */\n get #controlled(): boolean {\n return this._onSet\n }\n\n @property({ attribute: 'default-on', type: Boolean })\n defaultOn: boolean | undefined = undefined\n @property({ reflect: true, type: Boolean }) disabled = false\n @property({ reflect: true, type: Boolean }) readonly = false\n @property({ reflect: true, type: Boolean }) required = false\n @property({ attribute: 'described-by-id' }) describedById: string | undefined = undefined\n @property() name: string | undefined = undefined\n\n // string | null matches lib.dom.d.ts; the contract normalizes to\n // string | undefined for the public API.\n @property({ attribute: 'aria-label' }) override ariaLabel: string | null = null\n\n // @state so Lit picks up changes and re-runs updated().\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 track + 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 /* Visually hidden but accessible input (same pattern as sken-checkbox). */\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 .track {\n position: relative;\n box-sizing: border-box;\n inline-size: 2.5rem;\n block-size: 1.375rem;\n padding: 2px;\n border-radius: 999px;\n background: var(--sken-border);\n transition: background-color 160ms ease;\n }\n\n .thumb {\n display: block;\n inline-size: calc(1.375rem - 4px);\n block-size: calc(1.375rem - 4px);\n border-radius: 50%;\n background: var(--sken-input);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n transition: transform 160ms ease;\n transform: translateX(0);\n }\n\n :host([data-on]) .track {\n background: var(--sken-primary);\n }\n :host([data-on]) .thumb {\n transform: translateX(1.125rem);\n }\n\n :host(:focus-within) .track {\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 override connectedCallback(): void {\n super.connectedCallback()\n if (this.on === undefined) {\n this._uncontrolled = this.defaultOn ?? false\n }\n }\n\n protected override updated(): void {\n const input = this.#getInput()\n if (!input) return\n const isOn = (this.#controlled ? this.on : this._uncontrolled) ?? false\n input.checked = isOn\n if (isOn) this.setAttribute('data-on', '')\n else this.removeAttribute('data-on')\n }\n\n protected override render() {\n // The visible UI (track + thumb + label) is wrapped in a\n // `<label>` element so clicking anywhere on it toggles the\n // hidden input. This is the standard WAI-ARIA pattern for a\n // custom-styled checkbox / switch. Without the label, the\n // visually-hidden input would never receive a click event and\n // the switch would look completely inert to mouse / touch.\n return html`\n <label>\n <input\n part=\"input\"\n type=\"checkbox\"\n role=\"switch\"\n aria-checked=${this.on === undefined ? String(this._uncontrolled) : String(this.on)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-describedby=${this.describedById ?? ''}\n aria-label=${this.ariaLabel ?? ''}\n name=${this.name ?? ''}\n @change=${this.#handleChange}\n @focus=${this.#handleFocus}\n @blur=${this.#handleBlur}\n />\n <span class=\"track\" part=\"track\" aria-hidden=\"true\">\n <span class=\"thumb\" part=\"thumb\"></span>\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 the input was disabled\n // programmatically (no click event) or in case the consumer\n // toggled `disabled` mid-flight. Either way, do not advance\n // state.\n if (this.disabled) {\n target.checked = this.#controlled ? this.on === true : this._uncontrolled\n return\n }\n // Readonly: the native `<input type=\"checkbox\">` does NOT\n // block the toggle on click (readonly only affects text\n // inputs), so the input flips visually. We revert the flip\n // and skip the change event so the consumer never sees it.\n // The `data-on` attribute is set in `updated()` from the\n // controlled / uncontrolled value, so the visual stays in\n // sync after the revert.\n if (this.readonly) {\n const value = this.#controlled ? this.on === true : this._uncontrolled\n target.checked = value\n this.requestUpdate()\n return\n }\n // In uncontrolled mode, the consumer does not own the value,\n // so we update the internal `@state` and let Lit re-render.\n // In controlled mode, the consumer owns the value: we do NOT\n // touch the internal state (the consumer's next prop change\n // will drive the next render). Either way, the input's\n // `change` event already flipped `target.checked` in the DOM\n // and we emit `sken-change` for both modes so the consumer\n // can sync.\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-switch': SkenSwitch\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sken-switch.js","names":[],"sources":["../src/components/sken-switch.ts"],"sourcesContent":["// ── <sken-switch> — framework-ready Web Component ────────────────────\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\n@customElement('sken-switch')\nexport class SkenSwitch extends LitElement {\n private _on: boolean | undefined = undefined\n private _onSet: boolean = false\n @property({\n attribute: 'on',\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 on(v: boolean | undefined) {\n this._on = v\n this._onSet = v !== undefined\n this.requestUpdate()\n }\n get on(): boolean | undefined {\n return this._on\n }\n get #controlled(): boolean {\n return this._onSet\n }\n\n @property({ attribute: 'default-on', type: Boolean })\n defaultOn: boolean | undefined = undefined\n @property({ reflect: true, type: Boolean }) disabled = false\n @property({ reflect: true, type: Boolean }) readonly = 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\n @property({ attribute: 'aria-label' }) override ariaLabel: string | null = null\n\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 track + 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-xs, 0.75rem);\n line-height: 1.25;\n }\n\n :host([disabled]) label {\n cursor: not-allowed;\n }\n\n /* Visually hidden but accessible input (same pattern as sken-checkbox). */\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 .track {\n position: relative;\n box-sizing: border-box;\n inline-size: 2.5rem;\n block-size: 1.375rem;\n padding: 2px;\n border: 1px solid transparent;\n border-radius: 999px;\n background: var(--sken-border);\n transition:\n background-color 160ms ease,\n border-color 160ms ease;\n }\n\n .thumb {\n display: block;\n inline-size: calc(1.375rem - 6px);\n block-size: calc(1.375rem - 6px);\n border-radius: 50%;\n background: var(--sken-input);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n transition: transform 160ms ease;\n transform: translateX(0);\n }\n\n :host([data-on]) .track {\n background: var(--sken-primary);\n }\n :host([data-on]) .thumb {\n transform: translateX(1.125rem);\n }\n\n :host(:focus-within) .track {\n outline: 2px solid var(--sken-ring, currentColor);\n outline-offset: 2px;\n }\n :host(:focus-within) {\n outline: none;\n }\n\n :host([invalid]) .track {\n border-color: var(--sken-destructive);\n }\n\n .label {\n user-select: none;\n }\n\n :host([required]) .label::after {\n content: ' *';\n }\n\n :host([required][invalid]) .label,\n :host([required][invalid]) .label::after {\n color: var(--sken-destructive);\n }\n `\n\n override connectedCallback(): void {\n super.connectedCallback()\n if (this.on === undefined) {\n this._uncontrolled = this.defaultOn ?? false\n }\n }\n\n protected override updated(): void {\n const input = this.#getInput()\n if (!input) return\n const isOn = (this.#controlled ? this.on : this._uncontrolled) ?? false\n input.checked = isOn\n if (isOn) this.setAttribute('data-on', '')\n else this.removeAttribute('data-on')\n }\n\n protected override render() {\n return html`\n <label>\n <input\n part=\"input\"\n type=\"checkbox\"\n role=\"switch\"\n aria-checked=${this.on === undefined ? String(this._uncontrolled) : String(this.on)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${this.invalid ? 'true' : 'false'}\n aria-describedby=${this.describedById ?? ''}\n aria-label=${this.ariaLabel ?? ''}\n name=${this.name ?? ''}\n @change=${this.#handleChange}\n @focus=${this.#handleFocus}\n @blur=${this.#handleBlur}\n />\n <span class=\"track\" part=\"track\" aria-hidden=\"true\">\n <span class=\"thumb\" part=\"thumb\"></span>\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 if (this.disabled) {\n target.checked = this.#controlled ? this.on === true : this._uncontrolled\n return\n }\n if (this.readonly) {\n const value = this.#controlled ? this.on === true : this._uncontrolled\n target.checked = value\n this.requestUpdate()\n return\n }\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-switch': SkenSwitch\n }\n}\n"],"mappings":"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"}
|
package/dist/sken-textarea.js
CHANGED
|
@@ -1,40 +1,46 @@
|
|
|
1
|
-
import { t as e } from "./decorate-
|
|
2
|
-
import { LitElement as t, css as n, html as r } from "lit";
|
|
3
|
-
import { customElement as
|
|
1
|
+
import { t as e } from "./decorate-C1e2sg49.js";
|
|
2
|
+
import { LitElement as t, css as n, html as r, nothing as i } from "lit";
|
|
3
|
+
import { customElement as a, property as o } from "lit/decorators.js";
|
|
4
4
|
//#region src/components/sken-textarea.ts
|
|
5
|
-
|
|
5
|
+
function s(e) {
|
|
6
|
+
return e ? e.assignedNodes({ flatten: !0 }).some((e) => e.nodeType !== Node.TEXT_NODE || (e.textContent ?? "").trim() !== "") : !1;
|
|
7
|
+
}
|
|
8
|
+
var c = class extends t {
|
|
6
9
|
static {
|
|
7
10
|
this.formAssociated = !0;
|
|
8
11
|
}
|
|
9
12
|
#e;
|
|
10
13
|
constructor() {
|
|
11
|
-
super(), this.#e = void 0, this.size = "md", this.rows = 4, this.cols = void 0, this.maxLength = void 0, this.resize = "vertical", this.placeholder = void 0, this.value = void 0, this.defaultValue = void 0, this.disabled = !1, this.readonly = !1, this.required = !1, this.invalid = !1, this.describedById = void 0, this.name = void 0, this.#t = "", this.#
|
|
14
|
+
super(), this.#e = void 0, this.size = "md", this.label = void 0, this.rows = 4, this.cols = void 0, this.maxLength = void 0, this.resize = "vertical", this.placeholder = void 0, this.value = void 0, this.defaultValue = void 0, this.disabled = !1, this.readonly = !1, this.required = !1, this.invalid = !1, this.describedById = void 0, this.name = void 0, this.ariaLabel = null, this.#t = "", this._textareaId = `sken-textarea-${crypto.randomUUID()}`, this.#n = () => {
|
|
15
|
+
let e = this.renderRoot.querySelector(".slot-start"), t = this.renderRoot.querySelector(".slot-end"), n = this.renderRoot.querySelector("slot[name=\"start\"]"), r = this.renderRoot.querySelector("slot[name=\"end\"]");
|
|
16
|
+
e?.toggleAttribute("data-empty", !s(n)), t?.toggleAttribute("data-empty", !s(r));
|
|
17
|
+
}, this.#r = void 0, this.#i = void 0, this.#o = (e) => {
|
|
12
18
|
let t = e.target.value;
|
|
13
|
-
this.value === void 0 && (this.#t = t), this.#
|
|
19
|
+
this.value === void 0 && (this.#t = t), this.#a(), this.dispatchEvent(new CustomEvent("sken-input", {
|
|
14
20
|
detail: t,
|
|
15
21
|
bubbles: !0,
|
|
16
22
|
composed: !0
|
|
17
23
|
}));
|
|
18
|
-
}, this.#
|
|
24
|
+
}, this.#s = (e) => {
|
|
19
25
|
let t = e.target;
|
|
20
|
-
this.#
|
|
26
|
+
this.#a(), this.dispatchEvent(new CustomEvent("sken-change", {
|
|
21
27
|
detail: t.value,
|
|
22
28
|
bubbles: !0,
|
|
23
29
|
composed: !0
|
|
24
30
|
}));
|
|
25
|
-
}, this.#
|
|
31
|
+
}, this.#c = (e) => {
|
|
26
32
|
this.dispatchEvent(new CustomEvent("sken-focus", {
|
|
27
33
|
detail: e,
|
|
28
34
|
bubbles: !0,
|
|
29
35
|
composed: !0
|
|
30
36
|
}));
|
|
31
|
-
}, this.#
|
|
37
|
+
}, this.#l = (e) => {
|
|
32
38
|
this.dispatchEvent(new CustomEvent("sken-blur", {
|
|
33
39
|
detail: e,
|
|
34
40
|
bubbles: !0,
|
|
35
41
|
composed: !0
|
|
36
42
|
}));
|
|
37
|
-
}, this.#
|
|
43
|
+
}, this.#u = (e) => {
|
|
38
44
|
if (e.key !== "Enter" || e.isComposing || e.shiftKey || this.disabled || this.readonly) return;
|
|
39
45
|
e.preventDefault();
|
|
40
46
|
let t = this.#e?.form;
|
|
@@ -54,6 +60,26 @@ var o = class extends t {
|
|
|
54
60
|
inline-size: 100%;
|
|
55
61
|
}
|
|
56
62
|
|
|
63
|
+
.field {
|
|
64
|
+
display: grid;
|
|
65
|
+
gap: var(--sken-1, 0.25rem);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.label {
|
|
69
|
+
font-size: var(--sken-size-xs, 0.75rem);
|
|
70
|
+
font-weight: 500;
|
|
71
|
+
color: var(--sken-foreground);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
:host([required]) .label::after {
|
|
75
|
+
content: ' *';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:host([required][invalid]) .label,
|
|
79
|
+
:host([required][invalid]) .label::after {
|
|
80
|
+
color: var(--sken-destructive);
|
|
81
|
+
}
|
|
82
|
+
|
|
57
83
|
.textarea-wrapper {
|
|
58
84
|
position: relative;
|
|
59
85
|
display: flex;
|
|
@@ -99,6 +125,10 @@ var o = class extends t {
|
|
|
99
125
|
min-block-size: 0.25rem;
|
|
100
126
|
}
|
|
101
127
|
|
|
128
|
+
.slot[data-empty] {
|
|
129
|
+
display: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
102
132
|
.slot-start {
|
|
103
133
|
padding-block-end: 0.25rem;
|
|
104
134
|
}
|
|
@@ -161,19 +191,40 @@ var o = class extends t {
|
|
|
161
191
|
`;
|
|
162
192
|
}
|
|
163
193
|
connectedCallback() {
|
|
164
|
-
super.connectedCallback(), this.value === void 0 && (this.#t = this.defaultValue ?? ""), this.#
|
|
194
|
+
super.connectedCallback(), this.value === void 0 && (this.#t = this.defaultValue ?? ""), this.#a();
|
|
195
|
+
}
|
|
196
|
+
disconnectedCallback() {
|
|
197
|
+
super.disconnectedCallback(), this.#r?.disconnect(), this.#i?.disconnect();
|
|
198
|
+
}
|
|
199
|
+
firstUpdated() {
|
|
200
|
+
let e = this.renderRoot.querySelector(".slot-start"), t = this.renderRoot.querySelector(".slot-end");
|
|
201
|
+
if (!e || !t) return;
|
|
202
|
+
this.#r = new MutationObserver(() => this.#n()), this.#r.observe(e, {
|
|
203
|
+
childList: !0,
|
|
204
|
+
subtree: !0,
|
|
205
|
+
attributes: !0
|
|
206
|
+
}), this.#i = new MutationObserver(() => this.#n()), this.#i.observe(t, {
|
|
207
|
+
childList: !0,
|
|
208
|
+
subtree: !0,
|
|
209
|
+
attributes: !0
|
|
210
|
+
});
|
|
211
|
+
let n = this.renderRoot.querySelector("slot[name=\"start\"]"), r = this.renderRoot.querySelector("slot[name=\"end\"]");
|
|
212
|
+
n?.addEventListener("slotchange", this.#n), r?.addEventListener("slotchange", this.#n), this.#n();
|
|
165
213
|
}
|
|
214
|
+
#n;
|
|
215
|
+
#r;
|
|
216
|
+
#i;
|
|
166
217
|
formResetCallback() {
|
|
167
218
|
if (this.value === void 0) {
|
|
168
219
|
this.#t = this.defaultValue ?? "";
|
|
169
220
|
let e = this.renderRoot.querySelector("textarea");
|
|
170
|
-
e && (e.value = this.#t), this.#
|
|
221
|
+
e && (e.value = this.#t), this.#a();
|
|
171
222
|
} else this.requestUpdate();
|
|
172
223
|
}
|
|
173
224
|
formDisabledCallback(e) {
|
|
174
225
|
this.disabled = e;
|
|
175
226
|
}
|
|
176
|
-
#
|
|
227
|
+
#a() {
|
|
177
228
|
if (!this.#e) return;
|
|
178
229
|
let e = this.value ?? this.#t;
|
|
179
230
|
this.#e.setFormValue(e);
|
|
@@ -181,64 +232,69 @@ var o = class extends t {
|
|
|
181
232
|
render() {
|
|
182
233
|
let e = this.value ?? this.#t;
|
|
183
234
|
return r`
|
|
184
|
-
<div class="
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
235
|
+
<div class="field" part="field">
|
|
236
|
+
${this.label ? r`<label class="label" part="label" for=${this._textareaId}>${this.label}</label>` : i}
|
|
237
|
+
<div class="textarea-wrapper" part="wrapper">
|
|
238
|
+
<div class="slot slot-start" part="slot-start">
|
|
239
|
+
<slot name="start"></slot>
|
|
240
|
+
</div>
|
|
241
|
+
<textarea
|
|
242
|
+
id=${this._textareaId}
|
|
243
|
+
part="textarea"
|
|
244
|
+
.value=${e}
|
|
245
|
+
rows=${this.rows}
|
|
246
|
+
cols=${this.cols ?? ""}
|
|
247
|
+
maxlength=${this.maxLength ?? ""}
|
|
248
|
+
placeholder=${this.placeholder ?? ""}
|
|
249
|
+
?disabled=${this.disabled}
|
|
250
|
+
?readonly=${this.readonly}
|
|
251
|
+
?required=${this.required}
|
|
252
|
+
aria-invalid=${this.invalid ? "true" : "false"}
|
|
253
|
+
aria-describedby=${this.describedById ?? ""}
|
|
254
|
+
aria-label=${this.ariaLabel ?? ""}
|
|
255
|
+
name=${this.name ?? ""}
|
|
256
|
+
@input=${this.#o}
|
|
257
|
+
@change=${this.#s}
|
|
258
|
+
@focus=${this.#c}
|
|
259
|
+
@blur=${this.#l}
|
|
260
|
+
@keydown=${this.#u}
|
|
261
|
+
></textarea>
|
|
262
|
+
<div class="slot slot-end" part="slot-end">
|
|
263
|
+
<slot name="end"></slot>
|
|
264
|
+
</div>
|
|
209
265
|
</div>
|
|
210
266
|
</div>
|
|
211
267
|
`;
|
|
212
268
|
}
|
|
213
|
-
#r;
|
|
214
|
-
#i;
|
|
215
|
-
#a;
|
|
216
269
|
#o;
|
|
217
270
|
#s;
|
|
271
|
+
#c;
|
|
272
|
+
#l;
|
|
273
|
+
#u;
|
|
218
274
|
};
|
|
219
|
-
e([
|
|
275
|
+
e([o({ reflect: !0 })], c.prototype, "size", void 0), e([o()], c.prototype, "label", void 0), e([o({
|
|
220
276
|
reflect: !0,
|
|
221
277
|
type: Number
|
|
222
|
-
})],
|
|
278
|
+
})], c.prototype, "rows", void 0), e([o({
|
|
223
279
|
reflect: !0,
|
|
224
280
|
type: Number
|
|
225
|
-
})],
|
|
281
|
+
})], c.prototype, "cols", void 0), e([o({
|
|
226
282
|
attribute: "max-length",
|
|
227
283
|
type: Number
|
|
228
|
-
})],
|
|
284
|
+
})], c.prototype, "maxLength", void 0), e([o({ reflect: !0 })], c.prototype, "resize", void 0), e([o()], c.prototype, "placeholder", void 0), e([o()], c.prototype, "value", void 0), e([o({ attribute: "default-value" })], c.prototype, "defaultValue", void 0), e([o({
|
|
229
285
|
reflect: !0,
|
|
230
286
|
type: Boolean
|
|
231
|
-
})],
|
|
287
|
+
})], c.prototype, "disabled", void 0), e([o({
|
|
232
288
|
reflect: !0,
|
|
233
289
|
type: Boolean
|
|
234
|
-
})],
|
|
290
|
+
})], c.prototype, "readonly", void 0), e([o({
|
|
235
291
|
reflect: !0,
|
|
236
292
|
type: Boolean
|
|
237
|
-
})],
|
|
293
|
+
})], c.prototype, "required", void 0), e([o({
|
|
238
294
|
reflect: !0,
|
|
239
295
|
type: Boolean
|
|
240
|
-
})],
|
|
296
|
+
})], c.prototype, "invalid", void 0), e([o({ attribute: "described-by-id" })], c.prototype, "describedById", void 0), e([o()], c.prototype, "name", void 0), e([o({ attribute: "aria-label" })], c.prototype, "ariaLabel", void 0), c = e([a("sken-textarea")], c);
|
|
241
297
|
//#endregion
|
|
242
|
-
export {
|
|
298
|
+
export { c as SkenTextarea };
|
|
243
299
|
|
|
244
300
|
//# sourceMappingURL=sken-textarea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sken-textarea.js","names":["#internalValue","#syncFormValue","#internals","#handleInput","#handleChange","#handleFocus","#handleBlur","#handleKeydown"],"sources":["../src/components/sken-textarea.ts"],"sourcesContent":["// ── <sken-textarea> — framework-ready Web Component ────────────────\n// Multiline text input. Wraps a native <textarea> with token-driven\n// styles and the same shadow-DOM event surface as <sken-input>.\n// Slots are placed above (start) and below (end) the textarea, not\n// to the sides — multiline editors don't lend themselves to\n// horizontal adornments the way single-line inputs do.\n//\n// Requires @sken-ds/theme/css (ADR-0006). Pairs with @sken-ds/contracts'\n// SkenTextareaProps / SkenTextareaSlots / SkenTextareaEmits.\n\nimport type { SkenTextareaResize, SkenTextareaSize } from '@sken-ds/contracts'\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('sken-textarea')\nexport class SkenTextarea extends LitElement {\n // Form-associated custom element. Opt in to the\n // ElementInternals API so this primitive participates in\n // the surrounding <form>'s submit/reset lifecycle and\n // FormData(form) picks up the textarea's value under its\n // `name` attribute. See SkenInput for the full rationale;\n // the pattern is identical. Lit docs:\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 that do not\n // implement ElementInternals.\n #internals: ElementInternals | undefined = undefined\n\n constructor() {\n super()\n try {\n this.#internals = this.attachInternals()\n } catch {\n this.#internals = undefined\n }\n }\n\n @property({ reflect: true }) size: SkenTextareaSize = 'md'\n @property({ reflect: true, type: Number }) rows = 4\n @property({ reflect: true, type: Number }) cols: number | undefined = undefined\n @property({ attribute: 'max-length', type: Number }) maxLength: number | undefined = undefined\n @property({ reflect: true }) resize: SkenTextareaResize = 'vertical'\n @property() placeholder: string | undefined = undefined\n @property() value: string | undefined = undefined\n @property({ attribute: 'default-value' }) defaultValue: string | undefined = undefined\n @property({ reflect: true, type: Boolean }) disabled = false\n @property({ reflect: true, type: Boolean }) readonly = 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\n // Internal value for uncontrolled mode. Seeded from `defaultValue`\n // on first connection; from then on the DOM textarea keeps the\n // source of truth. Same pattern as SkenInput.\n #internalValue: string = ''\n\n static styles = css`\n :host {\n display: inline-block;\n inline-size: 100%;\n }\n\n .textarea-wrapper {\n position: relative;\n display: flex;\n flex-direction: column;\n inline-size: 100%;\n }\n\n textarea {\n box-sizing: border-box;\n inline-size: 100%;\n border: 1px solid var(--sken-border);\n border-radius: var(--sken-md);\n background: var(--sken-input);\n color: var(--sken-foreground);\n font-family: var(--sken-family-sans);\n font-size: var(--sken-size-md);\n line-height: 1.5;\n padding-block: var(--sken-2);\n padding-inline: var(--sken-3);\n min-block-size: 4.5rem;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n /* Resize is controlled by the resize attribute, not by\n user-agent stylesheet, so consumers can override. */\n }\n\n textarea::placeholder {\n color: var(--sken-muted-foreground);\n opacity: 1;\n }\n\n /* ── Slot containers ──────────────────────────────────────\n Position: relative (not absolute) so the slotted content\n flows naturally above and below the textarea. The wrapper\n has a flex column, so the textarea's vertical padding is\n NOT auto-adjusted (unlike SkenInput). Slot height adds to\n the wrapper's natural height. */\n .slot {\n display: flex;\n align-items: center;\n color: var(--sken-muted-foreground);\n min-block-size: 0.25rem;\n }\n\n .slot-start {\n padding-block-end: 0.25rem;\n }\n\n .slot-end {\n padding-block-start: 0.25rem;\n }\n\n /* ── Sizes ────────────────────────────────────────────────── */\n :host([size='sm']) textarea {\n padding-block: var(--sken-1);\n padding-inline: var(--sken-2);\n font-size: var(--sken-size-sm);\n }\n :host([size='md']) textarea {\n /* Default styles above. */\n }\n :host([size='lg']) textarea {\n padding-block: var(--sken-3);\n padding-inline: var(--sken-4);\n font-size: var(--sken-size-lg);\n }\n\n /* ── Resize policies ────────────────────────────────────── */\n :host([resize='none']) textarea {\n resize: none;\n }\n :host([resize='vertical']) textarea {\n resize: vertical;\n }\n :host([resize='horizontal']) textarea {\n resize: horizontal;\n }\n :host([resize='both']) textarea {\n resize: both;\n }\n\n /* ── States ───────────────────────────────────────────────── */\n .textarea-wrapper:hover textarea:not(:disabled):not(:read-only) {\n border-color: var(--sken-foreground);\n }\n .textarea-wrapper:focus-within textarea {\n outline: 2px solid var(--sken-ring, currentColor);\n outline-offset: 2px;\n border-color: var(--sken-primary);\n }\n textarea:disabled {\n cursor: not-allowed;\n opacity: var(--sken-disabled);\n }\n textarea:read-only {\n background: var(--sken-muted);\n }\n :host([invalid]) textarea {\n border-color: var(--sken-destructive);\n }\n :host([invalid]) .textarea-wrapper:focus-within textarea {\n outline-color: var(--sken-destructive);\n }\n `\n\n override connectedCallback(): void {\n super.connectedCallback()\n if (this.value === undefined) {\n this.#internalValue = this.defaultValue ?? ''\n }\n // Publish the initial value to the surrounding form.\n this.#syncFormValue()\n }\n\n // ── Form-association callbacks ─────────────────────────────\n // formResetCallback: for uncontrolled mode, restore the seed\n // value and re-publish. For controlled mode, re-render and\n // let Lit re-publish the controlled value.\n formResetCallback(): void {\n if (this.value === undefined) {\n this.#internalValue = this.defaultValue ?? ''\n const ta = this.renderRoot.querySelector('textarea') as HTMLTextAreaElement | null\n if (ta) ta.value = this.#internalValue\n this.#syncFormValue()\n } else {\n this.requestUpdate()\n }\n }\n\n // formDisabledCallback: mirror the form's :disabled state onto\n // the prop. Lit re-renders; the inner <textarea> picks up\n // `?disabled=${this.disabled}` in the template.\n formDisabledCallback(isDisabled: boolean): void {\n this.disabled = isDisabled\n }\n\n // Publish the current value to the form. Called on every\n // change so FormData and submit/reset stay in sync.\n #syncFormValue(): void {\n if (!this.#internals) return\n const value = this.value ?? this.#internalValue\n this.#internals.setFormValue(value)\n }\n\n protected override render() {\n const value = this.value ?? this.#internalValue\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <div class=\"slot slot-start\" part=\"slot-start\">\n <slot name=\"start\"></slot>\n </div>\n <textarea\n part=\"textarea\"\n .value=${value}\n rows=${this.rows}\n cols=${this.cols ?? ''}\n maxlength=${this.maxLength ?? ''}\n placeholder=${this.placeholder ?? ''}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${this.invalid ? 'true' : 'false'}\n aria-describedby=${this.describedById ?? ''}\n name=${this.name ?? ''}\n @input=${this.#handleInput}\n @change=${this.#handleChange}\n @focus=${this.#handleFocus}\n @blur=${this.#handleBlur}\n @keydown=${this.#handleKeydown}\n ></textarea>\n <div class=\"slot slot-end\" part=\"slot-end\">\n <slot name=\"end\"></slot>\n </div>\n </div>\n `\n }\n\n // composed: true on every event so the framework adapter outside\n // the shadow boundary can listen. Mirrors SkenInput.\n #handleInput = (event: Event) => {\n const target = event.target as HTMLTextAreaElement\n const newValue = target.value\n if (this.value === undefined) this.#internalValue = newValue\n // Publish the new value to the surrounding form so submit\n // and FormData see the latest text. Per-keystroke is fine:\n // setFormValue is cheap.\n this.#syncFormValue()\n this.dispatchEvent(\n new CustomEvent<string>('sken-input', { detail: newValue, bubbles: true, composed: true }),\n )\n }\n\n #handleChange = (event: Event) => {\n const target = event.target as HTMLTextAreaElement\n this.#syncFormValue()\n this.dispatchEvent(\n new CustomEvent<string>('sken-change', {\n detail: target.value,\n bubbles: true,\n composed: true,\n }),\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 // Wire Enter-on-the-inner-textarea to the host's associated\n // form. Mirrors SkenInput.#handleKeydown with one key\n // difference: textareas are multiline, so the user can press\n // Shift+Enter to insert a newline. Only Enter WITHOUT shift\n // submits. The browser's implicit submission algorithm does\n // not see the inner textarea (shadow boundary), so we bridge\n // it ourselves via `internals.form.requestSubmit()`.\n // `isComposing` guards IME composition (Enter to confirm a\n // kanji candidate is not a submit intent).\n #handleKeydown = (event: KeyboardEvent) => {\n if (event.key !== 'Enter' || event.isComposing) return\n if (event.shiftKey) return // newline; let the browser insert it\n if (this.disabled || this.readonly) return\n // preventDefault runs even without ElementInternals support,\n // keeping the observable behaviour consistent.\n event.preventDefault()\n const form = this.#internals?.form\n if (!form) return\n form.requestSubmit()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-textarea': SkenTextarea\n }\n}\n"],"mappings":";;;;AAeO,IAAM,IAAN,cAA2B,EAAW;;EAQnB,KAAA,iBAAA;;CAOxB;CAEA,cAAc;EAqQI,AApQhB,MAAM,GAHmC,KAAA,KAAA,KAAA,GAWW,KAAA,OAAA,MACJ,KAAA,OAAA,GACoB,KAAA,OAAA,KAAA,GACe,KAAA,YAAA,KAAA,GAC3B,KAAA,SAAA,YACZ,KAAA,cAAA,KAAA,GACN,KAAA,QAAA,KAAA,GACqC,KAAA,eAAA,KAAA,GACtB,KAAA,WAAA,IACA,KAAA,WAAA,IACA,KAAA,WAAA,IACD,KAAA,UAAA,IAC0B,KAAA,gBAAA,KAAA,GACzC,KAAA,OAAA,KAAA,GAKd,KAAA,KAAA,IA4LT,KAAA,MAAA,MAAiB;GAE/B,IAAM,IADS,EAAM,OACG;GAMxB,AALI,KAAK,UAAU,KAAA,MAAW,KAAKA,KAAiB,IAIpD,KAAKC,GAAe,GACpB,KAAK,cACH,IAAI,YAAoB,cAAc;IAAE,QAAQ;IAAU,SAAS;IAAM,UAAU;GAAK,CAAC,CAC3F;EACF,GAEiB,KAAA,MAAA,MAAiB;GAChC,IAAM,IAAS,EAAM;GAErB,AADA,KAAKA,GAAe,GACpB,KAAK,cACH,IAAI,YAAoB,eAAe;IACrC,QAAQ,EAAO;IACf,SAAS;IACT,UAAU;GACZ,CAAC,CACH;EACF,GAEgB,KAAA,MAAA,MAAsB;GACpC,KAAK,cACH,IAAI,YAAwB,cAAc;IAAE,QAAQ;IAAO,SAAS;IAAM,UAAU;GAAK,CAAC,CAC5F;EACF,GAEe,KAAA,MAAA,MAAsB;GACnC,KAAK,cACH,IAAI,YAAwB,aAAa;IAAE,QAAQ;IAAO,SAAS;IAAM,UAAU;GAAK,CAAC,CAC3F;EACF,GAWkB,KAAA,MAAA,MAAyB;GAGzC,IAFI,EAAM,QAAQ,WAAW,EAAM,eAC/B,EAAM,YACN,KAAK,YAAY,KAAK,UAAU;GAGpC,EAAM,eAAe;GACrB,IAAM,IAAO,KAAKC,IAAY;GACzB,KACL,EAAK,cAAc;EACrB;EA7QE,IAAI;GACF,KAAKA,KAAa,KAAK,gBAAgB;EACzC,QAAQ;GACN,KAAKA,KAAa,KAAA;EACpB;CACF;CAoBA;;EAEgB,KAAA,SAAA,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHnB,oBAAmC;EAMjC,AALA,MAAM,kBAAkB,GACpB,KAAK,UAAU,KAAA,MACjB,KAAKF,KAAiB,KAAK,gBAAgB,KAG7C,KAAKC,GAAe;CACtB;CAMA,oBAA0B;EACxB,IAAI,KAAK,UAAU,KAAA,GAAW;GAC5B,KAAKD,KAAiB,KAAK,gBAAgB;GAC3C,IAAM,IAAK,KAAK,WAAW,cAAc,UAAU;GAEnD,AADI,MAAI,EAAG,QAAQ,KAAKA,KACxB,KAAKC,GAAe;EACtB,OACE,KAAK,cAAc;CAEvB;CAKA,qBAAqB,GAA2B;EAC9C,KAAK,WAAW;CAClB;CAIA,KAAuB;EACrB,IAAI,CAAC,KAAKC,IAAY;EACtB,IAAM,IAAQ,KAAK,SAAS,KAAKF;EACjC,KAAKE,GAAW,aAAa,CAAK;CACpC;CAEA,SAA4B;EAC1B,IAAM,IAAQ,KAAK,SAAS,KAAKF;EACjC,OAAO,CAAI;;;;;;;mBAOI,EAAM;iBACR,KAAK,KAAK;iBACV,KAAK,QAAQ,GAAG;sBACX,KAAK,aAAa,GAAG;wBACnB,KAAK,eAAe,GAAG;sBACzB,KAAK,SAAS;sBACd,KAAK,SAAS;sBACd,KAAK,SAAS;yBACX,KAAK,UAAU,SAAS,QAAQ;6BAC5B,KAAK,iBAAiB,GAAG;iBACrC,KAAK,QAAQ,GAAG;mBACd,KAAKG,GAAa;oBACjB,KAAKC,GAAc;mBACpB,KAAKC,GAAa;kBACnB,KAAKC,GAAY;qBACd,KAAKC,GAAe;;;;;;;CAOvC;CAIA;CAaA;CAYA;CAMA;CAeA;AAWF;AAvQG,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAO,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAO,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACxC,EAAA,CAAA,EAAS;CAAE,WAAW;CAAc,MAAM;AAAO,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAClD,EAAA,CAAA,EAAS,EAAE,SAAS,GAAK,CAAC,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GACT,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,SAAA,KAAA,CAAA,GACT,EAAA,CAAA,EAAS,EAAE,WAAW,gBAAgB,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GACvC,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,SAAS;CAAM,MAAM;AAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,EAAE,WAAW,kBAAkB,CAAC,CAAA,GAAA,EAAA,WAAA,iBAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAxCX,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"sken-textarea.js","names":[],"sources":["../src/components/sken-textarea.ts"],"sourcesContent":["// ── <sken-textarea> — framework-ready Web Component ────────────────\n\nimport type { SkenTextareaResize, SkenTextareaSize } from '@sken-ds/contracts'\nimport { LitElement, css, html, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nfunction slotHasContent(slot: HTMLSlotElement | null): boolean {\n if (!slot) return false\n return slot\n .assignedNodes({ flatten: true })\n .some((node) => node.nodeType !== Node.TEXT_NODE || (node.textContent ?? '').trim() !== '')\n}\n\n@customElement('sken-textarea')\nexport class SkenTextarea extends LitElement {\n static formAssociated = true\n\n #internals: ElementInternals | undefined = undefined\n\n constructor() {\n super()\n try {\n this.#internals = this.attachInternals()\n } catch {\n this.#internals = undefined\n }\n }\n\n @property({ reflect: true }) size: SkenTextareaSize = 'md'\n @property() label: string | undefined = undefined\n @property({ reflect: true, type: Number }) rows = 4\n @property({ reflect: true, type: Number }) cols: number | undefined = undefined\n @property({ attribute: 'max-length', type: Number }) maxLength: number | undefined = undefined\n @property({ reflect: true }) resize: SkenTextareaResize = 'vertical'\n @property() placeholder: string | undefined = undefined\n @property() value: string | undefined = undefined\n @property({ attribute: 'default-value' }) defaultValue: string | undefined = undefined\n @property({ reflect: true, type: Boolean }) disabled = false\n @property({ reflect: true, type: Boolean }) readonly = 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({ attribute: 'aria-label' }) override ariaLabel: string | null = null\n\n #internalValue: string = ''\n\n private readonly _textareaId = `sken-textarea-${crypto.randomUUID()}`\n\n static styles = css`\n :host {\n display: inline-block;\n inline-size: 100%;\n }\n\n .field {\n display: grid;\n gap: var(--sken-1, 0.25rem);\n }\n\n .label {\n font-size: var(--sken-size-xs, 0.75rem);\n font-weight: 500;\n color: var(--sken-foreground);\n }\n\n :host([required]) .label::after {\n content: ' *';\n }\n\n :host([required][invalid]) .label,\n :host([required][invalid]) .label::after {\n color: var(--sken-destructive);\n }\n\n .textarea-wrapper {\n position: relative;\n display: flex;\n flex-direction: column;\n inline-size: 100%;\n }\n\n textarea {\n box-sizing: border-box;\n inline-size: 100%;\n border: 1px solid var(--sken-border);\n border-radius: var(--sken-md);\n background: var(--sken-input);\n color: var(--sken-foreground);\n font-family: var(--sken-family-sans);\n font-size: var(--sken-size-md);\n line-height: 1.5;\n padding-block: var(--sken-2);\n padding-inline: var(--sken-3);\n min-block-size: 4.5rem;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n /* Resize is controlled by the resize attribute, not by\n user-agent stylesheet, so consumers can override. */\n }\n\n textarea::placeholder {\n color: var(--sken-muted-foreground);\n opacity: 1;\n }\n\n /* ── Slot containers ──────────────────────────────────────\n Position: relative (not absolute) so the slotted content\n flows naturally above and below the textarea. The wrapper\n has a flex column, so the textarea's vertical padding is\n NOT auto-adjusted (unlike SkenInput). Slot height adds to\n the wrapper's natural height. */\n .slot {\n display: flex;\n align-items: center;\n color: var(--sken-muted-foreground);\n min-block-size: 0.25rem;\n }\n\n .slot[data-empty] {\n display: none;\n }\n\n .slot-start {\n padding-block-end: 0.25rem;\n }\n\n .slot-end {\n padding-block-start: 0.25rem;\n }\n\n /* ── Sizes ────────────────────────────────────────────────── */\n :host([size='sm']) textarea {\n padding-block: var(--sken-1);\n padding-inline: var(--sken-2);\n font-size: var(--sken-size-sm);\n }\n :host([size='md']) textarea {\n /* Default styles above. */\n }\n :host([size='lg']) textarea {\n padding-block: var(--sken-3);\n padding-inline: var(--sken-4);\n font-size: var(--sken-size-lg);\n }\n\n /* ── Resize policies ────────────────────────────────────── */\n :host([resize='none']) textarea {\n resize: none;\n }\n :host([resize='vertical']) textarea {\n resize: vertical;\n }\n :host([resize='horizontal']) textarea {\n resize: horizontal;\n }\n :host([resize='both']) textarea {\n resize: both;\n }\n\n /* ── States ───────────────────────────────────────────────── */\n .textarea-wrapper:hover textarea:not(:disabled):not(:read-only) {\n border-color: var(--sken-foreground);\n }\n .textarea-wrapper:focus-within textarea {\n outline: 2px solid var(--sken-ring, currentColor);\n outline-offset: 2px;\n border-color: var(--sken-primary);\n }\n textarea:disabled {\n cursor: not-allowed;\n opacity: var(--sken-disabled);\n }\n textarea:read-only {\n background: var(--sken-muted);\n }\n :host([invalid]) textarea {\n border-color: var(--sken-destructive);\n }\n :host([invalid]) .textarea-wrapper:focus-within textarea {\n outline-color: var(--sken-destructive);\n }\n `\n\n override connectedCallback(): void {\n super.connectedCallback()\n if (this.value === undefined) {\n this.#internalValue = this.defaultValue ?? ''\n }\n this.#syncFormValue()\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback()\n this.#slotStartObserver?.disconnect()\n this.#slotEndObserver?.disconnect()\n }\n\n protected override firstUpdated(): void {\n const startEl = this.renderRoot.querySelector('.slot-start') as HTMLElement | null\n const endEl = this.renderRoot.querySelector('.slot-end') as HTMLElement | null\n if (!startEl || !endEl) return\n\n this.#slotStartObserver = new MutationObserver(() => this.#adjustSlotVisibility())\n this.#slotStartObserver.observe(startEl, { childList: true, subtree: true, attributes: true })\n this.#slotEndObserver = new MutationObserver(() => this.#adjustSlotVisibility())\n this.#slotEndObserver.observe(endEl, { childList: true, subtree: true, attributes: true })\n\n const startSlot = this.renderRoot.querySelector('slot[name=\"start\"]') as HTMLSlotElement | null\n const endSlot = this.renderRoot.querySelector('slot[name=\"end\"]') as HTMLSlotElement | null\n startSlot?.addEventListener('slotchange', this.#adjustSlotVisibility)\n endSlot?.addEventListener('slotchange', this.#adjustSlotVisibility)\n\n this.#adjustSlotVisibility()\n }\n\n #adjustSlotVisibility = (): void => {\n const startEl = this.renderRoot.querySelector('.slot-start') as HTMLElement | null\n const endEl = this.renderRoot.querySelector('.slot-end') as HTMLElement | null\n const startSlot = this.renderRoot.querySelector('slot[name=\"start\"]') as HTMLSlotElement | null\n const endSlot = this.renderRoot.querySelector('slot[name=\"end\"]') as HTMLSlotElement | null\n startEl?.toggleAttribute('data-empty', !slotHasContent(startSlot))\n endEl?.toggleAttribute('data-empty', !slotHasContent(endSlot))\n }\n\n #slotStartObserver: MutationObserver | undefined = undefined\n #slotEndObserver: MutationObserver | undefined = undefined\n\n // ── Form-association callbacks ─────────────────────────────\n formResetCallback(): void {\n if (this.value === undefined) {\n this.#internalValue = this.defaultValue ?? ''\n const ta = this.renderRoot.querySelector('textarea') as HTMLTextAreaElement | null\n if (ta) ta.value = this.#internalValue\n this.#syncFormValue()\n } else {\n this.requestUpdate()\n }\n }\n\n formDisabledCallback(isDisabled: boolean): void {\n this.disabled = isDisabled\n }\n\n #syncFormValue(): void {\n if (!this.#internals) return\n const value = this.value ?? this.#internalValue\n this.#internals.setFormValue(value)\n }\n\n protected override render() {\n const value = this.value ?? this.#internalValue\n return html`\n <div class=\"field\" part=\"field\">\n ${\n this.label\n ? html`<label class=\"label\" part=\"label\" for=${this._textareaId}>${this.label}</label>`\n : nothing\n }\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <div class=\"slot slot-start\" part=\"slot-start\">\n <slot name=\"start\"></slot>\n </div>\n <textarea\n id=${this._textareaId}\n part=\"textarea\"\n .value=${value}\n rows=${this.rows}\n cols=${this.cols ?? ''}\n maxlength=${this.maxLength ?? ''}\n placeholder=${this.placeholder ?? ''}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n aria-invalid=${this.invalid ? 'true' : 'false'}\n aria-describedby=${this.describedById ?? ''}\n aria-label=${this.ariaLabel ?? ''}\n name=${this.name ?? ''}\n @input=${this.#handleInput}\n @change=${this.#handleChange}\n @focus=${this.#handleFocus}\n @blur=${this.#handleBlur}\n @keydown=${this.#handleKeydown}\n ></textarea>\n <div class=\"slot slot-end\" part=\"slot-end\">\n <slot name=\"end\"></slot>\n </div>\n </div>\n </div>\n `\n }\n\n #handleInput = (event: Event) => {\n const target = event.target as HTMLTextAreaElement\n const newValue = target.value\n if (this.value === undefined) this.#internalValue = newValue\n this.#syncFormValue()\n this.dispatchEvent(\n new CustomEvent<string>('sken-input', { detail: newValue, bubbles: true, composed: true }),\n )\n }\n\n #handleChange = (event: Event) => {\n const target = event.target as HTMLTextAreaElement\n this.#syncFormValue()\n this.dispatchEvent(\n new CustomEvent<string>('sken-change', {\n detail: target.value,\n bubbles: true,\n composed: true,\n }),\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 #handleKeydown = (event: KeyboardEvent) => {\n if (event.key !== 'Enter' || event.isComposing) return\n if (event.shiftKey) return // newline; let the browser insert it\n if (this.disabled || this.readonly) return\n event.preventDefault()\n const form = this.#internals?.form\n if (!form) return\n form.requestSubmit()\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-textarea': SkenTextarea\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { t as e } from "./decorate-C1e2sg49.js";
|
|
2
|
+
import { LitElement as t, html as n } from "lit";
|
|
3
|
+
import { customElement as r, property as i } from "lit/decorators.js";
|
|
4
|
+
import { defineCustomElements as a } from "@siemens/ix-icons/loader";
|
|
5
|
+
import { defineCustomElements as o } from "@siemens/ix/loader";
|
|
6
|
+
//#region src/vendor/ix.ts
|
|
7
|
+
typeof window < "u" && globalThis.__skenIxRegistered !== !0 && (globalThis.__skenIxRegistered = !0, o(window), a(window));
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/components/sken-tooltip.ts
|
|
10
|
+
var s = {
|
|
11
|
+
sm: "var(--sken-sm)",
|
|
12
|
+
md: "var(--sken-md)",
|
|
13
|
+
lg: "var(--sken-lg)",
|
|
14
|
+
full: "var(--sken-full)"
|
|
15
|
+
}, c = class extends t {
|
|
16
|
+
constructor(...e) {
|
|
17
|
+
super(...e), this.for_ = "", this.content = "", this.placement = "top", this.showDelay = 0, this.hideDelay = 0, this.interactive = !1, this.radius = "sm", this.#t = () => {
|
|
18
|
+
this.dispatchEvent(new CustomEvent("sken-show", {
|
|
19
|
+
bubbles: !0,
|
|
20
|
+
composed: !0
|
|
21
|
+
}));
|
|
22
|
+
}, this.#n = () => {
|
|
23
|
+
this.dispatchEvent(new CustomEvent("sken-hide", {
|
|
24
|
+
bubbles: !0,
|
|
25
|
+
composed: !0
|
|
26
|
+
}));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
createRenderRoot() {
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
render() {
|
|
33
|
+
return n`
|
|
34
|
+
<ix-tooltip
|
|
35
|
+
data-sken-tooltip-engine=""
|
|
36
|
+
for=${this.for_}
|
|
37
|
+
title-content=${this.content}
|
|
38
|
+
placement=${this.placement}
|
|
39
|
+
?interactive=${this.interactive}
|
|
40
|
+
data-testid="sken-tooltip"
|
|
41
|
+
@ixTooltipShow=${this.#t}
|
|
42
|
+
@ixTooltipHide=${this.#n}
|
|
43
|
+
></ix-tooltip>
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
updated() {
|
|
47
|
+
let e = this.querySelector("[data-sken-tooltip-engine]");
|
|
48
|
+
e && (this.showDelay > 0 && e.showDelay !== this.showDelay && (e.showDelay = this.showDelay), this.hideDelay > 0 && e.hideDelay !== this.hideDelay && (e.hideDelay = this.hideDelay), e.style && e.style.setProperty("--sken-tooltip-radius", s[this.radius]), this.#e(e));
|
|
49
|
+
}
|
|
50
|
+
#e(e) {
|
|
51
|
+
let t = () => {
|
|
52
|
+
let t = e.shadowRoot?.querySelector(".tooltip-container");
|
|
53
|
+
t && t.style.setProperty("border-radius", `var(--sken-${this.radius})`);
|
|
54
|
+
};
|
|
55
|
+
t(), queueMicrotask(t);
|
|
56
|
+
}
|
|
57
|
+
#t;
|
|
58
|
+
#n;
|
|
59
|
+
};
|
|
60
|
+
e([i({ attribute: "for" })], c.prototype, "for_", void 0), e([i()], c.prototype, "content", void 0), e([i()], c.prototype, "placement", void 0), e([i({
|
|
61
|
+
attribute: "show-delay",
|
|
62
|
+
type: Number
|
|
63
|
+
})], c.prototype, "showDelay", void 0), e([i({
|
|
64
|
+
attribute: "hide-delay",
|
|
65
|
+
type: Number
|
|
66
|
+
})], c.prototype, "hideDelay", void 0), e([i({ type: Boolean })], c.prototype, "interactive", void 0), e([i()], c.prototype, "radius", void 0), c = e([r("sken-tooltip")], c);
|
|
67
|
+
//#endregion
|
|
68
|
+
export { c as SkenTooltip };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=sken-tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sken-tooltip.js","names":[],"sources":["../src/vendor/ix.ts","../src/components/sken-tooltip.ts"],"sourcesContent":["// ── iX vendor bootstrap (side-effect module) ────────────────────\n\nimport { defineCustomElements as defineIxIconElements } from '@siemens/ix-icons/loader'\nimport { defineCustomElements as defineIxElements } from '@siemens/ix/loader'\nimport '../css/ix-bridge.css'\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __skenIxRegistered: boolean | undefined\n}\n\nif (typeof window !== 'undefined' && globalThis.__skenIxRegistered !== true) {\n globalThis.__skenIxRegistered = true\n defineIxElements(window)\n defineIxIconElements(window)\n}\n","// ── <sken-tooltip> — Sken contract implementation (ADR-0007) ─────────\n\nimport type { SkenTooltipPlacement, SkenTooltipRadius } from '@sken-ds/contracts'\nimport { LitElement, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport '../vendor/ix.js'\n\nconst RADIUS_TOKEN: Record<SkenTooltipRadius, string> = {\n sm: 'var(--sken-sm)',\n md: 'var(--sken-md)',\n lg: 'var(--sken-lg)',\n full: 'var(--sken-full)',\n}\n\n@customElement('sken-tooltip')\nexport class SkenTooltip extends LitElement {\n @property({ attribute: 'for' }) for_ = ''\n @property() content = ''\n @property() placement: SkenTooltipPlacement = 'top'\n @property({ attribute: 'show-delay', type: Number }) showDelay = 0\n @property({ attribute: 'hide-delay', type: Number }) hideDelay = 0\n @property({ type: Boolean }) interactive = false\n @property() radius: SkenTooltipRadius = 'sm'\n\n protected override createRenderRoot(): HTMLElement {\n return this as unknown as HTMLElement\n }\n\n override render() {\n return html`\n <ix-tooltip\n data-sken-tooltip-engine=\"\"\n for=${this.for_}\n title-content=${this.content}\n placement=${this.placement}\n ?interactive=${this.interactive}\n data-testid=\"sken-tooltip\"\n @ixTooltipShow=${this.#handleShow}\n @ixTooltipHide=${this.#handleHide}\n ></ix-tooltip>\n `\n }\n\n protected override updated(): void {\n const el = this.querySelector('[data-sken-tooltip-engine]') as\n | (HTMLElement & {\n showDelay?: number\n hideDelay?: number\n style?: CSSStyleDeclaration\n shadowRoot?: ShadowRoot | null\n })\n | null\n if (!el) return\n if (this.showDelay > 0 && el.showDelay !== this.showDelay) {\n el.showDelay = this.showDelay\n }\n if (this.hideDelay > 0 && el.hideDelay !== this.hideDelay) {\n el.hideDelay = this.hideDelay\n }\n if (el.style) {\n el.style.setProperty('--sken-tooltip-radius', RADIUS_TOKEN[this.radius])\n }\n this.#stampContainerRadius(el)\n }\n\n #stampContainerRadius(el: HTMLElement & { shadowRoot?: ShadowRoot | null }): void {\n const apply = () => {\n const container = el.shadowRoot?.querySelector('.tooltip-container') as HTMLElement | null\n if (container) {\n container.style.setProperty('border-radius', `var(--sken-${this.radius})`)\n }\n }\n apply()\n queueMicrotask(apply)\n }\n\n #handleShow = (): void => {\n this.dispatchEvent(new CustomEvent('sken-show', { bubbles: true, composed: true }))\n }\n\n #handleHide = (): void => {\n this.dispatchEvent(new CustomEvent('sken-hide', { bubbles: true, composed: true }))\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sken-tooltip': SkenTooltip\n }\n}\n\nexport type { SkenTooltipPlacement, SkenTooltipProps, SkenTooltipRadius } from '@sken-ds/contracts'\n"],"mappings":";;;;;;AAWI,OAAO,SAAW,OAAe,WAAW,uBAAuB,OACrE,WAAW,qBAAqB,IAChC,EAAiB,MAAM,GACvB,EAAqB,MAAM;;;ACP7B,IAAM,IAAkD;CACtD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;AACR,GAGa,IAAN,cAA0B,EAAW;;EAiEhB,aAhEa,KAAA,OAAA,IACjB,KAAA,UAAA,IACwB,KAAA,YAAA,OACmB,KAAA,YAAA,GACA,KAAA,YAAA,GACtB,KAAA,cAAA,IACH,KAAA,SAAA,MAsDd,KAAA,WAAA;GACxB,KAAK,cAAc,IAAI,YAAY,aAAa;IAAE,SAAS;IAAM,UAAU;GAAK,CAAC,CAAC;EACpF,GAE0B,KAAA,WAAA;GACxB,KAAK,cAAc,IAAI,YAAY,aAAa;IAAE,SAAS;IAAM,UAAU;GAAK,CAAC,CAAC;EACpF;;CA1DA,mBAAmD;EACjD,OAAO;CACT;CAEA,SAAkB;EAChB,OAAO,CAAI;;;cAGD,KAAK,KAAK;wBACA,KAAK,QAAQ;oBACjB,KAAK,UAAU;uBACZ,KAAK,YAAY;;yBAEf,KAAK,GAAY;yBACjB,KAAK,GAAY;;;CAGxC;CAEA,UAAmC;EACjC,IAAM,IAAK,KAAK,cAAc,4BAA4B;EAQrD,MACD,KAAK,YAAY,KAAK,EAAG,cAAc,KAAK,cAC9C,EAAG,YAAY,KAAK,YAElB,KAAK,YAAY,KAAK,EAAG,cAAc,KAAK,cAC9C,EAAG,YAAY,KAAK,YAElB,EAAG,SACL,EAAG,MAAM,YAAY,yBAAyB,EAAa,KAAK,OAAO,GAEzE,KAAK,GAAsB,CAAE;CAC/B;CAEA,GAAsB,GAA4D;EAChF,IAAM,UAAc;GAClB,IAAM,IAAY,EAAG,YAAY,cAAc,oBAAoB;GACnE,AAAI,KACF,EAAU,MAAM,YAAY,iBAAiB,cAAc,KAAK,OAAO,EAAE;EAE7E;EAEA,AADA,EAAM,GACN,eAAe,CAAK;CACtB;CAEA;CAIA;AAGF;AAnEG,EAAA,CAAA,EAAS,EAAE,WAAW,MAAM,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GAC7B,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,WAAA,KAAA,CAAA,GACT,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GACT,EAAA,CAAA,EAAS;CAAE,WAAW;CAAc,MAAM;AAAO,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAClD,EAAA,CAAA,EAAS;CAAE,WAAW;CAAc,MAAM;AAAO,CAAC,CAAA,GAAA,EAAA,WAAA,aAAA,KAAA,CAAA,GAClD,EAAA,CAAA,EAAS,EAAE,MAAM,QAAQ,CAAC,CAAA,GAAA,EAAA,WAAA,eAAA,KAAA,CAAA,GAC1B,EAAA,CAAA,EAAS,CAAA,GAAA,EAAA,WAAA,UAAA,KAAA,CAAA,GARX,IAAA,EAAA,CAAA,EAAc,cAAc,CAAA,GAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sken-ds/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"access": "public"
|
|
@@ -36,6 +36,18 @@
|
|
|
36
36
|
"types": "./dist/sken-layout.d.ts",
|
|
37
37
|
"import": "./dist/sken-layout.js"
|
|
38
38
|
},
|
|
39
|
+
"./sken-nav": {
|
|
40
|
+
"types": "./dist/sken-nav.d.ts",
|
|
41
|
+
"import": "./dist/sken-nav.js"
|
|
42
|
+
},
|
|
43
|
+
"./sken-nav-item": {
|
|
44
|
+
"types": "./dist/sken-nav-item.d.ts",
|
|
45
|
+
"import": "./dist/sken-nav-item.js"
|
|
46
|
+
},
|
|
47
|
+
"./sken-nav-group": {
|
|
48
|
+
"types": "./dist/sken-nav-group.d.ts",
|
|
49
|
+
"import": "./dist/sken-nav-group.js"
|
|
50
|
+
},
|
|
39
51
|
"./sken-layout-region": {
|
|
40
52
|
"types": "./dist/sken-layout-region.d.ts",
|
|
41
53
|
"import": "./dist/sken-layout-region.js"
|
|
@@ -79,36 +91,42 @@
|
|
|
79
91
|
"./sken-dialog": {
|
|
80
92
|
"types": "./dist/sken-dialog.d.ts",
|
|
81
93
|
"import": "./dist/sken-dialog.js"
|
|
94
|
+
},
|
|
95
|
+
"./sken-tooltip": {
|
|
96
|
+
"types": "./dist/sken-tooltip.d.ts",
|
|
97
|
+
"import": "./dist/sken-tooltip.js"
|
|
82
98
|
}
|
|
83
99
|
},
|
|
84
100
|
"files": [
|
|
85
101
|
"dist",
|
|
86
102
|
"README.md"
|
|
87
103
|
],
|
|
104
|
+
"scripts": {
|
|
105
|
+
"build": "vite build",
|
|
106
|
+
"dev": "vite build --watch",
|
|
107
|
+
"typecheck": "tsc --noEmit",
|
|
108
|
+
"lint": "echo 'lint placeholder'",
|
|
109
|
+
"test": "vitest run",
|
|
110
|
+
"test:coverage": "vitest run --coverage",
|
|
111
|
+
"clean": "rm -rf dist .turbo *.tsbuildinfo coverage"
|
|
112
|
+
},
|
|
88
113
|
"dependencies": {
|
|
89
114
|
"@lit/context": "^1.1.6",
|
|
90
115
|
"@siemens/ix": "^5.2.0",
|
|
91
116
|
"@siemens/ix-icons": "^3.5.0",
|
|
92
|
-
"@
|
|
117
|
+
"@sken-ds/contracts": "*",
|
|
118
|
+
"@sken-ds/icons": "*",
|
|
119
|
+
"@tanstack/lit-table": "^9.1.2",
|
|
93
120
|
"@tanstack/match-sorter-utils": "^9.0.0",
|
|
94
121
|
"@tanstack/table-core": "^9.0.0",
|
|
95
122
|
"lit": "^3.3.3",
|
|
96
|
-
"lit-html": "^3.3.3"
|
|
97
|
-
"@sken-ds/contracts": "0.5.0"
|
|
123
|
+
"lit-html": "^3.3.3"
|
|
98
124
|
},
|
|
99
125
|
"devDependencies": {
|
|
100
|
-
"@vitest/coverage-v8": "^4.1.
|
|
126
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
101
127
|
"happy-dom": "^20.11.1",
|
|
102
128
|
"typescript": "^6.0.3",
|
|
103
|
-
"vite": "^8.2.
|
|
129
|
+
"vite": "^8.2.2",
|
|
104
130
|
"vitest": "^4.1.10"
|
|
105
|
-
},
|
|
106
|
-
"scripts": {
|
|
107
|
-
"build": "vite build && node scripts/copy-css-assets.mjs",
|
|
108
|
-
"dev": "vite build --watch",
|
|
109
|
-
"typecheck": "tsc --noEmit",
|
|
110
|
-
"lint": "echo 'lint placeholder'",
|
|
111
|
-
"test": "vitest run",
|
|
112
|
-
"clean": "rm -rf dist .turbo *.tsbuildinfo"
|
|
113
131
|
}
|
|
114
|
-
}
|
|
132
|
+
}
|