@mhmo91/schmancy 0.9.14 → 0.9.16
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/custom-elements.json +57 -30
- package/dist/agent/schmancy.agent.js +178 -25
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/agent/schmancy.manifest.json +208 -12
- package/dist/autocomplete-CgWUCUU-.js.map +1 -1
- package/dist/autocomplete-EM0jE7X2.cjs.map +1 -1
- package/dist/button.cjs.map +1 -1
- package/dist/button.js.map +1 -1
- package/dist/checkbox-Br84TiCs.js.map +1 -1
- package/dist/checkbox-DtcFMgZL.cjs.map +1 -1
- package/dist/chips-BNYOweGm.js.map +1 -1
- package/dist/chips-DoCu5YQb.cjs.map +1 -1
- package/dist/extra-BUgyMgjl.cjs.map +1 -1
- package/dist/extra-HwbaUnCD.js.map +1 -1
- package/dist/form-rCZqoAoK.js.map +1 -1
- package/dist/form-wI58M85H.cjs.map +1 -1
- package/dist/handover/agent-runtime-followups.md +247 -0
- package/dist/handover/agent-runtime-v1.md +109 -0
- package/dist/input-BGNZlfL8.cjs.map +1 -1
- package/dist/input-Bc3bVISm.js.map +1 -1
- package/dist/input-chip-CiG61y-N.js.map +1 -1
- package/dist/input-chip-p24lkYtY.cjs.map +1 -1
- package/dist/radio-group-B72sYGnS.js.map +1 -1
- package/dist/radio-group-B7DuNxUq.cjs.map +1 -1
- package/dist/select-DFxoBgEf.cjs.map +1 -1
- package/dist/select-wFDKDLQI.js.map +1 -1
- package/dist/switch.cjs.map +1 -1
- package/dist/switch.js.map +1 -1
- package/dist/textarea-B2544vx9.cjs.map +1 -1
- package/dist/textarea-CS-KdSLz.js.map +1 -1
- package/package.json +3 -2
- package/src/autocomplete/autocomplete.ts +12 -1
- package/src/button/button.ts +6 -1
- package/src/button/icon-button.ts +7 -1
- package/src/checkbox/checkbox.ts +7 -1
- package/src/chips/chips.ts +14 -0
- package/src/chips/input-chip.ts +6 -6
- package/src/extra/countries/countries.ts +10 -0
- package/src/extra/timezone/timezone.ts +8 -1
- package/src/form/form.ts +9 -2
- package/src/input/input.ts +11 -4
- package/src/radio-group/radio-button.ts +10 -1
- package/src/radio-group/radio-group.ts +18 -0
- package/src/select/select.ts +12 -1
- package/src/switch/switch.ts +7 -4
- package/src/textarea/textarea.ts +9 -1
- package/types/src/autocomplete/autocomplete.d.ts +12 -1
- package/types/src/button/button.d.ts +6 -1
- package/types/src/button/icon-button.d.ts +7 -1
- package/types/src/checkbox/checkbox.d.ts +7 -1
- package/types/src/chips/chips.d.ts +14 -0
- package/types/src/chips/input-chip.d.ts +6 -6
- package/types/src/extra/countries/countries.d.ts +10 -0
- package/types/src/extra/timezone/timezone.d.ts +8 -1
- package/types/src/form/form.d.ts +9 -2
- package/types/src/input/input.d.ts +11 -4
- package/types/src/radio-group/radio-button.d.ts +10 -1
- package/types/src/radio-group/radio-group.d.ts +18 -0
- package/types/src/select/select.d.ts +12 -1
- package/types/src/switch/switch.d.ts +7 -4
- package/types/src/textarea/textarea.d.ts +9 -1
package/dist/switch.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.cjs","names":[],"sources":["../src/switch/switch.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/index'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nexport type SchmancySwitchChangeEvent = CustomEvent<{ value: boolean }>\n\n/**\n * Binary on/off control. Form-associated, keyboard-accessible, semantically a
|
|
1
|
+
{"version":3,"file":"switch.cjs","names":[],"sources":["../src/switch/switch.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/index'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nexport type SchmancySwitchChangeEvent = CustomEvent<{ value: boolean }>\n\n/**\n * Binary on/off control with immediate effect. Form-associated, keyboard-accessible, semantically a switch (ARIA role=\"switch\"). Distinct from `schmancy-checkbox`: a switch represents an immediate state change, a checkbox represents a selection in a form to be submitted.\n *\n * @element schmancy-switch\n * @summary Use when flipping the control takes effect right away (e.g. \"Dark mode\", \"Enable notifications\"). Prefer schmancy-checkbox for form submissions.\n * @example\n * <schmancy-switch ?checked=${this.darkMode} @change=${(e) => this.darkMode = e.detail.value}>\n * Dark mode\n * </schmancy-switch>\n * @platform switch change - Accessible native `<button role=\"switch\" aria-checked>` under the hood. No native HTML element exists; falls back to a styled checkbox if the tag never registers.\n * @fires change - `CustomEvent<{ value: boolean }>` when the state changes.\n * @attr checked - Initial checked state (also reflected via `value`).\n * @attr disabled - Disables interaction.\n * @attr required - Requires the switch to be on for form validity.\n * @attr name - Form field name for submission.\n * @csspart track - The background track.\n * @csspart thumb - The moving thumb.\n */\n@customElement('schmancy-switch')\nexport class SchmancySwitch extends TailwindElement(css`\n\t:host {\n\t\tdisplay: inline-block;\n\t}\n\t:host([disabled]) {\n\t\topacity: 0.38;\n\t\tpointer-events: none;\n\t}\n\tbutton {\n\t\tappearance: none;\n\t\tbackground: none;\n\t\tborder: 0;\n\t\tpadding: 0;\n\t\tcursor: pointer;\n\t\tfont: inherit;\n\t}\n\t.track {\n\t\twidth: 2.25rem;\n\t\theight: 1.25rem;\n\t\tborder-radius: 999px;\n\t\tbackground: var(--schmancy-sys-color-surface-containerHighest, #e0e0e0);\n\t\tborder: 1px solid var(--schmancy-sys-color-outline, #79747e);\n\t\tposition: relative;\n\t\ttransition: background 150ms ease, border-color 150ms ease;\n\t}\n\t:host(:state(checked)) .track {\n\t\tbackground: var(--schmancy-sys-color-primary-default, #6750a4);\n\t\tborder-color: var(--schmancy-sys-color-primary-default, #6750a4);\n\t}\n\t.thumb {\n\t\tposition: absolute;\n\t\ttop: 50%;\n\t\tleft: 0.125rem;\n\t\twidth: 0.75rem;\n\t\theight: 0.75rem;\n\t\tborder-radius: 999px;\n\t\tbackground: var(--schmancy-sys-color-outline, #79747e);\n\t\ttransform: translateY(-50%);\n\t\ttransition: transform 150ms ease, background 150ms ease, width 150ms ease, height 150ms ease;\n\t}\n\t:host(:state(checked)) .thumb {\n\t\ttransform: translate(1rem, -50%);\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tbackground: var(--schmancy-sys-color-primary-on, #ffffff);\n\t}\n\tbutton:focus-visible .track {\n\t\toutline: 2px solid var(--schmancy-sys-color-primary-default, #6750a4);\n\t\toutline-offset: 2px;\n\t}\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.track, .thumb { transition: none; }\n\t}\n`) {\n\tstatic formAssociated = true\n\tprivate internals: ElementInternals | undefined\n\n\t@property({ type: Boolean, reflect: true }) checked = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: String }) name = ''\n\t@property({ type: String }) value = 'on'\n\t@property({ type: String }) label = ''\n\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tget form(): HTMLFormElement | null {\n\t\treturn this.internals?.form ?? null\n\t}\n\n\tprotected updated(changed: Map<string, unknown>) {\n\t\tsuper.updated?.(changed)\n\t\tif (changed.has('checked') || changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.checked ? this.value : null)\n\t\t\tif (this.checked) this.internals?.states.add('checked')\n\t\t\telse this.internals?.states.delete('checked')\n\t\t}\n\t\tif (changed.has('required') || changed.has('checked')) {\n\t\t\tif (this.required && !this.checked) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'This switch is required.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback() {\n\t\tthis.checked = this.hasAttribute('checked')\n\t}\n\n\tformDisabledCallback(disabled: boolean) {\n\t\tthis.disabled = disabled\n\t}\n\n\tpublic checkValidity(): boolean {\n\t\treturn this.internals?.checkValidity() ?? true\n\t}\n\n\tpublic reportValidity(): boolean {\n\t\treturn this.internals?.reportValidity() ?? true\n\t}\n\n\tprivate _toggle = () => {\n\t\tif (this.disabled) return\n\t\tthis.checked = !this.checked\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('change', {\n\t\t\t\tdetail: { value: this.checked },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _onKeydown = (e: KeyboardEvent) => {\n\t\tif (e.key === ' ' || e.key === 'Enter') {\n\t\t\te.preventDefault()\n\t\t\tthis._toggle()\n\t\t}\n\t}\n\n\trender() {\n\t\treturn html`\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"switch\"\n\t\t\t\taria-checked=${this.checked ? 'true' : 'false'}\n\t\t\t\taria-label=${this.label || nothing}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\t?disabled=${this.disabled}\n\t\t\t\t@click=${this._toggle}\n\t\t\t\t@keydown=${this._onKeydown}\n\t\t\t>\n\t\t\t\t<span part=\"track\" class=\"track\">\n\t\t\t\t\t<span part=\"thumb\" class=\"thumb\"></span>\n\t\t\t\t</span>\n\t\t\t</button>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-switch': SchmancySwitch\n\t}\n}\n"],"mappings":"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"}
|
package/dist/switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.js","names":[],"sources":["../src/switch/switch.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/index'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nexport type SchmancySwitchChangeEvent = CustomEvent<{ value: boolean }>\n\n/**\n * Binary on/off control. Form-associated, keyboard-accessible, semantically a
|
|
1
|
+
{"version":3,"file":"switch.js","names":[],"sources":["../src/switch/switch.ts"],"sourcesContent":["import { TailwindElement } from '@mixins/index'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nexport type SchmancySwitchChangeEvent = CustomEvent<{ value: boolean }>\n\n/**\n * Binary on/off control with immediate effect. Form-associated, keyboard-accessible, semantically a switch (ARIA role=\"switch\"). Distinct from `schmancy-checkbox`: a switch represents an immediate state change, a checkbox represents a selection in a form to be submitted.\n *\n * @element schmancy-switch\n * @summary Use when flipping the control takes effect right away (e.g. \"Dark mode\", \"Enable notifications\"). Prefer schmancy-checkbox for form submissions.\n * @example\n * <schmancy-switch ?checked=${this.darkMode} @change=${(e) => this.darkMode = e.detail.value}>\n * Dark mode\n * </schmancy-switch>\n * @platform switch change - Accessible native `<button role=\"switch\" aria-checked>` under the hood. No native HTML element exists; falls back to a styled checkbox if the tag never registers.\n * @fires change - `CustomEvent<{ value: boolean }>` when the state changes.\n * @attr checked - Initial checked state (also reflected via `value`).\n * @attr disabled - Disables interaction.\n * @attr required - Requires the switch to be on for form validity.\n * @attr name - Form field name for submission.\n * @csspart track - The background track.\n * @csspart thumb - The moving thumb.\n */\n@customElement('schmancy-switch')\nexport class SchmancySwitch extends TailwindElement(css`\n\t:host {\n\t\tdisplay: inline-block;\n\t}\n\t:host([disabled]) {\n\t\topacity: 0.38;\n\t\tpointer-events: none;\n\t}\n\tbutton {\n\t\tappearance: none;\n\t\tbackground: none;\n\t\tborder: 0;\n\t\tpadding: 0;\n\t\tcursor: pointer;\n\t\tfont: inherit;\n\t}\n\t.track {\n\t\twidth: 2.25rem;\n\t\theight: 1.25rem;\n\t\tborder-radius: 999px;\n\t\tbackground: var(--schmancy-sys-color-surface-containerHighest, #e0e0e0);\n\t\tborder: 1px solid var(--schmancy-sys-color-outline, #79747e);\n\t\tposition: relative;\n\t\ttransition: background 150ms ease, border-color 150ms ease;\n\t}\n\t:host(:state(checked)) .track {\n\t\tbackground: var(--schmancy-sys-color-primary-default, #6750a4);\n\t\tborder-color: var(--schmancy-sys-color-primary-default, #6750a4);\n\t}\n\t.thumb {\n\t\tposition: absolute;\n\t\ttop: 50%;\n\t\tleft: 0.125rem;\n\t\twidth: 0.75rem;\n\t\theight: 0.75rem;\n\t\tborder-radius: 999px;\n\t\tbackground: var(--schmancy-sys-color-outline, #79747e);\n\t\ttransform: translateY(-50%);\n\t\ttransition: transform 150ms ease, background 150ms ease, width 150ms ease, height 150ms ease;\n\t}\n\t:host(:state(checked)) .thumb {\n\t\ttransform: translate(1rem, -50%);\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t\tbackground: var(--schmancy-sys-color-primary-on, #ffffff);\n\t}\n\tbutton:focus-visible .track {\n\t\toutline: 2px solid var(--schmancy-sys-color-primary-default, #6750a4);\n\t\toutline-offset: 2px;\n\t}\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.track, .thumb { transition: none; }\n\t}\n`) {\n\tstatic formAssociated = true\n\tprivate internals: ElementInternals | undefined\n\n\t@property({ type: Boolean, reflect: true }) checked = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: String }) name = ''\n\t@property({ type: String }) value = 'on'\n\t@property({ type: String }) label = ''\n\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tget form(): HTMLFormElement | null {\n\t\treturn this.internals?.form ?? null\n\t}\n\n\tprotected updated(changed: Map<string, unknown>) {\n\t\tsuper.updated?.(changed)\n\t\tif (changed.has('checked') || changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.checked ? this.value : null)\n\t\t\tif (this.checked) this.internals?.states.add('checked')\n\t\t\telse this.internals?.states.delete('checked')\n\t\t}\n\t\tif (changed.has('required') || changed.has('checked')) {\n\t\t\tif (this.required && !this.checked) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'This switch is required.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback() {\n\t\tthis.checked = this.hasAttribute('checked')\n\t}\n\n\tformDisabledCallback(disabled: boolean) {\n\t\tthis.disabled = disabled\n\t}\n\n\tpublic checkValidity(): boolean {\n\t\treturn this.internals?.checkValidity() ?? true\n\t}\n\n\tpublic reportValidity(): boolean {\n\t\treturn this.internals?.reportValidity() ?? true\n\t}\n\n\tprivate _toggle = () => {\n\t\tif (this.disabled) return\n\t\tthis.checked = !this.checked\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('change', {\n\t\t\t\tdetail: { value: this.checked },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _onKeydown = (e: KeyboardEvent) => {\n\t\tif (e.key === ' ' || e.key === 'Enter') {\n\t\t\te.preventDefault()\n\t\t\tthis._toggle()\n\t\t}\n\t}\n\n\trender() {\n\t\treturn html`\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\trole=\"switch\"\n\t\t\t\taria-checked=${this.checked ? 'true' : 'false'}\n\t\t\t\taria-label=${this.label || nothing}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\t?disabled=${this.disabled}\n\t\t\t\t@click=${this._toggle}\n\t\t\t\t@keydown=${this._onKeydown}\n\t\t\t>\n\t\t\t\t<span part=\"track\" class=\"track\">\n\t\t\t\t\t<span part=\"thumb\" class=\"thumb\"></span>\n\t\t\t\t</span>\n\t\t\t</button>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-switch': SchmancySwitch\n\t}\n}\n"],"mappings":";;;;;AAyBO,IAAA,IAAA,cAA6B,EAAgB,CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAsD9B;;CAAA;AAAA,OAAA,oBAUa;GAAA,GACjC,EAAW;GACd,gBAAA,CAAgB;GAAA;;CAGjB,cAAA;AACC,SAAA,EAAA,KAAA,UAAA,CAbqD,GAAA,KAAA,WAAA,CACC,GAAA,KAAA,WAAA,CACA,GAAA,KAAA,OACpB,IAAA,KAAA,QACC,MAAA,KAAA,QACA,IAAA,KAAA,gBAAA;AAqD/B,QAAK,aACT,KAAK,UAAA,CAAW,KAAK,SACrB,KAAK,cACJ,IAAI,YAAY,UAAU;IACzB,QAAQ,EAAE,OAAO,KAAK,SAAA;IACtB,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA;KAAA,KAAA,cAKS,MAAA;AACP,GAAV,EAAE,QAAQ,OAAO,EAAE,QAAQ,YAC9B,EAAE,gBAAA,EACF,KAAK,SAAA;;AA1DN,MAAA;AACC,QAAK,YAAY,KAAK,iBAAA;UAAA;AAEtB,QAAK,YAAA,KAAY;;;CAInB,IAAA,OAAI;AACH,SAAO,KAAK,WAAW,QAAQ;;CAGhC,QAAkB,GAAA;AACjB,QAAM,UAAU,EAAA,GACZ,EAAQ,IAAI,UAAA,IAAc,EAAQ,IAAI,QAAA,IAAY,EAAQ,IAAI,OAAA,MACjE,KAAK,WAAW,aAAa,KAAK,UAAU,KAAK,QAAQ,KAAA,EACrD,KAAK,UAAS,KAAK,WAAW,OAAO,IAAI,UAAA,GACxC,KAAK,WAAW,OAAO,OAAO,UAAA,IAEhC,EAAQ,IAAI,WAAA,IAAe,EAAQ,IAAI,UAAA,MACtC,KAAK,YAAA,CAAa,KAAK,UAC1B,KAAK,WAAW,YAAY,EAAE,cAAA,CAAc,GAAA,EAAQ,2BAAA,GAEpD,KAAK,WAAW,YAAY,EAAA,CAAA;;CAK/B,oBAAA;AACC,OAAK,UAAU,KAAK,aAAa,UAAA;;CAGlC,qBAAqB,GAAA;AACpB,OAAK,WAAW;;CAGjB,gBAAA;AACC,SAAO,KAAK,WAAW,eAAA,IAAA,CAAmB;;CAG3C,iBAAA;AACC,SAAO,KAAK,WAAW,gBAAA,IAAA,CAAoB;;CAsB5C,SAAA;AACC,SAAO,CAAI;;;;mBAIM,KAAK,UAAU,SAAS,QAAA;iBAC1B,KAAK,SAAS,EAAA;oBACX,KAAK,WAAW,SAAS,QAAA;gBAC7B,KAAK,SAAA;aACR,KAAK,QAAA;eACH,KAAK,WAAA;;;;;;;;;GAtFlB,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,WAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,IAAA,EAAA,CA/D3B,EAAc,kBAAA,CAAA,EAAkB,EAAA;AAAA,SAAA,KAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea-B2544vx9.cjs","names":[],"sources":["../src/textarea/textarea.scss?inline","../src/textarea/textarea.ts"],"sourcesContent":[":host {\n\tborder: unset !important;\n\tline-height: unset !important;\n\tbackground: unset !important;\n\tpadding: unset !important;\n\tfont-size: unset !important;\n\tbox-shadow: unset !important;\n\twidth: -webkit-fill-available;\n\tdisplay: block;\n}\n\n:host([fillHeight]) {\n\theight: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n:host:focus {\n\tbox-shadow: unset !important;\n}\n\ntextarea:focus-visible {\n\toutline: none !important;\n}\n\ntextarea {\n\t/* Inherit typographic styles */\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\tline-height: inherit;\n\tcolor: inherit;\n\tletter-spacing: inherit;\n\ttext-transform: inherit;\n\ttext-decoration: inherit;\n\ttext-indent: inherit;\n\ttext-shadow: inherit;\n\ttext-overflow: inherit;\n\ttext-rendering: inherit;\n\ttext-size-adjust: inherit;\n\ttext-align-last: inherit;\n\toverflow-y: auto; /* Ensure content is scrollable if it exceeds the visible area */\n}\n\n@keyframes onAutoFillStart {\n\tfrom {\n\t}\n\tto {\n\t}\n}\n\ntextarea:-webkit-autofill {\n\tanimation-name: onAutoFillStart;\n}\n","import { LitElement, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { when } from 'lit/directives/when.js'\nimport { distinctUntilChanged, filter, fromEvent, map } from 'rxjs'\nimport style from './textarea.scss?inline'\nimport { TailwindElement } from '@mixins/index'\n\n/**\n * Textarea component with auto-resize and form integration.\n *\n * @prop {string} name - Name attribute for form submission\n * @prop {string} value - Current value of the textarea\n * @prop {string} placeholder - Placeholder text\n * @prop {boolean} required - Whether the field is required\n * @prop {boolean} disabled - Whether the field is disabled\n * @prop {boolean} readonly - Whether the field is read-only\n * @prop {number} rows - Number of visible text rows\n * @prop {number} maxlength - Maximum character length\n */\n@customElement('schmancy-textarea')\nexport default class SchmancyTextarea extends TailwindElement(style) {\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\tstatic formAssociated = true\n\t// private internals\n\tinternals: ElementInternals | undefined\n\ttextareaRef = createRef<HTMLTextAreaElement>()\n\n\tprivate readonly _a11yId = `schmancy-textarea-${Math.random().toString(36).slice(2, 10)}`\n\n\t/**\n\t * The label of the control.\n\t * @attr\n\t * @type {string} label\n\t * @default ''\n\t * @public\n\t */\n\t@property() label = ''\n\n\t/**\n\t * The name of the control.\n\t * @attr name\n\t * @type {string} name\n\t * @default 'name_' + Date.now()\n\t * @public\n\t */\n\t@property() name = 'name_' + Date.now()\n\n\t/**\n\t * The placeholder of the control.\n\t * @attr placeholder\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property() placeholder = ''\n\n\t/**\n\t * The value of the control.\n\t * @attr {string} value - The value of the control.\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) public value = ''\n\n\t/**\n\t * The minlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic minlength: number | undefined\n\n\t/**\n\t * The maxlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic maxlength!: number\n\n\t/**\n\t * The number of columns (width) of the control.\n\t * @attr cols\n\t * @type {number}\n\t * @default 20\n\t * @public\n\t */\n\t@property({ type: Number }) cols = 20\n\n\t/**\n\t * The number of rows (height) of the control.\n\t * When not set, the textarea auto-sizes to fit its content via field-sizing: content.\n\t * @attr rows\n\t * @type {number}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: Number }) rows: number | undefined\n\n\t/**\n\t * Makes the textarea fill the height of its container.\n\t * @attr fillHeight\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean, reflect: true }) fillHeight = false\n\n\t/**\n\t * Automatically adjusts height based on content.\n\t * @attr autoHeight\n\t * @type {boolean}\n\t * @default true\n\t * @public\n\t */\n\t@property({ type: Boolean }) autoHeight = true\n\n\t/**\n\t * Controls whether the textarea can be resized by the user.\n\t * @attr resize\n\t * @type {'none' | 'vertical' | 'horizontal' | 'both'}\n\t * @default 'vertical'\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) resize: 'none' | 'vertical' | 'horizontal' | 'both' = 'vertical'\n\n\t/**\n\t * Specifies how the text in a text area is to be wrapped when submitted in a form.\n\t * @attr wrap\n\t * @type {'hard' | 'soft'}\n\t * @default 'soft'\n\t * @public\n\t */\n\t@property({ type: String }) wrap: 'hard' | 'soft' = 'soft'\n\n\t/**\n\t * The dirname attribute of the control.\n\t * @attr dirname\n\t * @type {string}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: String }) dirname: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) readonly = false\n\t@property({ type: Boolean, reflect: true }) spellcheck = false\n\n\t@property({ type: String, reflect: true }) align: 'left' | 'center' | 'right' = 'left'\n\n\t/**\n\t * The autofocus attribute of the control.\n\t * @attr\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean })\n\tpublic override autofocus!: boolean\n\n\t@property({ type: Number })\n\tpublic override tabIndex = 0\n\n\t@query('textarea') textareaElement!: HTMLTextAreaElement\n\n\t@property() hint: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) public error = false\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\tif (changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.value ?? '')\n\t\t}\n\t\tif (changed.has('required') || changed.has('value')) {\n\t\t\tif (this.required && !this.value) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'Please fill out this field.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.value = this.getAttribute('value') ?? ''\n\t\tthis.error = false\n\t}\n\n\tformDisabledCallback(disabled: boolean): void {\n\t\tthis.disabled = disabled\n\t}\n\n\tfirstUpdated() {\n\t\tif (this.autofocus) {\n\t\t\tthis.focus()\n\t\t}\n\t\tif (this.autoHeight) {\n\t\t\t// Initial adjustment for pre-filled content\n\t\t\tsetTimeout(() => this.adjustHeight(), 0)\n\t\t}\n\t\tfromEvent(this.textareaElement, 'input')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\tfromEvent(this.textareaElement, 'change')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t// emit on enter\n\t\tfromEvent<KeyboardEvent>(this.textareaElement, 'keyup')\n\t\t\t.pipe(\n\t\t\t\tfilter(event => event.key === 'Enter'),\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('enter', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t}\n\n\tget form() {\n\t\treturn this.internals?.form\n\t}\n\n\t/** Checks for validity of the control and shows the browser message if it's invalid. */\n\tpublic reportValidity() {\n\t\treturn this.textareaRef.value?.reportValidity()\n\t}\n\n\t/** Checks for validity of the control and emits the invalid event if it invalid. */\n\tpublic checkValidity() {\n\t\treturn this.textareaRef.value?.checkValidity()\n\t}\n\n\t/** Sets a custom validity message. */\n\tpublic setCustomValidity(message: string) {\n\t\treturn this.textareaRef.value?.setCustomValidity(message)\n\t}\n\n\t/** Selects all text within the textarea. */\n\tpublic select() {\n\t\treturn this.textareaRef.value?.select()\n\t}\n\n\t/** Sets the selection range. */\n\tpublic setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') {\n\t\tthis.textareaRef.value?.setSelectionRange(start, end, direction)\n\t}\n\n\t/** Returns the selected text within the textarea. */\n\tpublic get selectionStart(): number | null {\n\t\treturn this.textareaRef.value?.selectionStart ?? null\n\t}\n\n\tpublic get selectionEnd(): number | null {\n\t\treturn this.textareaRef.value?.selectionEnd ?? null\n\t}\n\n\tpublic get selectionDirection(): 'forward' | 'backward' | 'none' | null {\n\t\treturn this.textareaRef.value?.selectionDirection ?? null\n\t}\n\n\t/** Sets the range of text to be selected. */\n\tpublic setRangeText(replacement: string) {\n\t\tthis.textareaRef.value?.setRangeText(replacement)\n\t}\n\n\t/** Adjusts the height of the textarea based on its content. */\n\tpublic adjustHeight() {\n\t\tconst textarea = this.textareaRef.value\n\t\tif (textarea) {\n\t\t\t// Only grow, never shrink\n\t\t\tconst currentHeight = textarea.offsetHeight\n\t\t\tconst scrollHeight = textarea.scrollHeight\n\t\t\tif (scrollHeight > currentHeight) {\n\t\t\t\ttextarea.style.height = scrollHeight + 'px'\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic validity(): ValidityState | undefined {\n\t\treturn this.textareaRef.value?.validity\n\t}\n\n\tpublic override focus(\n\t\toptions: FocusOptions = {\n\t\t\tpreventScroll: true,\n\t\t},\n\t) {\n\t\tthis.textareaRef.value?.focus(options)\n\t\tthis.dispatchEvent(new Event('focus'))\n\t}\n\n\tpublic override click() {\n\t\tthis.textareaRef.value?.click()\n\t\tthis.dispatchEvent(new Event('click'))\n\t}\n\n\tpublic override blur() {\n\t\tthis.textareaRef.value?.blur()\n\t\tthis.dispatchEvent(new Event('blur'))\n\t}\n\n\tprotected render(): unknown {\n\t\tconst textareaClasses = {\n\t\t\t// Base styles - matching input component\n\t\t\t'block w-full min-w-0 rounded-2xl border bg-surface-containerLowest text-surface-on': true,\n\t\t\t// Border color\n\t\t\t'border-outline': !this.error,\n\t\t\t'border-error-default': this.error,\n\t\t\t// Focus styles\n\t\t\t'outline-secondary-default focus:outline-1 focus:border-secondary-default': true,\n\t\t\t// Disabled styles\n\t\t\t'disabled:opacity-40 disabled:cursor-not-allowed': true,\n\t\t\t// Placeholder\n\t\t\t'placeholder:text-muted': true,\n\t\t\t// Ring styles (subtle focus ring)\n\t\t\t'ring-0 focus:ring-1 focus:ring-inset': true,\n\t\t\t'focus:ring-secondary-default': !this.error,\n\t\t\t'focus:ring-error-default': this.error,\n\t\t\t// Readonly styles\n\t\t\t'caret-transparent focus:outline-hidden cursor-pointer select-none': this.readonly,\n\t\t\t// Text alignment\n\t\t\t'text-left': this.align === 'left',\n\t\t\t'text-center': this.align === 'center',\n\t\t\t'text-right': this.align === 'right',\n\t\t\t// Textarea specific\n\t\t\t'h-full': this.fillHeight,\n\t\t\t'resize-none': this.resize === 'none',\n\t\t\t'resize-y': this.resize === 'vertical',\n\t\t\t'resize-x': this.resize === 'horizontal',\n\t\t\t'resize': this.resize === 'both',\n\t\t\t// Padding matching input\n\t\t\t'px-4 py-3': true,\n\t\t}\n\t\tconst fieldSizing = this.rows == null ? 'field-sizing: content;' : ''\n\t\tconst labelClasses = {\n\t\t\t'block mb-1 font-medium text-sm': true,\n\t\t\t'opacity-40': this.disabled,\n\t\t\t'text-primary-default': !this.error,\n\t\t\t'text-error-default': this.error,\n\t\t}\n\t\tconst containerClasses = {\n\t\t\t'w-full min-w-0': true,\n\t\t\t'flex flex-col h-full': this.fillHeight,\n\t\t}\n\t\tconst hintId = `${this._a11yId}-hint`\n\t\treturn html`\n\t\t<div class=\"${this.classMap(containerClasses)}\">\n\t\t\t${when(\n\t\t\t\tthis.label,\n\t\t\t\t() => html`\n\t\t\t\t\t<label class=\"${this.classMap(labelClasses)}\" for=${this.id}>\n\t\t\t\t\t\t${this.label}\n\t\t\t\t\t</label>\n\t\t\t\t`,\n\t\t\t)}\n\n\t\t\t<textarea\n\t\t\t\t${ref(this.textareaRef)}\n\t\t\t\t.value=${this.value}\n\t\t\t\t.id=${this.id}\n\t\t\t\t.name=${this.name}\n\t\t\t\t.placeholder=${this.placeholder}\n\t\t\t\t.required=${this.required}\n\t\t\t\tclass=${this.classMap(textareaClasses)}\n\t\t\t\tstyle=${fieldSizing}\n\t\t\t\t.disabled=${this.disabled}\n\t\t\t\tminlength=${ifDefined(this.minlength)}\n\t\t\t\tmaxlength=${ifDefined(this.maxlength)}\n\t\t\t\t.readonly=${this.readonly}\n\t\t\t\t.spellcheck=${this.spellcheck}\n\t\t\t\tcols=${ifDefined(this.cols)}\n\t\t\t\trows=${ifDefined(this.rows)}\n\t\t\t\twrap=${ifDefined(this.wrap)}\n\t\t\t\tdirname=${ifDefined(this.dirname)}\n\t\t\t\taria-invalid=${this.error ? 'true' : 'false'}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\taria-describedby=${this.hint ? hintId : nothing}\n\t\t\t\taria-label=${!this.label && this.placeholder ? this.placeholder : nothing}\n\t\t\t></textarea>\n\n\t\t\t${when(\n\t\t\t\tthis.hint,\n\t\t\t\t() => html`\n\t\t\t\t\t<div id=${hintId} class=\"mt-1 text-sm ${this.error ? 'text-error-default' : 'text-surface-onVariant'}\">\n\t\t\t\t\t\t${this.hint}\n\t\t\t\t\t</div>\n\t\t\t\t`,\n\t\t\t)}\n\t\t</div>\n\t\t`\n\t}\n}\n\ntype EventDetails = {\n\tvalue: string\n}\n\nexport type SchmancyTextareaChangeEvent = CustomEvent<EventDetails>\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-textarea': SchmancyTextarea\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea-B2544vx9.cjs","names":[],"sources":["../src/textarea/textarea.scss?inline","../src/textarea/textarea.ts"],"sourcesContent":[":host {\n\tborder: unset !important;\n\tline-height: unset !important;\n\tbackground: unset !important;\n\tpadding: unset !important;\n\tfont-size: unset !important;\n\tbox-shadow: unset !important;\n\twidth: -webkit-fill-available;\n\tdisplay: block;\n}\n\n:host([fillHeight]) {\n\theight: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n:host:focus {\n\tbox-shadow: unset !important;\n}\n\ntextarea:focus-visible {\n\toutline: none !important;\n}\n\ntextarea {\n\t/* Inherit typographic styles */\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\tline-height: inherit;\n\tcolor: inherit;\n\tletter-spacing: inherit;\n\ttext-transform: inherit;\n\ttext-decoration: inherit;\n\ttext-indent: inherit;\n\ttext-shadow: inherit;\n\ttext-overflow: inherit;\n\ttext-rendering: inherit;\n\ttext-size-adjust: inherit;\n\ttext-align-last: inherit;\n\toverflow-y: auto; /* Ensure content is scrollable if it exceeds the visible area */\n}\n\n@keyframes onAutoFillStart {\n\tfrom {\n\t}\n\tto {\n\t}\n}\n\ntextarea:-webkit-autofill {\n\tanimation-name: onAutoFillStart;\n}\n","import { LitElement, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { when } from 'lit/directives/when.js'\nimport { distinctUntilChanged, filter, fromEvent, map } from 'rxjs'\nimport style from './textarea.scss?inline'\nimport { TailwindElement } from '@mixins/index'\n\n/**\n * Multi-line text input with auto-resize and form integration. Form-associated.\n *\n * @element schmancy-textarea\n * @summary Textarea for freeform text — notes, descriptions, messages. Auto-grows with content up to a maxlength.\n * @example\n * <schmancy-textarea name=\"description\" label=\"Description\" rows=\"4\" maxlength=\"500\"></schmancy-textarea>\n * @platform textarea change - Schmancy-skinned native `<textarea>`. Degrades to styled native `<textarea>` if the tag never registers.\n * @fires input - On every keystroke.\n * @fires change - On blur.\n *\n * @prop {string} name - Name attribute for form submission\n * @prop {string} value - Current value of the textarea\n * @prop {string} placeholder - Placeholder text\n * @prop {boolean} required - Whether the field is required\n * @prop {boolean} disabled - Whether the field is disabled\n * @prop {boolean} readonly - Whether the field is read-only\n * @prop {number} rows - Number of visible text rows\n * @prop {number} maxlength - Maximum character length\n */\n@customElement('schmancy-textarea')\nexport default class SchmancyTextarea extends TailwindElement(style) {\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\tstatic formAssociated = true\n\t// private internals\n\tinternals: ElementInternals | undefined\n\ttextareaRef = createRef<HTMLTextAreaElement>()\n\n\tprivate readonly _a11yId = `schmancy-textarea-${Math.random().toString(36).slice(2, 10)}`\n\n\t/**\n\t * The label of the control.\n\t * @attr\n\t * @type {string} label\n\t * @default ''\n\t * @public\n\t */\n\t@property() label = ''\n\n\t/**\n\t * The name of the control.\n\t * @attr name\n\t * @type {string} name\n\t * @default 'name_' + Date.now()\n\t * @public\n\t */\n\t@property() name = 'name_' + Date.now()\n\n\t/**\n\t * The placeholder of the control.\n\t * @attr placeholder\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property() placeholder = ''\n\n\t/**\n\t * The value of the control.\n\t * @attr {string} value - The value of the control.\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) public value = ''\n\n\t/**\n\t * The minlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic minlength: number | undefined\n\n\t/**\n\t * The maxlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic maxlength!: number\n\n\t/**\n\t * The number of columns (width) of the control.\n\t * @attr cols\n\t * @type {number}\n\t * @default 20\n\t * @public\n\t */\n\t@property({ type: Number }) cols = 20\n\n\t/**\n\t * The number of rows (height) of the control.\n\t * When not set, the textarea auto-sizes to fit its content via field-sizing: content.\n\t * @attr rows\n\t * @type {number}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: Number }) rows: number | undefined\n\n\t/**\n\t * Makes the textarea fill the height of its container.\n\t * @attr fillHeight\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean, reflect: true }) fillHeight = false\n\n\t/**\n\t * Automatically adjusts height based on content.\n\t * @attr autoHeight\n\t * @type {boolean}\n\t * @default true\n\t * @public\n\t */\n\t@property({ type: Boolean }) autoHeight = true\n\n\t/**\n\t * Controls whether the textarea can be resized by the user.\n\t * @attr resize\n\t * @type {'none' | 'vertical' | 'horizontal' | 'both'}\n\t * @default 'vertical'\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) resize: 'none' | 'vertical' | 'horizontal' | 'both' = 'vertical'\n\n\t/**\n\t * Specifies how the text in a text area is to be wrapped when submitted in a form.\n\t * @attr wrap\n\t * @type {'hard' | 'soft'}\n\t * @default 'soft'\n\t * @public\n\t */\n\t@property({ type: String }) wrap: 'hard' | 'soft' = 'soft'\n\n\t/**\n\t * The dirname attribute of the control.\n\t * @attr dirname\n\t * @type {string}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: String }) dirname: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) readonly = false\n\t@property({ type: Boolean, reflect: true }) spellcheck = false\n\n\t@property({ type: String, reflect: true }) align: 'left' | 'center' | 'right' = 'left'\n\n\t/**\n\t * The autofocus attribute of the control.\n\t * @attr\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean })\n\tpublic override autofocus!: boolean\n\n\t@property({ type: Number })\n\tpublic override tabIndex = 0\n\n\t@query('textarea') textareaElement!: HTMLTextAreaElement\n\n\t@property() hint: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) public error = false\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\tif (changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.value ?? '')\n\t\t}\n\t\tif (changed.has('required') || changed.has('value')) {\n\t\t\tif (this.required && !this.value) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'Please fill out this field.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.value = this.getAttribute('value') ?? ''\n\t\tthis.error = false\n\t}\n\n\tformDisabledCallback(disabled: boolean): void {\n\t\tthis.disabled = disabled\n\t}\n\n\tfirstUpdated() {\n\t\tif (this.autofocus) {\n\t\t\tthis.focus()\n\t\t}\n\t\tif (this.autoHeight) {\n\t\t\t// Initial adjustment for pre-filled content\n\t\t\tsetTimeout(() => this.adjustHeight(), 0)\n\t\t}\n\t\tfromEvent(this.textareaElement, 'input')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\tfromEvent(this.textareaElement, 'change')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t// emit on enter\n\t\tfromEvent<KeyboardEvent>(this.textareaElement, 'keyup')\n\t\t\t.pipe(\n\t\t\t\tfilter(event => event.key === 'Enter'),\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('enter', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t}\n\n\tget form() {\n\t\treturn this.internals?.form\n\t}\n\n\t/** Checks for validity of the control and shows the browser message if it's invalid. */\n\tpublic reportValidity() {\n\t\treturn this.textareaRef.value?.reportValidity()\n\t}\n\n\t/** Checks for validity of the control and emits the invalid event if it invalid. */\n\tpublic checkValidity() {\n\t\treturn this.textareaRef.value?.checkValidity()\n\t}\n\n\t/** Sets a custom validity message. */\n\tpublic setCustomValidity(message: string) {\n\t\treturn this.textareaRef.value?.setCustomValidity(message)\n\t}\n\n\t/** Selects all text within the textarea. */\n\tpublic select() {\n\t\treturn this.textareaRef.value?.select()\n\t}\n\n\t/** Sets the selection range. */\n\tpublic setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') {\n\t\tthis.textareaRef.value?.setSelectionRange(start, end, direction)\n\t}\n\n\t/** Returns the selected text within the textarea. */\n\tpublic get selectionStart(): number | null {\n\t\treturn this.textareaRef.value?.selectionStart ?? null\n\t}\n\n\tpublic get selectionEnd(): number | null {\n\t\treturn this.textareaRef.value?.selectionEnd ?? null\n\t}\n\n\tpublic get selectionDirection(): 'forward' | 'backward' | 'none' | null {\n\t\treturn this.textareaRef.value?.selectionDirection ?? null\n\t}\n\n\t/** Sets the range of text to be selected. */\n\tpublic setRangeText(replacement: string) {\n\t\tthis.textareaRef.value?.setRangeText(replacement)\n\t}\n\n\t/** Adjusts the height of the textarea based on its content. */\n\tpublic adjustHeight() {\n\t\tconst textarea = this.textareaRef.value\n\t\tif (textarea) {\n\t\t\t// Only grow, never shrink\n\t\t\tconst currentHeight = textarea.offsetHeight\n\t\t\tconst scrollHeight = textarea.scrollHeight\n\t\t\tif (scrollHeight > currentHeight) {\n\t\t\t\ttextarea.style.height = scrollHeight + 'px'\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic validity(): ValidityState | undefined {\n\t\treturn this.textareaRef.value?.validity\n\t}\n\n\tpublic override focus(\n\t\toptions: FocusOptions = {\n\t\t\tpreventScroll: true,\n\t\t},\n\t) {\n\t\tthis.textareaRef.value?.focus(options)\n\t\tthis.dispatchEvent(new Event('focus'))\n\t}\n\n\tpublic override click() {\n\t\tthis.textareaRef.value?.click()\n\t\tthis.dispatchEvent(new Event('click'))\n\t}\n\n\tpublic override blur() {\n\t\tthis.textareaRef.value?.blur()\n\t\tthis.dispatchEvent(new Event('blur'))\n\t}\n\n\tprotected render(): unknown {\n\t\tconst textareaClasses = {\n\t\t\t// Base styles - matching input component\n\t\t\t'block w-full min-w-0 rounded-2xl border bg-surface-containerLowest text-surface-on': true,\n\t\t\t// Border color\n\t\t\t'border-outline': !this.error,\n\t\t\t'border-error-default': this.error,\n\t\t\t// Focus styles\n\t\t\t'outline-secondary-default focus:outline-1 focus:border-secondary-default': true,\n\t\t\t// Disabled styles\n\t\t\t'disabled:opacity-40 disabled:cursor-not-allowed': true,\n\t\t\t// Placeholder\n\t\t\t'placeholder:text-muted': true,\n\t\t\t// Ring styles (subtle focus ring)\n\t\t\t'ring-0 focus:ring-1 focus:ring-inset': true,\n\t\t\t'focus:ring-secondary-default': !this.error,\n\t\t\t'focus:ring-error-default': this.error,\n\t\t\t// Readonly styles\n\t\t\t'caret-transparent focus:outline-hidden cursor-pointer select-none': this.readonly,\n\t\t\t// Text alignment\n\t\t\t'text-left': this.align === 'left',\n\t\t\t'text-center': this.align === 'center',\n\t\t\t'text-right': this.align === 'right',\n\t\t\t// Textarea specific\n\t\t\t'h-full': this.fillHeight,\n\t\t\t'resize-none': this.resize === 'none',\n\t\t\t'resize-y': this.resize === 'vertical',\n\t\t\t'resize-x': this.resize === 'horizontal',\n\t\t\t'resize': this.resize === 'both',\n\t\t\t// Padding matching input\n\t\t\t'px-4 py-3': true,\n\t\t}\n\t\tconst fieldSizing = this.rows == null ? 'field-sizing: content;' : ''\n\t\tconst labelClasses = {\n\t\t\t'block mb-1 font-medium text-sm': true,\n\t\t\t'opacity-40': this.disabled,\n\t\t\t'text-primary-default': !this.error,\n\t\t\t'text-error-default': this.error,\n\t\t}\n\t\tconst containerClasses = {\n\t\t\t'w-full min-w-0': true,\n\t\t\t'flex flex-col h-full': this.fillHeight,\n\t\t}\n\t\tconst hintId = `${this._a11yId}-hint`\n\t\treturn html`\n\t\t<div class=\"${this.classMap(containerClasses)}\">\n\t\t\t${when(\n\t\t\t\tthis.label,\n\t\t\t\t() => html`\n\t\t\t\t\t<label class=\"${this.classMap(labelClasses)}\" for=${this.id}>\n\t\t\t\t\t\t${this.label}\n\t\t\t\t\t</label>\n\t\t\t\t`,\n\t\t\t)}\n\n\t\t\t<textarea\n\t\t\t\t${ref(this.textareaRef)}\n\t\t\t\t.value=${this.value}\n\t\t\t\t.id=${this.id}\n\t\t\t\t.name=${this.name}\n\t\t\t\t.placeholder=${this.placeholder}\n\t\t\t\t.required=${this.required}\n\t\t\t\tclass=${this.classMap(textareaClasses)}\n\t\t\t\tstyle=${fieldSizing}\n\t\t\t\t.disabled=${this.disabled}\n\t\t\t\tminlength=${ifDefined(this.minlength)}\n\t\t\t\tmaxlength=${ifDefined(this.maxlength)}\n\t\t\t\t.readonly=${this.readonly}\n\t\t\t\t.spellcheck=${this.spellcheck}\n\t\t\t\tcols=${ifDefined(this.cols)}\n\t\t\t\trows=${ifDefined(this.rows)}\n\t\t\t\twrap=${ifDefined(this.wrap)}\n\t\t\t\tdirname=${ifDefined(this.dirname)}\n\t\t\t\taria-invalid=${this.error ? 'true' : 'false'}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\taria-describedby=${this.hint ? hintId : nothing}\n\t\t\t\taria-label=${!this.label && this.placeholder ? this.placeholder : nothing}\n\t\t\t></textarea>\n\n\t\t\t${when(\n\t\t\t\tthis.hint,\n\t\t\t\t() => html`\n\t\t\t\t\t<div id=${hintId} class=\"mt-1 text-sm ${this.error ? 'text-error-default' : 'text-surface-onVariant'}\">\n\t\t\t\t\t\t${this.hint}\n\t\t\t\t\t</div>\n\t\t\t\t`,\n\t\t\t)}\n\t\t</div>\n\t\t`\n\t}\n}\n\ntype EventDetails = {\n\tvalue: string\n}\n\nexport type SchmancyTextareaChangeEvent = CustomEvent<EventDetails>\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-textarea': SchmancyTextarea\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea-CS-KdSLz.js","names":[],"sources":["../src/textarea/textarea.scss?inline","../src/textarea/textarea.ts"],"sourcesContent":[":host {\n\tborder: unset !important;\n\tline-height: unset !important;\n\tbackground: unset !important;\n\tpadding: unset !important;\n\tfont-size: unset !important;\n\tbox-shadow: unset !important;\n\twidth: -webkit-fill-available;\n\tdisplay: block;\n}\n\n:host([fillHeight]) {\n\theight: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n:host:focus {\n\tbox-shadow: unset !important;\n}\n\ntextarea:focus-visible {\n\toutline: none !important;\n}\n\ntextarea {\n\t/* Inherit typographic styles */\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\tline-height: inherit;\n\tcolor: inherit;\n\tletter-spacing: inherit;\n\ttext-transform: inherit;\n\ttext-decoration: inherit;\n\ttext-indent: inherit;\n\ttext-shadow: inherit;\n\ttext-overflow: inherit;\n\ttext-rendering: inherit;\n\ttext-size-adjust: inherit;\n\ttext-align-last: inherit;\n\toverflow-y: auto; /* Ensure content is scrollable if it exceeds the visible area */\n}\n\n@keyframes onAutoFillStart {\n\tfrom {\n\t}\n\tto {\n\t}\n}\n\ntextarea:-webkit-autofill {\n\tanimation-name: onAutoFillStart;\n}\n","import { LitElement, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { when } from 'lit/directives/when.js'\nimport { distinctUntilChanged, filter, fromEvent, map } from 'rxjs'\nimport style from './textarea.scss?inline'\nimport { TailwindElement } from '@mixins/index'\n\n/**\n * Textarea component with auto-resize and form integration.\n *\n * @prop {string} name - Name attribute for form submission\n * @prop {string} value - Current value of the textarea\n * @prop {string} placeholder - Placeholder text\n * @prop {boolean} required - Whether the field is required\n * @prop {boolean} disabled - Whether the field is disabled\n * @prop {boolean} readonly - Whether the field is read-only\n * @prop {number} rows - Number of visible text rows\n * @prop {number} maxlength - Maximum character length\n */\n@customElement('schmancy-textarea')\nexport default class SchmancyTextarea extends TailwindElement(style) {\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\tstatic formAssociated = true\n\t// private internals\n\tinternals: ElementInternals | undefined\n\ttextareaRef = createRef<HTMLTextAreaElement>()\n\n\tprivate readonly _a11yId = `schmancy-textarea-${Math.random().toString(36).slice(2, 10)}`\n\n\t/**\n\t * The label of the control.\n\t * @attr\n\t * @type {string} label\n\t * @default ''\n\t * @public\n\t */\n\t@property() label = ''\n\n\t/**\n\t * The name of the control.\n\t * @attr name\n\t * @type {string} name\n\t * @default 'name_' + Date.now()\n\t * @public\n\t */\n\t@property() name = 'name_' + Date.now()\n\n\t/**\n\t * The placeholder of the control.\n\t * @attr placeholder\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property() placeholder = ''\n\n\t/**\n\t * The value of the control.\n\t * @attr {string} value - The value of the control.\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) public value = ''\n\n\t/**\n\t * The minlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic minlength: number | undefined\n\n\t/**\n\t * The maxlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic maxlength!: number\n\n\t/**\n\t * The number of columns (width) of the control.\n\t * @attr cols\n\t * @type {number}\n\t * @default 20\n\t * @public\n\t */\n\t@property({ type: Number }) cols = 20\n\n\t/**\n\t * The number of rows (height) of the control.\n\t * When not set, the textarea auto-sizes to fit its content via field-sizing: content.\n\t * @attr rows\n\t * @type {number}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: Number }) rows: number | undefined\n\n\t/**\n\t * Makes the textarea fill the height of its container.\n\t * @attr fillHeight\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean, reflect: true }) fillHeight = false\n\n\t/**\n\t * Automatically adjusts height based on content.\n\t * @attr autoHeight\n\t * @type {boolean}\n\t * @default true\n\t * @public\n\t */\n\t@property({ type: Boolean }) autoHeight = true\n\n\t/**\n\t * Controls whether the textarea can be resized by the user.\n\t * @attr resize\n\t * @type {'none' | 'vertical' | 'horizontal' | 'both'}\n\t * @default 'vertical'\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) resize: 'none' | 'vertical' | 'horizontal' | 'both' = 'vertical'\n\n\t/**\n\t * Specifies how the text in a text area is to be wrapped when submitted in a form.\n\t * @attr wrap\n\t * @type {'hard' | 'soft'}\n\t * @default 'soft'\n\t * @public\n\t */\n\t@property({ type: String }) wrap: 'hard' | 'soft' = 'soft'\n\n\t/**\n\t * The dirname attribute of the control.\n\t * @attr dirname\n\t * @type {string}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: String }) dirname: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) readonly = false\n\t@property({ type: Boolean, reflect: true }) spellcheck = false\n\n\t@property({ type: String, reflect: true }) align: 'left' | 'center' | 'right' = 'left'\n\n\t/**\n\t * The autofocus attribute of the control.\n\t * @attr\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean })\n\tpublic override autofocus!: boolean\n\n\t@property({ type: Number })\n\tpublic override tabIndex = 0\n\n\t@query('textarea') textareaElement!: HTMLTextAreaElement\n\n\t@property() hint: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) public error = false\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\tif (changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.value ?? '')\n\t\t}\n\t\tif (changed.has('required') || changed.has('value')) {\n\t\t\tif (this.required && !this.value) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'Please fill out this field.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.value = this.getAttribute('value') ?? ''\n\t\tthis.error = false\n\t}\n\n\tformDisabledCallback(disabled: boolean): void {\n\t\tthis.disabled = disabled\n\t}\n\n\tfirstUpdated() {\n\t\tif (this.autofocus) {\n\t\t\tthis.focus()\n\t\t}\n\t\tif (this.autoHeight) {\n\t\t\t// Initial adjustment for pre-filled content\n\t\t\tsetTimeout(() => this.adjustHeight(), 0)\n\t\t}\n\t\tfromEvent(this.textareaElement, 'input')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\tfromEvent(this.textareaElement, 'change')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t// emit on enter\n\t\tfromEvent<KeyboardEvent>(this.textareaElement, 'keyup')\n\t\t\t.pipe(\n\t\t\t\tfilter(event => event.key === 'Enter'),\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('enter', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t}\n\n\tget form() {\n\t\treturn this.internals?.form\n\t}\n\n\t/** Checks for validity of the control and shows the browser message if it's invalid. */\n\tpublic reportValidity() {\n\t\treturn this.textareaRef.value?.reportValidity()\n\t}\n\n\t/** Checks for validity of the control and emits the invalid event if it invalid. */\n\tpublic checkValidity() {\n\t\treturn this.textareaRef.value?.checkValidity()\n\t}\n\n\t/** Sets a custom validity message. */\n\tpublic setCustomValidity(message: string) {\n\t\treturn this.textareaRef.value?.setCustomValidity(message)\n\t}\n\n\t/** Selects all text within the textarea. */\n\tpublic select() {\n\t\treturn this.textareaRef.value?.select()\n\t}\n\n\t/** Sets the selection range. */\n\tpublic setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') {\n\t\tthis.textareaRef.value?.setSelectionRange(start, end, direction)\n\t}\n\n\t/** Returns the selected text within the textarea. */\n\tpublic get selectionStart(): number | null {\n\t\treturn this.textareaRef.value?.selectionStart ?? null\n\t}\n\n\tpublic get selectionEnd(): number | null {\n\t\treturn this.textareaRef.value?.selectionEnd ?? null\n\t}\n\n\tpublic get selectionDirection(): 'forward' | 'backward' | 'none' | null {\n\t\treturn this.textareaRef.value?.selectionDirection ?? null\n\t}\n\n\t/** Sets the range of text to be selected. */\n\tpublic setRangeText(replacement: string) {\n\t\tthis.textareaRef.value?.setRangeText(replacement)\n\t}\n\n\t/** Adjusts the height of the textarea based on its content. */\n\tpublic adjustHeight() {\n\t\tconst textarea = this.textareaRef.value\n\t\tif (textarea) {\n\t\t\t// Only grow, never shrink\n\t\t\tconst currentHeight = textarea.offsetHeight\n\t\t\tconst scrollHeight = textarea.scrollHeight\n\t\t\tif (scrollHeight > currentHeight) {\n\t\t\t\ttextarea.style.height = scrollHeight + 'px'\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic validity(): ValidityState | undefined {\n\t\treturn this.textareaRef.value?.validity\n\t}\n\n\tpublic override focus(\n\t\toptions: FocusOptions = {\n\t\t\tpreventScroll: true,\n\t\t},\n\t) {\n\t\tthis.textareaRef.value?.focus(options)\n\t\tthis.dispatchEvent(new Event('focus'))\n\t}\n\n\tpublic override click() {\n\t\tthis.textareaRef.value?.click()\n\t\tthis.dispatchEvent(new Event('click'))\n\t}\n\n\tpublic override blur() {\n\t\tthis.textareaRef.value?.blur()\n\t\tthis.dispatchEvent(new Event('blur'))\n\t}\n\n\tprotected render(): unknown {\n\t\tconst textareaClasses = {\n\t\t\t// Base styles - matching input component\n\t\t\t'block w-full min-w-0 rounded-2xl border bg-surface-containerLowest text-surface-on': true,\n\t\t\t// Border color\n\t\t\t'border-outline': !this.error,\n\t\t\t'border-error-default': this.error,\n\t\t\t// Focus styles\n\t\t\t'outline-secondary-default focus:outline-1 focus:border-secondary-default': true,\n\t\t\t// Disabled styles\n\t\t\t'disabled:opacity-40 disabled:cursor-not-allowed': true,\n\t\t\t// Placeholder\n\t\t\t'placeholder:text-muted': true,\n\t\t\t// Ring styles (subtle focus ring)\n\t\t\t'ring-0 focus:ring-1 focus:ring-inset': true,\n\t\t\t'focus:ring-secondary-default': !this.error,\n\t\t\t'focus:ring-error-default': this.error,\n\t\t\t// Readonly styles\n\t\t\t'caret-transparent focus:outline-hidden cursor-pointer select-none': this.readonly,\n\t\t\t// Text alignment\n\t\t\t'text-left': this.align === 'left',\n\t\t\t'text-center': this.align === 'center',\n\t\t\t'text-right': this.align === 'right',\n\t\t\t// Textarea specific\n\t\t\t'h-full': this.fillHeight,\n\t\t\t'resize-none': this.resize === 'none',\n\t\t\t'resize-y': this.resize === 'vertical',\n\t\t\t'resize-x': this.resize === 'horizontal',\n\t\t\t'resize': this.resize === 'both',\n\t\t\t// Padding matching input\n\t\t\t'px-4 py-3': true,\n\t\t}\n\t\tconst fieldSizing = this.rows == null ? 'field-sizing: content;' : ''\n\t\tconst labelClasses = {\n\t\t\t'block mb-1 font-medium text-sm': true,\n\t\t\t'opacity-40': this.disabled,\n\t\t\t'text-primary-default': !this.error,\n\t\t\t'text-error-default': this.error,\n\t\t}\n\t\tconst containerClasses = {\n\t\t\t'w-full min-w-0': true,\n\t\t\t'flex flex-col h-full': this.fillHeight,\n\t\t}\n\t\tconst hintId = `${this._a11yId}-hint`\n\t\treturn html`\n\t\t<div class=\"${this.classMap(containerClasses)}\">\n\t\t\t${when(\n\t\t\t\tthis.label,\n\t\t\t\t() => html`\n\t\t\t\t\t<label class=\"${this.classMap(labelClasses)}\" for=${this.id}>\n\t\t\t\t\t\t${this.label}\n\t\t\t\t\t</label>\n\t\t\t\t`,\n\t\t\t)}\n\n\t\t\t<textarea\n\t\t\t\t${ref(this.textareaRef)}\n\t\t\t\t.value=${this.value}\n\t\t\t\t.id=${this.id}\n\t\t\t\t.name=${this.name}\n\t\t\t\t.placeholder=${this.placeholder}\n\t\t\t\t.required=${this.required}\n\t\t\t\tclass=${this.classMap(textareaClasses)}\n\t\t\t\tstyle=${fieldSizing}\n\t\t\t\t.disabled=${this.disabled}\n\t\t\t\tminlength=${ifDefined(this.minlength)}\n\t\t\t\tmaxlength=${ifDefined(this.maxlength)}\n\t\t\t\t.readonly=${this.readonly}\n\t\t\t\t.spellcheck=${this.spellcheck}\n\t\t\t\tcols=${ifDefined(this.cols)}\n\t\t\t\trows=${ifDefined(this.rows)}\n\t\t\t\twrap=${ifDefined(this.wrap)}\n\t\t\t\tdirname=${ifDefined(this.dirname)}\n\t\t\t\taria-invalid=${this.error ? 'true' : 'false'}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\taria-describedby=${this.hint ? hintId : nothing}\n\t\t\t\taria-label=${!this.label && this.placeholder ? this.placeholder : nothing}\n\t\t\t></textarea>\n\n\t\t\t${when(\n\t\t\t\tthis.hint,\n\t\t\t\t() => html`\n\t\t\t\t\t<div id=${hintId} class=\"mt-1 text-sm ${this.error ? 'text-error-default' : 'text-surface-onVariant'}\">\n\t\t\t\t\t\t${this.hint}\n\t\t\t\t\t</div>\n\t\t\t\t`,\n\t\t\t)}\n\t\t</div>\n\t\t`\n\t}\n}\n\ntype EventDetails = {\n\tvalue: string\n}\n\nexport type SchmancyTextareaChangeEvent = CustomEvent<EventDetails>\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-textarea': SchmancyTextarea\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea-CS-KdSLz.js","names":[],"sources":["../src/textarea/textarea.scss?inline","../src/textarea/textarea.ts"],"sourcesContent":[":host {\n\tborder: unset !important;\n\tline-height: unset !important;\n\tbackground: unset !important;\n\tpadding: unset !important;\n\tfont-size: unset !important;\n\tbox-shadow: unset !important;\n\twidth: -webkit-fill-available;\n\tdisplay: block;\n}\n\n:host([fillHeight]) {\n\theight: 100%;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n:host:focus {\n\tbox-shadow: unset !important;\n}\n\ntextarea:focus-visible {\n\toutline: none !important;\n}\n\ntextarea {\n\t/* Inherit typographic styles */\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\tline-height: inherit;\n\tcolor: inherit;\n\tletter-spacing: inherit;\n\ttext-transform: inherit;\n\ttext-decoration: inherit;\n\ttext-indent: inherit;\n\ttext-shadow: inherit;\n\ttext-overflow: inherit;\n\ttext-rendering: inherit;\n\ttext-size-adjust: inherit;\n\ttext-align-last: inherit;\n\toverflow-y: auto; /* Ensure content is scrollable if it exceeds the visible area */\n}\n\n@keyframes onAutoFillStart {\n\tfrom {\n\t}\n\tto {\n\t}\n}\n\ntextarea:-webkit-autofill {\n\tanimation-name: onAutoFillStart;\n}\n","import { LitElement, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { when } from 'lit/directives/when.js'\nimport { distinctUntilChanged, filter, fromEvent, map } from 'rxjs'\nimport style from './textarea.scss?inline'\nimport { TailwindElement } from '@mixins/index'\n\n/**\n * Multi-line text input with auto-resize and form integration. Form-associated.\n *\n * @element schmancy-textarea\n * @summary Textarea for freeform text — notes, descriptions, messages. Auto-grows with content up to a maxlength.\n * @example\n * <schmancy-textarea name=\"description\" label=\"Description\" rows=\"4\" maxlength=\"500\"></schmancy-textarea>\n * @platform textarea change - Schmancy-skinned native `<textarea>`. Degrades to styled native `<textarea>` if the tag never registers.\n * @fires input - On every keystroke.\n * @fires change - On blur.\n *\n * @prop {string} name - Name attribute for form submission\n * @prop {string} value - Current value of the textarea\n * @prop {string} placeholder - Placeholder text\n * @prop {boolean} required - Whether the field is required\n * @prop {boolean} disabled - Whether the field is disabled\n * @prop {boolean} readonly - Whether the field is read-only\n * @prop {number} rows - Number of visible text rows\n * @prop {number} maxlength - Maximum character length\n */\n@customElement('schmancy-textarea')\nexport default class SchmancyTextarea extends TailwindElement(style) {\n\tprotected static shadowRootOptions = {\n\t\t...LitElement.shadowRootOptions,\n\t\tdelegatesFocus: true,\n\t}\n\tstatic formAssociated = true\n\t// private internals\n\tinternals: ElementInternals | undefined\n\ttextareaRef = createRef<HTMLTextAreaElement>()\n\n\tprivate readonly _a11yId = `schmancy-textarea-${Math.random().toString(36).slice(2, 10)}`\n\n\t/**\n\t * The label of the control.\n\t * @attr\n\t * @type {string} label\n\t * @default ''\n\t * @public\n\t */\n\t@property() label = ''\n\n\t/**\n\t * The name of the control.\n\t * @attr name\n\t * @type {string} name\n\t * @default 'name_' + Date.now()\n\t * @public\n\t */\n\t@property() name = 'name_' + Date.now()\n\n\t/**\n\t * The placeholder of the control.\n\t * @attr placeholder\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property() placeholder = ''\n\n\t/**\n\t * The value of the control.\n\t * @attr {string} value - The value of the control.\n\t * @type {string}\n\t * @default ''\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) public value = ''\n\n\t/**\n\t * The minlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic minlength: number | undefined\n\n\t/**\n\t * The maxlength attribute of the control.\n\t * @attr\n\t */\n\t@property({ type: Number })\n\tpublic maxlength!: number\n\n\t/**\n\t * The number of columns (width) of the control.\n\t * @attr cols\n\t * @type {number}\n\t * @default 20\n\t * @public\n\t */\n\t@property({ type: Number }) cols = 20\n\n\t/**\n\t * The number of rows (height) of the control.\n\t * When not set, the textarea auto-sizes to fit its content via field-sizing: content.\n\t * @attr rows\n\t * @type {number}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: Number }) rows: number | undefined\n\n\t/**\n\t * Makes the textarea fill the height of its container.\n\t * @attr fillHeight\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean, reflect: true }) fillHeight = false\n\n\t/**\n\t * Automatically adjusts height based on content.\n\t * @attr autoHeight\n\t * @type {boolean}\n\t * @default true\n\t * @public\n\t */\n\t@property({ type: Boolean }) autoHeight = true\n\n\t/**\n\t * Controls whether the textarea can be resized by the user.\n\t * @attr resize\n\t * @type {'none' | 'vertical' | 'horizontal' | 'both'}\n\t * @default 'vertical'\n\t * @public\n\t */\n\t@property({ type: String, reflect: true }) resize: 'none' | 'vertical' | 'horizontal' | 'both' = 'vertical'\n\n\t/**\n\t * Specifies how the text in a text area is to be wrapped when submitted in a form.\n\t * @attr wrap\n\t * @type {'hard' | 'soft'}\n\t * @default 'soft'\n\t * @public\n\t */\n\t@property({ type: String }) wrap: 'hard' | 'soft' = 'soft'\n\n\t/**\n\t * The dirname attribute of the control.\n\t * @attr dirname\n\t * @type {string}\n\t * @default undefined\n\t * @public\n\t */\n\t@property({ type: String }) dirname: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) required = false\n\t@property({ type: Boolean, reflect: true }) disabled = false\n\t@property({ type: Boolean, reflect: true }) readonly = false\n\t@property({ type: Boolean, reflect: true }) spellcheck = false\n\n\t@property({ type: String, reflect: true }) align: 'left' | 'center' | 'right' = 'left'\n\n\t/**\n\t * The autofocus attribute of the control.\n\t * @attr\n\t * @type {boolean}\n\t * @default false\n\t * @public\n\t */\n\t@property({ type: Boolean })\n\tpublic override autofocus!: boolean\n\n\t@property({ type: Number })\n\tpublic override tabIndex = 0\n\n\t@query('textarea') textareaElement!: HTMLTextAreaElement\n\n\t@property() hint: string | undefined\n\n\t@property({ type: Boolean, reflect: true }) public error = false\n\n\tconstructor() {\n\t\tsuper()\n\t\ttry {\n\t\t\tthis.internals = this.attachInternals()\n\t\t} catch {\n\t\t\tthis.internals = undefined\n\t\t}\n\t}\n\n\tprotected willUpdate(changed: PropertyValues): void {\n\t\tsuper.willUpdate?.(changed)\n\t\tif (changed.has('value') || changed.has('name')) {\n\t\t\tthis.internals?.setFormValue(this.value ?? '')\n\t\t}\n\t\tif (changed.has('required') || changed.has('value')) {\n\t\t\tif (this.required && !this.value) {\n\t\t\t\tthis.internals?.setValidity({ valueMissing: true }, 'Please fill out this field.')\n\t\t\t} else {\n\t\t\t\tthis.internals?.setValidity({})\n\t\t\t}\n\t\t}\n\t}\n\n\tformResetCallback(): void {\n\t\tthis.value = this.getAttribute('value') ?? ''\n\t\tthis.error = false\n\t}\n\n\tformDisabledCallback(disabled: boolean): void {\n\t\tthis.disabled = disabled\n\t}\n\n\tfirstUpdated() {\n\t\tif (this.autofocus) {\n\t\t\tthis.focus()\n\t\t}\n\t\tif (this.autoHeight) {\n\t\t\t// Initial adjustment for pre-filled content\n\t\t\tsetTimeout(() => this.adjustHeight(), 0)\n\t\t}\n\t\tfromEvent(this.textareaElement, 'input')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\tfromEvent(this.textareaElement, 'change')\n\t\t\t.pipe(\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tif (this.autoHeight) {\n\t\t\t\t\tthis.adjustHeight()\n\t\t\t\t}\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t\t// emit on enter\n\t\tfromEvent<KeyboardEvent>(this.textareaElement, 'keyup')\n\t\t\t.pipe(\n\t\t\t\tfilter(event => event.key === 'Enter'),\n\t\t\t\tmap(event => (event.target as HTMLTextAreaElement).value),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t)\n\t\t\t.subscribe(value => {\n\t\t\t\tthis.value = value\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('change', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\tthis.dispatchEvent(\n\t\t\t\t\tnew CustomEvent<EventDetails>('enter', {\n\t\t\t\t\t\tdetail: { value },\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t})\n\t}\n\n\tget form() {\n\t\treturn this.internals?.form\n\t}\n\n\t/** Checks for validity of the control and shows the browser message if it's invalid. */\n\tpublic reportValidity() {\n\t\treturn this.textareaRef.value?.reportValidity()\n\t}\n\n\t/** Checks for validity of the control and emits the invalid event if it invalid. */\n\tpublic checkValidity() {\n\t\treturn this.textareaRef.value?.checkValidity()\n\t}\n\n\t/** Sets a custom validity message. */\n\tpublic setCustomValidity(message: string) {\n\t\treturn this.textareaRef.value?.setCustomValidity(message)\n\t}\n\n\t/** Selects all text within the textarea. */\n\tpublic select() {\n\t\treturn this.textareaRef.value?.select()\n\t}\n\n\t/** Sets the selection range. */\n\tpublic setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') {\n\t\tthis.textareaRef.value?.setSelectionRange(start, end, direction)\n\t}\n\n\t/** Returns the selected text within the textarea. */\n\tpublic get selectionStart(): number | null {\n\t\treturn this.textareaRef.value?.selectionStart ?? null\n\t}\n\n\tpublic get selectionEnd(): number | null {\n\t\treturn this.textareaRef.value?.selectionEnd ?? null\n\t}\n\n\tpublic get selectionDirection(): 'forward' | 'backward' | 'none' | null {\n\t\treturn this.textareaRef.value?.selectionDirection ?? null\n\t}\n\n\t/** Sets the range of text to be selected. */\n\tpublic setRangeText(replacement: string) {\n\t\tthis.textareaRef.value?.setRangeText(replacement)\n\t}\n\n\t/** Adjusts the height of the textarea based on its content. */\n\tpublic adjustHeight() {\n\t\tconst textarea = this.textareaRef.value\n\t\tif (textarea) {\n\t\t\t// Only grow, never shrink\n\t\t\tconst currentHeight = textarea.offsetHeight\n\t\t\tconst scrollHeight = textarea.scrollHeight\n\t\t\tif (scrollHeight > currentHeight) {\n\t\t\t\ttextarea.style.height = scrollHeight + 'px'\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic validity(): ValidityState | undefined {\n\t\treturn this.textareaRef.value?.validity\n\t}\n\n\tpublic override focus(\n\t\toptions: FocusOptions = {\n\t\t\tpreventScroll: true,\n\t\t},\n\t) {\n\t\tthis.textareaRef.value?.focus(options)\n\t\tthis.dispatchEvent(new Event('focus'))\n\t}\n\n\tpublic override click() {\n\t\tthis.textareaRef.value?.click()\n\t\tthis.dispatchEvent(new Event('click'))\n\t}\n\n\tpublic override blur() {\n\t\tthis.textareaRef.value?.blur()\n\t\tthis.dispatchEvent(new Event('blur'))\n\t}\n\n\tprotected render(): unknown {\n\t\tconst textareaClasses = {\n\t\t\t// Base styles - matching input component\n\t\t\t'block w-full min-w-0 rounded-2xl border bg-surface-containerLowest text-surface-on': true,\n\t\t\t// Border color\n\t\t\t'border-outline': !this.error,\n\t\t\t'border-error-default': this.error,\n\t\t\t// Focus styles\n\t\t\t'outline-secondary-default focus:outline-1 focus:border-secondary-default': true,\n\t\t\t// Disabled styles\n\t\t\t'disabled:opacity-40 disabled:cursor-not-allowed': true,\n\t\t\t// Placeholder\n\t\t\t'placeholder:text-muted': true,\n\t\t\t// Ring styles (subtle focus ring)\n\t\t\t'ring-0 focus:ring-1 focus:ring-inset': true,\n\t\t\t'focus:ring-secondary-default': !this.error,\n\t\t\t'focus:ring-error-default': this.error,\n\t\t\t// Readonly styles\n\t\t\t'caret-transparent focus:outline-hidden cursor-pointer select-none': this.readonly,\n\t\t\t// Text alignment\n\t\t\t'text-left': this.align === 'left',\n\t\t\t'text-center': this.align === 'center',\n\t\t\t'text-right': this.align === 'right',\n\t\t\t// Textarea specific\n\t\t\t'h-full': this.fillHeight,\n\t\t\t'resize-none': this.resize === 'none',\n\t\t\t'resize-y': this.resize === 'vertical',\n\t\t\t'resize-x': this.resize === 'horizontal',\n\t\t\t'resize': this.resize === 'both',\n\t\t\t// Padding matching input\n\t\t\t'px-4 py-3': true,\n\t\t}\n\t\tconst fieldSizing = this.rows == null ? 'field-sizing: content;' : ''\n\t\tconst labelClasses = {\n\t\t\t'block mb-1 font-medium text-sm': true,\n\t\t\t'opacity-40': this.disabled,\n\t\t\t'text-primary-default': !this.error,\n\t\t\t'text-error-default': this.error,\n\t\t}\n\t\tconst containerClasses = {\n\t\t\t'w-full min-w-0': true,\n\t\t\t'flex flex-col h-full': this.fillHeight,\n\t\t}\n\t\tconst hintId = `${this._a11yId}-hint`\n\t\treturn html`\n\t\t<div class=\"${this.classMap(containerClasses)}\">\n\t\t\t${when(\n\t\t\t\tthis.label,\n\t\t\t\t() => html`\n\t\t\t\t\t<label class=\"${this.classMap(labelClasses)}\" for=${this.id}>\n\t\t\t\t\t\t${this.label}\n\t\t\t\t\t</label>\n\t\t\t\t`,\n\t\t\t)}\n\n\t\t\t<textarea\n\t\t\t\t${ref(this.textareaRef)}\n\t\t\t\t.value=${this.value}\n\t\t\t\t.id=${this.id}\n\t\t\t\t.name=${this.name}\n\t\t\t\t.placeholder=${this.placeholder}\n\t\t\t\t.required=${this.required}\n\t\t\t\tclass=${this.classMap(textareaClasses)}\n\t\t\t\tstyle=${fieldSizing}\n\t\t\t\t.disabled=${this.disabled}\n\t\t\t\tminlength=${ifDefined(this.minlength)}\n\t\t\t\tmaxlength=${ifDefined(this.maxlength)}\n\t\t\t\t.readonly=${this.readonly}\n\t\t\t\t.spellcheck=${this.spellcheck}\n\t\t\t\tcols=${ifDefined(this.cols)}\n\t\t\t\trows=${ifDefined(this.rows)}\n\t\t\t\twrap=${ifDefined(this.wrap)}\n\t\t\t\tdirname=${ifDefined(this.dirname)}\n\t\t\t\taria-invalid=${this.error ? 'true' : 'false'}\n\t\t\t\taria-required=${this.required ? 'true' : 'false'}\n\t\t\t\taria-describedby=${this.hint ? hintId : nothing}\n\t\t\t\taria-label=${!this.label && this.placeholder ? this.placeholder : nothing}\n\t\t\t></textarea>\n\n\t\t\t${when(\n\t\t\t\tthis.hint,\n\t\t\t\t() => html`\n\t\t\t\t\t<div id=${hintId} class=\"mt-1 text-sm ${this.error ? 'text-error-default' : 'text-surface-onVariant'}\">\n\t\t\t\t\t\t${this.hint}\n\t\t\t\t\t</div>\n\t\t\t\t`,\n\t\t\t)}\n\t\t</div>\n\t\t`\n\t}\n}\n\ntype EventDetails = {\n\tvalue: string\n}\n\nexport type SchmancyTextareaChangeEvent = CustomEvent<EventDetails>\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-textarea': SchmancyTextarea\n\t}\n}\n"],"mappings":";;;;;;;;;IC8Be,IAAA,cAA+B,EAAA,6xBAAA,CAAA;CAAA;AAAA,OAAA,oBACR;GAAA,GACjC,EAAW;GACd,gBAAA,CAAgB;GAAA;;CAAA;AAAA,OAAA,iBAAA,CAEO;;CAmJxB,cAAA;AACC,SAAA,EAAA,KAAA,cAjJa,GAAA,EAAA,KAAA,UAEa,qBAAqB,KAAK,QAAA,CAAS,SAAS,GAAA,CAAI,MAAM,GAAG,GAAA,IAAA,KAAA,QAShE,IAAA,KAAA,OASD,UAAU,KAAK,KAAA,EAAA,KAAA,cASR,IAAA,KAAA,QASgC,IAAA,KAAA,OAuBvB,IAAA,KAAA,aAAA,CAmBsB,GAAA,KAAA,aAAA,CASf,GAAA,KAAA,SASuD,YAAA,KAAA,OAS7C,QAAA,KAAA,WAAA,CAWG,GAAA,KAAA,WAAA,CACA,GAAA,KAAA,WAAA,CACA,GAAA,KAAA,aAAA,CACE,GAAA,KAAA,QAEuB,QAAA,KAAA,WAarD,GAAA,KAAA,QAAA,CAMgC;AAI1D,MAAA;AACC,QAAK,YAAY,KAAK,iBAAA;UAAA;AAEtB,QAAK,YAAA,KAAY;;;CAInB,WAAqB,GAAA;AACpB,QAAM,aAAa,EAAA,GACf,EAAQ,IAAI,QAAA,IAAY,EAAQ,IAAI,OAAA,KACvC,KAAK,WAAW,aAAa,KAAK,SAAS,GAAA,GAExC,EAAQ,IAAI,WAAA,IAAe,EAAQ,IAAI,QAAA,MACtC,KAAK,YAAA,CAAa,KAAK,QAC1B,KAAK,WAAW,YAAY,EAAE,cAAA,CAAc,GAAA,EAAQ,8BAAA,GAEpD,KAAK,WAAW,YAAY,EAAA,CAAA;;CAK/B,oBAAA;AACC,OAAK,QAAQ,KAAK,aAAa,QAAA,IAAY,IAC3C,KAAK,QAAA,CAAQ;;CAGd,qBAAqB,GAAA;AACpB,OAAK,WAAW;;CAGjB,eAAA;AACK,OAAK,aACR,KAAK,OAAA,EAEF,KAAK,cAER,iBAAiB,KAAK,cAAA,EAAgB,EAAA,EAEvC,EAAU,KAAK,iBAAiB,QAAA,CAC9B,KACA,GAAI,MAAU,EAAM,OAA+B,MAAA,EACnD,GAAA,CAAA,CAEA,WAAU,MAAA;AACV,QAAK,QAAQ,GACT,KAAK,cACR,KAAK,cAAA,EAEN,KAAK,cACJ,IAAI,YAA0B,UAAU;IACvC,QAAQ,EAAE,OAAA,GAAA;IACV,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA;IAAA,EAId,EAAU,KAAK,iBAAiB,SAAA,CAC9B,KACA,GAAI,MAAU,EAAM,OAA+B,MAAA,EACnD,GAAA,CAAA,CAEA,WAAU,MAAA;AACV,QAAK,QAAQ,GACT,KAAK,cACR,KAAK,cAAA,EAEN,KAAK,cACJ,IAAI,YAA0B,UAAU;IACvC,QAAQ,EAAE,OAAA,GAAA;IACV,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA;IAAA,EAKd,EAAyB,KAAK,iBAAiB,QAAA,CAC7C,KACA,GAAO,MAAS,EAAM,QAAQ,QAAR,EACtB,GAAI,MAAU,EAAM,OAA+B,MAAA,EACnD,GAAA,CAAA,CAEA,WAAU,MAAA;AACV,QAAK,QAAQ,GACb,KAAK,cACJ,IAAI,YAA0B,UAAU;IACvC,QAAQ,EAAE,OAAA,GAAA;IACV,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA,EAGZ,KAAK,cACJ,IAAI,YAA0B,SAAS;IACtC,QAAQ,EAAE,OAAA,GAAA;IACV,SAAA,CAAS;IACT,UAAA,CAAU;IAAA,CAAA,CAAA;IAAA;;CAMf,IAAA,OAAI;AACH,SAAO,KAAK,WAAW;;CAIxB,iBAAA;AACC,SAAO,KAAK,YAAY,OAAO,gBAAA;;CAIhC,gBAAA;AACC,SAAO,KAAK,YAAY,OAAO,eAAA;;CAIhC,kBAAyB,GAAA;AACxB,SAAO,KAAK,YAAY,OAAO,kBAAkB,EAAA;;CAIlD,SAAA;AACC,SAAO,KAAK,YAAY,OAAO,QAAA;;CAIhC,kBAAyB,GAAe,GAAa,GAAA;AACpD,OAAK,YAAY,OAAO,kBAAkB,GAAO,GAAK,EAAA;;CAIvD,IAAA,iBAAW;AACV,SAAO,KAAK,YAAY,OAAO,kBAAkB;;CAGlD,IAAA,eAAW;AACV,SAAO,KAAK,YAAY,OAAO,gBAAgB;;CAGhD,IAAA,qBAAW;AACV,SAAO,KAAK,YAAY,OAAO,sBAAsB;;CAItD,aAAoB,GAAA;AACnB,OAAK,YAAY,OAAO,aAAa,EAAA;;CAItC,eAAA;EACC,IAAM,IAAW,KAAK,YAAY;AAClC,MAAI,GAAU;GAEb,IAAM,IAAgB,EAAS,cACzB,IAAe,EAAS;AAC1B,OAAe,MAClB,EAAS,MAAM,SAAS,IAAe;;;CAK1C,WAAA;AACC,SAAO,KAAK,YAAY,OAAO;;CAGhC,MACC,IAAwB,EACvB,eAAA,CAAe,GAAA,EAAA;AAGhB,OAAK,YAAY,OAAO,MAAM,EAAA,EAC9B,KAAK,cAAc,IAAI,MAAM,QAAA,CAAA;;CAG9B,QAAA;AACC,OAAK,YAAY,OAAO,OAAA,EACxB,KAAK,cAAc,IAAI,MAAM,QAAA,CAAA;;CAG9B,OAAA;AACC,OAAK,YAAY,OAAO,MAAA,EACxB,KAAK,cAAc,IAAI,MAAM,OAAA,CAAA;;CAG9B,SAAA;EACC,IAAM,IAAkB;GAEvB,sFAAA,CAAsF;GAEtF,kBAAA,CAAmB,KAAK;GACxB,wBAAwB,KAAK;GAE7B,4EAAA,CAA4E;GAE5E,mDAAA,CAAmD;GAEnD,0BAAA,CAA0B;GAE1B,wCAAA,CAAwC;GACxC,gCAAA,CAAiC,KAAK;GACtC,4BAA4B,KAAK;GAEjC,qEAAqE,KAAK;GAE1E,aAAa,KAAK,UAAU;GAC5B,eAAe,KAAK,UAAU;GAC9B,cAAc,KAAK,UAAU;GAE7B,UAAU,KAAK;GACf,eAAe,KAAK,WAAW;GAC/B,YAAY,KAAK,WAAW;GAC5B,YAAY,KAAK,WAAW;GAC5B,QAAU,KAAK,WAAW;GAE1B,aAAA,CAAa;GAAA,EAER,IAAc,KAAK,QAAQ,OAAO,2BAA2B,IAC7D,IAAe;GACpB,kCAAA,CAAkC;GAClC,cAAc,KAAK;GACnB,wBAAA,CAAyB,KAAK;GAC9B,sBAAsB,KAAK;GAAA,EAEtB,IAAmB;GACxB,kBAAA,CAAkB;GAClB,wBAAwB,KAAK;GAAA,EAExB,IAAS,GAAG,KAAK,QAAA;AACvB,SAAO,CAAI;gBACG,KAAK,SAAS,EAAA,CAAA;KACzB,EACD,KAAK,aACC,CAAI;qBACO,KAAK,SAAS,EAAA,CAAA,QAAsB,KAAK,GAAA;QACtD,KAAK,MAAA;;;;;MAMP,EAAI,KAAK,YAAA,CAAA;aACF,KAAK,MAAA;UACR,KAAK,GAAA;YACH,KAAK,KAAA;mBACE,KAAK,YAAA;gBACR,KAAK,SAAA;YACT,KAAK,SAAS,EAAA,CAAA;YACd,EAAA;gBACI,KAAK,SAAA;gBACL,EAAU,KAAK,UAAA,CAAA;gBACf,EAAU,KAAK,UAAA,CAAA;gBACf,KAAK,SAAA;kBACH,KAAK,WAAA;WACZ,EAAU,KAAK,KAAA,CAAA;WACf,EAAU,KAAK,KAAA,CAAA;WACf,EAAU,KAAK,KAAA,CAAA;cACZ,EAAU,KAAK,QAAA,CAAA;mBACV,KAAK,QAAQ,SAAS,QAAA;oBACrB,KAAK,WAAW,SAAS,QAAA;uBACtB,KAAK,OAAO,IAAS,EAAA;kBAC1B,KAAK,SAAS,KAAK,cAAc,KAAK,cAAc,EAAA;;;KAGjE,EACD,KAAK,YACC,CAAI;eACC,EAAA,uBAA8B,KAAK,QAAQ,uBAAuB,yBAAA;QACzE,KAAK,KAAA;;;;;;;GAjZX,GAAA,CAAA,EAAU,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CASV,GAAA,CAAA,EAAU,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CASV,GAAA,CAAA,EAAU,EAAA,WAAA,eAAA,KAAA,EAAA,EAAA,EAAA,CASV,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CAMzC,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CAO1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CAU1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAU1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAS1B,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,cAAA,KAAA,EAAA,EAAA,EAAA,CAS1C,EAAS,EAAE,MAAM,SAAA,CAAA,CAAA,EAAU,EAAA,WAAA,cAAA,KAAA,EAAA,EAAA,EAAA,CAS3B,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,UAAA,KAAA,EAAA,EAAA,EAAA,CASzC,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAS1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,WAAA,KAAA,EAAA,EAAA,EAAA,CAE1B,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1C,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,cAAA,KAAA,EAAA,EAAA,EAAA,CAE1C,EAAS;CAAE,MAAM;CAAQ,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CASzC,EAAS,EAAE,MAAM,SAAA,CAAA,CAAA,EAAU,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CAG3B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAG1B,EAAM,WAAA,CAAA,EAAW,EAAA,WAAA,mBAAA,KAAA,EAAA,EAAA,EAAA,CAEjB,GAAA,CAAA,EAAU,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAEV,EAAS;CAAE,MAAM;CAAS,SAAA,CAAS;CAAA,CAAA,CAAA,EAAO,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,IAAA,EAAA,CAvJ3C,EAAc,oBAAA,CAAA,EAAoB,EAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mhmo91/schmancy",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.16",
|
|
4
4
|
"description": "UI library build with web components",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"customElements": "custom-elements.json",
|
|
@@ -58,8 +58,9 @@
|
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"dev": "vite build --config vite.config.ts --watch",
|
|
61
|
-
"build": "tsc && vite build --config vite.config.ts && yarn manifest && yarn build:agent",
|
|
61
|
+
"build": "tsc && vite build --config vite.config.ts && yarn manifest && yarn build:agent && yarn build:handover",
|
|
62
62
|
"build:agent": "vite build --config vite.config.agent.ts",
|
|
63
|
+
"build:handover": "node scripts/render-handover.mjs",
|
|
63
64
|
"manifest": "wca 'src/**/*.ts' --outFile custom-elements.json --format json",
|
|
64
65
|
"ncu": "ncu -u && npm i",
|
|
65
66
|
"test": "vitest run",
|
|
@@ -36,7 +36,18 @@ interface FilteredOption {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Combobox with type-ahead filtering over a list of `<schmancy-option>` children. Single or multi-select. Form-associated.
|
|
40
|
+
*
|
|
41
|
+
* @element schmancy-autocomplete
|
|
42
|
+
* @summary Use when users need to pick from a known list of options but the list is too long for a plain select dropdown. Prefer schmancy-select for short static lists.
|
|
43
|
+
* @example
|
|
44
|
+
* <schmancy-autocomplete name="country" label="Country" placeholder="Start typing…">
|
|
45
|
+
* <schmancy-option value="US">United States</schmancy-option>
|
|
46
|
+
* <schmancy-option value="CA">Canada</schmancy-option>
|
|
47
|
+
* <schmancy-option value="GB">United Kingdom</schmancy-option>
|
|
48
|
+
* </schmancy-autocomplete>
|
|
49
|
+
* @platform combobox change - Composed of a schmancy-input + a floating listbox populated from `<schmancy-option>` children. Multi-select renders selections as schmancy-input-chip chips. Degrades to a datalist-backed native input if the tag never registers.
|
|
50
|
+
* @fires change - `SchmancyAutocompleteChangeEvent` with `{ value }` (single) or `{ value, values }` (multi).
|
|
40
51
|
*
|
|
41
52
|
* @prop {string} name - Name attribute for form submission
|
|
42
53
|
* @prop {string} label - Label text displayed above the input
|
package/src/button/button.ts
CHANGED
|
@@ -16,8 +16,13 @@ export type ButtonVariant = 'elevated' | 'filled' | 'filled tonal' | 'tonal' | '
|
|
|
16
16
|
export type ButtonColor = 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info' | 'neutral'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Material Design button — primary interactive surface for triggering actions or navigation.
|
|
20
20
|
* @element schmancy-button
|
|
21
|
+
* @summary Trigger actions or navigate. Form-associated; participates in native form submission.
|
|
22
|
+
* @example
|
|
23
|
+
* <schmancy-button variant="filled" @click=${() => save()}>Save</schmancy-button>
|
|
24
|
+
* <schmancy-button variant="outlined" href="/next">Continue</schmancy-button>
|
|
25
|
+
* @platform button click - Schmancy-skinned native `<button type="submit">`. When `href` is set, degrades to `<a href="…">`. Falls back to plain `<button>` styled with Tailwind if the tag never registers.
|
|
21
26
|
* @slot - The default slot.
|
|
22
27
|
* @slot prefix - The prefix slot.
|
|
23
28
|
* @slot suffix - The suffix slot.
|
|
@@ -7,8 +7,14 @@ import { magnetic } from '../directives/magnetic'
|
|
|
7
7
|
import { ButtonVariant } from './button'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Icon-only button for toolbar actions, close affordances, or overflow menus.
|
|
11
11
|
* @element schmancy-icon-button
|
|
12
|
+
* @summary Compact round/square button wrapping a single icon glyph. Form-associated like schmancy-button.
|
|
13
|
+
* @example
|
|
14
|
+
* <schmancy-icon-button aria-label="Close" @click=${() => close()}>
|
|
15
|
+
* <schmancy-icon>close</schmancy-icon>
|
|
16
|
+
* </schmancy-icon-button>
|
|
17
|
+
* @platform button click - Schmancy-skinned native `<button>` (or `<a>` when `href` is set). aria-label is required for a11y because there's no text content.
|
|
12
18
|
* @slot - The default slot (usually an icon or glyph).
|
|
13
19
|
* @csspart base - The underlying native `<button>` (or `<a>` when `href` is set).
|
|
14
20
|
*/
|
package/src/checkbox/checkbox.ts
CHANGED
|
@@ -9,9 +9,15 @@ export type schmancyCheckBoxChangeEvent = CustomEvent<{
|
|
|
9
9
|
}>
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
+
* Binary checkbox for multi-select or boolean form fields. Wraps Material Web's `<md-checkbox>`; form-associated.
|
|
13
|
+
*
|
|
12
14
|
* @element schmancy-checkbox
|
|
15
|
+
* @summary Use for "select many from a list" or any boolean that's part of a form submission. Prefer schmancy-switch for immediate-effect toggles.
|
|
16
|
+
* @example
|
|
17
|
+
* <schmancy-checkbox name="tos" required>I accept the terms</schmancy-checkbox>
|
|
18
|
+
* @platform checkbox change - Wraps `<md-checkbox>` from `@material/web`. Degrades to styled native `<input type="checkbox">` if the tag never registers.
|
|
13
19
|
* @slot - The label for the checkbox.
|
|
14
|
-
* @fires valueChange -
|
|
20
|
+
* @fires valueChange - `CustomEvent<{ value: boolean }>` when the checkbox is toggled.
|
|
15
21
|
**/
|
|
16
22
|
|
|
17
23
|
@customElement('schmancy-checkbox')
|
package/src/chips/chips.ts
CHANGED
|
@@ -7,6 +7,20 @@ import { fullWidth } from '../directives/layout'
|
|
|
7
7
|
import type { FilterChipChangeEvent as SchmancyChipChangeEvent } from './filter-chip'
|
|
8
8
|
import { SchmancyFilterChip as SchmancyChip } from './filter-chip'
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Filter-chip group — container for selectable `<schmancy-chip>` children. Single or multi-select.
|
|
12
|
+
*
|
|
13
|
+
* @element schmancy-chips
|
|
14
|
+
* @summary Use for filtering or choosing from 2–8 mutually-visible options ("Status: active / paused / archived"). Prefer schmancy-select when the list gets long or vertical.
|
|
15
|
+
* @example
|
|
16
|
+
* <schmancy-chips multi @change=${(e) => this.filters = e.detail.values}>
|
|
17
|
+
* <schmancy-chip value="active">Active</schmancy-chip>
|
|
18
|
+
* <schmancy-chip value="paused">Paused</schmancy-chip>
|
|
19
|
+
* <schmancy-chip value="archived">Archived</schmancy-chip>
|
|
20
|
+
* </schmancy-chips>
|
|
21
|
+
* @platform chip-group change - No direct native equivalent. Degrades to a styled schmancy-select with similar semantics if the tag never registers.
|
|
22
|
+
* @fires change - `CustomEvent<{ value: string }>` (single) or `{ values: string[] }` (multi).
|
|
23
|
+
*/
|
|
10
24
|
@customElement('schmancy-chips')
|
|
11
25
|
export default class SchmancyChips extends $LitElement(
|
|
12
26
|
|
package/src/chips/input-chip.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { BehaviorSubject, combineLatest } from 'rxjs'
|
|
|
6
6
|
import { map, takeUntil, tap } from 'rxjs/operators'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Input chip
|
|
9
|
+
* Input chip — displays user-provided information (tags, recipients, filters) that can be removed but not toggled.
|
|
10
10
|
*
|
|
11
11
|
* IMPORTANT: Per Material Design 3 specification, input chips do NOT have selected state.
|
|
12
12
|
* They represent discrete pieces of user input (like entered tags, selections from lists, etc.)
|
|
@@ -18,15 +18,15 @@ import { map, takeUntil, tap } from 'rxjs/operators'
|
|
|
18
18
|
* - Tags or keywords entered by the user
|
|
19
19
|
* - Selected items from a multi-select dropdown
|
|
20
20
|
*
|
|
21
|
-
* @
|
|
22
|
-
* @
|
|
23
|
-
*
|
|
21
|
+
* @element schmancy-input-chip
|
|
22
|
+
* @summary Removable pill that represents a single user input value. No selected state — use schmancy-chip (filter chip) for toggleable options.
|
|
24
23
|
* @example
|
|
25
|
-
* ```html
|
|
26
24
|
* <schmancy-input-chip value="john@example.com" avatar="/avatars/john.jpg">
|
|
27
25
|
* John Doe
|
|
28
26
|
* </schmancy-input-chip>
|
|
29
|
-
*
|
|
27
|
+
* @platform chip remove - No native equivalent. Composed of a labeled pill + close button. Degrades to a styled `<span>` with a trailing close `<button>` if the tag never registers.
|
|
28
|
+
* @fires click - Optional click event on chip body (value)
|
|
29
|
+
* @fires remove - Dispatched when remove button is clicked (value)
|
|
30
30
|
*/
|
|
31
31
|
@customElement('schmancy-input-chip')
|
|
32
32
|
export class SchmancyInputChip extends TailwindElement(css`
|
|
@@ -6,6 +6,16 @@ import { repeat } from 'lit/directives/repeat.js'
|
|
|
6
6
|
import countriesData from './countries.data'
|
|
7
7
|
import SchmancyAutocomplete from '@schmancy/autocomplete/autocomplete'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Country picker — type-ahead autocomplete over the ISO 3166-1 country list. Form-associated.
|
|
11
|
+
*
|
|
12
|
+
* @element schmancy-select-countries
|
|
13
|
+
* @summary Drop-in replacement for schmancy-autocomplete when the options are specifically "every country". Pre-seeds the list from countries.data.
|
|
14
|
+
* @example
|
|
15
|
+
* <schmancy-select-countries name="country" label="Shipping country" required></schmancy-select-countries>
|
|
16
|
+
* @platform combobox change - Composes schmancy-autocomplete with a static options list. Value is the 2-letter ISO code.
|
|
17
|
+
* @fires change - `SchmancyAutocompleteChangeEvent` with `{ value: string }` (the ISO code).
|
|
18
|
+
*/
|
|
9
19
|
@customElement('schmancy-select-countries')
|
|
10
20
|
export class SchmancyCountriesSelect extends $LitElement(css`
|
|
11
21
|
:host {
|
|
@@ -6,7 +6,14 @@ import timezonesData from './timezones.data'
|
|
|
6
6
|
import SchmancyAutocomplete from '@schmancy/autocomplete/autocomplete'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Timezone
|
|
9
|
+
* Timezone picker — type-ahead autocomplete over the IANA tz database. Form-associated.
|
|
10
|
+
*
|
|
11
|
+
* @element schmancy-select-timezones
|
|
12
|
+
* @summary Drop-in replacement for schmancy-autocomplete when the options are IANA timezone names. Value is the IANA identifier ("America/Los_Angeles").
|
|
13
|
+
* @example
|
|
14
|
+
* <schmancy-select-timezones name="tz" label="Timezone" value="America/New_York"></schmancy-select-timezones>
|
|
15
|
+
* @platform combobox change - Composes schmancy-autocomplete with a static IANA timezones list.
|
|
16
|
+
* @fires change - `SchmancyAutocompleteChangeEvent` with `{ value: string }` (the IANA tz name).
|
|
10
17
|
*
|
|
11
18
|
* @prop {string} name - Name attribute for form submission
|
|
12
19
|
* @prop {string} value - Selected timezone value
|
package/src/form/form.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { customElement } from 'lit/decorators.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* reparented into a `<form>` element in light DOM on connection, so:
|
|
4
|
+
* Ergonomic wrapper around a native `<form>`. Children are reparented into a light-DOM `<form>` on connection so form-associated custom elements resolve `internals.form` via native DOM ancestry.
|
|
6
5
|
*
|
|
7
6
|
* - Form-associated custom elements (FACE) resolve their `internals.form`
|
|
8
7
|
* correctly via native DOM ancestry.
|
|
@@ -18,6 +17,14 @@ import { customElement } from 'lit/decorators.js'
|
|
|
18
17
|
* lifting is the platform's.
|
|
19
18
|
*
|
|
20
19
|
* @element schmancy-form
|
|
20
|
+
* @summary Always wrap form-associated schmancy components in schmancy-form (or a native `<form>`) so `new FormData(form)` just works.
|
|
21
|
+
* @example
|
|
22
|
+
* <schmancy-form @submit=${(e) => console.log(Object.fromEntries(e.detail))}>
|
|
23
|
+
* <schmancy-input name="email" type="email" required></schmancy-input>
|
|
24
|
+
* <schmancy-input name="password" type="password" required></schmancy-input>
|
|
25
|
+
* <schmancy-button type="submit" variant="filled">Sign in</schmancy-button>
|
|
26
|
+
* </schmancy-form>
|
|
27
|
+
* @platform form submit - Light-DOM native `<form>` element. Degrades to a `<form>` if the tag never registers — same semantics, just no CustomEvent translation.
|
|
21
28
|
* @fires submit - `CustomEvent<FormData>` emitted when the form is submitted.
|
|
22
29
|
* @fires reset - Emitted after the underlying form resets.
|
|
23
30
|
*/
|
package/src/input/input.ts
CHANGED
|
@@ -43,11 +43,18 @@ export type SchmancyInputEnterEvent = CustomEvent<EventDetails>
|
|
|
43
43
|
export type InputSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg'
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
* and compatibility with legacy API.
|
|
46
|
+
* Single-line text input — the primary form-text primitive. Form-associated via ElementInternals, so it participates in native `<form>` submission, validation, and reset without additional wiring.
|
|
48
47
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* @element schmancy-input
|
|
49
|
+
* @summary Text input with Material Design styling, native form integration, and RxJS-debounced input/change/enter events.
|
|
50
|
+
* @example
|
|
51
|
+
* <schmancy-form @submit=${onSubmit}>
|
|
52
|
+
* <schmancy-input name="email" type="email" label="Email" required></schmancy-input>
|
|
53
|
+
* </schmancy-form>
|
|
54
|
+
* @platform input change - Schmancy-skinned native `<input>`. Degrades to `<input class="…">` styled via Tailwind if the tag never registers.
|
|
55
|
+
* @fires input - `CustomEvent<{value: string}>` on every keystroke.
|
|
56
|
+
* @fires change - `CustomEvent<{value: string}>` on blur/change.
|
|
57
|
+
* @fires enter - `CustomEvent<{value: string}>` when user presses Enter.
|
|
51
58
|
*
|
|
52
59
|
* @prop {string} name - Name attribute for form submission (inherited from FormFieldMixin)
|
|
53
60
|
* @prop {string} label - Label text for the form field (inherited from FormFieldMixin)
|
|
@@ -5,7 +5,16 @@ import { FormFieldMixin } from '../../mixins/formField.mixin'
|
|
|
5
5
|
import { fromEvent, takeUntil } from 'rxjs'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Single radio button — always rendered as a child of `<schmancy-radio-group>`, never standalone.
|
|
9
|
+
*
|
|
10
|
+
* @element schmancy-radio-button
|
|
11
|
+
* @summary Low-level primitive. Use schmancy-radio-group and pass `.options` for the common path; only instantiate schmancy-radio-button directly when you need per-button custom rendering.
|
|
12
|
+
* @example
|
|
13
|
+
* <schmancy-radio-group name="plan">
|
|
14
|
+
* <schmancy-radio-button value="free">Free</schmancy-radio-button>
|
|
15
|
+
* <schmancy-radio-button value="pro" checked>Pro</schmancy-radio-button>
|
|
16
|
+
* </schmancy-radio-group>
|
|
17
|
+
* @platform radio change - Schmancy-skinned `<input type="radio">` semantics. Degrades to native radio if the tag never registers.
|
|
9
18
|
*
|
|
10
19
|
* @prop {string} name - Name attribute for grouping radio buttons
|
|
11
20
|
* @prop {string} value - Value of this radio button
|
|
@@ -13,6 +13,24 @@ export type SchmancyRadioGroupOption = {
|
|
|
13
13
|
export type SchmancyRadioGroupChangeEvent = CustomEvent<{
|
|
14
14
|
value: string
|
|
15
15
|
}>
|
|
16
|
+
/**
|
|
17
|
+
* Radio-button group — single-select from a static list of mutually-exclusive options. Form-associated.
|
|
18
|
+
*
|
|
19
|
+
* @element schmancy-radio-group
|
|
20
|
+
* @summary Use for 2–5 mutually-exclusive options where all should stay visible ("Shipping: standard / express / overnight"). Prefer schmancy-select when the list grows.
|
|
21
|
+
* @example
|
|
22
|
+
* <schmancy-radio-group
|
|
23
|
+
* name="shipping"
|
|
24
|
+
* label="Shipping"
|
|
25
|
+
* .options=${[
|
|
26
|
+
* { label: 'Standard (5 days)', value: 'standard' },
|
|
27
|
+
* { label: 'Express (2 days)', value: 'express' },
|
|
28
|
+
* { label: 'Overnight', value: 'overnight' },
|
|
29
|
+
* ]}
|
|
30
|
+
* ></schmancy-radio-group>
|
|
31
|
+
* @platform radiogroup change - Renders schmancy-radio-button children. Degrades to a fieldset with native `<input type="radio" name="…">` siblings if the tag never registers.
|
|
32
|
+
* @fires change - `SchmancyRadioGroupChangeEvent` with the selected `value`.
|
|
33
|
+
*/
|
|
16
34
|
@customElement('schmancy-radio-group')
|
|
17
35
|
export class RadioGroup extends FormFieldMixin(TailwindElement(style)) {
|
|
18
36
|
@property({ type: String }) override label = ''
|
package/src/select/select.ts
CHANGED
|
@@ -15,7 +15,18 @@ export type SchmancySelectChangeEvent = CustomEvent<{
|
|
|
15
15
|
}>
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Dropdown selector — single or multi-select from a list of `<schmancy-option>` children. Form-associated.
|
|
19
|
+
*
|
|
20
|
+
* @element schmancy-select
|
|
21
|
+
* @summary Material Design dropdown with type-to-filter, keyboard nav, single or multi-select. Options are declared as `<schmancy-option>` children; value / values props sync with selection.
|
|
22
|
+
* @example
|
|
23
|
+
* <schmancy-select name="priority" label="Priority" value="medium">
|
|
24
|
+
* <schmancy-option value="low">Low</schmancy-option>
|
|
25
|
+
* <schmancy-option value="medium">Medium</schmancy-option>
|
|
26
|
+
* <schmancy-option value="high">High</schmancy-option>
|
|
27
|
+
* </schmancy-select>
|
|
28
|
+
* @platform select change - Floating-UI-positioned listbox. Degrades to native `<select>` styled via Tailwind if the tag never registers, though multi-select UX is lost.
|
|
29
|
+
* @fires change - `SchmancySelectChangeEvent` with `{ value }` (single) or `{ value: string[] }` (multi).
|
|
19
30
|
*
|
|
20
31
|
* @prop {string} name - Name attribute for form submission
|
|
21
32
|
* @prop {string} label - Label text displayed above the select
|