@spark-web/select 0.0.0-snapshot-release-20220907020533

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 ADDED
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: Select
3
+ storybookPath: forms-select--default
4
+ isExperimentalPackage: false
5
+ ---
6
+
7
+ Allows the user to make a single selection from a list of values — usually in a
8
+ form. If only a few options are provided, consider using a `RadioButton`
9
+ instead.
10
+
11
+ ## Usage
12
+
13
+ ### Field
14
+
15
+ Each select input must be accompanied by a Field with a label. Effective form
16
+ labeling helps inform users which selection to make.
17
+
18
+ ## Examples
19
+
20
+ ### Controlled
21
+
22
+ A `<Select>` can be both controlled and uncontrolled. To control a `<Select>`
23
+ provide a `value`, as well as an `onChange` function to set the new value when
24
+ the select is updated.
25
+
26
+ ```jsx live
27
+ const [selectedOption, setSelectedOption] = React.useState('');
28
+
29
+ const options = [
30
+ { label: 'NSW', value: 'nsw' },
31
+ { label: 'VIC', value: 'vic' },
32
+ { label: 'QLD', value: 'qld' },
33
+ { label: 'SA', value: 'sa' },
34
+ { label: 'WA', value: 'wa' },
35
+ { label: 'TAS', value: 'tas' },
36
+ { label: 'NT', value: 'nt' },
37
+ { label: 'ACT', value: 'act' },
38
+ ];
39
+
40
+ return (
41
+ <Stack gap="large">
42
+ <Field label="State">
43
+ <Select
44
+ placeholder="Choose a state..."
45
+ value={selectedOption}
46
+ onChange={event => setSelectedOption(event.target.value)}
47
+ options={options}
48
+ required
49
+ />
50
+ </Field>
51
+ {selectedOption && (
52
+ <Text>
53
+ You have selected{' '}
54
+ {options.find(option => option.value === selectedOption).label}
55
+ </Text>
56
+ )}
57
+ </Stack>
58
+ );
59
+ ```
60
+
61
+ ### Uncontrolled
62
+
63
+ The `<Select>`, by default, is an uncontrolled component, meaning that the form
64
+ data is controlled directly by the DOM itself. To access the value, instead of
65
+ writing an `onChange` handler, you would use a `ref` to get form values from the
66
+ DOM.
67
+
68
+ ```jsx live
69
+ <Field label="Breaking Bad Characters">
70
+ <Select
71
+ options={[
72
+ { label: 'Walter White', value: 'walter-white' },
73
+ { label: 'Jesse Pinkman', value: 'jesse-pinkman' },
74
+ { label: 'Saul Goodman', value: 'saul-goodman' },
75
+ { label: 'Gus Fring', value: 'gus-fring' },
76
+ { label: 'Hank Schrader', value: 'hank-schrader' },
77
+ { label: 'Mike Ehrmantraut', value: 'mike-ehrmantraut' },
78
+ ]}
79
+ />
80
+ </Field>
81
+ ```
82
+
83
+ ### Groups
84
+
85
+ Related options can be grouped by passing in an array of objects with a label
86
+ and option key — where each option is an array of objects with label, value and
87
+ (optionally) disabled keys. Internally this uses the
88
+ [`<optgroup>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup).
89
+
90
+ ```jsx live
91
+ const [selectedOption, setSelectedOption] = React.useState('');
92
+
93
+ return (
94
+ <Field label="Select">
95
+ <Select
96
+ placeholder="TV Characters"
97
+ options={[
98
+ {
99
+ label: 'Mad Men',
100
+ options: [
101
+ { label: 'Don Draper', value: 'don-draper' },
102
+ { label: 'Peggy Olson', value: 'peggy-olson' },
103
+ { label: 'Joan Harris', value: 'joan-harris' },
104
+ { label: 'Roger Sterling', value: 'roger-sterling' },
105
+ { label: 'Pete Campbell', value: 'pete-campbell' },
106
+ ],
107
+ },
108
+ {
109
+ label: 'Breaking Bad',
110
+ options: [
111
+ { label: 'Walter White', value: 'walter-white' },
112
+ { label: 'Jesse Pinkman', value: 'jesse-pinkman' },
113
+ { label: 'Saul Goodman', value: 'saul-goodman' },
114
+ { label: 'Gus Fring', value: 'gus-fring' },
115
+ { label: 'Hank Schrader', value: 'hank-schrader' },
116
+ { label: 'Mike Ehrmantraut', value: 'mike-ehrmantraut' },
117
+ ],
118
+ },
119
+ ]}
120
+ />
121
+ </Field>
122
+ );
123
+ ```
124
+
125
+ ## Props
126
+
127
+ | Prop | Type | Default | Description |
128
+ | ------------- | -------------------------------------------- | ------- | -------------------------------------------------------------------------------------- |
129
+ | data? | [DataAttributeMap][data-attribute-map] | | Sets data attributes on the component. |
130
+ | options | Readonly\<Array\<Option \| Group>> | | The values that can be selected by the input. |
131
+ | placeholder? | string | | Placeholder text for when the input does not have an initial value. |
132
+ | defaultValue? | string \| number \| readonly string[] | | Default value of the select. |
133
+ | name? | string | | This attribute is used to specify the name of the control. |
134
+ | onBlur? | React.FocusEventHandler\<HTMLSelectElement> | | Function for handling change events. |
135
+ | onChange? | React.ChangeEventHandler\<HTMLSelectElement> | | Function for handling blur events. |
136
+ | required? | boolean | | Boolean that indicating that an option with a non-empty string value must be selected. |
137
+ | value | string \| number \| readonly string[] | | Value of the select. |
138
+
139
+ [data-attribute-map]:
140
+ https://github.com/brighte-labs/spark-web/blob/e7f6f4285b4cfd876312cc89fbdd094039aa239a/packages/utils/src/internal/buildDataAttributes.ts#L1
@@ -0,0 +1,34 @@
1
+ import type { DataAttributeMap } from '@spark-web/utils/internal';
2
+ import type { SelectHTMLAttributes } from 'react';
3
+ export declare type Option = {
4
+ /** Whether or not the option is disabled. */
5
+ disabled?: boolean;
6
+ /** Label for the option. */
7
+ label: string;
8
+ /** Value of the option. */
9
+ value: string | number;
10
+ };
11
+ export declare type Group = {
12
+ /** List of options for the group. */
13
+ options: Array<Option>;
14
+ /** Label for the group. */
15
+ label: string;
16
+ };
17
+ export declare type OptionsOrGroups = Array<Option | Group>;
18
+ export declare type NativeSelectProps = Pick<SelectHTMLAttributes<HTMLSelectElement>, 'defaultValue' | 'name' | 'onBlur' | 'onChange' | 'required' | 'value'>;
19
+ export declare type SelectProps = NativeSelectProps & {
20
+ /** Allows setting of data attributes on the underlying element. */
21
+ data?: DataAttributeMap;
22
+ /** The values that can be selected by the input. */
23
+ options: OptionsOrGroups;
24
+ /** Placeholder text for when the input does not have an initial value. */
25
+ placeholder?: string;
26
+ };
27
+ export declare const Select: import("react").ForwardRefExoticComponent<NativeSelectProps & {
28
+ /** Allows setting of data attributes on the underlying element. */
29
+ data?: DataAttributeMap | undefined;
30
+ /** The values that can be selected by the input. */
31
+ options: OptionsOrGroups;
32
+ /** Placeholder text for when the input does not have an initial value. */
33
+ placeholder?: string | undefined;
34
+ } & import("react").RefAttributes<HTMLSelectElement>>;
@@ -0,0 +1,2 @@
1
+ export { Select } from './Select';
2
+ export type { SelectProps } from './Select';
@@ -0,0 +1 @@
1
+ export * from "./declarations/src/index";
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
6
+ var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
7
+ var css = require('@emotion/css');
8
+ var box = require('@spark-web/box');
9
+ var field = require('@spark-web/field');
10
+ var icon = require('@spark-web/icon');
11
+ var textInput = require('@spark-web/text-input');
12
+ var theme = require('@spark-web/theme');
13
+ var react = require('react');
14
+ var jsxRuntime = require('react/jsx-runtime');
15
+
16
+ var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
17
+ var data = _ref.data,
18
+ defaultValue = _ref.defaultValue,
19
+ name = _ref.name,
20
+ onBlur = _ref.onBlur,
21
+ onChange = _ref.onChange,
22
+ optionsOrGroups = _ref.options,
23
+ placeholder = _ref.placeholder,
24
+ required = _ref.required,
25
+ value = _ref.value;
26
+
27
+ var _useFieldContext = field.useFieldContext(),
28
+ _useFieldContext2 = _slicedToArray(_useFieldContext, 2),
29
+ _useFieldContext2$ = _useFieldContext2[0],
30
+ disabled = _useFieldContext2$.disabled,
31
+ invalid = _useFieldContext2$.invalid,
32
+ a11yProps = _useFieldContext2[1];
33
+
34
+ var _useSelectStyles = useSelectStyles({
35
+ disabled: disabled,
36
+ invalid: invalid
37
+ }),
38
+ _useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
39
+ boxProps = _useSelectStyles2[0],
40
+ inputStyles = _useSelectStyles2[1];
41
+
42
+ var mapOptions = react.useCallback(function (opt) {
43
+ return /*#__PURE__*/jsxRuntime.jsx("option", {
44
+ value: opt.value,
45
+ disabled: opt.disabled,
46
+ children: opt.label
47
+ }, opt.value);
48
+ }, []);
49
+ return /*#__PURE__*/jsxRuntime.jsxs(textInput.InputContainer, {
50
+ children: [/*#__PURE__*/jsxRuntime.jsx(Indicator, {}), /*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread(_objectSpread({}, boxProps), a11yProps), {}, {
51
+ as: "select",
52
+ className: css.css(inputStyles),
53
+ data: data,
54
+ defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
55
+ disabled: disabled,
56
+ name: name,
57
+ onBlur: onBlur,
58
+ onChange: onChange,
59
+ ref: forwardedRef,
60
+ required: required,
61
+ value: value,
62
+ width: "full",
63
+ children: [!value || placeholder ? /*#__PURE__*/jsxRuntime.jsx("option", {
64
+ value: "",
65
+ disabled: true,
66
+ children: placeholder
67
+ }) : null, optionsOrGroups.map(function (optionOrGroup) {
68
+ if ('options' in optionOrGroup) {
69
+ return /*#__PURE__*/jsxRuntime.jsx("optgroup", {
70
+ label: optionOrGroup.label,
71
+ children: optionOrGroup.options.map(function (option) {
72
+ return mapOptions(option);
73
+ })
74
+ }, optionOrGroup.label);
75
+ }
76
+
77
+ return mapOptions(optionOrGroup);
78
+ })]
79
+ }))]
80
+ });
81
+ });
82
+ Select.displayName = 'Select';
83
+
84
+ var Indicator = function Indicator() {
85
+ return /*#__PURE__*/jsxRuntime.jsx(box.Box, {
86
+ position: "absolute",
87
+ top: 0,
88
+ bottom: 0,
89
+ right: 0,
90
+ display: "flex",
91
+ alignItems: "center",
92
+ padding: "medium",
93
+ className: css.css({
94
+ pointerEvents: 'none'
95
+ }),
96
+ children: /*#__PURE__*/jsxRuntime.jsx(icon.ChevronDownIcon, {
97
+ size: "xxsmall",
98
+ tone: "placeholder"
99
+ })
100
+ });
101
+ };
102
+
103
+ function useSelectStyles(props) {
104
+ var _useInputStyles = textInput.useInputStyles(props),
105
+ _useInputStyles2 = _slicedToArray(_useInputStyles, 2),
106
+ boxProps = _useInputStyles2[0],
107
+ inputStyles = _useInputStyles2[1];
108
+
109
+ var theme$1 = theme.useTheme();
110
+ return [boxProps, _objectSpread(_objectSpread({}, inputStyles), {}, {
111
+ // Prevent text going underneath the chevron icon
112
+ paddingRight: theme$1.sizing.xxsmall + // size of chevron icon
113
+ theme$1.spacing.medium * 2 // paddingX value
114
+
115
+ })];
116
+ }
117
+
118
+ exports.Select = Select;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./spark-web-select.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./spark-web-select.cjs.dev.js");
7
+ }
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
6
+ var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
7
+ var css = require('@emotion/css');
8
+ var box = require('@spark-web/box');
9
+ var field = require('@spark-web/field');
10
+ var icon = require('@spark-web/icon');
11
+ var textInput = require('@spark-web/text-input');
12
+ var theme = require('@spark-web/theme');
13
+ var react = require('react');
14
+ var jsxRuntime = require('react/jsx-runtime');
15
+
16
+ var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
17
+ var data = _ref.data,
18
+ defaultValue = _ref.defaultValue,
19
+ name = _ref.name,
20
+ onBlur = _ref.onBlur,
21
+ onChange = _ref.onChange,
22
+ optionsOrGroups = _ref.options,
23
+ placeholder = _ref.placeholder,
24
+ required = _ref.required,
25
+ value = _ref.value;
26
+
27
+ var _useFieldContext = field.useFieldContext(),
28
+ _useFieldContext2 = _slicedToArray(_useFieldContext, 2),
29
+ _useFieldContext2$ = _useFieldContext2[0],
30
+ disabled = _useFieldContext2$.disabled,
31
+ invalid = _useFieldContext2$.invalid,
32
+ a11yProps = _useFieldContext2[1];
33
+
34
+ var _useSelectStyles = useSelectStyles({
35
+ disabled: disabled,
36
+ invalid: invalid
37
+ }),
38
+ _useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
39
+ boxProps = _useSelectStyles2[0],
40
+ inputStyles = _useSelectStyles2[1];
41
+
42
+ var mapOptions = react.useCallback(function (opt) {
43
+ return /*#__PURE__*/jsxRuntime.jsx("option", {
44
+ value: opt.value,
45
+ disabled: opt.disabled,
46
+ children: opt.label
47
+ }, opt.value);
48
+ }, []);
49
+ return /*#__PURE__*/jsxRuntime.jsxs(textInput.InputContainer, {
50
+ children: [/*#__PURE__*/jsxRuntime.jsx(Indicator, {}), /*#__PURE__*/jsxRuntime.jsxs(box.Box, _objectSpread(_objectSpread(_objectSpread({}, boxProps), a11yProps), {}, {
51
+ as: "select",
52
+ className: css.css(inputStyles),
53
+ data: data,
54
+ defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
55
+ disabled: disabled,
56
+ name: name,
57
+ onBlur: onBlur,
58
+ onChange: onChange,
59
+ ref: forwardedRef,
60
+ required: required,
61
+ value: value,
62
+ width: "full",
63
+ children: [!value || placeholder ? /*#__PURE__*/jsxRuntime.jsx("option", {
64
+ value: "",
65
+ disabled: true,
66
+ children: placeholder
67
+ }) : null, optionsOrGroups.map(function (optionOrGroup) {
68
+ if ('options' in optionOrGroup) {
69
+ return /*#__PURE__*/jsxRuntime.jsx("optgroup", {
70
+ label: optionOrGroup.label,
71
+ children: optionOrGroup.options.map(function (option) {
72
+ return mapOptions(option);
73
+ })
74
+ }, optionOrGroup.label);
75
+ }
76
+
77
+ return mapOptions(optionOrGroup);
78
+ })]
79
+ }))]
80
+ });
81
+ });
82
+ Select.displayName = 'Select';
83
+
84
+ var Indicator = function Indicator() {
85
+ return /*#__PURE__*/jsxRuntime.jsx(box.Box, {
86
+ position: "absolute",
87
+ top: 0,
88
+ bottom: 0,
89
+ right: 0,
90
+ display: "flex",
91
+ alignItems: "center",
92
+ padding: "medium",
93
+ className: css.css({
94
+ pointerEvents: 'none'
95
+ }),
96
+ children: /*#__PURE__*/jsxRuntime.jsx(icon.ChevronDownIcon, {
97
+ size: "xxsmall",
98
+ tone: "placeholder"
99
+ })
100
+ });
101
+ };
102
+
103
+ function useSelectStyles(props) {
104
+ var _useInputStyles = textInput.useInputStyles(props),
105
+ _useInputStyles2 = _slicedToArray(_useInputStyles, 2),
106
+ boxProps = _useInputStyles2[0],
107
+ inputStyles = _useInputStyles2[1];
108
+
109
+ var theme$1 = theme.useTheme();
110
+ return [boxProps, _objectSpread(_objectSpread({}, inputStyles), {}, {
111
+ // Prevent text going underneath the chevron icon
112
+ paddingRight: theme$1.sizing.xxsmall + // size of chevron icon
113
+ theme$1.spacing.medium * 2 // paddingX value
114
+
115
+ })];
116
+ }
117
+
118
+ exports.Select = Select;
@@ -0,0 +1,114 @@
1
+ import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
2
+ import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray';
3
+ import { css } from '@emotion/css';
4
+ import { Box } from '@spark-web/box';
5
+ import { useFieldContext } from '@spark-web/field';
6
+ import { ChevronDownIcon } from '@spark-web/icon';
7
+ import { InputContainer, useInputStyles } from '@spark-web/text-input';
8
+ import { useTheme } from '@spark-web/theme';
9
+ import { forwardRef, useCallback } from 'react';
10
+ import { jsx, jsxs } from 'react/jsx-runtime';
11
+
12
+ var Select = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
13
+ var data = _ref.data,
14
+ defaultValue = _ref.defaultValue,
15
+ name = _ref.name,
16
+ onBlur = _ref.onBlur,
17
+ onChange = _ref.onChange,
18
+ optionsOrGroups = _ref.options,
19
+ placeholder = _ref.placeholder,
20
+ required = _ref.required,
21
+ value = _ref.value;
22
+
23
+ var _useFieldContext = useFieldContext(),
24
+ _useFieldContext2 = _slicedToArray(_useFieldContext, 2),
25
+ _useFieldContext2$ = _useFieldContext2[0],
26
+ disabled = _useFieldContext2$.disabled,
27
+ invalid = _useFieldContext2$.invalid,
28
+ a11yProps = _useFieldContext2[1];
29
+
30
+ var _useSelectStyles = useSelectStyles({
31
+ disabled: disabled,
32
+ invalid: invalid
33
+ }),
34
+ _useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
35
+ boxProps = _useSelectStyles2[0],
36
+ inputStyles = _useSelectStyles2[1];
37
+
38
+ var mapOptions = useCallback(function (opt) {
39
+ return /*#__PURE__*/jsx("option", {
40
+ value: opt.value,
41
+ disabled: opt.disabled,
42
+ children: opt.label
43
+ }, opt.value);
44
+ }, []);
45
+ return /*#__PURE__*/jsxs(InputContainer, {
46
+ children: [/*#__PURE__*/jsx(Indicator, {}), /*#__PURE__*/jsxs(Box, _objectSpread(_objectSpread(_objectSpread({}, boxProps), a11yProps), {}, {
47
+ as: "select",
48
+ className: css(inputStyles),
49
+ data: data,
50
+ defaultValue: (defaultValue !== null && defaultValue !== void 0 ? defaultValue : placeholder) ? '' : undefined,
51
+ disabled: disabled,
52
+ name: name,
53
+ onBlur: onBlur,
54
+ onChange: onChange,
55
+ ref: forwardedRef,
56
+ required: required,
57
+ value: value,
58
+ width: "full",
59
+ children: [!value || placeholder ? /*#__PURE__*/jsx("option", {
60
+ value: "",
61
+ disabled: true,
62
+ children: placeholder
63
+ }) : null, optionsOrGroups.map(function (optionOrGroup) {
64
+ if ('options' in optionOrGroup) {
65
+ return /*#__PURE__*/jsx("optgroup", {
66
+ label: optionOrGroup.label,
67
+ children: optionOrGroup.options.map(function (option) {
68
+ return mapOptions(option);
69
+ })
70
+ }, optionOrGroup.label);
71
+ }
72
+
73
+ return mapOptions(optionOrGroup);
74
+ })]
75
+ }))]
76
+ });
77
+ });
78
+ Select.displayName = 'Select';
79
+
80
+ var Indicator = function Indicator() {
81
+ return /*#__PURE__*/jsx(Box, {
82
+ position: "absolute",
83
+ top: 0,
84
+ bottom: 0,
85
+ right: 0,
86
+ display: "flex",
87
+ alignItems: "center",
88
+ padding: "medium",
89
+ className: css({
90
+ pointerEvents: 'none'
91
+ }),
92
+ children: /*#__PURE__*/jsx(ChevronDownIcon, {
93
+ size: "xxsmall",
94
+ tone: "placeholder"
95
+ })
96
+ });
97
+ };
98
+
99
+ function useSelectStyles(props) {
100
+ var _useInputStyles = useInputStyles(props),
101
+ _useInputStyles2 = _slicedToArray(_useInputStyles, 2),
102
+ boxProps = _useInputStyles2[0],
103
+ inputStyles = _useInputStyles2[1];
104
+
105
+ var theme = useTheme();
106
+ return [boxProps, _objectSpread(_objectSpread({}, inputStyles), {}, {
107
+ // Prevent text going underneath the chevron icon
108
+ paddingRight: theme.sizing.xxsmall + // size of chevron icon
109
+ theme.spacing.medium * 2 // paddingX value
110
+
111
+ })];
112
+ }
113
+
114
+ export { Select };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@spark-web/select",
3
+ "version": "0.0.0-snapshot-release-20220907020533",
4
+ "license": "MIT",
5
+ "main": "dist/spark-web-select.cjs.js",
6
+ "module": "dist/spark-web-select.esm.js",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "dependencies": {
11
+ "@babel/runtime": "^7.18.9",
12
+ "@emotion/css": "^11.9.0",
13
+ "@spark-web/box": "^1.0.7",
14
+ "@spark-web/icon": "^1.1.5",
15
+ "@spark-web/text-input": "^2.0.1",
16
+ "@spark-web/theme": "0.0.0-snapshot-release-20220907020533"
17
+ },
18
+ "devDependencies": {
19
+ "@spark-web/field": "^3.0.3",
20
+ "@spark-web/utils": "^1.2.0",
21
+ "@types/react": "^17.0.12",
22
+ "react": "^17.0.2"
23
+ },
24
+ "peerDependencies": {
25
+ "@spark-web/field": "^3.0.3",
26
+ "react": ">=17.0.2"
27
+ },
28
+ "engines": {
29
+ "node": ">= 14.13"
30
+ }
31
+ }