@koobiq/react-components 0.24.0 → 0.25.0
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/dist/components/ContenPanel/ContentPanel.d.ts +3 -2
- package/dist/components/ContenPanel/ContentPanel.js +9 -9
- package/dist/components/Divider/Divider.d.ts +14 -4
- package/dist/components/Divider/Divider.js +23 -8
- package/dist/components/Divider/types.d.ts +4 -3
- package/dist/components/Navbar/components/NavbarItem.d.ts +4 -0
- package/dist/components/Navbar/components/NavbarItem.js +11 -1
- package/dist/components/SearchInput/SearchInput.d.ts +1 -1
- package/dist/components/Select/Select.d.ts +4 -0
- package/dist/components/SelectNext/Select.d.ts +13 -0
- package/dist/components/SelectNext/Select.js +258 -0
- package/dist/components/SelectNext/Select.module.css.js +23 -0
- package/dist/components/SelectNext/SelectContext.d.ts +2 -0
- package/dist/components/SelectNext/SelectContext.js +5 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.d.ts +37 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.js +131 -0
- package/dist/components/SelectNext/components/SelectList/SelectList.module.css.js +11 -0
- package/dist/components/SelectNext/components/SelectList/index.d.ts +1 -0
- package/dist/components/SelectNext/components/SelectOption/SelectOption.d.ts +37 -0
- package/dist/components/SelectNext/components/SelectOption/SelectOption.js +48 -0
- package/dist/components/SelectNext/components/SelectOption/index.d.ts +1 -0
- package/dist/components/SelectNext/components/SelectSection/SelectSection.d.ts +9 -0
- package/dist/components/SelectNext/components/SelectSection/SelectSection.js +51 -0
- package/dist/components/SelectNext/components/SelectSection/index.d.ts +1 -0
- package/dist/components/SelectNext/components/Tag/Tag.d.ts +18 -0
- package/dist/components/SelectNext/components/Tag/Tag.js +67 -0
- package/dist/components/SelectNext/components/Tag/index.d.ts +1 -0
- package/dist/components/SelectNext/components/Tag/intl.json.js +7 -0
- package/dist/components/SelectNext/components/Tag/utils.d.ts +3 -0
- package/dist/components/SelectNext/components/Tag/utils.js +9 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.d.ts +13 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.js +25 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroup.module.css.js +20 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.d.ts +3 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupMultiline.js +44 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.d.ts +3 -0
- package/dist/components/SelectNext/components/TagGroup/TagGroupResponsive.js +65 -0
- package/dist/components/SelectNext/components/TagGroup/index.d.ts +1 -0
- package/dist/components/SelectNext/components/TagGroup/utils.d.ts +1 -0
- package/dist/components/SelectNext/components/TagGroup/utils.js +4 -0
- package/dist/components/SelectNext/components/index.d.ts +5 -0
- package/dist/components/SelectNext/index.d.ts +2 -0
- package/dist/components/SelectNext/intl.d.ts +2 -0
- package/dist/components/SelectNext/intl.js +21 -0
- package/dist/components/SelectNext/types.d.ts +99 -0
- package/dist/components/SelectNext/types.js +12 -0
- package/dist/components/SelectNext/utils.d.ts +9 -0
- package/dist/components/SelectNext/utils.js +26 -0
- package/dist/components/index.d.ts +2 -1
- package/dist/index.js +8 -1
- package/dist/style.css +172 -43
- package/package.json +5 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SelectList';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Key, ExtendableComponentPropsWithRef } from '@koobiq/react-core';
|
|
2
|
+
export type SelectOptionProps<T = object> = ExtendableComponentPropsWithRef<{
|
|
3
|
+
className?: string;
|
|
4
|
+
/** The unique id of the item. */
|
|
5
|
+
id?: Key;
|
|
6
|
+
/** The object value that this item represents. When using dynamic collections, this is set automatically. */
|
|
7
|
+
value?: T;
|
|
8
|
+
/** A string representation of the item's contents, used for features like typeahead. */
|
|
9
|
+
textValue?: string;
|
|
10
|
+
/** An accessibility label for this item. */
|
|
11
|
+
'aria-label'?: string;
|
|
12
|
+
/** Whether the item is disabled. */
|
|
13
|
+
isDisabled?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Handler that is called when a user performs an action on the item. The exact user event depends on
|
|
16
|
+
* the collection's `selectionBehavior` prop and the interaction modality.
|
|
17
|
+
*/
|
|
18
|
+
onAction?: () => void;
|
|
19
|
+
}, 'a'>;
|
|
20
|
+
export declare const SelectOption: <T extends object>(props: Omit<import("react").DetailedHTMLProps<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "value" | "className" | "id" | "aria-label" | "isDisabled" | "textValue" | "onAction"> & {
|
|
21
|
+
className?: string;
|
|
22
|
+
/** The unique id of the item. */
|
|
23
|
+
id?: Key;
|
|
24
|
+
/** The object value that this item represents. When using dynamic collections, this is set automatically. */
|
|
25
|
+
value?: object | undefined;
|
|
26
|
+
/** A string representation of the item's contents, used for features like typeahead. */
|
|
27
|
+
textValue?: string;
|
|
28
|
+
/** An accessibility label for this item. */
|
|
29
|
+
'aria-label'?: string;
|
|
30
|
+
/** Whether the item is disabled. */
|
|
31
|
+
isDisabled?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Handler that is called when a user performs an action on the item. The exact user event depends on
|
|
34
|
+
* the collection's `selectionBehavior` prop and the interaction modality.
|
|
35
|
+
*/
|
|
36
|
+
onAction?: () => void;
|
|
37
|
+
} & import("react").RefAttributes<HTMLElement>) => import("react").ReactElement | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useContext } from "react";
|
|
4
|
+
import { useMultiRef, useHover, usePress, filterDOMProps, clsx, mergeProps } from "@koobiq/react-core";
|
|
5
|
+
import { createLeafComponent, ItemNode, useOption } from "@koobiq/react-primitives";
|
|
6
|
+
import { utilClasses } from "../../../../styles/utility.js";
|
|
7
|
+
import { SelectContext } from "../../SelectContext.js";
|
|
8
|
+
import { Checkbox } from "../../../Checkbox/Checkbox.js";
|
|
9
|
+
const textVariant = utilClasses.typography;
|
|
10
|
+
const { listItem } = utilClasses;
|
|
11
|
+
const SelectOption = createLeafComponent(ItemNode, function SelectItem(props, forwardedRef, item) {
|
|
12
|
+
const { href, className, style } = props;
|
|
13
|
+
const domRef = useRef(null);
|
|
14
|
+
const ref = useMultiRef([forwardedRef, domRef]);
|
|
15
|
+
const state = useContext(SelectContext);
|
|
16
|
+
const { optionProps, isSelected, isDisabled, isFocusVisible } = useOption(
|
|
17
|
+
{ key: item.key },
|
|
18
|
+
state,
|
|
19
|
+
domRef
|
|
20
|
+
);
|
|
21
|
+
const { hoverProps, isHovered } = useHover({ isDisabled });
|
|
22
|
+
const { isPressed, pressProps } = usePress({ isDisabled });
|
|
23
|
+
const Tag = href ? "a" : "li";
|
|
24
|
+
const DOMProps = filterDOMProps(props, { global: true });
|
|
25
|
+
delete DOMProps.id;
|
|
26
|
+
delete DOMProps.onClick;
|
|
27
|
+
return /* @__PURE__ */ jsxs(
|
|
28
|
+
Tag,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
style,
|
|
32
|
+
"data-hovered": isHovered || void 0,
|
|
33
|
+
"data-pressed": isPressed || void 0,
|
|
34
|
+
"data-disabled": isDisabled || void 0,
|
|
35
|
+
"data-selected": isSelected || void 0,
|
|
36
|
+
"data-focus-visible": isFocusVisible || void 0,
|
|
37
|
+
...mergeProps(optionProps, hoverProps, pressProps),
|
|
38
|
+
className: clsx(listItem, textVariant["text-normal"], className),
|
|
39
|
+
children: [
|
|
40
|
+
state.selectionManager.selectionMode === "multiple" && /* @__PURE__ */ jsx(Checkbox, { isDisabled, isSelected, isReadOnly: true }),
|
|
41
|
+
item.rendered
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
export {
|
|
47
|
+
SelectOption
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SelectOption';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Key, SectionProps, ExtendableComponentPropsWithRef } from '@koobiq/react-core';
|
|
2
|
+
export type SelectSectionProps<T> = ExtendableComponentPropsWithRef<SectionProps<T> & {
|
|
3
|
+
/** The unique id of the item. */
|
|
4
|
+
id?: Key;
|
|
5
|
+
}, 'section'>;
|
|
6
|
+
export declare const SelectSection: <T extends object>(props: Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLElement>, HTMLElement>, "id" | keyof SectionProps<T_1>> & SectionProps<T> & {
|
|
7
|
+
/** The unique id of the item. */
|
|
8
|
+
id?: Key;
|
|
9
|
+
} & import("react").RefAttributes<HTMLElement>) => import("react").ReactElement | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useContext } from "react";
|
|
4
|
+
import { filterDOMProps, mergeProps } from "@koobiq/react-core";
|
|
5
|
+
import { createBranchComponent, SectionNode, useListBoxSection } from "@koobiq/react-primitives";
|
|
6
|
+
import { utilClasses } from "../../../../styles/utility.js";
|
|
7
|
+
import { SelectContext } from "../../SelectContext.js";
|
|
8
|
+
import { CollectionBranch } from "../../utils.js";
|
|
9
|
+
import { Typography } from "../../../Typography/Typography.js";
|
|
10
|
+
const { listHeading } = utilClasses;
|
|
11
|
+
function SelectSectionInner(props, ref, section) {
|
|
12
|
+
const state = useContext(SelectContext);
|
|
13
|
+
const { className, style } = props;
|
|
14
|
+
const { headingProps, groupProps } = useListBoxSection({
|
|
15
|
+
heading: section.rendered,
|
|
16
|
+
"aria-label": props["aria-label"] ?? void 0
|
|
17
|
+
});
|
|
18
|
+
const DOMProps = filterDOMProps(props, { global: true });
|
|
19
|
+
delete DOMProps.id;
|
|
20
|
+
return /* @__PURE__ */ jsxs(
|
|
21
|
+
"section",
|
|
22
|
+
{
|
|
23
|
+
...mergeProps(DOMProps, groupProps),
|
|
24
|
+
className,
|
|
25
|
+
style,
|
|
26
|
+
ref,
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ jsx(
|
|
29
|
+
Typography,
|
|
30
|
+
{
|
|
31
|
+
as: "span",
|
|
32
|
+
display: "block",
|
|
33
|
+
variant: "caps-compact-strong",
|
|
34
|
+
color: "contrast-secondary",
|
|
35
|
+
className: listHeading,
|
|
36
|
+
...headingProps,
|
|
37
|
+
children: props.title
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
/* @__PURE__ */ jsx(CollectionBranch, { collection: state.collection, parent: section })
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const SelectSection = createBranchComponent(
|
|
46
|
+
SectionNode,
|
|
47
|
+
SelectSectionInner
|
|
48
|
+
);
|
|
49
|
+
export {
|
|
50
|
+
SelectSection
|
|
51
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SelectSection';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
|
+
import type { ExtendableComponentPropsWithRef } from '@koobiq/react-core';
|
|
3
|
+
import type { TagGroupPropVariant } from '../../../TagGroup';
|
|
4
|
+
type TagProps = ExtendableComponentPropsWithRef<{
|
|
5
|
+
/**
|
|
6
|
+
* The variant to use.
|
|
7
|
+
* @default 'theme-fade'
|
|
8
|
+
*/
|
|
9
|
+
variant?: TagGroupPropVariant;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
icon?: ReactNode;
|
|
14
|
+
isDisabled?: boolean;
|
|
15
|
+
onRemove?: () => void;
|
|
16
|
+
}, 'div'>;
|
|
17
|
+
export declare const Tag: import("react").ForwardRefExoticComponent<Omit<TagProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { useLocalizedStringFormatter, mergeProps, clsx, isNotNil } from "@koobiq/react-core";
|
|
5
|
+
import { IconXmarkS16 } from "@koobiq/react-icons";
|
|
6
|
+
import { utilClasses } from "../../../../styles/utility.js";
|
|
7
|
+
import s from "../../../TagGroup/components/Tag/Tag.module.css.js";
|
|
8
|
+
import intlMessages from "./intl.json.js";
|
|
9
|
+
import { matchVariantToCloseButton } from "./utils.js";
|
|
10
|
+
import { IconButton } from "../../../IconButton/IconButton.js";
|
|
11
|
+
const textNormalMedium = utilClasses.typography["text-normal-medium"];
|
|
12
|
+
const Tag = forwardRef((props, ref) => {
|
|
13
|
+
const {
|
|
14
|
+
variant = "theme-fade",
|
|
15
|
+
icon,
|
|
16
|
+
className,
|
|
17
|
+
style,
|
|
18
|
+
isDisabled,
|
|
19
|
+
children,
|
|
20
|
+
onRemove,
|
|
21
|
+
...other
|
|
22
|
+
} = props;
|
|
23
|
+
const stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
24
|
+
const rootProps = mergeProps({
|
|
25
|
+
className: clsx(
|
|
26
|
+
s.base,
|
|
27
|
+
s[variant],
|
|
28
|
+
isDisabled && s.disabled,
|
|
29
|
+
textNormalMedium,
|
|
30
|
+
className
|
|
31
|
+
),
|
|
32
|
+
...other,
|
|
33
|
+
style
|
|
34
|
+
});
|
|
35
|
+
const removeButtonProps = {
|
|
36
|
+
isCompact: true,
|
|
37
|
+
isDisabled,
|
|
38
|
+
className: s.cancelIcon,
|
|
39
|
+
variant: matchVariantToCloseButton[variant],
|
|
40
|
+
"aria-label": stringFormatter.format("remove")
|
|
41
|
+
};
|
|
42
|
+
const contentProps = mergeProps({
|
|
43
|
+
className: s.content
|
|
44
|
+
});
|
|
45
|
+
const iconProps = mergeProps({
|
|
46
|
+
className: s.icon
|
|
47
|
+
});
|
|
48
|
+
return /* @__PURE__ */ jsxs("div", { ref, ...rootProps, children: [
|
|
49
|
+
isNotNil(icon) && /* @__PURE__ */ jsx("span", { ...iconProps, children: icon }),
|
|
50
|
+
isNotNil(children) && /* @__PURE__ */ jsx("span", { ...contentProps, children }),
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
IconButton,
|
|
53
|
+
{
|
|
54
|
+
as: "div",
|
|
55
|
+
size: "l",
|
|
56
|
+
...removeButtonProps,
|
|
57
|
+
tabIndex: void 0,
|
|
58
|
+
onPress: onRemove,
|
|
59
|
+
children: /* @__PURE__ */ jsx(IconXmarkS16, {})
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] });
|
|
63
|
+
});
|
|
64
|
+
Tag.displayName = "SelectTag";
|
|
65
|
+
export {
|
|
66
|
+
Tag
|
|
67
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Tag';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SelectState } from '@koobiq/react-primitives';
|
|
2
|
+
import type { SelectionMode } from '@react-types/select';
|
|
3
|
+
import type { SelectNextPropSelectedTagsOverflow } from '../../types';
|
|
4
|
+
export type TagGroupProps<T extends object, M extends SelectionMode = 'single'> = {
|
|
5
|
+
state: SelectState<T, M>;
|
|
6
|
+
states: {
|
|
7
|
+
isInvalid?: boolean;
|
|
8
|
+
isDisabled?: boolean;
|
|
9
|
+
isRequired?: boolean;
|
|
10
|
+
};
|
|
11
|
+
selectedTagsOverflow?: SelectNextPropSelectedTagsOverflow;
|
|
12
|
+
};
|
|
13
|
+
export declare function TagGroup<T extends object, M extends SelectionMode = 'single'>({ selectedTagsOverflow, ...rest }: TagGroupProps<T, M>): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { logger } from "@koobiq/logger";
|
|
4
|
+
import { TagGroupMultiline } from "./TagGroupMultiline.js";
|
|
5
|
+
import { TagGroupResponsive } from "./TagGroupResponsive.js";
|
|
6
|
+
function assertNever(x) {
|
|
7
|
+
logger.error(`Unhandled selectedTagsOverflow variant: ${x}`);
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
function TagGroup({
|
|
11
|
+
selectedTagsOverflow = "responsive",
|
|
12
|
+
...rest
|
|
13
|
+
}) {
|
|
14
|
+
switch (selectedTagsOverflow) {
|
|
15
|
+
case "responsive":
|
|
16
|
+
return /* @__PURE__ */ jsx(TagGroupResponsive, { ...rest });
|
|
17
|
+
case "multiline":
|
|
18
|
+
return /* @__PURE__ */ jsx(TagGroupMultiline, { ...rest });
|
|
19
|
+
default:
|
|
20
|
+
return assertNever(selectedTagsOverflow);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
TagGroup
|
|
25
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const container = "kbq-taggroup-container-5d455a";
|
|
2
|
+
const hasStartAddon = "kbq-taggroup-hasStartAddon-eb7d88";
|
|
3
|
+
const base = "kbq-taggroup-b97495";
|
|
4
|
+
const tag = "kbq-taggroup-tag-262753";
|
|
5
|
+
const more = "kbq-taggroup-more-db5a34";
|
|
6
|
+
const s = {
|
|
7
|
+
container,
|
|
8
|
+
hasStartAddon,
|
|
9
|
+
base,
|
|
10
|
+
tag,
|
|
11
|
+
more
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
base,
|
|
15
|
+
container,
|
|
16
|
+
s as default,
|
|
17
|
+
hasStartAddon,
|
|
18
|
+
more,
|
|
19
|
+
tag
|
|
20
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SelectionMode } from '@react-types/select';
|
|
2
|
+
import type { TagGroupProps } from './TagGroup';
|
|
3
|
+
export declare function TagGroupMultiline<T extends object, M extends SelectionMode = 'single'>({ state, states }: TagGroupProps<T, M>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLocalizedStringFormatter, clsx } from "@koobiq/react-core";
|
|
3
|
+
import intlMessages from "../../intl.js";
|
|
4
|
+
import s from "./TagGroup.module.css.js";
|
|
5
|
+
import { Tag } from "../Tag/Tag.js";
|
|
6
|
+
import { useFormFieldControlGroup } from "../../../FormField/FormFieldControlGroup/FormFieldControlGroupContext.js";
|
|
7
|
+
function TagGroupMultiline({ state, states }) {
|
|
8
|
+
const { isDisabled, isInvalid } = states;
|
|
9
|
+
const t = useLocalizedStringFormatter(intlMessages);
|
|
10
|
+
const { hasStartAddon } = useFormFieldControlGroup();
|
|
11
|
+
return /* @__PURE__ */ jsx(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
className: clsx(s.container, hasStartAddon && s.hasStartAddon),
|
|
15
|
+
"aria-hidden": true,
|
|
16
|
+
children: /* @__PURE__ */ jsx(
|
|
17
|
+
"div",
|
|
18
|
+
{
|
|
19
|
+
className: s.base,
|
|
20
|
+
"data-limit-tags": "multiline",
|
|
21
|
+
"aria-label": t.format("selected items"),
|
|
22
|
+
children: state.selectedItems?.map((item) => /* @__PURE__ */ jsx(
|
|
23
|
+
Tag,
|
|
24
|
+
{
|
|
25
|
+
className: s.tag,
|
|
26
|
+
isDisabled,
|
|
27
|
+
variant: isInvalid ? "error-fade" : "contrast-fade",
|
|
28
|
+
onRemove: () => {
|
|
29
|
+
if (state.selectionManager.isSelected(item.key)) {
|
|
30
|
+
state.selectionManager.toggleSelection(item.key);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
children: item.textValue
|
|
34
|
+
},
|
|
35
|
+
item.key
|
|
36
|
+
))
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
export {
|
|
43
|
+
TagGroupMultiline
|
|
44
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SelectionMode } from '@react-types/select';
|
|
2
|
+
import type { TagGroupProps } from './TagGroup';
|
|
3
|
+
export declare function TagGroupResponsive<T extends object, M extends SelectionMode = 'single'>({ state, states }: TagGroupProps<T, M>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useHideOverflowItems, useLocalizedStringFormatter, clsx } from "@koobiq/react-core";
|
|
3
|
+
import intlMessages from "../../intl.js";
|
|
4
|
+
import s from "./TagGroup.module.css.js";
|
|
5
|
+
import { getHiddenCount } from "./utils.js";
|
|
6
|
+
import { useFormFieldControlGroup } from "../../../FormField/FormFieldControlGroup/FormFieldControlGroupContext.js";
|
|
7
|
+
import { Tag } from "../Tag/Tag.js";
|
|
8
|
+
function TagGroupResponsive({ state, states }) {
|
|
9
|
+
const { isDisabled, isInvalid } = states;
|
|
10
|
+
const length = state?.selectedItems?.length || 0;
|
|
11
|
+
const { parentRef, visibleMap, itemsRefs } = useHideOverflowItems({
|
|
12
|
+
length: length + 1,
|
|
13
|
+
pinnedIndex: 0
|
|
14
|
+
});
|
|
15
|
+
const hiddenCount = getHiddenCount(visibleMap);
|
|
16
|
+
const t = useLocalizedStringFormatter(intlMessages);
|
|
17
|
+
const { hasStartAddon } = useFormFieldControlGroup();
|
|
18
|
+
return /* @__PURE__ */ jsxs(
|
|
19
|
+
"div",
|
|
20
|
+
{
|
|
21
|
+
className: clsx(s.container, hasStartAddon && s.hasStartAddon),
|
|
22
|
+
ref: parentRef,
|
|
23
|
+
"aria-hidden": true,
|
|
24
|
+
children: [
|
|
25
|
+
/* @__PURE__ */ jsx(
|
|
26
|
+
"div",
|
|
27
|
+
{
|
|
28
|
+
className: s.base,
|
|
29
|
+
"data-limit-tags": "responsive",
|
|
30
|
+
"aria-label": t.format("selected items"),
|
|
31
|
+
children: state.selectedItems?.map((item, i) => /* @__PURE__ */ jsx(
|
|
32
|
+
Tag,
|
|
33
|
+
{
|
|
34
|
+
className: s.tag,
|
|
35
|
+
ref: itemsRefs[i],
|
|
36
|
+
isDisabled,
|
|
37
|
+
"aria-hidden": !visibleMap[i] || void 0,
|
|
38
|
+
variant: isInvalid ? "error-fade" : "contrast-fade",
|
|
39
|
+
onRemove: () => {
|
|
40
|
+
if (state.selectionManager.isSelected(item.key)) {
|
|
41
|
+
state.selectionManager.toggleSelection(item.key);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
children: item.textValue
|
|
45
|
+
},
|
|
46
|
+
item.key
|
|
47
|
+
))
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
className: s.more,
|
|
54
|
+
ref: itemsRefs[itemsRefs.length - 1],
|
|
55
|
+
"aria-hidden": !visibleMap[length] || void 0,
|
|
56
|
+
children: t.format("more", { count: hiddenCount })
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
TagGroupResponsive
|
|
65
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagGroup';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getHiddenCount: (map: boolean[]) => number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const intlMessages = {
|
|
2
|
+
"ru-RU": {
|
|
3
|
+
"empty items": "Нет вариантов выбора",
|
|
4
|
+
"nothing found": "Ничего не найдено",
|
|
5
|
+
loading: "Загрузка…",
|
|
6
|
+
"selected items": "Выбранные элементы",
|
|
7
|
+
search: "Поиск",
|
|
8
|
+
more: ({ count }) => `+${count}`
|
|
9
|
+
},
|
|
10
|
+
"en-US": {
|
|
11
|
+
"empty items": "No options available",
|
|
12
|
+
"nothing found": "Nothing found",
|
|
13
|
+
"selected items": "Selected items",
|
|
14
|
+
loading: "Loading…",
|
|
15
|
+
search: "Search",
|
|
16
|
+
more: ({ count }) => `+${count}`
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export {
|
|
20
|
+
intlMessages as default
|
|
21
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ComponentRef, CSSProperties, ReactElement, ReactNode, Ref } from 'react';
|
|
2
|
+
import type { ExtendableProps } from '@koobiq/react-core';
|
|
3
|
+
import type { AriaSelectProps, SelectState } from '@koobiq/react-primitives';
|
|
4
|
+
import type { SelectionMode } from '@react-types/select';
|
|
5
|
+
import type { FormFieldLabelProps, FormFieldErrorProps, FormFieldSelectProps, FormFieldCaptionProps, FormFieldPropLabelAlign, FormFieldControlGroupProps, FormFieldPropLabelPlacement } from '../FormField';
|
|
6
|
+
import type { IconButtonProps } from '../IconButton';
|
|
7
|
+
import type { PopoverProps } from '../Popover';
|
|
8
|
+
import type { SearchInputProps } from '../SearchInput';
|
|
9
|
+
import type { SelectListProps } from './components';
|
|
10
|
+
export declare const selectNextPropSelectedTagsOverflow: readonly ["multiline", "responsive"];
|
|
11
|
+
export type SelectNextPropSelectedTagsOverflow = (typeof selectNextPropSelectedTagsOverflow)[number];
|
|
12
|
+
export declare const selectNextPropLabelPlacement: readonly ["top", "side"];
|
|
13
|
+
export type SelectNextPropLabelPlacement = FormFieldPropLabelPlacement;
|
|
14
|
+
export declare const selectNextPropLabelAlign: readonly ["start", "end"];
|
|
15
|
+
export type SelectNextPropLabelAlign = FormFieldPropLabelAlign;
|
|
16
|
+
export type SelectNextProps<T extends object, M extends SelectionMode = 'single'> = ExtendableProps<{
|
|
17
|
+
/**
|
|
18
|
+
* Defines how selected tags are displayed when they exceed the available space.
|
|
19
|
+
*
|
|
20
|
+
*- `"multiline"` — tags wrap to multiple lines.
|
|
21
|
+
*- `"responsive"` — tags collapse into a summary (e.g., "3 more").
|
|
22
|
+
* @default 'responsive'
|
|
23
|
+
*/
|
|
24
|
+
selectedTagsOverflow?: SelectNextPropSelectedTagsOverflow;
|
|
25
|
+
/** Handler that is called when the clear button is clicked. */
|
|
26
|
+
onClear?: () => void;
|
|
27
|
+
/** Sets the CSS [`className`](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. */
|
|
28
|
+
className?: string;
|
|
29
|
+
/** Whether the field can be emptied. */
|
|
30
|
+
isClearable?: boolean;
|
|
31
|
+
/** Addon placed before the children. */
|
|
32
|
+
startAddon?: ReactNode;
|
|
33
|
+
/** Addon placed after the children. */
|
|
34
|
+
endAddon?: ReactNode;
|
|
35
|
+
/** Inline styles. */
|
|
36
|
+
style?: CSSProperties;
|
|
37
|
+
/**
|
|
38
|
+
* If `true`, the label is hidden. Be sure to add aria-label to the input element.
|
|
39
|
+
*/
|
|
40
|
+
isLabelHidden?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The label's overall position relative to the element it is labeling.
|
|
43
|
+
* @default 'top'
|
|
44
|
+
*/
|
|
45
|
+
labelPlacement?: SelectNextPropLabelPlacement;
|
|
46
|
+
/**
|
|
47
|
+
* The label's horizontal alignment relative to the element it is labeling.
|
|
48
|
+
* @default 'start'
|
|
49
|
+
*/
|
|
50
|
+
labelAlign?: SelectNextPropLabelAlign;
|
|
51
|
+
/** The helper text content. */
|
|
52
|
+
caption?: ReactNode;
|
|
53
|
+
/**
|
|
54
|
+
* If true, the input will take up the full width of its container.
|
|
55
|
+
*/
|
|
56
|
+
fullWidth?: boolean;
|
|
57
|
+
/** The load more spinner to render when loading additional items. */
|
|
58
|
+
isLoading?: boolean;
|
|
59
|
+
/** Handler that is called when more items should be loaded, e.g. while scrolling near the bottom. */
|
|
60
|
+
onLoadMore?: () => void;
|
|
61
|
+
/** Unique identifier for testing purposes. */
|
|
62
|
+
'data-testid'?: string | number;
|
|
63
|
+
/** Ref to the control */
|
|
64
|
+
ref?: Ref<HTMLDivElement>;
|
|
65
|
+
/** A render function for displaying the selected value. */
|
|
66
|
+
renderValue?: (state: SelectState<T, M>, states: {
|
|
67
|
+
isInvalid?: boolean;
|
|
68
|
+
isDisabled?: boolean;
|
|
69
|
+
isRequired?: boolean;
|
|
70
|
+
}) => ReactNode;
|
|
71
|
+
/** Content to display when no items are available. */
|
|
72
|
+
noItemsText?: ReactNode;
|
|
73
|
+
/** Content to display when items are loading. */
|
|
74
|
+
loadingText?: ReactNode;
|
|
75
|
+
/** Enables search input for filtering items in the list. */
|
|
76
|
+
isSearchable?: boolean;
|
|
77
|
+
/** The value of the Select search input (controlled). */
|
|
78
|
+
inputValue?: string;
|
|
79
|
+
/** The default value of the Select search input (uncontrolled). */
|
|
80
|
+
defaultInputValue?: string;
|
|
81
|
+
/** Handler that is called when the Select search input value changes. */
|
|
82
|
+
onInputChange?: (value: string) => void;
|
|
83
|
+
/** The filter function used to determine if an option should be included in the Select list. */
|
|
84
|
+
defaultFilter?: (textValue: string, inputValue: string) => boolean;
|
|
85
|
+
/** The props used for each slot inside. */
|
|
86
|
+
slotProps?: {
|
|
87
|
+
popover?: PopoverProps;
|
|
88
|
+
label?: FormFieldLabelProps;
|
|
89
|
+
clearButton?: IconButtonProps;
|
|
90
|
+
control?: FormFieldSelectProps;
|
|
91
|
+
caption?: FormFieldCaptionProps;
|
|
92
|
+
group?: FormFieldControlGroupProps;
|
|
93
|
+
errorMessage?: FormFieldErrorProps;
|
|
94
|
+
list?: Omit<SelectListProps<T, M>, 'state'>;
|
|
95
|
+
'search-input'?: SearchInputProps;
|
|
96
|
+
};
|
|
97
|
+
}, Omit<AriaSelectProps<T, M>, 'description' | 'validationState' | 'selectedKey' | 'onSelectionChange' | 'defaultSelectedKey'>>;
|
|
98
|
+
export type SelectNextComponent = <T extends object, M extends SelectionMode = 'single'>(props: SelectNextProps<T, M>) => ReactElement | null;
|
|
99
|
+
export type SelectNextRef = ComponentRef<'div'>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { formFieldPropLabelPlacement, formFieldPropLabelAlign } from "../FormField/types.js";
|
|
2
|
+
const selectNextPropSelectedTagsOverflow = [
|
|
3
|
+
"multiline",
|
|
4
|
+
"responsive"
|
|
5
|
+
];
|
|
6
|
+
const selectNextPropLabelPlacement = formFieldPropLabelPlacement;
|
|
7
|
+
const selectNextPropLabelAlign = formFieldPropLabelAlign;
|
|
8
|
+
export {
|
|
9
|
+
selectNextPropLabelAlign,
|
|
10
|
+
selectNextPropLabelPlacement,
|
|
11
|
+
selectNextPropSelectedTagsOverflow
|
|
12
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Collection, Node } from '@react-types/shared';
|
|
2
|
+
export declare function useCollectionRender<T>(collection: Collection<Node<T>>, parent: Node<T> | null): import("react").ReactNode;
|
|
3
|
+
export declare function CollectionRoot<T>({ collection, }: {
|
|
4
|
+
collection: Collection<Node<T>>;
|
|
5
|
+
}): import("react").ReactNode;
|
|
6
|
+
export declare function CollectionBranch<T>({ collection, parent, }: {
|
|
7
|
+
collection: Collection<Node<T>>;
|
|
8
|
+
parent: Node<T>;
|
|
9
|
+
}): import("react").ReactNode;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCachedChildren } from "@koobiq/react-primitives";
|
|
2
|
+
function useCollectionRender(collection, parent) {
|
|
3
|
+
return useCachedChildren({
|
|
4
|
+
items: parent ? collection.getChildren(parent.key) : collection,
|
|
5
|
+
dependencies: [],
|
|
6
|
+
children(node) {
|
|
7
|
+
return node.render(node);
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function CollectionRoot({
|
|
12
|
+
collection
|
|
13
|
+
}) {
|
|
14
|
+
return useCollectionRender(collection, null);
|
|
15
|
+
}
|
|
16
|
+
function CollectionBranch({
|
|
17
|
+
collection,
|
|
18
|
+
parent
|
|
19
|
+
}) {
|
|
20
|
+
return useCollectionRender(collection, parent);
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
CollectionBranch,
|
|
24
|
+
CollectionRoot,
|
|
25
|
+
useCollectionRender
|
|
26
|
+
};
|