@sky.ui/core 0.0.35 → 0.0.36

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.
@@ -1 +1 @@
1
- {"version":3,"file":"sky-input.js","sources":["../../src/sky-input/sky-input.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\r\nimport { ifDefined } from \"lit/directives/if-defined.js\";\r\nimport { styleMap } from \"lit/directives/style-map.js\";\r\nimport { customElement, property, query, state } from \"lit/decorators.js\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { live } from \"lit/directives/live.js\";\r\nimport { FormControlBase } from \"../helper/internals/form-control-base\";\r\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\r\n\r\nexport type SkyInputValue = string | number | File[] | null;\r\nexport type SkyInputType = string;\r\nexport type SkyInputErrorDisplayMode = \"none\" | \"single\" | \"all\";\r\nexport type SkyInputIconPosition = \"left\" | \"right\";\r\nexport type SkyInputValidation = (value: string | File[]) => true | string;\r\nexport type SkyInputValueChangedDetail = { value: string | number };\r\nexport type SkyInputValueClearedDetail = { value: string | number };\r\nexport type SkyInputFileSelectedDetail = {\r\n files: File[];\r\n fileName: string;\r\n totalSize: number;\r\n fileCount: number;\r\n};\r\nexport type SkyInputValidationErrorDetail = { errors: string[] };\r\nexport type SkyInputIconClickDetail = {\r\n position: SkyInputIconPosition;\r\n eventType: string | null;\r\n eventData: Event | null;\r\n};\r\n\r\n/**\r\n * @element sky-input\r\n *\r\n * @summary Versatile form input supporting text, password, number, textarea, and file workflows.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://library.sky-ui.com/components/input\r\n * @dependency sky-icon\r\n *\r\n * @uiVModel value value-changed\r\n *\r\n * @slot icon-left - Optional icon/content placed in the left slot.\r\n * @slot icon-right - Optional icon/content placed in the right slot.\r\n * @property {SkyInputValue} value - Current input value.\r\n * @property {string} placeholder - Placeholder text.\r\n * @property {string} label - Label text shown above the input.\r\n * @property {SkyInputType} type - Input type (`text`, `password`, `number`, `textarea`, `file`, etc.).\r\n * @property {string} suffix - Optional suffix label fragment.\r\n * @property {string} prefix - Optional prefix label fragment.\r\n * @property {string} prefixColor - Prefix color override.\r\n * @property {string} suffixColor - Suffix color override.\r\n * @property {string} color - Accent color token/value.\r\n * @property {SkyInputValidation[]} validations - Validation functions.\r\n * @property {boolean} compact - Compact display mode.\r\n * @property {boolean} loading - Loading state.\r\n * @property {boolean} showErrors - Enables error rendering.\r\n * @property {boolean} clearable - Enables clear button.\r\n * @property {SkyInputErrorDisplayMode} errorDisplayMode - Error rendering mode.\r\n * @property {boolean} showNumberButtons - Enables number increment/decrement controls.\r\n * @property {boolean} showPasswordToggle - Enables password visibility toggle.\r\n * @property {string} passwordVisibleIcon - Icon used when password is visible.\r\n * @property {string} passwordHiddenIcon - Icon used when password is hidden.\r\n *\r\n * @fires {CustomEvent<SkyInputValueChangedDetail>} value-changed - Fired when value changes.\r\n * @fires {CustomEvent<SkyInputValueClearedDetail>} value-cleared - Fired after clear action.\r\n * @fires {CustomEvent<SkyInputFileSelectedDetail>} file-selected - Fired after file selection changes.\r\n * @fires {CustomEvent<SkyInputValidationErrorDetail>} validation-error - Fired after validations run.\r\n * @fires {CustomEvent<SkyInputIconClickDetail>} left-icon-click - Fired when left icon slot is clicked.\r\n * @fires {CustomEvent<SkyInputIconClickDetail>} right-icon-click - Fired when right icon slot is clicked.\r\n *\r\n * @method validateInput Runs configured validations and updates invalid state.\r\n * @method handleClear Clears value and emits corresponding events.\r\n * @method formatFileSize Formats byte size for UI display.\r\n * @method focusInput Focuses the underlying native input or textarea.\r\n *\r\n * @csspart input-container - The outer container wrapping label and input wrapper.\r\n * @csspart label - The label element above the input.\r\n * @csspart input-wrapper - The wrapper around input/textarea and icons.\r\n * @csspart icon-slot - Base class for left/right icon slots.\r\n * @csspart icon-slot-left - Left icon slot.\r\n * @csspart icon-slot-right - Right icon slot.\r\n * @csspart clear-button - The clear/reset button.\r\n * @csspart toggle-password - The toggle icon for password visibility.\r\n * @csspart loading-indicator - The spinner shown when loading.\r\n * @csspart error-list - UL element containing validation errors.\r\n * @csspart error - Individual error message.\r\n * @csspart file-info - File count and size info below the file input.\r\n * @csspart input-prefix - Inline prefix fragment inside the field.\r\n * @csspart input-suffix - Inline suffix fragment inside the field.\r\n *\r\n * @Behavior\r\n * - Extends `FormControlBase` for automatic form association and validation integration\r\n * - Supports all standard HTML input types with enhanced styling and functionality\r\n * - File inputs with multi-file support, preview, and size tracking\r\n * - Automatic validation integration with parent forms via `sky-form`\r\n *\r\n * - **none**: No error messages displayed\r\n * - **single**: Show only the first error message\r\n * - **all**: Show all validation error messages\r\n *\r\n * @example\r\n * ```html\r\n * <sky-input\r\n * label=\"Password\"\r\n * type=\"password\"\r\n * placeholder=\"Enter your password\"\r\n * clearable\r\n * show-password-toggle\r\n * required\r\n * >\r\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\r\n * </sky-input>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-input label=\"Password\" type=\"password\" clearable show-password-toggle required>\r\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\r\n * </sky-input>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-input label=\"Password\" type=\"password\" clearable show-password-toggle required>\r\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\r\n * </sky-input>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-input\")\r\nexport class SkyInput extends FormControlBase {\r\n\r\n static dependencies: Record<string, CustomElementConstructor> = {\r\n \"sky-icon\": SkyIcon,\r\n };\r\n\r\n // ============================================================\r\n // ✅ PUBLIC PROPERTIES (user-configurable)\r\n // ============================================================\r\n\r\n @property({ type: String }) value: SkyInputValue = \"\";\r\n @property({ type: String }) placeholder = \"\";\r\n @property({ type: String }) label = \"\";\r\n @property({ type: String }) type: SkyInputType = \"text\";\r\n @property({ type: String }) suffix = \"\";\r\n @property({ type: String }) prefix = \"\";\r\n @property({ type: String }) prefixColor = \"\";\r\n @property({ type: String }) suffixColor = \"\";\r\n @property({ type: String }) color = \"primary\";\r\n private _validations: SkyInputValidation[] = [];\r\n @property({ type: Array })\r\n get validations(): SkyInputValidation[] {\r\n return this._validations;\r\n }\r\n set validations(value: SkyInputValidation[] | null | undefined) {\r\n const old = this._validations;\r\n this._validations = Array.isArray(value) ? value : [];\r\n this.requestUpdate(\"validations\", old);\r\n }\r\n @property({ type: Boolean, reflect: true }) compact = false;\r\n @property({ type: Boolean, reflect: true }) loading = false;\r\n @property({ type: Boolean }) showErrors = false;\r\n @property({ type: Boolean, reflect: true }) clearable = false;\r\n @property({ type: String }) errorDisplayMode: SkyInputErrorDisplayMode = \"single\";\r\n @property({ type: Boolean, reflect: true }) override required = false;\r\n @property({ type: String }) step: string | null = null;\r\n @property({ type: String }) min: string | null = null;\r\n @property({ type: String }) max: string | null = null;\r\n @property({ type: String }) override autocapitalize = \"off\";\r\n @property({ type: String }) autocomplete = \"off\";\r\n @property({ type: Boolean }) override spellcheck = false;\r\n @property({ type: String }) override dir = \"ltr\";\r\n @property({ type: Number }) rows = 6;\r\n @property({ type: String }) resizable = \"none\";\r\n @property({ type: String }) accept = \"\";\r\n @property({ type: Boolean }) multiple = false;\r\n @property({ type: String }) inputmode: string | null = null;\r\n @property({ type: String }) enterkeyhint: string | null = null;\r\n @property({ type: String }) pattern: string | null = null;\r\n @property({ type: Number }) minlength: number | null = null;\r\n @property({ type: Number }) maxlength: number | null = null;\r\n @property({ type: String }) list: string | null = null;\r\n @property({ type: Number }) size: number | null = null;\r\n @property({ type: Number }) cols: number | null = null;\r\n @property({ type: Boolean }) autofocus = false;\r\n @property({ type: Boolean }) capture = false;\r\n @property({ type: String }) inputRole: string | null = null;\r\n @property({ type: String }) ariaLabel: string | null = null;\r\n @property({ type: String }) ariaLabelledby: string | null = null;\r\n @property({ type: String }) ariaDescribedby: string | null = null;\r\n @property({ type: Boolean }) showNumberButtons = false;\r\n @property({ type: Boolean }) showPasswordToggle = true;\r\n @property({ type: String }) passwordVisibleIcon = \"material-symbols:visibility-off\";\r\n @property({ type: String }) passwordHiddenIcon = \"material-symbols:visibility\";\r\n @property({ type: Boolean, reflect: true }) validationActive = false;\r\n @property({ type: Boolean, reflect: true }) invalid = false;\r\n @property({ type: String, reflect: true }) variant = 'default';\r\n\r\n // ============================================================\r\n // ✅ INTERNAL STATE (read-only, managed by component)\r\n // ============================================================\r\n\r\n @state() private selectedFileName = \"\";\r\n @state() private selectedFiles: File[] = [];\r\n @state() private focused = false;\r\n @state() private validationStatus: boolean[] = [];\r\n @state() private validationErrors: string[] = [];\r\n @state() private typingStarted = false;\r\n @state() private autofillIconSlot = \"left\";\r\n @state() private autofillGuardActive = false;\r\n @state() private showPassword = false;\r\n @state() private totalFileSize = 0;\r\n @state() private selectedFileCount = 0;\r\n @state() private filePreview: string | ArrayBuffer | null = null;\r\n\r\n // ============================================================\r\n // ✅ PRIVATE FIELDS (internal, not reactive)\r\n // ============================================================\r\n\r\n @query(\".input-wrapper\") private inputWrapperEl!: HTMLElement;\r\n @query(\"input, textarea\") private nativeInputEl!:\r\n | HTMLInputElement\r\n | HTMLTextAreaElement;\r\n\r\n private _leftIconSlot: HTMLSlotElement | null = null;\r\n private _rightIconSlot: HTMLSlotElement | null = null;\r\n private _iconClickWired = new WeakSet<HTMLElement>();\r\n private _onLeftIconSlotChange = () =>\r\n this._wireIconSlot(\"left\", this._leftIconSlot);\r\n private _onRightIconSlotChange = () =>\r\n this._wireIconSlot(\"right\", this._rightIconSlot);\r\n\r\n static override styles = css`\r\n :host {\r\n display: block;\r\n font-family: var(--sky-font);\r\n width: 100%;\r\n }\r\n\r\n :host([disabled]) .input-container {\r\n opacity: var(--sky-opacity-disabled, 0.6);\r\n }\r\n :host([disabled]) * {\r\n pointer-events: none;\r\n }\r\n\r\n :host([variant=\"highlight\"]){\r\n .label{\r\n color: var(--sky-input-color);\r\n }\r\n }\r\n\r\n .input-container {\r\n position: relative;\r\n display: flex;\r\n flex-direction: column;\r\n width: inherit;\r\n cursor: text;\r\n }\r\n\r\n sky-icon {\r\n display: inline-block;\r\n width: 1em;\r\n height: 1em;\r\n }\r\n\r\n .input-container:focus-within .label {\r\n color: var(--sky-input-color);\r\n font-size: var(--sky-font-size-sm);\r\n transition: all 0.3s ease;\r\n }\r\n .label {\r\n font-size: var(--sky-font-size-sm);\r\n margin-bottom: var(--sky-space-1, 4px);\r\n text-align: start;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n .input-container:focus-within[compact] .label {\r\n font-size: var(--sky-font-size-xs);\r\n color: var(--sky-input-color);\r\n }\r\n\r\n .input-wrapper {\r\n position: relative;\r\n display: flex;\r\n width: 100%;\r\n align-items: center;\r\n box-sizing: border-box;\r\n height: 38px;\r\n pointer-events: auto;\r\n background: var(--sky-glass-solid);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n border-radius: var(--sky-radius-secondary);\r\n border: var(--sky-border-primary);\r\n box-shadow: var(--sky-box-shadow-primary);\r\n transition:\r\n border-color var(--sky-transition-normal, 200ms ease),\r\n box-shadow var(--sky-transition-normal, 200ms ease);\r\n }\r\n\r\n .input-wrapper::after {\r\n content: \"\";\r\n position: absolute;\r\n top: -1px;\r\n left: -1px;\r\n right: -1px;\r\n bottom: -1px;\r\n border-radius: inherit;\r\n border: 1px solid transparent;\r\n border-bottom-color: transparent;\r\n opacity: 0;\r\n transition:\r\n opacity 0.3s ease,\r\n border-color 0.3s ease;\r\n pointer-events: none;\r\n }\r\n\r\n .input-wrapper:has(input:focus-visible)::after,\r\n .input-wrapper:has(textarea:focus-visible)::after {\r\n opacity: 1;\r\n border-bottom-color: var(--sky-input-color);\r\n }\r\n\r\n .input-wrapper:has(input:focus)::after,\r\n .input-wrapper:has(textarea:focus)::after {\r\n opacity: 1;\r\n border-bottom-color: var(--sky-input-color);\r\n }\r\n\r\n :host([validationActive]:invalid) .input-wrapper::after {\r\n opacity: 1;\r\n border-bottom-color: var(--sky-danger-primary);\r\n }\r\n :host([validationActive]:invalid) .label {\r\n color: var(--sky-danger-primary);\r\n }\r\n\r\n :host([validationActive]:invalid) .icon-slot {\r\n color: var(--sky-danger-primary);\r\n }\r\n\r\n .input-wrapper[compact] {\r\n height: 30px;\r\n border: var(--sky-border-primary);\r\n }\r\n\r\n input[type=\"date\"],\r\n input[type=\"time\"],\r\n input[type=\"week\"],\r\n input[type=\"month\"],\r\n input[type=\"datetime-local\"] {\r\n -webkit-appearance: none;\r\n -moz-appearance: none;\r\n appearance: none;\r\n background: none;\r\n border: none;\r\n font-family: inherit;\r\n }\r\n\r\n input[type=\"date\"]::-webkit-calendar-picker-indicator,\r\n input[type=\"time\"]::-webkit-calendar-picker-indicator,\r\n input[type=\"week\"]::-webkit-calendar-picker-indicator,\r\n input[type=\"month\"]::-webkit-calendar-picker-indicator,\r\n input[type=\"datetime-local\"]::-webkit-calendar-picker-indicator {\r\n display: none;\r\n }\r\n\r\n .input-wrapper:has(input:focus)[compact]::after {\r\n border: 1px solid var(--sky-input-color);\r\n }\r\n\r\n .toggle-password[compact] {\r\n font-size: var(--sky-font-size-md);\r\n }\r\n\r\n input {\r\n font-family: var(--sky-font);\r\n font-size: var(--sky-font-size-md);\r\n text-align: left;\r\n transition: transform var(--sky-transition-normal, 200ms ease);\r\n }\r\n\r\n input:-webkit-autofill {\r\n -webkit-text-fill-color: var(--sky-text-secondary, inherit) !important;\r\n transition: background-color 9999s ease-in-out 0s !important;\r\n }\r\n\r\n :dir(rtl) input {\r\n text-align: right;\r\n }\r\n\r\n input[type=\"number\"] {\r\n appearance: textfield;\r\n -moz-appearance: textfield;\r\n }\r\n\r\n input[type=\"number\"]::-webkit-inner-spin-button,\r\n input[type=\"number\"]::-webkit-outer-spin-button {\r\n -webkit-appearance: none;\r\n margin: 0;\r\n }\r\n .number-btn {\r\n display: flex;\r\n flex-shrink: 0;\r\n margin-inline-end: var(--sky-space-1, 4px);\r\n gap: var(--sky-space-1, 4px);\r\n }\r\n\r\n :dir(rtl).number-btn {\r\n margin-inline-end: var(--sky-space-1, 4px);\r\n }\r\n\r\n .file-info {\r\n display: flex;\r\n justify-content: flex-end;\r\n font-size: var(--sky-font-size-xs);\r\n color: var(--sky-text-secondary);\r\n font-family: var(--sky-font);\r\n }\r\n\r\n :dir(rtl).file-info {\r\n flex-direction: row-reverse;\r\n }\r\n\r\n .increment-btn,\r\n .decrement-btn {\r\n background: var(--sky-glass-solid);\r\n color: var(--sky-text-primary);\r\n border: var(--sky-border-primary);\r\n border-radius: var(--sky-radius-primary);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: var(--sky-space-0\\\\.5, 2px) var(--sky-space-1\\\\.5, 6px);\r\n font-size: var(--sky-font-size-sm);\r\n cursor: pointer;\r\n transition: color var(--sky-transition-normal, 200ms ease);\r\n font-family: var(--sky-font);\r\n }\r\n\r\n .increment-btn:hover,\r\n .decrement-btn:hover {\r\n color: var(--sky-input-color);\r\n }\r\n\r\n .toggle-password {\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-inline-end: var(--sky-space-1, 4px);\r\n font-size: var(--sky-font-size-lg);\r\n color: var(--sky-text-tertiary);\r\n cursor: pointer;\r\n }\r\n\r\n .toggle-password:hover {\r\n color: var(--sky-input-color);\r\n }\r\n\r\n input {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n border: none;\r\n outline: none;\r\n background: transparent;\r\n box-sizing: border-box;\r\n color: var(--sky-text-primary);\r\n padding-block: 0;\r\n padding-inline: var(--sky-space-3, 12px);\r\n }\r\n\r\n input::placeholder {\r\n color: var(--sky-text-tertiary);\r\n }\r\n\r\n .input-affix {\r\n flex: 0 0 auto;\r\n font-family: var(--sky-font);\r\n font-size: var(--sky-font-size-md);\r\n font-weight: var(--sky-font-weight-medium);\r\n color: var(--sky-text-secondary);\r\n user-select: none;\r\n white-space: nowrap;\r\n line-height: 1;\r\n }\r\n\r\n .input-affix.prefix {\r\n padding-inline-start: var(--sky-space-3, 12px);\r\n padding-inline-end: var(--sky-space-1, 4px);\r\n }\r\n\r\n .input-affix.suffix {\r\n padding-inline-start: var(--sky-space-1, 4px);\r\n padding-inline-end: var(--sky-space-2, 8px);\r\n }\r\n\r\n .input-wrapper[compact] .input-affix {\r\n font-size: var(--sky-font-size-sm);\r\n }\r\n\r\n .input-wrapper:has(.input-affix.prefix) input,\r\n .input-wrapper:has(.input-affix.prefix) textarea {\r\n padding-inline-start: var(--sky-space-1, 4px);\r\n }\r\n\r\n .input-wrapper:has(.icon-slot[filled].left) input,\r\n .input-wrapper:has(.icon-slot[filled].left) textarea {\r\n padding-inline-start: var(--sky-space-1, 4px);\r\n }\r\n\r\n .custom-file-label__text {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n color: var(--sky-text-tertiary);\r\n padding-inline-end: var(--sky-space-3, 12px);\r\n }\r\n\r\n .custom-file-label:not(:has(.input-affix.prefix)) .custom-file-label__text {\r\n padding-inline-start: var(--sky-space-3, 12px);\r\n }\r\n\r\n .custom-file-label__text[data-filled] {\r\n color: var(--sky-text-primary);\r\n }\r\n\r\n .icon-slot {\r\n display: none;\r\n justify-content: center;\r\n font-size: var(--sky-font-size-xl);\r\n align-items: center;\r\n color: var(--sky-text-primary);\r\n border-radius: var(--sky-radius-secondary);\r\n height: inherit;\r\n max-height: 100%;\r\n box-sizing: border-box;\r\n min-width: 36px;\r\n background: var(--sky-glass-solid);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n transition:\r\n transform var(--sky-transition-normal, 200ms ease),\r\n color var(--sky-transition-normal, 200ms ease);\r\n }\r\n\r\n .input-wrapper:has(textarea) .icon-slot {\r\n max-height: 38px;\r\n border-bottom: var(--sky-border-primary);\r\n }\r\n\r\n .icon-slot[filled] {\r\n display: flex;\r\n flex-shrink: 0;\r\n cursor: pointer;\r\n }\r\n .icon-slot[filled]:hover {\r\n transform: translate(-5px, -5px);\r\n color: var(--sky-input-color);\r\n }\r\n .icon-slot.right[filled]:hover {\r\n transform: translate(5px, -5px);\r\n color: var(--sky-input-color);\r\n }\r\n\r\n .icon-slot.focused {\r\n transform: translate(-5px, -5px);\r\n color: var(--sky-input-color);\r\n border: var(--sky-border-primary) !important;\r\n }\r\n\r\n :dir(rtl) .icon-slot[filled]:hover {\r\n transform: translate(5px, -5px);\r\n }\r\n\r\n :dir(rtl) .icon-slot.right[filled]:hover {\r\n transform: translate(-5px, -5px);\r\n }\r\n\r\n :dir(rtl) .icon-slot.focused {\r\n transform: translate(5px, -5px);\r\n }\r\n\r\n .icon-slot.right {\r\n border-left: var(--sky-border-primary);\r\n }\r\n .icon-slot.left {\r\n border-right: var(--sky-border-primary);\r\n }\r\n\r\n :dir(rtl) .icon-slot.right {\r\n border-left: unset;\r\n border-right: var(--sky-border-primary);\r\n }\r\n :dir(rtl) .icon-slot.left {\r\n border-right: unset;\r\n border-left: var(--sky-border-primary);\r\n }\r\n\r\n .icon-slot.right.focused {\r\n transform: translate(5px, -5px);\r\n }\r\n\r\n :dir(rtl) .icon-slot.right.focused {\r\n transform: translate(-5px, -5px);\r\n }\r\n\r\n .progress-message {\r\n pointer-events: none;\r\n width: 100%;\r\n overflow: hidden;\r\n white-space: nowrap;\r\n text-overflow: ellipsis;\r\n font-size: var(--sky-font-size-sm);\r\n margin-left: 5px;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n :dir(rtl) .progress-message {\r\n margin-left: unset;\r\n margin-right: 5px;\r\n }\r\n\r\n .error-list {\r\n list-style: none;\r\n margin: 0;\r\n padding: 0;\r\n width: 100%;\r\n }\r\n\r\n .error {\r\n font-size: var(--sky-font-size-xs);\r\n color: var(--sky-danger-primary);\r\n text-align: start;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n ::slotted(.icon-slot) {\r\n display: block;\r\n }\r\n\r\n .input-wrapper[loading] input {\r\n cursor: wait;\r\n }\r\n\r\n .loading-indicator {\r\n flex-shrink: 0;\r\n margin-inline-end: var(--sky-space-1, 4px);\r\n width: 16px;\r\n height: 16px;\r\n border: 2px solid var(--sky-hover-primary);\r\n border-top: 2px solid var(--sky-input-color);\r\n border-radius: var(--sky-radius-full);\r\n animation: spin 1s linear infinite;\r\n }\r\n\r\n .loading-indicator[compact] {\r\n width: 10px;\r\n height: 10px;\r\n }\r\n\r\n .input-wrapper[loading] .icon-slot.right {\r\n display: none;\r\n }\r\n\r\n @keyframes spin {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n .clear-button {\r\n flex-shrink: 0;\r\n margin-inline-end: var(--sky-space-1, 4px);\r\n border: none;\r\n font-size: var(--sky-font-size-xl);\r\n color: var(--sky-input-color);\r\n background-color: var(--sky-hover-primary);\r\n border-radius: var(--sky-radius-full);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n cursor: pointer;\r\n transition: color var(--sky-transition-normal, 200ms ease);\r\n }\r\n\r\n .clear-button[compact] {\r\n font-size: var(--sky-font-size-md);\r\n }\r\n\r\n .clear-button[loading] {\r\n opacity: 0.6;\r\n pointer-events: none;\r\n }\r\n\r\n input[type=\"file\"] {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n opacity: 0;\r\n pointer-events: auto;\r\n z-index: -1;\r\n }\r\n\r\n .custom-file-label {\r\n position: relative;\r\n flex: 1;\r\n display: flex;\r\n align-items: center;\r\n gap: var(--sky-space-1, 4px);\r\n text-align: left;\r\n padding: 0;\r\n color: var(--sky-input-color);\r\n border-radius: var(--sky-radius-secondary);\r\n overflow: hidden;\r\n white-space: nowrap;\r\n text-overflow: ellipsis;\r\n cursor: pointer;\r\n transition:\r\n background 0.3s ease,\r\n padding 0.3s ease;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n .custom-file-label:hover .custom-file-label__text {\r\n padding-inline-start: var(--sky-space-2\\\\.5, 10px);\r\n }\r\n\r\n .custom-file-label:empty::after {\r\n content: \"Choose file\";\r\n color: var(--sky-input-color);\r\n }\r\n\r\n .clear-button:hover {\r\n color: var(--sky-danger-primary);\r\n }\r\n\r\n textarea {\r\n flex: 1 1 auto;\r\n min-width: 0;\r\n border: none;\r\n outline: none;\r\n background: transparent;\r\n box-sizing: border-box;\r\n color: var(--sky-text-primary);\r\n padding: var(--sky-space-2\\\\.5, 10px) var(--sky-space-3, 12px);\r\n resize: none;\r\n overflow: auto;\r\n font-family: var(--sky-font);\r\n }\r\n\r\n textarea[resizable=\"vertical\"] {\r\n resize: vertical;\r\n }\r\n\r\n textarea[resizable=\"both\"] {\r\n resize: both;\r\n }\r\n\r\n textarea {\r\n scrollbar-width: thin;\r\n scrollbar-color: var(--sky-scrollbar-thumb) var(--sky-scrollbar-track);\r\n }\r\n\r\n textarea::-webkit-scrollbar {\r\n width: 6px;\r\n height: 6px;\r\n }\r\n\r\n textarea::-webkit-scrollbar-thumb {\r\n background-color: var(--sky-scrollbar-thumb);\r\n border-radius: var(--sky-radius-full, 9999px);\r\n transition: background-color var(--sky-duration-normal, 200ms)\r\n var(--sky-ease-default, ease);\r\n cursor: grab;\r\n }\r\n\r\n textarea::-webkit-scrollbar-thumb:hover {\r\n background-color: var(--sky-scrollbar-thumb-hover);\r\n }\r\n\r\n textarea::-webkit-scrollbar-track {\r\n background: var(--sky-scrollbar-track);\r\n }\r\n\r\n textarea::-webkit-scrollbar-button {\r\n display: none;\r\n }\r\n\r\n textarea::placeholder {\r\n color: var(--sky-text-tertiary);\r\n }\r\n\r\n .input-wrapper:has(textarea) {\r\n height: calc((var(--rows)) * 23px);\r\n align-items: flex-start;\r\n }\r\n textarea {\r\n height: calc((var(--rows)) * 23px);\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .loading-indicator {\r\n animation: none;\r\n }\r\n\r\n .input-container:focus-within .label,\r\n .input-wrapper,\r\n .icon-slot,\r\n .increment-btn,\r\n .decrement-btn,\r\n .clear-button,\r\n input,\r\n textarea,\r\n .custom-file-label {\r\n transition: none;\r\n }\r\n }\r\n `;\r\n\r\n static override shadowRootOptions = {\r\n ...LitElement.shadowRootOptions,\r\n delegatesFocus: true,\r\n };\r\n\r\n override connectedCallback(): void {\r\n super.connectedCallback();\r\n this.autofillGuardActive = this.type === \"search\";\r\n\r\n // Make the host focusable\r\n if (!this.hasAttribute(\"tabindex\")) {\r\n this.tabIndex = this.disabled ? -1 : 0;\r\n }\r\n\r\n if (this.hasUpdated) {\r\n this._setupIconSlots();\r\n }\r\n }\r\n\r\n override disconnectedCallback(): void {\r\n this._leftIconSlot?.removeEventListener(\r\n \"slotchange\",\r\n this._onLeftIconSlotChange,\r\n );\r\n this._rightIconSlot?.removeEventListener(\r\n \"slotchange\",\r\n this._onRightIconSlotChange,\r\n );\r\n this._leftIconSlot = null;\r\n this._rightIconSlot = null;\r\n super.disconnectedCallback();\r\n }\r\n\r\n private _setupIconSlots(): void {\r\n if (!this._leftIconSlot) {\r\n this._leftIconSlot =\r\n this.shadowRoot?.querySelector<HTMLSlotElement>(\r\n 'slot[name=\"icon-left\"]',\r\n ) ?? null;\r\n this._leftIconSlot?.addEventListener(\r\n \"slotchange\",\r\n this._onLeftIconSlotChange,\r\n );\r\n }\r\n if (!this._rightIconSlot) {\r\n this._rightIconSlot =\r\n this.shadowRoot?.querySelector<HTMLSlotElement>(\r\n 'slot[name=\"icon-right\"]',\r\n ) ?? null;\r\n this._rightIconSlot?.addEventListener(\r\n \"slotchange\",\r\n this._onRightIconSlotChange,\r\n );\r\n }\r\n this._wireIconSlot(\"left\", this._leftIconSlot);\r\n this._wireIconSlot(\"right\", this._rightIconSlot);\r\n }\r\n\r\n private _wireIconSlot(\r\n side: \"left\" | \"right\",\r\n slot: HTMLSlotElement | null,\r\n ): void {\r\n if (!slot) return;\r\n for (const node of slot.assignedElements({ flatten: true })) {\r\n if (!(node instanceof HTMLElement)) continue;\r\n if (this._iconClickWired.has(node)) continue;\r\n this._iconClickWired.add(node);\r\n node.addEventListener(\"click\", () => this.handleIconClick(side));\r\n }\r\n }\r\n\r\n override firstUpdated(\r\n _changedProperties: Map<string | number | symbol, unknown>,\r\n ) {\r\n super.firstUpdated(_changedProperties);\r\n\r\n // default/reset value\r\n this.captureDefaultValue(this.value as string);\r\n\r\n // initial sync into form\r\n this.syncFormValue();\r\n this.syncValidity();\r\n\r\n this._setupIconSlots();\r\n }\r\n\r\n override willUpdate(\r\n changedProperties: Map<string | number | symbol, unknown>,\r\n ) {\r\n if (\r\n changedProperties.has(\"validations\") &&\r\n Array.isArray(this.validations)\r\n ) {\r\n this.validationStatus = this.validations.map(() => false);\r\n }\r\n\r\n if (changedProperties.has(\"value\") && this.type === \"file\") {\r\n if (this.value == null || String(this.value).trim() === \"\") {\r\n this.selectedFileName = \"\";\r\n this.selectedFiles = [];\r\n this.totalFileSize = 0;\r\n this.selectedFileCount = 0;\r\n this.filePreview = null;\r\n } else if (!this.selectedFileName) {\r\n this.selectedFileName = this.value as string;\r\n }\r\n }\r\n if (changedProperties.has(\"type\") && this.type === \"search\") {\r\n this.autofillGuardActive = true;\r\n }\r\n }\r\n\r\n override updated(changedProperties: Map<string | number | symbol, unknown>) {\r\n super.updated(changedProperties);\r\n\r\n if (changedProperties.has(\"color\") && this.color) {\r\n this.style.setProperty(\"--sky-input-color\", resolveColor(this.color));\r\n }\r\n\r\n if (changedProperties.has(\"rows\")) {\r\n const inputWrapper = this.inputWrapperEl;\r\n if (inputWrapper) {\r\n inputWrapper.style.setProperty(\"--rows\", String(this.rows));\r\n }\r\n }\r\n\r\n if (\r\n changedProperties.has(\"value\") ||\r\n changedProperties.has(\"selectedFiles\") ||\r\n changedProperties.has(\"selectedFileName\") ||\r\n changedProperties.has(\"type\") ||\r\n changedProperties.has(\"multiple\") ||\r\n changedProperties.has(\"name\") ||\r\n changedProperties.has(\"disabled\")\r\n ) {\r\n this.syncFormValue();\r\n }\r\n\r\n if (\r\n changedProperties.has(\"value\") ||\r\n changedProperties.has(\"selectedFiles\") ||\r\n changedProperties.has(\"selectedFileName\") ||\r\n changedProperties.has(\"validationErrors\") ||\r\n changedProperties.has(\"required\") ||\r\n changedProperties.has(\"disabled\") ||\r\n changedProperties.has(\"readonly\")\r\n ) {\r\n this.syncValidity();\r\n }\r\n }\r\n\r\n /** @protected */\r\n protected override getFormValue(): string | File | FormData | null {\r\n if (!this.name) return null;\r\n\r\n if (this.type === \"file\") {\r\n if (!this.selectedFiles || this.selectedFiles.length === 0) return null;\r\n\r\n if (this.multiple) {\r\n const fd = new FormData();\r\n for (const f of this.selectedFiles) fd.append(this.name, f);\r\n return fd;\r\n }\r\n return this.selectedFiles[0];\r\n }\r\n\r\n return this.value as string ?? \"\";\r\n }\r\n\r\n /** @protected */\r\n protected override setValueFromFormState(\r\n state: string | File | FormData | null,\r\n ) {\r\n // For SkyInput, state restore is typically string\r\n if (typeof state === \"string\") {\r\n this.value = state;\r\n // for textarea/input UI to refresh, you already use live()\r\n return;\r\n }\r\n\r\n // For file state restore: browsers usually won't restore actual File objects for security.\r\n // So do a safe reset:\r\n this.value = \"\";\r\n this.selectedFileName = \"\";\r\n this.selectedFiles = [];\r\n this.totalFileSize = 0;\r\n this.selectedFileCount = 0;\r\n this.filePreview = null;\r\n }\r\n\r\n /** @protected */\r\n protected override getValidityAnchor(): HTMLElement | undefined {\r\n return this;\r\n }\r\n\r\n /** @protected */\r\n protected override isEmpty(): boolean {\r\n if (this.type === \"file\") {\r\n return !this.selectedFiles || this.selectedFiles.length === 0;\r\n }\r\n return !this.value || this.value.toString().trim() === \"\";\r\n }\r\n\r\n /** @protected */\r\n protected override getCustomErrorMessage(): string {\r\n if (!this.validationErrors?.length) return \"\";\r\n\r\n // single message that includes all\r\n if (this.errorDisplayMode === \"all\") {\r\n return this.validationErrors.join(\"\\n\");\r\n }\r\n\r\n // single mode\r\n return this.validationErrors[0];\r\n }\r\n\r\n /** @protected */\r\n protected override getNativeControl(): HTMLElement | null {\r\n if (this.type === \"textarea\") {\r\n return this.shadowRoot?.querySelector(\r\n \"textarea\",\r\n ) as HTMLTextAreaElement | null;\r\n }\r\n // for all other types (text/email/password/date/...)\r\n return this.shadowRoot?.querySelector(\"input\") as HTMLInputElement | null;\r\n }\r\n\r\n /** @protected */\r\n protected override onNativeValueMutated(native: any): void {\r\n // IMPORTANT: file input is managed via change handler; don't trust setting native.value\r\n if (this.type !== \"file\") {\r\n this.value = native?.value ?? \"\";\r\n }\r\n // keep SkyInput custom validations in sync\r\n this.validateInput();\r\n }\r\n\r\n /**\r\n * Resets the input field to its initial state.\r\n * @public\r\n */\r\n reset() {\r\n this.value = \"\";\r\n this.selectedFileName = \"\";\r\n this.filePreview = null;\r\n this.selectedFiles = [];\r\n this.selectedFileCount = 0;\r\n this.validationErrors = [];\r\n this.typingStarted = false;\r\n this.validationActive = false;\r\n this.selectedFileCount = 0;\r\n this.totalFileSize = 0;\r\n }\r\n\r\n /** @private */\r\n private get nativeRequiredMessage(): string {\r\n if (!this.validationActive) return \"\";\r\n if (this.disabled) return \"\";\r\n if (this.required && this.isEmpty())\r\n return this.requiredMessage || \"This field is required.\";\r\n return \"\";\r\n }\r\n\r\n /** @private */\r\n private getEmittedValue(): string | number {\r\n if (this.type !== \"number\") return this.value as string;\r\n\r\n // allow empty to stay empty (important for clearing)\r\n if (this.value === \"\" || this.value == null) return \"\";\r\n\r\n const n = Number(this.value);\r\n // if user is still typing an invalid numeric token, keep as string\r\n return Number.isFinite(n) ? n : this.value as string;\r\n }\r\n\r\n /**\r\n * Clears the input value and resets typing state.\r\n * @public\r\n */\r\n handleClear() {\r\n if (this.disabled || this.readonly) {\r\n return;\r\n }\r\n this.reset();\r\n this.validationActive = true;\r\n this.validateInput();\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\r\n detail: { value: this.getEmittedValue() },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValueClearedDetail>(\"value-cleared\", {\r\n detail: { value: this.getEmittedValue() },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Handles the `change` event triggered by the file input element.\r\n * @param {Event} event - The event object generated by the file input element when files are selected.\r\n * @public\r\n */\r\n handleFileChange(event: Event): void {\r\n if (this.disabled || this.readonly) {\r\n return;\r\n }\r\n const input = event.target as HTMLInputElement;\r\n const files = input.files;\r\n\r\n if (files && files.length) {\r\n const fileList: File[] = Array.from(files);\r\n this.selectedFiles = fileList;\r\n this.selectedFileName = fileList\r\n .map((file: File) => file.name)\r\n .join(\", \");\r\n this.value = this.selectedFileName;\r\n\r\n this.syncFormValue();\r\n this.syncValidity();\r\n\r\n const totalSize: number = fileList.reduce(\r\n (total: number, file: File) => total + file.size,\r\n 0,\r\n );\r\n this.totalFileSize = totalSize;\r\n\r\n this.selectedFileCount = fileList.length;\r\n\r\n if (fileList[0].type.startsWith(\"image/\")) {\r\n const reader = new FileReader();\r\n reader.onload = (e: ProgressEvent<FileReader>) => {\r\n if (e.target) {\r\n this.filePreview = e.target.result;\r\n }\r\n };\r\n reader.readAsDataURL(fileList[0]);\r\n } else {\r\n this.filePreview = null;\r\n }\r\n\r\n this.reemitNativeEvent(\"change\", event);\r\n this.reemitNativeEvent(\"input\", event);\r\n\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputFileSelectedDetail>(\"file-selected\", {\r\n detail: {\r\n files: fileList,\r\n fileName: this.selectedFileName,\r\n totalSize,\r\n fileCount: this.selectedFileCount,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n\r\n this.validateInput();\r\n } else {\r\n this.value = \"\";\r\n this.filePreview = null;\r\n this.totalFileSize = 0;\r\n this.selectedFileCount = 0;\r\n this.selectedFiles = [];\r\n this.validateInput();\r\n }\r\n }\r\n\r\n /**\r\n * Handles the keydown event for the input component.\r\n * @param event - The keyboard event triggered by the user.\r\n * @private\r\n */\r\n private handleKeydown(event: KeyboardEvent) {\r\n if (this.disabled || this.readonly) {\r\n return;\r\n }\r\n if (event.key === \"Enter\" && this.type === \"file\") {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.triggerNativeDropdown();\r\n }\r\n }\r\n\r\n /**\r\n * Gets the current file preview.\r\n * @returns The preview of the file, as stored in `filePreview`.\r\n * @public\r\n */\r\n get preview() {\r\n return this.filePreview;\r\n }\r\n\r\n /**\r\n * Handles the input event for the input field.\r\n * @param {Event} event - The input event triggered by user interaction.\r\n * @public\r\n */\r\n handleInput(event: Event) {\r\n event.stopPropagation();\r\n\r\n if (this.disabled || this.readonly) {\r\n event.preventDefault();\r\n return;\r\n }\r\n\r\n this.value = (event.target as HTMLInputElement | HTMLTextAreaElement).value;\r\n\r\n this.syncFormValue(); // ✅ IMPORTANT\r\n this.syncValidity(); // ✅ optional but good\r\n\r\n if (!this.typingStarted) this.typingStarted = true;\r\n\r\n this.validateInput();\r\n\r\n this.reemitNativeEvent(\"input\", event);\r\n\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\r\n detail: { value: this.getEmittedValue() },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Handles the focus event for the input field.\r\n * @public\r\n */\r\n handleFocus(event: Event) {\r\n event.stopPropagation();\r\n this.releaseAutofillGuard();\r\n this.focused = true;\r\n this.reemitNativeEvent(\"focus\", event);\r\n }\r\n\r\n /** Chrome may autofill saved usernames into filter fields; readonly until interaction blocks that. */\r\n private releaseAutofillGuard(): void {\r\n if (!this.autofillGuardActive) return;\r\n this.autofillGuardActive = false;\r\n }\r\n\r\n private handleAutofillGuardPointerDown(event: Event): void {\r\n this.releaseAutofillGuard();\r\n event.stopPropagation();\r\n }\r\n\r\n /** @protected */\r\n protected override onFormReset() {\r\n // restore default value (or blank)\r\n this.setValueFromFormState(this.defaultValue);\r\n\r\n // ✅ reset UI state\r\n this.validationActive = false;\r\n this.invalid = false;\r\n this.typingStarted = false;\r\n this.validationErrors = [];\r\n this.validationStatus = [];\r\n\r\n // If file:\r\n if (this.type === \"file\") {\r\n this.selectedFiles = [];\r\n this.selectedFileName = \"\";\r\n this.totalFileSize = 0;\r\n this.selectedFileCount = 0;\r\n this.filePreview = null;\r\n }\r\n\r\n if (this.type === \"search\") {\r\n this.autofillGuardActive = true;\r\n }\r\n }\r\n\r\n /**\r\n * Handles the blur event for the input field.\r\n * @public\r\n */\r\n handleBlur(event: Event) {\r\n event.stopPropagation();\r\n this.validationActive = true;\r\n this.focused = false;\r\n this.reemitNativeEvent(\"blur\", event);\r\n }\r\n\r\n /** @protected */\r\n protected override validateForForm(): string {\r\n // run your `this.validations` against current value even if validationActive is false\r\n const payload =\r\n this.type === \"file\" ? (this.selectedFiles ?? []) : (this.value ?? \"\");\r\n\r\n for (const v of this.validations ?? []) {\r\n const r = v(payload as string | File[]);\r\n if (r !== true) return typeof r === \"string\" ? r : \"Invalid value.\";\r\n }\r\n\r\n return \"\";\r\n }\r\n\r\n /**\r\n * Validates the input value against the configured validation rules.\r\n * @returns {boolean} True if validation passes, false otherwise.\r\n * @public\r\n */\r\n validateInput(): boolean {\r\n // reset\r\n this.validationErrors = [];\r\n this.validationStatus = [];\r\n\r\n const isFileInput = this.type === \"file\";\r\n const isEmpty = isFileInput\r\n ? !this.selectedFiles || this.selectedFiles.length === 0\r\n : !this.value || this.value.toString().trim() === \"\";\r\n\r\n // 1) If empty + required -> let SkyFormControlBase handle native required\r\n // (do NOT push required into validationErrors)\r\n if (this.required && isEmpty) {\r\n this.syncValidity(); // will set valueMissing\r\n }\r\n\r\n // 2) Run custom validations only if there is something to validate\r\n if (Array.isArray(this.validations) && this.validations.length) {\r\n const payload: string | File[] = isFileInput\r\n ? (this.selectedFiles ?? [])\r\n : (this.value as string ?? \"\");\r\n\r\n this.validationStatus = this.validations.map((validation, index) => {\r\n try {\r\n if (typeof validation !== \"function\") {\r\n throw new Error(`Validation at index ${index} must be a function.`);\r\n }\r\n\r\n const result = validation(payload);\r\n\r\n if (result !== true) {\r\n this.validationErrors.push(\r\n typeof result === \"string\"\r\n ? result\r\n : `Validation ${index} failed.`,\r\n );\r\n return false;\r\n }\r\n\r\n return true;\r\n } catch (error) {\r\n const message =\r\n typeof error === \"object\" && error !== null && \"message\" in error\r\n ? String((error as any).message)\r\n : typeof error === \"string\"\r\n ? error\r\n : \"Unknown error\";\r\n\r\n this.validationErrors.push(\r\n `Error in validation ${index}: ${message}`,\r\n );\r\n return false;\r\n }\r\n });\r\n }\r\n // 3) Dispatch event with all accumulated errors\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValidationErrorDetail>(\"validation-error\", {\r\n detail: { errors: this.validationErrors },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n\r\n this.syncValidity();\r\n\r\n const isValid = this.validationErrors.length === 0;\r\n this.invalid = !isValid;\r\n\r\n return isValid;\r\n }\r\n\r\n /**\r\n * Retrieves validation error messages based on the configured error display mode.\r\n * @returns {Array} - An array of error messages to display.\r\n * @private\r\n */\r\n private getErrorMessages() {\r\n switch (this.errorDisplayMode) {\r\n case \"single\":\r\n return this.validationErrors.slice(0, 1);\r\n case \"all\":\r\n return this.validationErrors;\r\n case \"none\":\r\n default:\r\n return [];\r\n }\r\n }\r\n\r\n /**\r\n * Handles click events for the left or right icon slots.\r\n * @param {String} position - The position of the icon (\"left\" or \"right\").\r\n * @param {Event|null} event - The original event triggered by the click (optional).\r\n * @public\r\n */\r\n handleIconClick(position: \"left\" | \"right\", event: Event | null = null) {\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputIconClickDetail>(`${position}-icon-click`, {\r\n detail: {\r\n position,\r\n eventType: event ? event.type : null,\r\n eventData: event,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Formats a file size in bytes into a human-readable string.\r\n * @param {number} bytes - The file size in bytes.\r\n * @returns {string} - The formatted file size string.\r\n * @public\r\n */\r\n formatFileSize(bytes: number): string {\r\n if (bytes === 0) return \"0 Bytes\";\r\n\r\n const k = 1024;\r\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\r\n const i = Math.floor(Math.log(bytes) / Math.log(k));\r\n\r\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\r\n }\r\n\r\n /**\r\n * Increments the input value by the specified step, respecting min/max constraints.\r\n * @private\r\n */\r\n private incrementValue() {\r\n if (this.disabled || this.readonly) return;\r\n const currentValue = parseFloat(this.value as string) || 0;\r\n const step = parseFloat(this.step ?? \"\") || 1;\r\n const max = this.max ? parseFloat(this.max) : Infinity;\r\n\r\n if (currentValue + step <= max) {\r\n this.value = (currentValue + step).toString();\r\n this.validateInput();\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\r\n detail: { value: this.getEmittedValue() },\r\n }),\r\n );\r\n }\r\n this.refocusInput();\r\n }\r\n\r\n /**\r\n * Decrements the input value by the specified step, respecting min/max constraints.\r\n * @private\r\n */\r\n private decrementValue() {\r\n if (this.disabled || this.readonly) return;\r\n const currentValue = parseFloat(this.value as string) || 0;\r\n const step = parseFloat(this.step ?? \"\") || 1;\r\n const min = this.min ? parseFloat(this.min) : -Infinity;\r\n\r\n if (currentValue - step >= min) {\r\n this.value = (currentValue - step).toString();\r\n this.validateInput();\r\n this.dispatchEvent(\r\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\r\n detail: { value: this.getEmittedValue() },\r\n }),\r\n );\r\n }\r\n this.refocusInput();\r\n }\r\n\r\n /**\r\n * Renders validation error messages if applicable.\r\n * @returns {TemplateResult|null} - The rendered error messages or null.\r\n * @private\r\n */\r\n private renderValidationErrors() {\r\n\r\n if (!this.showErrors || !this.validationActive) return null;\r\n\r\n const requiredMsg = this.nativeRequiredMessage;\r\n const customMsgs = this.getErrorMessages(); // already respects errorDisplayMode for custom\r\n\r\n let msgs: string[] = [];\r\n\r\n if (this.errorDisplayMode === \"single\") {\r\n // ✅ single message overall: required wins, else first custom\r\n if (requiredMsg) msgs = [requiredMsg];\r\n else if (customMsgs.length) msgs = [customMsgs[0]];\r\n } else {\r\n // all/none behavior\r\n msgs = requiredMsg ? [requiredMsg, ...customMsgs] : customMsgs;\r\n }\r\n\r\n if (!msgs.length) return null;\r\n\r\n const errId = `${this.id || \"sky-input\"}-errors`;\r\n\r\n return html`\r\n <div class=\"progress-message\">\r\n <ul id=${errId} class=\"error-list\" part=\"error-list\">\r\n ${msgs.map((m) => html`<li class=\"error\" part=\"error\">${m}</li>`)}\r\n </ul>\r\n </div>\r\n `;\r\n }\r\n\r\n /**\r\n * Toggles the visibility of the password input.\r\n * @public\r\n */\r\n togglePasswordVisibility() {\r\n this.showPassword = !this.showPassword;\r\n }\r\n\r\n public focusInput(): void {\r\n const input = this.nativeInputEl;\r\n if (\r\n input &&\r\n typeof (input as HTMLInputElement | HTMLTextAreaElement).focus === \"function\"\r\n ) {\r\n (input as HTMLInputElement | HTMLTextAreaElement).focus();\r\n }\r\n }\r\n\r\n /**\r\n * Handles click events on the input wrapper.\r\n * @param {Event} event - The original click event.\r\n * @private\r\n */\r\n private handleWrapperClick(event: Event) {\r\n event.stopPropagation();\r\n if (this.disabled) return;\r\n const input = this.nativeInputEl;\r\n if (\r\n input &&\r\n typeof (input as HTMLInputElement | HTMLTextAreaElement).focus ===\r\n \"function\"\r\n ) {\r\n (input as HTMLInputElement | HTMLTextAreaElement).focus();\r\n }\r\n }\r\n\r\n /** @private */\r\n private get isInvalid(): boolean {\r\n return (\r\n this.matches(\":invalid\") ||\r\n (this.validationActive && this.validationErrors.length > 0)\r\n );\r\n }\r\n\r\n /** @private */\r\n private get describedById(): string | undefined {\r\n return (\r\n this.ariaDescribedby ??\r\n (this.showErrors ? `${this.id || \"sky-input\"}-errors` : undefined)\r\n );\r\n }\r\n\r\n /**\r\n * Refocuses the input element.\r\n * @private\r\n */\r\n private refocusInput() {\r\n const el = this.shadowRoot?.querySelector(\r\n \"input\",\r\n ) as HTMLInputElement | null;\r\n el?.focus({ preventScroll: true });\r\n }\r\n\r\n /**\r\n * Keeps the input focused when interacting with related controls.\r\n * @param {Event} e - The original event.\r\n * @private\r\n */\r\n private keepInputFocused = (e: Event) => {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.refocusInput();\r\n };\r\n\r\n /**\r\n * Triggers the native dropdown for date/time/file inputs.\r\n * @private\r\n */\r\n private triggerNativeDropdown() {\r\n if (this.disabled || this.readonly) return;\r\n const input = this.shadowRoot?.querySelector(\r\n 'input[type=\"date\"], input[type=\"time\"], input[type=\"week\"], input[type=\"month\"], input[type=\"datetime-local\"], input[type=\"file\"]',\r\n ) as HTMLInputElement | null;\r\n\r\n if (input) {\r\n if (this.type === \"file\") {\r\n input.click();\r\n } else {\r\n this.showPicker();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Filter/search inputs (`type=\"search\"`) are rendered as plain text fields so\r\n * Chrome does not treat them as login username targets. Credential autofill is\r\n * further blocked with readonly-until-focus (Chrome ignores autocomplete tokens).\r\n */\r\n private isFilterSearchInput(): boolean {\r\n return this.type === \"search\";\r\n }\r\n\r\n private nativeAutocomplete(): string {\r\n if (this.isFilterSearchInput()) {\r\n return \"off\";\r\n }\r\n return this.autocomplete;\r\n }\r\n\r\n private nativeTextInputType(isPassword: boolean): string {\r\n if (isPassword && this.showPassword) return \"text\";\r\n if (this.isFilterSearchInput()) return \"text\";\r\n return this.type;\r\n }\r\n\r\n private nativeInputMode(): string | undefined {\r\n if (this.inputmode) return this.inputmode;\r\n if (this.isFilterSearchInput()) return \"search\";\r\n return undefined;\r\n }\r\n\r\n private nativeEnterKeyHint():\r\n | \"enter\"\r\n | \"done\"\r\n | \"go\"\r\n | \"next\"\r\n | \"previous\"\r\n | \"search\"\r\n | \"send\"\r\n | undefined {\r\n if (this.enterkeyhint) {\r\n return this.enterkeyhint as\r\n | \"enter\"\r\n | \"done\"\r\n | \"go\"\r\n | \"next\"\r\n | \"previous\"\r\n | \"search\"\r\n | \"send\";\r\n }\r\n if (this.isFilterSearchInput()) return \"search\";\r\n return undefined;\r\n }\r\n\r\n private nativeInputRole(): string | undefined {\r\n if (this.inputRole) return this.inputRole;\r\n if (this.type === \"search\") return \"searchbox\";\r\n return undefined;\r\n }\r\n\r\n private affixColorStyle(color: string) {\r\n const trimmed = String(color ?? \"\").trim();\r\n if (!trimmed) return undefined;\r\n return { color: resolveColor(trimmed) };\r\n }\r\n\r\n private renderInputAffix(kind: \"prefix\" | \"suffix\") {\r\n const value = kind === \"prefix\" ? this.prefix : this.suffix;\r\n if (!String(value ?? \"\").length) return nothing;\r\n const color = kind === \"prefix\" ? this.prefixColor : this.suffixColor;\r\n const style = this.affixColorStyle(color);\r\n return html`<span\r\n class=\"input-affix ${kind}\"\r\n part=\"input-${kind}\"\r\n style=${style ? styleMap(style) : nothing}\r\n >${value}</span\r\n >`;\r\n }\r\n\r\n override render() {\r\n const isFileInput = this.type === \"file\";\r\n const isTextarea = this.type === \"textarea\";\r\n const isNumberInput = this.type === \"number\";\r\n const isPassword = this.type === \"password\";\r\n const supportsInlineAffixes = !isFileInput && !isTextarea;\r\n\r\n const hasLeftSlot = !!this.querySelector('[slot=\"icon-left\"]');\r\n const hasRightSlot = !!this.querySelector('[slot=\"icon-right\"]');\r\n\r\n let autoIcon: unknown = null;\r\n if (this.type === \"date\")\r\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\r\n else if (this.type === \"time\")\r\n autoIcon = html`<sky-icon icon=\"ion:time\"></sky-icon>`;\r\n else if (this.type === \"week\")\r\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\r\n else if (this.type === \"month\")\r\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\r\n else if (this.type === \"datetime-local\")\r\n autoIcon = html`<sky-icon icon=\"ion:time\"></sky-icon>`;\r\n\r\n const showFilePreview = this.filePreview && (hasLeftSlot || hasRightSlot);\r\n const showAutoIconInLeft = this.autofillIconSlot === \"left\" && autoIcon;\r\n const showAutoIconInRight = this.autofillIconSlot === \"right\" && autoIcon;\r\n\r\n const ImagePreview = () => html`\r\n <img\r\n src=${ifDefined(\r\n typeof this.filePreview === \"string\" ? this.filePreview : undefined,\r\n )}\r\n alt=\"Preview\"\r\n style=\"width:100%;height:100%;object-fit:cover;border-radius:12px;\"\r\n />\r\n `;\r\n\r\n const LeftIconSlot = () => html`\r\n <div\r\n class=\"icon-slot left ${this.focused ? \"focused\" : \"\"}\"\r\n part=\"icon-slot icon-slot-left\"\r\n ?filled=${Boolean(showFilePreview && hasLeftSlot) ||\r\n Boolean(showAutoIconInLeft) ||\r\n hasLeftSlot}\r\n @click=${() => {\r\n if (isFileInput || showAutoIconInLeft) this.triggerNativeDropdown();\r\n }}\r\n >\r\n ${showFilePreview && hasLeftSlot\r\n ? ImagePreview()\r\n : showAutoIconInLeft\r\n ? autoIcon\r\n : html`<slot name=\"icon-left\"></slot>`}\r\n </div>\r\n `;\r\n\r\n const RightIconSlot = () =>\r\n this.loading\r\n ? html`<div\r\n class=\"loading-indicator\"\r\n part=\"loading-indicator\"\r\n ?compact=${this.compact}\r\n ></div>`\r\n : html`\r\n <div\r\n class=\"icon-slot right ${this.focused ? \"focused\" : \"\"}\"\r\n part=\"icon-slot icon-slot-right\"\r\n ?filled=${Boolean(showFilePreview && hasRightSlot) ||\r\n Boolean(showAutoIconInRight) ||\r\n hasRightSlot}\r\n @click=${() => {\r\n if (isFileInput || showAutoIconInRight)\r\n this.triggerNativeDropdown();\r\n }}\r\n >\r\n ${showFilePreview && hasRightSlot\r\n ? ImagePreview()\r\n : showAutoIconInRight\r\n ? autoIcon\r\n : html`<slot name=\"icon-right\"></slot>`}\r\n </div>\r\n `;\r\n\r\n const FileControl = () => html`\r\n <label\r\n class=\"custom-file-label\"\r\n part=\"custom-file-label\"\r\n for=\"fileInput\"\r\n ?disabled=${this.disabled}\r\n >\r\n ${this.renderInputAffix(\"prefix\")}\r\n <span\r\n class=\"custom-file-label__text\"\r\n part=\"custom-file-label-text\"\r\n ?data-filled=${Boolean(this.selectedFileName)}\r\n >\r\n ${this.selectedFileName || this.placeholder || \"Choose file\"}\r\n </span>\r\n ${this.renderInputAffix(\"suffix\")}\r\n </label>\r\n\r\n <input\r\n id=\"fileInput\"\r\n type=\"file\"\r\n @change=${this.handleFileChange}\r\n ?disabled=${this.disabled}\r\n accept=${this.accept || \"\"}\r\n ?multiple=${this.multiple}\r\n .required=${this.required}\r\n @keydown=${this.handleKeydown}\r\n .dir=${this.dir}\r\n name=${ifDefined(this.name || undefined)}\r\n .autocomplete=${this.nativeAutocomplete()}\r\n .autocapitalize=${this.autocapitalize}\r\n spellcheck=${this.spellcheck}\r\n ?autofocus=${this.autofocus}\r\n inputmode=${ifDefined(this.inputmode || undefined)}\r\n enterkeyhint=${ifDefined(\r\n this.enterkeyhint as\r\n | \"enter\"\r\n | \"done\"\r\n | \"go\"\r\n | \"next\"\r\n | \"previous\"\r\n | \"search\"\r\n | \"send\"\r\n | undefined,\r\n )}\r\n list=${ifDefined(this.list || undefined)}\r\n capture=${ifDefined(this.capture ? \"environment\" : undefined)}\r\n .aria-invalid=${String(this.isInvalid)}\r\n .aria-required=${String(this.required)}\r\n aria-label=${ifDefined(this.ariaLabel || undefined)}\r\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\r\n aria-describedby=${ifDefined(this.describedById)}\r\n />\r\n `;\r\n\r\n const TextareaControl = () => html`\r\n <textarea\r\n .value=${live(this.value)}\r\n @input=${this.handleInput}\r\n @focus=${this.handleFocus}\r\n @blur=${this.handleBlur}\r\n ?compact=${this.compact}\r\n ?disabled=${this.disabled}\r\n .required=${this.required}\r\n .rows=${this.rows}\r\n placeholder=${this.placeholder}\r\n resizable=${this.resizable || \"none\"}\r\n style=\"width:100%;border:none;outline:none;padding:10px;\"\r\n .autocapitalize=${this.autocapitalize}\r\n ?spellcheck=${this.spellcheck}\r\n name=${ifDefined(this.name || undefined)}\r\n .autocomplete=${this.nativeAutocomplete()}\r\n inputmode=${ifDefined(this.inputmode || undefined)}\r\n enterkeyhint=${ifDefined(\r\n this.enterkeyhint as\r\n | \"enter\"\r\n | \"done\"\r\n | \"go\"\r\n | \"next\"\r\n | \"previous\"\r\n | \"search\"\r\n | \"send\"\r\n | undefined,\r\n )}\r\n minlength=${ifDefined(this.minlength ?? undefined)}\r\n maxlength=${ifDefined(this.maxlength ?? undefined)}\r\n ?autofocus=${this.autofocus}\r\n .aria-invalid=${String(this.isInvalid)}\r\n .aria-required=${String(this.required)}\r\n aria-label=${ifDefined(this.ariaLabel || undefined)}\r\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\r\n aria-describedby=${ifDefined(this.describedById)}\r\n role=${ifDefined(this.nativeInputRole() as\r\n | \"textbox\"\r\n | \"searchbox\"\r\n | \"combobox\"\r\n | \"listbox\"\r\n | \"menuitem\"\r\n | \"option\"\r\n | \"slider\"\r\n | \"spinbutton\"\r\n | \"treeitem\"\r\n | undefined)}\r\n ></textarea>\r\n `;\r\n\r\n const TextInputControl = () => html`\r\n <input\r\n .type=${this.nativeTextInputType(isPassword)}\r\n .value=${live(this.value)}\r\n @input=${this.handleInput}\r\n @focus=${this.handleFocus}\r\n @blur=${this.handleBlur}\r\n @pointerdown=${this.handleAutofillGuardPointerDown}\r\n ?compact=${this.compact}\r\n ?disabled=${this.disabled}\r\n .required=${this.required}\r\n .readOnly=${this.readonly || this.autofillGuardActive}\r\n style=\"appearance:none;pointer-events:auto;\"\r\n placeholder=${this.placeholder}\r\n name=${ifDefined(this.name || undefined)}\r\n .autocomplete=${this.nativeAutocomplete()}\r\n .autocapitalize=${this.autocapitalize}\r\n spellcheck=${this.spellcheck}\r\n inputmode=${ifDefined(this.nativeInputMode())}\r\n enterkeyhint=${ifDefined(this.nativeEnterKeyHint())}\r\n data-form-type=${this.isFilterSearchInput() ? \"other\" : nothing}\r\n ?data-1p-ignore=${this.isFilterSearchInput()}\r\n ?data-lpignore=${this.isFilterSearchInput()}\r\n list=${ifDefined(this.list || undefined)}\r\n pattern=${ifDefined(this.pattern || undefined)}\r\n minlength=${ifDefined(this.minlength ?? undefined)}\r\n maxlength=${ifDefined(this.maxlength ?? undefined)}\r\n size=${ifDefined(this.size ?? undefined)}\r\n step=${ifDefined(this.step !== null ? Number(this.step) : undefined)}\r\n min=${ifDefined(this.min ?? undefined)}\r\n max=${ifDefined(this.max ?? undefined)}\r\n ?autofocus=${this.autofocus}\r\n .aria-invalid=${String(this.isInvalid)}\r\n .aria-required=${String(this.required)}\r\n aria-label=${ifDefined(this.ariaLabel || undefined)}\r\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\r\n aria-describedby=${ifDefined(this.describedById)}\r\n role=${ifDefined(this.nativeInputRole() as\r\n | \"textbox\"\r\n | \"searchbox\"\r\n | \"combobox\"\r\n | \"listbox\"\r\n | \"menuitem\"\r\n | \"option\"\r\n | \"slider\"\r\n | \"spinbutton\"\r\n | \"treeitem\"\r\n | undefined)}\r\n />\r\n `;\r\n\r\n const NumberButtons = () =>\r\n isNumberInput && this.showNumberButtons\r\n ? html`\r\n <div class=\"number-btn\">\r\n <button\r\n class=\"decrement-btn\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n @mousedown=${this.keepInputFocused}\r\n @pointerdown=${this.keepInputFocused}\r\n @click=${(e: Event) => {\r\n e.stopPropagation();\r\n this.decrementValue();\r\n }}\r\n aria-label=\"Decrease value\"\r\n >\r\n <sky-icon icon=\"ion:minus\"></sky-icon>\r\n </button>\r\n <button\r\n class=\"increment-btn\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n @mousedown=${this.keepInputFocused}\r\n @pointerdown=${this.keepInputFocused}\r\n @click=${(e: Event) => {\r\n e.stopPropagation();\r\n this.incrementValue();\r\n }}\r\n aria-label=\"Increase value\"\r\n >\r\n <sky-icon icon=\"ion:add\"></sky-icon>\r\n </button>\r\n </div>\r\n `\r\n : null;\r\n\r\n const PasswordToggle = () =>\r\n isPassword && this.showPasswordToggle\r\n ? html`\r\n <sky-icon\r\n class=\"toggle-password\"\r\n part=\"toggle-password\"\r\n ?compact=${this.compact}\r\n icon=${this.showPassword\r\n ? this.passwordVisibleIcon\r\n : this.passwordHiddenIcon}\r\n @click=${this.togglePasswordVisibility}\r\n ></sky-icon>\r\n `\r\n : null;\r\n\r\n const ClearButton = () =>\r\n this.clearable &&\r\n (this.value || this.selectedFileName || this.selectedFileCount > 0)\r\n ? html`\r\n <sky-icon\r\n class=\"clear-button\"\r\n part=\"clear-button\"\r\n ?compact=${this.compact}\r\n @click=${this.handleClear}\r\n ?loading=${this.loading}\r\n icon=\"ion:close\"\r\n ></sky-icon>\r\n `\r\n : null;\r\n\r\n const FileInfo = () =>\r\n isFileInput && this.totalFileSize\r\n ? html`\r\n <div class=\"file-info\" part=\"file-info\">\r\n <span>\r\n ${this.selectedFileCount}\r\n file${this.selectedFileCount !== 1 ? \"s selected\" : \" selected\"} </span\r\n >,\r\n <span>${this.formatFileSize(this.totalFileSize)}</span>\r\n </div>\r\n `\r\n : null;\r\n\r\n const Control = () =>\r\n isFileInput\r\n ? FileControl()\r\n : isTextarea\r\n ? TextareaControl()\r\n : TextInputControl();\r\n\r\n return html`\r\n <div\r\n class=\"input-container\"\r\n @click=${this.handleWrapperClick}\r\n part=\"input-container\"\r\n >\r\n ${this.label\r\n ? html`<div class=\"label\" part=\"label\">${this.label}</div>`\r\n : null}\r\n <div\r\n class=\"input-wrapper\"\r\n part=\"input-wrapper\"\r\n ?compact=${this.compact}\r\n ?loading=${this.loading}\r\n >\r\n ${LeftIconSlot()}\r\n ${supportsInlineAffixes ? this.renderInputAffix(\"prefix\") : nothing}\r\n ${Control()}\r\n ${supportsInlineAffixes ? this.renderInputAffix(\"suffix\") : nothing}\r\n ${NumberButtons()} ${PasswordToggle()}\r\n ${ClearButton()} ${RightIconSlot()}\r\n </div>\r\n\r\n ${FileInfo()} ${this.renderValidationErrors()}\r\n </div>\r\n `;\r\n }\r\n}\r\n"],"names":["SkyInput","FormControlBase","constructor","super","arguments","this","value","placeholder","label","type","suffix","prefix","prefixColor","suffixColor","color","_validations","compact","loading","showErrors","clearable","errorDisplayMode","required","step","min","max","autocapitalize","autocomplete","spellcheck","dir","rows","resizable","accept","multiple","inputmode","enterkeyhint","pattern","minlength","maxlength","list","size","cols","autofocus","capture","inputRole","ariaLabel","ariaLabelledby","ariaDescribedby","showNumberButtons","showPasswordToggle","passwordVisibleIcon","passwordHiddenIcon","validationActive","invalid","variant","selectedFileName","selectedFiles","focused","validationStatus","validationErrors","typingStarted","autofillIconSlot","autofillGuardActive","showPassword","totalFileSize","selectedFileCount","filePreview","_leftIconSlot","_rightIconSlot","_iconClickWired","WeakSet","_onLeftIconSlotChange","_wireIconSlot","_onRightIconSlotChange","keepInputFocused","e","preventDefault","stopPropagation","refocusInput","validations","old","Array","isArray","requestUpdate","connectedCallback","hasAttribute","tabIndex","disabled","hasUpdated","_setupIconSlots","disconnectedCallback","removeEventListener","shadowRoot","querySelector","addEventListener","side","slot","node","assignedElements","flatten","HTMLElement","has","add","handleIconClick","firstUpdated","_changedProperties","captureDefaultValue","syncFormValue","syncValidity","willUpdate","changedProperties","map","String","trim","updated","style","setProperty","resolveColor","inputWrapper","inputWrapperEl","getFormValue","name","length","fd","FormData","f","append","setValueFromFormState","state","getValidityAnchor","isEmpty","toString","getCustomErrorMessage","join","getNativeControl","onNativeValueMutated","native","validateInput","reset","nativeRequiredMessage","requiredMessage","getEmittedValue","n","Number","isFinite","handleClear","readonly","dispatchEvent","CustomEvent","detail","bubbles","composed","handleFileChange","event","files","target","fileList","from","file","totalSize","reduce","total","startsWith","reader","FileReader","onload","result","readAsDataURL","reemitNativeEvent","fileName","fileCount","handleKeydown","key","triggerNativeDropdown","preview","handleInput","handleFocus","releaseAutofillGuard","handleAutofillGuardPointerDown","onFormReset","defaultValue","handleBlur","validateForForm","payload","v","r","isFileInput","validation","index","Error","push","error","message","errors","isValid","getErrorMessages","slice","position","eventType","eventData","formatFileSize","bytes","i","Math","floor","log","parseFloat","pow","toFixed","incrementValue","currentValue","Infinity","decrementValue","renderValidationErrors","requiredMsg","customMsgs","msgs","errId","id","html","m","togglePasswordVisibility","focusInput","input","nativeInputEl","focus","handleWrapperClick","isInvalid","matches","describedById","el","preventScroll","click","showPicker","isFilterSearchInput","nativeAutocomplete","nativeTextInputType","isPassword","nativeInputMode","nativeEnterKeyHint","nativeInputRole","affixColorStyle","trimmed","renderInputAffix","kind","nothing","styleMap","render","isTextarea","isNumberInput","supportsInlineAffixes","hasLeftSlot","hasRightSlot","autoIcon","showFilePreview","showAutoIconInLeft","showAutoIconInRight","ImagePreview","ifDefined","FileControl","Boolean","TextareaControl","live","TextInputControl","LeftIconSlot","NumberButtons","PasswordToggle","ClearButton","RightIconSlot","FileInfo","dependencies","SkyIcon","styles","css","shadowRootOptions","LitElement","delegatesFocus","__decorateClass","property","prototype","reflect","query","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"sky-input.js","sources":["../../src/sky-input/sky-input.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\nimport { ifDefined } from \"lit/directives/if-defined.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { customElement, property, query, state } from \"lit/decorators.js\";\nimport { resolveColor } from \"../helper/utils/color-resolver\";\nimport { live } from \"lit/directives/live.js\";\nimport { FormControlBase } from \"../helper/internals/form-control-base\";\nimport { SkyIcon } from \"../sky-icon/sky-icon.js\";\n\nexport type SkyInputValue = string | number | File[] | null;\nexport type SkyInputType = string;\nexport type SkyInputErrorDisplayMode = \"none\" | \"single\" | \"all\";\nexport type SkyInputIconPosition = \"left\" | \"right\";\nexport type SkyInputValidation = (value: string | File[]) => true | string;\nexport type SkyInputValueChangedDetail = { value: string | number };\nexport type SkyInputValueClearedDetail = { value: string | number };\nexport type SkyInputFileSelectedDetail = {\n files: File[];\n fileName: string;\n totalSize: number;\n fileCount: number;\n};\nexport type SkyInputValidationErrorDetail = { errors: string[] };\nexport type SkyInputIconClickDetail = {\n position: SkyInputIconPosition;\n eventType: string | null;\n eventData: Event | null;\n};\n\n/**\n * @element sky-input\n *\n * @summary Versatile form input supporting text, password, number, textarea, and file workflows.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://library.sky-ui.com/components/input\n * @dependency sky-icon\n *\n * @uiVModel value value-changed\n *\n * @slot icon-left - Optional icon/content placed in the left slot.\n * @slot icon-right - Optional icon/content placed in the right slot.\n * @property {SkyInputValue} value - Current input value.\n * @property {string} placeholder - Placeholder text.\n * @property {string} label - Label text shown above the input.\n * @property {SkyInputType} type - Input type (`text`, `password`, `number`, `textarea`, `file`, etc.).\n * @property {string} suffix - Optional suffix label fragment.\n * @property {string} prefix - Optional prefix label fragment.\n * @property {string} prefixColor - Prefix color override.\n * @property {string} suffixColor - Suffix color override.\n * @property {string} color - Accent color token/value.\n * @property {SkyInputValidation[]} validations - Validation functions.\n * @property {boolean} compact - Compact display mode.\n * @property {boolean} loading - Loading state.\n * @property {boolean} showErrors - Enables error rendering.\n * @property {boolean} clearable - Enables clear button.\n * @property {SkyInputErrorDisplayMode} errorDisplayMode - Error rendering mode.\n * @property {boolean} showNumberButtons - Enables number increment/decrement controls.\n * @property {boolean} showPasswordToggle - Enables password visibility toggle.\n * @property {string} passwordVisibleIcon - Icon used when password is visible.\n * @property {string} passwordHiddenIcon - Icon used when password is hidden.\n *\n * @fires {CustomEvent<SkyInputValueChangedDetail>} value-changed - Fired when value changes.\n * @fires {CustomEvent<SkyInputValueClearedDetail>} value-cleared - Fired after clear action.\n * @fires {CustomEvent<SkyInputFileSelectedDetail>} file-selected - Fired after file selection changes.\n * @fires {CustomEvent<SkyInputValidationErrorDetail>} validation-error - Fired after validations run.\n * @fires {CustomEvent<SkyInputIconClickDetail>} left-icon-click - Fired when left icon slot is clicked.\n * @fires {CustomEvent<SkyInputIconClickDetail>} right-icon-click - Fired when right icon slot is clicked.\n *\n * @method validateInput Runs configured validations and updates invalid state.\n * @method handleClear Clears value and emits corresponding events.\n * @method formatFileSize Formats byte size for UI display.\n * @method focusInput Focuses the underlying native input or textarea.\n *\n * @csspart input-container - The outer container wrapping label and input wrapper.\n * @csspart label - The label element above the input.\n * @csspart input-wrapper - The wrapper around input/textarea and icons.\n * @csspart icon-slot - Base class for left/right icon slots.\n * @csspart icon-slot-left - Left icon slot.\n * @csspart icon-slot-right - Right icon slot.\n * @csspart clear-button - The clear/reset button.\n * @csspart toggle-password - The toggle icon for password visibility.\n * @csspart loading-indicator - The spinner shown when loading.\n * @csspart error-list - UL element containing validation errors.\n * @csspart error - Individual error message.\n * @csspart file-info - File count and size info below the file input.\n * @csspart input-prefix - Inline prefix fragment inside the field.\n * @csspart input-suffix - Inline suffix fragment inside the field.\n *\n * @Behavior\n * - Extends `FormControlBase` for automatic form association and validation integration\n * - Supports all standard HTML input types with enhanced styling and functionality\n * - File inputs with multi-file support, preview, and size tracking\n * - Automatic validation integration with parent forms via `sky-form`\n *\n * - **none**: No error messages displayed\n * - **single**: Show only the first error message\n * - **all**: Show all validation error messages\n *\n * @example\n * ```html\n * <sky-input\n * label=\"Password\"\n * type=\"password\"\n * placeholder=\"Enter your password\"\n * clearable\n * show-password-toggle\n * required\n * >\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\n * </sky-input>\n * ```\n * ```vue\n * <template>\n * <sky-input label=\"Password\" type=\"password\" clearable show-password-toggle required>\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\n * </sky-input>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return (\n * <sky-input label=\"Password\" type=\"password\" clearable show-password-toggle required>\n * <sky-icon slot=\"icon-left\" icon=\"ion:lock-closed\"></sky-icon>\n * </sky-input>\n * );\n * }\n * ```\n */\n@customElement(\"sky-input\")\nexport class SkyInput extends FormControlBase {\n\n static dependencies: Record<string, CustomElementConstructor> = {\n \"sky-icon\": SkyIcon,\n };\n\n // ============================================================\n // ✅ PUBLIC PROPERTIES (user-configurable)\n // ============================================================\n\n @property({ type: String }) value: SkyInputValue = \"\";\n @property({ type: String }) placeholder = \"\";\n @property({ type: String }) label = \"\";\n @property({ type: String }) type: SkyInputType = \"text\";\n @property({ type: String }) suffix = \"\";\n @property({ type: String }) prefix = \"\";\n @property({ type: String }) prefixColor = \"\";\n @property({ type: String }) suffixColor = \"\";\n @property({ type: String }) color = \"primary\";\n private _validations: SkyInputValidation[] = [];\n @property({ type: Array })\n get validations(): SkyInputValidation[] {\n return this._validations;\n }\n set validations(value: SkyInputValidation[] | null | undefined) {\n const old = this._validations;\n this._validations = Array.isArray(value) ? value : [];\n this.requestUpdate(\"validations\", old);\n }\n @property({ type: Boolean, reflect: true }) compact = false;\n @property({ type: Boolean, reflect: true }) loading = false;\n @property({ type: Boolean }) showErrors = false;\n @property({ type: Boolean, reflect: true }) clearable = false;\n @property({ type: String }) errorDisplayMode: SkyInputErrorDisplayMode = \"single\";\n @property({ type: Boolean, reflect: true }) override required = false;\n @property({ type: String }) step: string | null = null;\n @property({ type: String }) min: string | null = null;\n @property({ type: String }) max: string | null = null;\n @property({ type: String }) override autocapitalize = \"off\";\n @property({ type: String }) autocomplete = \"off\";\n @property({ type: Boolean }) override spellcheck = false;\n @property({ type: String }) override dir = \"ltr\";\n @property({ type: Number }) rows = 6;\n @property({ type: String }) resizable = \"none\";\n @property({ type: String }) accept = \"\";\n @property({ type: Boolean }) multiple = false;\n @property({ type: String }) inputmode: string | null = null;\n @property({ type: String }) enterkeyhint: string | null = null;\n @property({ type: String }) pattern: string | null = null;\n @property({ type: Number }) minlength: number | null = null;\n @property({ type: Number }) maxlength: number | null = null;\n @property({ type: String }) list: string | null = null;\n @property({ type: Number }) size: number | null = null;\n @property({ type: Number }) cols: number | null = null;\n @property({ type: Boolean }) autofocus = false;\n @property({ type: Boolean }) capture = false;\n @property({ type: String }) inputRole: string | null = null;\n @property({ type: String }) ariaLabel: string | null = null;\n @property({ type: String }) ariaLabelledby: string | null = null;\n @property({ type: String }) ariaDescribedby: string | null = null;\n @property({ type: Boolean }) showNumberButtons = false;\n @property({ type: Boolean }) showPasswordToggle = true;\n @property({ type: String }) passwordVisibleIcon = \"material-symbols:visibility-off\";\n @property({ type: String }) passwordHiddenIcon = \"material-symbols:visibility\";\n @property({ type: Boolean, reflect: true }) validationActive = false;\n @property({ type: Boolean, reflect: true }) invalid = false;\n @property({ type: String, reflect: true }) variant = 'default';\n\n // ============================================================\n // ✅ INTERNAL STATE (read-only, managed by component)\n // ============================================================\n\n @state() private selectedFileName = \"\";\n @state() private selectedFiles: File[] = [];\n @state() private focused = false;\n @state() private validationStatus: boolean[] = [];\n @state() private validationErrors: string[] = [];\n @state() private typingStarted = false;\n @state() private autofillIconSlot = \"left\";\n @state() private autofillGuardActive = false;\n @state() private showPassword = false;\n @state() private totalFileSize = 0;\n @state() private selectedFileCount = 0;\n @state() private filePreview: string | ArrayBuffer | null = null;\n\n // ============================================================\n // ✅ PRIVATE FIELDS (internal, not reactive)\n // ============================================================\n\n @query(\".input-wrapper\") private inputWrapperEl!: HTMLElement;\n @query(\"input, textarea\") private nativeInputEl!:\n | HTMLInputElement\n | HTMLTextAreaElement;\n\n private _leftIconSlot: HTMLSlotElement | null = null;\n private _rightIconSlot: HTMLSlotElement | null = null;\n private _iconClickWired = new WeakSet<HTMLElement>();\n private _onLeftIconSlotChange = () =>\n this._wireIconSlot(\"left\", this._leftIconSlot);\n private _onRightIconSlotChange = () =>\n this._wireIconSlot(\"right\", this._rightIconSlot);\n\n static override styles = css`\n :host {\n display: block;\n font-family: var(--sky-font);\n width: 100%;\n }\n\n :host([disabled]) .input-container {\n opacity: var(--sky-opacity-disabled, 0.6);\n }\n :host([disabled]) * {\n pointer-events: none;\n }\n\n :host([variant=\"highlight\"]){\n .label{\n color: var(--sky-input-color);\n }\n }\n\n .input-container {\n position: relative;\n display: flex;\n flex-direction: column;\n width: inherit;\n cursor: text;\n }\n\n sky-icon {\n display: inline-block;\n width: 1em;\n height: 1em;\n }\n\n .input-container:focus-within .label {\n color: var(--sky-input-color);\n font-size: var(--sky-font-size-sm);\n transition: all 0.3s ease;\n }\n .label {\n font-size: var(--sky-font-size-sm);\n margin-bottom: var(--sky-space-1, 4px);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: var(--sky-font);\n }\n\n .input-container:focus-within[compact] .label {\n font-size: var(--sky-font-size-xs);\n color: var(--sky-input-color);\n }\n\n .input-wrapper {\n position: relative;\n display: flex;\n width: 100%;\n align-items: center;\n box-sizing: border-box;\n height: 38px;\n pointer-events: auto;\n background: var(--sky-glass-solid);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n border-radius: var(--sky-radius-secondary);\n border: var(--sky-border-primary);\n box-shadow: var(--sky-box-shadow-primary);\n transition:\n border-color var(--sky-transition-normal, 200ms ease),\n box-shadow var(--sky-transition-normal, 200ms ease);\n }\n\n .input-wrapper::after {\n content: \"\";\n position: absolute;\n top: -1px;\n left: -1px;\n right: -1px;\n bottom: -1px;\n border-radius: inherit;\n border: 1px solid transparent;\n border-bottom-color: transparent;\n opacity: 0;\n transition:\n opacity 0.3s ease,\n border-color 0.3s ease;\n pointer-events: none;\n }\n\n .input-wrapper:has(input:focus-visible)::after,\n .input-wrapper:has(textarea:focus-visible)::after {\n opacity: 1;\n border-bottom-color: var(--sky-input-color);\n }\n\n .input-wrapper:has(input:focus)::after,\n .input-wrapper:has(textarea:focus)::after {\n opacity: 1;\n border-bottom-color: var(--sky-input-color);\n }\n\n :host([validationActive]:invalid) .input-wrapper::after {\n opacity: 1;\n border-bottom-color: var(--sky-danger-primary);\n }\n :host([validationActive]:invalid) .label {\n color: var(--sky-danger-primary);\n }\n\n :host([validationActive]:invalid) .icon-slot {\n color: var(--sky-danger-primary);\n }\n\n .input-wrapper[compact] {\n height: 30px;\n border: var(--sky-border-primary);\n }\n\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"week\"],\n input[type=\"month\"],\n input[type=\"datetime-local\"] {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background: none;\n border: none;\n font-family: inherit;\n }\n\n input[type=\"date\"]::-webkit-calendar-picker-indicator,\n input[type=\"time\"]::-webkit-calendar-picker-indicator,\n input[type=\"week\"]::-webkit-calendar-picker-indicator,\n input[type=\"month\"]::-webkit-calendar-picker-indicator,\n input[type=\"datetime-local\"]::-webkit-calendar-picker-indicator {\n display: none;\n }\n\n .input-wrapper:has(input:focus)[compact]::after {\n border: 1px solid var(--sky-input-color);\n }\n\n .toggle-password[compact] {\n font-size: var(--sky-font-size-md);\n }\n\n input {\n font-family: var(--sky-font);\n font-size: var(--sky-font-size-md);\n text-align: left;\n transition: transform var(--sky-transition-normal, 200ms ease);\n }\n\n input:-webkit-autofill {\n -webkit-text-fill-color: var(--sky-text-secondary, inherit) !important;\n transition: background-color 9999s ease-in-out 0s !important;\n }\n\n :dir(rtl) input {\n text-align: right;\n }\n\n input[type=\"number\"] {\n appearance: textfield;\n -moz-appearance: textfield;\n }\n\n input[type=\"number\"]::-webkit-inner-spin-button,\n input[type=\"number\"]::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n .number-btn {\n display: flex;\n flex-shrink: 0;\n margin-inline-end: var(--sky-space-1, 4px);\n gap: var(--sky-space-1, 4px);\n }\n\n :dir(rtl).number-btn {\n margin-inline-end: var(--sky-space-1, 4px);\n }\n\n .file-info {\n display: flex;\n justify-content: flex-end;\n font-size: var(--sky-font-size-xs);\n color: var(--sky-text-secondary);\n font-family: var(--sky-font);\n }\n\n :dir(rtl).file-info {\n flex-direction: row-reverse;\n }\n\n .increment-btn,\n .decrement-btn {\n background: var(--sky-glass-solid);\n color: var(--sky-text-primary);\n border: var(--sky-border-primary);\n border-radius: var(--sky-radius-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--sky-space-0\\\\.5, 2px) var(--sky-space-1\\\\.5, 6px);\n font-size: var(--sky-font-size-sm);\n cursor: pointer;\n transition: color var(--sky-transition-normal, 200ms ease);\n font-family: var(--sky-font);\n }\n\n .increment-btn:hover,\n .decrement-btn:hover {\n color: var(--sky-input-color);\n }\n\n .toggle-password {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-inline-end: var(--sky-space-1, 4px);\n font-size: var(--sky-font-size-lg);\n color: var(--sky-text-tertiary);\n cursor: pointer;\n }\n\n .toggle-password:hover {\n color: var(--sky-input-color);\n }\n\n input {\n flex: 1 1 auto;\n min-width: 0;\n border: none;\n outline: none;\n background: transparent;\n box-sizing: border-box;\n color: var(--sky-text-primary);\n padding-block: 0;\n padding-inline: var(--sky-space-3, 12px);\n }\n\n input::placeholder {\n color: var(--sky-text-tertiary);\n }\n\n .input-affix {\n flex: 0 0 auto;\n font-family: var(--sky-font);\n font-size: var(--sky-font-size-md);\n font-weight: var(--sky-font-weight-medium);\n color: var(--sky-text-secondary);\n user-select: none;\n white-space: nowrap;\n line-height: 1;\n }\n\n .input-affix.prefix {\n padding-inline-start: var(--sky-space-3, 12px);\n padding-inline-end: var(--sky-space-1, 4px);\n }\n\n .input-affix.suffix {\n padding-inline-start: var(--sky-space-1, 4px);\n padding-inline-end: var(--sky-space-2, 8px);\n }\n\n .input-wrapper[compact] .input-affix {\n font-size: var(--sky-font-size-sm);\n }\n\n .input-wrapper:has(.input-affix.prefix) input,\n .input-wrapper:has(.input-affix.prefix) textarea {\n padding-inline-start: var(--sky-space-1, 4px);\n }\n\n .input-wrapper:has(.icon-slot[filled].left) input,\n .input-wrapper:has(.icon-slot[filled].left) textarea {\n padding-inline-start: var(--sky-space-1, 4px);\n }\n\n .custom-file-label__text {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--sky-text-tertiary);\n padding-inline-end: var(--sky-space-3, 12px);\n }\n\n .custom-file-label:not(:has(.input-affix.prefix)) .custom-file-label__text {\n padding-inline-start: var(--sky-space-3, 12px);\n }\n\n .custom-file-label__text[data-filled] {\n color: var(--sky-text-primary);\n }\n\n .icon-slot {\n display: none;\n justify-content: center;\n font-size: var(--sky-font-size-xl);\n align-items: center;\n color: var(--sky-text-primary);\n border-radius: var(--sky-radius-secondary);\n height: inherit;\n max-height: 100%;\n box-sizing: border-box;\n min-width: 36px;\n background: var(--sky-glass-solid);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n transition:\n transform var(--sky-transition-normal, 200ms ease),\n color var(--sky-transition-normal, 200ms ease);\n }\n\n .input-wrapper:has(textarea) .icon-slot {\n max-height: 38px;\n border-bottom: var(--sky-border-primary);\n }\n\n .icon-slot[filled] {\n display: flex;\n flex-shrink: 0;\n cursor: pointer;\n }\n .icon-slot[filled]:hover {\n transform: translate(-5px, -5px);\n color: var(--sky-input-color);\n }\n .icon-slot.right[filled]:hover {\n transform: translate(5px, -5px);\n color: var(--sky-input-color);\n }\n\n .icon-slot.focused {\n transform: translate(-5px, -5px);\n color: var(--sky-input-color);\n border: var(--sky-border-primary) !important;\n }\n\n :dir(rtl) .icon-slot[filled]:hover {\n transform: translate(5px, -5px);\n }\n\n :dir(rtl) .icon-slot.right[filled]:hover {\n transform: translate(-5px, -5px);\n }\n\n :dir(rtl) .icon-slot.focused {\n transform: translate(5px, -5px);\n }\n\n .icon-slot.right {\n border-left: var(--sky-border-primary);\n }\n .icon-slot.left {\n border-right: var(--sky-border-primary);\n }\n\n :dir(rtl) .icon-slot.right {\n border-left: unset;\n border-right: var(--sky-border-primary);\n }\n :dir(rtl) .icon-slot.left {\n border-right: unset;\n border-left: var(--sky-border-primary);\n }\n\n .icon-slot.right.focused {\n transform: translate(5px, -5px);\n }\n\n :dir(rtl) .icon-slot.right.focused {\n transform: translate(-5px, -5px);\n }\n\n .progress-message {\n pointer-events: none;\n width: 100%;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: var(--sky-font-size-sm);\n margin-left: 5px;\n font-family: var(--sky-font);\n }\n\n :dir(rtl) .progress-message {\n margin-left: unset;\n margin-right: 5px;\n }\n\n .error-list {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n }\n\n .error {\n font-size: var(--sky-font-size-xs);\n color: var(--sky-danger-primary);\n text-align: start;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: var(--sky-font);\n }\n\n ::slotted(.icon-slot) {\n display: block;\n }\n\n .input-wrapper[loading] input {\n cursor: wait;\n }\n\n .loading-indicator {\n flex-shrink: 0;\n margin-inline-end: var(--sky-space-1, 4px);\n width: 16px;\n height: 16px;\n border: 2px solid var(--sky-hover-primary);\n border-top: 2px solid var(--sky-input-color);\n border-radius: var(--sky-radius-full);\n animation: spin 1s linear infinite;\n }\n\n .loading-indicator[compact] {\n width: 10px;\n height: 10px;\n }\n\n .input-wrapper[loading] .icon-slot.right {\n display: none;\n }\n\n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n .clear-button {\n flex-shrink: 0;\n margin-inline-end: var(--sky-space-1, 4px);\n border: none;\n font-size: var(--sky-font-size-xl);\n color: var(--sky-input-color);\n background-color: var(--sky-hover-primary);\n border-radius: var(--sky-radius-full);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n cursor: pointer;\n transition: color var(--sky-transition-normal, 200ms ease);\n }\n\n .clear-button[compact] {\n font-size: var(--sky-font-size-md);\n }\n\n .clear-button[loading] {\n opacity: 0.6;\n pointer-events: none;\n }\n\n input[type=\"file\"] {\n position: absolute;\n width: 100%;\n height: 100%;\n opacity: 0;\n pointer-events: auto;\n z-index: -1;\n }\n\n .custom-file-label {\n position: relative;\n flex: 1;\n display: flex;\n align-items: center;\n gap: var(--sky-space-1, 4px);\n text-align: left;\n padding: 0;\n color: var(--sky-input-color);\n border-radius: var(--sky-radius-secondary);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n cursor: pointer;\n transition:\n background 0.3s ease,\n padding 0.3s ease;\n font-family: var(--sky-font);\n }\n\n .custom-file-label:hover .custom-file-label__text {\n padding-inline-start: var(--sky-space-2\\\\.5, 10px);\n }\n\n .custom-file-label:empty::after {\n content: \"Choose file\";\n color: var(--sky-input-color);\n }\n\n .clear-button:hover {\n color: var(--sky-danger-primary);\n }\n\n textarea {\n flex: 1 1 auto;\n min-width: 0;\n border: none;\n outline: none;\n background: transparent;\n box-sizing: border-box;\n color: var(--sky-text-primary);\n padding: var(--sky-space-2\\\\.5, 10px) var(--sky-space-3, 12px);\n resize: none;\n overflow: auto;\n font-family: var(--sky-font);\n }\n\n textarea[resizable=\"vertical\"] {\n resize: vertical;\n }\n\n textarea[resizable=\"both\"] {\n resize: both;\n }\n\n textarea {\n scrollbar-width: thin;\n scrollbar-color: var(--sky-scrollbar-thumb) var(--sky-scrollbar-track);\n }\n\n textarea::-webkit-scrollbar {\n width: 6px;\n height: 6px;\n }\n\n textarea::-webkit-scrollbar-thumb {\n background-color: var(--sky-scrollbar-thumb);\n border-radius: var(--sky-radius-full, 9999px);\n transition: background-color var(--sky-duration-normal, 200ms)\n var(--sky-ease-default, ease);\n cursor: grab;\n }\n\n textarea::-webkit-scrollbar-thumb:hover {\n background-color: var(--sky-scrollbar-thumb-hover);\n }\n\n textarea::-webkit-scrollbar-track {\n background: var(--sky-scrollbar-track);\n }\n\n textarea::-webkit-scrollbar-button {\n display: none;\n }\n\n textarea::placeholder {\n color: var(--sky-text-tertiary);\n }\n\n .input-wrapper:has(textarea) {\n height: calc((var(--rows)) * 23px);\n align-items: flex-start;\n }\n textarea {\n height: calc((var(--rows)) * 23px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .loading-indicator {\n animation: none;\n }\n\n .input-container:focus-within .label,\n .input-wrapper,\n .icon-slot,\n .increment-btn,\n .decrement-btn,\n .clear-button,\n input,\n textarea,\n .custom-file-label {\n transition: none;\n }\n }\n `;\n\n static override shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.autofillGuardActive = this.type === \"search\";\n\n // Make the host focusable\n if (!this.hasAttribute(\"tabindex\")) {\n this.tabIndex = this.disabled ? -1 : 0;\n }\n\n if (this.hasUpdated) {\n this._setupIconSlots();\n }\n }\n\n override disconnectedCallback(): void {\n this._leftIconSlot?.removeEventListener(\n \"slotchange\",\n this._onLeftIconSlotChange,\n );\n this._rightIconSlot?.removeEventListener(\n \"slotchange\",\n this._onRightIconSlotChange,\n );\n this._leftIconSlot = null;\n this._rightIconSlot = null;\n super.disconnectedCallback();\n }\n\n private _setupIconSlots(): void {\n if (!this._leftIconSlot) {\n this._leftIconSlot =\n this.shadowRoot?.querySelector<HTMLSlotElement>(\n 'slot[name=\"icon-left\"]',\n ) ?? null;\n this._leftIconSlot?.addEventListener(\n \"slotchange\",\n this._onLeftIconSlotChange,\n );\n }\n if (!this._rightIconSlot) {\n this._rightIconSlot =\n this.shadowRoot?.querySelector<HTMLSlotElement>(\n 'slot[name=\"icon-right\"]',\n ) ?? null;\n this._rightIconSlot?.addEventListener(\n \"slotchange\",\n this._onRightIconSlotChange,\n );\n }\n this._wireIconSlot(\"left\", this._leftIconSlot);\n this._wireIconSlot(\"right\", this._rightIconSlot);\n }\n\n private _wireIconSlot(\n side: \"left\" | \"right\",\n slot: HTMLSlotElement | null,\n ): void {\n if (!slot) return;\n for (const node of slot.assignedElements({ flatten: true })) {\n if (!(node instanceof HTMLElement)) continue;\n if (this._iconClickWired.has(node)) continue;\n this._iconClickWired.add(node);\n node.addEventListener(\"click\", () => this.handleIconClick(side));\n }\n }\n\n override firstUpdated(\n _changedProperties: Map<string | number | symbol, unknown>,\n ) {\n super.firstUpdated(_changedProperties);\n\n // default/reset value\n this.captureDefaultValue(this.value as string);\n\n // initial sync into form\n this.syncFormValue();\n this.syncValidity();\n\n this._setupIconSlots();\n }\n\n override willUpdate(\n changedProperties: Map<string | number | symbol, unknown>,\n ) {\n if (\n changedProperties.has(\"validations\") &&\n Array.isArray(this.validations)\n ) {\n this.validationStatus = this.validations.map(() => false);\n }\n\n if (changedProperties.has(\"value\") && this.type === \"file\") {\n if (this.value == null || String(this.value).trim() === \"\") {\n this.selectedFileName = \"\";\n this.selectedFiles = [];\n this.totalFileSize = 0;\n this.selectedFileCount = 0;\n this.filePreview = null;\n } else if (!this.selectedFileName) {\n this.selectedFileName = this.value as string;\n }\n }\n if (changedProperties.has(\"type\") && this.type === \"search\") {\n this.autofillGuardActive = true;\n }\n }\n\n override updated(changedProperties: Map<string | number | symbol, unknown>) {\n super.updated(changedProperties);\n\n if (changedProperties.has(\"color\") && this.color) {\n this.style.setProperty(\"--sky-input-color\", resolveColor(this.color));\n }\n\n if (changedProperties.has(\"rows\")) {\n const inputWrapper = this.inputWrapperEl;\n if (inputWrapper) {\n inputWrapper.style.setProperty(\"--rows\", String(this.rows));\n }\n }\n\n if (\n changedProperties.has(\"value\") ||\n changedProperties.has(\"selectedFiles\") ||\n changedProperties.has(\"selectedFileName\") ||\n changedProperties.has(\"type\") ||\n changedProperties.has(\"multiple\") ||\n changedProperties.has(\"name\") ||\n changedProperties.has(\"disabled\")\n ) {\n this.syncFormValue();\n }\n\n if (\n changedProperties.has(\"value\") ||\n changedProperties.has(\"selectedFiles\") ||\n changedProperties.has(\"selectedFileName\") ||\n changedProperties.has(\"validationErrors\") ||\n changedProperties.has(\"required\") ||\n changedProperties.has(\"disabled\") ||\n changedProperties.has(\"readonly\")\n ) {\n this.syncValidity();\n }\n }\n\n /** @protected */\n protected override getFormValue(): string | File | FormData | null {\n if (!this.name) return null;\n\n if (this.type === \"file\") {\n if (!this.selectedFiles || this.selectedFiles.length === 0) return null;\n\n if (this.multiple) {\n const fd = new FormData();\n for (const f of this.selectedFiles) fd.append(this.name, f);\n return fd;\n }\n return this.selectedFiles[0];\n }\n\n return this.value as string ?? \"\";\n }\n\n /** @protected */\n protected override setValueFromFormState(\n state: string | File | FormData | null,\n ) {\n // For SkyInput, state restore is typically string\n if (typeof state === \"string\") {\n this.value = state;\n // for textarea/input UI to refresh, you already use live()\n return;\n }\n\n // For file state restore: browsers usually won't restore actual File objects for security.\n // So do a safe reset:\n this.value = \"\";\n this.selectedFileName = \"\";\n this.selectedFiles = [];\n this.totalFileSize = 0;\n this.selectedFileCount = 0;\n this.filePreview = null;\n }\n\n /** @protected */\n protected override getValidityAnchor(): HTMLElement | undefined {\n return this;\n }\n\n /** @protected */\n protected override isEmpty(): boolean {\n if (this.type === \"file\") {\n return !this.selectedFiles || this.selectedFiles.length === 0;\n }\n return !this.value || this.value.toString().trim() === \"\";\n }\n\n /** @protected */\n protected override getCustomErrorMessage(): string {\n if (!this.validationErrors?.length) return \"\";\n\n // single message that includes all\n if (this.errorDisplayMode === \"all\") {\n return this.validationErrors.join(\"\\n\");\n }\n\n // single mode\n return this.validationErrors[0];\n }\n\n /** @protected */\n protected override getNativeControl(): HTMLElement | null {\n if (this.type === \"textarea\") {\n return this.shadowRoot?.querySelector(\n \"textarea\",\n ) as HTMLTextAreaElement | null;\n }\n // for all other types (text/email/password/date/...)\n return this.shadowRoot?.querySelector(\"input\") as HTMLInputElement | null;\n }\n\n /** @protected */\n protected override onNativeValueMutated(native: any): void {\n // IMPORTANT: file input is managed via change handler; don't trust setting native.value\n if (this.type !== \"file\") {\n this.value = native?.value ?? \"\";\n }\n // keep SkyInput custom validations in sync\n this.validateInput();\n }\n\n /**\n * Resets the input field to its initial state.\n * @public\n */\n reset() {\n this.value = \"\";\n this.selectedFileName = \"\";\n this.filePreview = null;\n this.selectedFiles = [];\n this.selectedFileCount = 0;\n this.validationErrors = [];\n this.typingStarted = false;\n this.validationActive = false;\n this.selectedFileCount = 0;\n this.totalFileSize = 0;\n }\n\n /** @private */\n private get nativeRequiredMessage(): string {\n if (!this.validationActive) return \"\";\n if (this.disabled) return \"\";\n if (this.required && this.isEmpty())\n return this.requiredMessage || \"This field is required.\";\n return \"\";\n }\n\n /** @private */\n private getEmittedValue(): string | number {\n if (this.type !== \"number\") return this.value as string;\n\n // allow empty to stay empty (important for clearing)\n if (this.value === \"\" || this.value == null) return \"\";\n\n const n = Number(this.value);\n // if user is still typing an invalid numeric token, keep as string\n return Number.isFinite(n) ? n : this.value as string;\n }\n\n /**\n * Clears the input value and resets typing state.\n * @public\n */\n handleClear() {\n if (this.disabled || this.readonly) {\n return;\n }\n this.reset();\n this.validationActive = true;\n this.validateInput();\n this.dispatchEvent(\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\n detail: { value: this.getEmittedValue() },\n bubbles: true,\n composed: true,\n }),\n );\n this.dispatchEvent(\n new CustomEvent<SkyInputValueClearedDetail>(\"value-cleared\", {\n detail: { value: this.getEmittedValue() },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Handles the `change` event triggered by the file input element.\n * @param {Event} event - The event object generated by the file input element when files are selected.\n * @public\n */\n handleFileChange(event: Event): void {\n if (this.disabled || this.readonly) {\n return;\n }\n const input = event.target as HTMLInputElement;\n const files = input.files;\n\n if (files && files.length) {\n const fileList: File[] = Array.from(files);\n this.selectedFiles = fileList;\n this.selectedFileName = fileList\n .map((file: File) => file.name)\n .join(\", \");\n this.value = this.selectedFileName;\n\n this.syncFormValue();\n this.syncValidity();\n\n const totalSize: number = fileList.reduce(\n (total: number, file: File) => total + file.size,\n 0,\n );\n this.totalFileSize = totalSize;\n\n this.selectedFileCount = fileList.length;\n\n if (fileList[0].type.startsWith(\"image/\")) {\n const reader = new FileReader();\n reader.onload = (e: ProgressEvent<FileReader>) => {\n if (e.target) {\n this.filePreview = e.target.result;\n }\n };\n reader.readAsDataURL(fileList[0]);\n } else {\n this.filePreview = null;\n }\n\n this.reemitNativeEvent(\"change\", event);\n this.reemitNativeEvent(\"input\", event);\n\n this.dispatchEvent(\n new CustomEvent<SkyInputFileSelectedDetail>(\"file-selected\", {\n detail: {\n files: fileList,\n fileName: this.selectedFileName,\n totalSize,\n fileCount: this.selectedFileCount,\n },\n bubbles: true,\n composed: true,\n }),\n );\n\n this.validateInput();\n } else {\n this.value = \"\";\n this.filePreview = null;\n this.totalFileSize = 0;\n this.selectedFileCount = 0;\n this.selectedFiles = [];\n this.validateInput();\n }\n }\n\n /**\n * Handles the keydown event for the input component.\n * @param event - The keyboard event triggered by the user.\n * @private\n */\n private handleKeydown(event: KeyboardEvent) {\n if (this.disabled || this.readonly) {\n return;\n }\n if (event.key === \"Enter\" && this.type === \"file\") {\n event.preventDefault();\n event.stopPropagation();\n this.triggerNativeDropdown();\n }\n }\n\n /**\n * Gets the current file preview.\n * @returns The preview of the file, as stored in `filePreview`.\n * @public\n */\n get preview() {\n return this.filePreview;\n }\n\n /**\n * Handles the input event for the input field.\n * @param {Event} event - The input event triggered by user interaction.\n * @public\n */\n handleInput(event: Event) {\n event.stopPropagation();\n\n if (this.disabled || this.readonly) {\n event.preventDefault();\n return;\n }\n\n this.value = (event.target as HTMLInputElement | HTMLTextAreaElement).value;\n\n this.syncFormValue(); // ✅ IMPORTANT\n this.syncValidity(); // ✅ optional but good\n\n if (!this.typingStarted) this.typingStarted = true;\n\n this.validateInput();\n\n this.reemitNativeEvent(\"input\", event);\n\n this.dispatchEvent(\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\n detail: { value: this.getEmittedValue() },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Handles the focus event for the input field.\n * @public\n */\n handleFocus(event: Event) {\n event.stopPropagation();\n this.releaseAutofillGuard();\n this.focused = true;\n this.reemitNativeEvent(\"focus\", event);\n }\n\n /** Chrome may autofill saved usernames into filter fields; readonly until interaction blocks that. */\n private releaseAutofillGuard(): void {\n if (!this.autofillGuardActive) return;\n this.autofillGuardActive = false;\n }\n\n private handleAutofillGuardPointerDown(event: Event): void {\n this.releaseAutofillGuard();\n event.stopPropagation();\n }\n\n /** @protected */\n protected override onFormReset() {\n // restore default value (or blank)\n this.setValueFromFormState(this.defaultValue);\n\n // ✅ reset UI state\n this.validationActive = false;\n this.invalid = false;\n this.typingStarted = false;\n this.validationErrors = [];\n this.validationStatus = [];\n\n // If file:\n if (this.type === \"file\") {\n this.selectedFiles = [];\n this.selectedFileName = \"\";\n this.totalFileSize = 0;\n this.selectedFileCount = 0;\n this.filePreview = null;\n }\n\n if (this.type === \"search\") {\n this.autofillGuardActive = true;\n }\n }\n\n /**\n * Handles the blur event for the input field.\n * @public\n */\n handleBlur(event: Event) {\n event.stopPropagation();\n this.validationActive = true;\n this.focused = false;\n this.reemitNativeEvent(\"blur\", event);\n }\n\n /** @protected */\n protected override validateForForm(): string {\n // run your `this.validations` against current value even if validationActive is false\n const payload =\n this.type === \"file\" ? (this.selectedFiles ?? []) : (this.value ?? \"\");\n\n for (const v of this.validations ?? []) {\n const r = v(payload as string | File[]);\n if (r !== true) return typeof r === \"string\" ? r : \"Invalid value.\";\n }\n\n return \"\";\n }\n\n /**\n * Validates the input value against the configured validation rules.\n * @returns {boolean} True if validation passes, false otherwise.\n * @public\n */\n validateInput(): boolean {\n // reset\n this.validationErrors = [];\n this.validationStatus = [];\n\n const isFileInput = this.type === \"file\";\n const isEmpty = isFileInput\n ? !this.selectedFiles || this.selectedFiles.length === 0\n : !this.value || this.value.toString().trim() === \"\";\n\n // 1) If empty + required -> let SkyFormControlBase handle native required\n // (do NOT push required into validationErrors)\n if (this.required && isEmpty) {\n this.syncValidity(); // will set valueMissing\n }\n\n // 2) Run custom validations only if there is something to validate\n if (Array.isArray(this.validations) && this.validations.length) {\n const payload: string | File[] = isFileInput\n ? (this.selectedFiles ?? [])\n : (this.value as string ?? \"\");\n\n this.validationStatus = this.validations.map((validation, index) => {\n try {\n if (typeof validation !== \"function\") {\n throw new Error(`Validation at index ${index} must be a function.`);\n }\n\n const result = validation(payload);\n\n if (result !== true) {\n this.validationErrors.push(\n typeof result === \"string\"\n ? result\n : `Validation ${index} failed.`,\n );\n return false;\n }\n\n return true;\n } catch (error) {\n const message =\n typeof error === \"object\" && error !== null && \"message\" in error\n ? String((error as any).message)\n : typeof error === \"string\"\n ? error\n : \"Unknown error\";\n\n this.validationErrors.push(\n `Error in validation ${index}: ${message}`,\n );\n return false;\n }\n });\n }\n // 3) Dispatch event with all accumulated errors\n this.dispatchEvent(\n new CustomEvent<SkyInputValidationErrorDetail>(\"validation-error\", {\n detail: { errors: this.validationErrors },\n bubbles: true,\n composed: true,\n }),\n );\n\n this.syncValidity();\n\n const isValid = this.validationErrors.length === 0;\n this.invalid = !isValid;\n\n return isValid;\n }\n\n /**\n * Retrieves validation error messages based on the configured error display mode.\n * @returns {Array} - An array of error messages to display.\n * @private\n */\n private getErrorMessages() {\n switch (this.errorDisplayMode) {\n case \"single\":\n return this.validationErrors.slice(0, 1);\n case \"all\":\n return this.validationErrors;\n case \"none\":\n default:\n return [];\n }\n }\n\n /**\n * Handles click events for the left or right icon slots.\n * @param {String} position - The position of the icon (\"left\" or \"right\").\n * @param {Event|null} event - The original event triggered by the click (optional).\n * @public\n */\n handleIconClick(position: \"left\" | \"right\", event: Event | null = null) {\n this.dispatchEvent(\n new CustomEvent<SkyInputIconClickDetail>(`${position}-icon-click`, {\n detail: {\n position,\n eventType: event ? event.type : null,\n eventData: event,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Formats a file size in bytes into a human-readable string.\n * @param {number} bytes - The file size in bytes.\n * @returns {string} - The formatted file size string.\n * @public\n */\n formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 Bytes\";\n\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\", \"TB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n }\n\n /**\n * Increments the input value by the specified step, respecting min/max constraints.\n * @private\n */\n private incrementValue() {\n if (this.disabled || this.readonly) return;\n const currentValue = parseFloat(this.value as string) || 0;\n const step = parseFloat(this.step ?? \"\") || 1;\n const max = this.max ? parseFloat(this.max) : Infinity;\n\n if (currentValue + step <= max) {\n this.value = (currentValue + step).toString();\n this.validateInput();\n this.dispatchEvent(\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\n detail: { value: this.getEmittedValue() },\n }),\n );\n }\n this.refocusInput();\n }\n\n /**\n * Decrements the input value by the specified step, respecting min/max constraints.\n * @private\n */\n private decrementValue() {\n if (this.disabled || this.readonly) return;\n const currentValue = parseFloat(this.value as string) || 0;\n const step = parseFloat(this.step ?? \"\") || 1;\n const min = this.min ? parseFloat(this.min) : -Infinity;\n\n if (currentValue - step >= min) {\n this.value = (currentValue - step).toString();\n this.validateInput();\n this.dispatchEvent(\n new CustomEvent<SkyInputValueChangedDetail>(\"value-changed\", {\n detail: { value: this.getEmittedValue() },\n }),\n );\n }\n this.refocusInput();\n }\n\n /**\n * Renders validation error messages if applicable.\n * @returns {TemplateResult|null} - The rendered error messages or null.\n * @private\n */\n private renderValidationErrors() {\n\n if (!this.showErrors || !this.validationActive) return null;\n\n const requiredMsg = this.nativeRequiredMessage;\n const customMsgs = this.getErrorMessages(); // already respects errorDisplayMode for custom\n\n let msgs: string[] = [];\n\n if (this.errorDisplayMode === \"single\") {\n // ✅ single message overall: required wins, else first custom\n if (requiredMsg) msgs = [requiredMsg];\n else if (customMsgs.length) msgs = [customMsgs[0]];\n } else {\n // all/none behavior\n msgs = requiredMsg ? [requiredMsg, ...customMsgs] : customMsgs;\n }\n\n if (!msgs.length) return null;\n\n const errId = `${this.id || \"sky-input\"}-errors`;\n\n return html`\n <div class=\"progress-message\">\n <ul id=${errId} class=\"error-list\" part=\"error-list\">\n ${msgs.map((m) => html`<li class=\"error\" part=\"error\">${m}</li>`)}\n </ul>\n </div>\n `;\n }\n\n /**\n * Toggles the visibility of the password input.\n * @public\n */\n togglePasswordVisibility() {\n this.showPassword = !this.showPassword;\n }\n\n public focusInput(): void {\n const input = this.nativeInputEl;\n if (\n input &&\n typeof (input as HTMLInputElement | HTMLTextAreaElement).focus === \"function\"\n ) {\n (input as HTMLInputElement | HTMLTextAreaElement).focus();\n }\n }\n\n /**\n * Handles click events on the input wrapper.\n * @param {Event} event - The original click event.\n * @private\n */\n private handleWrapperClick(event: Event) {\n event.stopPropagation();\n if (this.disabled) return;\n const input = this.nativeInputEl;\n if (\n input &&\n typeof (input as HTMLInputElement | HTMLTextAreaElement).focus ===\n \"function\"\n ) {\n (input as HTMLInputElement | HTMLTextAreaElement).focus();\n }\n }\n\n /** @private */\n private get isInvalid(): boolean {\n return (\n this.matches(\":invalid\") ||\n (this.validationActive && this.validationErrors.length > 0)\n );\n }\n\n /** @private */\n private get describedById(): string | undefined {\n return (\n this.ariaDescribedby ??\n (this.showErrors ? `${this.id || \"sky-input\"}-errors` : undefined)\n );\n }\n\n /**\n * Refocuses the input element.\n * @private\n */\n private refocusInput() {\n const el = this.shadowRoot?.querySelector(\n \"input\",\n ) as HTMLInputElement | null;\n el?.focus({ preventScroll: true });\n }\n\n /**\n * Keeps the input focused when interacting with related controls.\n * @param {Event} e - The original event.\n * @private\n */\n private keepInputFocused = (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.refocusInput();\n };\n\n /**\n * Triggers the native dropdown for date/time/file inputs.\n * @private\n */\n private triggerNativeDropdown() {\n if (this.disabled || this.readonly) return;\n const input = this.shadowRoot?.querySelector(\n 'input[type=\"date\"], input[type=\"time\"], input[type=\"week\"], input[type=\"month\"], input[type=\"datetime-local\"], input[type=\"file\"]',\n ) as HTMLInputElement | null;\n\n if (input) {\n if (this.type === \"file\") {\n input.click();\n } else {\n this.showPicker();\n }\n }\n }\n\n /**\n * Filter/search inputs (`type=\"search\"`) are rendered as plain text fields so\n * Chrome does not treat them as login username targets. Credential autofill is\n * further blocked with readonly-until-focus (Chrome ignores autocomplete tokens).\n */\n private isFilterSearchInput(): boolean {\n return this.type === \"search\";\n }\n\n private nativeAutocomplete(): string {\n if (this.isFilterSearchInput()) {\n return \"off\";\n }\n return this.autocomplete;\n }\n\n private nativeTextInputType(isPassword: boolean): string {\n if (isPassword && this.showPassword) return \"text\";\n if (this.isFilterSearchInput()) return \"text\";\n return this.type;\n }\n\n private nativeInputMode(): string | undefined {\n if (this.inputmode) return this.inputmode;\n if (this.isFilterSearchInput()) return \"search\";\n return undefined;\n }\n\n private nativeEnterKeyHint():\n | \"enter\"\n | \"done\"\n | \"go\"\n | \"next\"\n | \"previous\"\n | \"search\"\n | \"send\"\n | undefined {\n if (this.enterkeyhint) {\n return this.enterkeyhint as\n | \"enter\"\n | \"done\"\n | \"go\"\n | \"next\"\n | \"previous\"\n | \"search\"\n | \"send\";\n }\n if (this.isFilterSearchInput()) return \"search\";\n return undefined;\n }\n\n private nativeInputRole(): string | undefined {\n if (this.inputRole) return this.inputRole;\n if (this.type === \"search\") return \"searchbox\";\n return undefined;\n }\n\n private affixColorStyle(color: string) {\n const trimmed = String(color ?? \"\").trim();\n if (!trimmed) return undefined;\n return { color: resolveColor(trimmed) };\n }\n\n private renderInputAffix(kind: \"prefix\" | \"suffix\") {\n const value = kind === \"prefix\" ? this.prefix : this.suffix;\n if (!String(value ?? \"\").length) return nothing;\n const color = kind === \"prefix\" ? this.prefixColor : this.suffixColor;\n const style = this.affixColorStyle(color);\n return html`<span\n class=\"input-affix ${kind}\"\n part=\"input-${kind}\"\n style=${style ? styleMap(style) : nothing}\n >${value}</span\n >`;\n }\n\n override render() {\n const isFileInput = this.type === \"file\";\n const isTextarea = this.type === \"textarea\";\n const isNumberInput = this.type === \"number\";\n const isPassword = this.type === \"password\";\n const supportsInlineAffixes = !isFileInput && !isTextarea;\n\n const hasLeftSlot = !!this.querySelector('[slot=\"icon-left\"]');\n const hasRightSlot = !!this.querySelector('[slot=\"icon-right\"]');\n\n let autoIcon: unknown = null;\n if (this.type === \"date\")\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\n else if (this.type === \"time\")\n autoIcon = html`<sky-icon icon=\"ion:time\"></sky-icon>`;\n else if (this.type === \"week\")\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\n else if (this.type === \"month\")\n autoIcon = html`<sky-icon icon=\"ion:calendar\"></sky-icon>`;\n else if (this.type === \"datetime-local\")\n autoIcon = html`<sky-icon icon=\"ion:time\"></sky-icon>`;\n\n const showFilePreview = this.filePreview && (hasLeftSlot || hasRightSlot);\n const showAutoIconInLeft = this.autofillIconSlot === \"left\" && autoIcon;\n const showAutoIconInRight = this.autofillIconSlot === \"right\" && autoIcon;\n\n const ImagePreview = () => html`\n <img\n src=${ifDefined(\n typeof this.filePreview === \"string\" ? this.filePreview : undefined,\n )}\n alt=\"Preview\"\n style=\"width:100%;height:100%;object-fit:cover;border-radius:12px;\"\n />\n `;\n\n const LeftIconSlot = () => html`\n <div\n class=\"icon-slot left ${this.focused ? \"focused\" : \"\"}\"\n part=\"icon-slot icon-slot-left\"\n ?filled=${Boolean(showFilePreview && hasLeftSlot) ||\n Boolean(showAutoIconInLeft) ||\n hasLeftSlot}\n @click=${() => {\n if (isFileInput || showAutoIconInLeft) this.triggerNativeDropdown();\n }}\n >\n ${showFilePreview && hasLeftSlot\n ? ImagePreview()\n : showAutoIconInLeft\n ? autoIcon\n : html`<slot name=\"icon-left\"></slot>`}\n </div>\n `;\n\n const RightIconSlot = () =>\n this.loading\n ? html`<div\n class=\"loading-indicator\"\n part=\"loading-indicator\"\n ?compact=${this.compact}\n ></div>`\n : html`\n <div\n class=\"icon-slot right ${this.focused ? \"focused\" : \"\"}\"\n part=\"icon-slot icon-slot-right\"\n ?filled=${Boolean(showFilePreview && hasRightSlot) ||\n Boolean(showAutoIconInRight) ||\n hasRightSlot}\n @click=${() => {\n if (isFileInput || showAutoIconInRight)\n this.triggerNativeDropdown();\n }}\n >\n ${showFilePreview && hasRightSlot\n ? ImagePreview()\n : showAutoIconInRight\n ? autoIcon\n : html`<slot name=\"icon-right\"></slot>`}\n </div>\n `;\n\n const FileControl = () => html`\n <label\n class=\"custom-file-label\"\n part=\"custom-file-label\"\n for=\"fileInput\"\n ?disabled=${this.disabled}\n >\n ${this.renderInputAffix(\"prefix\")}\n <span\n class=\"custom-file-label__text\"\n part=\"custom-file-label-text\"\n ?data-filled=${Boolean(this.selectedFileName)}\n >\n ${this.selectedFileName || this.placeholder || \"Choose file\"}\n </span>\n ${this.renderInputAffix(\"suffix\")}\n </label>\n\n <input\n id=\"fileInput\"\n type=\"file\"\n @change=${this.handleFileChange}\n ?disabled=${this.disabled}\n accept=${this.accept || \"\"}\n ?multiple=${this.multiple}\n .required=${this.required}\n @keydown=${this.handleKeydown}\n .dir=${this.dir}\n name=${ifDefined(this.name || undefined)}\n .autocomplete=${this.nativeAutocomplete()}\n .autocapitalize=${this.autocapitalize}\n spellcheck=${this.spellcheck}\n ?autofocus=${this.autofocus}\n inputmode=${ifDefined(this.inputmode || undefined)}\n enterkeyhint=${ifDefined(\n this.enterkeyhint as\n | \"enter\"\n | \"done\"\n | \"go\"\n | \"next\"\n | \"previous\"\n | \"search\"\n | \"send\"\n | undefined,\n )}\n list=${ifDefined(this.list || undefined)}\n capture=${ifDefined(this.capture ? \"environment\" : undefined)}\n .aria-invalid=${String(this.isInvalid)}\n .aria-required=${String(this.required)}\n aria-label=${ifDefined(this.ariaLabel || undefined)}\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\n aria-describedby=${ifDefined(this.describedById)}\n />\n `;\n\n const TextareaControl = () => html`\n <textarea\n .value=${live(this.value)}\n @input=${this.handleInput}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n ?compact=${this.compact}\n ?disabled=${this.disabled}\n .required=${this.required}\n .rows=${this.rows}\n placeholder=${this.placeholder}\n resizable=${this.resizable || \"none\"}\n style=\"width:100%;border:none;outline:none;padding:10px;\"\n .autocapitalize=${this.autocapitalize}\n ?spellcheck=${this.spellcheck}\n name=${ifDefined(this.name || undefined)}\n .autocomplete=${this.nativeAutocomplete()}\n inputmode=${ifDefined(this.inputmode || undefined)}\n enterkeyhint=${ifDefined(\n this.enterkeyhint as\n | \"enter\"\n | \"done\"\n | \"go\"\n | \"next\"\n | \"previous\"\n | \"search\"\n | \"send\"\n | undefined,\n )}\n minlength=${ifDefined(this.minlength ?? undefined)}\n maxlength=${ifDefined(this.maxlength ?? undefined)}\n ?autofocus=${this.autofocus}\n .aria-invalid=${String(this.isInvalid)}\n .aria-required=${String(this.required)}\n aria-label=${ifDefined(this.ariaLabel || undefined)}\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\n aria-describedby=${ifDefined(this.describedById)}\n role=${ifDefined(this.nativeInputRole() as\n | \"textbox\"\n | \"searchbox\"\n | \"combobox\"\n | \"listbox\"\n | \"menuitem\"\n | \"option\"\n | \"slider\"\n | \"spinbutton\"\n | \"treeitem\"\n | undefined)}\n ></textarea>\n `;\n\n const TextInputControl = () => html`\n <input\n .type=${this.nativeTextInputType(isPassword)}\n .value=${live(this.value)}\n @input=${this.handleInput}\n @focus=${this.handleFocus}\n @blur=${this.handleBlur}\n @pointerdown=${this.handleAutofillGuardPointerDown}\n ?compact=${this.compact}\n ?disabled=${this.disabled}\n .required=${this.required}\n .readOnly=${this.readonly || this.autofillGuardActive}\n style=\"appearance:none;pointer-events:auto;\"\n placeholder=${this.placeholder}\n name=${ifDefined(this.name || undefined)}\n .autocomplete=${this.nativeAutocomplete()}\n .autocapitalize=${this.autocapitalize}\n spellcheck=${this.spellcheck}\n inputmode=${ifDefined(this.nativeInputMode())}\n enterkeyhint=${ifDefined(this.nativeEnterKeyHint())}\n data-form-type=${this.isFilterSearchInput() ? \"other\" : nothing}\n ?data-1p-ignore=${this.isFilterSearchInput()}\n ?data-lpignore=${this.isFilterSearchInput()}\n list=${ifDefined(this.list || undefined)}\n pattern=${ifDefined(this.pattern || undefined)}\n minlength=${ifDefined(this.minlength ?? undefined)}\n maxlength=${ifDefined(this.maxlength ?? undefined)}\n size=${ifDefined(this.size ?? undefined)}\n step=${ifDefined(this.step !== null ? Number(this.step) : undefined)}\n min=${ifDefined(this.min ?? undefined)}\n max=${ifDefined(this.max ?? undefined)}\n ?autofocus=${this.autofocus}\n .aria-invalid=${String(this.isInvalid)}\n .aria-required=${String(this.required)}\n aria-label=${ifDefined(this.ariaLabel || undefined)}\n aria-labelledby=${ifDefined(this.ariaLabelledby || undefined)}\n aria-describedby=${ifDefined(this.describedById)}\n role=${ifDefined(this.nativeInputRole() as\n | \"textbox\"\n | \"searchbox\"\n | \"combobox\"\n | \"listbox\"\n | \"menuitem\"\n | \"option\"\n | \"slider\"\n | \"spinbutton\"\n | \"treeitem\"\n | undefined)}\n />\n `;\n\n const NumberButtons = () =>\n isNumberInput && this.showNumberButtons\n ? html`\n <div class=\"number-btn\">\n <button\n class=\"decrement-btn\"\n type=\"button\"\n tabindex=\"-1\"\n @mousedown=${this.keepInputFocused}\n @pointerdown=${this.keepInputFocused}\n @click=${(e: Event) => {\n e.stopPropagation();\n this.decrementValue();\n }}\n aria-label=\"Decrease value\"\n >\n <sky-icon icon=\"ion:minus\"></sky-icon>\n </button>\n <button\n class=\"increment-btn\"\n type=\"button\"\n tabindex=\"-1\"\n @mousedown=${this.keepInputFocused}\n @pointerdown=${this.keepInputFocused}\n @click=${(e: Event) => {\n e.stopPropagation();\n this.incrementValue();\n }}\n aria-label=\"Increase value\"\n >\n <sky-icon icon=\"ion:add\"></sky-icon>\n </button>\n </div>\n `\n : null;\n\n const PasswordToggle = () =>\n isPassword && this.showPasswordToggle\n ? html`\n <sky-icon\n class=\"toggle-password\"\n part=\"toggle-password\"\n ?compact=${this.compact}\n icon=${this.showPassword\n ? this.passwordVisibleIcon\n : this.passwordHiddenIcon}\n @click=${this.togglePasswordVisibility}\n ></sky-icon>\n `\n : null;\n\n const ClearButton = () =>\n this.clearable &&\n (this.value || this.selectedFileName || this.selectedFileCount > 0)\n ? html`\n <sky-icon\n class=\"clear-button\"\n part=\"clear-button\"\n ?compact=${this.compact}\n @click=${this.handleClear}\n ?loading=${this.loading}\n icon=\"ion:close\"\n ></sky-icon>\n `\n : null;\n\n const FileInfo = () =>\n isFileInput && this.totalFileSize\n ? html`\n <div class=\"file-info\" part=\"file-info\">\n <span>\n ${this.selectedFileCount}\n file${this.selectedFileCount !== 1 ? \"s selected\" : \" selected\"} </span\n >,\n <span>${this.formatFileSize(this.totalFileSize)}</span>\n </div>\n `\n : null;\n\n const Control = () =>\n isFileInput\n ? FileControl()\n : isTextarea\n ? TextareaControl()\n : TextInputControl();\n\n return html`\n <div\n class=\"input-container\"\n @click=${this.handleWrapperClick}\n part=\"input-container\"\n >\n ${this.label\n ? html`<div class=\"label\" part=\"label\">${this.label}</div>`\n : null}\n <div\n class=\"input-wrapper\"\n part=\"input-wrapper\"\n ?compact=${this.compact}\n ?loading=${this.loading}\n >\n ${LeftIconSlot()}\n ${supportsInlineAffixes ? this.renderInputAffix(\"prefix\") : nothing}\n ${Control()}\n ${supportsInlineAffixes ? this.renderInputAffix(\"suffix\") : nothing}\n ${NumberButtons()} ${PasswordToggle()}\n ${ClearButton()} ${RightIconSlot()}\n </div>\n\n ${FileInfo()} ${this.renderValidationErrors()}\n </div>\n `;\n }\n}\n"],"names":["SkyInput","FormControlBase","constructor","super","arguments","this","value","placeholder","label","type","suffix","prefix","prefixColor","suffixColor","color","_validations","compact","loading","showErrors","clearable","errorDisplayMode","required","step","min","max","autocapitalize","autocomplete","spellcheck","dir","rows","resizable","accept","multiple","inputmode","enterkeyhint","pattern","minlength","maxlength","list","size","cols","autofocus","capture","inputRole","ariaLabel","ariaLabelledby","ariaDescribedby","showNumberButtons","showPasswordToggle","passwordVisibleIcon","passwordHiddenIcon","validationActive","invalid","variant","selectedFileName","selectedFiles","focused","validationStatus","validationErrors","typingStarted","autofillIconSlot","autofillGuardActive","showPassword","totalFileSize","selectedFileCount","filePreview","_leftIconSlot","_rightIconSlot","_iconClickWired","WeakSet","_onLeftIconSlotChange","_wireIconSlot","_onRightIconSlotChange","keepInputFocused","e","preventDefault","stopPropagation","refocusInput","validations","old","Array","isArray","requestUpdate","connectedCallback","hasAttribute","tabIndex","disabled","hasUpdated","_setupIconSlots","disconnectedCallback","removeEventListener","shadowRoot","querySelector","addEventListener","side","slot","node","assignedElements","flatten","HTMLElement","has","add","handleIconClick","firstUpdated","_changedProperties","captureDefaultValue","syncFormValue","syncValidity","willUpdate","changedProperties","map","String","trim","updated","style","setProperty","resolveColor","inputWrapper","inputWrapperEl","getFormValue","name","length","fd","FormData","f","append","setValueFromFormState","state","getValidityAnchor","isEmpty","toString","getCustomErrorMessage","join","getNativeControl","onNativeValueMutated","native","validateInput","reset","nativeRequiredMessage","requiredMessage","getEmittedValue","n","Number","isFinite","handleClear","readonly","dispatchEvent","CustomEvent","detail","bubbles","composed","handleFileChange","event","files","target","fileList","from","file","totalSize","reduce","total","startsWith","reader","FileReader","onload","result","readAsDataURL","reemitNativeEvent","fileName","fileCount","handleKeydown","key","triggerNativeDropdown","preview","handleInput","handleFocus","releaseAutofillGuard","handleAutofillGuardPointerDown","onFormReset","defaultValue","handleBlur","validateForForm","payload","v","r","isFileInput","validation","index","Error","push","error","message","errors","isValid","getErrorMessages","slice","position","eventType","eventData","formatFileSize","bytes","i","Math","floor","log","parseFloat","pow","toFixed","incrementValue","currentValue","Infinity","decrementValue","renderValidationErrors","requiredMsg","customMsgs","msgs","errId","id","html","m","togglePasswordVisibility","focusInput","input","nativeInputEl","focus","handleWrapperClick","isInvalid","matches","describedById","el","preventScroll","click","showPicker","isFilterSearchInput","nativeAutocomplete","nativeTextInputType","isPassword","nativeInputMode","nativeEnterKeyHint","nativeInputRole","affixColorStyle","trimmed","renderInputAffix","kind","nothing","styleMap","render","isTextarea","isNumberInput","supportsInlineAffixes","hasLeftSlot","hasRightSlot","autoIcon","showFilePreview","showAutoIconInLeft","showAutoIconInRight","ImagePreview","ifDefined","FileControl","Boolean","TextareaControl","live","TextInputControl","LeftIconSlot","NumberButtons","PasswordToggle","ClearButton","RightIconSlot","FileInfo","dependencies","SkyIcon","styles","css","shadowRootOptions","LitElement","delegatesFocus","__decorateClass","property","prototype","reflect","query","customElement"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sky-radio.js","sources":["../../src/sky-radio/sky-radio.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\r\nimport { customElement, property, state } from \"lit/decorators.js\";\r\nimport { when } from \"lit/directives/when.js\";\r\nimport { classMap } from \"lit/directives/class-map.js\";\r\nimport { resolveColor } from \"../helper/utils/color-resolver\";\r\nimport { FormControlBase, FormState } from \"../helper/internals/form-control-base\";\r\n\r\nexport type SkyRadioSelectDetail = { value: string };\r\nexport type SkyRadioValidationErrorDetail = { errors: string[] };\r\nexport type SkyRadioValueClearedDetail = { value: \"\" };\r\n\r\n/**\r\n * @element sky-radio\r\n *\r\n * @summary Single radio option for grouped or standalone selection.\r\n *\r\n * @status stable\r\n * @since 1.0.0\r\n *\r\n * @documentation https://library.sky-ui.com/components/radio\r\n *\r\n * @slot - Content to display instead of the label property.\r\n *\r\n * @csspart wrapper - The circular radio control element.\r\n * @csspart input - The native hidden radio input element.\r\n * @csspart label - The text label element.\r\n *\r\n * @property {string} label - Text label displayed beside the control.\r\n * @property {string} value - Option value used for selection and form value.\r\n * @property {boolean} checked - Whether this option is selected.\r\n * @property {string} name - Radio name used for same-name exclusivity.\r\n * @property {string} color - Accent color used in checked state.\r\n * @property {boolean} disabled - Disables user interaction.\r\n * @property {boolean} readonly - Prevents selection changes while still allowing focus.\r\n * @property {boolean} required - Enables required validation for standalone usage.\r\n * @property {string} requiredMessage - Error message for required validation failures.\r\n *\r\n * @fires {CustomEvent<SkyRadioSelectDetail>} radio-select - Fired when the option becomes selected.\r\n * @fires {Event} change - Native change event for form compatibility.\r\n * @fires {Event} input - Native input event for form compatibility.\r\n * @fires {CustomEvent<SkyRadioValidationErrorDetail>} validation-error - Fired when validation errors occur.\r\n * @fires {CustomEvent<SkyRadioValueClearedDetail>} value-cleared - Fired when selection is reset.\r\n * @method check Selects this radio option.\r\n * @method focusRadio Focuses the underlying native radio control.\r\n *\r\n * @Behavior\r\n * - Uses a native hidden radio input for semantics and keyboard interaction.\r\n * - Supports grouped usage inside `sky-radio-group` and standalone usage.\r\n * - Synchronizes checked state and form value through `FormControlBase`.\r\n *\r\n * @example\r\n * ```html\r\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\r\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\r\n * <sky-radio value=\"green\">Green Environment</sky-radio>\r\n * </sky-radio-group>\r\n * ```\r\n * ```vue\r\n * <template>\r\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\r\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\r\n * <sky-radio value=\"green\">Green Environment</sky-radio>\r\n * </sky-radio-group>\r\n * </template>\r\n * ```\r\n * ```jsx\r\n * export default function Demo() {\r\n * return (\r\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\r\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\r\n * <sky-radio value=\"green\">Green Environment</sky-radio>\r\n * </sky-radio-group>\r\n * );\r\n * }\r\n * ```\r\n */\r\n@customElement(\"sky-radio\")\r\nexport class SkyRadio extends FormControlBase {\r\n @property({ type: String }) label: string = \"\";\r\n @property({ type: String }) value: string = \"\";\r\n @property({ type: Boolean, reflect: true }) checked: boolean = false;\r\n @property({ type: String }) color: string = \"primary\";\r\n @state() private _hasMeaningfulSlot = false;\r\n\r\n private syncStyleVars(): void {\r\n this.style.setProperty(\"--radio-checked-color\", resolveColor(this.color));\r\n }\r\n\r\n protected override willUpdate(changed: Map<string, unknown>): void {\r\n super.willUpdate(changed);\r\n if (changed.size === 0 || changed.has(\"color\")) {\r\n this.syncStyleVars();\r\n }\r\n }\r\n\r\n public check(): void {\r\n if (this.disabled || this.readonly) return;\r\n this.checked = true;\r\n this.syncFormValue();\r\n }\r\n\r\n public focusRadio(): void {\r\n const input = this.shadowRoot?.querySelector('input[type=\"radio\"]') as HTMLInputElement | null;\r\n input?.focus();\r\n }\r\n\r\n static override styles = css`\r\n :host {\r\n display: inline-flex;\r\n align-items: center;\r\n }\r\n\r\n /* readonly: allow focus + keyboard traversal, but show subtle visual state */\r\n :host([readonly]) label {\r\n cursor: default;\r\n }\r\n\r\n label {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--sky-space-1\\\\.5, 6px);\r\n color: var(--sky-text-primary);\r\n cursor: pointer;\r\n font-size: var(--sky-font-size-sm);\r\n font-family: var(--sky-font);\r\n }\r\n\r\n label[disabled] {\r\n pointer-events: none;\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n }\r\n\r\n :host([disabled]) label,\r\n :host([disabled]) .radio-wrapper {\r\n pointer-events: none;\r\n cursor: not-allowed;\r\n opacity: 0.6;\r\n }\r\n\r\n .radio-wrapper {\r\n position: relative;\r\n box-sizing: border-box;\r\n width: 18px;\r\n height: 18px;\r\n display: inline-block;\r\n background: var(--sky-glass-solid);\r\n backdrop-filter: none;\r\n -webkit-backdrop-filter: none;\r\n border: 2px solid var(--sky-text-tertiary);\r\n border-radius: 50%;\r\n transition:\r\n border-color 0.3s ease-in-out,\r\n background-color 0.3s ease-in-out,\r\n box-shadow 0.3s ease-in-out;\r\n cursor: pointer;\r\n flex-shrink: 0;\r\n }\r\n\r\n .radio-wrapper::before {\r\n content: \"\";\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%) scale(0);\r\n width: 10px;\r\n height: 10px;\r\n background-color: var(--sky-glass-solid);\r\n border-radius: 50%;\r\n transition:\r\n transform 0.3s ease-in-out,\r\n background-color 0.3s ease-in-out;\r\n }\r\n\r\n .radio-wrapper.checked {\r\n border-color: var(--radio-checked-color);\r\n background-color: var(--radio-checked-color);\r\n }\r\n\r\n .radio-wrapper.checked::before {\r\n transform: translate(-50%, -50%) scale(1);\r\n }\r\n\r\n input[type=\"radio\"] {\r\n position: absolute;\r\n opacity: 0;\r\n pointer-events: none;\r\n width: 0;\r\n height: 0;\r\n }\r\n\r\n :host(:focus-within) .radio-wrapper {\r\n box-shadow: var(--sky-focus-ring);\r\n border-color: var(--radio-checked-color);\r\n }\r\n\r\n sky-icon {\r\n display: inline-block;\r\n width: 1em;\r\n height: 1em;\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .radio-wrapper,\r\n .radio-wrapper::before {\r\n transition: none;\r\n }\r\n }\r\n `;\r\n\r\n constructor() {\r\n super();\r\n this.captureDefaultValue(\"\");\r\n }\r\n static override shadowRootOptions = {\r\n ...LitElement.shadowRootOptions,\r\n delegatesFocus: true,\r\n };\r\n\r\n\r\n override connectedCallback(): void {\r\n super.connectedCallback();\r\n this.addEventListener(\"keydown\", this.handleKeydown);\r\n // Make the host focusable\r\n if (!this.hasAttribute(\"tabindex\")) {\r\n this.tabIndex = this.disabled ? -1 : 0;\r\n }\r\n }\r\n\r\n override disconnectedCallback(): void {\r\n this.removeEventListener(\"keydown\", this.handleKeydown);\r\n super.disconnectedCallback();\r\n }\r\n\r\n override updated(changed: Map<string, unknown>): void {\r\n const input = this.shadowRoot?.querySelector<HTMLInputElement>(\r\n \"input[type='radio']\",\r\n );\r\n\r\n if (changed.has(\"checked\")) {\r\n if (input && input.checked !== this.checked) input.checked = this.checked;\r\n\r\n if (changed.get(\"checked\") !== undefined) {\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n }\r\n if (changed.has(\"disabled\") || changed.has(\"readonly\")) {\r\n if (input) {\r\n input.disabled = this.disabled;\r\n input.readOnly = this.readonly;\r\n }\r\n this.tabIndex = this.disabled ? -1 : 0;\r\n }\r\n\r\n if (changed.has(\"value\")) {\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n }\r\n\r\n private _slotHasMeaningfulContent(slotEl: HTMLSlotElement): boolean {\r\n const nodes = slotEl.assignedNodes({ flatten: true });\r\n return nodes.some((n) =>\r\n n.nodeType === Node.ELEMENT_NODE\r\n ? true\r\n : (n.textContent ?? \"\").trim().length > 0\r\n );\r\n }\r\n\r\n private _onSlotChange = (e: Event) => {\r\n const slot = e.target as HTMLSlotElement;\r\n const next = this._slotHasMeaningfulContent(slot);\r\n if (next !== this._hasMeaningfulSlot) this._hasMeaningfulSlot = next;\r\n };\r\n\r\n private onNativeChange = (e: Event) => {\r\n const input = e.currentTarget as HTMLInputElement;\r\n\r\n // ✅ Prevent state change when disabled or readonly, and re-sync native state\r\n if (this.disabled || this.readonly) {\r\n if (input.checked !== this.checked) {\r\n input.checked = this.checked;\r\n }\r\n return;\r\n }\r\n\r\n const becameChecked = input.checked && !this.checked;\r\n this.checked = input.checked;\r\n\r\n // When used individually, uncheck siblings with the same name\r\n if (this.checked && this.name && !this.closest(\"sky-radio-group\")) {\r\n const all = Array.from(document.querySelectorAll<SkyRadio>(\"sky-radio\"));\r\n for (const r of all) {\r\n if (r !== this && r.name === this.name) r.checked = false;\r\n }\r\n }\r\n\r\n if (becameChecked) {\r\n // Dispatch custom event\r\n this.dispatchEvent(\r\n new CustomEvent<SkyRadioSelectDetail>(\"radio-select\", {\r\n detail: { value: this.value },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n\r\n // Dispatch native events for form compatibility\r\n this.reemitNativeEvent(\"change\", e);\r\n this.reemitNativeEvent(\"input\", e);\r\n\r\n // Sync form value\r\n this.syncFormValue();\r\n this.syncValidity();\r\n }\r\n };\r\n\r\n private handleKeydown = (event: KeyboardEvent) => {\r\n // ✅ no keyboard activation in disabled/readonly mode\r\n if (this.disabled || this.readonly) return;\r\n\r\n if (event.key === \" \" || event.key === \"Enter\") {\r\n event.preventDefault();\r\n const input = this.shadowRoot?.querySelector<HTMLInputElement>(\r\n \"input[type='radio']\"\r\n );\r\n input?.click();\r\n }\r\n };\r\n\r\n // ============================================================\r\n // FormControlBase implementation\r\n // ============================================================\r\n\r\n /** Get the current value for form submission */\r\n protected override getFormValue(): FormState {\r\n return this.checked ? this.value : null;\r\n }\r\n\r\n /** Set value from form state (e.g., form reset) */\r\n protected override setValueFromFormState(state: FormState): void {\r\n if (typeof state === \"string\") {\r\n this.checked = state === this.value;\r\n } else {\r\n this.checked = false;\r\n }\r\n }\r\n\r\n /** Get the validity anchor (the hidden input) */\r\n protected override getValidityAnchor(): HTMLElement | undefined {\r\n return this.getNativeControl() || undefined;\r\n }\r\n\r\n /** Check if empty (for required validation) */\r\n protected override isEmpty(): boolean {\r\n return !this.checked;\r\n }\r\n\r\n /** Get the native control (hidden radio input) */\r\n protected override getNativeControl(): HTMLElement | null {\r\n return this.shadowRoot?.querySelector<HTMLElement>(\"input[type='radio']\") || null;\r\n }\r\n\r\n /** Handle native value mutation */\r\n protected override onNativeValueMutated(_native: any): void {\r\n // Sync the checked state from native input\r\n const input = this.getNativeControl() as HTMLInputElement;\r\n if (input) {\r\n this.checked = input.checked;\r\n }\r\n }\r\n\r\n /** Override to provide custom error messages */\r\n protected override getCustomErrorMessage(): string {\r\n return this.validationErrors?.[0] || \"\";\r\n }\r\n\r\n /** Get current validation errors */\r\n get validationErrors(): string[] {\r\n return this.required && !this.checked ? [this.requiredMessage] : [];\r\n }\r\n\r\n override render() {\r\n return html`\r\n <label\r\n part=\"label\"\r\n ?disabled=${this.disabled}\r\n ?readonly=${this.readonly}\r\n aria-disabled=${this.disabled ? \"true\" : \"false\"}\r\n aria-readonly=${this.readonly ? \"true\" : \"false\"}\r\n >\r\n <input\r\n type=\"radio\"\r\n part=\"input\"\r\n .name=${this.name}\r\n .value=${this.value}\r\n .checked=${this.checked}\r\n @change=${this.onNativeChange}\r\n ?disabled=${this.disabled}\r\n ?required=${this.required}\r\n />\r\n <div\r\n class=${classMap({ \"radio-wrapper\": true, checked: this.checked })}\r\n part=\"wrapper\"\r\n ></div>\r\n <slot @slotchange=${this._onSlotChange}></slot>\r\n ${when(!this._hasMeaningfulSlot, () => this.label)}\r\n </label>\r\n `;\r\n }\r\n}\r\n"],"names":["SkyRadio","FormControlBase","constructor","super","this","label","value","checked","color","_hasMeaningfulSlot","_onSlotChange","e","slot","target","next","_slotHasMeaningfulContent","onNativeChange","input","currentTarget","disabled","readonly","becameChecked","name","closest","all","Array","from","document","querySelectorAll","r","dispatchEvent","CustomEvent","detail","bubbles","composed","reemitNativeEvent","syncFormValue","syncValidity","handleKeydown","event","key","preventDefault","shadowRoot","querySelector","click","captureDefaultValue","syncStyleVars","style","setProperty","resolveColor","willUpdate","changed","size","has","check","focusRadio","focus","connectedCallback","addEventListener","hasAttribute","tabIndex","disconnectedCallback","removeEventListener","updated","get","readOnly","slotEl","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","textContent","trim","length","getFormValue","setValueFromFormState","state","getValidityAnchor","getNativeControl","isEmpty","onNativeValueMutated","_native","getCustomErrorMessage","validationErrors","required","requiredMessage","render","html","classMap","when","styles","css","shadowRootOptions","LitElement","delegatesFocus","__decorateClass","property","type","String","prototype","Boolean","reflect","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"sky-radio.js","sources":["../../src/sky-radio/sky-radio.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { when } from \"lit/directives/when.js\";\nimport { classMap } from \"lit/directives/class-map.js\";\nimport { resolveColor } from \"../helper/utils/color-resolver\";\nimport { FormControlBase, FormState } from \"../helper/internals/form-control-base\";\n\nexport type SkyRadioSelectDetail = { value: string };\nexport type SkyRadioValidationErrorDetail = { errors: string[] };\nexport type SkyRadioValueClearedDetail = { value: \"\" };\n\n/**\n * @element sky-radio\n *\n * @summary Single radio option for grouped or standalone selection.\n *\n * @status stable\n * @since 1.0.0\n *\n * @documentation https://library.sky-ui.com/components/radio\n *\n * @slot - Content to display instead of the label property.\n *\n * @csspart wrapper - The circular radio control element.\n * @csspart input - The native hidden radio input element.\n * @csspart label - The text label element.\n *\n * @property {string} label - Text label displayed beside the control.\n * @property {string} value - Option value used for selection and form value.\n * @property {boolean} checked - Whether this option is selected.\n * @property {string} name - Radio name used for same-name exclusivity.\n * @property {string} color - Accent color used in checked state.\n * @property {boolean} disabled - Disables user interaction.\n * @property {boolean} readonly - Prevents selection changes while still allowing focus.\n * @property {boolean} required - Enables required validation for standalone usage.\n * @property {string} requiredMessage - Error message for required validation failures.\n *\n * @fires {CustomEvent<SkyRadioSelectDetail>} radio-select - Fired when the option becomes selected.\n * @fires {Event} change - Native change event for form compatibility.\n * @fires {Event} input - Native input event for form compatibility.\n * @fires {CustomEvent<SkyRadioValidationErrorDetail>} validation-error - Fired when validation errors occur.\n * @fires {CustomEvent<SkyRadioValueClearedDetail>} value-cleared - Fired when selection is reset.\n * @method check Selects this radio option.\n * @method focusRadio Focuses the underlying native radio control.\n *\n * @Behavior\n * - Uses a native hidden radio input for semantics and keyboard interaction.\n * - Supports grouped usage inside `sky-radio-group` and standalone usage.\n * - Synchronizes checked state and form value through `FormControlBase`.\n *\n * @example\n * ```html\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\n * <sky-radio value=\"green\">Green Environment</sky-radio>\n * </sky-radio-group>\n * ```\n * ```vue\n * <template>\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\n * <sky-radio value=\"green\">Green Environment</sky-radio>\n * </sky-radio-group>\n * </template>\n * ```\n * ```jsx\n * export default function Demo() {\n * return (\n * <sky-radio-group label=\"Deployment\" name=\"deployment\">\n * <sky-radio value=\"blue\" checked color=\"primary\">Blue Environment</sky-radio>\n * <sky-radio value=\"green\">Green Environment</sky-radio>\n * </sky-radio-group>\n * );\n * }\n * ```\n */\n@customElement(\"sky-radio\")\nexport class SkyRadio extends FormControlBase {\n @property({ type: String }) label: string = \"\";\n @property({ type: String }) value: string = \"\";\n @property({ type: Boolean, reflect: true }) checked: boolean = false;\n @property({ type: String }) color: string = \"primary\";\n @state() private _hasMeaningfulSlot = false;\n\n private syncStyleVars(): void {\n this.style.setProperty(\"--radio-checked-color\", resolveColor(this.color));\n }\n\n protected override willUpdate(changed: Map<string, unknown>): void {\n super.willUpdate(changed);\n if (changed.size === 0 || changed.has(\"color\")) {\n this.syncStyleVars();\n }\n }\n\n public check(): void {\n if (this.disabled || this.readonly) return;\n this.checked = true;\n this.syncFormValue();\n }\n\n public focusRadio(): void {\n const input = this.shadowRoot?.querySelector('input[type=\"radio\"]') as HTMLInputElement | null;\n input?.focus();\n }\n\n static override styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n /* readonly: allow focus + keyboard traversal, but show subtle visual state */\n :host([readonly]) label {\n cursor: default;\n }\n\n label {\n display: flex;\n align-items: center;\n gap: var(--sky-space-1\\\\.5, 6px);\n color: var(--sky-text-primary);\n cursor: pointer;\n font-size: var(--sky-font-size-sm);\n font-family: var(--sky-font);\n }\n\n label[disabled] {\n pointer-events: none;\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n :host([disabled]) label,\n :host([disabled]) .radio-wrapper {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .radio-wrapper {\n position: relative;\n box-sizing: border-box;\n width: 18px;\n height: 18px;\n display: inline-block;\n background: var(--sky-glass-solid);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n border: 2px solid var(--sky-text-tertiary);\n border-radius: 50%;\n transition:\n border-color 0.3s ease-in-out,\n background-color 0.3s ease-in-out,\n box-shadow 0.3s ease-in-out;\n cursor: pointer;\n flex-shrink: 0;\n }\n\n .radio-wrapper::before {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) scale(0);\n width: 10px;\n height: 10px;\n background-color: var(--sky-glass-solid);\n border-radius: 50%;\n transition:\n transform 0.3s ease-in-out,\n background-color 0.3s ease-in-out;\n }\n\n .radio-wrapper.checked {\n border-color: var(--radio-checked-color);\n background-color: var(--radio-checked-color);\n }\n\n .radio-wrapper.checked::before {\n transform: translate(-50%, -50%) scale(1);\n }\n\n input[type=\"radio\"] {\n position: absolute;\n opacity: 0;\n pointer-events: none;\n width: 0;\n height: 0;\n }\n\n :host(:focus-within) .radio-wrapper {\n box-shadow: var(--sky-focus-ring);\n border-color: var(--radio-checked-color);\n }\n\n sky-icon {\n display: inline-block;\n width: 1em;\n height: 1em;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .radio-wrapper,\n .radio-wrapper::before {\n transition: none;\n }\n }\n `;\n\n constructor() {\n super();\n this.captureDefaultValue(\"\");\n }\n static override shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener(\"keydown\", this.handleKeydown);\n // Make the host focusable\n if (!this.hasAttribute(\"tabindex\")) {\n this.tabIndex = this.disabled ? -1 : 0;\n }\n }\n\n override disconnectedCallback(): void {\n this.removeEventListener(\"keydown\", this.handleKeydown);\n super.disconnectedCallback();\n }\n\n override updated(changed: Map<string, unknown>): void {\n const input = this.shadowRoot?.querySelector<HTMLInputElement>(\n \"input[type='radio']\",\n );\n\n if (changed.has(\"checked\")) {\n if (input && input.checked !== this.checked) input.checked = this.checked;\n\n if (changed.get(\"checked\") !== undefined) {\n this.syncFormValue();\n this.syncValidity();\n }\n }\n if (changed.has(\"disabled\") || changed.has(\"readonly\")) {\n if (input) {\n input.disabled = this.disabled;\n input.readOnly = this.readonly;\n }\n this.tabIndex = this.disabled ? -1 : 0;\n }\n\n if (changed.has(\"value\")) {\n this.syncFormValue();\n this.syncValidity();\n }\n }\n\n private _slotHasMeaningfulContent(slotEl: HTMLSlotElement): boolean {\n const nodes = slotEl.assignedNodes({ flatten: true });\n return nodes.some((n) =>\n n.nodeType === Node.ELEMENT_NODE\n ? true\n : (n.textContent ?? \"\").trim().length > 0\n );\n }\n\n private _onSlotChange = (e: Event) => {\n const slot = e.target as HTMLSlotElement;\n const next = this._slotHasMeaningfulContent(slot);\n if (next !== this._hasMeaningfulSlot) this._hasMeaningfulSlot = next;\n };\n\n private onNativeChange = (e: Event) => {\n const input = e.currentTarget as HTMLInputElement;\n\n // ✅ Prevent state change when disabled or readonly, and re-sync native state\n if (this.disabled || this.readonly) {\n if (input.checked !== this.checked) {\n input.checked = this.checked;\n }\n return;\n }\n\n const becameChecked = input.checked && !this.checked;\n this.checked = input.checked;\n\n // When used individually, uncheck siblings with the same name\n if (this.checked && this.name && !this.closest(\"sky-radio-group\")) {\n const all = Array.from(document.querySelectorAll<SkyRadio>(\"sky-radio\"));\n for (const r of all) {\n if (r !== this && r.name === this.name) r.checked = false;\n }\n }\n\n if (becameChecked) {\n // Dispatch custom event\n this.dispatchEvent(\n new CustomEvent<SkyRadioSelectDetail>(\"radio-select\", {\n detail: { value: this.value },\n bubbles: true,\n composed: true,\n })\n );\n\n // Dispatch native events for form compatibility\n this.reemitNativeEvent(\"change\", e);\n this.reemitNativeEvent(\"input\", e);\n\n // Sync form value\n this.syncFormValue();\n this.syncValidity();\n }\n };\n\n private handleKeydown = (event: KeyboardEvent) => {\n // ✅ no keyboard activation in disabled/readonly mode\n if (this.disabled || this.readonly) return;\n\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n const input = this.shadowRoot?.querySelector<HTMLInputElement>(\n \"input[type='radio']\"\n );\n input?.click();\n }\n };\n\n // ============================================================\n // FormControlBase implementation\n // ============================================================\n\n /** Get the current value for form submission */\n protected override getFormValue(): FormState {\n return this.checked ? this.value : null;\n }\n\n /** Set value from form state (e.g., form reset) */\n protected override setValueFromFormState(state: FormState): void {\n if (typeof state === \"string\") {\n this.checked = state === this.value;\n } else {\n this.checked = false;\n }\n }\n\n /** Get the validity anchor (the hidden input) */\n protected override getValidityAnchor(): HTMLElement | undefined {\n return this.getNativeControl() || undefined;\n }\n\n /** Check if empty (for required validation) */\n protected override isEmpty(): boolean {\n return !this.checked;\n }\n\n /** Get the native control (hidden radio input) */\n protected override getNativeControl(): HTMLElement | null {\n return this.shadowRoot?.querySelector<HTMLElement>(\"input[type='radio']\") || null;\n }\n\n /** Handle native value mutation */\n protected override onNativeValueMutated(_native: any): void {\n // Sync the checked state from native input\n const input = this.getNativeControl() as HTMLInputElement;\n if (input) {\n this.checked = input.checked;\n }\n }\n\n /** Override to provide custom error messages */\n protected override getCustomErrorMessage(): string {\n return this.validationErrors?.[0] || \"\";\n }\n\n /** Get current validation errors */\n get validationErrors(): string[] {\n return this.required && !this.checked ? [this.requiredMessage] : [];\n }\n\n override render() {\n return html`\n <label\n part=\"label\"\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n aria-disabled=${this.disabled ? \"true\" : \"false\"}\n aria-readonly=${this.readonly ? \"true\" : \"false\"}\n >\n <input\n type=\"radio\"\n part=\"input\"\n .name=${this.name}\n .value=${this.value}\n .checked=${this.checked}\n @change=${this.onNativeChange}\n ?disabled=${this.disabled}\n ?required=${this.required}\n />\n <div\n class=${classMap({ \"radio-wrapper\": true, checked: this.checked })}\n part=\"wrapper\"\n ></div>\n <slot @slotchange=${this._onSlotChange}></slot>\n ${when(!this._hasMeaningfulSlot, () => this.label)}\n </label>\n `;\n }\n}\n"],"names":["SkyRadio","FormControlBase","constructor","super","this","label","value","checked","color","_hasMeaningfulSlot","_onSlotChange","e","slot","target","next","_slotHasMeaningfulContent","onNativeChange","input","currentTarget","disabled","readonly","becameChecked","name","closest","all","Array","from","document","querySelectorAll","r","dispatchEvent","CustomEvent","detail","bubbles","composed","reemitNativeEvent","syncFormValue","syncValidity","handleKeydown","event","key","preventDefault","shadowRoot","querySelector","click","captureDefaultValue","syncStyleVars","style","setProperty","resolveColor","willUpdate","changed","size","has","check","focusRadio","focus","connectedCallback","addEventListener","hasAttribute","tabIndex","disconnectedCallback","removeEventListener","updated","get","readOnly","slotEl","assignedNodes","flatten","some","n","nodeType","Node","ELEMENT_NODE","textContent","trim","length","getFormValue","setValueFromFormState","state","getValidityAnchor","getNativeControl","isEmpty","onNativeValueMutated","_native","getCustomErrorMessage","validationErrors","required","requiredMessage","render","html","classMap","when","styles","css","shadowRootOptions","LitElement","delegatesFocus","__decorateClass","property","type","String","prototype","Boolean","reflect","customElement"],"mappings":"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"}