@ryuzaki13/react-foundation-ui 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/chunks/Input-BmjlpA09.js.map +1 -1
  2. package/dist/chunks/Select-BJ5OqTe7.js +182 -0
  3. package/dist/chunks/Select-BJ5OqTe7.js.map +1 -0
  4. package/dist/chunks/{SerializableSelect-DkYeJtAO.js → SerializableSelect-CNe728Qa.js} +2 -2
  5. package/dist/chunks/{SerializableSelect-DkYeJtAO.js.map → SerializableSelect-CNe728Qa.js.map} +1 -1
  6. package/dist/chunks/{StateSelect-1jH3uLz9.js → StateSelect-ujAre258.js} +2 -2
  7. package/dist/chunks/{StateSelect-1jH3uLz9.js.map → StateSelect-ujAre258.js.map} +1 -1
  8. package/dist/chunks/{select-BT65bQ8J.js → select-BkLc6dyx.js} +2 -2
  9. package/dist/chunks/select-BkLc6dyx.js.map +1 -0
  10. package/dist/chunks/slider-CFKsfxFp.js.map +1 -1
  11. package/dist/expandable-action-panel/stories/ExpandableActionPanel.stories.js +1 -1
  12. package/dist/input/Input.d.ts +1 -1
  13. package/dist/input/Input.d.ts.map +1 -1
  14. package/dist/input/stories/Input.stories.js +1 -1
  15. package/dist/input/stories/Input.stories.js.map +1 -1
  16. package/dist/preset-select/index.js +1 -1
  17. package/dist/preset-select/index.js.map +1 -1
  18. package/dist/select/Select.d.ts +10 -5
  19. package/dist/select/Select.d.ts.map +1 -1
  20. package/dist/select/index.js +3 -3
  21. package/dist/select/stories/Select.stories.d.ts +1 -1
  22. package/dist/select/stories/Select.stories.js +1 -1
  23. package/dist/select/stories/SerializableSelect.stories.js +1 -1
  24. package/dist/slider/SliderInput.d.ts +2 -2
  25. package/dist/slider/SliderInput.d.ts.map +1 -1
  26. package/dist/slider/stories/SliderInput.stories.js.map +1 -1
  27. package/dist/state-select/index.js +1 -1
  28. package/dist/state-select/stories/StateSelect.stories.js +1 -1
  29. package/package.json +1 -1
  30. package/dist/chunks/Select-CXeVjVKA.js +0 -182
  31. package/dist/chunks/Select-CXeVjVKA.js.map +0 -1
  32. package/dist/chunks/select-BT65bQ8J.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Input-BmjlpA09.js","names":[],"sources":["../../src/input/Input.module.scss","../../src/input/lib/useInputFieldIds.ts","../../src/input/Input.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.controlLayout {\n\tposition: relative;\n\twidth: 100%;\n}\n\n.input {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: var(--space-xs) var(--space-sm);\n\tfont-size: var(--font-size-md);\n\n\t--ui-color: var(--content-0);\n\t--ui-color-hover: var(--content-0);\n\t--ui-color-active: var(--content-0);\n}\n\n.inputNumber {\n\tappearance: textfield;\n\t-moz-appearance: textfield;\n\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n}\n\n.controlWithEndAdornment {\n\tpadding-right: calc(var(--input-end-adornment-width, var(--control-height)) + var(--space-sm));\n}\n\n.controlEndAdornment {\n\tposition: absolute;\n\theight: 100%;\n\ttop: 0;\n\tright: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n\t// max-width: calc(100% - (var(--space-md) * 2));\n\tmax-width: calc(100% - var(--space-md));\n}\n\n.endAdornmentGroup {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n}\n\n.clearButton {\n\twidth: 1.75em;\n\theight: 1.75em;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--content-1);\n\ttransition:\n\t\tcolor var(--transition-fast) ease,\n\t\tbackground-color var(--transition-fast) ease;\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t\tbackground-color: var(--status-info-soft);\n\t}\n\n\t&:focus-visible {\n\t\t@include focusVisible;\n\t}\n\n\t&:disabled {\n\t\tpointer-events: none;\n\t\topacity: 0.25;\n\t}\n}\n\n.error {\n\tposition: absolute;\n\tz-index: 11;\n\tbottom: calc(var(--space-xs) * -1);\n\tleft: 0;\n\tright: 0;\n\ttransform: translateY(100%);\n\t// font-size: var(--font-size-sm);\n\tcolor: var(--status-error-on-fill);\n\tbackground: var(--status-error-fill);\n\tborder-radius: var(--radius-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbox-shadow: var(--shadow-sm);\n\topacity: 0.9;\n}\n","import { useId } from \"react\";\n\nexport interface UseInputFieldIdsOptions {\n\tid?: string;\n\thasLabel?: boolean;\n\thasDescription?: boolean;\n\thasError?: boolean;\n}\n\nexport interface InputFieldIds {\n\tcontrolId: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tdescribedBy?: string;\n}\n\nexport function useInputFieldIds({ id: externalId, hasLabel, hasDescription, hasError }: UseInputFieldIdsOptions): InputFieldIds {\n\tconst autoId = useId();\n\tconst controlId = externalId ?? autoId;\n\tconst labelId = hasLabel ? `${controlId}-label` : undefined;\n\tconst descriptionId = hasDescription ? `${controlId}-description` : undefined;\n\tconst errorId = hasError ? `${controlId}-error` : undefined;\n\tconst describedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined;\n\n\treturn {\n\t\tcontrolId,\n\t\tlabelId,\n\t\tdescriptionId,\n\t\terrorId,\n\t\tdescribedBy\n\t};\n}\n","import React, { CSSProperties, InputHTMLAttributes, ReactNode, useEffect, useEffectEvent, useState } from \"react\";\n\nimport { toFiniteNumber } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport { UiBaseProps, UiSize } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./Input.module.scss\";\nimport { useInputFieldIds } from \"./lib/useInputFieldIds\";\n\nexport interface InputUIProps extends Omit<UiBaseProps<never>, \"value\" | \"onChange\"> {\n\tclassName?: string;\n\terror?: string;\n\tcontrolId?: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tchildren: React.ReactNode;\n}\n\nexport interface InputControlRenderProps {\n\tcontrolClassName?: string;\n}\n\nexport interface InputControlProps {\n\tclassName?: string;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n\tchildren: (props: InputControlRenderProps) => ReactNode;\n}\n\nexport interface InputClearButtonProps {\n\tonClick?: () => void;\n\tdisabled?: boolean;\n\tclassName?: string;\n\tariaLabel?: string;\n}\n\nfunction InputLabel({ label, controlId, labelId }: { label: React.ReactNode; controlId?: string; labelId?: string }) {\n\treturn (\n\t\t<label id={labelId} htmlFor={controlId} className={uiStyles.uiLabel}>\n\t\t\t{label}\n\t\t</label>\n\t);\n}\n\nexport function InputUILoading({\n\tlabel,\n\tdescription,\n\tsize,\n\tdisabled,\n\tclassName\n}: Pick<InputUIProps, \"label\" | \"description\" | \"size\" | \"disabled\" | \"className\">) {\n\tconst { controlId, labelId, descriptionId } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description\n\t});\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(uiStyles.uiElement, uiStyles.uiSizable, size && uiStyles[size as UiSize], uiStyles.disabled, className)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={cn(uiStyles.uiInputControlFake, \"skeletonLine\")} />\n\t\t</div>\n\t);\n}\n\n/**\n * Низкоуровневая оболочка поля ввода с общими элементами оформления.\n */\nexport function InputUI({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\terror,\n\tsize,\n\tcontrolId,\n\tlabelId,\n\tdescriptionId,\n\terrorId,\n\tchildren\n}: InputUIProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tuiStyles.uiElement,\n\t\t\t\tuiStyles.uiSizable,\n\t\t\t\tsize && uiStyles[size as UiSize],\n\t\t\t\tdisabled && uiStyles.disabled,\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={styles.controlLayout}>\n\t\t\t\t{children}\n\n\t\t\t\t{error && (\n\t\t\t\t\t<p id={errorId} className={styles.error} role=\"alert\">\n\t\t\t\t\t\t{error}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function InputControl({ className, endAdornment, endAdornmentClassName, endAdornmentWidth, children }: InputControlProps) {\n\tconst hasEndAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst style =\n\t\thasEndAdornment && endAdornmentWidth ? ({ \"--input-end-adornment-width\": endAdornmentWidth } as CSSProperties) : undefined;\n\n\treturn (\n\t\t<div className={cn(styles.controlLayout, className)} style={style}>\n\t\t\t{children({ controlClassName: hasEndAdornment ? styles.controlWithEndAdornment : undefined })}\n\t\t\t{hasEndAdornment && <div className={cn(styles.controlEndAdornment, endAdornmentClassName)}>{endAdornment}</div>}\n\t\t</div>\n\t);\n}\n\nexport function InputClearButton({ onClick, disabled, className, ariaLabel = \"Очистить значение\" }: InputClearButtonProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdisabled={disabled || !onClick}\n\t\t\tclassName={cn(styles.clearButton, \"flexCenter radiusSm\", className)}\n\t\t\tonClick={onClick}\n\t\t\taria-label={ariaLabel}>\n\t\t\t<XIcon />\n\t\t</button>\n\t);\n}\n\nfunction resolveEndAdornmentWidth(hasAdornment: boolean, hasClearAction: boolean, explicitWidth?: string) {\n\tif (explicitWidth) {\n\t\treturn explicitWidth;\n\t}\n\n\tif (hasAdornment && hasClearAction) {\n\t\treturn \"calc((var(--control-height) * 2) + var(--space-xs))\";\n\t}\n\n\tif (hasAdornment || hasClearAction) {\n\t\treturn \"var(--control-height)\";\n\t}\n\n\treturn undefined;\n}\n\nfunction createEndAdornment({ endAdornment, onClear, disabled }: { endAdornment?: ReactNode; onClear?: () => void; disabled?: boolean }) {\n\tif ((endAdornment === undefined || endAdornment === null) && !onClear) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<div className={styles.endAdornmentGroup}>\n\t\t\t{endAdornment}\n\t\t\t{onClear && <InputClearButton onClick={onClear} disabled={disabled} />}\n\t\t</div>\n\t);\n}\n\nexport interface BaseInputProps<T extends number | string, V = T>\n\textends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"type\" | \"defaultValue\" | \"onChange\">, UiBaseProps<T, V> {\n\tonClear?: () => void;\n\terror?: string;\n\tonClearError?: () => void;\n\tdefaultValue?: T;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n}\n\nexport interface InputTextProps extends BaseInputProps<string> {\n\ttype?: \"email\" | \"password\" | \"search\" | \"tel\" | \"text\" | \"url\";\n\n\t/**\n\t * Регулярное выражение для валидации всего введённого значения.\n\t * При несоответствии поле подсвечивается как невалидное, но текст не удаляется.\n\t * Пример: `/^\\d*$/`\n\t */\n\tallowedPattern?: RegExp;\n}\n\n/**\n * Базовое текстовое поле ввода для строковых значений.\n */\nexport function InputText({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tallowedPattern,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\ttype = \"text\",\n\t...props\n}: InputTextProps) {\n\tconst [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst newValue = e.target.value;\n\n\t\tif (allowedPattern !== undefined) {\n\t\t\tsetInternalInvalid(newValue !== \"\" && !allowedPattern.test(newValue));\n\t\t}\n\n\t\tonChange?.(newValue);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\tconst hasValue = Boolean(value && value.length > 0);\n\tconst visibleError = hasValue ? error : undefined;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!visibleError\n\t});\n\tconst isInvalid = hasValue && (!!error || internalInvalid);\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!onClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={visibleError}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\taria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tdata-invalid={isInvalid ? \"\" : undefined}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Числовое поле ввода с нормализацией значения и защитой от промежуточного невалидного ввода.\n */\nexport function InputNumber({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\t...props\n}: BaseInputProps<number, number | undefined>) {\n\tconst inputProps = props as InputHTMLAttributes<HTMLInputElement>;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\tconst [rawValue, setRawValue] = useState<string>(() => String(value));\n\t// const [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst syncRawValue = useEffectEvent((nextRaw: string) => {\n\t\tsetRawValue(nextRaw);\n\t\t// setInternalInvalid(false);\n\t});\n\n\tuseEffect(() => {\n\t\tconst nextRaw = value !== undefined && typeof value === \"number\" && !isNaN(value) ? String(value) : \"\";\n\t\tsyncRawValue(nextRaw);\n\t}, [value]);\n\n\tconst handleClear = onClear\n\t\t? () => {\n\t\t\t\tsetRawValue(\"\");\n\t\t\t\t// setInternalInvalid(false);\n\t\t\t\tonClear();\n\t\t\t}\n\t\t: undefined;\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst raw = e.target.value;\n\t\tsetRawValue(raw);\n\n\t\tconst parsed = toFiniteNumber(raw) ?? value ?? 0;\n\t\t// const isEmpty = raw.trim() === \"\";\n\n\t\t// const minNum = min !== undefined ? Number(min) : undefined;\n\t\t// const maxNum = max !== undefined ? Number(max) : undefined;\n\t\t// const isValidNumber = !isEmpty && !isNaN(parsed);\n\t\t// const isInRange = isValidNumber && (minNum === undefined || parsed >= minNum) && (maxNum === undefined || parsed <= maxNum);\n\n\t\t// setInternalInvalid(!isEmpty && (!isValidNumber || !isInRange));\n\n\t\tonChange?.(parsed);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\t// const isInvalid = !!error || internalInvalid;\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear: handleClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!handleClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...inputProps}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tinputMode=\"decimal\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={rawValue}\n\t\t\t\t\t\t// aria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, styles.inputNumber, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Совместимый алиас для `InputText`.\n */\nexport const Input = InputText;\n"],"mappings":";;;;;;;;;;;;;;;;;;ACiBA,SAAgB,EAAiB,EAAE,IAAI,GAAY,aAAU,mBAAgB,eAAoD;CAChI,IAAM,IAAS,EAAM,GACf,IAAY,KAAc,GAC1B,IAAU,IAAW,GAAG,EAAU,UAAU,KAAA,GAC5C,IAAgB,IAAiB,GAAG,EAAU,gBAAgB,KAAA,GAC9D,IAAU,IAAW,GAAG,EAAU,UAAU,KAAA;CAGlD,OAAO;EACN;EACA;EACA;EACA;EACA,aAPmB,CAAC,GAAe,CAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;CAQ1E;AACD;;;ACSA,SAAS,EAAW,EAAE,UAAO,cAAW,cAA6E;CACpH,OACC,kBAAC,SAAD;EAAO,IAAI;EAAS,SAAS;EAAW,WAAW,EAAS;YAC1D;CACK,CAAA;AAET;AAEA,SAAgB,EAAe,EAC9B,UACA,gBACA,SACA,aACA,gBACmF;CACnF,IAAM,EAAE,cAAW,YAAS,qBAAkB,EAAiB;EAC9D,UAAU,KAAiC;EAC3C,gBAAgB,CAAC,CAAC;CACnB,CAAC;CAED,OACC,kBAAC,OAAD;EACC,WAAW,EAAG,EAAS,WAAW,EAAS,WAAW,KAAQ,EAAS,IAAiB,EAAS,UAAU,CAAS;EACpH,iBAAe,KAAY,KAAA;YAF5B;GAGE,KAAS,kBAAC,GAAD;IAAmB;IAAkB;IAAoB;GAAU,CAAA;GAC5E,KACA,kBAAC,KAAD;IAAG,IAAI;IAAe,WAAW,EAAS;cACxC;GACC,CAAA;GAEJ,kBAAC,OAAD,EAAK,WAAW,EAAG,EAAS,oBAAoB,cAAc,EAAI,CAAA;EAC9D;;AAEP;AAKA,SAAgB,EAAQ,EACvB,UACA,gBACA,aACA,cACA,UACA,SACA,cACA,YACA,kBACA,YACA,eACgB;CAChB,OACC,kBAAC,OAAD;EACC,WAAW,EACV,EAAS,WACT,EAAS,WACT,KAAQ,EAAS,IACjB,KAAY,EAAS,UACrB,CACD;EACA,iBAAe,KAAY,KAAA;YAR5B;GASE,KAAS,kBAAC,GAAD;IAAmB;IAAkB;IAAoB;GAAU,CAAA;GAC5E,KACA,kBAAC,KAAD;IAAG,IAAI;IAAe,WAAW,EAAS;cACxC;GACC,CAAA;GAEJ,kBAAC,OAAD;IAAK,WAAW,EAAO;cAAvB,CACE,GAEA,KACA,kBAAC,KAAD;KAAG,IAAI;KAAS,WAAW,EAAO;KAAO,MAAK;eAC5C;IACC,CAAA,CAEA;;EACD;;AAEP;AAEA,SAAgB,EAAa,EAAE,cAAW,iBAAc,0BAAuB,sBAAmB,eAA+B;CAChI,IAAM,IAAkB,KAA+C,MACjE,IACL,KAAmB,IAAqB,EAAE,+BAA+B,EAAkB,IAAsB,KAAA;CAElH,OACC,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,eAAe,CAAS;EAAU;YAA5D,CACE,EAAS,EAAE,kBAAkB,IAAkB,EAAO,0BAA0B,KAAA,EAAU,CAAC,GAC3F,KAAmB,kBAAC,OAAD;GAAK,WAAW,EAAG,EAAO,qBAAqB,CAAqB;aAAI;EAAkB,CAAA,CAC1G;;AAEP;AAEA,SAAgB,EAAiB,EAAE,YAAS,aAAU,cAAW,eAAY,uBAA8C;CAC1H,OACC,kBAAC,UAAD;EACC,MAAK;EACL,UAAU,KAAY,CAAC;EACvB,WAAW,EAAG,EAAO,aAAa,uBAAuB,CAAS;EACzD;EACT,cAAY;YACZ,kBAAC,GAAD,CAAQ,CAAA;CACD,CAAA;AAEV;AAEA,SAAS,EAAyB,GAAuB,GAAyB,GAAwB;CACzG,IAAI,GACH,OAAO;CAGR,IAAI,KAAgB,GACnB,OAAO;CAGR,IAAI,KAAgB,GACnB,OAAO;AAIT;AAEA,SAAS,EAAmB,EAAE,iBAAc,YAAS,eAAoF;CACxI,MAAK,KAA+C,QAAS,CAAC,IAI9D,OACC,kBAAC,OAAD;EAAK,WAAW,EAAO;YAAvB,CACE,GACA,KAAW,kBAAC,GAAD;GAAkB,SAAS;GAAmB;EAAW,CAAA,CACjE;;AAEP;AA2BA,SAAgB,EAAU,EACzB,UACA,gBACA,aACA,cACA,YACA,UACA,iBACA,aACA,UACA,SACA,mBACA,iBACA,0BACA,sBACA,UAAO,QACP,GAAG,KACe;CAClB,IAAM,CAAC,GAAiB,KAAsB,EAAS,EAAK,GAEtD,KAAe,MAA2C;EAC/D,IAAM,IAAW,EAAE,OAAO;EAO1B,AALI,MAAmB,KAAA,KACtB,EAAmB,MAAa,MAAM,CAAC,EAAe,KAAK,CAAQ,CAAC,GAGrE,IAAW,CAAQ,GACf,KAAS,KAAc,EAAa;CACzC,GAEM,IAAW,GAAQ,KAAS,EAAM,SAAS,IAC3C,IAAe,IAAW,IAAQ,KAAA,GAClC,EAAE,cAAW,YAAS,kBAAe,YAAS,mBAAgB,EAAiB;EACpF,IAAI,EAAM;EACV,UAAU,KAAiC;EAC3C,gBAAgB,CAAC,CAAC;EAClB,UAAU,CAAC,CAAC;CACb,CAAC,GACK,IAAY,MAAa,CAAC,CAAC,KAAS;CAK1C,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACC;EACL;EACN,OAAO;EACI;EACF;EACM;EACN;YACT,kBAAC,GAAD;GACC,cAjB0B,EAAmB;IAAE;IAAc;IAAS;GAAS,CAiBjE;GACS;GACvB,mBAjB+B,EADP,KAA+C,MACK,CAAC,CAAC,GAAS,CAiBpE;cACjB,EAAE,0BACH,kBAAC,SAAD;IACC,GAAI;IACJ,IAAI;IACE;IACI;IACH;IACP,gBAAc,KAAa,KAAA;IAC3B,mBAAiB;IACjB,oBAAkB;IAClB,gBAAc,IAAY,KAAK,KAAA;IAC/B,WAAW,EAAG,EAAS,gBAAgB,EAAO,OAAO,CAAgB;IACrE,UAAU;GACV,CAAA;EAEW,CAAA;CACN,CAAA;AAEX;AAKA,SAAgB,EAAY,EAC3B,UACA,gBACA,aACA,cACA,YACA,UACA,iBACA,aACA,UACA,SACA,iBACA,0BACA,sBACA,GAAG,KAC2C;CAC9C,IAAM,IAAa,GACb,EAAE,cAAW,YAAS,kBAAe,YAAS,mBAAgB,EAAiB;EACpF,IAAI,EAAM;EACV,UAAU,KAAiC;EAC3C,gBAAgB,CAAC,CAAC;EAClB,UAAU,CAAC,CAAC;CACb,CAAC,GAEK,CAAC,GAAU,KAAe,QAAuB,OAAO,CAAK,CAAC,GAG9D,IAAe,GAAgB,MAAoB;EACxD,EAAY,CAAO;CAEpB,CAAC;CAED,QAAgB;EAEf,EADgB,MAAU,KAAA,KAAa,OAAO,KAAU,YAAY,CAAC,MAAM,CAAK,IAAI,OAAO,CAAK,IAAI,EAChF;CACrB,GAAG,CAAC,CAAK,CAAC;CAEV,IAAM,IAAc,UACX;EAGN,AAFA,EAAY,EAAE,GAEd,EAAQ;CACT,IACC,KAAA,GAEG,KAAe,MAA2C;EAC/D,IAAM,IAAM,EAAE,OAAO;EACrB,EAAY,CAAG;EAEf,IAAM,IAAS,EAAe,CAAG,KAAK,KAAS;EAW/C,AADA,IAAW,CAAM,GACb,KAAS,KAAc,EAAa;CACzC;CAOA,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACC;EACL;EACC;EACI;EACF;EACM;EACN;YACT,kBAAC,GAAD;GACC,cAjB0B,EAAmB;IAAE;IAAc,SAAS;IAAa;GAAS,CAiB9E;GACS;GACvB,mBAjB+B,EADP,KAA+C,MACK,CAAC,CAAC,GAAa,CAiBxE;cACjB,EAAE,0BACH,kBAAC,SAAD;IACC,GAAI;IACJ,IAAI;IACJ,MAAK;IACL,WAAU;IACA;IACV,OAAO;IAEP,mBAAiB;IACjB,oBAAkB;IAClB,WAAW,EAAG,EAAS,gBAAgB,EAAO,OAAO,EAAO,aAAa,CAAgB;IACzF,UAAU;GACV,CAAA;EAEW,CAAA;CACN,CAAA;AAEX;AAKA,IAAa,IAAQ"}
1
+ {"version":3,"file":"Input-BmjlpA09.js","names":[],"sources":["../../src/input/Input.module.scss","../../src/input/lib/useInputFieldIds.ts","../../src/input/Input.tsx"],"sourcesContent":["@use \"@/styles/mixins\" as *;\n\n.controlLayout {\n\tposition: relative;\n\twidth: 100%;\n}\n\n.input {\n\theight: var(--control-height);\n\twidth: 100%;\n\tpadding: var(--space-xs) var(--space-sm);\n\tfont-size: var(--font-size-md);\n\n\t--ui-color: var(--content-0);\n\t--ui-color-hover: var(--content-0);\n\t--ui-color-active: var(--content-0);\n}\n\n.inputNumber {\n\tappearance: textfield;\n\t-moz-appearance: textfield;\n\n\t&::-webkit-inner-spin-button,\n\t&::-webkit-outer-spin-button {\n\t\t-webkit-appearance: none;\n\t\tmargin: 0;\n\t}\n}\n\n.controlWithEndAdornment {\n\tpadding-right: calc(var(--input-end-adornment-width, var(--control-height)) + var(--space-sm));\n}\n\n.controlEndAdornment {\n\tposition: absolute;\n\theight: 100%;\n\ttop: 0;\n\tright: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: flex-end;\n\t// max-width: calc(100% - (var(--space-md) * 2));\n\tmax-width: calc(100% - var(--space-md));\n}\n\n.endAdornmentGroup {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n}\n\n.clearButton {\n\twidth: 1.75em;\n\theight: 1.75em;\n\tborder: none;\n\tbackground: transparent;\n\tcolor: var(--content-1);\n\ttransition:\n\t\tcolor var(--transition-fast) ease,\n\t\tbackground-color var(--transition-fast) ease;\n\n\t&:hover {\n\t\tcolor: var(--content-accent);\n\t\tbackground-color: var(--status-info-soft);\n\t}\n\n\t&:focus-visible {\n\t\t@include focusVisible;\n\t}\n\n\t&:disabled {\n\t\tpointer-events: none;\n\t\topacity: 0.25;\n\t}\n}\n\n.error {\n\tposition: absolute;\n\tz-index: 11;\n\tbottom: calc(var(--space-xs) * -1);\n\tleft: 0;\n\tright: 0;\n\ttransform: translateY(100%);\n\t// font-size: var(--font-size-sm);\n\tcolor: var(--status-error-on-fill);\n\tbackground: var(--status-error-fill);\n\tborder-radius: var(--radius-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n\tbox-shadow: var(--shadow-sm);\n\topacity: 0.9;\n}\n","import { useId } from \"react\";\n\nexport interface UseInputFieldIdsOptions {\n\tid?: string;\n\thasLabel?: boolean;\n\thasDescription?: boolean;\n\thasError?: boolean;\n}\n\nexport interface InputFieldIds {\n\tcontrolId: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tdescribedBy?: string;\n}\n\nexport function useInputFieldIds({ id: externalId, hasLabel, hasDescription, hasError }: UseInputFieldIdsOptions): InputFieldIds {\n\tconst autoId = useId();\n\tconst controlId = externalId ?? autoId;\n\tconst labelId = hasLabel ? `${controlId}-label` : undefined;\n\tconst descriptionId = hasDescription ? `${controlId}-description` : undefined;\n\tconst errorId = hasError ? `${controlId}-error` : undefined;\n\tconst describedBy = [descriptionId, errorId].filter(Boolean).join(\" \") || undefined;\n\n\treturn {\n\t\tcontrolId,\n\t\tlabelId,\n\t\tdescriptionId,\n\t\terrorId,\n\t\tdescribedBy\n\t};\n}\n","import React, { CSSProperties, InputHTMLAttributes, ReactNode, useEffect, useEffectEvent, useState } from \"react\";\n\nimport { toFiniteNumber } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { XIcon } from \"lucide-react\";\n\nimport { UiBaseProps, UiSize } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport styles from \"./Input.module.scss\";\nimport { useInputFieldIds } from \"./lib/useInputFieldIds\";\n\nexport interface InputUIProps extends Omit<UiBaseProps<never>, \"value\" | \"onChange\"> {\n\tclassName?: string;\n\terror?: string;\n\tcontrolId?: string;\n\tlabelId?: string;\n\tdescriptionId?: string;\n\terrorId?: string;\n\tchildren: React.ReactNode;\n}\n\nexport interface InputControlRenderProps {\n\tcontrolClassName?: string;\n}\n\nexport interface InputControlProps {\n\tclassName?: string;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n\tchildren: (props: InputControlRenderProps) => ReactNode;\n}\n\nexport interface InputClearButtonProps {\n\tonClick?: () => void;\n\tdisabled?: boolean;\n\tclassName?: string;\n\tariaLabel?: string;\n}\n\nfunction InputLabel({ label, controlId, labelId }: { label: React.ReactNode; controlId?: string; labelId?: string }) {\n\treturn (\n\t\t<label id={labelId} htmlFor={controlId} className={uiStyles.uiLabel}>\n\t\t\t{label}\n\t\t</label>\n\t);\n}\n\nexport function InputUILoading({\n\tlabel,\n\tdescription,\n\tsize,\n\tdisabled,\n\tclassName\n}: Pick<InputUIProps, \"label\" | \"description\" | \"size\" | \"disabled\" | \"className\">) {\n\tconst { controlId, labelId, descriptionId } = useInputFieldIds({\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description\n\t});\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(uiStyles.uiElement, uiStyles.uiSizable, size && uiStyles[size as UiSize], uiStyles.disabled, className)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={cn(uiStyles.uiInputControlFake, \"skeletonLine\")} />\n\t\t</div>\n\t);\n}\n\n/**\n * Низкоуровневая оболочка поля ввода с общими элементами оформления.\n */\nexport function InputUI({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\terror,\n\tsize,\n\tcontrolId,\n\tlabelId,\n\tdescriptionId,\n\terrorId,\n\tchildren\n}: InputUIProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\tuiStyles.uiElement,\n\t\t\t\tuiStyles.uiSizable,\n\t\t\t\tsize && uiStyles[size as UiSize],\n\t\t\t\tdisabled && uiStyles.disabled,\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\taria-disabled={disabled || undefined}>\n\t\t\t{label && <InputLabel label={label} controlId={controlId} labelId={labelId} />}\n\t\t\t{description && (\n\t\t\t\t<p id={descriptionId} className={uiStyles.uiDescription}>\n\t\t\t\t\t{description}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t<div className={styles.controlLayout}>\n\t\t\t\t{children}\n\n\t\t\t\t{error && (\n\t\t\t\t\t<p id={errorId} className={styles.error} role=\"alert\">\n\t\t\t\t\t\t{error}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport function InputControl({ className, endAdornment, endAdornmentClassName, endAdornmentWidth, children }: InputControlProps) {\n\tconst hasEndAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst style =\n\t\thasEndAdornment && endAdornmentWidth ? ({ \"--input-end-adornment-width\": endAdornmentWidth } as CSSProperties) : undefined;\n\n\treturn (\n\t\t<div className={cn(styles.controlLayout, className)} style={style}>\n\t\t\t{children({ controlClassName: hasEndAdornment ? styles.controlWithEndAdornment : undefined })}\n\t\t\t{hasEndAdornment && <div className={cn(styles.controlEndAdornment, endAdornmentClassName)}>{endAdornment}</div>}\n\t\t</div>\n\t);\n}\n\nexport function InputClearButton({ onClick, disabled, className, ariaLabel = \"Очистить значение\" }: InputClearButtonProps) {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdisabled={disabled || !onClick}\n\t\t\tclassName={cn(styles.clearButton, \"flexCenter radiusSm\", className)}\n\t\t\tonClick={onClick}\n\t\t\taria-label={ariaLabel}>\n\t\t\t<XIcon />\n\t\t</button>\n\t);\n}\n\nfunction resolveEndAdornmentWidth(hasAdornment: boolean, hasClearAction: boolean, explicitWidth?: string) {\n\tif (explicitWidth) {\n\t\treturn explicitWidth;\n\t}\n\n\tif (hasAdornment && hasClearAction) {\n\t\treturn \"calc((var(--control-height) * 2) + var(--space-xs))\";\n\t}\n\n\tif (hasAdornment || hasClearAction) {\n\t\treturn \"var(--control-height)\";\n\t}\n\n\treturn undefined;\n}\n\nfunction createEndAdornment({ endAdornment, onClear, disabled }: { endAdornment?: ReactNode; onClear?: () => void; disabled?: boolean }) {\n\tif ((endAdornment === undefined || endAdornment === null) && !onClear) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<div className={styles.endAdornmentGroup}>\n\t\t\t{endAdornment}\n\t\t\t{onClear && <InputClearButton onClick={onClear} disabled={disabled} />}\n\t\t</div>\n\t);\n}\n\nexport interface BaseInputProps<T extends number | string, V = T>\n\textends Omit<InputHTMLAttributes<HTMLInputElement>, \"size\" | \"value\" | \"type\" | \"defaultValue\" | \"onChange\">, UiBaseProps<T, V> {\n\tonClear?: () => void;\n\terror?: string;\n\tonClearError?: () => void;\n\tdefaultValue?: T;\n\tendAdornment?: ReactNode;\n\tendAdornmentClassName?: string;\n\tendAdornmentWidth?: string;\n}\n\nexport interface InputTextProps extends BaseInputProps<string> {\n\ttype?: \"email\" | \"password\" | \"search\" | \"tel\" | \"text\" | \"url\";\n\n\t/**\n\t * Регулярное выражение для валидации всего введённого значения.\n\t * При несоответствии поле подсвечивается как невалидное, но текст не удаляется.\n\t * Пример: `/^\\d*$/`\n\t */\n\tallowedPattern?: RegExp;\n}\n\n/**\n * Базовое текстовое поле ввода для строковых значений.\n */\nexport function InputText({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tallowedPattern,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\ttype = \"text\",\n\t...props\n}: InputTextProps) {\n\tconst [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst newValue = e.target.value;\n\n\t\tif (allowedPattern !== undefined) {\n\t\t\tsetInternalInvalid(newValue !== \"\" && !allowedPattern.test(newValue));\n\t\t}\n\n\t\tonChange?.(newValue);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\tconst hasValue = Boolean(value && value.length > 0);\n\tconst visibleError = hasValue ? error : undefined;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!visibleError\n\t});\n\tconst isInvalid = hasValue && (!!error || internalInvalid);\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!onClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={visibleError}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\taria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tdata-invalid={isInvalid ? \"\" : undefined}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Числовое поле ввода с нормализацией значения и защитой от промежуточного невалидного ввода.\n */\nexport function InputNumber({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tclassName,\n\tonClear,\n\terror,\n\tonClearError,\n\tonChange,\n\tvalue,\n\tsize,\n\tendAdornment,\n\tendAdornmentClassName,\n\tendAdornmentWidth,\n\t...props\n}: BaseInputProps<number>) {\n\tconst inputProps = props as InputHTMLAttributes<HTMLInputElement>;\n\tconst { controlId, labelId, descriptionId, errorId, describedBy } = useInputFieldIds({\n\t\tid: props.id,\n\t\thasLabel: label !== undefined && label !== null,\n\t\thasDescription: !!description,\n\t\thasError: !!error\n\t});\n\n\tconst [rawValue, setRawValue] = useState<string>(() => String(value));\n\t// const [internalInvalid, setInternalInvalid] = useState(false);\n\n\tconst syncRawValue = useEffectEvent((nextRaw: string) => {\n\t\tsetRawValue(nextRaw);\n\t\t// setInternalInvalid(false);\n\t});\n\n\tuseEffect(() => {\n\t\tconst nextRaw = value !== undefined && typeof value === \"number\" && !isNaN(value) ? String(value) : \"\";\n\t\tsyncRawValue(nextRaw);\n\t}, [value]);\n\n\tconst handleClear = onClear\n\t\t? () => {\n\t\t\t\tsetRawValue(\"\");\n\t\t\t\t// setInternalInvalid(false);\n\t\t\t\tonClear();\n\t\t\t}\n\t\t: undefined;\n\n\tconst handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst raw = e.target.value;\n\t\tsetRawValue(raw);\n\n\t\tconst parsed = toFiniteNumber(raw) ?? value ?? 0;\n\t\t// const isEmpty = raw.trim() === \"\";\n\n\t\t// const minNum = min !== undefined ? Number(min) : undefined;\n\t\t// const maxNum = max !== undefined ? Number(max) : undefined;\n\t\t// const isValidNumber = !isEmpty && !isNaN(parsed);\n\t\t// const isInRange = isValidNumber && (minNum === undefined || parsed >= minNum) && (maxNum === undefined || parsed <= maxNum);\n\n\t\t// setInternalInvalid(!isEmpty && (!isValidNumber || !isInRange));\n\n\t\tonChange?.(parsed);\n\t\tif (error && onClearError) onClearError();\n\t};\n\n\t// const isInvalid = !!error || internalInvalid;\n\tconst resolvedEndAdornment = createEndAdornment({ endAdornment, onClear: handleClear, disabled });\n\tconst hasCustomAdornment = endAdornment !== undefined && endAdornment !== null;\n\tconst resolvedEndAdornmentWidth = resolveEndAdornmentWidth(hasCustomAdornment, !!handleClear, endAdornmentWidth);\n\n\treturn (\n\t\t<InputUI\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tclassName={className}\n\t\t\tsize={size}\n\t\t\terror={error}\n\t\t\tcontrolId={controlId}\n\t\t\tlabelId={labelId}\n\t\t\tdescriptionId={descriptionId}\n\t\t\terrorId={errorId}>\n\t\t\t<InputControl\n\t\t\t\tendAdornment={resolvedEndAdornment}\n\t\t\t\tendAdornmentClassName={endAdornmentClassName}\n\t\t\t\tendAdornmentWidth={resolvedEndAdornmentWidth}>\n\t\t\t\t{({ controlClassName }) => (\n\t\t\t\t\t<input\n\t\t\t\t\t\t{...inputProps}\n\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tinputMode=\"decimal\"\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tvalue={rawValue}\n\t\t\t\t\t\t// aria-invalid={isInvalid || undefined}\n\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\tclassName={cn(uiStyles.uiInputControl, styles.input, styles.inputNumber, controlClassName)}\n\t\t\t\t\t\tonChange={handleInput}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</InputControl>\n\t\t</InputUI>\n\t);\n}\n\n/**\n * Совместимый алиас для `InputText`.\n */\nexport const Input = InputText;\n"],"mappings":"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"}
@@ -0,0 +1,182 @@
1
+ import { t as e } from "./ui.module-BisoTevy.js";
2
+ import { a as t, c as n, d as r, f as i, i as a, l as o, o as s, r as c, t as ee, u as te } from "./picker-Dg55Ss-B.js";
3
+ import { useRef as ne, useState as l } from "react";
4
+ import { cn as u } from "@ryuzaki13/react-foundation-lib/utils";
5
+ import { CheckIcon as re, XIcon as ie } from "lucide-react";
6
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
7
+ //#region src/select/lib/getOptionSearchText.ts
8
+ function m({ option: e, getOptionLabel: t, getOptionCode: n }) {
9
+ return [s(t(e)), s(n?.(e))].filter((e) => !!e).join(" ").toLowerCase();
10
+ }
11
+ function h(e, t, n) {
12
+ return e.find((e) => e.value === t) ?? n;
13
+ }
14
+ var g = {
15
+ inputWithOverlay: "aEEqH1",
16
+ valueOverlay: "_4HQKa7"
17
+ };
18
+ //#endregion
19
+ //#region src/select/Select.tsx
20
+ function _(h) {
21
+ let { label: _, description: ae, disabled: v, placeholder: y, size: oe, options: b, value: x, onChange: S, getOptionKey: C, getOptionLabel: w, getOptionCode: T, getOptionDisabled: E, getOptionAriaLabel: se, getOptionClassName: ce, renderOption: D, renderValue: O, className: le, buttonClassName: ue, optionsClassName: de, optionsContentClassName: fe, searchable: k = !1, defaultFilter: pe = !0, query: me, defaultQuery: he, onQuery: ge, renderPopupHeader: A, emptyState: j, loadingState: M, errorState: N, placement: P = "bottom-start", clearable: F = !1 } = h, I = S, L = ne(null), [R, _e] = l(!1), z = k ? "search-single" : "display", B = x === void 0 ? void 0 : C(x), V = B === void 0 ? void 0 : b.find((e) => C(e) === B) ?? x, { query: H, setQuery: U } = c({
22
+ open: R,
23
+ query: me,
24
+ defaultQuery: he,
25
+ onQuery: ge,
26
+ triggerMode: z
27
+ }), W = t({
28
+ options: b,
29
+ query: H,
30
+ enabled: k && pe,
31
+ getSearchText: (e) => m({
32
+ option: e,
33
+ getOptionLabel: w,
34
+ getOptionCode: T
35
+ })
36
+ }), { activeIndex: ve, context: ye, floatingStyles: be, getFloatingProps: xe, setReference: Se, setFloating: Ce, setOptionRef: we, close: G, openList: Te, toggleOpen: Ee, selectOption: De, selectActiveOption: Oe, handleReferenceKeyDown: ke, handleFloatingKeyDown: Ae, getOptionId: je, getActiveOptionId: K } = a({
37
+ options: W,
38
+ selectedIndex: B === void 0 ? -1 : W.findIndex((e) => C(e) === B),
39
+ open: R,
40
+ onOpenChange: _e,
41
+ getOptionDisabled: E,
42
+ onSelect: I,
43
+ disabled: v,
44
+ placement: P,
45
+ triggerMode: z
46
+ }), q = W.length > 0, J = V === void 0 ? void 0 : w(V), Y = V === void 0 ? void 0 : O ? O(V) : J, Me = s(J), Ne = V === void 0 ? void 0 : s(T?.(V)), X = s(Y) ?? Me ?? Ne ?? (B === void 0 ? "" : String(B)), Z = k && (R || H.length > 0), Pe = Z ? H : V === void 0 ? "" : X, Q = V !== void 0 && Y !== void 0 && s(Y) === void 0 && !Z, $ = ee({
47
+ mode: z,
48
+ open: R,
49
+ currentQuery: H,
50
+ hasDisplayValue: V !== void 0,
51
+ inputRef: L,
52
+ setQuery: U,
53
+ openList: Te,
54
+ close: G,
55
+ toggleOpen: Ee
56
+ }), Fe = (e) => {
57
+ L.current = e;
58
+ }, Ie = () => {
59
+ F && I(void 0), U(""), G();
60
+ };
61
+ return /* @__PURE__ */ f(i, {
62
+ label: _,
63
+ description: ae,
64
+ disabled: v,
65
+ placeholder: y,
66
+ size: oe,
67
+ className: le,
68
+ children: ({ controlId: t, labelId: i, describedBy: a }) => {
69
+ let s = `${t}-listbox`;
70
+ return /* @__PURE__ */ p(d, { children: [/* @__PURE__ */ f(n, {
71
+ ref: Fe,
72
+ rootRef: Se,
73
+ id: t,
74
+ type: "text",
75
+ disabled: v,
76
+ readOnly: !k,
77
+ autoComplete: "off",
78
+ role: "combobox",
79
+ value: Pe,
80
+ placeholder: V === void 0 || Z ? y : void 0,
81
+ "aria-labelledby": i,
82
+ "aria-describedby": a,
83
+ "aria-haspopup": "listbox",
84
+ "aria-expanded": R,
85
+ "aria-controls": R ? s : void 0,
86
+ "aria-autocomplete": k ? "list" : "none",
87
+ "aria-activedescendant": R ? K(s) : void 0,
88
+ inputClassName: u(Q && g.inputWithOverlay, ue, "textOverflow"),
89
+ overlay: Q ? /* @__PURE__ */ f("div", {
90
+ className: g.valueOverlay,
91
+ children: Y
92
+ }) : void 0,
93
+ endAdornment: /* @__PURE__ */ f(o, {
94
+ open: R,
95
+ disabled: v,
96
+ onToggleMouseDown: $.handleToggleMouseDown,
97
+ onToggleClick: $.handleToggleClick,
98
+ children: F && V !== void 0 && !v ? /* @__PURE__ */ f("button", {
99
+ type: "button",
100
+ className: e.uiClearButton,
101
+ "data-ui": "select-clear-button",
102
+ "data-action": "clear-select",
103
+ onMouseDown: (e) => {
104
+ e.preventDefault(), e.stopPropagation();
105
+ },
106
+ onClick: (e) => {
107
+ e.preventDefault(), e.stopPropagation(), Ie();
108
+ },
109
+ "aria-label": "Очистить выбор",
110
+ children: /* @__PURE__ */ f(ie, {})
111
+ }) : null
112
+ }),
113
+ onChange: (e) => {
114
+ k && $.handleTriggerInputChange(e.target.value);
115
+ },
116
+ onClick: $.handleTriggerClick,
117
+ onFocus: (e) => {
118
+ $.handleTriggerFocus(e.currentTarget);
119
+ },
120
+ onKeyDown: (e) => {
121
+ ke(e), !e.defaultPrevented && $.handleTriggerKeyDown({
122
+ event: e,
123
+ onActivateWhenOpen: Oe,
124
+ enableSpaceActivation: !k
125
+ });
126
+ }
127
+ }), /* @__PURE__ */ f(r, {
128
+ open: R,
129
+ context: ye,
130
+ floatingStyles: be,
131
+ listId: s,
132
+ labelId: i,
133
+ descriptionId: a,
134
+ activeOptionId: q ? K(s) : void 0,
135
+ setFloating: Ce,
136
+ getFloatingProps: xe,
137
+ onKeyDown: Ae,
138
+ className: u(e.uiPopupOptions, de),
139
+ header: A,
140
+ children: /* @__PURE__ */ f("div", {
141
+ className: u(fe, "h100 scrollable"),
142
+ children: q ? W.map((t, n) => {
143
+ let r = C(t), i = B !== void 0 && r === B, a = n === ve, o = E?.(t) ?? !1, c = {
144
+ active: a,
145
+ selected: i,
146
+ disabled: o
147
+ };
148
+ return /* @__PURE__ */ f("div", {
149
+ id: je(s, n),
150
+ ref: (e) => we(n, e),
151
+ role: "option",
152
+ "aria-selected": i,
153
+ "aria-disabled": o || void 0,
154
+ "aria-label": se?.(t),
155
+ className: u(e.uiPopupOption, o && e.disabled, a && e.uiPopupOptionActive, i && e.selected, ce?.(t, c)),
156
+ onClick: () => De(t),
157
+ children: D ? D(t, c) : /* @__PURE__ */ p(d, { children: [
158
+ f(i ? re : "span", { className: e.uiPopupOptionIcon }),
159
+ /* @__PURE__ */ f("div", {
160
+ className: e.uiOptionText,
161
+ children: w(t)
162
+ }),
163
+ T && /* @__PURE__ */ f("div", {
164
+ className: e.uiOptionCode,
165
+ children: T(t)
166
+ })
167
+ ] })
168
+ }, r);
169
+ }) : /* @__PURE__ */ f(te, {
170
+ emptyState: j,
171
+ loadingState: M,
172
+ errorState: N
173
+ })
174
+ })
175
+ })] });
176
+ }
177
+ });
178
+ }
179
+ //#endregion
180
+ export { h as n, _ as t };
181
+
182
+ //# sourceMappingURL=Select-BJ5OqTe7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select-BJ5OqTe7.js","names":[],"sources":["../../src/select/lib/getOptionSearchText.ts","../../src/select/Select.module.scss","../../src/select/Select.tsx"],"sourcesContent":["import { ReactNode } from \"react\";\n\nimport { InputType } from \"@ryuzaki13/react-foundation-lib/types\";\n\nimport { extractPickerTextContent } from \"../../picker\";\n\nexport function getOptionSearchText<T extends InputType>({\n\toption,\n\tgetOptionLabel,\n\tgetOptionCode\n}: {\n\toption: T;\n\tgetOptionLabel: (option: T) => ReactNode;\n\tgetOptionCode?: (option: T) => ReactNode;\n}) {\n\treturn [extractPickerTextContent(getOptionLabel(option)), extractPickerTextContent(getOptionCode?.(option))]\n\t\t.filter((part): part is string => Boolean(part))\n\t\t.join(\" \")\n\t\t.toLowerCase();\n}\n\n/** Находит selected option по value и возвращает fallback, если значение еще не нормализовано. */\nexport function resolveSelectedOption<TOption extends { value: string }>(\n\toptions: readonly TOption[],\n\tvalue: string,\n\tfallback: TOption\n): TOption {\n\treturn options.find((option) => option.value === value) ?? fallback;\n}\n",".inputWithOverlay {\n\tcolor: transparent;\n\tcaret-color: transparent;\n}\n\n.valueOverlay {\n\tposition: absolute;\n\tinset: 0 calc(var(--control-height) + var(--space-xs)) 0 var(--space-md);\n\tdisplay: flex;\n\talign-items: center;\n\tpointer-events: none;\n\toverflow: hidden;\n}\n","import { ReactNode, useRef, useState } from \"react\";\n\nimport { Placement } from \"@floating-ui/react\";\nimport { InputType } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { CheckIcon, XIcon } from \"lucide-react\";\n\nimport {\n\textractPickerTextContent,\n\tPickerField,\n\tPickerPopup,\n\tPickerStatus,\n\tPickerTriggerActions,\n\tPickerTriggerInput,\n\tusePickerDefaultFilter,\n\tusePickerFloatingListbox,\n\tusePickerQuery,\n\tusePickerTriggerController\n} from \"../picker\";\nimport { ChangeHandler, UiBaseProps } from \"../types\";\nimport uiStyles from \"../ui.module.scss\";\n\nimport { getOptionSearchText } from \"./lib\";\nimport styles from \"./Select.module.scss\";\n\nexport type SelectOptionKey = string | number;\n\nexport type SelectOptionState = {\n\tactive: boolean;\n\tselected: boolean;\n\tdisabled: boolean;\n};\n\ntype SelectSharedProps<TOption extends InputType> = Omit<UiBaseProps<TOption, TOption | undefined>, \"onChange\"> & {\n\toptions: readonly TOption[];\n\tgetOptionKey: (option: TOption) => SelectOptionKey;\n\tgetOptionLabel: (option: TOption) => ReactNode;\n\tgetOptionCode?: (option: TOption) => ReactNode;\n\tgetOptionDisabled?: (option: TOption) => boolean;\n\tgetOptionAriaLabel?: (option: TOption) => string;\n\tgetOptionClassName?: (option: TOption, state: SelectOptionState) => string | undefined;\n\trenderOption?: (option: TOption, state: SelectOptionState) => ReactNode;\n\trenderValue?: (option: TOption) => ReactNode;\n\tclassName?: string;\n\tbuttonClassName?: string;\n\toptionsClassName?: string;\n\toptionsContentClassName?: string;\n\tsearchable?: boolean;\n\tquery?: string;\n\tdefaultQuery?: string;\n\tonQuery?: (value: string) => void;\n\tdefaultFilter?: boolean;\n\trenderPopupHeader?: ReactNode;\n\temptyState?: ReactNode;\n\tloadingState?: ReactNode;\n\terrorState?: ReactNode;\n\tplacement?: Placement;\n};\n\ntype SelectChangeValue<TOption extends InputType, TClearable extends boolean | undefined> = true extends TClearable\n\t? TOption | undefined\n\t: TOption;\n\nexport type SelectProps<TOption extends InputType, TClearable extends boolean | undefined = false> = SelectSharedProps<TOption> & {\n\tclearable?: TClearable;\n\tonChange: ChangeHandler<SelectChangeValue<TOption, TClearable>>;\n};\n\n/**\n * Выпадающий список выбора значения из набора опций. Подходит для форм, фильтров и простых справочников.\n */\nexport function Select<TOption extends InputType, TClearable extends boolean | undefined = false>(props: SelectProps<TOption, TClearable>) {\n\tconst {\n\t\tlabel,\n\t\tdescription,\n\t\tdisabled,\n\t\tplaceholder,\n\t\tsize,\n\t\toptions,\n\t\tvalue,\n\t\tonChange,\n\t\tgetOptionKey,\n\t\tgetOptionLabel,\n\t\tgetOptionCode,\n\t\tgetOptionDisabled,\n\t\tgetOptionAriaLabel,\n\t\tgetOptionClassName,\n\t\trenderOption,\n\t\trenderValue,\n\t\tclassName,\n\t\tbuttonClassName,\n\t\toptionsClassName,\n\t\toptionsContentClassName,\n\t\tsearchable = false,\n\t\tdefaultFilter = true,\n\t\tquery,\n\t\tdefaultQuery,\n\t\tonQuery,\n\t\trenderPopupHeader,\n\t\temptyState,\n\t\tloadingState,\n\t\terrorState,\n\t\tplacement = \"bottom-start\",\n\t\tclearable = false\n\t} = props;\n\tconst emitChange = onChange as ChangeHandler<TOption | undefined>;\n\n\tconst inputRef = useRef<HTMLInputElement | null>(null);\n\tconst [open, setOpen] = useState(false);\n\tconst triggerMode = searchable ? \"search-single\" : \"display\";\n\tconst selectedKey = value === undefined ? undefined : getOptionKey(value);\n\tconst selectedOption =\n\t\tselectedKey === undefined ? undefined : (options.find((option) => getOptionKey(option) === selectedKey) ?? value);\n\tconst { query: currentQuery, setQuery } = usePickerQuery({\n\t\topen,\n\t\tquery,\n\t\tdefaultQuery,\n\t\tonQuery,\n\t\ttriggerMode\n\t});\n\tconst visibleOptions = usePickerDefaultFilter({\n\t\toptions,\n\t\tquery: currentQuery,\n\t\tenabled: searchable && defaultFilter,\n\t\tgetSearchText: (option) =>\n\t\t\tgetOptionSearchText({\n\t\t\t\toption,\n\t\t\t\tgetOptionLabel,\n\t\t\t\tgetOptionCode\n\t\t\t})\n\t});\n\tconst selectedIndex = selectedKey === undefined ? -1 : visibleOptions.findIndex((option) => getOptionKey(option) === selectedKey);\n\tconst {\n\t\tactiveIndex,\n\t\tcontext,\n\t\tfloatingStyles,\n\t\tgetFloatingProps,\n\t\tsetReference,\n\t\tsetFloating,\n\t\tsetOptionRef,\n\t\tclose,\n\t\topenList,\n\t\ttoggleOpen,\n\t\tselectOption,\n\t\tselectActiveOption,\n\t\thandleReferenceKeyDown,\n\t\thandleFloatingKeyDown,\n\t\tgetOptionId,\n\t\tgetActiveOptionId\n\t} = usePickerFloatingListbox({\n\t\toptions: visibleOptions,\n\t\tselectedIndex,\n\t\topen,\n\t\tonOpenChange: setOpen,\n\t\tgetOptionDisabled,\n\t\tonSelect: emitChange,\n\t\tdisabled,\n\t\tplacement,\n\t\ttriggerMode\n\t});\n\n\tconst hasOptions = visibleOptions.length > 0;\n\tconst labelContent = selectedOption !== undefined ? getOptionLabel(selectedOption) : undefined;\n\tconst displayContent = selectedOption !== undefined ? (renderValue ? renderValue(selectedOption) : labelContent) : undefined;\n\tconst labelText = extractPickerTextContent(labelContent);\n\tconst codeText = selectedOption !== undefined ? extractPickerTextContent(getOptionCode?.(selectedOption)) : undefined;\n\tconst displayText =\n\t\textractPickerTextContent(displayContent) ?? labelText ?? codeText ?? (selectedKey !== undefined ? String(selectedKey) : \"\");\n\tconst showSearchValue = searchable && (open || currentQuery.length > 0);\n\tconst inputValue = showSearchValue ? currentQuery : selectedOption !== undefined ? displayText : \"\";\n\tconst showDisplayOverlay =\n\t\tselectedOption !== undefined &&\n\t\tdisplayContent !== undefined &&\n\t\textractPickerTextContent(displayContent) === undefined &&\n\t\t!showSearchValue;\n\tconst triggerController = usePickerTriggerController({\n\t\tmode: triggerMode,\n\t\topen,\n\t\tcurrentQuery,\n\t\thasDisplayValue: selectedOption !== undefined,\n\t\tinputRef,\n\t\tsetQuery,\n\t\topenList,\n\t\tclose,\n\t\ttoggleOpen\n\t});\n\tconst setInputNode = (node: HTMLInputElement | null) => {\n\t\tinputRef.current = node;\n\t};\n\tconst handleClear = () => {\n\t\tif (clearable) {\n\t\t\temitChange(undefined);\n\t\t}\n\n\t\tsetQuery(\"\");\n\t\tclose();\n\t};\n\n\treturn (\n\t\t<PickerField\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tplaceholder={placeholder}\n\t\t\tsize={size}\n\t\t\tclassName={className}>\n\t\t\t{({ controlId, labelId, describedBy }) => {\n\t\t\t\tconst listId = `${controlId}-listbox`;\n\n\t\t\t\treturn (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<PickerTriggerInput\n\t\t\t\t\t\t\tref={setInputNode}\n\t\t\t\t\t\t\trootRef={setReference}\n\t\t\t\t\t\t\tid={controlId}\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\treadOnly={!searchable}\n\t\t\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t\t\trole=\"combobox\"\n\t\t\t\t\t\t\tvalue={inputValue}\n\t\t\t\t\t\t\tplaceholder={selectedOption === undefined || showSearchValue ? placeholder : undefined}\n\t\t\t\t\t\t\taria-labelledby={labelId}\n\t\t\t\t\t\t\taria-describedby={describedBy}\n\t\t\t\t\t\t\taria-haspopup=\"listbox\"\n\t\t\t\t\t\t\taria-expanded={open}\n\t\t\t\t\t\t\taria-controls={open ? listId : undefined}\n\t\t\t\t\t\t\taria-autocomplete={searchable ? \"list\" : \"none\"}\n\t\t\t\t\t\t\taria-activedescendant={open ? getActiveOptionId(listId) : undefined}\n\t\t\t\t\t\t\tinputClassName={cn(showDisplayOverlay && styles.inputWithOverlay, buttonClassName, \"textOverflow\")}\n\t\t\t\t\t\t\toverlay={showDisplayOverlay ? <div className={styles.valueOverlay}>{displayContent}</div> : undefined}\n\t\t\t\t\t\t\tendAdornment={\n\t\t\t\t\t\t\t\t<PickerTriggerActions\n\t\t\t\t\t\t\t\t\topen={open}\n\t\t\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t\t\t\tonToggleMouseDown={triggerController.handleToggleMouseDown}\n\t\t\t\t\t\t\t\t\tonToggleClick={triggerController.handleToggleClick}>\n\t\t\t\t\t\t\t\t\t{clearable && selectedOption !== undefined && !disabled ? (\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={uiStyles.uiClearButton}\n\t\t\t\t\t\t\t\t\t\t\tdata-ui=\"select-clear-button\"\n\t\t\t\t\t\t\t\t\t\t\tdata-action=\"clear-select\"\n\t\t\t\t\t\t\t\t\t\t\tonMouseDown={(event) => {\n\t\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t\t\t\t\t\t\thandleClear();\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\taria-label=\"Очистить выбор\">\n\t\t\t\t\t\t\t\t\t\t\t<XIcon />\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</PickerTriggerActions>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\t\t\tif (!searchable) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttriggerController.handleTriggerInputChange(event.target.value);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonClick={triggerController.handleTriggerClick}\n\t\t\t\t\t\t\tonFocus={(event) => {\n\t\t\t\t\t\t\t\ttriggerController.handleTriggerFocus(event.currentTarget);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tonKeyDown={(event) => {\n\t\t\t\t\t\t\t\thandleReferenceKeyDown(event);\n\n\t\t\t\t\t\t\t\tif (event.defaultPrevented) {\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\ttriggerController.handleTriggerKeyDown({\n\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\tonActivateWhenOpen: selectActiveOption,\n\t\t\t\t\t\t\t\t\tenableSpaceActivation: !searchable\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t<PickerPopup\n\t\t\t\t\t\t\topen={open}\n\t\t\t\t\t\t\tcontext={context}\n\t\t\t\t\t\t\tfloatingStyles={floatingStyles}\n\t\t\t\t\t\t\tlistId={listId}\n\t\t\t\t\t\t\tlabelId={labelId}\n\t\t\t\t\t\t\tdescriptionId={describedBy}\n\t\t\t\t\t\t\tactiveOptionId={hasOptions ? getActiveOptionId(listId) : undefined}\n\t\t\t\t\t\t\tsetFloating={setFloating}\n\t\t\t\t\t\t\tgetFloatingProps={getFloatingProps}\n\t\t\t\t\t\t\tonKeyDown={handleFloatingKeyDown}\n\t\t\t\t\t\t\tclassName={cn(uiStyles.uiPopupOptions, optionsClassName)}\n\t\t\t\t\t\t\theader={renderPopupHeader}>\n\t\t\t\t\t\t\t<div className={cn(optionsContentClassName, \"h100 scrollable\")}>\n\t\t\t\t\t\t\t\t{hasOptions ? (\n\t\t\t\t\t\t\t\t\tvisibleOptions.map((option, index) => {\n\t\t\t\t\t\t\t\t\t\tconst optionKey = getOptionKey(option);\n\t\t\t\t\t\t\t\t\t\tconst selected = selectedKey !== undefined && optionKey === selectedKey;\n\t\t\t\t\t\t\t\t\t\tconst active = index === activeIndex;\n\t\t\t\t\t\t\t\t\t\tconst optionDisabled = getOptionDisabled?.(option) ?? false;\n\t\t\t\t\t\t\t\t\t\tconst optionState = { active, selected, disabled: optionDisabled };\n\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tkey={optionKey}\n\t\t\t\t\t\t\t\t\t\t\t\tid={getOptionId(listId, index)}\n\t\t\t\t\t\t\t\t\t\t\t\tref={(node) => setOptionRef(index, node)}\n\t\t\t\t\t\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-selected={selected}\n\t\t\t\t\t\t\t\t\t\t\t\taria-disabled={optionDisabled || undefined}\n\t\t\t\t\t\t\t\t\t\t\t\taria-label={getOptionAriaLabel?.(option)}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\tuiStyles.uiPopupOption,\n\t\t\t\t\t\t\t\t\t\t\t\t\toptionDisabled && uiStyles.disabled,\n\t\t\t\t\t\t\t\t\t\t\t\t\tactive && uiStyles.uiPopupOptionActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\tselected && uiStyles.selected,\n\t\t\t\t\t\t\t\t\t\t\t\t\tgetOptionClassName?.(option, optionState)\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => selectOption(option)}>\n\t\t\t\t\t\t\t\t\t\t\t\t{renderOption ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\trenderOption(option, optionState)\n\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{selected ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CheckIcon className={uiStyles.uiPopupOptionIcon} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span className={uiStyles.uiPopupOptionIcon} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className={uiStyles.uiOptionText}>{getOptionLabel(option)}</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{getOptionCode && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className={uiStyles.uiOptionCode}>{getOptionCode(option)}</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<PickerStatus emptyState={emptyState} loadingState={loadingState} errorState={errorState} />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</PickerPopup>\n\t\t\t\t\t</>\n\t\t\t\t);\n\t\t\t}}\n\t\t</PickerField>\n\t);\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,EAAyC,EACxD,WACA,mBACA,oBAKE;CACF,OAAO,CAAC,EAAyB,EAAe,CAAM,CAAC,GAAG,EAAyB,IAAgB,CAAM,CAAC,CAAC,CAAC,CAC1G,QAAQ,MAAyB,EAAQ,CAAK,CAAC,CAC/C,KAAK,GAAG,CAAC,CACT,YAAY;AACf;AAGA,SAAgB,EACf,GACA,GACA,GACU;CACV,OAAO,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAK,KAAK;AAC5D;;;;;;;AE2CA,SAAgB,EAAkF,GAAyC;CAC1I,IAAM,EACL,UACA,iBACA,aACA,gBACA,UACA,YACA,UACA,aACA,iBACA,mBACA,kBACA,sBACA,wBACA,wBACA,iBACA,gBACA,eACA,qBACA,sBACA,6BACA,gBAAa,IACb,oBAAgB,IAChB,WACA,kBACA,aACA,sBACA,eACA,iBACA,eACA,eAAY,gBACZ,eAAY,OACT,GACE,IAAa,GAEb,IAAW,GAAgC,IAAI,GAC/C,CAAC,GAAM,MAAW,EAAS,EAAK,GAChC,IAAc,IAAa,kBAAkB,WAC7C,IAAc,MAAU,KAAA,IAAY,KAAA,IAAY,EAAa,CAAK,GAClE,IACL,MAAgB,KAAA,IAAY,KAAA,IAAa,EAAQ,MAAM,MAAW,EAAa,CAAM,MAAM,CAAW,KAAK,GACtG,EAAE,OAAO,GAAc,gBAAa,EAAe;EACxD;EACA;EACA;EACA;EACA;CACD,CAAC,GACK,IAAiB,EAAuB;EAC7C;EACA,OAAO;EACP,SAAS,KAAc;EACvB,gBAAgB,MACf,EAAoB;GACnB;GACA;GACA;EACD,CAAC;CACH,CAAC,GAEK,EACL,iBACA,aACA,oBACA,sBACA,kBACA,iBACA,kBACA,UACA,cACA,gBACA,kBACA,wBACA,4BACA,2BACA,iBACA,yBACG,EAAyB;EAC5B,SAAS;EACT,eApBqB,MAAgB,KAAA,IAAY,KAAK,EAAe,WAAW,MAAW,EAAa,CAAM,MAAM,CAAW;EAqB/H;EACA,cAAc;EACd;EACA,UAAU;EACV;EACA;EACA;CACD,CAAC,GAEK,IAAa,EAAe,SAAS,GACrC,IAAe,MAAmB,KAAA,IAA6C,KAAA,IAAjC,EAAe,CAAc,GAC3E,IAAiB,MAAmB,KAAA,IAAyE,KAAA,IAA5D,IAAc,EAAY,CAAc,IAAI,GAC7F,KAAY,EAAyB,CAAY,GACjD,KAAW,MAAmB,KAAA,IAAwE,KAAA,IAA5D,EAAyB,IAAgB,CAAc,CAAC,GAClG,IACL,EAAyB,CAAc,KAAK,MAAa,OAAa,MAAgB,KAAA,IAAkC,KAAtB,OAAO,CAAW,IAC/G,IAAkB,MAAe,KAAQ,EAAa,SAAS,IAC/D,KAAa,IAAkB,IAAe,MAAmB,KAAA,IAA0B,KAAd,GAC7E,IACL,MAAmB,KAAA,KACnB,MAAmB,KAAA,KACnB,EAAyB,CAAc,MAAM,KAAA,KAC7C,CAAC,GACI,IAAoB,GAA2B;EACpD,MAAM;EACN;EACA;EACA,iBAAiB,MAAmB,KAAA;EACpC;EACA;EACA;EACA;EACA;CACD,CAAC,GACK,MAAgB,MAAkC;EACvD,EAAS,UAAU;CACpB,GACM,WAAoB;EAMzB,AALI,KACH,EAAW,KAAA,CAAS,GAGrB,EAAS,EAAE,GACX,EAAM;CACP;CAEA,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACG;EACP;EACK;aACT,EAAE,cAAW,YAAS,qBAAkB;GACzC,IAAM,IAAS,GAAG,EAAU;GAE5B,OACC,kBAAA,GAAA,EAAA,UAAA,CACC,kBAAC,GAAD;IACC,KAAK;IACL,SAAS;IACT,IAAI;IACJ,MAAK;IACK;IACV,UAAU,CAAC;IACX,cAAa;IACb,MAAK;IACL,OAAO;IACP,aAAa,MAAmB,KAAA,KAAa,IAAkB,IAAc,KAAA;IAC7E,mBAAiB;IACjB,oBAAkB;IAClB,iBAAc;IACd,iBAAe;IACf,iBAAe,IAAO,IAAS,KAAA;IAC/B,qBAAmB,IAAa,SAAS;IACzC,yBAAuB,IAAO,EAAkB,CAAM,IAAI,KAAA;IAC1D,gBAAgB,EAAG,KAAsB,EAAO,kBAAkB,IAAiB,cAAc;IACjG,SAAS,IAAqB,kBAAC,OAAD;KAAK,WAAW,EAAO;eAAe;IAAoB,CAAA,IAAI,KAAA;IAC5F,cACC,kBAAC,GAAD;KACO;KACI;KACV,mBAAmB,EAAkB;KACrC,eAAe,EAAkB;eAChC,KAAa,MAAmB,KAAA,KAAa,CAAC,IAC9C,kBAAC,UAAD;MACC,MAAK;MACL,WAAW,EAAS;MACpB,WAAQ;MACR,eAAY;MACZ,cAAc,MAAU;OAEvB,AADA,EAAM,eAAe,GACrB,EAAM,gBAAgB;MACvB;MACA,UAAU,MAAU;OAGnB,AAFA,EAAM,eAAe,GACrB,EAAM,gBAAgB,GACtB,GAAY;MACb;MACA,cAAW;gBACX,kBAAC,IAAD,CAAQ,CAAA;KACD,CAAA,IACL;IACiB,CAAA;IAEvB,WAAW,MAAU;KACf,KAIL,EAAkB,yBAAyB,EAAM,OAAO,KAAK;IAC9D;IACA,SAAS,EAAkB;IAC3B,UAAU,MAAU;KACnB,EAAkB,mBAAmB,EAAM,aAAa;IACzD;IACA,YAAY,MAAU;KACrB,GAAuB,CAAK,GAExB,GAAM,oBAIV,EAAkB,qBAAqB;MACtC;MACA,oBAAoB;MACpB,uBAAuB,CAAC;KACzB,CAAC;IACF;GACA,CAAA,GAED,kBAAC,GAAD;IACO;IACG;IACO;IACR;IACC;IACT,eAAe;IACf,gBAAgB,IAAa,EAAkB,CAAM,IAAI,KAAA;IAC5C;IACK;IAClB,WAAW;IACX,WAAW,EAAG,EAAS,gBAAgB,EAAgB;IACvD,QAAQ;cACR,kBAAC,OAAD;KAAK,WAAW,EAAG,IAAyB,iBAAiB;eAC3D,IACA,EAAe,KAAK,GAAQ,MAAU;MACrC,IAAM,IAAY,EAAa,CAAM,GAC/B,IAAW,MAAgB,KAAA,KAAa,MAAc,GACtD,IAAS,MAAU,IACnB,IAAiB,IAAoB,CAAM,KAAK,IAChD,IAAc;OAAE;OAAQ;OAAU,UAAU;MAAe;MAEjE,OACC,kBAAC,OAAD;OAEC,IAAI,GAAY,GAAQ,CAAK;OAC7B,MAAM,MAAS,GAAa,GAAO,CAAI;OACvC,MAAK;OACL,iBAAe;OACf,iBAAe,KAAkB,KAAA;OACjC,cAAY,KAAqB,CAAM;OACvC,WAAW,EACV,EAAS,eACT,KAAkB,EAAS,UAC3B,KAAU,EAAS,qBACnB,KAAY,EAAS,UACrB,KAAqB,GAAQ,CAAW,CACzC;OACA,eAAe,GAAa,CAAM;iBACjC,IACA,EAAa,GAAQ,CAAW,IAEhC,kBAAA,GAAA,EAAA,UAAA;QAEE,EADA,IACC,KAEA,QAFD,EAAW,WAAW,EAAS,kBAAoB,CAEL;QAE/C,kBAAC,OAAD;SAAK,WAAW,EAAS;mBAAe,EAAe,CAAM;QAAO,CAAA;QACnE,KACA,kBAAC,OAAD;SAAK,WAAW,EAAS;mBAAe,EAAc,CAAM;QAAO,CAAA;OAEnE,EAAA,CAAA;MAEC,GA9BC,CA8BD;KAEP,CAAC,IAED,kBAAC,IAAD;MAA0B;MAA0B;MAA0B;KAAa,CAAA;IAExF,CAAA;GACO,CAAA,CACZ,EAAA,CAAA;EAEJ;CACY,CAAA;AAEf"}
@@ -1,4 +1,4 @@
1
- import { t as e } from "./Select-CXeVjVKA.js";
1
+ import { t as e } from "./Select-BJ5OqTe7.js";
2
2
  import { jsx as t } from "react/jsx-runtime";
3
3
  //#region src/select/SerializableSelect.tsx
4
4
  function n(e, t) {
@@ -30,4 +30,4 @@ function i({ label: i, description: a, disabled: o, placeholder: s, size: c, opt
30
30
  //#endregion
31
31
  export { i as t };
32
32
 
33
- //# sourceMappingURL=SerializableSelect-DkYeJtAO.js.map
33
+ //# sourceMappingURL=SerializableSelect-CNe728Qa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SerializableSelect-DkYeJtAO.js","names":[],"sources":["../../src/select/SerializableSelect.tsx"],"sourcesContent":["import { Select } from \"./Select\";\n\nimport type { UiBaseProps } from \"../types\";\nimport type { SelectOptionKey } from \"./Select\";\n\ntype SerializableOptionRecord = Record<string, unknown>;\n\ntype SerializableOptionKeyField<TOption extends SerializableOptionRecord> = {\n\t[K in keyof TOption]: Extract<TOption[K], SelectOptionKey> extends never ? never : K;\n}[keyof TOption];\n\ntype SerializableOptionValue<TOption extends SerializableOptionRecord, TOptionKey extends SerializableOptionKeyField<TOption>> = Extract<\n\tTOption[TOptionKey],\n\tSelectOptionKey\n>;\n\nexport interface SerializableSelectProps<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n> extends Omit<UiBaseProps<SerializableOptionValue<TOption, TOptionKey> | undefined>, \"onChange\"> {\n\toptions: readonly TOption[];\n\tonChange: (value: SerializableOptionValue<TOption, TOptionKey> | undefined) => void;\n\toptionKey: TOptionKey;\n\toptionLabel: TOptionLabel;\n\trenderCode?: true;\n\tclassName?: string;\n\tclearable?: boolean;\n}\n\nfunction getSerializableOptionKey<TOption extends SerializableOptionRecord, TOptionKey extends SerializableOptionKeyField<TOption>>(\n\toption: TOption,\n\toptionKey: TOptionKey\n): Extract<TOption[TOptionKey], SelectOptionKey> {\n\treturn option[optionKey] as Extract<TOption[TOptionKey], SelectOptionKey>;\n}\n\nfunction getSerializableOptionLabel<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n>(option: TOption, optionLabel: TOptionLabel, optionKey: TOptionKey): string | number {\n\tconst label = option[optionLabel];\n\n\tif (typeof label === \"string\" || typeof label === \"number\") {\n\t\treturn label;\n\t}\n\n\tconst key = getSerializableOptionKey(option, optionKey);\n\treturn typeof key === \"string\" || typeof key === \"number\" ? key : String(key);\n}\n\nexport function SerializableSelect<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n>({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tplaceholder,\n\tsize,\n\toptions,\n\tvalue,\n\tonChange,\n\toptionKey,\n\toptionLabel,\n\trenderCode,\n\tclassName,\n\tclearable\n}: SerializableSelectProps<TOption, TOptionKey, TOptionLabel>) {\n\tconst selectedOption =\n\t\tvalue === undefined ? undefined : options.find((option) => getSerializableOptionKey(option, optionKey) === value);\n\n\treturn (\n\t\t<Select<TOption, TOption | undefined>\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tplaceholder={placeholder}\n\t\t\tsize={size}\n\t\t\toptions={options}\n\t\t\tvalue={selectedOption}\n\t\t\tonChange={(option) => onChange(option ? getSerializableOptionKey(option, optionKey) : undefined)}\n\t\t\tgetOptionKey={(option) => getSerializableOptionKey(option, optionKey)}\n\t\t\tgetOptionLabel={(option) => getSerializableOptionLabel(option, optionLabel, optionKey)}\n\t\t\tgetOptionCode={renderCode ? (option) => getSerializableOptionKey(option, optionKey) : undefined}\n\t\t\tclassName={className}\n\t\t\tclearable={clearable}\n\t\t/>\n\t);\n}\n"],"mappings":";;;AA8BA,SAAS,EACR,GACA,GACgD;CAChD,OAAO,EAAO;AACf;AAEA,SAAS,EAIP,GAAiB,GAA2B,GAAwC;CACrF,IAAM,IAAQ,EAAO;CAErB,IAAI,OAAO,KAAU,YAAY,OAAO,KAAU,UACjD,OAAO;CAGR,IAAM,IAAM,EAAyB,GAAQ,CAAS;CACtD,OAAO,OAAO,KAAQ,YAAY,OAAO,KAAQ,WAAW,IAAM,OAAO,CAAG;AAC7E;AAEA,SAAgB,EAId,EACD,UACA,gBACA,aACA,gBACA,SACA,YACA,UACA,aACA,cACA,gBACA,eACA,cACA,gBAC8D;CAI9D,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACG;EACP;EACG;EACT,OAVD,MAAU,KAAA,IAAY,KAAA,IAAY,EAAQ,MAAM,MAAW,EAAyB,GAAQ,CAAS,MAAM,CAAK;EAW/G,WAAW,MAAW,EAAS,IAAS,EAAyB,GAAQ,CAAS,IAAI,KAAA,CAAS;EAC/F,eAAe,MAAW,EAAyB,GAAQ,CAAS;EACpE,iBAAiB,MAAW,EAA2B,GAAQ,GAAa,CAAS;EACrF,eAAe,KAAc,MAAW,EAAyB,GAAQ,CAAS,IAAI,KAAA;EAC3E;EACA;CACX,CAAA;AAEH"}
1
+ {"version":3,"file":"SerializableSelect-CNe728Qa.js","names":[],"sources":["../../src/select/SerializableSelect.tsx"],"sourcesContent":["import { Select } from \"./Select\";\n\nimport type { UiBaseProps } from \"../types\";\nimport type { SelectOptionKey } from \"./Select\";\n\ntype SerializableOptionRecord = Record<string, unknown>;\n\ntype SerializableOptionKeyField<TOption extends SerializableOptionRecord> = {\n\t[K in keyof TOption]: Extract<TOption[K], SelectOptionKey> extends never ? never : K;\n}[keyof TOption];\n\ntype SerializableOptionValue<TOption extends SerializableOptionRecord, TOptionKey extends SerializableOptionKeyField<TOption>> = Extract<\n\tTOption[TOptionKey],\n\tSelectOptionKey\n>;\n\nexport interface SerializableSelectProps<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n> extends Omit<UiBaseProps<SerializableOptionValue<TOption, TOptionKey> | undefined>, \"onChange\"> {\n\toptions: readonly TOption[];\n\tonChange: (value: SerializableOptionValue<TOption, TOptionKey> | undefined) => void;\n\toptionKey: TOptionKey;\n\toptionLabel: TOptionLabel;\n\trenderCode?: true;\n\tclassName?: string;\n\tclearable?: boolean;\n}\n\nfunction getSerializableOptionKey<TOption extends SerializableOptionRecord, TOptionKey extends SerializableOptionKeyField<TOption>>(\n\toption: TOption,\n\toptionKey: TOptionKey\n): Extract<TOption[TOptionKey], SelectOptionKey> {\n\treturn option[optionKey] as Extract<TOption[TOptionKey], SelectOptionKey>;\n}\n\nfunction getSerializableOptionLabel<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n>(option: TOption, optionLabel: TOptionLabel, optionKey: TOptionKey): string | number {\n\tconst label = option[optionLabel];\n\n\tif (typeof label === \"string\" || typeof label === \"number\") {\n\t\treturn label;\n\t}\n\n\tconst key = getSerializableOptionKey(option, optionKey);\n\treturn typeof key === \"string\" || typeof key === \"number\" ? key : String(key);\n}\n\nexport function SerializableSelect<\n\tTOption extends SerializableOptionRecord,\n\tTOptionKey extends SerializableOptionKeyField<TOption>,\n\tTOptionLabel extends keyof TOption\n>({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tplaceholder,\n\tsize,\n\toptions,\n\tvalue,\n\tonChange,\n\toptionKey,\n\toptionLabel,\n\trenderCode,\n\tclassName,\n\tclearable\n}: SerializableSelectProps<TOption, TOptionKey, TOptionLabel>) {\n\tconst selectedOption =\n\t\tvalue === undefined ? undefined : options.find((option) => getSerializableOptionKey(option, optionKey) === value);\n\n\treturn (\n\t\t<Select\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tplaceholder={placeholder}\n\t\t\tsize={size}\n\t\t\toptions={options}\n\t\t\tvalue={selectedOption}\n\t\t\tonChange={(option: TOption | undefined) => onChange(option ? getSerializableOptionKey(option, optionKey) : undefined)}\n\t\t\tgetOptionKey={(option: TOption) => getSerializableOptionKey(option, optionKey)}\n\t\t\tgetOptionLabel={(option: TOption) => getSerializableOptionLabel(option, optionLabel, optionKey)}\n\t\t\tgetOptionCode={renderCode ? (option: TOption) => getSerializableOptionKey(option, optionKey) : undefined}\n\t\t\tclassName={className}\n\t\t\tclearable={clearable}\n\t\t/>\n\t);\n}\n"],"mappings":";;;AA8BA,SAAS,EACR,GACA,GACgD;CAChD,OAAO,EAAO;AACf;AAEA,SAAS,EAIP,GAAiB,GAA2B,GAAwC;CACrF,IAAM,IAAQ,EAAO;CAErB,IAAI,OAAO,KAAU,YAAY,OAAO,KAAU,UACjD,OAAO;CAGR,IAAM,IAAM,EAAyB,GAAQ,CAAS;CACtD,OAAO,OAAO,KAAQ,YAAY,OAAO,KAAQ,WAAW,IAAM,OAAO,CAAG;AAC7E;AAEA,SAAgB,EAId,EACD,UACA,gBACA,aACA,gBACA,SACA,YACA,UACA,aACA,cACA,gBACA,eACA,cACA,gBAC8D;CAI9D,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACG;EACP;EACG;EACT,OAVD,MAAU,KAAA,IAAY,KAAA,IAAY,EAAQ,MAAM,MAAW,EAAyB,GAAQ,CAAS,MAAM,CAAK;EAW/G,WAAW,MAAgC,EAAS,IAAS,EAAyB,GAAQ,CAAS,IAAI,KAAA,CAAS;EACpH,eAAe,MAAoB,EAAyB,GAAQ,CAAS;EAC7E,iBAAiB,MAAoB,EAA2B,GAAQ,GAAa,CAAS;EAC9F,eAAe,KAAc,MAAoB,EAAyB,GAAQ,CAAS,IAAI,KAAA;EACpF;EACA;CACX,CAAA;AAEH"}
@@ -1,4 +1,4 @@
1
- import { t as e } from "./Select-CXeVjVKA.js";
1
+ import { t as e } from "./Select-BJ5OqTe7.js";
2
2
  import { useMemo as t } from "react";
3
3
  import { cn as n } from "@ryuzaki13/react-foundation-lib/utils";
4
4
  import { DEFAULT_VALUE_STATES as r, VALUE_STATE_COLOR_TOKENS as i } from "@ryuzaki13/react-foundation-lib/formatters";
@@ -75,4 +75,4 @@ function m({ label: i, description: m, disabled: h, placeholder: g, size: _, val
75
75
  //#endregion
76
76
  export { m as t };
77
77
 
78
- //# sourceMappingURL=StateSelect-1jH3uLz9.js.map
78
+ //# sourceMappingURL=StateSelect-ujAre258.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StateSelect-1jH3uLz9.js","names":[],"sources":["../../src/state-select/StateSelect.module.scss","../../src/state-select/StateSelect.tsx"],"sourcesContent":[".button {\n\tpadding-left: var(--space-sm);\n}\n\n.valueContainer {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-sm);\n\twidth: 100%;\n\tmin-height: 1.5em;\n\tmin-width: 0;\n}\n\n.swatch {\n\t--state-color: transparent;\n\n\twidth: 1.25em;\n\theight: 1.25em;\n\tflex-shrink: 0;\n\tdisplay: inline-block;\n\tborder-radius: var(--radius-xs);\n\tborder: var(--border-width) solid var(--border-0);\n\tbackground-color: var(--state-color);\n\n\t&[data-empty] {\n\t\tbackground-color: var(--surface-0);\n\t\tbackground-image: repeating-linear-gradient(135deg, var(--border-0), var(--border-0) 0.25em, transparent 0.25em, transparent 0.5em);\n\t}\n}\n\n// .options {\n// \tpadding: var(--space-xs);\n// }\n\n.optionsPalette {\n\t--input-width: auto;\n\n\tdisplay: grid;\n\tgrid-template-columns: repeat(5, minmax(0, 1fr));\n\tgap: var(--space-xs);\n}\n\n.optionsDetailed {\n\t--input-width: 16em;\n}\n\n.option {\n\tborder-radius: var(--radius-sm);\n\toutline: none;\n\tuser-select: none;\n}\n\n.optionPalette {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: var(--space-sm);\n\tmin-width: 2.25em;\n}\n\n.optionDetailed {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n}\n\n.optionMeta {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tmin-width: 0;\n}\n\n.optionMetaIcon {\n\tdisplay: inline-flex;\n\talign-items: center;\n}\n\n.optionMetaLabel {\n\tmin-width: 0;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n}\n","import { CSSProperties, ReactNode, useMemo } from \"react\";\n\nimport { DEFAULT_VALUE_STATES, VALUE_STATE_COLOR_TOKENS } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { Select, SelectProps } from \"../select\";\nimport { UiBaseProps } from \"../types\";\n\nimport styles from \"./StateSelect.module.scss\";\n\nexport type StateMeta = {\n\tlabel?: ReactNode;\n\ticon?: ReactNode;\n};\n\nexport interface StateSelectProps extends Omit<UiBaseProps<State | undefined>, \"placeholder\"> {\n\tplaceholder?: string;\n\toptions?: readonly State[];\n\tstateMeta?: Partial<Record<State, StateMeta>>;\n\tclassName?: string;\n\tclearable?: boolean;\n}\n\ninterface StateSwatchProps {\n\tstate: State;\n\tclassName?: string;\n}\n\nfunction StateSwatch({ state, className }: StateSwatchProps) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(styles.swatch, className)}\n\t\t\tdata-empty={state === \"none\" ? \"\" : undefined}\n\t\t\tstyle={{ \"--state-color\": VALUE_STATE_COLOR_TOKENS[state] } as CSSProperties}\n\t\t/>\n\t);\n}\n\nfunction hasStateMeta(meta: StateMeta | undefined): boolean {\n\treturn Boolean(meta?.icon || meta?.label);\n}\n\nfunction resolveStateAriaLabel(state: State, meta: StateMeta | undefined): string {\n\tif (typeof meta?.label === \"string\" && meta.label.trim()) {\n\t\treturn meta.label;\n\t}\n\n\treturn state || \"empty\";\n}\n\nfunction renderStateMeta(meta: StateMeta | undefined) {\n\tif (!hasStateMeta(meta)) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<span className={styles.optionMeta}>\n\t\t\t{meta?.icon ? <span className={styles.optionMetaIcon}>{meta.icon}</span> : null}\n\t\t\t{meta?.label ? <span className={styles.optionMetaLabel}>{meta.label}</span> : null}\n\t\t</span>\n\t);\n}\n\nfunction renderStateValue(state: State, meta: StateMeta | undefined) {\n\treturn (\n\t\t<div className={styles.valueContainer}>\n\t\t\t<StateSwatch state={state} />\n\t\t\t{renderStateMeta(meta)}\n\t\t</div>\n\t);\n}\n\n/**\n * Специализированный селект для выбора цветового или статусного состояния. Используется там, где значению соответствует визуальный swatch.\n */\nexport function StateSelect({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tplaceholder,\n\tsize,\n\tvalue,\n\tonChange,\n\toptions = DEFAULT_VALUE_STATES,\n\tstateMeta,\n\tclassName,\n\tclearable\n}: StateSelectProps) {\n\tconst stateOptions = useMemo(() => Array.from(new Set(options)), [options]);\n\tconst hasDetailedOptions = stateOptions.some((stateOption) => hasStateMeta(stateMeta?.[stateOption]));\n\n\tconst sharedSelectProps: Pick<\n\t\tSelectProps<State, State | undefined>,\n\t\t| \"getOptionKey\"\n\t\t| \"getOptionLabel\"\n\t\t| \"getOptionAriaLabel\"\n\t\t| \"renderValue\"\n\t\t| \"renderOption\"\n\t\t| \"buttonClassName\"\n\t\t| \"optionsContentClassName\"\n\t\t| \"getOptionClassName\"\n\t> = {\n\t\tgetOptionKey: (stateOption) => stateOption || \"__empty_state__\",\n\t\tgetOptionLabel: (stateOption) => stateMeta?.[stateOption]?.label ?? stateOption,\n\t\tgetOptionAriaLabel: (stateOption) => resolveStateAriaLabel(stateOption, stateMeta?.[stateOption]),\n\t\trenderValue: (stateOption) => renderStateValue(stateOption, stateMeta?.[stateOption]),\n\t\trenderOption: (stateOption) => (\n\t\t\t<>\n\t\t\t\t<StateSwatch state={stateOption} />\n\t\t\t\t{hasDetailedOptions ? renderStateMeta(stateMeta?.[stateOption]) : null}\n\t\t\t</>\n\t\t),\n\t\tbuttonClassName: styles.button,\n\t\toptionsContentClassName: cn(/*styles.options,*/ hasDetailedOptions ? styles.optionsDetailed : styles.optionsPalette),\n\t\tgetOptionClassName: () => cn(styles.option, hasDetailedOptions ? styles.optionDetailed : styles.optionPalette)\n\t};\n\n\treturn (\n\t\t<Select<State, State | undefined>\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tplaceholder={placeholder}\n\t\t\tsize={size}\n\t\t\tvalue={value}\n\t\t\tonChange={onChange}\n\t\t\toptions={stateOptions}\n\t\t\tclassName={className}\n\t\t\tclearable={clearable}\n\t\t\t{...sharedSelectProps}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AC6BA,SAAS,EAAY,EAAE,UAAO,gBAA+B;CAC5D,OACC,kBAAC,QAAD;EACC,WAAW,EAAG,EAAO,QAAQ,CAAS;EACtC,cAAY,MAAU,SAAS,KAAK,KAAA;EACpC,OAAO,EAAE,iBAAiB,EAAyB,GAAO;CAC1D,CAAA;AAEH;AAEA,SAAS,EAAa,GAAsC;CAC3D,OAAO,GAAQ,GAAM,QAAQ,GAAM;AACpC;AAEA,SAAS,EAAsB,GAAc,GAAqC;CAKjF,OAJI,OAAO,GAAM,SAAU,YAAY,EAAK,MAAM,KAAK,IAC/C,EAAK,QAGN,KAAS;AACjB;AAEA,SAAS,EAAgB,GAA6B;CAKrD,OAJK,EAAa,CAAI,IAKrB,kBAAC,QAAD;EAAM,WAAW,EAAO;YAAxB,CACE,GAAM,OAAO,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAiB,EAAK;EAAW,CAAA,IAAI,MAC1E,GAAM,QAAQ,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAkB,EAAK;EAAY,CAAA,IAAI,IACzE;MAPC;AAST;AAEA,SAAS,EAAiB,GAAc,GAA6B;CACpE,OACC,kBAAC,OAAD;EAAK,WAAW,EAAO;YAAvB,CACC,kBAAC,GAAD,EAAoB,SAAQ,CAAA,GAC3B,EAAgB,CAAI,CACjB;;AAEP;AAKA,SAAgB,EAAY,EAC3B,UACA,gBACA,aACA,gBACA,SACA,UACA,aACA,aAAU,GACV,cACA,cACA,gBACoB;CACpB,IAAM,IAAe,QAAc,MAAM,KAAK,IAAI,IAAI,CAAO,CAAC,GAAG,CAAC,CAAO,CAAC,GACpE,IAAqB,EAAa,MAAM,MAAgB,EAAa,IAAY,EAAY,CAAC;CA4BpG,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACG;EACP;EACC;EACG;EACV,SAAS;EACE;EACA;EA1BZ,eAAe,MAAgB,KAAe;EAC9C,iBAAiB,MAAgB,IAAY,EAAY,EAAE,SAAS;EACpE,qBAAqB,MAAgB,EAAsB,GAAa,IAAY,EAAY;EAChG,cAAc,MAAgB,EAAiB,GAAa,IAAY,EAAY;EACpF,eAAe,MACd,kBAAA,GAAA,EAAA,UAAA,CACC,kBAAC,GAAD,EAAa,OAAO,EAAc,CAAA,GACjC,IAAqB,EAAgB,IAAY,EAAY,IAAI,IACjE,EAAA,CAAA;EAEH,iBAAiB,EAAO;EACxB,yBAAyB,EAAuB,IAAqB,EAAO,kBAAkB,EAAO,cAAc;EACnH,0BAA0B,EAAG,EAAO,QAAQ,IAAqB,EAAO,iBAAiB,EAAO,aAAa;CAgB5G,CAAA;AAEH"}
1
+ {"version":3,"file":"StateSelect-ujAre258.js","names":[],"sources":["../../src/state-select/StateSelect.module.scss","../../src/state-select/StateSelect.tsx"],"sourcesContent":[".button {\n\tpadding-left: var(--space-sm);\n}\n\n.valueContainer {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-sm);\n\twidth: 100%;\n\tmin-height: 1.5em;\n\tmin-width: 0;\n}\n\n.swatch {\n\t--state-color: transparent;\n\n\twidth: 1.25em;\n\theight: 1.25em;\n\tflex-shrink: 0;\n\tdisplay: inline-block;\n\tborder-radius: var(--radius-xs);\n\tborder: var(--border-width) solid var(--border-0);\n\tbackground-color: var(--state-color);\n\n\t&[data-empty] {\n\t\tbackground-color: var(--surface-0);\n\t\tbackground-image: repeating-linear-gradient(135deg, var(--border-0), var(--border-0) 0.25em, transparent 0.25em, transparent 0.5em);\n\t}\n}\n\n// .options {\n// \tpadding: var(--space-xs);\n// }\n\n.optionsPalette {\n\t--input-width: auto;\n\n\tdisplay: grid;\n\tgrid-template-columns: repeat(5, minmax(0, 1fr));\n\tgap: var(--space-xs);\n}\n\n.optionsDetailed {\n\t--input-width: 16em;\n}\n\n.option {\n\tborder-radius: var(--radius-sm);\n\toutline: none;\n\tuser-select: none;\n}\n\n.optionPalette {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: var(--space-sm);\n\tmin-width: 2.25em;\n}\n\n.optionDetailed {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: var(--space-sm);\n\tpadding: var(--space-xs) var(--space-sm);\n}\n\n.optionMeta {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--space-xs);\n\tmin-width: 0;\n}\n\n.optionMetaIcon {\n\tdisplay: inline-flex;\n\talign-items: center;\n}\n\n.optionMetaLabel {\n\tmin-width: 0;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n}\n","import { CSSProperties, ReactNode, useMemo } from \"react\";\n\nimport { DEFAULT_VALUE_STATES, VALUE_STATE_COLOR_TOKENS } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { State } from \"@ryuzaki13/react-foundation-lib/types\";\nimport { cn } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { Select, SelectProps } from \"../select\";\nimport { UiBaseProps } from \"../types\";\n\nimport styles from \"./StateSelect.module.scss\";\n\nexport type StateMeta = {\n\tlabel?: ReactNode;\n\ticon?: ReactNode;\n};\n\nexport interface StateSelectProps extends Omit<UiBaseProps<State | undefined>, \"placeholder\"> {\n\tplaceholder?: string;\n\toptions?: readonly State[];\n\tstateMeta?: Partial<Record<State, StateMeta>>;\n\tclassName?: string;\n\tclearable?: boolean;\n}\n\ninterface StateSwatchProps {\n\tstate: State;\n\tclassName?: string;\n}\n\nfunction StateSwatch({ state, className }: StateSwatchProps) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(styles.swatch, className)}\n\t\t\tdata-empty={state === \"none\" ? \"\" : undefined}\n\t\t\tstyle={{ \"--state-color\": VALUE_STATE_COLOR_TOKENS[state] } as CSSProperties}\n\t\t/>\n\t);\n}\n\nfunction hasStateMeta(meta: StateMeta | undefined): boolean {\n\treturn Boolean(meta?.icon || meta?.label);\n}\n\nfunction resolveStateAriaLabel(state: State, meta: StateMeta | undefined): string {\n\tif (typeof meta?.label === \"string\" && meta.label.trim()) {\n\t\treturn meta.label;\n\t}\n\n\treturn state || \"empty\";\n}\n\nfunction renderStateMeta(meta: StateMeta | undefined) {\n\tif (!hasStateMeta(meta)) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<span className={styles.optionMeta}>\n\t\t\t{meta?.icon ? <span className={styles.optionMetaIcon}>{meta.icon}</span> : null}\n\t\t\t{meta?.label ? <span className={styles.optionMetaLabel}>{meta.label}</span> : null}\n\t\t</span>\n\t);\n}\n\nfunction renderStateValue(state: State, meta: StateMeta | undefined) {\n\treturn (\n\t\t<div className={styles.valueContainer}>\n\t\t\t<StateSwatch state={state} />\n\t\t\t{renderStateMeta(meta)}\n\t\t</div>\n\t);\n}\n\n/**\n * Специализированный селект для выбора цветового или статусного состояния. Используется там, где значению соответствует визуальный swatch.\n */\nexport function StateSelect({\n\tlabel,\n\tdescription,\n\tdisabled,\n\tplaceholder,\n\tsize,\n\tvalue,\n\tonChange,\n\toptions = DEFAULT_VALUE_STATES,\n\tstateMeta,\n\tclassName,\n\tclearable\n}: StateSelectProps) {\n\tconst stateOptions = useMemo(() => Array.from(new Set(options)), [options]);\n\tconst hasDetailedOptions = stateOptions.some((stateOption) => hasStateMeta(stateMeta?.[stateOption]));\n\n\tconst sharedSelectProps: Pick<\n\t\tSelectProps<State>,\n\t\t| \"getOptionKey\"\n\t\t| \"getOptionLabel\"\n\t\t| \"getOptionAriaLabel\"\n\t\t| \"renderValue\"\n\t\t| \"renderOption\"\n\t\t| \"buttonClassName\"\n\t\t| \"optionsContentClassName\"\n\t\t| \"getOptionClassName\"\n\t> = {\n\t\tgetOptionKey: (stateOption) => stateOption || \"__empty_state__\",\n\t\tgetOptionLabel: (stateOption) => stateMeta?.[stateOption]?.label ?? stateOption,\n\t\tgetOptionAriaLabel: (stateOption) => resolveStateAriaLabel(stateOption, stateMeta?.[stateOption]),\n\t\trenderValue: (stateOption) => renderStateValue(stateOption, stateMeta?.[stateOption]),\n\t\trenderOption: (stateOption) => (\n\t\t\t<>\n\t\t\t\t<StateSwatch state={stateOption} />\n\t\t\t\t{hasDetailedOptions ? renderStateMeta(stateMeta?.[stateOption]) : null}\n\t\t\t</>\n\t\t),\n\t\tbuttonClassName: styles.button,\n\t\toptionsContentClassName: cn(/*styles.options,*/ hasDetailedOptions ? styles.optionsDetailed : styles.optionsPalette),\n\t\tgetOptionClassName: () => cn(styles.option, hasDetailedOptions ? styles.optionDetailed : styles.optionPalette)\n\t};\n\n\treturn (\n\t\t<Select\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\tdisabled={disabled}\n\t\t\tplaceholder={placeholder}\n\t\t\tsize={size}\n\t\t\tvalue={value}\n\t\t\tonChange={onChange}\n\t\t\toptions={stateOptions}\n\t\t\tclassName={className}\n\t\t\tclearable={clearable}\n\t\t\t{...sharedSelectProps}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AC6BA,SAAS,EAAY,EAAE,UAAO,gBAA+B;CAC5D,OACC,kBAAC,QAAD;EACC,WAAW,EAAG,EAAO,QAAQ,CAAS;EACtC,cAAY,MAAU,SAAS,KAAK,KAAA;EACpC,OAAO,EAAE,iBAAiB,EAAyB,GAAO;CAC1D,CAAA;AAEH;AAEA,SAAS,EAAa,GAAsC;CAC3D,OAAO,GAAQ,GAAM,QAAQ,GAAM;AACpC;AAEA,SAAS,EAAsB,GAAc,GAAqC;CAKjF,OAJI,OAAO,GAAM,SAAU,YAAY,EAAK,MAAM,KAAK,IAC/C,EAAK,QAGN,KAAS;AACjB;AAEA,SAAS,EAAgB,GAA6B;CAKrD,OAJK,EAAa,CAAI,IAKrB,kBAAC,QAAD;EAAM,WAAW,EAAO;YAAxB,CACE,GAAM,OAAO,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAiB,EAAK;EAAW,CAAA,IAAI,MAC1E,GAAM,QAAQ,kBAAC,QAAD;GAAM,WAAW,EAAO;aAAkB,EAAK;EAAY,CAAA,IAAI,IACzE;MAPC;AAST;AAEA,SAAS,EAAiB,GAAc,GAA6B;CACpE,OACC,kBAAC,OAAD;EAAK,WAAW,EAAO;YAAvB,CACC,kBAAC,GAAD,EAAoB,SAAQ,CAAA,GAC3B,EAAgB,CAAI,CACjB;;AAEP;AAKA,SAAgB,EAAY,EAC3B,UACA,gBACA,aACA,gBACA,SACA,UACA,aACA,aAAU,GACV,cACA,cACA,gBACoB;CACpB,IAAM,IAAe,QAAc,MAAM,KAAK,IAAI,IAAI,CAAO,CAAC,GAAG,CAAC,CAAO,CAAC,GACpE,IAAqB,EAAa,MAAM,MAAgB,EAAa,IAAY,EAAY,CAAC;CA4BpG,OACC,kBAAC,GAAD;EACQ;EACM;EACH;EACG;EACP;EACC;EACG;EACV,SAAS;EACE;EACA;EA1BZ,eAAe,MAAgB,KAAe;EAC9C,iBAAiB,MAAgB,IAAY,EAAY,EAAE,SAAS;EACpE,qBAAqB,MAAgB,EAAsB,GAAa,IAAY,EAAY;EAChG,cAAc,MAAgB,EAAiB,GAAa,IAAY,EAAY;EACpF,eAAe,MACd,kBAAA,GAAA,EAAA,UAAA,CACC,kBAAC,GAAD,EAAa,OAAO,EAAc,CAAA,GACjC,IAAqB,EAAgB,IAAY,EAAY,IAAI,IACjE,EAAA,CAAA;EAEH,iBAAiB,EAAO;EACxB,yBAAyB,EAAuB,IAAqB,EAAO,kBAAkB,EAAO,cAAc;EACnH,0BAA0B,EAAG,EAAO,QAAQ,IAAqB,EAAO,iBAAiB,EAAO,aAAa;CAgB5G,CAAA;AAEH"}
@@ -2,7 +2,7 @@ import { a as e } from "./odata-DSW7z3nh.js";
2
2
  import { s as t } from "./Input-BmjlpA09.js";
3
3
  import { t as n } from "./SelectOptionContent-CI7wq9Oi.js";
4
4
  import { n as r } from "./useODataSelectBase-BbeKdq6x.js";
5
- import { t as i } from "./Select-CXeVjVKA.js";
5
+ import { t as i } from "./Select-BJ5OqTe7.js";
6
6
  import { useMemo as a } from "react";
7
7
  import { jsx as o } from "react/jsx-runtime";
8
8
  //#region src/select/model/useODataSelect.ts
@@ -78,4 +78,4 @@ var l = ({ odata: r, segment: a, model: l, size: u, label: d, description: f, di
78
78
  //#endregion
79
79
  export { l as t };
80
80
 
81
- //# sourceMappingURL=select-BT65bQ8J.js.map
81
+ //# sourceMappingURL=select-BkLc6dyx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-BkLc6dyx.js","names":[],"sources":["../../src/select/model/useODataSelect.ts","../../src/select/ODataSelect.tsx"],"sourcesContent":["import { useMemo } from \"react\";\n\nimport { ODataCollectionModel, ODataSingleSelectProps } from \"@ryuzaki13/react-foundation-api/odata\";\nimport { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nimport { useODataSelectBase } from \"./useODataSelectBase\";\n\ninterface UseODataSelectOptions extends Omit<ODataSingleSelectProps, \"model\"> {\n\tmodel: Required<ODataCollectionModel>;\n\tonChange: (value: string | undefined) => void;\n}\n\nexport function useODataSelect({ odata, segment, model, value, dependencies, onChange }: UseODataSelectOptions) {\n\tconst odataModel = useODataSelectBase({\n\t\todata,\n\t\tsegment,\n\t\tmodel,\n\t\tvalue: value ? [value] : [],\n\t\tdependencies\n\t});\n\n\tconst selectedItem = odataModel.selectedItems[0];\n\tconst options = useMemo(() => {\n\t\tif (!selectedItem) {\n\t\t\treturn odataModel.filteredItems;\n\t\t}\n\n\t\treturn [selectedItem, ...odataModel.filteredItems];\n\t}, [odataModel.filteredItems, selectedItem]);\n\n\tconst handleChange = (item: CollectionItem | undefined) => {\n\t\tonChange(item?.[odataModel.selectionKey]);\n\t};\n\n\treturn {\n\t\t...odataModel,\n\t\tselectedItem,\n\t\toptions,\n\t\thandleChange\n\t};\n}\n","import React from \"react\";\n\nimport { ODataSingleSelectProps, useODataCollectionModel } from \"@ryuzaki13/react-foundation-api/odata\";\nimport { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nimport { InputUILoading } from \"../input\";\nimport { UiBaseProps } from \"../types\";\n\nimport { useODataSelect } from \"./model/useODataSelect\";\nimport { Select } from \"./Select\";\nimport { SelectOptionContent } from \"./SelectOptionContent\";\n\ntype ODataSelectProps = Omit<ODataSingleSelectProps, \"value\"> & UiBaseProps<string | undefined> & { clearable?: boolean };\n\nfunction getODataOptionTextKey(item: CollectionItem | undefined, textKey: string, codeKey: string) {\n\tif (!item) {\n\t\treturn textKey || codeKey;\n\t}\n\n\treturn textKey || Object.keys(item).find((key) => key !== codeKey) || codeKey;\n}\n\nexport const ODataSelect: React.FC<ODataSelectProps> = ({\n\todata,\n\tsegment,\n\tmodel: initialModel,\n\tsize,\n\tlabel,\n\tdescription,\n\tdisabled,\n\tvalue,\n\tdependencies,\n\tonChange,\n\tclearable\n}) => {\n\tconst model = useODataCollectionModel(initialModel);\n\tconst odataModel = useODataSelect({\n\t\todata,\n\t\tsegment,\n\t\tmodel,\n\t\tvalue,\n\t\tdependencies,\n\t\tonChange\n\t});\n\n\tif (odataModel.isLoading) {\n\t\treturn <InputUILoading size={size} label={label} description={description} />;\n\t}\n\n\tconst hideCode = segment.hideCode ?? odata.hideCode;\n\tconst resolvedTextKey = getODataOptionTextKey(odataModel.selectedItem ?? odataModel.options[0], odataModel.textKey, odataModel.codeKey);\n\n\treturn (\n\t\t<Select\n\t\t\tsize={size}\n\t\t\tlabel={label}\n\t\t\tdescription={description}\n\t\t\toptions={odataModel.options}\n\t\t\tvalue={odataModel.selectedItem}\n\t\t\tonChange={odataModel.handleChange}\n\t\t\tgetOptionKey={(item) => item[odataModel.codeKey]}\n\t\t\tgetOptionLabel={(item) => item[resolvedTextKey]}\n\t\t\tgetOptionCode={hideCode ? undefined : (item) => item[odataModel.codeKey]}\n\t\t\tgetOptionAriaLabel={(item) =>\n\t\t\t\thideCode || item[resolvedTextKey] === item[odataModel.codeKey]\n\t\t\t\t\t? String(item[resolvedTextKey])\n\t\t\t\t\t: `${item[resolvedTextKey]} ${item[odataModel.codeKey]}`\n\t\t\t}\n\t\t\trenderValue={(item) => (\n\t\t\t\t<SelectOptionContent label={item[resolvedTextKey]} code={hideCode ? undefined : item[odataModel.codeKey]} />\n\t\t\t)}\n\t\t\trenderOption={(item) => (\n\t\t\t\t<SelectOptionContent\n\t\t\t\t\tlabel={item[resolvedTextKey]}\n\t\t\t\t\tcode={hideCode ? undefined : item[odataModel.codeKey]}\n\t\t\t\t\thighlight={odataModel.debouncedQuery}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\tsearchable\n\t\t\tquery={odataModel.query}\n\t\t\tonQuery={odataModel.setQuery}\n\t\t\tdefaultFilter={false}\n\t\t\tdisabled={disabled || odataModel.isLoading}\n\t\t\tplaceholder={odataModel.placeholder}\n\t\t\tloadingState=\"Загрузка...\"\n\t\t\terrorState={odataModel.isError ? \"Ошибка загрузки\" : undefined}\n\t\t\temptyState={!odataModel.isLoading && !odataModel.isError ? \"Нет данных\" : undefined}\n\t\t\tclearable={clearable}\n\t\t/>\n\t);\n};\n"],"mappings":";;;;;;;;AAYA,SAAgB,EAAe,EAAE,UAAO,YAAS,UAAO,UAAO,iBAAc,eAAmC;CAC/G,IAAM,IAAa,EAAmB;EACrC;EACA;EACA;EACA,OAAO,IAAQ,CAAC,CAAK,IAAI,CAAC;EAC1B;CACD,CAAC,GAEK,IAAe,EAAW,cAAc,IACxC,IAAU,QACV,IAIE,CAAC,GAAc,GAAG,EAAW,aAAa,IAHzC,EAAW,eAIjB,CAAC,EAAW,eAAe,CAAY,CAAC,GAErC,KAAgB,MAAqC;EAC1D,EAAS,IAAO,EAAW,aAAa;CACzC;CAEA,OAAO;EACN,GAAG;EACH;EACA;EACA;CACD;AACD;;;AC1BA,SAAS,EAAsB,GAAkC,GAAiB,GAAiB;CAKlG,OAJK,IAIE,KAAW,OAAO,KAAK,CAAI,CAAC,CAAC,MAAM,MAAQ,MAAQ,CAAO,KAAK,IAH9D,KAAW;AAIpB;AAEA,IAAa,KAA2C,EACvD,UACA,YACA,OAAO,GACP,SACA,UACA,gBACA,aACA,UACA,iBACA,aACA,mBACK;CAEL,IAAM,IAAa,EAAe;EACjC;EACA;EACA,OAJa,EAAwB,CAIrC;EACA;EACA;EACA;CACD,CAAC;CAED,IAAI,EAAW,WACd,OAAO,kBAAC,GAAD;EAAsB;EAAa;EAAoB;CAAc,CAAA;CAG7E,IAAM,IAAW,EAAQ,YAAY,EAAM,UACrC,IAAkB,EAAsB,EAAW,gBAAgB,EAAW,QAAQ,IAAI,EAAW,SAAS,EAAW,OAAO;CAEtI,OACC,kBAAC,GAAD;EACO;EACC;EACM;EACb,SAAS,EAAW;EACpB,OAAO,EAAW;EAClB,UAAU,EAAW;EACrB,eAAe,MAAS,EAAK,EAAW;EACxC,iBAAiB,MAAS,EAAK;EAC/B,eAAe,IAAW,KAAA,KAAa,MAAS,EAAK,EAAW;EAChE,qBAAqB,MACpB,KAAY,EAAK,OAAqB,EAAK,EAAW,WACnD,OAAO,EAAK,EAAgB,IAC5B,GAAG,EAAK,GAAiB,GAAG,EAAK,EAAW;EAEhD,cAAc,MACb,kBAAC,GAAD;GAAqB,OAAO,EAAK;GAAkB,MAAM,IAAW,KAAA,IAAY,EAAK,EAAW;EAAW,CAAA;EAE5G,eAAe,MACd,kBAAC,GAAD;GACC,OAAO,EAAK;GACZ,MAAM,IAAW,KAAA,IAAY,EAAK,EAAW;GAC7C,WAAW,EAAW;EACtB,CAAA;EAEF,YAAA;EACA,OAAO,EAAW;EAClB,SAAS,EAAW;EACpB,eAAe;EACf,UAAU,KAAY,EAAW;EACjC,aAAa,EAAW;EACxB,cAAa;EACb,YAAY,EAAW,UAAU,oBAAoB,KAAA;EACrD,YAAY,CAAC,EAAW,aAAa,CAAC,EAAW,UAAU,eAAe,KAAA;EAC/D;CACX,CAAA;AAEH"}