{"version":3,"file":"NumberInput.cjs","sources":["../../../../src/components/number-input/NumberInput.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n    type ComponentType,\n    forwardRef,\n    useRef,\n    useState,\n} from \"react\";\nimport { mergeRefs } from \"../../utilities/mergeRefs.js\";\nimport { MinusIcon, PlusIcon } from \"../icon/index.js\";\nimport { InputGroup } from \"../input-group/InputGroup.js\";\nimport type { NumberInputProps } from \"./types.js\";\n\ntype NumberInputValue = string | number | readonly string[] | undefined;\n\ntype StepDirection = \"increment\" | \"decrement\";\n\nconst stepperConfig: Record<\n    StepDirection,\n    { label: string; Icon: ComponentType }\n> = {\n    decrement: { label: \"Senk verdien\", Icon: MinusIcon },\n    increment: { label: \"Øk verdien\", Icon: PlusIcon },\n};\n\nfunction toNumeric(value: NumberInputValue): number {\n    if (typeof value === \"number\") {\n        return value;\n    }\n    if (typeof value === \"string\" && value.trim() !== \"\") {\n        return Number(value);\n    }\n    return Number.NaN;\n}\n\ntype StepperButtonProps = {\n    direction: StepDirection;\n    disabled: boolean;\n    onClick: () => void;\n};\n\nfunction StepperButton({ direction, disabled, onClick }: StepperButtonProps) {\n    const { label, Icon } = stepperConfig[direction];\n\n    return (\n        <button\n            type=\"button\"\n            className=\"jkl-button jkl-button--ghost\"\n            aria-label={label}\n            data-direction={direction}\n            onPointerDown={(event) => event.preventDefault()}\n            onClick={onClick}\n            disabled={disabled}\n        >\n            <span aria-hidden=\"true\">\n                <Icon />\n            </span>\n        </button>\n    );\n}\n\nexport const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(\n    (props, ref) => {\n        const {\n            \"data-size\": dataSize,\n            \"data-testautoid\": testAutoId,\n            \"data-testid\": dataTestId,\n            align = \"left\",\n            id,\n            label,\n            className,\n            style,\n            errorLabel,\n            helpLabel,\n            inputClassName,\n            labelProps,\n            supportLabelProps,\n            stepper = false,\n            tooltip,\n            description,\n            width,\n            onChange,\n            ...rest\n        } = props;\n        const internalRef = useRef<HTMLInputElement>(null);\n        const mergedRef = mergeRefs(internalRef, ref);\n        const [uncontrolledValue, setUncontrolledValue] =\n            useState<NumberInputValue>(rest.defaultValue);\n\n        // I kontrollert bruk må vi lese direkte fra `value` for at disabled-\n        // state på stepper-knappene skal følge prop-en i samme render. Bruker\n        // intern state som fallback for ukontrollert bruk.\n        const effectiveValue =\n            rest.value !== undefined ? rest.value : uncontrolledValue;\n\n        const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n            if (rest.value === undefined) {\n                setUncontrolledValue(event.target.value);\n            }\n            onChange?.(event);\n        };\n\n        const numericValue = toNumeric(effectiveValue);\n        const minNumeric =\n            rest.min !== undefined ? Number(rest.min) : Number.NaN;\n        const maxNumeric =\n            rest.max !== undefined ? Number(rest.max) : Number.NaN;\n        const isAtOrBelowMin =\n            Number.isFinite(numericValue) &&\n            Number.isFinite(minNumeric) &&\n            numericValue <= minNumeric;\n        const isAtOrAboveMax =\n            Number.isFinite(numericValue) &&\n            Number.isFinite(maxNumeric) &&\n            numericValue >= maxNumeric;\n\n        const inputWrapperStyle =\n            style || width\n                ? {\n                      ...style,\n                      ...(width ? { width } : undefined),\n                  }\n                : undefined;\n        const inputGroupProps = {\n            id,\n            label,\n            errorLabel,\n            helpLabel,\n            labelProps,\n            supportLabelProps,\n            tooltip,\n            description,\n        };\n\n        const triggerStep = (direction: StepDirection) => {\n            const input = internalRef.current;\n\n            if (!input || input.disabled || input.readOnly) {\n                return;\n            }\n\n            const previousValue = input.value;\n            input.focus();\n\n            try {\n                if (direction === \"increment\") {\n                    input.stepUp();\n                } else {\n                    input.stepDown();\n                }\n            } catch {\n                return;\n            }\n\n            if (input.value === previousValue) {\n                return;\n            }\n\n            input.dispatchEvent(new Event(\"input\", { bubbles: true }));\n        };\n\n        const stepperDisabled = rest.disabled || rest.readOnly;\n\n        return (\n            <InputGroup\n                {...inputGroupProps}\n                className={clsx(className, \"jkl-number-input\")}\n                data-size={dataSize}\n                data-testid={dataTestId ?? \"jkl-number-input\"}\n                render={(inputProps) => (\n                    <div\n                        className={clsx(\"jkl-number-input__wrapper\", {\n                            \"jkl-number-input__wrapper--stepper\": stepper,\n                        })}\n                        data-invalid={inputProps[\"aria-invalid\"]}\n                        style={inputWrapperStyle}\n                    >\n                        {stepper && (\n                            <StepperButton\n                                direction=\"decrement\"\n                                disabled={stepperDisabled || isAtOrBelowMin}\n                                onClick={() => triggerStep(\"decrement\")}\n                            />\n                        )}\n                        <input\n                            {...inputProps}\n                            {...rest}\n                            ref={mergedRef}\n                            type=\"number\"\n                            onChange={handleChange}\n                            className={clsx(\n                                \"jkl-number-input__input\",\n                                {\n                                    \"jkl-number-input__input--stepper\": stepper,\n                                    \"jkl-number-input__input--align-right\":\n                                        !stepper && align === \"right\",\n                                },\n                                inputClassName,\n                            )}\n                            data-testautoid={testAutoId}\n                        />\n                        {stepper && (\n                            <StepperButton\n                                direction=\"increment\"\n                                disabled={stepperDisabled || isAtOrAboveMax}\n                                onClick={() => triggerStep(\"increment\")}\n                            />\n                        )}\n                    </div>\n                )}\n            />\n        );\n    },\n);\n\nNumberInput.displayName = \"NumberInput\";\n"],"names":["stepperConfig","decrement","label","Icon","MinusIcon","increment","PlusIcon","StepperButton","direction","disabled","onClick","jsx","type","className","onPointerDown","event","preventDefault","children","NumberInput","forwardRef","props","ref","dataSize","testAutoId","dataTestId","align","id","style","errorLabel","helpLabel","inputClassName","labelProps","supportLabelProps","stepper","tooltip","description","width","onChange","rest","internalRef","useRef","mergedRef","mergeRefs","uncontrolledValue","setUncontrolledValue","useState","defaultValue","effectiveValue","value","handleChange","target","numericValue","trim","Number","NaN","toNumeric","minNumeric","min","maxNumeric","max","isAtOrBelowMin","isFinite","isAtOrAboveMax","inputWrapperStyle","inputGroupProps","triggerStep","input","current","readOnly","previousValue","focus","stepUp","stepDown","dispatchEvent","Event","bubbles","stepperDisabled","InputGroup","clsx","render","inputProps","jsxs","displayName"],"mappings":"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"}