@canonical/react-components 1.7.3 → 1.9.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/CustomSelect/CustomSelect.d.ts +36 -0
- package/dist/components/CustomSelect/CustomSelect.js +145 -0
- package/dist/components/CustomSelect/CustomSelect.scss +82 -0
- package/dist/components/CustomSelect/CustomSelect.stories.d.ts +28 -0
- package/dist/components/CustomSelect/CustomSelect.stories.js +132 -0
- package/dist/components/CustomSelect/CustomSelect.test.d.ts +1 -0
- package/dist/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.d.ts +25 -0
- package/dist/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.js +300 -0
- package/dist/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.test.d.ts +1 -0
- package/dist/components/CustomSelect/CustomSelectDropdown/index.d.ts +2 -0
- package/dist/components/CustomSelect/CustomSelectDropdown/index.js +20 -0
- package/dist/components/CustomSelect/index.d.ts +3 -0
- package/dist/components/CustomSelect/index.js +13 -0
- package/dist/components/MultiSelect/MultiSelect.d.ts +1 -0
- package/dist/components/MultiSelect/MultiSelect.js +6 -3
- package/dist/esm/components/CustomSelect/CustomSelect.d.ts +36 -0
- package/dist/esm/components/CustomSelect/CustomSelect.js +139 -0
- package/dist/esm/components/CustomSelect/CustomSelect.scss +82 -0
- package/dist/esm/components/CustomSelect/CustomSelect.stories.d.ts +28 -0
- package/dist/esm/components/CustomSelect/CustomSelect.stories.js +126 -0
- package/dist/esm/components/CustomSelect/CustomSelect.test.d.ts +1 -0
- package/dist/esm/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.d.ts +25 -0
- package/dist/esm/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.js +285 -0
- package/dist/esm/components/CustomSelect/CustomSelectDropdown/CustomSelectDropdown.test.d.ts +1 -0
- package/dist/esm/components/CustomSelect/CustomSelectDropdown/index.d.ts +2 -0
- package/dist/esm/components/CustomSelect/CustomSelectDropdown/index.js +1 -0
- package/dist/esm/components/CustomSelect/index.d.ts +3 -0
- package/dist/esm/components/CustomSelect/index.js +1 -0
- package/dist/esm/components/MultiSelect/MultiSelect.d.ts +1 -0
- package/dist/esm/components/MultiSelect/MultiSelect.js +6 -3
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MutableRefObject, ReactNode } from "react";
|
|
2
|
+
import { ClassName, PropsWithSpread } from "../../types";
|
|
3
|
+
import { FieldProps } from "../Field";
|
|
4
|
+
import { Position } from "../ContextualMenu";
|
|
5
|
+
import { CustomSelectOption } from "./CustomSelectDropdown";
|
|
6
|
+
import "./CustomSelect.scss";
|
|
7
|
+
export type SelectRef = MutableRefObject<{
|
|
8
|
+
open: () => void;
|
|
9
|
+
close: () => void;
|
|
10
|
+
isOpen: boolean;
|
|
11
|
+
focus: () => void;
|
|
12
|
+
} | undefined>;
|
|
13
|
+
export type Props = PropsWithSpread<FieldProps, {
|
|
14
|
+
value: string;
|
|
15
|
+
options: CustomSelectOption[];
|
|
16
|
+
onChange: (value: string) => void;
|
|
17
|
+
onSearch?: (value: string) => void;
|
|
18
|
+
id?: string | null;
|
|
19
|
+
name?: string;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
wrapperClassName?: ClassName;
|
|
22
|
+
toggleClassName?: ClassName;
|
|
23
|
+
dropdownClassName?: string;
|
|
24
|
+
searchable?: "auto" | "always" | "never";
|
|
25
|
+
takeFocus?: boolean;
|
|
26
|
+
header?: ReactNode;
|
|
27
|
+
selectRef?: SelectRef;
|
|
28
|
+
initialPosition?: Position;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* This is a [React](https://reactjs.org/) component that extends from the Vanilla [Select](https://vanillaframework.io/docs/base/forms#select) element.
|
|
32
|
+
*
|
|
33
|
+
* The aim of this component is to provide a select component with customisable options and a dropdown menu, whilst maintaining accessibility and usability.
|
|
34
|
+
*/
|
|
35
|
+
declare const CustomSelect: ({ value, options, onChange, onSearch, id, name, disabled, success, error, help, wrapperClassName, toggleClassName, dropdownClassName, searchable, takeFocus, header, selectRef, initialPosition, ...fieldProps }: Props) => JSX.Element;
|
|
36
|
+
export default CustomSelect;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _classnames = _interopRequireDefault(require("classnames"));
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _Field = _interopRequireDefault(require("../Field"));
|
|
10
|
+
var _ContextualMenu = _interopRequireDefault(require("../ContextualMenu"));
|
|
11
|
+
var _hooks = require("../../hooks");
|
|
12
|
+
var _CustomSelectDropdown = _interopRequireWildcard(require("./CustomSelectDropdown"));
|
|
13
|
+
require("./CustomSelect.scss");
|
|
14
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
15
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
16
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
18
|
+
/**
|
|
19
|
+
* This is a [React](https://reactjs.org/) component that extends from the Vanilla [Select](https://vanillaframework.io/docs/base/forms#select) element.
|
|
20
|
+
*
|
|
21
|
+
* The aim of this component is to provide a select component with customisable options and a dropdown menu, whilst maintaining accessibility and usability.
|
|
22
|
+
*/
|
|
23
|
+
const CustomSelect = _ref => {
|
|
24
|
+
let {
|
|
25
|
+
value,
|
|
26
|
+
options,
|
|
27
|
+
onChange,
|
|
28
|
+
onSearch,
|
|
29
|
+
id,
|
|
30
|
+
name,
|
|
31
|
+
disabled,
|
|
32
|
+
success,
|
|
33
|
+
error,
|
|
34
|
+
help,
|
|
35
|
+
wrapperClassName,
|
|
36
|
+
toggleClassName,
|
|
37
|
+
dropdownClassName,
|
|
38
|
+
searchable = "auto",
|
|
39
|
+
takeFocus,
|
|
40
|
+
header,
|
|
41
|
+
selectRef,
|
|
42
|
+
initialPosition = "left",
|
|
43
|
+
...fieldProps
|
|
44
|
+
} = _ref;
|
|
45
|
+
const [isOpen, setIsOpen] = (0, _react.useState)(false);
|
|
46
|
+
const validationId = (0, _react.useId)();
|
|
47
|
+
const defaultSelectId = (0, _react.useId)();
|
|
48
|
+
const selectId = id || defaultSelectId;
|
|
49
|
+
const helpId = (0, _react.useId)();
|
|
50
|
+
const hasError = !!error;
|
|
51
|
+
|
|
52
|
+
// Close the dropdown when the browser tab is hidden
|
|
53
|
+
const onBrowserTabHidden = () => {
|
|
54
|
+
if (document.visibilityState === "hidden") {
|
|
55
|
+
setIsOpen(false);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
(0, _hooks.useListener)(window, onBrowserTabHidden, "visibilitychange");
|
|
59
|
+
|
|
60
|
+
// Close the dropdown when the browser window loses focus
|
|
61
|
+
(0, _hooks.useListener)(window, () => setIsOpen(false), "blur");
|
|
62
|
+
(0, _react.useImperativeHandle)(selectRef, () => ({
|
|
63
|
+
open: () => {
|
|
64
|
+
var _document$getElementB;
|
|
65
|
+
setIsOpen(true);
|
|
66
|
+
(_document$getElementB = document.getElementById(selectId)) === null || _document$getElementB === void 0 || _document$getElementB.focus();
|
|
67
|
+
},
|
|
68
|
+
focus: () => {
|
|
69
|
+
var _document$getElementB2;
|
|
70
|
+
return (_document$getElementB2 = document.getElementById(selectId)) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.focus();
|
|
71
|
+
},
|
|
72
|
+
close: setIsOpen.bind(null, false),
|
|
73
|
+
isOpen: isOpen
|
|
74
|
+
}), [isOpen, selectId]);
|
|
75
|
+
(0, _react.useEffect)(() => {
|
|
76
|
+
if (takeFocus) {
|
|
77
|
+
const toggleButton = document.getElementById(selectId);
|
|
78
|
+
toggleButton === null || toggleButton === void 0 || toggleButton.focus();
|
|
79
|
+
}
|
|
80
|
+
}, [takeFocus, selectId]);
|
|
81
|
+
const selectedOption = options.find(option => option.value === value);
|
|
82
|
+
const toggleLabel = /*#__PURE__*/_react.default.createElement("span", {
|
|
83
|
+
className: "toggle-label u-truncate"
|
|
84
|
+
}, selectedOption ? (0, _CustomSelectDropdown.getOptionText)(selectedOption) : "Select an option");
|
|
85
|
+
const handleSelect = value => {
|
|
86
|
+
var _document$getElementB3;
|
|
87
|
+
(_document$getElementB3 = document.getElementById(selectId)) === null || _document$getElementB3 === void 0 || _document$getElementB3.focus();
|
|
88
|
+
setIsOpen(false);
|
|
89
|
+
onChange(value);
|
|
90
|
+
};
|
|
91
|
+
return /*#__PURE__*/_react.default.createElement(_Field.default, _extends({}, fieldProps, {
|
|
92
|
+
className: (0, _classnames.default)("p-custom-select", wrapperClassName),
|
|
93
|
+
error: error,
|
|
94
|
+
forId: selectId,
|
|
95
|
+
help: help,
|
|
96
|
+
helpId: helpId,
|
|
97
|
+
isSelect: true,
|
|
98
|
+
success: success,
|
|
99
|
+
validationId: validationId
|
|
100
|
+
}), /*#__PURE__*/_react.default.createElement(_ContextualMenu.default, {
|
|
101
|
+
"aria-describedby": [help ? helpId : null, success ? validationId : null].filter(Boolean).join(" "),
|
|
102
|
+
"aria-errormessage": hasError ? validationId : undefined,
|
|
103
|
+
"aria-invalid": hasError,
|
|
104
|
+
toggleClassName: (0, _classnames.default)("p-custom-select__toggle", "p-form-validation__input", toggleClassName, {
|
|
105
|
+
active: isOpen
|
|
106
|
+
}),
|
|
107
|
+
toggleLabel: toggleLabel,
|
|
108
|
+
visible: isOpen,
|
|
109
|
+
onToggleMenu: open => {
|
|
110
|
+
// Handle syncing the state when toggling the menu from within the
|
|
111
|
+
// contextual menu component e.g. when clicking outside.
|
|
112
|
+
if (open !== isOpen) {
|
|
113
|
+
setIsOpen(open);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
toggleProps: {
|
|
117
|
+
id: selectId,
|
|
118
|
+
disabled: disabled,
|
|
119
|
+
// tabIndex is set to -1 when disabled to prevent keyboard navigation to the select toggle
|
|
120
|
+
tabIndex: disabled ? -1 : 0
|
|
121
|
+
},
|
|
122
|
+
className: "p-custom-select__wrapper",
|
|
123
|
+
dropdownClassName: dropdownClassName,
|
|
124
|
+
style: {
|
|
125
|
+
width: "100%"
|
|
126
|
+
},
|
|
127
|
+
autoAdjust: true,
|
|
128
|
+
position: initialPosition
|
|
129
|
+
}, close => /*#__PURE__*/_react.default.createElement(_CustomSelectDropdown.default, {
|
|
130
|
+
searchable: searchable,
|
|
131
|
+
onSearch: onSearch,
|
|
132
|
+
name: name || "",
|
|
133
|
+
options: options || [],
|
|
134
|
+
onSelect: handleSelect,
|
|
135
|
+
onClose: () => {
|
|
136
|
+
var _document$getElementB4;
|
|
137
|
+
// When pressing ESC to close the dropdown, we keep focus on the toggle button
|
|
138
|
+
close();
|
|
139
|
+
(_document$getElementB4 = document.getElementById(selectId)) === null || _document$getElementB4 === void 0 || _document$getElementB4.focus();
|
|
140
|
+
},
|
|
141
|
+
header: header,
|
|
142
|
+
toggleId: selectId
|
|
143
|
+
})));
|
|
144
|
+
};
|
|
145
|
+
var _default = exports.default = CustomSelect;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
@import "vanilla-framework";
|
|
3
|
+
@include vf-b-placeholders; // Vanilla base placeholders to extend from
|
|
4
|
+
|
|
5
|
+
.p-custom-select {
|
|
6
|
+
@include vf-b-forms;
|
|
7
|
+
|
|
8
|
+
// style copied directly from vanilla-framework for the select element
|
|
9
|
+
.p-custom-select__toggle {
|
|
10
|
+
@include vf-icon-chevron-themed;
|
|
11
|
+
@extend %vf-input-elements;
|
|
12
|
+
|
|
13
|
+
// stylelint-disable property-no-vendor-prefix
|
|
14
|
+
-moz-appearance: none;
|
|
15
|
+
-webkit-appearance: none;
|
|
16
|
+
appearance: none;
|
|
17
|
+
// stylelint-enable property-no-vendor-prefix
|
|
18
|
+
background-position: right calc(map-get($grid-margin-widths, default) / 2)
|
|
19
|
+
center;
|
|
20
|
+
background-repeat: no-repeat;
|
|
21
|
+
background-size: map-get($icon-sizes, default);
|
|
22
|
+
border-top: none;
|
|
23
|
+
box-shadow: none;
|
|
24
|
+
min-height: map-get($line-heights, default-text);
|
|
25
|
+
padding-right: calc($default-icon-size + 2 * $sph--small);
|
|
26
|
+
text-indent: 0.01px;
|
|
27
|
+
|
|
28
|
+
&:hover {
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// this emulates the highlight effect when the select is focused
|
|
33
|
+
// without crowding the content with a border
|
|
34
|
+
&.active,
|
|
35
|
+
&:focus {
|
|
36
|
+
box-shadow: inset 0 0 0 3px $color-focus;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.toggle-label {
|
|
40
|
+
display: flow-root;
|
|
41
|
+
text-align: left;
|
|
42
|
+
width: 100%;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.p-custom-select__dropdown {
|
|
48
|
+
background-color: $colors--theme--background-alt;
|
|
49
|
+
box-shadow: $box-shadow--deep;
|
|
50
|
+
outline: none;
|
|
51
|
+
position: relative;
|
|
52
|
+
|
|
53
|
+
.p-custom-select__option {
|
|
54
|
+
background-color: $colors--theme--background-alt;
|
|
55
|
+
font-weight: $font-weight-regular-text;
|
|
56
|
+
padding: $sph--x-small $sph--small;
|
|
57
|
+
|
|
58
|
+
&.highlight {
|
|
59
|
+
// browser default styling for options when hovered
|
|
60
|
+
background-color: #06c;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
|
|
63
|
+
// make sure that if an option is highlighted, its text is white for good contrast
|
|
64
|
+
* {
|
|
65
|
+
color: white;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.p-custom-select__search {
|
|
71
|
+
background-color: $colors--theme--background-alt;
|
|
72
|
+
padding: $sph--x-small;
|
|
73
|
+
padding-bottom: $sph--small;
|
|
74
|
+
position: sticky;
|
|
75
|
+
top: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.p-list {
|
|
79
|
+
max-height: 30rem;
|
|
80
|
+
overflow: auto;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react/*";
|
|
2
|
+
import CustomSelect from "./CustomSelect";
|
|
3
|
+
import { ComponentProps } from "react";
|
|
4
|
+
type StoryProps = ComponentProps<typeof CustomSelect>;
|
|
5
|
+
declare const meta: Meta<StoryProps>;
|
|
6
|
+
export default meta;
|
|
7
|
+
type Story = StoryObj<StoryProps>;
|
|
8
|
+
/**
|
|
9
|
+
* If `label` is of `string` type. You do not have to do anything extra to render it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const StandardOptions: Story;
|
|
12
|
+
/**
|
|
13
|
+
* If `label` is of `ReactNode` type. You can render custom content.
|
|
14
|
+
* In this case, the `text` property for each option is required and is used for display in the toggle, search and sort functionalities.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CustomOptions: Story;
|
|
17
|
+
/**
|
|
18
|
+
* For each option, if `disabled` is set to `true`, the option will be disabled.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DisabledOptions: Story;
|
|
21
|
+
/**
|
|
22
|
+
* Search is enabled by default when there are 5 or more options.
|
|
23
|
+
*/
|
|
24
|
+
export declare const AutoSearchable: Story;
|
|
25
|
+
/**
|
|
26
|
+
* Search can be enabled manually by setting `searchable` to `always`.
|
|
27
|
+
*/
|
|
28
|
+
export declare const ManualSearchable: Story;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.StandardOptions = exports.ManualSearchable = exports.DisabledOptions = exports.CustomOptions = exports.AutoSearchable = void 0;
|
|
7
|
+
var _CustomSelect = _interopRequireDefault(require("./CustomSelect"));
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
10
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
13
|
+
const generateStandardOptions = num => Array(num).fill(null).map((_, i) => ({
|
|
14
|
+
value: "option-".concat(i + 1),
|
|
15
|
+
label: "Option ".concat(i + 1),
|
|
16
|
+
text: "Option ".concat(i + 1),
|
|
17
|
+
disabled: false
|
|
18
|
+
}));
|
|
19
|
+
const generateCustomOptions = () => {
|
|
20
|
+
return [{
|
|
21
|
+
value: "smile",
|
|
22
|
+
label: /*#__PURE__*/_react.default.createElement("div", null, "\uD83D\uDE00"),
|
|
23
|
+
text: "Smile",
|
|
24
|
+
disabled: false
|
|
25
|
+
}, {
|
|
26
|
+
value: "grin",
|
|
27
|
+
label: /*#__PURE__*/_react.default.createElement("div", null, "\uD83D\uDE01"),
|
|
28
|
+
text: "Grin",
|
|
29
|
+
disabled: false
|
|
30
|
+
}, {
|
|
31
|
+
value: "cry",
|
|
32
|
+
label: /*#__PURE__*/_react.default.createElement("div", null, "\uD83D\uDE2D"),
|
|
33
|
+
text: "Cry",
|
|
34
|
+
disabled: false
|
|
35
|
+
}, {
|
|
36
|
+
value: "angry",
|
|
37
|
+
label: /*#__PURE__*/_react.default.createElement("div", null, "\uD83D\uDE21"),
|
|
38
|
+
text: "Angry",
|
|
39
|
+
disabled: false
|
|
40
|
+
}, {
|
|
41
|
+
value: "sad",
|
|
42
|
+
label: /*#__PURE__*/_react.default.createElement("div", null, "\uD83D\uDE22"),
|
|
43
|
+
text: "Sad",
|
|
44
|
+
disabled: false
|
|
45
|
+
}];
|
|
46
|
+
};
|
|
47
|
+
const Template = _ref => {
|
|
48
|
+
let {
|
|
49
|
+
...props
|
|
50
|
+
} = _ref;
|
|
51
|
+
const [selected, setSelected] = (0, _react.useState)(props.value || "");
|
|
52
|
+
return /*#__PURE__*/_react.default.createElement(_CustomSelect.default, _extends({}, props, {
|
|
53
|
+
value: selected,
|
|
54
|
+
onChange: value => setSelected(value)
|
|
55
|
+
}));
|
|
56
|
+
};
|
|
57
|
+
const meta = {
|
|
58
|
+
component: _CustomSelect.default,
|
|
59
|
+
render: Template,
|
|
60
|
+
tags: ["autodocs"],
|
|
61
|
+
args: {
|
|
62
|
+
name: "customSelect",
|
|
63
|
+
label: "Custom Select",
|
|
64
|
+
searchable: "auto",
|
|
65
|
+
initialPosition: "left"
|
|
66
|
+
},
|
|
67
|
+
argTypes: {
|
|
68
|
+
searchable: {
|
|
69
|
+
options: ["auto", "always", "never"],
|
|
70
|
+
control: {
|
|
71
|
+
type: "select"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
initialPosition: {
|
|
75
|
+
options: ["left", "right"],
|
|
76
|
+
control: {
|
|
77
|
+
type: "select"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var _default = exports.default = meta;
|
|
83
|
+
/**
|
|
84
|
+
* If `label` is of `string` type. You do not have to do anything extra to render it.
|
|
85
|
+
*/
|
|
86
|
+
const StandardOptions = exports.StandardOptions = {
|
|
87
|
+
args: {
|
|
88
|
+
options: generateStandardOptions(10)
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* If `label` is of `ReactNode` type. You can render custom content.
|
|
94
|
+
* In this case, the `text` property for each option is required and is used for display in the toggle, search and sort functionalities.
|
|
95
|
+
*/
|
|
96
|
+
const CustomOptions = exports.CustomOptions = {
|
|
97
|
+
args: {
|
|
98
|
+
options: generateCustomOptions()
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* For each option, if `disabled` is set to `true`, the option will be disabled.
|
|
104
|
+
*/
|
|
105
|
+
const DisabledOptions = exports.DisabledOptions = {
|
|
106
|
+
args: {
|
|
107
|
+
options: generateStandardOptions(5).map((option, i) => ({
|
|
108
|
+
...option,
|
|
109
|
+
disabled: i % 2 === 0
|
|
110
|
+
}))
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Search is enabled by default when there are 5 or more options.
|
|
116
|
+
*/
|
|
117
|
+
const AutoSearchable = exports.AutoSearchable = {
|
|
118
|
+
args: {
|
|
119
|
+
options: generateStandardOptions(5),
|
|
120
|
+
searchable: "auto"
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Search can be enabled manually by setting `searchable` to `always`.
|
|
126
|
+
*/
|
|
127
|
+
const ManualSearchable = exports.ManualSearchable = {
|
|
128
|
+
args: {
|
|
129
|
+
options: generateStandardOptions(4),
|
|
130
|
+
searchable: "always"
|
|
131
|
+
}
|
|
132
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FC, LiHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
export type CustomSelectOption = LiHTMLAttributes<HTMLLIElement> & {
|
|
3
|
+
value: string;
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
text?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type Props = {
|
|
9
|
+
searchable?: "auto" | "always" | "never";
|
|
10
|
+
name: string;
|
|
11
|
+
options: CustomSelectOption[];
|
|
12
|
+
onSelect: (value: string) => void;
|
|
13
|
+
onSearch?: (value: string) => void;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
header?: ReactNode;
|
|
16
|
+
toggleId: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const adjustDropdownHeightBelow: (dropdown: HTMLUListElement) => void;
|
|
19
|
+
export declare const adjustDropdownHeightAbove: (dropdown: HTMLUListElement, search: HTMLInputElement | null) => void;
|
|
20
|
+
export declare const dropdownIsAbove: (dropdown: HTMLUListElement) => boolean;
|
|
21
|
+
export declare const adjustDropdownHeight: (dropdown: HTMLUListElement | null, search: HTMLInputElement | null) => void;
|
|
22
|
+
export declare const getNearestParentsZIndex: (element: HTMLElement | null) => string;
|
|
23
|
+
export declare const getOptionText: (option: CustomSelectOption) => string;
|
|
24
|
+
declare const CustomSelectDropdown: FC<Props>;
|
|
25
|
+
export default CustomSelectDropdown;
|