@synerise/ds-input-number 1.2.48 → 1.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/CLAUDE.md +149 -0
- package/README.md +7 -10
- package/dist/InputNumber.d.ts +1 -1
- package/dist/InputNumber.js +139 -59
- package/dist/InputNumber.styles.d.ts +27 -11
- package/dist/InputNumber.styles.js +58 -33
- package/dist/InputNumber.types.d.ts +27 -4
- package/dist/constants/inputNumber.constants.d.ts +2 -0
- package/dist/constants/inputNumber.constants.js +4 -0
- package/dist/hooks/useStepper.d.ts +25 -0
- package/dist/hooks/useStepper.js +108 -0
- package/package.json +7 -10
- package/dist/assets/style/index-tn0RQdqM.css +0 -0
- package/dist/style/index.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.2.50](https://github.com/Synerise/synerise-design/compare/@synerise/ds-input-number@1.2.49...@synerise/ds-input-number@1.2.50) (2026-07-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @synerise/ds-input-number
|
|
9
|
+
|
|
10
|
+
## [1.2.49](https://github.com/Synerise/synerise-design/compare/@synerise/ds-input-number@1.2.48...@synerise/ds-input-number@1.2.49) (2026-07-09)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @synerise/ds-input-number
|
|
13
|
+
|
|
6
14
|
## [1.2.48](https://github.com/Synerise/synerise-design/compare/@synerise/ds-input-number@1.2.47...@synerise/ds-input-number@1.2.48) (2026-06-17)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @synerise/ds-input-number
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# InputNumber (`@synerise/ds-input-number`)
|
|
2
|
+
|
|
3
|
+
> Locale-aware numeric input, **DS-native** (no Ant Design). Renders a styled `<input>` with custom
|
|
4
|
+
> up/down steppers, form-field layout (label, tooltip, description, error text), autosize support,
|
|
5
|
+
> and locale-driven thousand/decimal formatting.
|
|
6
|
+
|
|
7
|
+
## Package structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
InputNumber.tsx — main component (value flow, steppers, autosize wiring)
|
|
12
|
+
InputNumber.types.ts — InputNumberProps (explicit, hand-written), deprecated Props alias
|
|
13
|
+
InputNumber.styles.tsx — DS-native styled-components (InputNumberRoot, HandlerWrap, HandlerUp/Down, InputField, Addon, …)
|
|
14
|
+
index.ts — public exports
|
|
15
|
+
hooks/
|
|
16
|
+
useStepper.ts — float-safe increment/decrement, clamp, precision, press-and-hold + Shift×10
|
|
17
|
+
constants/
|
|
18
|
+
inputNumber.constants.ts — MAXIMUM_FRACTION_DIGITS (20), MAXIMUM_NUMBER_DIGITS (15), NUMBER_DELIMITER ('.'), ANGLE_UP_SVG / ANGLE_DOWN_SVG (stepper glyphs)
|
|
19
|
+
utils/
|
|
20
|
+
inputNumber.utils.ts — formatNumber, parseFormattedNumber helpers
|
|
21
|
+
__specs__/
|
|
22
|
+
InputNumber.spec.tsx — Vitest tests (component + steppers + value flow)
|
|
23
|
+
inputNumber.utils.spec.tsx — Vitest tests (utils)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
There is **no `style/` LESS** — all styling is in `InputNumber.styles.tsx`.
|
|
27
|
+
|
|
28
|
+
## Public exports
|
|
29
|
+
|
|
30
|
+
### `InputNumber` (default export)
|
|
31
|
+
|
|
32
|
+
Functional component. Not a forwardRef — no ref forwarding.
|
|
33
|
+
|
|
34
|
+
Props = explicit `InputNumberOwnProps` + `FormFieldCommonProps` + `PassthroughAttributes` (`data-*`/`aria-*`)
|
|
35
|
+
+ standard input HTML attributes via `Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'size' | 'min' | 'max' | 'type'>` (antd-parity forwarding of `maxLength`, `onFocus`, `tabIndex`, `inputMode`, `onKeyDown`, …). The omitted keys are owned explicitly by the component (different types/behavior). Two have special wiring: `onKeyDown` and `onKeyPress` are composed with the internal arrow-stepping / numeric-filter handlers (consumer called first), and `inputMode` defaults to `'decimal'` but a consumer value overrides it:
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Description |
|
|
38
|
+
|------|------|---------|-------------|
|
|
39
|
+
| `value` | `number \| null` | `undefined` | Controlled value |
|
|
40
|
+
| `defaultValue` | `number \| null` | `undefined` | Uncontrolled initial value |
|
|
41
|
+
| `onChange` | `(value: number \| null) => void` | `undefined` | Called with parsed numeric value on every change |
|
|
42
|
+
| `onBlur` | `(event: FocusEvent<HTMLInputElement>) => void` | `undefined` | Native input blur, invoked **after** the on-blur min/max re-align (consumers read `event.target.value`) |
|
|
43
|
+
| `onKeyPress` | `(event: KeyboardEvent<HTMLInputElement>) => void` | `undefined` | Forwarded the input's `keypress` event (fired before the internal numeric-key filter) |
|
|
44
|
+
| `onStep` | `(value: number, info: { offset: number; type: 'up' \| 'down' }) => void` | `undefined` | Fires on a stepper interaction (up/down button or ArrowUp/ArrowDown). antd parity — fires alongside `onChange`; `offset` is the applied step magnitude (incl. Shift×10) |
|
|
45
|
+
| `min` / `max` | `number` | `undefined` | Stepper bounds (clamped on step) |
|
|
46
|
+
| `step` | `number \| string` | `1` | Stepper increment |
|
|
47
|
+
| `disabled` / `readOnly` | `boolean` | `undefined` | Disable input; steppers are not rendered |
|
|
48
|
+
| `autoFocus` | `boolean` | `undefined` | Focus the input on mount |
|
|
49
|
+
| `tabIndex` | `number` | `undefined` | Forwarded to the underlying `<input>` (focus order) |
|
|
50
|
+
| `placeholder` | `string` | `undefined` | Input placeholder |
|
|
51
|
+
| `size` | `'small' \| 'middle' \| 'large'` | `undefined` | `'large'` → 48px tall |
|
|
52
|
+
| `error` | `boolean` | `undefined` | Triggers error state (red inset border + background) |
|
|
53
|
+
| `errorText` | `ReactNode` | `undefined` | Error message shown below input; also triggers error state |
|
|
54
|
+
| `label` / `description` / `tooltip` / `tooltipConfig` | from `FormFieldCommonProps` | `undefined` | Form-field layout |
|
|
55
|
+
| `prefixel` / `suffixel` | `ReactNode` | `undefined` | Content in the left / right addon slot |
|
|
56
|
+
| `raw` | `boolean` | `undefined` | When `true`, renders bare input without FormField wrapper |
|
|
57
|
+
| `valueFormatOptions` | `NumberToFormatOptions` | `undefined` | Override formatting options (e.g. `{ maximumFractionDigits: 2 }`) |
|
|
58
|
+
| `autoResize` | `AutoResizeProp` | `undefined` | Enable autosize: `true` or `{ minWidth, maxWidth?, stretchToFit? }` |
|
|
59
|
+
| `autoResizeProps` | `Partial<Pick<AutosizeInputProps, 'placeholderIsMinWidth' \| 'wrapperClassName' \| 'wrapperStyle' \| 'extraWidth'>>` | `undefined` | Extra props passed to `AutosizeWrapper` |
|
|
60
|
+
| `style` / `className` | `CSSProperties` / `string` | `undefined` | Applied to the inner `InputNumberWrapper` |
|
|
61
|
+
|
|
62
|
+
> **Removed in the antd-removal migration (STOR-2334) — BREAKING.** The antd-only props are gone:
|
|
63
|
+
> `formatter`, `parser` (formatting is always locale-driven via `useDataFormat` + `valueFormatOptions`),
|
|
64
|
+
> `decimalSeparator` (superseded by the locale `decimalDelimiter`), `controls`, `keyboard`, `stringMode`,
|
|
65
|
+
> `bordered`, `status`, `prefix`, `onPressEnter`, and `addonBefore`/`addonAfter` (use `prefixel`/`suffixel`).
|
|
66
|
+
> Also removed: `precision` — the stepped value is now rounded to
|
|
67
|
+
> `max(decimals(step), valueFormatOptions?.maximumFractionDigits ?? 0)`, so express decimal precision
|
|
68
|
+
> via `step` and/or `valueFormatOptions` instead.
|
|
69
|
+
|
|
70
|
+
### `InputNumberProps` (type export)
|
|
71
|
+
|
|
72
|
+
The full props type. `Props` is also exported from the types file as a `@deprecated` alias but is **not**
|
|
73
|
+
re-exported from `index.ts`.
|
|
74
|
+
|
|
75
|
+
## Usage patterns
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import InputNumber from '@synerise/ds-input-number';
|
|
79
|
+
|
|
80
|
+
// Basic with form field
|
|
81
|
+
<InputNumber label="Quantity" min={1} max={100} defaultValue={10} onChange={(v) => console.log(v)} />
|
|
82
|
+
|
|
83
|
+
// Error state
|
|
84
|
+
<InputNumber label="Price" error errorText="Must be positive" value={price} onChange={setPrice} />
|
|
85
|
+
|
|
86
|
+
// With prefix/suffix
|
|
87
|
+
<InputNumber prefixel="$" suffixel="USD" min={0} step={0.01} />
|
|
88
|
+
|
|
89
|
+
// Raw (no form field wrapper)
|
|
90
|
+
<InputNumber raw value={qty} onChange={setQty} />
|
|
91
|
+
|
|
92
|
+
// Autosize
|
|
93
|
+
<InputNumber autoResize={{ minWidth: '60px', maxWidth: '200px', stretchToFit: true }} value={val} onChange={setVal} />
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Styling
|
|
97
|
+
|
|
98
|
+
All styling lives in `InputNumber.styles.tsx` as DS-native styled-components driven by transient
|
|
99
|
+
`$`-props and `:focus-within` (no antd LESS, no `.ant-*`/`.ds-*` styling selectors). The
|
|
100
|
+
`ant-input-number-*` and `ds-input-number-*` class names are kept on the elements as hooks only
|
|
101
|
+
(ui-tests / interim external CSS). Theme tokens used: `grey-700` (text), `grey-300` (idle border),
|
|
102
|
+
`blue-600` (focus border), `red-600`/`red-050` (error), `grey-500` (placeholder), `grey-050` (addon).
|
|
103
|
+
|
|
104
|
+
> **Deep import**: `InputNumber.styles.tsx` imports `autoresizeConfObjToCss` from
|
|
105
|
+
> `@synerise/ds-input/dist/Input.styles` — a fragile internal path (pre-existing; flagged as an
|
|
106
|
+
> eslint warning until ds-input exposes it from the root).
|
|
107
|
+
|
|
108
|
+
## Key dependencies
|
|
109
|
+
|
|
110
|
+
- `@synerise/ds-form-field` — `FormField` wrapper providing label, tooltip, description, error layout
|
|
111
|
+
- `@synerise/ds-input` — `AutosizeWrapper` + `AutoResizeProp` type
|
|
112
|
+
- `@synerise/ds-core` — `useDataFormat` hook (locale-aware number formatting), `NumberToFormatOptions`, `ThemeProps`
|
|
113
|
+
- `@synerise/ds-utils` — `useResizeObserver` (for `stretchToFit` autosize) + `PassthroughAttributes` type
|
|
114
|
+
- `uuid` — generates stable `id` for label `htmlFor` association
|
|
115
|
+
|
|
116
|
+
## Implementation notes
|
|
117
|
+
|
|
118
|
+
- **Steppers (`useStepper`)**: float-safe arithmetic (integer scaling, so `0.1 + 0.2 === 0.3`), clamp to
|
|
119
|
+
`min`/`max`, then round to `max(decimals(step), valueFormatOptions?.maximumFractionDigits ?? 0)` — so a
|
|
120
|
+
fractional `step` (e.g. `0.01`) keeps its decimals without any extra config, and `maximumFractionDigits`
|
|
121
|
+
raises the rounding floor. Mouse press-and-hold auto-repeats (600ms delay → 200ms interval);
|
|
122
|
+
`Shift` multiplies the step by ten; ArrowUp/ArrowDown step from the keyboard (a consumer `onKeyDown`
|
|
123
|
+
is invoked first, then the stepping runs). Steppers are not rendered when `disabled` or `readOnly`.
|
|
124
|
+
- **Value flow**: a controlled `<input type="text">`. Typed input is parsed locale→number string first
|
|
125
|
+
(`parseFormattedNumber`) then re-formatted for display (`formatNumber`) — preserving a lone `-`, a
|
|
126
|
+
trailing decimal and trailing zeros while typing. `onChange` always emits `number | null` (emits `0`,
|
|
127
|
+
not `null`). `aria-valuenow` carries the raw numeric value.
|
|
128
|
+
- **On-blur min/max re-align (antd parity)**: typing is never clamped (rc-input-number's
|
|
129
|
+
`userTyping=true` path), so a value can exceed `min`/`max` mid-edit. On blur, an out-of-range value is
|
|
130
|
+
re-aligned to the nearest bound (`> max ⇒ max`, `< min ⇒ min`) — mirroring rc-input-number's
|
|
131
|
+
`flushInputValue(false)` → `triggerValueUpdate(…, userTyping=false)` → `getRangeValue`. When it clamps
|
|
132
|
+
it updates the display and fires `onChange(clamped)`; an in-range value is left untouched (no
|
|
133
|
+
`onChange`). Empty / `NaN` values are not clamped. Steppers clamp independently in `useStepper`.
|
|
134
|
+
- **Numeric key filter**: lives on the input's `onKeyPress` — the native `keypress` event does not fire
|
|
135
|
+
for Backspace / arrows / Delete, so editing keys are never blocked. A consumer-supplied `onKeyPress`
|
|
136
|
+
prop is invoked first (so it can inspect / `preventDefault`), then the numeric filter runs.
|
|
137
|
+
- **Locale-aware formatting**: `useDataFormat()` returns `formatValue`, `thousandDelimiter`,
|
|
138
|
+
`decimalDelimiter` based on the active `DataFormatNotationType` (`'EU'` or `'US'`).
|
|
139
|
+
- **Controlled/uncontrolled hybrid**: keeps `localValue`/`displayValue` state; `value` prop changes sync
|
|
140
|
+
via `useEffect` (only when `value !== localValue`).
|
|
141
|
+
- **Error state**: `error={true}` or a non-empty `errorText` adds the `error` class to the root and the
|
|
142
|
+
red inset border + `red-050` background via `$error`.
|
|
143
|
+
- **`raw` mode**: skips the `FormField` wrapper — `label`/`description`/`errorText`/`tooltip` have no effect.
|
|
144
|
+
- **`autoResize` + `stretchToFit`**: `useResizeObserver` on a wrapper ref dynamically sets `max-width`;
|
|
145
|
+
`AUTOSIZE_EXTRA_WIDTH = 45` accommodates the stepper buttons.
|
|
146
|
+
- **Maximum digits**: `parseFormattedNumber` truncates to `MAXIMUM_NUMBER_DIGITS = 15` to avoid
|
|
147
|
+
floating-point precision issues near `Number.MAX_SAFE_INTEGER`.
|
|
148
|
+
- **Uses Vitest** for testing.
|
|
149
|
+
```
|
package/README.md
CHANGED
|
@@ -24,12 +24,13 @@ Input-Number UI Component
|
|
|
24
24
|
| label | Input label | ReactNode | - |
|
|
25
25
|
| max | Max value | number | Infinity |
|
|
26
26
|
| min | Min value | number | -Infinity |
|
|
27
|
+
| onBlur | Native input blur handler (consumers read `event.target.value`) | (e: FocusEvent<HTMLInputElement>) => void | - |
|
|
27
28
|
| onChange | Called with the parsed numeric value on change. Returns `null` when input is cleared. | (value: number \| null) => void | - |
|
|
28
|
-
| onPressEnter | Callback triggered when Enter key is pressed | (e: Event) => void | - |
|
|
29
29
|
| precision | Precision of input value | number | - |
|
|
30
30
|
| prefixel | ReactNode to render in the left addon slot | ReactNode | - |
|
|
31
31
|
| raw | Render bare input without FormField wrapper (no label / tooltip / description / errorText) | boolean | - |
|
|
32
|
-
|
|
|
32
|
+
| readOnly | Read-only input (steppers are not rendered) | boolean | `false` |
|
|
33
|
+
| size | Height of input box (`'large'` → 48px) | 'small' \| 'middle' \| 'large' | - |
|
|
33
34
|
| step | The number by which the current value is increased or decreased | number \| string | 1 |
|
|
34
35
|
| suffixel | ReactNode to render in the right addon slot | ReactNode | - |
|
|
35
36
|
| tooltip | Tooltip content shown next to the label | ReactNode | - |
|
|
@@ -39,11 +40,7 @@ Input-Number UI Component
|
|
|
39
40
|
| autoResize | Enable autosize: `true` or `{ minWidth, maxWidth?, stretchToFit? }` | boolean \| object | - |
|
|
40
41
|
| autoResizeProps | Extra props for the autosize wrapper (`placeholderIsMinWidth`, `wrapperClassName`, `wrapperStyle`, `extraWidth`) | object | - |
|
|
41
42
|
|
|
42
|
-
> **Note**:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
| Name | Description |
|
|
47
|
-
| ------- | ------------ |
|
|
48
|
-
| blur() | remove focus |
|
|
49
|
-
| focus() | get focus |
|
|
43
|
+
> **Note**: this component is DS-native (no Ant Design). The former antd-only props were removed —
|
|
44
|
+
> `formatter`/`parser`/`decimalSeparator` (formatting is always locale-driven via `valueFormatOptions`),
|
|
45
|
+
> `controls`, `keyboard`, `stringMode`, `bordered`, `status`, `prefix`, `onPressEnter`, and
|
|
46
|
+
> `addonBefore`/`addonAfter` (use `prefixel`/`suffixel`).
|
package/dist/InputNumber.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { InputNumberProps } from './InputNumber.types';
|
|
3
|
-
declare const InputNumber: ({ label, description, errorText, raw, error, prefixel, suffixel, style, tooltip, tooltipConfig, value, defaultValue, valueFormatOptions, onChange, autoResize, autoResizeProps, ...
|
|
3
|
+
declare const InputNumber: ({ label, description, errorText, raw, error, prefixel, suffixel, style, className, tooltip, tooltipConfig, value, defaultValue, valueFormatOptions, onChange, onBlur, onKeyPress, onKeyDown, onStep, autoResize, autoResizeProps, min, max, step, disabled, readOnly, autoFocus, inputMode, placeholder, size, name, id: idProp, ...rest }: InputNumberProps) => React.JSX.Element;
|
|
4
4
|
export default InputNumber;
|
package/dist/InputNumber.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useRef,
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useState, useRef, useMemo, useEffect } from "react";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
import { useDataFormat } from "@synerise/ds-core";
|
|
5
5
|
import FormField from "@synerise/ds-form-field";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { useAutosizeWidth, useStretchToFit, SIZER_STYLE } from "@synerise/ds-input";
|
|
7
|
+
import { InputNumberRoot, HandlerWrap, HandlerUp, HandlerDown, InputFieldWrap, InputField, InputNumberAutosize, InputNumberContainer, InputNumberWrapper, GroupWrapper, Group, Addon } from "./InputNumber.styles.js";
|
|
8
|
+
import { useStepper } from "./hooks/useStepper.js";
|
|
9
9
|
import { formatNumber, parseFormattedNumber } from "./utils/inputNumber.utils.js";
|
|
10
|
-
import "./style/index.css";
|
|
11
10
|
const AUTOSIZE_EXTRA_WIDTH = 45;
|
|
11
|
+
const NUMERIC_KEY = /^-?\d*(\.|,)?\d*$/i;
|
|
12
|
+
const cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
12
13
|
const InputNumber = ({
|
|
13
14
|
label,
|
|
14
15
|
description,
|
|
@@ -18,94 +19,173 @@ const InputNumber = ({
|
|
|
18
19
|
prefixel,
|
|
19
20
|
suffixel,
|
|
20
21
|
style,
|
|
22
|
+
className,
|
|
21
23
|
tooltip,
|
|
22
24
|
tooltipConfig,
|
|
23
25
|
value,
|
|
24
26
|
defaultValue,
|
|
25
27
|
valueFormatOptions,
|
|
26
28
|
onChange,
|
|
29
|
+
onBlur,
|
|
30
|
+
onKeyPress,
|
|
31
|
+
onKeyDown,
|
|
32
|
+
onStep,
|
|
27
33
|
autoResize,
|
|
28
34
|
autoResizeProps,
|
|
29
|
-
|
|
35
|
+
min,
|
|
36
|
+
max,
|
|
37
|
+
step,
|
|
38
|
+
disabled,
|
|
39
|
+
readOnly,
|
|
40
|
+
autoFocus,
|
|
41
|
+
inputMode,
|
|
42
|
+
placeholder,
|
|
43
|
+
size,
|
|
44
|
+
name,
|
|
45
|
+
id: idProp,
|
|
46
|
+
// forward remaining standard input attributes (maxLength, onFocus, tabIndex, data-*/aria-*, …)
|
|
47
|
+
// to the input, as antd's rc-input-number did
|
|
48
|
+
...rest
|
|
30
49
|
}) => {
|
|
31
50
|
const {
|
|
32
51
|
formatValue,
|
|
33
52
|
thousandDelimiter,
|
|
34
53
|
decimalDelimiter
|
|
35
54
|
} = useDataFormat();
|
|
36
|
-
const [
|
|
55
|
+
const formatter = useCallback((inputValue) => formatNumber(inputValue, formatValue, thousandDelimiter, decimalDelimiter, valueFormatOptions), [formatValue, valueFormatOptions, thousandDelimiter, decimalDelimiter]);
|
|
37
56
|
const [localValue, setLocalValue] = useState(value ?? defaultValue);
|
|
38
|
-
const
|
|
57
|
+
const [displayValue, setDisplayValue] = useState(() => formatter(value ?? defaultValue));
|
|
39
58
|
const inputRef = useRef(null);
|
|
40
|
-
const inputNumberRef = useRef(null);
|
|
41
|
-
const elementRef = useRef(null);
|
|
42
59
|
const scrollLeftRef = useRef(0);
|
|
60
|
+
const id = useMemo(() => idProp ?? v4(), [idProp]);
|
|
61
|
+
const showError = Boolean(error || errorText);
|
|
43
62
|
useEffect(() => {
|
|
44
63
|
if (value !== void 0 && value !== localValue) {
|
|
45
64
|
setLocalValue(value);
|
|
65
|
+
setDisplayValue(formatter(value));
|
|
46
66
|
}
|
|
47
67
|
}, [value]);
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
return formatted;
|
|
53
|
-
}, [formatValue, valueFormatOptions, thousandDelimiter, decimalDelimiter]);
|
|
54
|
-
const parser = useCallback((inputValue) => {
|
|
55
|
-
return parseFloat(`${parseFormattedNumber(inputValue, formatValue, thousandDelimiter, decimalDelimiter)}`);
|
|
56
|
-
}, [formatValue, thousandDelimiter, decimalDelimiter]);
|
|
57
|
-
const handleOnChange = useCallback((changedValue) => {
|
|
58
|
-
const formattedValue = formatter(changedValue);
|
|
59
|
-
const parsedFormattedValue = parser(formattedValue);
|
|
60
|
-
const valueAsNumber = typeof parsedFormattedValue === "string" ? parseFloat(parsedFormattedValue) : parsedFormattedValue;
|
|
68
|
+
const handleInputChange = useCallback((rawValue) => {
|
|
69
|
+
const jsString = `${parseFormattedNumber(rawValue, formatValue, thousandDelimiter, decimalDelimiter)}`;
|
|
70
|
+
const formattedValue = formatNumber(jsString, formatValue, thousandDelimiter, decimalDelimiter, valueFormatOptions);
|
|
71
|
+
const valueAsNumber = parseFloat(jsString);
|
|
61
72
|
const resultValue = Number.isNaN(valueAsNumber) ? defaultValue : valueAsNumber;
|
|
62
73
|
setDisplayValue(formattedValue);
|
|
63
74
|
setLocalValue(resultValue);
|
|
64
75
|
onChange && onChange(resultValue ?? null);
|
|
65
|
-
}, [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
}, [formatValue, thousandDelimiter, decimalDelimiter, valueFormatOptions, defaultValue, onChange]);
|
|
77
|
+
const commitStep = useCallback((next, info) => {
|
|
78
|
+
setDisplayValue(formatter(next));
|
|
79
|
+
setLocalValue(next);
|
|
80
|
+
onChange && onChange(next);
|
|
81
|
+
onStep && onStep(next, info);
|
|
82
|
+
}, [formatter, onChange, onStep]);
|
|
83
|
+
const precision = valueFormatOptions?.maximumFractionDigits;
|
|
84
|
+
const {
|
|
85
|
+
step: stepOnce,
|
|
86
|
+
startStep,
|
|
87
|
+
stopStep,
|
|
88
|
+
upDisabled,
|
|
89
|
+
downDisabled
|
|
90
|
+
} = useStepper({
|
|
91
|
+
value: localValue,
|
|
92
|
+
step,
|
|
93
|
+
min,
|
|
94
|
+
max,
|
|
95
|
+
precision,
|
|
96
|
+
disabled,
|
|
97
|
+
readOnly,
|
|
98
|
+
onStep: commitStep
|
|
99
|
+
});
|
|
100
|
+
const handleKeyDown = useCallback((event) => {
|
|
101
|
+
onKeyDown && onKeyDown(event);
|
|
102
|
+
if (event.key === "ArrowUp") {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
stepOnce(1, event.shiftKey);
|
|
105
|
+
} else if (event.key === "ArrowDown") {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
stepOnce(-1, event.shiftKey);
|
|
108
|
+
}
|
|
109
|
+
}, [stepOnce, onKeyDown]);
|
|
110
|
+
const handleKeyPress = useCallback((event) => {
|
|
111
|
+
onKeyPress && onKeyPress(event);
|
|
112
|
+
if (!NUMERIC_KEY.test(event.key)) {
|
|
113
|
+
event.preventDefault();
|
|
75
114
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
115
|
+
}, [onKeyPress]);
|
|
116
|
+
const handleBlur = useCallback((event) => {
|
|
117
|
+
if (typeof localValue === "number" && Number.isFinite(localValue)) {
|
|
118
|
+
let clamped = localValue;
|
|
119
|
+
if (max !== void 0 && clamped > max) {
|
|
120
|
+
clamped = max;
|
|
79
121
|
}
|
|
80
|
-
|
|
81
|
-
|
|
122
|
+
if (min !== void 0 && clamped < min) {
|
|
123
|
+
clamped = min;
|
|
124
|
+
}
|
|
125
|
+
if (clamped !== localValue) {
|
|
126
|
+
setLocalValue(clamped);
|
|
127
|
+
setDisplayValue(formatter(clamped));
|
|
128
|
+
onChange && onChange(clamped);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
onBlur && onBlur(event);
|
|
132
|
+
}, [localValue, min, max, formatter, onChange, onBlur]);
|
|
82
133
|
const stretchToFit = autoResize && autoResize !== true && Boolean(autoResize.stretchToFit);
|
|
83
|
-
const
|
|
134
|
+
const {
|
|
135
|
+
sizerRef,
|
|
136
|
+
containerRef
|
|
137
|
+
} = useAutosizeWidth({
|
|
138
|
+
value: displayValue,
|
|
139
|
+
placeholder,
|
|
140
|
+
extraWidth: AUTOSIZE_EXTRA_WIDTH,
|
|
141
|
+
placeholderIsMinWidth: autoResizeProps?.placeholderIsMinWidth,
|
|
142
|
+
inputRef
|
|
143
|
+
});
|
|
144
|
+
const handleStretchBefore = useCallback(() => {
|
|
84
145
|
scrollLeftRef.current = inputRef.current?.scrollLeft || 0;
|
|
85
|
-
inputNumberRef.current && inputNumberRef.current.style.removeProperty("max-width");
|
|
86
146
|
}, []);
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
if (stretchToFit && inputNumberRef.current && parentRect?.width) {
|
|
90
|
-
inputNumberRef.current.style.maxWidth = `${parentRect?.width}px`;
|
|
91
|
-
inputRef.current && inputRef.current.scrollTo(scrollLeftRef.current, 0);
|
|
92
|
-
}
|
|
93
|
-
}, [stretchToFit]);
|
|
94
|
-
const handleWrapperToResize = useCallback(() => {
|
|
95
|
-
handlePreAutosize();
|
|
96
|
-
handleAutosize();
|
|
97
|
-
}, [handleAutosize, handlePreAutosize]);
|
|
98
|
-
const transformRef = useCallback((element) => {
|
|
99
|
-
inputNumberRef.current = element;
|
|
100
|
-
return element.querySelector("input");
|
|
147
|
+
const handleStretchAfter = useCallback(() => {
|
|
148
|
+
inputRef.current && inputRef.current.scrollTo(scrollLeftRef.current, 0);
|
|
101
149
|
}, []);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
150
|
+
const {
|
|
151
|
+
outerRef
|
|
152
|
+
} = useStretchToFit({
|
|
153
|
+
enabled: !!stretchToFit,
|
|
154
|
+
targetRef: containerRef,
|
|
155
|
+
onBeforeResize: handleStretchBefore,
|
|
156
|
+
onAfterResize: handleStretchAfter
|
|
157
|
+
});
|
|
158
|
+
const showHandlers = !disabled && !readOnly;
|
|
159
|
+
const isLarge = size === "large";
|
|
160
|
+
const hasPrefix = prefixel !== void 0 && prefixel !== null;
|
|
161
|
+
const hasSuffix = suffixel !== void 0 && suffixel !== null;
|
|
162
|
+
const numberCore = /* @__PURE__ */ jsxs(InputNumberRoot, { className: cx("ds-input-number", isLarge && "ds-input-number-lg", showError && "error"), $error: showError, $disabled: disabled, $size: size, $hasPrefix: hasPrefix, $hasSuffix: hasSuffix, children: [
|
|
163
|
+
showHandlers && /* @__PURE__ */ jsxs(HandlerWrap, { className: "ds-input-number-handler-wrap", children: [
|
|
164
|
+
/* @__PURE__ */ jsx(HandlerUp, { role: "button", "aria-label": "Increase Value", className: "ds-input-number-handler ds-input-number-handler-up", $disabled: upDisabled, onMouseDown: (event) => {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
startStep(1, event.shiftKey);
|
|
167
|
+
}, onMouseUp: stopStep, onMouseLeave: stopStep }),
|
|
168
|
+
/* @__PURE__ */ jsx(HandlerDown, { role: "button", "aria-label": "Decrease Value", className: "ds-input-number-handler ds-input-number-handler-down", $disabled: downDisabled, onMouseDown: (event) => {
|
|
169
|
+
event.preventDefault();
|
|
170
|
+
startStep(-1, event.shiftKey);
|
|
171
|
+
}, onMouseUp: stopStep, onMouseLeave: stopStep })
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsx(InputFieldWrap, { className: "ds-input-number-input-wrap", $size: size, children: /* @__PURE__ */ jsx(InputField, { ...rest, ref: inputRef, type: "text", inputMode: inputMode ?? "decimal", role: "spinbutton", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": localValue ?? void 0, id, name, className: "ds-input-number-input", autoComplete: "off", placeholder, disabled, readOnly, autoFocus, value: displayValue, $autoResize: autoResize, onChange: (event) => handleInputChange(event.target.value), onKeyDown: handleKeyDown, onKeyPress: handleKeyPress, onBlur: handleBlur }) })
|
|
174
|
+
] });
|
|
175
|
+
const withAddons = hasPrefix || hasSuffix ? /* @__PURE__ */ jsx(GroupWrapper, { className: "ds-input-number-group-wrapper", children: /* @__PURE__ */ jsxs(Group, { className: "ds-input-number-group", children: [
|
|
176
|
+
hasPrefix && /* @__PURE__ */ jsx(Addon, { className: "ds-input-number-group-addon", children: prefixel }),
|
|
177
|
+
numberCore,
|
|
178
|
+
hasSuffix && /* @__PURE__ */ jsx(Addon, { className: "ds-input-number-group-addon", children: suffixel })
|
|
179
|
+
] }) }) : numberCore;
|
|
180
|
+
const rawInput = /* @__PURE__ */ jsx(InputNumberWrapper, { ref: containerRef, style, className, children: withAddons });
|
|
181
|
+
const autoSizeInput = /* @__PURE__ */ jsxs(InputNumberAutosize, { ref: outerRef, $autoResize: autoResize, className: autoResizeProps?.wrapperClassName, style: autoResizeProps?.wrapperStyle, children: [
|
|
182
|
+
rawInput,
|
|
183
|
+
/* @__PURE__ */ jsx("span", { ref: sizerRef, style: SIZER_STYLE, "aria-hidden": true })
|
|
184
|
+
] });
|
|
105
185
|
if (raw) {
|
|
106
186
|
return /* @__PURE__ */ jsx(InputNumberContainer, { children: rawInput });
|
|
107
187
|
}
|
|
108
|
-
return /* @__PURE__ */ jsx(InputNumberContainer, {
|
|
188
|
+
return /* @__PURE__ */ jsx(InputNumberContainer, { children: /* @__PURE__ */ jsx(FormField, { id, label, tooltip, tooltipConfig, description, errorText, children: autoResize ? autoSizeInput : rawInput }) });
|
|
109
189
|
};
|
|
110
190
|
export {
|
|
111
191
|
InputNumber as default
|
|
@@ -1,16 +1,32 @@
|
|
|
1
|
-
import { InputNumberProps } from 'antd';
|
|
2
|
-
import { default as React } from 'react';
|
|
3
1
|
import { ThemeProps } from '@synerise/ds-core';
|
|
4
2
|
import { AutoResizeProp } from '@synerise/ds-input';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
type SizeProp = 'small' | 'middle' | 'large';
|
|
4
|
+
export declare const HandlerUp: import('styled-components').StyledComponent<"span", any, {
|
|
5
|
+
$disabled?: boolean;
|
|
6
|
+
} & ThemeProps, never>;
|
|
7
|
+
export declare const HandlerDown: import('styled-components').StyledComponent<"span", any, {
|
|
8
|
+
$disabled?: boolean;
|
|
9
|
+
} & ThemeProps, never>;
|
|
10
|
+
export declare const HandlerWrap: import('styled-components').StyledComponent<"div", any, ThemeProps, never>;
|
|
11
|
+
export declare const InputField: import('styled-components').StyledComponent<"input", any, {
|
|
12
|
+
$autoResize?: AutoResizeProp;
|
|
13
|
+
} & ThemeProps, never>;
|
|
14
|
+
export declare const InputFieldWrap: import('styled-components').StyledComponent<"div", any, {
|
|
15
|
+
$size?: SizeProp;
|
|
10
16
|
}, never>;
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
17
|
+
export declare const Addon: import('styled-components').StyledComponent<"div", any, ThemeProps, never>;
|
|
18
|
+
export declare const Group: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
19
|
+
export declare const GroupWrapper: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
20
|
+
export declare const InputNumberRoot: import('styled-components').StyledComponent<"div", any, {
|
|
21
|
+
$error?: boolean;
|
|
22
|
+
$disabled?: boolean;
|
|
23
|
+
$size?: SizeProp;
|
|
24
|
+
$hasPrefix?: boolean;
|
|
25
|
+
$hasSuffix?: boolean;
|
|
13
26
|
} & ThemeProps, never>;
|
|
14
|
-
export declare const Prefixel: import('styled-components').StyledComponent<"div", any, ThemeProps, never>;
|
|
15
|
-
export declare const Suffixel: import('styled-components').StyledComponent<"div", any, ThemeProps, never>;
|
|
16
27
|
export declare const InputNumberWrapper: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
28
|
+
export declare const InputNumberContainer: import('styled-components').StyledComponent<"div", any, {}, never>;
|
|
29
|
+
export declare const InputNumberAutosize: import('styled-components').StyledComponent<"div", any, {
|
|
30
|
+
$autoResize?: AutoResizeProp;
|
|
31
|
+
}, never>;
|
|
32
|
+
export {};
|
|
@@ -1,44 +1,69 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
displayName: "InputNumberstyles__InputNumberContainer",
|
|
1
|
+
import styled, { css } from "styled-components";
|
|
2
|
+
import { autoresizeConfObjToCss } from "@synerise/ds-input";
|
|
3
|
+
import { ANGLE_DOWN_SVG, ANGLE_UP_SVG } from "./constants/inputNumber.constants.js";
|
|
4
|
+
const handlerGlyph = /* @__PURE__ */ css(["position:relative;flex:1 1 50%;min-height:0;cursor:pointer;user-select:none;&::before{content:'';position:absolute;inset:0;background-color:", ";mask-repeat:no-repeat;mask-position:center;mask-size:16px 16px;-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:16px 16px;}& > svg,& > i{display:none;}"], (props) => props.theme.palette["grey-600"]);
|
|
5
|
+
const HandlerUp = /* @__PURE__ */ styled.span.withConfig({
|
|
6
|
+
displayName: "InputNumberstyles__HandlerUp",
|
|
8
7
|
componentId: "sc-abrul0-0"
|
|
9
|
-
})(["
|
|
10
|
-
const
|
|
11
|
-
displayName: "
|
|
8
|
+
})(["", " &::before{mask-image:url('", "');-webkit-mask-image:url('", "');}", ""], handlerGlyph, ANGLE_UP_SVG, ANGLE_UP_SVG, (props) => props.$disabled && css(["cursor:not-allowed;opacity:0.4;"]));
|
|
9
|
+
const HandlerDown = /* @__PURE__ */ styled.span.withConfig({
|
|
10
|
+
displayName: "InputNumberstyles__HandlerDown",
|
|
12
11
|
componentId: "sc-abrul0-1"
|
|
13
|
-
})(["
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}));
|
|
17
|
-
const NumberOnlyBaseAntInputNumber = forwardRef((props, ref) => /* @__PURE__ */ jsx(InputNumber, { ...props, ref }));
|
|
18
|
-
const AntdInputNumber = /* @__PURE__ */ styled(NumberOnlyBaseAntInputNumber).withConfig({
|
|
19
|
-
displayName: "InputNumberstyles__AntdInputNumber",
|
|
12
|
+
})(["", " &::before{mask-image:url('", "');-webkit-mask-image:url('", "');}border-top:1px solid ", ";", ""], handlerGlyph, ANGLE_DOWN_SVG, ANGLE_DOWN_SVG, (props) => props.theme.palette["grey-300"], (props) => props.$disabled && css(["cursor:not-allowed;opacity:0.4;"]));
|
|
13
|
+
const HandlerWrap = /* @__PURE__ */ styled.div.withConfig({
|
|
14
|
+
displayName: "InputNumberstyles__HandlerWrap",
|
|
20
15
|
componentId: "sc-abrul0-2"
|
|
21
|
-
})(["
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
`, (props) => props.theme.palette["grey-050"]);
|
|
25
|
-
const Prefixel = /* @__PURE__ */ styled.div.withConfig({
|
|
26
|
-
displayName: "InputNumberstyles__Prefixel",
|
|
16
|
+
})(["position:absolute;z-index:3;top:1px;right:1px;width:22px;height:30px;display:flex;flex-direction:column;border-left:1px solid ", ";opacity:0;transition:opacity 0.24s linear 0.1s;"], (props) => props.theme.palette["grey-300"]);
|
|
17
|
+
const InputField = /* @__PURE__ */ styled.input.withConfig({
|
|
18
|
+
displayName: "InputNumberstyles__InputField",
|
|
27
19
|
componentId: "sc-abrul0-3"
|
|
28
|
-
})(["border:
|
|
29
|
-
const
|
|
30
|
-
displayName: "
|
|
20
|
+
})(["box-sizing:border-box;display:block;width:100%;height:100%;text-align:left;&&{height:100%;padding:", ";line-height:1;}color:inherit;font-family:inherit;font-size:13px;font-variant-numeric:tabular-nums;background:transparent;border:0;outline:0;transition:unset;&::placeholder{color:", ";}&:focus{box-shadow:unset;}"], (props) => props.$autoResize ? "0" : "7px 11px", (props) => props.theme.palette["grey-500"]);
|
|
21
|
+
const InputFieldWrap = /* @__PURE__ */ styled.div.withConfig({
|
|
22
|
+
displayName: "InputNumberstyles__InputFieldWrap",
|
|
31
23
|
componentId: "sc-abrul0-4"
|
|
32
|
-
})(["
|
|
24
|
+
})(["height:100%;margin:0 2px;"]);
|
|
25
|
+
const Addon = /* @__PURE__ */ styled.div.withConfig({
|
|
26
|
+
displayName: "InputNumberstyles__Addon",
|
|
27
|
+
componentId: "sc-abrul0-5"
|
|
28
|
+
})(["display:flex;align-items:center;padding:0 12px;background-color:", ";border:1px solid ", ";&:first-child{border-radius:3px 0 0 3px;border-right-width:0;}&:last-child{border-radius:0 3px 3px 0;border-left-width:0;}"], (props) => props.theme.palette["grey-050"], (props) => props.theme.palette["grey-300"]);
|
|
29
|
+
const Group = /* @__PURE__ */ styled.div.withConfig({
|
|
30
|
+
displayName: "InputNumberstyles__Group",
|
|
31
|
+
componentId: "sc-abrul0-6"
|
|
32
|
+
})(["display:inline-flex;width:100%;vertical-align:top;"]);
|
|
33
|
+
const GroupWrapper = /* @__PURE__ */ styled.div.withConfig({
|
|
34
|
+
displayName: "InputNumberstyles__GroupWrapper",
|
|
35
|
+
componentId: "sc-abrul0-7"
|
|
36
|
+
})(["display:inline-block;"]);
|
|
37
|
+
const InputNumberRoot = /* @__PURE__ */ styled.div.withConfig({
|
|
38
|
+
displayName: "InputNumberstyles__InputNumberRoot",
|
|
39
|
+
componentId: "sc-abrul0-8"
|
|
40
|
+
})(["position:relative;box-sizing:border-box;width:100%;height:", ";line-height:1.38;color:", ";background:", ";border:0;border-radius:", ";box-shadow:", ";&:focus-within{box-shadow:", ";background:", ";}", " &:hover ", ",&:focus-within ", "{opacity:1;}&:focus-within ", "{width:21px;height:28px;top:2px;right:2px;}", " ", " ", ""], (props) => props.$size === "large" ? "48px" : "32px", (props) => props.theme.palette["grey-700"], (props) => props.$error ? props.theme.palette["red-050"] : props.theme.palette.white, (props) => `${props.$hasPrefix ? "0" : "3px"} ${props.$hasSuffix ? "0" : "3px"} ${props.$hasSuffix ? "0" : "3px"} ${props.$hasPrefix ? "0" : "3px"}`, (props) => props.$error ? `inset 0px 0px 0px 2px ${props.theme.palette["red-600"]}` : `inset 0px 0px 0px 1px ${props.theme.palette["grey-300"]}`, (props) => props.$error ? `inset 0px 0px 0px 2px ${props.theme.palette["red-600"]}` : `inset 0px 0px 0px 2px ${props.theme.palette["blue-600"]}`, (props) => props.$error ? props.theme.palette["red-050"] : props.theme.palette["blue-050"], (props) => !props.$error && !props.$disabled && css(["&:hover:not(:focus-within){box-shadow:inset 0px 0px 0px 1px ", ";}"], props.theme.palette["grey-400"]), HandlerWrap, HandlerWrap, HandlerWrap, (props) => props.$error && css(["", "{width:21px;height:28px;top:2px;right:2px;}"], HandlerWrap), (props) => props.$size === "large" && css(["", "{width:24px;height:44px;}&:focus-within ", "{height:44px;}"], HandlerWrap, HandlerWrap), (props) => props.$disabled && css(["cursor:not-allowed;background:", ";", "{cursor:not-allowed;color:", ";}"], props.theme.palette["grey-050"], InputField, props.theme.palette["grey-400"]));
|
|
33
41
|
const InputNumberWrapper = /* @__PURE__ */ styled.div.withConfig({
|
|
34
42
|
displayName: "InputNumberstyles__InputNumberWrapper",
|
|
35
|
-
componentId: "sc-abrul0-
|
|
36
|
-
})([""]);
|
|
43
|
+
componentId: "sc-abrul0-9"
|
|
44
|
+
})(["display:block;"]);
|
|
45
|
+
const InputNumberContainer = /* @__PURE__ */ styled.div.withConfig({
|
|
46
|
+
displayName: "InputNumberstyles__InputNumberContainer",
|
|
47
|
+
componentId: "sc-abrul0-10"
|
|
48
|
+
})(["display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;"]);
|
|
49
|
+
const InputNumberAutosize = /* @__PURE__ */ styled.div.withConfig({
|
|
50
|
+
displayName: "InputNumberstyles__InputNumberAutosize",
|
|
51
|
+
componentId: "sc-abrul0-11"
|
|
52
|
+
})(["", " ", "{text-indent:4px;letter-spacing:normal;font-variant-numeric:tabular-nums;}"], (props) => css(["", "{width:", ";", ";grid-area:1 / 1;}"], InputNumberRoot, props.$autoResize ? "100%" : "200px", autoresizeConfObjToCss({
|
|
53
|
+
autoResize: props.$autoResize,
|
|
54
|
+
boxSizing: "border-box"
|
|
55
|
+
})), InputField);
|
|
37
56
|
export {
|
|
38
|
-
|
|
57
|
+
Addon,
|
|
58
|
+
Group,
|
|
59
|
+
GroupWrapper,
|
|
60
|
+
HandlerDown,
|
|
61
|
+
HandlerUp,
|
|
62
|
+
HandlerWrap,
|
|
63
|
+
InputField,
|
|
64
|
+
InputFieldWrap,
|
|
39
65
|
InputNumberAutosize,
|
|
40
66
|
InputNumberContainer,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Suffixel
|
|
67
|
+
InputNumberRoot,
|
|
68
|
+
InputNumberWrapper
|
|
44
69
|
};
|
|
@@ -1,10 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ReactNode } from 'react';
|
|
1
|
+
import { CSSProperties, FocusEvent, InputHTMLAttributes, KeyboardEvent, ReactNode } from 'react';
|
|
3
2
|
import { NumberToFormatOptions } from '@synerise/ds-core';
|
|
4
3
|
import { FormFieldCommonProps } from '@synerise/ds-form-field';
|
|
5
4
|
import { AutoResizeProp, AutosizeInputProps } from '@synerise/ds-input';
|
|
6
|
-
|
|
5
|
+
import { PassthroughAttributes } from '@synerise/ds-utils';
|
|
6
|
+
type InputNumberOwnProps = {
|
|
7
|
+
value?: number | null;
|
|
7
8
|
defaultValue?: number | null;
|
|
9
|
+
onChange?: (value: number | null) => void;
|
|
10
|
+
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
|
|
11
|
+
onKeyPress?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
12
|
+
onStep?: (value: number, info: {
|
|
13
|
+
offset: number;
|
|
14
|
+
type: 'up' | 'down';
|
|
15
|
+
}) => void;
|
|
16
|
+
min?: number;
|
|
17
|
+
max?: number;
|
|
18
|
+
step?: number | string;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
readOnly?: boolean;
|
|
21
|
+
autoFocus?: boolean;
|
|
22
|
+
tabIndex?: number;
|
|
23
|
+
placeholder?: string;
|
|
24
|
+
size?: 'small' | 'middle' | 'large';
|
|
25
|
+
name?: string;
|
|
26
|
+
id?: string;
|
|
8
27
|
error?: boolean;
|
|
9
28
|
prefixel?: ReactNode;
|
|
10
29
|
suffixel?: ReactNode;
|
|
@@ -12,8 +31,12 @@ export type InputNumberProps = AntdInputNumberProps<number> & {
|
|
|
12
31
|
valueFormatOptions?: NumberToFormatOptions;
|
|
13
32
|
autoResize?: AutoResizeProp;
|
|
14
33
|
autoResizeProps?: Partial<Pick<AutosizeInputProps, 'placeholderIsMinWidth' | 'wrapperClassName' | 'wrapperStyle' | 'extraWidth'>>;
|
|
15
|
-
|
|
34
|
+
style?: CSSProperties;
|
|
35
|
+
className?: string;
|
|
36
|
+
};
|
|
37
|
+
export type InputNumberProps = InputNumberOwnProps & FormFieldCommonProps & PassthroughAttributes & Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'size' | 'min' | 'max' | 'type'>;
|
|
16
38
|
/**
|
|
17
39
|
* @deprecated - use InputNumberProps
|
|
18
40
|
*/
|
|
19
41
|
export type Props = InputNumberProps;
|
|
42
|
+
export {};
|
|
@@ -2,3 +2,5 @@ import { Delimiter } from '@synerise/ds-core';
|
|
|
2
2
|
export declare const MAXIMUM_FRACTION_DIGITS = 20;
|
|
3
3
|
export declare const NUMBER_DELIMITER: Delimiter;
|
|
4
4
|
export declare const MAXIMUM_NUMBER_DIGITS = 15;
|
|
5
|
+
export declare const ANGLE_UP_SVG = "data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAxLWFuZ2xlLXVwLXM8L3RpdGxlPjxyZWN0IGlkPSJjYW52YXMiIGNsYXNzPSJjbHMtMSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMTUuMjUsMTQuMzhhLjc5Ljc5LDAsMCwxLS41My0uMjJMMTIsMTEuNDQsOS4yOCwxNC4xNmEuNzUuNzUsMCwwLDEtMS4wNiwwLC43Ny43NywwLDAsMSwwLTEuMDdsMy4yNS0zLjI1YS43NS43NSwwLDAsMSwxLjA2LDBsMy4yNSwzLjI1YS43Ny43NywwLDAsMSwwLDEuMDdBLjc5Ljc5LDAsMCwxLDE1LjI1LDE0LjM4WiIvPjwvc3ZnPg==";
|
|
6
|
+
export declare const ANGLE_DOWN_SVG = "data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAzLWFuZ2xlLWRvd24tczwvdGl0bGU+PHJlY3QgaWQ9ImNhbnZhcyIgY2xhc3M9ImNscy0xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik0xMiwxNC4zOGEuNzkuNzksMCwwLDEtLjUzLS4yMkw4LjIyLDEwLjkxYS43Ny43NywwLDAsMSwwLTEuMDcuNzUuNzUsMCwwLDEsMS4wNiwwTDEyLDEyLjU2bDIuNzItMi43MmEuNzUuNzUsMCwwLDEsMS4wNiwwLC43Ny43NywwLDAsMSwwLDEuMDdsLTMuMjUsMy4yNUEuNzkuNzksMCwwLDEsMTIsMTQuMzhaIi8+PC9zdmc+";
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
const MAXIMUM_FRACTION_DIGITS = 20;
|
|
2
2
|
const NUMBER_DELIMITER = ".";
|
|
3
3
|
const MAXIMUM_NUMBER_DIGITS = 15;
|
|
4
|
+
const ANGLE_UP_SVG = "data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAxLWFuZ2xlLXVwLXM8L3RpdGxlPjxyZWN0IGlkPSJjYW52YXMiIGNsYXNzPSJjbHMtMSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMTUuMjUsMTQuMzhhLjc5Ljc5LDAsMCwxLS41My0uMjJMMTIsMTEuNDQsOS4yOCwxNC4xNmEuNzUuNzUsMCwwLDEtMS4wNiwwLC43Ny43NywwLDAsMSwwLTEuMDdsMy4yNS0zLjI1YS43NS43NSwwLDAsMSwxLjA2LDBsMy4yNSwzLjI1YS43Ny43NywwLDAsMSwwLDEuMDdBLjc5Ljc5LDAsMCwxLDE1LjI1LDE0LjM4WiIvPjwvc3ZnPg==";
|
|
5
|
+
const ANGLE_DOWN_SVG = "data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAzLWFuZ2xlLWRvd24tczwvdGl0bGU+PHJlY3QgaWQ9ImNhbnZhcyIgY2xhc3M9ImNscy0xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik0xMiwxNC4zOGEuNzkuNzksMCwwLDEtLjUzLS4yMkw4LjIyLDEwLjkxYS43Ny43NywwLDAsMSwwLTEuMDcuNzUuNzUsMCwwLDEsMS4wNiwwTDEyLDEyLjU2bDIuNzItMi43MmEuNzUuNzUsMCwwLDEsMS4wNiwwLC43Ny43NywwLDAsMSwwLDEuMDdsLTMuMjUsMy4yNUEuNzkuNzksMCwwLDEsMTIsMTQuMzhaIi8+PC9zdmc+";
|
|
4
6
|
export {
|
|
7
|
+
ANGLE_DOWN_SVG,
|
|
8
|
+
ANGLE_UP_SVG,
|
|
5
9
|
MAXIMUM_FRACTION_DIGITS,
|
|
6
10
|
MAXIMUM_NUMBER_DIGITS,
|
|
7
11
|
NUMBER_DELIMITER
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type UseStepperArgs = {
|
|
2
|
+
value: number | null | undefined;
|
|
3
|
+
step?: number | string;
|
|
4
|
+
min?: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
/** Display precision floor (from valueFormatOptions); the step's own decimals are added on top. */
|
|
7
|
+
precision?: number;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
readOnly?: boolean;
|
|
10
|
+
onStep: (next: number, info: {
|
|
11
|
+
offset: number;
|
|
12
|
+
type: 'up' | 'down';
|
|
13
|
+
}) => void;
|
|
14
|
+
};
|
|
15
|
+
type UseStepperResult = {
|
|
16
|
+
/** Single step — used for keyboard (the OS repeats key-down events itself). */
|
|
17
|
+
step: (direction: 1 | -1, decuple?: boolean) => void;
|
|
18
|
+
/** Press-and-hold: immediate step, then auto-repeat — used for the mouse handlers. */
|
|
19
|
+
startStep: (direction: 1 | -1, decuple?: boolean) => void;
|
|
20
|
+
stopStep: () => void;
|
|
21
|
+
upDisabled: boolean;
|
|
22
|
+
downDisabled: boolean;
|
|
23
|
+
};
|
|
24
|
+
export declare const useStepper: ({ value, step, min, max, precision, disabled, readOnly, onStep, }: UseStepperArgs) => UseStepperResult;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useRef, useCallback, useEffect } from "react";
|
|
2
|
+
const STEP_DELAY = 600;
|
|
3
|
+
const STEP_INTERVAL = 200;
|
|
4
|
+
const DECUPLE = 10;
|
|
5
|
+
const countDecimals = (value) => {
|
|
6
|
+
if (!Number.isFinite(value)) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
const text = String(value);
|
|
10
|
+
if (text.includes("e-")) {
|
|
11
|
+
return Number(text.split("e-")[1]);
|
|
12
|
+
}
|
|
13
|
+
return text.includes(".") ? text.split(".")[1].length : 0;
|
|
14
|
+
};
|
|
15
|
+
const scaledAdd = (a, b) => {
|
|
16
|
+
const factor = Math.pow(10, Math.max(countDecimals(a), countDecimals(b)));
|
|
17
|
+
return (Math.round(a * factor) + Math.round(b * factor)) / factor;
|
|
18
|
+
};
|
|
19
|
+
const clamp = (value, min, max) => {
|
|
20
|
+
let next = value;
|
|
21
|
+
if (max !== void 0 && next > max) {
|
|
22
|
+
next = max;
|
|
23
|
+
}
|
|
24
|
+
if (min !== void 0 && next < min) {
|
|
25
|
+
next = min;
|
|
26
|
+
}
|
|
27
|
+
return next;
|
|
28
|
+
};
|
|
29
|
+
const applyPrecision = (value, precision) => precision === void 0 ? value : Number(value.toFixed(precision));
|
|
30
|
+
const useStepper = ({
|
|
31
|
+
value,
|
|
32
|
+
step = 1,
|
|
33
|
+
min,
|
|
34
|
+
max,
|
|
35
|
+
precision,
|
|
36
|
+
disabled,
|
|
37
|
+
readOnly,
|
|
38
|
+
onStep
|
|
39
|
+
}) => {
|
|
40
|
+
const timerRef = useRef(null);
|
|
41
|
+
const latest = useRef({
|
|
42
|
+
value,
|
|
43
|
+
step,
|
|
44
|
+
min,
|
|
45
|
+
max,
|
|
46
|
+
precision,
|
|
47
|
+
disabled,
|
|
48
|
+
readOnly,
|
|
49
|
+
onStep
|
|
50
|
+
});
|
|
51
|
+
latest.current = {
|
|
52
|
+
value,
|
|
53
|
+
step,
|
|
54
|
+
min,
|
|
55
|
+
max,
|
|
56
|
+
precision,
|
|
57
|
+
disabled,
|
|
58
|
+
readOnly,
|
|
59
|
+
onStep
|
|
60
|
+
};
|
|
61
|
+
const base = value ?? 0;
|
|
62
|
+
const locked = Boolean(disabled || readOnly);
|
|
63
|
+
const upDisabled = locked || max !== void 0 && base >= max;
|
|
64
|
+
const downDisabled = locked || min !== void 0 && base <= min;
|
|
65
|
+
const stepOnce = useCallback((direction, decuple = false) => {
|
|
66
|
+
const args = latest.current;
|
|
67
|
+
if (args.disabled || args.readOnly) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const rawStep = typeof args.step === "string" ? parseFloat(args.step) || 1 : args.step ?? 1;
|
|
71
|
+
const delta = rawStep * (decuple ? DECUPLE : 1) * direction;
|
|
72
|
+
const effectivePrecision = Math.max(countDecimals(rawStep), args.precision ?? 0);
|
|
73
|
+
const next = applyPrecision(clamp(scaledAdd(args.value ?? 0, delta), args.min, args.max), effectivePrecision);
|
|
74
|
+
args.onStep(next, {
|
|
75
|
+
offset: Math.abs(delta),
|
|
76
|
+
type: direction === 1 ? "up" : "down"
|
|
77
|
+
});
|
|
78
|
+
}, []);
|
|
79
|
+
const clearTimer = useCallback(() => {
|
|
80
|
+
if (timerRef.current) {
|
|
81
|
+
clearTimeout(timerRef.current);
|
|
82
|
+
timerRef.current = null;
|
|
83
|
+
}
|
|
84
|
+
}, []);
|
|
85
|
+
const startStep = useCallback((direction, decuple = false) => {
|
|
86
|
+
clearTimer();
|
|
87
|
+
if (latest.current.disabled || latest.current.readOnly) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
stepOnce(direction, decuple);
|
|
91
|
+
const loop = () => {
|
|
92
|
+
stepOnce(direction, decuple);
|
|
93
|
+
timerRef.current = setTimeout(loop, STEP_INTERVAL);
|
|
94
|
+
};
|
|
95
|
+
timerRef.current = setTimeout(loop, STEP_DELAY);
|
|
96
|
+
}, [clearTimer, stepOnce]);
|
|
97
|
+
useEffect(() => clearTimer, [clearTimer]);
|
|
98
|
+
return {
|
|
99
|
+
step: stepOnce,
|
|
100
|
+
startStep,
|
|
101
|
+
stopStep: clearTimer,
|
|
102
|
+
upDisabled,
|
|
103
|
+
downDisabled
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export {
|
|
107
|
+
useStepper
|
|
108
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synerise/ds-input-number",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.50",
|
|
4
4
|
"description": "Input-Number UI Component for the Synerise Design System",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": "Synerise/synerise-design",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"/dist",
|
|
19
19
|
"CHANGELOG.md",
|
|
20
|
+
"CLAUDE.md",
|
|
20
21
|
"README.md",
|
|
21
22
|
"package.json",
|
|
22
23
|
"LICENSE.md"
|
|
@@ -35,23 +36,19 @@
|
|
|
35
36
|
"check:circular-dependencies": "madge --circular --extensions ts,tsx,js,jsx --ts-config tsconfig.json src/ --exclude '/dist/'",
|
|
36
37
|
"upgrade:ds": "ncu -f \"@synerise/ds-*\" -u"
|
|
37
38
|
},
|
|
38
|
-
"sideEffects":
|
|
39
|
-
"dist/style/*",
|
|
40
|
-
"*.less"
|
|
41
|
-
],
|
|
39
|
+
"sideEffects": false,
|
|
42
40
|
"types": "dist/index.d.ts",
|
|
43
41
|
"dependencies": {
|
|
44
|
-
"@synerise/ds-form-field": "^1.3.
|
|
45
|
-
"@synerise/ds-input": "^1.7.
|
|
46
|
-
"@synerise/ds-utils": "^1.10.
|
|
42
|
+
"@synerise/ds-form-field": "^1.3.24",
|
|
43
|
+
"@synerise/ds-input": "^1.7.13",
|
|
44
|
+
"@synerise/ds-utils": "^1.10.2",
|
|
47
45
|
"uuid": "^8.3.2"
|
|
48
46
|
},
|
|
49
47
|
"peerDependencies": {
|
|
50
48
|
"@synerise/ds-core": "*",
|
|
51
|
-
"antd": "4.24.16",
|
|
52
49
|
"react": ">=16.9.0 <= 18.3.1",
|
|
53
50
|
"styled-components": "^5.3.3",
|
|
54
51
|
"vitest": "4"
|
|
55
52
|
},
|
|
56
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
|
|
57
54
|
}
|
|
File without changes
|
package/dist/style/index.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.ant-input-number-affix-wrapper{display:inline-block;width:100%;min-width:0;padding:4px 15px;color:#6a7580;font-size:13px;line-height:1.38;background-color:#fff;background-image:none;border:1px solid #dbe0e3;border-radius:3px;transition:all .3s;position:relative;display:inline-flex;width:90px;padding:0;padding-inline-start:15px}.ant-input-number-affix-wrapper::placeholder{color:#b5bdc3;user-select:none}.ant-input-number-affix-wrapper:placeholder-shown{text-overflow:ellipsis}.ant-input-number-affix-wrapper:hover{border-color:#b5bdc3;border-right-width:1px}.ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper:focus{border-color:#38f;box-shadow:0 0 0 0 rgba(11,104,255,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-disabled{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-affix-wrapper-disabled:hover{border-color:#dbe0e3;border-right-width:1px}.ant-input-number-affix-wrapper[disabled]{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-affix-wrapper[disabled]:hover{border-color:#dbe0e3;border-right-width:1px}.ant-input-number-affix-wrapper-borderless,.ant-input-number-affix-wrapper-borderless-disabled,.ant-input-number-affix-wrapper-borderless-focused,.ant-input-number-affix-wrapper-borderless:focus,.ant-input-number-affix-wrapper-borderless:hover,.ant-input-number-affix-wrapper-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input-number-affix-wrapper{max-width:100%;height:auto;min-height:32px;line-height:1.38;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-number-affix-wrapper-lg{padding:6px 15px;font-size:13px}.ant-input-number-affix-wrapper-sm{padding:1px 7px}.ant-input-number-affix-wrapper:not(.ant-input-number-affix-wrapper-disabled):hover{border-color:#b5bdc3;border-right-width:1px;z-index:1}.ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper:focus{z-index:1}.ant-input-number-affix-wrapper-disabled .ant-input-number[disabled]{background:0 0}.ant-input-number-affix-wrapper>div.ant-input-number{width:100%;border:none;outline:0}.ant-input-number-affix-wrapper>div.ant-input-number.ant-input-number-focused{box-shadow:none!important}.ant-input-number-affix-wrapper input.ant-input-number-input{padding:0}.ant-input-number-affix-wrapper::before{display:inline-block;width:0;visibility:hidden;content:'\a0'}.ant-input-number-affix-wrapper .ant-input-number-handler-wrap{z-index:2}.ant-input-number-prefix,.ant-input-number-suffix{display:flex;flex:none;align-items:center;pointer-events:none}.ant-input-number-prefix{margin-inline-end:4px}.ant-input-number-suffix{position:absolute;top:0;right:0;z-index:1;height:100%;margin-right:15px;margin-left:4px}.ant-input-number-group-wrapper .ant-input-number-affix-wrapper{width:100%}.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number,.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:hover{background:#fff;border-color:#f52922}.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number-focused,.ant-input-number-status-error:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:focus{border-color:#ff584d;box-shadow:0 0 0 0 rgba(245,41,34,.2);border-right-width:1px;outline:0}.ant-input-number-status-error .ant-input-number-prefix{color:#f52922}.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number,.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:hover{background:#fff;border-color:#fab700}.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number-focused,.ant-input-number-status-warning:not(.ant-input-number-disabled):not(.ant-input-number-borderless).ant-input-number:focus{border-color:#ffcd29;box-shadow:0 0 0 0 rgba(250,183,0,.2);border-right-width:1px;outline:0}.ant-input-number-status-warning .ant-input-number-prefix{color:#fab700}.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper,.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:hover{background:#fff;border-color:#f52922}.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper-status-error:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:focus{border-color:#ff584d;box-shadow:0 0 0 0 rgba(245,41,34,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-status-error .ant-input-number-prefix{color:#f52922}.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper,.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:hover{background:#fff;border-color:#fab700}.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper-focused,.ant-input-number-affix-wrapper-status-warning:not(.ant-input-number-affix-wrapper-disabled):not(.ant-input-number-affix-wrapper-borderless).ant-input-number-affix-wrapper:focus{border-color:#ffcd29;box-shadow:0 0 0 0 rgba(250,183,0,.2);border-right-width:1px;outline:0}.ant-input-number-affix-wrapper-status-warning .ant-input-number-prefix{color:#fab700}.ant-input-number-group-wrapper-status-error .ant-input-number-group-addon{color:#f52922;border-color:#f52922}.ant-input-number-group-wrapper-status-warning .ant-input-number-group-addon{color:#fab700;border-color:#fab700}.ant-input-number{box-sizing:border-box;font-variant:tabular-nums;list-style:none;font-feature-settings:'tnum';position:relative;width:100%;min-width:0;padding:4px 15px;color:#6a7580;font-size:13px;line-height:1.38;background-color:#fff;background-image:none;transition:all .3s;display:inline-block;width:90px;margin:0;padding:0;border:1px solid #dbe0e3;border-radius:3px}.ant-input-number::placeholder{color:#b5bdc3;user-select:none}.ant-input-number:placeholder-shown{text-overflow:ellipsis}.ant-input-number:hover{border-color:#b5bdc3;border-right-width:1px}.ant-input-number-focused,.ant-input-number:focus{border-color:#38f;box-shadow:0 0 0 0 rgba(11,104,255,.2);border-right-width:1px;outline:0}.ant-input-number-disabled{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-disabled:hover{border-color:#dbe0e3;border-right-width:1px}.ant-input-number[disabled]{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number[disabled]:hover{border-color:#dbe0e3;border-right-width:1px}.ant-input-number-borderless,.ant-input-number-borderless-disabled,.ant-input-number-borderless-focused,.ant-input-number-borderless:focus,.ant-input-number-borderless:hover,.ant-input-number-borderless[disabled]{background-color:transparent;border:none;box-shadow:none}textarea.ant-input-number{max-width:100%;height:auto;min-height:32px;line-height:1.38;vertical-align:bottom;transition:all .3s,height 0s}.ant-input-number-lg{padding:6px 15px;font-size:13px}.ant-input-number-sm{padding:1px 7px}.ant-input-number-group{box-sizing:border-box;margin:0;padding:0;color:#6a7580;font-size:13px;font-variant:tabular-nums;line-height:1.38;list-style:none;font-feature-settings:'tnum';position:relative;display:table;width:100%;border-collapse:separate;border-spacing:0}.ant-input-number-group[class*=col-]{float:none;padding-right:0;padding-left:0}.ant-input-number-group>[class*=col-]{padding-right:8px}.ant-input-number-group>[class*=col-]:last-child{padding-right:0}.ant-input-number-group-addon,.ant-input-number-group-wrap,.ant-input-number-group>.ant-input-number{display:table-cell}.ant-input-number-group-addon:not(:first-child):not(:last-child),.ant-input-number-group-wrap:not(:first-child):not(:last-child),.ant-input-number-group>.ant-input-number:not(:first-child):not(:last-child){border-radius:0}.ant-input-number-group-addon,.ant-input-number-group-wrap{width:1px;white-space:nowrap;vertical-align:middle}.ant-input-number-group-wrap>*{display:block!important}.ant-input-number-group .ant-input-number{float:left;width:100%;margin-bottom:0;text-align:inherit}.ant-input-number-group .ant-input-number:focus{z-index:1;border-right-width:1px}.ant-input-number-group .ant-input-number:hover{z-index:1;border-right-width:1px}.ant-input-search-with-button .ant-input-number-group .ant-input-number:hover{z-index:0}.ant-input-number-group-addon{position:relative;padding:0 15px;color:#6a7580;font-weight:400;font-size:13px;text-align:center;background-color:#e9edee;border:1px solid #dbe0e3;border-radius:3px;transition:all .3s}.ant-input-number-group-addon .ant-select{margin:-5px -15px}.ant-input-number-group-addon .ant-select.ant-select-single:not(.ant-select-customize-input) .ant-select-selector{background-color:inherit;border:1px solid transparent;box-shadow:none}.ant-input-number-group-addon .ant-select-focused .ant-select-selector,.ant-input-number-group-addon .ant-select-open .ant-select-selector{color:#0b68ff}.ant-input-number-group-addon .ant-cascader-picker{margin:-9px -16px;background-color:transparent}.ant-input-number-group-addon .ant-cascader-picker .ant-cascader-input{text-align:left;border:0;box-shadow:none}.ant-input-number-group-addon:first-child,.ant-input-number-group>.ant-input-number:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group-addon:first-child .ant-select .ant-select-selector,.ant-input-number-group>.ant-input-number:first-child .ant-select .ant-select-selector{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group>.ant-input-number-affix-wrapper:not(:first-child) .ant-input-number{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group>.ant-input-number-affix-wrapper:not(:last-child) .ant-input-number{border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-group-addon:first-child{border-right:0}.ant-input-number-group-addon:last-child{border-left:0}.ant-input-number-group-addon:last-child,.ant-input-number-group>.ant-input-number:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group-addon:last-child .ant-select .ant-select-selector,.ant-input-number-group>.ant-input-number:last-child .ant-select .ant-select-selector{border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group-lg .ant-input-number,.ant-input-number-group-lg>.ant-input-number-group-addon{padding:6px 15px;font-size:13px}.ant-input-number-group-sm .ant-input-number,.ant-input-number-group-sm>.ant-input-number-group-addon{padding:1px 7px}.ant-input-number-group-lg .ant-select-single .ant-select-selector{height:48px}.ant-input-number-group-sm .ant-select-single .ant-select-selector{height:24px}.ant-input-number-group .ant-input-number-affix-wrapper:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-search .ant-input-number-group .ant-input-number-affix-wrapper:not(:last-child){border-top-left-radius:3px;border-bottom-left-radius:3px}.ant-input-number-group .ant-input-number-affix-wrapper:not(:first-child),.ant-input-search .ant-input-number-group .ant-input-number-affix-wrapper:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-group.ant-input-number-group-compact{display:block}.ant-input-number-group.ant-input-number-group-compact::before{display:table;content:''}.ant-input-number-group.ant-input-number-group-compact::after{display:table;clear:both;content:''}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child),.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child){border-right-width:1px}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child):hover,.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child):hover,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child):hover{z-index:1}.ant-input-number-group.ant-input-number-group-compact-addon:not(:first-child):not(:last-child):focus,.ant-input-number-group.ant-input-number-group-compact-wrap:not(:first-child):not(:last-child):focus,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number:not(:first-child):not(:last-child):focus{z-index:1}.ant-input-number-group.ant-input-number-group-compact>*{display:inline-block;float:none;vertical-align:top;border-radius:0}.ant-input-number-group.ant-input-number-group-compact>.ant-input-number-affix-wrapper,.ant-input-number-group.ant-input-number-group-compact>.ant-input-number-number-affix-wrapper,.ant-input-number-group.ant-input-number-group-compact>.ant-picker-range{display:inline-flex}.ant-input-number-group.ant-input-number-group-compact>:not(:last-child){margin-right:-1px;border-right-width:1px}.ant-input-number-group.ant-input-number-group-compact .ant-input-number{float:none}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector{border-right-width:1px;border-radius:0}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input:hover,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector:hover{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-input-group-wrapper .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input:focus,.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-selector:focus{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-select-focused{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-select>.ant-select-arrow{z-index:1}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker:first-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete:first-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select:first-child>.ant-select-selector,.ant-input-number-group.ant-input-number-group-compact>:first-child{border-top-left-radius:3px;border-bottom-left-radius:3px}.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker-focused:last-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-cascader-picker:last-child .ant-input,.ant-input-number-group.ant-input-number-group-compact>.ant-select:last-child>.ant-select-selector,.ant-input-number-group.ant-input-number-group-compact>:last-child{border-right-width:1px;border-top-right-radius:3px;border-bottom-right-radius:3px}.ant-input-number-group.ant-input-number-group-compact>.ant-select-auto-complete .ant-input{vertical-align:top}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper{margin-left:-1px}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper+.ant-input-group-wrapper .ant-input-affix-wrapper{border-radius:0}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input-group-addon>.ant-input-search-button{border-radius:0}.ant-input-number-group.ant-input-number-group-compact .ant-input-group-wrapper:not(:last-child).ant-input-search>.ant-input-group>.ant-input{border-radius:3px 0 0 3px}.ant-input-number-group>.ant-input-number-rtl:first-child{border-radius:0 3px 3px 0}.ant-input-number-group>.ant-input-number-rtl:last-child{border-radius:3px 0 0 3px}.ant-input-number-group-rtl .ant-input-number-group-addon:first-child{border-right:1px solid #dbe0e3;border-left:0;border-radius:0 3px 3px 0}.ant-input-number-group-rtl .ant-input-number-group-addon:last-child{border-right:0;border-left:1px solid #dbe0e3;border-radius:3px 0 0 3px}.ant-input-number-group-wrapper{display:inline-block;text-align:start;vertical-align:top}.ant-input-number-handler{position:relative;display:block;width:100%;height:50%;overflow:hidden;color:#232936;font-weight:700;line-height:0;text-align:center;border-left:1px solid #dbe0e3;transition:all .1s linear}.ant-input-number-handler:active{background:#f4f4f4}.ant-input-number-handler:hover .ant-input-number-handler-down-inner,.ant-input-number-handler:hover .ant-input-number-handler-up-inner{color:#38f}.ant-input-number-handler-down-inner,.ant-input-number-handler-up-inner{display:inline-flex;align-items:center;color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizelegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;position:absolute;right:4px;width:12px;height:12px;color:#232936;line-height:12px;transition:all .1s linear;user-select:none}.ant-input-number-handler-down-inner>*,.ant-input-number-handler-up-inner>*{line-height:1}.ant-input-number-handler-down-inner svg,.ant-input-number-handler-up-inner svg{display:inline-block}.ant-input-number-handler-down-inner::before,.ant-input-number-handler-up-inner::before{display:none}.ant-input-number-handler-down-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-down-inner .ant-input-number-handler-up-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-down-inner-icon,.ant-input-number-handler-up-inner .ant-input-number-handler-up-inner-icon{display:block}.ant-input-number:hover{border-color:#b5bdc3;border-right-width:1px}.ant-input-number:hover+.ant-form-item-children-icon{opacity:0;transition:opacity .24s linear .24s}.ant-input-number-focused{border-color:#38f;box-shadow:0 0 0 0 rgba(11,104,255,.2);border-right-width:1px;outline:0}.ant-input-number-disabled{color:#b5bdc3;background-color:#f9fafb;border-color:#dbe0e3;box-shadow:none;cursor:not-allowed;opacity:1}.ant-input-number-disabled:hover{border-color:#dbe0e3;border-right-width:1px}.ant-input-number-disabled .ant-input-number-input{cursor:not-allowed}.ant-input-number-disabled .ant-input-number-handler-wrap{display:none}.ant-input-number-readonly .ant-input-number-handler-wrap{display:none}.ant-input-number-input{width:100%;height:30px;padding:0 15px;text-align:left;background-color:transparent;border:0;border-radius:3px;outline:0;transition:all .3s linear;appearance:textfield!important}.ant-input-number-input::placeholder{color:#b5bdc3;user-select:none}.ant-input-number-input:placeholder-shown{text-overflow:ellipsis}.ant-input-number-input[type=number]::-webkit-inner-spin-button,.ant-input-number-input[type=number]::-webkit-outer-spin-button{margin:0;-webkit-appearance:none;appearance:none}.ant-input-number-lg{padding:0;font-size:13px}.ant-input-number-lg input{height:46px}.ant-input-number-sm{padding:0}.ant-input-number-sm input{height:22px;padding:0 7px}.ant-input-number-handler-wrap{position:absolute;top:0;right:0;width:22px;height:100%;background:#fff;border-radius:0 3px 3px 0;opacity:0;transition:opacity .24s linear .1s}.ant-input-number-handler-wrap .ant-input-number-handler .ant-input-number-handler-down-inner,.ant-input-number-handler-wrap .ant-input-number-handler .ant-input-number-handler-up-inner{display:flex;align-items:center;justify-content:center;min-width:auto;margin-right:0;font-size:7px}.ant-input-number-borderless .ant-input-number-handler-wrap{border-left-width:0}.ant-input-number-handler-wrap:hover .ant-input-number-handler{height:40%}.ant-input-number-focused .ant-input-number-handler-wrap,.ant-input-number:hover .ant-input-number-handler-wrap{opacity:1}.ant-input-number-handler-up{border-top-right-radius:3px;cursor:pointer}.ant-input-number-handler-up-inner{top:50%;margin-top:-5px;text-align:center}.ant-input-number-handler-up:hover{height:60%!important}.ant-input-number-handler-down{top:0;border-top:1px solid #dbe0e3;border-bottom-right-radius:3px;cursor:pointer}.ant-input-number-handler-down-inner{top:50%;text-align:center;transform:translateY(-50%)}.ant-input-number-handler-down:hover{height:60%!important}.ant-input-number-borderless .ant-input-number-handler-down{border-top-width:0}.ant-input-number-focused:not(.ant-input-number-borderless) .ant-input-number-handler-down,.ant-input-number:hover:not(.ant-input-number-borderless) .ant-input-number-handler-down{border-top:1px solid #dbe0e3}.ant-input-number-handler-down-disabled,.ant-input-number-handler-up-disabled{cursor:not-allowed}.ant-input-number-handler-down-disabled:hover .ant-input-number-handler-down-inner,.ant-input-number-handler-up-disabled:hover .ant-input-number-handler-up-inner{color:#b5bdc3}.ant-input-number-borderless{box-shadow:none}.ant-input-number-out-of-range input{color:#f52922}.ant-input-number-compact-item:not(.ant-input-number-compact-last-item):not(.ant-input-number-compact-item-rtl){margin-right:-1px}.ant-input-number-compact-item:not(.ant-input-number-compact-last-item).ant-input-number-compact-item-rtl{margin-left:-1px}.ant-input-number-compact-item:active,.ant-input-number-compact-item:focus,.ant-input-number-compact-item:hover{z-index:2}.ant-input-number-compact-item.ant-input-number-focused{z-index:2}.ant-input-number-compact-item[disabled]{z-index:0}.ant-input-number-compact-item:not(.ant-input-number-compact-first-item):not(.ant-input-number-compact-last-item).ant-input-number{border-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-first-item:not(.ant-input-number-compact-last-item):not(.ant-input-number-compact-item-rtl){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-last-item:not(.ant-input-number-compact-first-item):not(.ant-input-number-compact-item-rtl){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-item-rtl.ant-input-number-compact-first-item:not(.ant-input-number-compact-last-item){border-top-left-radius:0;border-bottom-left-radius:0}.ant-input-number-compact-item.ant-input-number.ant-input-number-compact-item-rtl.ant-input-number-compact-last-item:not(.ant-input-number-compact-first-item){border-top-right-radius:0;border-bottom-right-radius:0}.ant-input-number-rtl{direction:rtl}.ant-input-number-rtl .ant-input-number-handler{border-right:1px solid #dbe0e3;border-left:0}.ant-input-number-rtl .ant-input-number-handler-wrap{right:auto;left:0}.ant-input-number-rtl.ant-input-number-borderless .ant-input-number-handler-wrap{border-right-width:0}.ant-input-number-rtl .ant-input-number-handler-up{border-top-right-radius:0}.ant-input-number-rtl .ant-input-number-handler-down{border-bottom-right-radius:0}.ant-input-number-rtl .ant-input-number-input{direction:ltr;text-align:right}.ant-input-number-input{height:32px;border:0;outline:0;transition:unset}.ant-input-number-input *{transition:unset}.ant-input-number{width:100%}.ant-input-number-input:focus{box-shadow:unset}.ant-input-number{border:0}.ant-input-number.ant-input-number{line-height:1.38;height:32px;box-shadow:inset 0 0 0 1px #dbe0e3}.ant-input-number.ant-input-number input::placeholder{color:#949ea6}.ant-input-number.ant-input-number.ant-input-number-focused{box-shadow:inset 0 0 0 2px #0b68ff;border:0!important}.ant-input-number.ant-input-number.ant-input-number-lg{height:48px}.ant-input-number.ant-input-number.ant-input-number-lg .ant-input-number-input-wrap{height:44px}.ant-input-number .ant-input-number-handler svg{display:none}.ant-input-number.ant-input-number.ant-input-number-focused .ant-input-number-handler-wrap{width:21px;height:28px;top:2px;right:2px}.ant-input-number.ant-input-number.ant-input-number-lg.ant-input-number-focused .ant-input-number-handler-wrap{height:44px}.ant-input-number.ant-input-number.ant-input-number-lg .ant-input-number-handler-wrap{width:24px;height:44px}.ant-input-number .ant-input-number-handler-wrap{z-index:3;height:30px;top:1px;right:1px}.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-down,.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-up{background-repeat:no-repeat;background-size:cover;background-position:center}.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-down i,.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-up i{display:none}.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-up{background-image:url('data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAxLWFuZ2xlLXVwLXM8L3RpdGxlPjxyZWN0IGlkPSJjYW52YXMiIGNsYXNzPSJjbHMtMSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+PHBhdGggZmlsbD0iIzZhNzU4MCIgZD0iTTE1LjI1LDE0LjM4YS43OS43OSwwLDAsMS0uNTMtLjIyTDEyLDExLjQ0LDkuMjgsMTQuMTZhLjc1Ljc1LDAsMCwxLTEuMDYsMCwuNzcuNzcsMCwwLDEsMC0xLjA3bDMuMjUtMy4yNWEuNzUuNzUsMCwwLDEsMS4wNiwwbDMuMjUsMy4yNWEuNzcuNzcsMCwwLDEsMCwxLjA3QS43OS43OSwwLDAsMSwxNS4yNSwxNC4zOFoiLz48L3N2Zz4=')}.ant-input-number .ant-input-number-handler-wrap .ant-input-number-handler-down{background-image:url('data:image/svg+xml;base64,PHN2ZyBpZD0iaWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPjAxLTAzLWFuZ2xlLWRvd24tczwvdGl0bGU+PHJlY3QgaWQ9ImNhbnZhcyIgY2xhc3M9ImNscy0xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz48cGF0aCBmaWxsPSIjNmE3NTgwIiBkPSJNMTIsMTQuMzhhLjc5Ljc5LDAsMCwxLS41My0uMjJMOC4yMiwxMC45MWEuNzcuNzcsMCwwLDEsMC0xLjA3Ljc1Ljc1LDAsMCwxLDEuMDYsMEwxMiwxMi41NmwyLjcyLTIuNzJhLjc1Ljc1LDAsMCwxLDEuMDYsMCwuNzcuNzcsMCwwLDEsMCwxLjA3bC0zLjI1LDMuMjVBLjc5Ljc5LDAsMCwxLDEyLDE0LjM4WiIvPjwvc3ZnPg==')}.ant-input-number .ant-input-number-input-wrap{height:28px;margin-top:2px;margin:2px}.ant-input-number .ant-input-number-input{position:relative;top:0;height:inherit}.ant-input-number.ant-input-number-focused .ant-input-number-input{top:0;box-shadow:unset}.ant-input-number.error.ant-input-number.error{box-shadow:inset 0 0 0 2px #f52922}.ant-input-number.error .ant-input-number-handler-wrap{z-index:3;width:21px;height:28px;top:2px;right:2px}.ant-input-group.ant-input-group-compact>:not(:first-child).ant-input-number.error{margin-left:-2px}.ant-input-group.ant-input-group-compact>:not(:last-child).ant-input-number.error{margin-right:-2px}
|