@spark-web/select 1.0.3 → 1.0.4
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 +1 -1
- package/dist/declarations/src/Select.d.ts +4 -4
- package/dist/spark-web-select.cjs.dev.js +5 -25
- package/dist/spark-web-select.cjs.prod.js +5 -25
- package/dist/spark-web-select.esm.js +5 -5
- package/package.json +12 -9
- package/CHANGELOG.md +0 -83
- package/src/Select.stories.tsx +0 -37
- package/src/Select.test.tsx +0 -135
- package/src/Select.tsx +0 -134
- package/src/index.ts +0 -5
package/README.md
CHANGED
|
@@ -136,4 +136,4 @@ return (
|
|
|
136
136
|
| value | string \| number \| readonly string[] | | Value of the select. |
|
|
137
137
|
|
|
138
138
|
[data-attribute-map]:
|
|
139
|
-
https://
|
|
139
|
+
https://github.com/brighte-labs/spark-web/blob/e7f6f4285b4cfd876312cc89fbdd094039aa239a/packages/utils/src/internal/buildDataAttributes.ts#L1
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataAttributeMap } from '@spark-web/utils/internal';
|
|
2
|
-
import
|
|
2
|
+
import type { SelectHTMLAttributes } from 'react';
|
|
3
3
|
declare type Option = {
|
|
4
4
|
disabled?: boolean;
|
|
5
5
|
label: string;
|
|
@@ -10,14 +10,14 @@ declare type Group = {
|
|
|
10
10
|
label: string;
|
|
11
11
|
};
|
|
12
12
|
export declare type OptionsOrGroups = Array<Option | Group>;
|
|
13
|
-
export declare type SelectProps = Pick<
|
|
13
|
+
export declare type SelectProps = Pick<SelectHTMLAttributes<HTMLSelectElement>, 'defaultValue' | 'name' | 'onBlur' | 'onChange' | 'required' | 'value'> & {
|
|
14
14
|
data?: DataAttributeMap;
|
|
15
15
|
options: OptionsOrGroups;
|
|
16
16
|
placeholder?: string;
|
|
17
17
|
};
|
|
18
|
-
export declare const Select:
|
|
18
|
+
export declare const Select: import("react").ForwardRefExoticComponent<Pick<SelectHTMLAttributes<HTMLSelectElement>, "value" | "defaultValue" | "onBlur" | "onChange" | "name" | "required"> & {
|
|
19
19
|
data?: DataAttributeMap | undefined;
|
|
20
20
|
options: OptionsOrGroups;
|
|
21
21
|
placeholder?: string | undefined;
|
|
22
|
-
} &
|
|
22
|
+
} & import("react").RefAttributes<HTMLSelectElement>>;
|
|
23
23
|
export {};
|
|
@@ -10,32 +10,11 @@ var field = require('@spark-web/field');
|
|
|
10
10
|
var icon = require('@spark-web/icon');
|
|
11
11
|
var textInput = require('@spark-web/text-input');
|
|
12
12
|
var theme = require('@spark-web/theme');
|
|
13
|
-
var
|
|
14
|
-
var React = require('react');
|
|
13
|
+
var react = require('react');
|
|
15
14
|
var jsxRuntime = require('react/jsx-runtime');
|
|
16
15
|
|
|
17
|
-
function _interopNamespace(e) {
|
|
18
|
-
if (e && e.__esModule) return e;
|
|
19
|
-
var n = Object.create(null);
|
|
20
|
-
if (e) {
|
|
21
|
-
Object.keys(e).forEach(function (k) {
|
|
22
|
-
if (k !== 'default') {
|
|
23
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
24
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return e[k]; }
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
n["default"] = e;
|
|
32
|
-
return Object.freeze(n);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
|
-
|
|
37
16
|
var _excluded = ["disabled", "invalid"];
|
|
38
|
-
var Select = /*#__PURE__*/
|
|
17
|
+
var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
39
18
|
var data = _ref.data,
|
|
40
19
|
defaultValue = _ref.defaultValue,
|
|
41
20
|
name = _ref.name,
|
|
@@ -55,7 +34,7 @@ var Select = /*#__PURE__*/React__namespace.forwardRef(function (_ref, forwardedR
|
|
|
55
34
|
disabled: disabled,
|
|
56
35
|
invalid: invalid
|
|
57
36
|
});
|
|
58
|
-
var mapOptions =
|
|
37
|
+
var mapOptions = react.useCallback(function (opt) {
|
|
59
38
|
return /*#__PURE__*/jsxRuntime.jsx("option", {
|
|
60
39
|
value: opt.value,
|
|
61
40
|
disabled: opt.disabled,
|
|
@@ -64,7 +43,8 @@ var Select = /*#__PURE__*/React__namespace.forwardRef(function (_ref, forwardedR
|
|
|
64
43
|
}, []);
|
|
65
44
|
return /*#__PURE__*/jsxRuntime.jsxs(box.Box, {
|
|
66
45
|
position: "relative",
|
|
67
|
-
children: [/*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread(
|
|
46
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread({}, a11yProps), {}, {
|
|
47
|
+
data: data,
|
|
68
48
|
as: "select",
|
|
69
49
|
defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
|
|
70
50
|
disabled: disabled,
|
|
@@ -10,32 +10,11 @@ var field = require('@spark-web/field');
|
|
|
10
10
|
var icon = require('@spark-web/icon');
|
|
11
11
|
var textInput = require('@spark-web/text-input');
|
|
12
12
|
var theme = require('@spark-web/theme');
|
|
13
|
-
var
|
|
14
|
-
var React = require('react');
|
|
13
|
+
var react = require('react');
|
|
15
14
|
var jsxRuntime = require('react/jsx-runtime');
|
|
16
15
|
|
|
17
|
-
function _interopNamespace(e) {
|
|
18
|
-
if (e && e.__esModule) return e;
|
|
19
|
-
var n = Object.create(null);
|
|
20
|
-
if (e) {
|
|
21
|
-
Object.keys(e).forEach(function (k) {
|
|
22
|
-
if (k !== 'default') {
|
|
23
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
24
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return e[k]; }
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
n["default"] = e;
|
|
32
|
-
return Object.freeze(n);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
|
-
|
|
37
16
|
var _excluded = ["disabled", "invalid"];
|
|
38
|
-
var Select = /*#__PURE__*/
|
|
17
|
+
var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
39
18
|
var data = _ref.data,
|
|
40
19
|
defaultValue = _ref.defaultValue,
|
|
41
20
|
name = _ref.name,
|
|
@@ -55,7 +34,7 @@ var Select = /*#__PURE__*/React__namespace.forwardRef(function (_ref, forwardedR
|
|
|
55
34
|
disabled: disabled,
|
|
56
35
|
invalid: invalid
|
|
57
36
|
});
|
|
58
|
-
var mapOptions =
|
|
37
|
+
var mapOptions = react.useCallback(function (opt) {
|
|
59
38
|
return /*#__PURE__*/jsxRuntime.jsx("option", {
|
|
60
39
|
value: opt.value,
|
|
61
40
|
disabled: opt.disabled,
|
|
@@ -64,7 +43,8 @@ var Select = /*#__PURE__*/React__namespace.forwardRef(function (_ref, forwardedR
|
|
|
64
43
|
}, []);
|
|
65
44
|
return /*#__PURE__*/jsxRuntime.jsxs(box.Box, {
|
|
66
45
|
position: "relative",
|
|
67
|
-
children: [/*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread(
|
|
46
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread({}, a11yProps), {}, {
|
|
47
|
+
data: data,
|
|
68
48
|
as: "select",
|
|
69
49
|
defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
|
|
70
50
|
disabled: disabled,
|
|
@@ -6,12 +6,11 @@ import { useFieldContext } from '@spark-web/field';
|
|
|
6
6
|
import { ChevronDownIcon } from '@spark-web/icon';
|
|
7
7
|
import { useInput } from '@spark-web/text-input';
|
|
8
8
|
import { useTheme } from '@spark-web/theme';
|
|
9
|
-
import {
|
|
10
|
-
import * as React from 'react';
|
|
9
|
+
import { forwardRef, useCallback } from 'react';
|
|
11
10
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
12
11
|
|
|
13
12
|
var _excluded = ["disabled", "invalid"];
|
|
14
|
-
var Select = /*#__PURE__*/
|
|
13
|
+
var Select = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
15
14
|
var data = _ref.data,
|
|
16
15
|
defaultValue = _ref.defaultValue,
|
|
17
16
|
name = _ref.name,
|
|
@@ -31,7 +30,7 @@ var Select = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
|
31
30
|
disabled: disabled,
|
|
32
31
|
invalid: invalid
|
|
33
32
|
});
|
|
34
|
-
var mapOptions =
|
|
33
|
+
var mapOptions = useCallback(function (opt) {
|
|
35
34
|
return /*#__PURE__*/jsx("option", {
|
|
36
35
|
value: opt.value,
|
|
37
36
|
disabled: opt.disabled,
|
|
@@ -40,7 +39,8 @@ var Select = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
|
40
39
|
}, []);
|
|
41
40
|
return /*#__PURE__*/jsxs(Box, {
|
|
42
41
|
position: "relative",
|
|
43
|
-
children: [/*#__PURE__*/jsxs(Box, _objectSpread(_objectSpread(
|
|
42
|
+
children: [/*#__PURE__*/jsxs(Box, _objectSpread(_objectSpread({}, a11yProps), {}, {
|
|
43
|
+
data: data,
|
|
44
44
|
as: "select",
|
|
45
45
|
defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
|
|
46
46
|
disabled: disabled,
|
package/package.json
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spark-web/select",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/spark-web-select.cjs.js",
|
|
6
6
|
"module": "dist/spark-web-select.esm.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
7
10
|
"dependencies": {
|
|
8
11
|
"@babel/runtime": "^7.14.6",
|
|
9
12
|
"@emotion/css": "^11.7.1",
|
|
10
|
-
"@spark-web/a11y": "^1.0.
|
|
11
|
-
"@spark-web/box": "^1.0.
|
|
12
|
-
"@spark-web/field": "^1.0
|
|
13
|
-
"@spark-web/icon": "^1.1.
|
|
14
|
-
"@spark-web/text": "^1.0.
|
|
15
|
-
"@spark-web/text-input": "^1.0
|
|
16
|
-
"@spark-web/theme": "^
|
|
17
|
-
"@spark-web/utils": "^1.1.
|
|
13
|
+
"@spark-web/a11y": "^1.0.4",
|
|
14
|
+
"@spark-web/box": "^1.0.4",
|
|
15
|
+
"@spark-web/field": "^1.1.0",
|
|
16
|
+
"@spark-web/icon": "^1.1.2",
|
|
17
|
+
"@spark-web/text": "^1.0.4",
|
|
18
|
+
"@spark-web/text-input": "^1.1.0",
|
|
19
|
+
"@spark-web/theme": "^3.0.0",
|
|
20
|
+
"@spark-web/utils": "^1.1.2"
|
|
18
21
|
},
|
|
19
22
|
"devDependencies": {
|
|
20
23
|
"@types/react": "^17.0.12",
|
package/CHANGELOG.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# @spark-web/select
|
|
2
|
-
|
|
3
|
-
## 1.0.3
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- [#42](https://github.com/brighte-labs/spark-web/pull/42)
|
|
8
|
-
[`435779a`](https://github.com/brighte-labs/spark-web/commit/435779aa42bd635bbf43e1fd41724c666402caa2)
|
|
9
|
-
Thanks [@lukebennett88](https://github.com/lukebennett88)! - Prevent multiple
|
|
10
|
-
versions of React
|
|
11
|
-
|
|
12
|
-
- Updated dependencies
|
|
13
|
-
[[`435779a`](https://github.com/brighte-labs/spark-web/commit/435779aa42bd635bbf43e1fd41724c666402caa2)]:
|
|
14
|
-
- @spark-web/a11y@1.0.3
|
|
15
|
-
- @spark-web/box@1.0.3
|
|
16
|
-
- @spark-web/field@1.0.3
|
|
17
|
-
- @spark-web/icon@1.1.1
|
|
18
|
-
- @spark-web/text@1.0.3
|
|
19
|
-
- @spark-web/text-input@1.0.3
|
|
20
|
-
- @spark-web/theme@2.0.2
|
|
21
|
-
- @spark-web/utils@1.1.1
|
|
22
|
-
|
|
23
|
-
## 1.0.2
|
|
24
|
-
|
|
25
|
-
### Patch Changes
|
|
26
|
-
|
|
27
|
-
- [#40](https://github.com/brighte-labs/spark-web/pull/40)
|
|
28
|
-
[`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)
|
|
29
|
-
Thanks [@lukebennett88](https://github.com/lukebennett88)! - Add
|
|
30
|
-
@babel/transform-runtime
|
|
31
|
-
|
|
32
|
-
- Updated dependencies
|
|
33
|
-
[[`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)]:
|
|
34
|
-
- @spark-web/a11y@1.0.2
|
|
35
|
-
- @spark-web/box@1.0.2
|
|
36
|
-
- @spark-web/field@1.0.2
|
|
37
|
-
- @spark-web/icon@1.0.2
|
|
38
|
-
- @spark-web/text@1.0.2
|
|
39
|
-
- @spark-web/text-input@1.0.2
|
|
40
|
-
- @spark-web/theme@2.0.1
|
|
41
|
-
- @spark-web/utils@1.0.2
|
|
42
|
-
|
|
43
|
-
## 1.0.1
|
|
44
|
-
|
|
45
|
-
### Patch Changes
|
|
46
|
-
|
|
47
|
-
- [#36](https://github.com/brighte-labs/spark-web/pull/36)
|
|
48
|
-
[`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)
|
|
49
|
-
Thanks [@lukebennett88](https://github.com/lukebennett88)! - Update Babel
|
|
50
|
-
config
|
|
51
|
-
|
|
52
|
-
- Updated dependencies
|
|
53
|
-
[[`aebff30`](https://github.com/brighte-labs/spark-web/commit/aebff30c86cb0a9db22b545c46159ce0d1c14afb),
|
|
54
|
-
[`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)]:
|
|
55
|
-
- @spark-web/theme@2.0.0
|
|
56
|
-
- @spark-web/a11y@1.0.1
|
|
57
|
-
- @spark-web/box@1.0.1
|
|
58
|
-
- @spark-web/field@1.0.1
|
|
59
|
-
- @spark-web/icon@1.0.1
|
|
60
|
-
- @spark-web/text@1.0.1
|
|
61
|
-
- @spark-web/text-input@1.0.1
|
|
62
|
-
- @spark-web/utils@1.0.1
|
|
63
|
-
|
|
64
|
-
## 1.0.0
|
|
65
|
-
|
|
66
|
-
### Major Changes
|
|
67
|
-
|
|
68
|
-
- [#27](https://github.com/brighte-labs/spark-web/pull/27)
|
|
69
|
-
[`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)
|
|
70
|
-
Thanks [@JedWatson](https://github.com/JedWatson)! - Initial Version
|
|
71
|
-
|
|
72
|
-
### Patch Changes
|
|
73
|
-
|
|
74
|
-
- Updated dependencies
|
|
75
|
-
[[`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)]:
|
|
76
|
-
- @spark-web/a11y@1.0.0
|
|
77
|
-
- @spark-web/box@1.0.0
|
|
78
|
-
- @spark-web/field@1.0.0
|
|
79
|
-
- @spark-web/icon@1.0.0
|
|
80
|
-
- @spark-web/text@1.0.0
|
|
81
|
-
- @spark-web/text-input@1.0.0
|
|
82
|
-
- @spark-web/theme@1.0.0
|
|
83
|
-
- @spark-web/utils@1.0.0
|
package/src/Select.stories.tsx
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Field } from '@spark-web/field';
|
|
2
|
-
import { InformationCircleIcon } from '@spark-web/icon';
|
|
3
|
-
import { Inline } from '@spark-web/inline';
|
|
4
|
-
import { Stack } from '@spark-web/stack';
|
|
5
|
-
import { Text } from '@spark-web/text';
|
|
6
|
-
import type { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
7
|
-
|
|
8
|
-
import type { SelectProps } from './Select';
|
|
9
|
-
import { Select } from './Select';
|
|
10
|
-
|
|
11
|
-
export default {
|
|
12
|
-
title: 'Forms / Select',
|
|
13
|
-
component: Select,
|
|
14
|
-
} as ComponentMeta<typeof Select>;
|
|
15
|
-
|
|
16
|
-
const SelectStory: ComponentStory<typeof Select> = (args: SelectProps) => (
|
|
17
|
-
<Stack gap="large">
|
|
18
|
-
<Inline gap="xsmall" alignY="center">
|
|
19
|
-
<InformationCircleIcon tone="info" size="xsmall" />
|
|
20
|
-
<Text weight="medium" tone="info" baseline={false}>
|
|
21
|
-
{`Must be used inside of a <Field/>`}
|
|
22
|
-
</Text>
|
|
23
|
-
</Inline>
|
|
24
|
-
<Field label="Select input">
|
|
25
|
-
<Select options={args.options} />
|
|
26
|
-
</Field>
|
|
27
|
-
</Stack>
|
|
28
|
-
);
|
|
29
|
-
export const Default = SelectStory.bind({});
|
|
30
|
-
|
|
31
|
-
Default.args = {
|
|
32
|
-
options: [
|
|
33
|
-
{ value: 'one', label: 'One' },
|
|
34
|
-
{ value: 'two', label: 'Two' },
|
|
35
|
-
{ value: 'three', label: 'Three' },
|
|
36
|
-
],
|
|
37
|
-
} as SelectProps;
|
package/src/Select.test.tsx
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
2
|
-
|
|
3
|
-
import { Field, useFieldContext } from '@spark-web/field';
|
|
4
|
-
import type { DataAttributeMap } from '@spark-web/utils/internal';
|
|
5
|
-
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
6
|
-
|
|
7
|
-
import type { OptionsOrGroups } from './Select';
|
|
8
|
-
import { Select } from './Select';
|
|
9
|
-
|
|
10
|
-
jest.mock('@spark-web/field', () => {
|
|
11
|
-
const original = jest.requireActual('@spark-web/field');
|
|
12
|
-
return {
|
|
13
|
-
...original,
|
|
14
|
-
useFieldContext: jest.fn(),
|
|
15
|
-
};
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const useFieldContextMock = useFieldContext as jest.Mock;
|
|
19
|
-
|
|
20
|
-
const renderComponent = ({
|
|
21
|
-
options,
|
|
22
|
-
name,
|
|
23
|
-
placeholder,
|
|
24
|
-
data,
|
|
25
|
-
}: {
|
|
26
|
-
options: OptionsOrGroups;
|
|
27
|
-
name: string;
|
|
28
|
-
placeholder?: string;
|
|
29
|
-
data?: DataAttributeMap;
|
|
30
|
-
}) =>
|
|
31
|
-
render(
|
|
32
|
-
<Field label={name}>
|
|
33
|
-
<Select
|
|
34
|
-
options={options}
|
|
35
|
-
{...(placeholder && { placeholder })}
|
|
36
|
-
{...(data && { data })}
|
|
37
|
-
/>
|
|
38
|
-
</Field>
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
describe('Select component', () => {
|
|
42
|
-
const name = 'test select';
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
useFieldContextMock.mockReturnValue({
|
|
45
|
-
disabled: false,
|
|
46
|
-
invalid: false,
|
|
47
|
-
'aria-label': name,
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
afterEach(cleanup);
|
|
52
|
-
|
|
53
|
-
it('should display select label', () => {
|
|
54
|
-
renderComponent({ options: [], name });
|
|
55
|
-
screen.getByText(name);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should display placeholder with empty value and disabled', () => {
|
|
59
|
-
const placeholder = 'select placeholder';
|
|
60
|
-
renderComponent({ options: [], name, placeholder });
|
|
61
|
-
const placeholderOption = screen.getByRole('option', {
|
|
62
|
-
name: placeholder,
|
|
63
|
-
}) as HTMLOptionElement;
|
|
64
|
-
expect(placeholderOption.selected).toBe(true);
|
|
65
|
-
expect(placeholderOption.value).toBe('');
|
|
66
|
-
expect(placeholderOption).toBeDisabled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should have options to select', () => {
|
|
70
|
-
const options = [
|
|
71
|
-
{ label: 'foo', value: 'bar' },
|
|
72
|
-
{ label: 'foo1', value: 'bar1' },
|
|
73
|
-
{ label: 'foo2', value: 'bar2' },
|
|
74
|
-
];
|
|
75
|
-
renderComponent({ options, name });
|
|
76
|
-
expect(
|
|
77
|
-
(screen.getByRole('option', { name: 'foo' }) as HTMLOptionElement)
|
|
78
|
-
.selected
|
|
79
|
-
).toBe(true);
|
|
80
|
-
|
|
81
|
-
fireEvent.change(screen.getByLabelText(name), {
|
|
82
|
-
target: { value: 'bar1' },
|
|
83
|
-
});
|
|
84
|
-
expect(
|
|
85
|
-
(screen.getByRole('option', { name: 'foo1' }) as HTMLOptionElement)
|
|
86
|
-
.selected
|
|
87
|
-
).toBe(true);
|
|
88
|
-
|
|
89
|
-
fireEvent.change(screen.getByLabelText(name), {
|
|
90
|
-
target: { value: 'bar2' },
|
|
91
|
-
});
|
|
92
|
-
expect(
|
|
93
|
-
(screen.getByRole('option', { name: 'foo2' }) as HTMLOptionElement)
|
|
94
|
-
.selected
|
|
95
|
-
).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('should have attributes built by data', () => {
|
|
99
|
-
const data = { foo: 'bar', foo1: 'bar1' };
|
|
100
|
-
|
|
101
|
-
renderComponent({ data, name, options: [] });
|
|
102
|
-
expect(screen.getByLabelText(name)).toHaveAttribute('data-foo', 'bar');
|
|
103
|
-
expect(screen.getByLabelText(name)).toHaveAttribute('data-foo1', 'bar1');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should be disabled by field context', () => {
|
|
107
|
-
useFieldContextMock.mockReturnValue({
|
|
108
|
-
disabled: true,
|
|
109
|
-
invalid: true,
|
|
110
|
-
'aria-label': name,
|
|
111
|
-
});
|
|
112
|
-
renderComponent({ name, options: [] });
|
|
113
|
-
expect(screen.getByLabelText(name)).toBeDisabled();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should have option in optGroup', () => {
|
|
117
|
-
const optGroupOption = { label: 'foo1-0', value: 'bar1-0' };
|
|
118
|
-
const options = [
|
|
119
|
-
{ label: 'foo', value: 'bar' },
|
|
120
|
-
{
|
|
121
|
-
label: 'foo1',
|
|
122
|
-
value: 'bar1',
|
|
123
|
-
options: [optGroupOption],
|
|
124
|
-
},
|
|
125
|
-
];
|
|
126
|
-
renderComponent({ name, options });
|
|
127
|
-
expect(
|
|
128
|
-
(
|
|
129
|
-
screen.getByRole('option', {
|
|
130
|
-
name: optGroupOption.label,
|
|
131
|
-
}) as HTMLOptionElement
|
|
132
|
-
).value
|
|
133
|
-
).toBe(optGroupOption.value);
|
|
134
|
-
});
|
|
135
|
-
});
|
package/src/Select.tsx
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { css } from '@emotion/css';
|
|
2
|
-
import { Box } from '@spark-web/box';
|
|
3
|
-
import { useFieldContext } from '@spark-web/field';
|
|
4
|
-
import { ChevronDownIcon } from '@spark-web/icon';
|
|
5
|
-
import type { UseInputProps } from '@spark-web/text-input';
|
|
6
|
-
import { useInput } from '@spark-web/text-input';
|
|
7
|
-
import { useTheme } from '@spark-web/theme';
|
|
8
|
-
import type { DataAttributeMap } from '@spark-web/utils/internal';
|
|
9
|
-
import { buildDataAttributes } from '@spark-web/utils/internal';
|
|
10
|
-
import * as React from 'react';
|
|
11
|
-
|
|
12
|
-
type Option = {
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
label: string;
|
|
15
|
-
value: string | number;
|
|
16
|
-
};
|
|
17
|
-
type Group = { options: Array<Option>; label: string };
|
|
18
|
-
export type OptionsOrGroups = Array<Option | Group>;
|
|
19
|
-
|
|
20
|
-
export type SelectProps = Pick<
|
|
21
|
-
React.SelectHTMLAttributes<HTMLSelectElement>,
|
|
22
|
-
'defaultValue' | 'name' | 'onBlur' | 'onChange' | 'required' | 'value'
|
|
23
|
-
> & {
|
|
24
|
-
data?: DataAttributeMap;
|
|
25
|
-
options: OptionsOrGroups;
|
|
26
|
-
placeholder?: string;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
|
|
30
|
-
(
|
|
31
|
-
{
|
|
32
|
-
data,
|
|
33
|
-
defaultValue,
|
|
34
|
-
name,
|
|
35
|
-
onBlur,
|
|
36
|
-
onChange,
|
|
37
|
-
options: optionsOrGroups,
|
|
38
|
-
placeholder,
|
|
39
|
-
required,
|
|
40
|
-
value,
|
|
41
|
-
},
|
|
42
|
-
forwardedRef
|
|
43
|
-
) => {
|
|
44
|
-
const { disabled, invalid, ...a11yProps } = useFieldContext();
|
|
45
|
-
const styles = useSelectStyles({ disabled, invalid });
|
|
46
|
-
|
|
47
|
-
const mapOptions = React.useCallback(
|
|
48
|
-
(opt: Option) => (
|
|
49
|
-
<option key={opt.value} value={opt.value} disabled={opt.disabled}>
|
|
50
|
-
{opt.label}
|
|
51
|
-
</option>
|
|
52
|
-
),
|
|
53
|
-
[]
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<Box position="relative">
|
|
58
|
-
<Box
|
|
59
|
-
{...a11yProps}
|
|
60
|
-
{...(data ? buildDataAttributes(data) : null)}
|
|
61
|
-
as="select"
|
|
62
|
-
defaultValue={defaultValue ?? placeholder ? '' : undefined}
|
|
63
|
-
disabled={disabled}
|
|
64
|
-
name={name}
|
|
65
|
-
onBlur={onBlur}
|
|
66
|
-
onChange={onChange}
|
|
67
|
-
ref={forwardedRef}
|
|
68
|
-
required={required}
|
|
69
|
-
value={value}
|
|
70
|
-
// Styles
|
|
71
|
-
background={disabled ? 'inputDisabled' : 'input'}
|
|
72
|
-
border={invalid ? 'critical' : 'field'}
|
|
73
|
-
borderRadius="small"
|
|
74
|
-
paddingX="medium"
|
|
75
|
-
height="medium"
|
|
76
|
-
width="full"
|
|
77
|
-
className={css(styles)}
|
|
78
|
-
>
|
|
79
|
-
{placeholder && (
|
|
80
|
-
<option value="" disabled>
|
|
81
|
-
{placeholder}
|
|
82
|
-
</option>
|
|
83
|
-
)}
|
|
84
|
-
{optionsOrGroups.map(optionOrGroup => {
|
|
85
|
-
if ('options' in optionOrGroup) {
|
|
86
|
-
return (
|
|
87
|
-
<optgroup key={optionOrGroup.label} label={optionOrGroup.label}>
|
|
88
|
-
{optionOrGroup.options.map(option => mapOptions(option))}
|
|
89
|
-
</optgroup>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
return mapOptions(optionOrGroup);
|
|
93
|
-
})}
|
|
94
|
-
</Box>
|
|
95
|
-
<Box
|
|
96
|
-
position="absolute"
|
|
97
|
-
top={0}
|
|
98
|
-
bottom={0}
|
|
99
|
-
right={0}
|
|
100
|
-
display="flex"
|
|
101
|
-
alignItems="center"
|
|
102
|
-
padding="medium"
|
|
103
|
-
className={css({ pointerEvents: 'none' })}
|
|
104
|
-
>
|
|
105
|
-
<ChevronDownIcon size="xxsmall" tone="placeholder" />
|
|
106
|
-
</Box>
|
|
107
|
-
</Box>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
Select.displayName = 'Select';
|
|
113
|
-
|
|
114
|
-
function useSelectStyles({ disabled, invalid }: UseInputProps) {
|
|
115
|
-
const theme = useTheme();
|
|
116
|
-
const inputStyles = useInput({
|
|
117
|
-
disabled,
|
|
118
|
-
invalid,
|
|
119
|
-
});
|
|
120
|
-
return {
|
|
121
|
-
...inputStyles,
|
|
122
|
-
overflow: 'hidden', // fix for Safari to prevent unwanted scrolling of parent container to occur
|
|
123
|
-
textOverflow: 'ellipsis',
|
|
124
|
-
|
|
125
|
-
// Prevent text going underneath the chevron icon
|
|
126
|
-
paddingRight:
|
|
127
|
-
theme.sizing.xxsmall + // size of chevron icon
|
|
128
|
-
theme.spacing.medium * 2, // paddingX value
|
|
129
|
-
|
|
130
|
-
':invalid': {
|
|
131
|
-
color: theme.color.foreground.muted,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|