@phpsoftbox/react-softbox 1.15.1 → 1.16.1
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/README.md +6 -0
- package/dist/components/Input/FloatLabel/FloatLabel.module.css +16 -5
- package/dist/components/Input/Input.d.ts +12 -2
- package/dist/components/Input/Input.js +4 -1
- package/dist/components/Input/Input.js.map +1 -1
- package/dist/components/Input/InputGroup.d.ts +14 -3
- package/dist/components/Input/InputGroup.js +27 -4
- package/dist/components/Input/InputGroup.js.map +1 -1
- package/dist/components/Input/InputGroup.module.css +79 -3
- package/dist/components/Input/Radio/Radio.js +1 -1
- package/dist/components/Input/Radio/Radio.js.map +1 -1
- package/dist/components/Input/Select/Select.d.ts +2 -1
- package/dist/components/Input/Select/Select.js +59 -45
- package/dist/components/Input/Select/Select.js.map +1 -1
- package/dist/components/Input/Select/Select.module.css +60 -18
- package/dist/components/Input/Textarea/Textarea.module.css +1 -1
- package/dist/components/MarkdownEditor/MarkdownEditor.js +58 -4
- package/dist/components/MarkdownEditor/MarkdownEditor.js.map +1 -1
- package/dist/foundations/tokens.css +2 -0
- package/dist/hooks/useDropdownPosition.js +33 -2
- package/dist/hooks/useDropdownPosition.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +2 -0
- package/dist/markdown.js +2 -0
- package/dist/markdown.js.map +1 -0
- package/docs/README.md +6 -0
- package/docs/forms.md +28 -2
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -46,6 +46,12 @@ import {
|
|
|
46
46
|
} from '@phpsoftbox/react-softbox';
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
```ts
|
|
50
|
+
import { MarkdownEditor } from '@phpsoftbox/react-softbox/markdown';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`MarkdownEditor` вынесен в отдельный entrypoint, чтобы основной пакет не подтягивал `shiki`.
|
|
54
|
+
|
|
49
55
|
## Тема
|
|
50
56
|
|
|
51
57
|
```ts
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
.wrapper {
|
|
2
|
+
--ui-float-label-background: var(--surface-input);
|
|
2
3
|
position: relative;
|
|
3
4
|
display: block;
|
|
4
5
|
}
|
|
@@ -10,9 +11,10 @@
|
|
|
10
11
|
|
|
11
12
|
.label {
|
|
12
13
|
position: absolute;
|
|
13
|
-
left:
|
|
14
|
-
|
|
14
|
+
left: 12px;
|
|
15
|
+
max-width: calc(100% - 24px);
|
|
15
16
|
top: 16px;
|
|
17
|
+
box-sizing: border-box;
|
|
16
18
|
color: var(--color-muted-2);
|
|
17
19
|
font-size: var(--ui-control-font-size, var(--font-size-3));
|
|
18
20
|
line-height: 1.2;
|
|
@@ -20,8 +22,8 @@
|
|
|
20
22
|
transition: transform 0.2s ease, color 0.2s ease, opacity 0.2s ease;
|
|
21
23
|
pointer-events: none;
|
|
22
24
|
z-index: 1;
|
|
23
|
-
background: var(--
|
|
24
|
-
padding: 0;
|
|
25
|
+
background: var(--ui-float-label-background);
|
|
26
|
+
padding: 0 4px;
|
|
25
27
|
border-radius: 4px;
|
|
26
28
|
white-space: nowrap;
|
|
27
29
|
overflow: hidden;
|
|
@@ -29,7 +31,16 @@
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
.wrapperWithHint .label {
|
|
32
|
-
|
|
34
|
+
max-width: calc(100% - 64px);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.wrapper > textarea + .label {
|
|
38
|
+
background: var(--surface-input-solid);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.wrapper > input:disabled + .label,
|
|
42
|
+
.wrapper > textarea:disabled + .label {
|
|
43
|
+
background: var(--surface-input-disabled);
|
|
33
44
|
}
|
|
34
45
|
|
|
35
46
|
.requiredMark {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Select from './Select/Select';
|
|
2
2
|
import FloatLabel from './FloatLabel/FloatLabel';
|
|
3
|
-
import {
|
|
3
|
+
import { InputAddon, InputGroupChoice, InputGroupLabel, InputGroupText } from './InputGroup';
|
|
4
4
|
import MaskedInput from './MaskedInput';
|
|
5
5
|
import NumberInput from './NumberInput';
|
|
6
6
|
import DatePicker from './DatePicker';
|
|
@@ -46,8 +46,18 @@ declare const Input: import("react").FC<import("react").HTMLAttributes<HTMLDivEl
|
|
|
46
46
|
} & import("react").RefAttributes<HTMLTextAreaElement>>;
|
|
47
47
|
Select: typeof Select;
|
|
48
48
|
FloatLabel: typeof FloatLabel;
|
|
49
|
-
Group:
|
|
49
|
+
Group: (({ stretch, className, children, ...props }: import("react").HTMLAttributes<HTMLDivElement> & {
|
|
50
|
+
stretch?: boolean;
|
|
51
|
+
}) => import("react/jsx-runtime").JSX.Element) & {
|
|
52
|
+
Addon: typeof InputAddon;
|
|
53
|
+
Label: typeof InputGroupLabel;
|
|
54
|
+
Text: typeof InputGroupText;
|
|
55
|
+
Choice: typeof InputGroupChoice;
|
|
56
|
+
};
|
|
50
57
|
Addon: typeof InputAddon;
|
|
58
|
+
GroupLabel: typeof InputGroupLabel;
|
|
59
|
+
GroupText: typeof InputGroupText;
|
|
60
|
+
GroupChoice: typeof InputGroupChoice;
|
|
51
61
|
MaskedInput: typeof MaskedInput;
|
|
52
62
|
Number: typeof NumberInput;
|
|
53
63
|
DatePicker: typeof DatePicker;
|
|
@@ -3,7 +3,7 @@ import InputField from './Field';
|
|
|
3
3
|
import Textarea from './Textarea/Textarea';
|
|
4
4
|
import Select from './Select/Select';
|
|
5
5
|
import FloatLabel from './FloatLabel/FloatLabel';
|
|
6
|
-
import { InputGroup, InputAddon } from './InputGroup';
|
|
6
|
+
import { InputGroup, InputAddon, InputGroupChoice, InputGroupLabel, InputGroupText } from './InputGroup';
|
|
7
7
|
import MaskedInput from './MaskedInput';
|
|
8
8
|
import NumberInput from './NumberInput';
|
|
9
9
|
import DatePicker from './DatePicker';
|
|
@@ -24,6 +24,9 @@ const Input = Object.assign(FormField, {
|
|
|
24
24
|
FloatLabel,
|
|
25
25
|
Group: InputGroup,
|
|
26
26
|
Addon: InputAddon,
|
|
27
|
+
GroupLabel: InputGroupLabel,
|
|
28
|
+
GroupText: InputGroupText,
|
|
29
|
+
GroupChoice: InputGroupChoice,
|
|
27
30
|
MaskedInput,
|
|
28
31
|
Number: NumberInput,
|
|
29
32
|
DatePicker,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../../src/components/Input/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAC9C,OAAO,UAAU,MAAM,SAAS,CAAC;AACjC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../../src/components/Input/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,uBAAuB,CAAC;AAC9C,OAAO,UAAU,MAAM,SAAS,CAAC;AACjC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,UAAU,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,eAAe,CAAC;AAClC,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,YAAY,MAAM,6BAA6B,CAAC;AACvD,OAAO,IAAI,MAAM,aAAa,CAAC;AAE/B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE;IACrC,KAAK,EAAE,SAAS,CAAC,KAAK;IACtB,OAAO,EAAE,SAAS,CAAC,OAAO;IAC1B,QAAQ,EAAE,SAAS,CAAC,QAAQ;IAC5B,KAAK,EAAE,UAAU;IACjB,QAAQ,EAAE,QAAQ;IAClB,MAAM;IACN,UAAU;IACV,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,eAAe;IAC3B,SAAS,EAAE,cAAc;IACzB,WAAW,EAAE,gBAAgB;IAC7B,WAAW;IACX,MAAM,EAAE,WAAW;IACnB,UAAU;IACV,UAAU;IACV,SAAS,EAAE,eAAe;IAC1B,KAAK;IACL,MAAM;IACN,QAAQ;IACR,YAAY;IACZ,IAAI;IACJ,SAAS;CACV,CAAC,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
|
@@ -3,9 +3,20 @@ import './InputGroup.module.css';
|
|
|
3
3
|
type GroupProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
4
4
|
stretch?: boolean;
|
|
5
5
|
};
|
|
6
|
-
type
|
|
6
|
+
type AddonVariant = 'default' | 'label' | 'muted' | 'choice';
|
|
7
|
+
type AddonProps = React.HTMLAttributes<HTMLElement> & {
|
|
7
8
|
as?: React.ElementType;
|
|
9
|
+
variant?: AddonVariant;
|
|
10
|
+
};
|
|
11
|
+
declare function InputGroupRoot({ stretch, className, children, ...props }: GroupProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function InputAddon({ as, variant, className, ...props }: AddonProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function InputGroupLabel(props: Omit<AddonProps, 'variant'>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function InputGroupText(props: Omit<AddonProps, 'variant'>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function InputGroupChoice(props: Omit<AddonProps, 'variant'>): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare const InputGroup: typeof InputGroupRoot & {
|
|
17
|
+
Addon: typeof InputAddon;
|
|
18
|
+
Label: typeof InputGroupLabel;
|
|
19
|
+
Text: typeof InputGroupText;
|
|
20
|
+
Choice: typeof InputGroupChoice;
|
|
8
21
|
};
|
|
9
|
-
export declare function InputGroup({ stretch, className, children, ...props }: GroupProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
-
export declare function InputAddon({ as, className, ...props }: AddonProps): import("react/jsx-runtime").JSX.Element;
|
|
11
22
|
export {};
|
|
@@ -5,21 +5,44 @@ const GROUP_CLASS = 'rsb-input-group';
|
|
|
5
5
|
const GROUP_STRETCH_CLASS = 'rsb-input-group--stretch';
|
|
6
6
|
const ITEM_CLASS = 'rsb-group-item';
|
|
7
7
|
const ADDON_CLASS = 'rsb-input-addon';
|
|
8
|
-
|
|
8
|
+
const mergeClassNames = (...classes) => classes.filter(Boolean).join(' ');
|
|
9
|
+
function InputGroupRoot({ stretch = false, className, children, ...props }) {
|
|
9
10
|
const classes = [GROUP_CLASS, stretch ? GROUP_STRETCH_CLASS : null, className].filter(Boolean).join(' ');
|
|
10
11
|
const items = React.Children.map(children, (child) => {
|
|
11
12
|
if (!React.isValidElement(child)) {
|
|
12
13
|
return child;
|
|
13
14
|
}
|
|
14
15
|
const element = child;
|
|
15
|
-
const childClassName =
|
|
16
|
+
const childClassName = mergeClassNames(element.props.className, ITEM_CLASS);
|
|
16
17
|
return React.cloneElement(element, { className: childClassName });
|
|
17
18
|
});
|
|
18
19
|
return (_jsx("div", { className: classes, ...props, children: items }));
|
|
19
20
|
}
|
|
20
|
-
export function InputAddon({ as = 'div', className, ...props }) {
|
|
21
|
+
export function InputAddon({ as = 'div', variant = 'default', className, ...props }) {
|
|
21
22
|
const Component = as;
|
|
22
|
-
const classes = [
|
|
23
|
+
const classes = [
|
|
24
|
+
ADDON_CLASS,
|
|
25
|
+
`${ADDON_CLASS}--${variant}`,
|
|
26
|
+
ITEM_CLASS,
|
|
27
|
+
className,
|
|
28
|
+
]
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(' ');
|
|
23
31
|
return _jsx(Component, { className: classes, ...props });
|
|
24
32
|
}
|
|
33
|
+
export function InputGroupLabel(props) {
|
|
34
|
+
return _jsx(InputAddon, { as: "span", ...props, variant: "label" });
|
|
35
|
+
}
|
|
36
|
+
export function InputGroupText(props) {
|
|
37
|
+
return _jsx(InputAddon, { as: "span", ...props, variant: "muted" });
|
|
38
|
+
}
|
|
39
|
+
export function InputGroupChoice(props) {
|
|
40
|
+
return _jsx(InputAddon, { as: "span", ...props, variant: "choice" });
|
|
41
|
+
}
|
|
42
|
+
export const InputGroup = Object.assign(InputGroupRoot, {
|
|
43
|
+
Addon: InputAddon,
|
|
44
|
+
Label: InputGroupLabel,
|
|
45
|
+
Text: InputGroupText,
|
|
46
|
+
Choice: InputGroupChoice,
|
|
47
|
+
});
|
|
25
48
|
//# sourceMappingURL=InputGroup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputGroup.js","sourceRoot":"","sources":["../../../src/components/Input/InputGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AAEjC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AACvD,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,WAAW,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"InputGroup.js","sourceRoot":"","sources":["../../../src/components/Input/InputGroup.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,yBAAyB,CAAC;AAEjC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AACvD,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAatC,MAAM,eAAe,GAAG,CAAC,GAAG,OAAiD,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEpH,SAAS,cAAc,CAAC,EAAE,OAAO,GAAG,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAc;IACpF,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzG,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAG,KAAmD,CAAC;QACpE,MAAM,cAAc,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC5E,OAAO,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,cAAK,SAAS,EAAE,OAAO,KAAM,KAAK,YAC/B,KAAK,GACF,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,GAAG,SAAS,EAAE,SAAS,EAAE,GAAG,KAAK,EAAc;IAC7F,MAAM,SAAS,GAAG,EAAuB,CAAC;IAC1C,MAAM,OAAO,GAAG;QACd,WAAW;QACX,GAAG,WAAW,KAAK,OAAO,EAAE;QAC5B,UAAU;QACV,SAAS;KACV;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,OAAO,KAAC,SAAS,IAAC,SAAS,EAAE,OAAO,KAAM,KAAK,GAAI,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkC;IAChE,OAAO,KAAC,UAAU,IAAC,EAAE,EAAC,MAAM,KAAK,KAAK,EAAE,OAAO,EAAC,OAAO,GAAG,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAkC;IAC/D,OAAO,KAAC,UAAU,IAAC,EAAE,EAAC,MAAM,KAAK,KAAK,EAAE,OAAO,EAAC,OAAO,GAAG,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAkC;IACjE,OAAO,KAAC,UAAU,IAAC,EAAE,EAAC,MAAM,KAAK,KAAK,EAAE,OAAO,EAAC,QAAQ,GAAG,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE;IACtD,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,eAAe;IACtB,IAAI,EAAE,cAAc;IACpB,MAAM,EAAE,gBAAgB;CACzB,CAAC,CAAC"}
|
|
@@ -2,14 +2,37 @@
|
|
|
2
2
|
display: flex;
|
|
3
3
|
align-items: stretch;
|
|
4
4
|
gap: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
min-width: 0;
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
:global(.rsb-input-group--stretch) > :global(.rsb-group-item) {
|
|
8
|
-
flex:
|
|
10
|
+
flex: 0 0 auto;
|
|
9
11
|
min-width: 0;
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
:global(.rsb-input-group--stretch > .rsb-group-item:not(.rsb-input-addon):not(.btn):not(.rsb-radio)) {
|
|
15
|
+
flex: 1 1 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
:global(.rsb-input-group) > :global(.rsb-group-item) {
|
|
19
|
+
position: relative;
|
|
20
|
+
border-radius: 0 !important;
|
|
21
|
+
min-height: var(--ui-control-height, 48px);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:global(.rsb-input-group) > :global(.rsb-group-item):focus,
|
|
25
|
+
:global(.rsb-input-group) > :global(.rsb-group-item):focus-within {
|
|
26
|
+
z-index: 2;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:global(.rsb-input-group) > :global(.rsb-group-item.btn) {
|
|
30
|
+
min-height: var(--ui-control-height, 48px);
|
|
31
|
+
box-shadow: none;
|
|
32
|
+
flex: 0 0 auto;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
:global(.rsb-input-group) > :global(.rsb-group-item) > :where(input, button, textarea) {
|
|
13
36
|
border-radius: 0 !important;
|
|
14
37
|
}
|
|
15
38
|
|
|
@@ -18,11 +41,21 @@
|
|
|
18
41
|
border-bottom-left-radius: var(--radius-sm) !important;
|
|
19
42
|
}
|
|
20
43
|
|
|
44
|
+
:global(.rsb-input-group) > :global(.rsb-group-item):first-child > :where(input, button, textarea) {
|
|
45
|
+
border-top-left-radius: var(--radius-sm) !important;
|
|
46
|
+
border-bottom-left-radius: var(--radius-sm) !important;
|
|
47
|
+
}
|
|
48
|
+
|
|
21
49
|
:global(.rsb-input-group) > :global(.rsb-group-item):last-child {
|
|
22
50
|
border-top-right-radius: var(--radius-sm) !important;
|
|
23
51
|
border-bottom-right-radius: var(--radius-sm) !important;
|
|
24
52
|
}
|
|
25
53
|
|
|
54
|
+
:global(.rsb-input-group) > :global(.rsb-group-item):last-child > :where(input, button, textarea) {
|
|
55
|
+
border-top-right-radius: var(--radius-sm) !important;
|
|
56
|
+
border-bottom-right-radius: var(--radius-sm) !important;
|
|
57
|
+
}
|
|
58
|
+
|
|
26
59
|
:global(.rsb-input-group) > :global(.rsb-group-item) + :global(.rsb-group-item) {
|
|
27
60
|
margin-left: -1px;
|
|
28
61
|
}
|
|
@@ -30,9 +63,52 @@
|
|
|
30
63
|
:global(.rsb-input-addon) {
|
|
31
64
|
display: inline-flex;
|
|
32
65
|
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
min-height: var(--ui-control-height, 48px);
|
|
33
68
|
padding: 0 12px;
|
|
34
|
-
border: 1px solid
|
|
35
|
-
background: var(--surface-input);
|
|
69
|
+
border: 1px solid var(--color-line);
|
|
70
|
+
background: var(--surface-input-muted);
|
|
71
|
+
color: var(--color-muted);
|
|
72
|
+
font-size: var(--ui-control-font-size, var(--font-size-3));
|
|
73
|
+
font-weight: 600;
|
|
74
|
+
line-height: var(--ui-control-line-height, 1.2);
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:global(.rsb-input-addon--label),
|
|
79
|
+
:global(.rsb-input-addon--muted) {
|
|
80
|
+
background: var(--surface-input-muted);
|
|
36
81
|
color: var(--color-muted);
|
|
82
|
+
border-color: var(--color-line);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
:global(.rsb-input-addon--label) {
|
|
86
|
+
color: var(--color-muted-2);
|
|
87
|
+
font-size: var(--font-size-2);
|
|
88
|
+
text-transform: none;
|
|
89
|
+
letter-spacing: 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
:global(.rsb-input-addon--muted) {
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:global(.rsb-input-addon--choice) {
|
|
97
|
+
gap: 10px;
|
|
98
|
+
padding: 0 14px;
|
|
99
|
+
background: var(--surface-input-muted);
|
|
100
|
+
border-color: var(--color-line);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
:global(.rsb-input-addon--choice) > :global(.rsb-radio) {
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
:global(.rsb-input-group) > :global(.rsb-radio.rsb-group-item) {
|
|
108
|
+
align-items: center;
|
|
109
|
+
min-height: var(--ui-control-height, 48px);
|
|
110
|
+
padding: 0 14px;
|
|
111
|
+
border: 1px solid var(--color-line);
|
|
112
|
+
background: var(--surface-input-muted);
|
|
37
113
|
white-space: nowrap;
|
|
38
114
|
}
|
|
@@ -4,7 +4,7 @@ import styles from './Radio.module.css';
|
|
|
4
4
|
import Hint from '../Hint/Hint';
|
|
5
5
|
export default function Radio({ id, label, description, hint, hintPlacement = 'auto', className, ...props }) {
|
|
6
6
|
const inputId = id ?? React.useId();
|
|
7
|
-
const classes = [styles.radio, className].filter(Boolean).join(' ');
|
|
7
|
+
const classes = [styles.radio, 'rsb-radio', className].filter(Boolean).join(' ');
|
|
8
8
|
return (_jsxs("label", { className: classes, htmlFor: inputId, children: [_jsx("input", { id: inputId, type: "radio", className: styles.input, ...props }), _jsx("span", { className: styles.control, "aria-hidden": "true" }), _jsxs("span", { className: styles.texts, children: [label ? (_jsxs("span", { className: styles.labelWrap, children: [_jsx("span", { className: styles.label, children: label }), _jsx(Hint, { content: hint, placement: hintPlacement, ariaLabel: "\u041F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430 \u043A radio-\u043F\u043E\u043B\u044E" })] })) : null, description ? _jsx("span", { className: styles.description, children: description }) : null] })] }));
|
|
9
9
|
}
|
|
10
10
|
//# sourceMappingURL=Radio.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../../src/components/Input/Radio/Radio.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,cAAc,CAAC;AAUhC,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAS;IAChH,MAAM,OAAO,GAAG,EAAE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../../src/components/Input/Radio/Radio.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,cAAc,CAAC;AAUhC,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAS;IAChH,MAAM,OAAO,GAAG,EAAE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEjF,OAAO,CACL,iBAAO,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,aACzC,gBAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAC,OAAO,EAAC,SAAS,EAAE,MAAM,CAAC,KAAK,KAAM,KAAK,GAAI,EACvE,eAAM,SAAS,EAAE,MAAM,CAAC,OAAO,iBAAc,MAAM,GAAG,EACtD,gBAAM,SAAS,EAAE,MAAM,CAAC,KAAK,aAC1B,KAAK,CAAC,CAAC,CAAC,CACP,gBAAM,SAAS,EAAE,MAAM,CAAC,SAAS,aAC/B,eAAM,SAAS,EAAE,MAAM,CAAC,KAAK,YAAG,KAAK,GAAQ,EAC7C,KAAC,IAAI,IAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAC,8FAAwB,GAAG,IAC/E,CACR,CAAC,CAAC,CAAC,IAAI,EACP,WAAW,CAAC,CAAC,CAAC,eAAM,SAAS,EAAE,MAAM,CAAC,WAAW,YAAG,WAAW,GAAQ,CAAC,CAAC,CAAC,IAAI,IAC1E,IACD,CACT,CAAC;AACJ,CAAC"}
|
|
@@ -55,6 +55,7 @@ type SharedProps<T extends string | number, M = unknown> = {
|
|
|
55
55
|
floatLabel?: boolean;
|
|
56
56
|
endActions?: React.ReactNode;
|
|
57
57
|
className?: string;
|
|
58
|
+
style?: React.CSSProperties;
|
|
58
59
|
};
|
|
59
60
|
type SingleProps<T extends string | number, M = unknown> = SharedProps<T, M> & {
|
|
60
61
|
multiple?: false;
|
|
@@ -88,7 +89,7 @@ type MultiProps<T extends string | number, M = unknown> = SharedProps<T, M> & {
|
|
|
88
89
|
onChange?: (value: T[], options: SelectOption<T, M>[]) => void;
|
|
89
90
|
};
|
|
90
91
|
type Props<T extends string | number, M = unknown> = SingleProps<T, M> | SingleClearableProps<T, M> | SingleAllowEmptyProps<T, M> | MultiProps<T, M>;
|
|
91
|
-
declare function Select<T extends string | number = string | number, M = unknown>({ label, id, name, required, options, value, defaultValue, placeholder, multiple, searchable, clearable, clearLabel, allowEmptyValue, emptyOptionLabel, emptyOptionValue, loadingText, emptyText, creatable, createLabel, creatingText, onCreateOption, loadOptions, request, onAfterRequest, renderOption, renderValue, placement, portal, disabled, floatLabel, endActions, className, onChange, }: Props<T, M>): import("react/jsx-runtime").JSX.Element;
|
|
92
|
+
declare function Select<T extends string | number = string | number, M = unknown>({ label, id, name, required, options, value, defaultValue, placeholder, multiple, searchable, clearable, clearLabel, allowEmptyValue, emptyOptionLabel, emptyOptionValue, loadingText, emptyText, creatable, createLabel, creatingText, onCreateOption, loadOptions, request, onAfterRequest, renderOption, renderValue, placement, portal, disabled, floatLabel, endActions, className, style, onChange, }: Props<T, M>): import("react/jsx-runtime").JSX.Element;
|
|
92
93
|
declare namespace Select {
|
|
93
94
|
var supportsFloatLabel: boolean;
|
|
94
95
|
var floatLabelKind: string;
|
|
@@ -12,7 +12,7 @@ const defaultMapOptions = (data) => {
|
|
|
12
12
|
}
|
|
13
13
|
return [];
|
|
14
14
|
};
|
|
15
|
-
export default function Select({ label, id, name, required = false, options = [], value, defaultValue, placeholder = 'Выберите...', multiple = false, searchable = false, clearable = false, clearLabel = 'Очистить', allowEmptyValue = false, emptyOptionLabel = 'Не выбрано', emptyOptionValue, loadingText = 'Загрузка...', emptyText = 'Нет данных', creatable = false, createLabel = (nextQuery) => `Добавить "${nextQuery}"`, creatingText = 'Добавление...', onCreateOption, loadOptions, request, onAfterRequest, renderOption, renderValue, placement = 'auto', portal = true, disabled = false, floatLabel = false, endActions, className, onChange, }) {
|
|
15
|
+
export default function Select({ label, id, name, required = false, options = [], value, defaultValue, placeholder = 'Выберите...', multiple = false, searchable = false, clearable = false, clearLabel = 'Очистить', allowEmptyValue = false, emptyOptionLabel = 'Не выбрано', emptyOptionValue, loadingText = 'Загрузка...', emptyText = 'Нет данных', creatable = false, createLabel = (nextQuery) => `Добавить "${nextQuery}"`, creatingText = 'Добавление...', onCreateOption, loadOptions, request, onAfterRequest, renderOption, renderValue, placement = 'auto', portal = true, disabled = false, floatLabel = false, endActions, className, style, onChange, }) {
|
|
16
16
|
const resolvedOptions = options;
|
|
17
17
|
const resolvedLoadOptions = loadOptions;
|
|
18
18
|
const resolvedRequest = request;
|
|
@@ -28,6 +28,7 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
28
28
|
const shouldPortal = portal && canPortal;
|
|
29
29
|
const [items, setItems] = React.useState(resolvedOptions);
|
|
30
30
|
const [createdItems, setCreatedItems] = React.useState([]);
|
|
31
|
+
const containerRef = React.useRef(null);
|
|
31
32
|
const controlRef = React.useRef(null);
|
|
32
33
|
const optionRefs = React.useRef([]);
|
|
33
34
|
const activeOptionSourceRef = React.useRef('sync');
|
|
@@ -35,10 +36,9 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
35
36
|
gap: 6,
|
|
36
37
|
align: 'left',
|
|
37
38
|
placement,
|
|
38
|
-
anchorRef:
|
|
39
|
+
anchorRef: containerRef,
|
|
39
40
|
strategy: shouldPortal ? 'fixed' : 'absolute',
|
|
40
41
|
});
|
|
41
|
-
const containerRef = React.useRef(null);
|
|
42
42
|
const inputRef = React.useRef(null);
|
|
43
43
|
const listRef = React.useRef(null);
|
|
44
44
|
const generatedId = React.useId();
|
|
@@ -116,7 +116,8 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
const target = event.target;
|
|
119
|
-
const
|
|
119
|
+
const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
120
|
+
const insideControl = containerRef.current.contains(target) || eventPath.includes(containerRef.current);
|
|
120
121
|
const insideDropdown = dropdownRef.current ? dropdownRef.current.contains(target) : false;
|
|
121
122
|
if (!insideControl && !insideDropdown) {
|
|
122
123
|
setOpen(false);
|
|
@@ -153,6 +154,11 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}, [open, searchable]);
|
|
157
|
+
React.useEffect(() => {
|
|
158
|
+
if (!open && query !== '') {
|
|
159
|
+
setQuery('');
|
|
160
|
+
}
|
|
161
|
+
}, [open, query]);
|
|
156
162
|
const allOptions = React.useMemo(() => (emptyOption ? [emptyOption, ...mergedItems] : mergedItems), [emptyOption, mergedItems]);
|
|
157
163
|
const optionMap = React.useMemo(() => {
|
|
158
164
|
return new Map(allOptions.map((item) => [item.value, item]));
|
|
@@ -201,6 +207,14 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
201
207
|
const hasValue = multiple ? selectedValues.length > 0 : selectedValues !== undefined;
|
|
202
208
|
const isEmptySelection = !multiple && allowEmpty && selectedValues === resolvedEmptyValue;
|
|
203
209
|
const floatActive = floatLabel && (open || hasValue);
|
|
210
|
+
const showInlineSearch = searchable && open;
|
|
211
|
+
const searchPlaceholder = React.useMemo(() => {
|
|
212
|
+
if (!hasValue) {
|
|
213
|
+
return placeholder;
|
|
214
|
+
}
|
|
215
|
+
const selectedLabel = selectedList.map((item) => item.label).filter(Boolean).join(', ');
|
|
216
|
+
return selectedLabel || placeholder;
|
|
217
|
+
}, [hasValue, selectedList, placeholder]);
|
|
204
218
|
const displayedOptions = React.useMemo(() => {
|
|
205
219
|
if (isRemote) {
|
|
206
220
|
const filtered = mergedItems;
|
|
@@ -443,7 +457,7 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
443
457
|
setCreating(false);
|
|
444
458
|
}
|
|
445
459
|
};
|
|
446
|
-
const controlWidth =
|
|
460
|
+
const controlWidth = containerRef.current?.getBoundingClientRect().width;
|
|
447
461
|
const resolvedDropdownStyle = shouldPortal
|
|
448
462
|
? {
|
|
449
463
|
...dropdownStyle,
|
|
@@ -451,49 +465,49 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
451
465
|
minWidth: controlWidth ? `${controlWidth}px` : undefined,
|
|
452
466
|
}
|
|
453
467
|
: dropdownStyle;
|
|
454
|
-
const dropdown = open ? (
|
|
455
|
-
if (event.key === 'Enter' && canCreate) {
|
|
468
|
+
const dropdown = open ? (_jsx("div", { className: [styles.dropdown, shouldPortal ? styles.dropdownPortal : null].filter(Boolean).join(' '), ref: dropdownRef, style: resolvedDropdownStyle, children: _jsxs("div", { className: styles.list, role: "listbox", id: listId, ref: listRef, children: [loading ? _jsx("div", { className: styles.status, children: loadingText }) : null, !loading && !canCreate && (allowEmpty ? displayedOptions.length <= 1 : displayedOptions.length === 0) ? (_jsx("div", { className: styles.status, children: emptyText })) : null, !loading && canCreate ? (_jsxs("button", { type: "button", className: [styles.option, styles.optionCreate].filter(Boolean).join(' '), onMouseDown: (event) => {
|
|
456
469
|
event.preventDefault();
|
|
457
470
|
void handleCreateOption();
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
event.preventDefault();
|
|
471
|
+
}, onClick: (event) => {
|
|
472
|
+
if (event.detail === 0) {
|
|
461
473
|
void handleCreateOption();
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
]
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
474
|
+
}
|
|
475
|
+
}, disabled: creating, children: [_jsx("span", { children: creating ? creatingText : createLabel(trimmedQuery) }), _jsx("span", { className: styles.createMark, children: "+" })] })) : null, !loading
|
|
476
|
+
? displayedOptions.map((option, index) => {
|
|
477
|
+
const selected = multiple
|
|
478
|
+
? option.value !== null && selectedValues.includes(option.value)
|
|
479
|
+
: selectedValues === option.value;
|
|
480
|
+
const active = index === activeOptionIndex;
|
|
481
|
+
return (_jsxs("button", { type: "button", className: [
|
|
482
|
+
styles.option,
|
|
483
|
+
selected ? styles.optionSelected : null,
|
|
484
|
+
active ? styles.optionActive : null,
|
|
485
|
+
option.disabled ? styles.optionDisabled : null,
|
|
486
|
+
]
|
|
487
|
+
.filter(Boolean)
|
|
488
|
+
.join(' '), ref: (node) => {
|
|
489
|
+
optionRefs.current[index] = node;
|
|
490
|
+
}, role: "option", "aria-selected": selected, "aria-label": option.label, onMouseEnter: () => {
|
|
491
|
+
activeOptionSourceRef.current = 'mouse';
|
|
492
|
+
setActiveOptionIndex(index);
|
|
493
|
+
}, onMouseDown: (event) => {
|
|
494
|
+
event.preventDefault();
|
|
495
|
+
handleSelect(option);
|
|
496
|
+
}, onClick: (event) => {
|
|
497
|
+
if (event.detail === 0) {
|
|
486
498
|
handleSelect(option);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
499
|
+
}
|
|
500
|
+
}, disabled: option.disabled, children: [renderOption
|
|
501
|
+
? renderOption(option, { selected, active, multiple })
|
|
502
|
+
: _jsx("span", { className: styles.optionLabel, children: option.label }), selected ? _jsx("span", { className: styles.check, children: "\u2713" }) : null] }, option.value ?? '__empty'));
|
|
503
|
+
})
|
|
504
|
+
: null] }) })) : null;
|
|
505
|
+
return (_jsxs("div", { className: [styles.wrapper, className].filter(Boolean).join(' '), "data-open": open, "data-has-value": hasValue, "data-multiple": multiple ? 'true' : 'false', "data-has-query": query.length > 0, "data-has-label": hasLabel, "data-float-label": floatLabel ? 'true' : undefined, "data-float-active": floatActive ? 'true' : undefined, "data-has-clear": showClear ? 'true' : undefined, ref: containerRef, style: { ...style, ...controlStyle }, onKeyDown: handleKeyDown, children: [label ? (_jsx("span", { id: labelId, className: styles.label, children: label })) : null, showInlineSearch ? (_jsx("input", { ref: inputRef, id: controlId, className: styles.controlSearch, style: controlStyle, value: query, placeholder: searchPlaceholder, autoComplete: "off", spellCheck: false, role: "combobox", "aria-autocomplete": "list", "aria-expanded": open, "aria-controls": listId, "aria-labelledby": label ? labelId : undefined, disabled: disabled, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
|
|
506
|
+
if (event.key === 'Enter' && canCreate) {
|
|
507
|
+
event.preventDefault();
|
|
508
|
+
void handleCreateOption();
|
|
509
|
+
}
|
|
510
|
+
} })) : (_jsx("button", { type: "button", className: styles.control, style: controlStyle, "aria-haspopup": "listbox", "aria-expanded": open, "aria-controls": listId, "aria-labelledby": label ? labelId : undefined, id: controlId, onClick: () => !disabled && setOpen((prev) => !prev), disabled: disabled, ref: controlRef, children: _jsx("div", { className: styles.value, children: hasValue ? (multiple ? (selectedList.map((item) => (_jsxs("div", { className: styles.tag, children: [renderValue ? renderValue(item) : item.label, _jsx("span", { role: "button", tabIndex: 0, className: styles.remove, onClick: (event) => {
|
|
497
511
|
event.stopPropagation();
|
|
498
512
|
handleRemove(item.value);
|
|
499
513
|
}, onKeyDown: (event) => {
|
|
@@ -502,7 +516,7 @@ export default function Select({ label, id, name, required = false, options = []
|
|
|
502
516
|
event.stopPropagation();
|
|
503
517
|
handleRemove(item.value);
|
|
504
518
|
}
|
|
505
|
-
}, "aria-label": `Удалить ${item.label}`, children: "\u00D7" })] }, String(item.value))))) : (_jsx("span", { className: styles.singleValue, children: selectedList[0] ? (renderValue ? renderValue(selectedList[0]) : selectedList[0].label) : null }))) : (_jsx("span", { className: [styles.placeholder, styles.singleValue].join(' '), children: placeholder })) }) }), _jsxs(ActionStack, { className: styles.controls, children: [endActions, showClear ? (_jsx("span", { role: "button", tabIndex: 0, className: styles.clearButton, "aria-label": clearLabel, onMouseDown: (event) => event.preventDefault(), onClick: handleClear, onKeyDown: (event) => {
|
|
519
|
+
}, "aria-label": `Удалить ${item.label}`, children: "\u00D7" })] }, String(item.value))))) : (_jsx("span", { className: styles.singleValue, children: selectedList[0] ? (renderValue ? renderValue(selectedList[0]) : selectedList[0].label) : null }))) : (_jsx("span", { className: [styles.placeholder, styles.singleValue].join(' '), children: placeholder })) }) })), _jsxs(ActionStack, { className: styles.controls, children: [endActions, showClear ? (_jsx("span", { role: "button", tabIndex: 0, className: styles.clearButton, "aria-label": clearLabel, onMouseDown: (event) => event.preventDefault(), onClick: handleClear, onKeyDown: (event) => {
|
|
506
520
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
507
521
|
event.preventDefault();
|
|
508
522
|
handleClear(event);
|