@spark-web/select 6.0.0 → 6.0.2
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/CHANGELOG.md +30 -0
- package/CLAUDE.md +105 -0
- package/dist/spark-web-select.cjs.dev.js +17 -3
- package/dist/spark-web-select.cjs.prod.js +17 -3
- package/dist/spark-web-select.esm.js +17 -3
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @spark-web/select
|
|
2
2
|
|
|
3
|
+
## 6.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#789](https://github.com/brighte-labs/spark-web/pull/789)
|
|
8
|
+
[`56d67c3`](https://github.com/brighte-labs/spark-web/commit/56d67c310457b792d663fe4e903111c5f45be90f)
|
|
9
|
+
Thanks [@jacobporci-brighte](https://github.com/jacobporci-brighte)! - Apply
|
|
10
|
+
muted color to placeholder text when no value is selected, matching the
|
|
11
|
+
appearance of text-input placeholders.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
[[`56d67c3`](https://github.com/brighte-labs/spark-web/commit/56d67c310457b792d663fe4e903111c5f45be90f),
|
|
14
|
+
[`56d67c3`](https://github.com/brighte-labs/spark-web/commit/56d67c310457b792d663fe4e903111c5f45be90f)]:
|
|
15
|
+
- @spark-web/field@5.3.2
|
|
16
|
+
- @spark-web/text-input@6.0.2
|
|
17
|
+
|
|
18
|
+
## 6.0.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#782](https://github.com/brighte-labs/spark-web/pull/782)
|
|
23
|
+
[`bb41800`](https://github.com/brighte-labs/spark-web/commit/bb418004d21165f72f4bf2456afea844ee04a21c)
|
|
24
|
+
Thanks [@jacobporci-brighte](https://github.com/jacobporci-brighte)! -
|
|
25
|
+
**docs:** add CLAUDE.md AI context files to foundation and form packages;
|
|
26
|
+
patch data-table with manual sort and spinner overlay patterns
|
|
27
|
+
- Updated dependencies
|
|
28
|
+
[[`bb41800`](https://github.com/brighte-labs/spark-web/commit/bb418004d21165f72f4bf2456afea844ee04a21c)]:
|
|
29
|
+
- @spark-web/box@6.0.1
|
|
30
|
+
- @spark-web/field@5.3.1
|
|
31
|
+
- @spark-web/text-input@6.0.1
|
|
32
|
+
|
|
3
33
|
## 6.0.0
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# @spark-web/select — AI Context
|
|
2
|
+
|
|
3
|
+
## What this is
|
|
4
|
+
|
|
5
|
+
A native `<select>` element styled to match the Spark design system. Accepts a
|
|
6
|
+
flat list of options or grouped options. Must always be wrapped in a `Field`
|
|
7
|
+
from `@spark-web/field`. Use for filter dropdowns (role, status, state) and form
|
|
8
|
+
selects with a small, known set of options.
|
|
9
|
+
|
|
10
|
+
## What this is NOT
|
|
11
|
+
|
|
12
|
+
- Not a combobox or searchable select — for searchable/async options use a
|
|
13
|
+
third-party combobox component with Spark styling
|
|
14
|
+
- Not usable without `Field` — always wrap in `<Field label="…">`
|
|
15
|
+
- Not responsible for its own label
|
|
16
|
+
|
|
17
|
+
## Props interface
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Notes |
|
|
20
|
+
| -------------- | ------------------------ | ----------------------------------------------------- |
|
|
21
|
+
| `options` | `Array<Option \| Group>` | required — the selectable values |
|
|
22
|
+
| `value` | `string \| number` | Controlled value |
|
|
23
|
+
| `onChange` | `ChangeEventHandler` | — |
|
|
24
|
+
| `placeholder` | `string` | Shown as disabled first option when no value selected |
|
|
25
|
+
| `defaultValue` | `string \| number` | Uncontrolled initial value |
|
|
26
|
+
| `name` | `string` | — |
|
|
27
|
+
| `required` | `boolean` | — |
|
|
28
|
+
| `data` | `DataAttributeMap` | Test/analytics attributes |
|
|
29
|
+
|
|
30
|
+
### Option shape
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
type Option = { label: string; value: string | number; disabled?: boolean };
|
|
34
|
+
type Group = { label: string; options: Option[] };
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`Option`, `Group`, and `OptionsOrGroups` are exported from `@spark-web/select`
|
|
38
|
+
and can be imported for type annotations.
|
|
39
|
+
|
|
40
|
+
## Common patterns
|
|
41
|
+
|
|
42
|
+
### Filter dropdown
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<Field label="Status" labelVisibility="hidden">
|
|
46
|
+
<Select
|
|
47
|
+
placeholder="Select status"
|
|
48
|
+
options={[
|
|
49
|
+
{ label: 'Active', value: 'active' },
|
|
50
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
51
|
+
{ label: 'Suspended', value: 'suspended' },
|
|
52
|
+
]}
|
|
53
|
+
value={statusFilter}
|
|
54
|
+
onChange={e => setStatusFilter(e.target.value)}
|
|
55
|
+
/>
|
|
56
|
+
</Field>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Grouped options
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
<Field label="Role">
|
|
63
|
+
<Select
|
|
64
|
+
placeholder="Select role"
|
|
65
|
+
options={[
|
|
66
|
+
{
|
|
67
|
+
label: 'Admin roles',
|
|
68
|
+
options: [
|
|
69
|
+
{ label: 'Admin', value: 'ADMIN' },
|
|
70
|
+
{ label: 'Admin Operations', value: 'ADMIN_OPERATIONS' },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
label: 'Other',
|
|
75
|
+
options: [{ label: 'Vendor', value: 'VENDOR' }],
|
|
76
|
+
},
|
|
77
|
+
]}
|
|
78
|
+
value={role}
|
|
79
|
+
onChange={e => setRole(e.target.value)}
|
|
80
|
+
/>
|
|
81
|
+
</Field>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Resettable filter (with an "All" option)
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<Select
|
|
88
|
+
value={filter}
|
|
89
|
+
onChange={e => setFilter(e.target.value)}
|
|
90
|
+
options={[
|
|
91
|
+
{ label: 'All statuses', value: '' },
|
|
92
|
+
{ label: 'Active', value: 'active' },
|
|
93
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
94
|
+
]}
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Do NOTs
|
|
99
|
+
|
|
100
|
+
- NEVER use `Select` without a parent `Field`
|
|
101
|
+
- NEVER use raw `<select>` — always use `Select`
|
|
102
|
+
- NEVER use `Select` for more than ~20 options without a searchable combobox
|
|
103
|
+
- NEVER pass `disabled` directly — set it on the parent `Field`
|
|
104
|
+
- NEVER use `Select` for boolean toggles — use a `Checkbox` or two `Button`
|
|
105
|
+
options instead
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
|
|
5
6
|
var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
|
|
6
7
|
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
7
8
|
var react$1 = require('@emotion/react');
|
|
@@ -13,6 +14,7 @@ var theme = require('@spark-web/theme');
|
|
|
13
14
|
var react = require('react');
|
|
14
15
|
var jsxRuntime = require('@emotion/react/jsx-runtime');
|
|
15
16
|
|
|
17
|
+
var _excluded = ["isPlaceholderActive", "disabled"];
|
|
16
18
|
var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
17
19
|
var data = _ref.data,
|
|
18
20
|
defaultValue = _ref.defaultValue,
|
|
@@ -29,9 +31,14 @@ var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
|
29
31
|
disabled = _useFieldContext2$.disabled,
|
|
30
32
|
invalid = _useFieldContext2$.invalid,
|
|
31
33
|
a11yProps = _useFieldContext2[1];
|
|
34
|
+
// Only applies when value is controlled and explicitly empty — the component
|
|
35
|
+
// cannot detect when the user selects an option in uncontrolled mode, so we
|
|
36
|
+
// only apply the muted style when value === '' (i.e. the caller controls it).
|
|
37
|
+
var isPlaceholderActive = placeholder !== undefined && value === '';
|
|
32
38
|
var _useSelectStyles = useSelectStyles({
|
|
33
39
|
disabled: disabled,
|
|
34
|
-
invalid: invalid
|
|
40
|
+
invalid: invalid,
|
|
41
|
+
isPlaceholderActive: isPlaceholderActive
|
|
35
42
|
}),
|
|
36
43
|
_useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
|
|
37
44
|
boxProps = _useSelectStyles2[0],
|
|
@@ -95,7 +102,12 @@ var Indicator = function Indicator() {
|
|
|
95
102
|
});
|
|
96
103
|
};
|
|
97
104
|
function useSelectStyles(props) {
|
|
98
|
-
var
|
|
105
|
+
var isPlaceholderActive = props.isPlaceholderActive,
|
|
106
|
+
disabled = props.disabled,
|
|
107
|
+
inputStylesProps = _objectWithoutProperties(props, _excluded);
|
|
108
|
+
var _useInputStyles = textInput.useInputStyles(_objectSpread({
|
|
109
|
+
disabled: disabled
|
|
110
|
+
}, inputStylesProps)),
|
|
99
111
|
_useInputStyles2 = _slicedToArray(_useInputStyles, 2),
|
|
100
112
|
boxProps = _useInputStyles2[0],
|
|
101
113
|
inputStyles = _useInputStyles2[1];
|
|
@@ -104,7 +116,9 @@ function useSelectStyles(props) {
|
|
|
104
116
|
// Prevent text going underneath the chevron icon
|
|
105
117
|
paddingRight: theme$1.sizing.xxsmall +
|
|
106
118
|
// size of chevron icon
|
|
107
|
-
theme$1.spacing.medium * 2
|
|
119
|
+
theme$1.spacing.medium * 2
|
|
120
|
+
}, isPlaceholderActive && !disabled && {
|
|
121
|
+
color: theme$1.color.foreground.placeholder
|
|
108
122
|
})];
|
|
109
123
|
}
|
|
110
124
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
|
|
5
6
|
var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
|
|
6
7
|
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
7
8
|
var react$1 = require('@emotion/react');
|
|
@@ -13,6 +14,7 @@ var theme = require('@spark-web/theme');
|
|
|
13
14
|
var react = require('react');
|
|
14
15
|
var jsxRuntime = require('@emotion/react/jsx-runtime');
|
|
15
16
|
|
|
17
|
+
var _excluded = ["isPlaceholderActive", "disabled"];
|
|
16
18
|
var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
17
19
|
var data = _ref.data,
|
|
18
20
|
defaultValue = _ref.defaultValue,
|
|
@@ -29,9 +31,14 @@ var Select = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
|
29
31
|
disabled = _useFieldContext2$.disabled,
|
|
30
32
|
invalid = _useFieldContext2$.invalid,
|
|
31
33
|
a11yProps = _useFieldContext2[1];
|
|
34
|
+
// Only applies when value is controlled and explicitly empty — the component
|
|
35
|
+
// cannot detect when the user selects an option in uncontrolled mode, so we
|
|
36
|
+
// only apply the muted style when value === '' (i.e. the caller controls it).
|
|
37
|
+
var isPlaceholderActive = placeholder !== undefined && value === '';
|
|
32
38
|
var _useSelectStyles = useSelectStyles({
|
|
33
39
|
disabled: disabled,
|
|
34
|
-
invalid: invalid
|
|
40
|
+
invalid: invalid,
|
|
41
|
+
isPlaceholderActive: isPlaceholderActive
|
|
35
42
|
}),
|
|
36
43
|
_useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
|
|
37
44
|
boxProps = _useSelectStyles2[0],
|
|
@@ -95,7 +102,12 @@ var Indicator = function Indicator() {
|
|
|
95
102
|
});
|
|
96
103
|
};
|
|
97
104
|
function useSelectStyles(props) {
|
|
98
|
-
var
|
|
105
|
+
var isPlaceholderActive = props.isPlaceholderActive,
|
|
106
|
+
disabled = props.disabled,
|
|
107
|
+
inputStylesProps = _objectWithoutProperties(props, _excluded);
|
|
108
|
+
var _useInputStyles = textInput.useInputStyles(_objectSpread({
|
|
109
|
+
disabled: disabled
|
|
110
|
+
}, inputStylesProps)),
|
|
99
111
|
_useInputStyles2 = _slicedToArray(_useInputStyles, 2),
|
|
100
112
|
boxProps = _useInputStyles2[0],
|
|
101
113
|
inputStyles = _useInputStyles2[1];
|
|
@@ -104,7 +116,9 @@ function useSelectStyles(props) {
|
|
|
104
116
|
// Prevent text going underneath the chevron icon
|
|
105
117
|
paddingRight: theme$1.sizing.xxsmall +
|
|
106
118
|
// size of chevron icon
|
|
107
|
-
theme$1.spacing.medium * 2
|
|
119
|
+
theme$1.spacing.medium * 2
|
|
120
|
+
}, isPlaceholderActive && !disabled && {
|
|
121
|
+
color: theme$1.color.foreground.placeholder
|
|
108
122
|
})];
|
|
109
123
|
}
|
|
110
124
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
|
|
1
2
|
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
|
|
2
3
|
import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray';
|
|
3
4
|
import { css } from '@emotion/react';
|
|
@@ -9,6 +10,7 @@ import { useTheme } from '@spark-web/theme';
|
|
|
9
10
|
import { forwardRef, useCallback } from 'react';
|
|
10
11
|
import { jsx, jsxs } from '@emotion/react/jsx-runtime';
|
|
11
12
|
|
|
13
|
+
var _excluded = ["isPlaceholderActive", "disabled"];
|
|
12
14
|
var Select = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
13
15
|
var data = _ref.data,
|
|
14
16
|
defaultValue = _ref.defaultValue,
|
|
@@ -25,9 +27,14 @@ var Select = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
|
|
|
25
27
|
disabled = _useFieldContext2$.disabled,
|
|
26
28
|
invalid = _useFieldContext2$.invalid,
|
|
27
29
|
a11yProps = _useFieldContext2[1];
|
|
30
|
+
// Only applies when value is controlled and explicitly empty — the component
|
|
31
|
+
// cannot detect when the user selects an option in uncontrolled mode, so we
|
|
32
|
+
// only apply the muted style when value === '' (i.e. the caller controls it).
|
|
33
|
+
var isPlaceholderActive = placeholder !== undefined && value === '';
|
|
28
34
|
var _useSelectStyles = useSelectStyles({
|
|
29
35
|
disabled: disabled,
|
|
30
|
-
invalid: invalid
|
|
36
|
+
invalid: invalid,
|
|
37
|
+
isPlaceholderActive: isPlaceholderActive
|
|
31
38
|
}),
|
|
32
39
|
_useSelectStyles2 = _slicedToArray(_useSelectStyles, 2),
|
|
33
40
|
boxProps = _useSelectStyles2[0],
|
|
@@ -91,7 +98,12 @@ var Indicator = function Indicator() {
|
|
|
91
98
|
});
|
|
92
99
|
};
|
|
93
100
|
function useSelectStyles(props) {
|
|
94
|
-
var
|
|
101
|
+
var isPlaceholderActive = props.isPlaceholderActive,
|
|
102
|
+
disabled = props.disabled,
|
|
103
|
+
inputStylesProps = _objectWithoutProperties(props, _excluded);
|
|
104
|
+
var _useInputStyles = useInputStyles(_objectSpread({
|
|
105
|
+
disabled: disabled
|
|
106
|
+
}, inputStylesProps)),
|
|
95
107
|
_useInputStyles2 = _slicedToArray(_useInputStyles, 2),
|
|
96
108
|
boxProps = _useInputStyles2[0],
|
|
97
109
|
inputStyles = _useInputStyles2[1];
|
|
@@ -100,7 +112,9 @@ function useSelectStyles(props) {
|
|
|
100
112
|
// Prevent text going underneath the chevron icon
|
|
101
113
|
paddingRight: theme.sizing.xxsmall +
|
|
102
114
|
// size of chevron icon
|
|
103
|
-
theme.spacing.medium * 2
|
|
115
|
+
theme.spacing.medium * 2
|
|
116
|
+
}, isPlaceholderActive && !disabled && {
|
|
117
|
+
color: theme.color.foreground.placeholder
|
|
104
118
|
})];
|
|
105
119
|
}
|
|
106
120
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spark-web/select",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"homepage": "https://github.com/brighte-labs/spark-web#readme",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,25 +11,26 @@
|
|
|
11
11
|
"module": "dist/spark-web-select.esm.js",
|
|
12
12
|
"files": [
|
|
13
13
|
"CHANGELOG.md",
|
|
14
|
+
"CLAUDE.md",
|
|
14
15
|
"dist",
|
|
15
16
|
"README.md"
|
|
16
17
|
],
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"@babel/runtime": "^7.25.0",
|
|
19
20
|
"@emotion/react": "^11.14.0",
|
|
20
|
-
"@spark-web/box": "^6.0.
|
|
21
|
+
"@spark-web/box": "^6.0.1",
|
|
21
22
|
"@spark-web/icon": "^5.1.0",
|
|
22
|
-
"@spark-web/text-input": "^6.0.
|
|
23
|
+
"@spark-web/text-input": "^6.0.2",
|
|
23
24
|
"@spark-web/theme": "^5.13.0"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
|
-
"@spark-web/field": "^5.3.
|
|
27
|
+
"@spark-web/field": "^5.3.2",
|
|
27
28
|
"@spark-web/utils": "^5.1.0",
|
|
28
29
|
"@types/react": "^19.1.0",
|
|
29
30
|
"react": "^19.1.0"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|
|
32
|
-
"@spark-web/field": "^5.3.
|
|
33
|
+
"@spark-web/field": "^5.3.2",
|
|
33
34
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
34
35
|
},
|
|
35
36
|
"engines": {
|