@sproutsocial/seeds-react-select 1.1.41 → 1.1.43

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.
@@ -1,5 +1,5 @@
1
1
  yarn run v1.22.22
2
- $ tsup --dts
2
+ $ tsup --dts && cp src/select.css dist/select.css
3
3
  CLI Building entry: src/index.ts
4
4
  CLI Using tsconfig: tsconfig.json
5
5
  CLI tsup v8.5.0
@@ -8,14 +8,14 @@ $ tsup --dts
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- CJS dist/index.js 6.78 KB
12
- CJS dist/index.js.map 9.86 KB
13
- CJS ⚡️ Build success in 88ms
14
- ESM dist/esm/index.js 4.79 KB
15
- ESM dist/esm/index.js.map 9.78 KB
16
- ESM ⚡️ Build success in 87ms
11
+ CJS dist/index.js 9.83 KB
12
+ CJS dist/index.js.map 15.23 KB
13
+ CJS ⚡️ Build success in 17ms
14
+ ESM dist/esm/index.js 7.56 KB
15
+ ESM dist/esm/index.js.map 15.10 KB
16
+ ESM ⚡️ Build success in 17ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 5916ms
19
- DTS dist/index.d.ts 1.72 KB
20
- DTS dist/index.d.mts 1.72 KB
21
- Done in 7.79s.
18
+ DTS ⚡️ Build success in 4293ms
19
+ DTS dist/index.d.ts 1.80 KB
20
+ DTS dist/index.d.mts 1.80 KB
21
+ Done in 5.99s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @sproutsocial/seeds-react-select
2
2
 
3
+ ## 1.1.43
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [85f9728]
8
+ - Updated dependencies [fa7d859]
9
+ - @sproutsocial/seeds-react-theme@4.2.0
10
+ - @sproutsocial/seeds-react-icon@2.4.2
11
+ - @sproutsocial/seeds-react-mixins@4.3.9
12
+
13
+ ## 1.1.42
14
+
15
+ ### Patch Changes
16
+
17
+ - 0e113bc: Migrate progress, token, select, spot-illustration, and collapsible to the Button hybrid Tailwind pattern. Each component now ships a CSS-class implementation routed alongside the styled-components path. Component CSS is wrapped in `@layer components` so Tailwind utility classes win the cascade and can override component styles via `className`. `Collapsible.Panel` now forwards `className` onto the panel root so utility overrides reach the styled element.
18
+
3
19
  ## 1.1.41
4
20
 
5
21
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // src/Select.tsx
2
2
  import "react";
3
- import Icon from "@sproutsocial/seeds-react-icon";
3
+
4
+ // src/SelectHybrid.tsx
5
+ import "react";
6
+ import Icon2 from "@sproutsocial/seeds-react-icon";
7
+ import { hasStyledProps } from "@sproutsocial/seeds-react-system-props";
4
8
 
5
9
  // src/styles.ts
6
10
  import styled, { css } from "styled-components";
@@ -116,9 +120,27 @@ Container.displayName = "SelectContainer";
116
120
  Arrow.displayName = "Select Arrow";
117
121
  var styles_default = Container;
118
122
 
119
- // src/Select.tsx
123
+ // src/SelectTailwind.tsx
124
+ import "react";
125
+ import Icon from "@sproutsocial/seeds-react-icon";
120
126
  import { jsx, jsxs } from "react/jsx-runtime";
121
- var Select = ({
127
+ function cn(...inputs) {
128
+ const classes = [];
129
+ for (const input of inputs) {
130
+ if (!input) continue;
131
+ if (typeof input === "string") {
132
+ classes.push(input);
133
+ } else if (typeof input === "object") {
134
+ for (const [key, value] of Object.entries(input)) {
135
+ if (value) {
136
+ classes.push(key);
137
+ }
138
+ }
139
+ }
140
+ }
141
+ return classes.join(" ");
142
+ }
143
+ var SelectTailwind = ({
122
144
  id,
123
145
  name,
124
146
  children,
@@ -134,6 +156,7 @@ var Select = ({
134
156
  size = "default",
135
157
  qa = {},
136
158
  inputProps = {},
159
+ className,
137
160
  ...rest
138
161
  }) => {
139
162
  const handleChange = (e) => {
@@ -141,41 +164,128 @@ var Select = ({
141
164
  onChange(e);
142
165
  }
143
166
  };
144
- return /* @__PURE__ */ jsxs(styles_default, { invalid: isInvalid, disabled, size, ...rest, children: [
145
- /* @__PURE__ */ jsx(
146
- "select",
147
- {
148
- id,
149
- name,
150
- "aria-label": ariaLabel,
151
- "aria-describedby": ariaDescribedby,
152
- defaultValue,
153
- value,
154
- required,
155
- autoFocus,
156
- disabled,
157
- onChange: handleChange,
158
- "data-qa-select": name || "",
159
- "data-qa-select-value": value || "unselected",
160
- "data-qa-select-isrequired": required === true,
161
- "data-qa-select-isdisabled": disabled === true,
162
- ...qa,
163
- ...inputProps,
164
- children
165
- }
166
- ),
167
- /* @__PURE__ */ jsx(Arrow, { size, children: /* @__PURE__ */ jsx(
168
- Icon,
169
- {
170
- name: "chevron-down-outline",
171
- fixedWidth: true,
172
- size: size === "large" ? "medium" : "small",
173
- "aria-hidden": true
174
- }
175
- ) })
176
- ] });
167
+ return /* @__PURE__ */ jsxs(
168
+ "div",
169
+ {
170
+ className: cn(
171
+ "seeds-select",
172
+ `seeds-select-${size}`,
173
+ {
174
+ "seeds-select-invalid": !!isInvalid,
175
+ "seeds-select-disabled": !!disabled
176
+ },
177
+ className
178
+ ),
179
+ ...rest,
180
+ children: [
181
+ /* @__PURE__ */ jsx(
182
+ "select",
183
+ {
184
+ className: "seeds-select-input",
185
+ id,
186
+ name,
187
+ "aria-label": ariaLabel,
188
+ "aria-describedby": ariaDescribedby,
189
+ defaultValue,
190
+ value,
191
+ required,
192
+ autoFocus,
193
+ disabled,
194
+ onChange: handleChange,
195
+ "data-qa-select": name || "",
196
+ "data-qa-select-value": value || "unselected",
197
+ "data-qa-select-isrequired": required === true,
198
+ "data-qa-select-isdisabled": disabled === true,
199
+ ...qa,
200
+ ...inputProps,
201
+ children
202
+ }
203
+ ),
204
+ /* @__PURE__ */ jsx("span", { className: cn("seeds-select-arrow", `seeds-select-arrow-${size}`), children: /* @__PURE__ */ jsx(
205
+ Icon,
206
+ {
207
+ name: "chevron-down-outline",
208
+ fixedWidth: true,
209
+ size: size === "large" ? "medium" : "small",
210
+ "aria-hidden": true
211
+ }
212
+ ) })
213
+ ]
214
+ }
215
+ );
177
216
  };
178
- var Select_default = Select;
217
+ SelectTailwind.displayName = "SelectTailwind";
218
+
219
+ // src/SelectHybrid.tsx
220
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
221
+ var Select = (props) => {
222
+ const {
223
+ id,
224
+ name,
225
+ children,
226
+ defaultValue,
227
+ value,
228
+ required,
229
+ isInvalid,
230
+ onChange,
231
+ autoFocus,
232
+ disabled,
233
+ ariaLabel,
234
+ ariaDescribedby,
235
+ size = "default",
236
+ qa = {},
237
+ inputProps = {},
238
+ ...rest
239
+ } = props;
240
+ const handleChange = (e) => {
241
+ if (onChange) {
242
+ onChange(e);
243
+ }
244
+ };
245
+ if (hasStyledProps(rest)) {
246
+ return /* @__PURE__ */ jsxs2(styles_default, { invalid: isInvalid, disabled, size, ...rest, children: [
247
+ /* @__PURE__ */ jsx2(
248
+ "select",
249
+ {
250
+ id,
251
+ name,
252
+ "aria-label": ariaLabel,
253
+ "aria-describedby": ariaDescribedby,
254
+ defaultValue,
255
+ value,
256
+ required,
257
+ autoFocus,
258
+ disabled,
259
+ onChange: handleChange,
260
+ "data-qa-select": name || "",
261
+ "data-qa-select-value": value || "unselected",
262
+ "data-qa-select-isrequired": required === true,
263
+ "data-qa-select-isdisabled": disabled === true,
264
+ ...qa,
265
+ ...inputProps,
266
+ children
267
+ }
268
+ ),
269
+ /* @__PURE__ */ jsx2(Arrow, { size, children: /* @__PURE__ */ jsx2(
270
+ Icon2,
271
+ {
272
+ name: "chevron-down-outline",
273
+ fixedWidth: true,
274
+ size: size === "large" ? "medium" : "small",
275
+ "aria-hidden": true
276
+ }
277
+ ) })
278
+ ] });
279
+ }
280
+ return /* @__PURE__ */ jsx2(SelectTailwind, { ...props });
281
+ };
282
+ var SelectHybrid_default = Select;
283
+
284
+ // src/Select.tsx
285
+ import { jsx as jsx3 } from "react/jsx-runtime";
286
+ var Select2 = (props) => /* @__PURE__ */ jsx3(SelectHybrid_default, { ...props });
287
+ Select2.displayName = "Select";
288
+ var Select_default = Select2;
179
289
 
180
290
  // src/SelectTypes.ts
181
291
  import "react";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Select.tsx","../../src/styles.ts","../../src/SelectTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport Container, { Arrow } from \"./styles\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\nconst Select = ({\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n ...rest\n}: TypeSelectProps) => {\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>\n <select\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <Arrow size={size}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </Arrow>\n </Container>\n );\n};\n\nexport default Select;\n","import styled, { css } from \"styled-components\";\nimport { focusRing } from \"@sproutsocial/seeds-react-mixins\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\ninterface TypeSelectContainer extends Omit<TypeSelectProps, \"isInvalid\"> {\n invalid?: boolean;\n}\n\nconst Container = styled.div<TypeSelectContainer>`\n position: relative;\n box-sizing: border-box;\n\n select {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid ${(props) => props.theme.colors.form.border.base};\n border-radius: ${(props) => props.theme.radii[500]};\n background-color: ${(props) => props.theme.colors.form.background.base};\n color: ${(props) => props.theme.colors.text.body};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n outline: none;\n appearance: none;\n transition: border-color ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in},\n box-shadow ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in};\n font-family: ${(props) => props.theme.fontFamily};\n font-weight: ${(props) => props.theme.fontWeights.normal};\n margin: 0;\n /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */\n visibility: visible;\n\n padding: ${(props) => {\n switch (props.size) {\n case \"large\":\n return `${props.theme.space[350]} ${props.theme.space[600]} ${props.theme.space[350]} ${props.theme.space[400]}`;\n\n case \"small\":\n return `${props.theme.space[200]} ${props.theme.space[500]} ${props.theme.space[200]} ${props.theme.space[200]}`;\n\n case \"default\":\n default:\n return `${props.theme.space[300]} ${props.theme.space[500]} ${props.theme.space[300]} ${props.theme.space[300]}`;\n }\n }};\n font-size: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].fontSize;\n\n case \"small\":\n case \"default\":\n default:\n return props.theme.typography[200].fontSize;\n }\n }};\n\n line-height: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].lineHeight;\n\n /* hardcoded to 'normal' so the large change doesn't impact small/default */\n case \"small\":\n case \"default\":\n default:\n return \"normal\";\n }\n }};\n\n /* kill the dropdown arrow on IE 11 */\n &::-ms-expand {\n display: none;\n }\n\n &:focus {\n ${focusRing}\n }\n\n /* Fix for red ring when input is marked required in Firefox */\n &:not(output):not(:focus):-moz-ui-invalid {\n box-shadow: none;\n }\n }\n\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n `}\n\n ${(props) =>\n props.invalid &&\n css`\n select {\n border-color: ${(props) => props.theme.colors.form.border.error};\n }\n\n ${Arrow} {\n color: ${(props) => props.theme.colors.icon.error};\n }\n `}\n\n ${COMMON}\n`;\n\nexport const Arrow = styled.span<Pick<TypeSelectProps, \"size\">>`\n position: absolute;\n top: 50%;\n right: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.space[350];\n case \"small\":\n case \"default\":\n default:\n return props.theme.space[300];\n }\n }};\n transform: translateY(-50%);\n color: ${(props) => props.theme.colors.icon.base};\n pointer-events: none;\n`;\n\nContainer.displayName = \"SelectContainer\";\nArrow.displayName = \"Select Arrow\";\n\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeSelectProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\" | \"onChange\"> {\n /** ID of the form element, should match the \"for\" value of the associated label */\n id: string;\n name: string;\n\n /** Label used to describe the select if not used with an accompanying visual label */\n ariaLabel?: string;\n\n /** Attribute used to associate other elements that describe the Select, like an error */\n ariaDescribedby?: string;\n children: React.ReactNode;\n defaultValue?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n\n /** Current value of the input */\n value?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n required?: boolean;\n isInvalid?: boolean;\n autoFocus?: boolean;\n disabled?: boolean;\n\n /** Props to spread onto the underlying input element */\n inputProps?: React.ComponentPropsWithRef<\"select\">;\n qa?: object;\n onChange?: (e: React.SyntheticEvent<HTMLSelectElement>) => void;\n size?: \"large\" | \"small\" | \"default\";\n}\n","import Select from \"./Select\";\n\nexport default Select;\nexport { Select };\nexport * from \"./SelectTypes\";\nexport * from \"./styles\";\n"],"mappings":"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","names":["props"]}
1
+ {"version":3,"sources":["../../src/Select.tsx","../../src/SelectHybrid.tsx","../../src/styles.ts","../../src/SelectTailwind.tsx","../../src/SelectTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport SelectHybrid from \"./SelectHybrid\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\n/**\n * Select component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or styled() extension).\n */\nconst Select = (props: TypeSelectProps) => <SelectHybrid {...props} />;\n\nSelect.displayName = \"Select\";\n\nexport default Select;\n","/**\n * Hybrid Select Component\n * Automatically chooses between Tailwind and styled-components based on props.\n * Consumers passing styled-system props (e.g. `mb`, `width`, `bg`) get the\n * styled-components implementation; everyone else gets the Tailwind path.\n */\n\nimport * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\nimport Container, { Arrow } from \"./styles\";\nimport { SelectTailwind } from \"./SelectTailwind\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\nconst Select = (props: TypeSelectProps) => {\n const {\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n ...rest\n } = props;\n\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n if (hasStyledProps(rest)) {\n return (\n <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>\n <select\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <Arrow size={size}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </Arrow>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <SelectTailwind {...props} />;\n};\n\nexport default Select;\n","import styled, { css } from \"styled-components\";\nimport { focusRing } from \"@sproutsocial/seeds-react-mixins\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\ninterface TypeSelectContainer extends Omit<TypeSelectProps, \"isInvalid\"> {\n invalid?: boolean;\n}\n\nconst Container = styled.div<TypeSelectContainer>`\n position: relative;\n box-sizing: border-box;\n\n select {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid ${(props) => props.theme.colors.form.border.base};\n border-radius: ${(props) => props.theme.radii[500]};\n background-color: ${(props) => props.theme.colors.form.background.base};\n color: ${(props) => props.theme.colors.text.body};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n outline: none;\n appearance: none;\n transition: border-color ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in},\n box-shadow ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in};\n font-family: ${(props) => props.theme.fontFamily};\n font-weight: ${(props) => props.theme.fontWeights.normal};\n margin: 0;\n /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */\n visibility: visible;\n\n padding: ${(props) => {\n switch (props.size) {\n case \"large\":\n return `${props.theme.space[350]} ${props.theme.space[600]} ${props.theme.space[350]} ${props.theme.space[400]}`;\n\n case \"small\":\n return `${props.theme.space[200]} ${props.theme.space[500]} ${props.theme.space[200]} ${props.theme.space[200]}`;\n\n case \"default\":\n default:\n return `${props.theme.space[300]} ${props.theme.space[500]} ${props.theme.space[300]} ${props.theme.space[300]}`;\n }\n }};\n font-size: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].fontSize;\n\n case \"small\":\n case \"default\":\n default:\n return props.theme.typography[200].fontSize;\n }\n }};\n\n line-height: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].lineHeight;\n\n /* hardcoded to 'normal' so the large change doesn't impact small/default */\n case \"small\":\n case \"default\":\n default:\n return \"normal\";\n }\n }};\n\n /* kill the dropdown arrow on IE 11 */\n &::-ms-expand {\n display: none;\n }\n\n &:focus {\n ${focusRing}\n }\n\n /* Fix for red ring when input is marked required in Firefox */\n &:not(output):not(:focus):-moz-ui-invalid {\n box-shadow: none;\n }\n }\n\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n `}\n\n ${(props) =>\n props.invalid &&\n css`\n select {\n border-color: ${(props) => props.theme.colors.form.border.error};\n }\n\n ${Arrow} {\n color: ${(props) => props.theme.colors.icon.error};\n }\n `}\n\n ${COMMON}\n`;\n\nexport const Arrow = styled.span<Pick<TypeSelectProps, \"size\">>`\n position: absolute;\n top: 50%;\n right: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.space[350];\n case \"small\":\n case \"default\":\n default:\n return props.theme.space[300];\n }\n }};\n transform: translateY(-50%);\n color: ${(props) => props.theme.colors.icon.base};\n pointer-events: none;\n`;\n\nContainer.displayName = \"SelectContainer\";\nArrow.displayName = \"Select Arrow\";\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Select component\n * Uses Seeds select CSS classes from select.css\n */\n\nimport * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const SelectTailwind = ({\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n className,\n ...rest\n}: TypeSelectProps) => {\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <div\n className={cn(\n \"seeds-select\",\n `seeds-select-${size}`,\n {\n \"seeds-select-invalid\": !!isInvalid,\n \"seeds-select-disabled\": !!disabled,\n },\n className\n )}\n {...(rest as any)}\n >\n <select\n className=\"seeds-select-input\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <span className={cn(\"seeds-select-arrow\", `seeds-select-arrow-${size}`)}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </span>\n </div>\n );\n};\n\nSelectTailwind.displayName = \"SelectTailwind\";\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeSelectProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\" | \"onChange\"> {\n /** ID of the form element, should match the \"for\" value of the associated label */\n id: string;\n name: string;\n\n /** Label used to describe the select if not used with an accompanying visual label */\n ariaLabel?: string;\n\n /** Attribute used to associate other elements that describe the Select, like an error */\n ariaDescribedby?: string;\n children: React.ReactNode;\n defaultValue?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n\n /** Current value of the input */\n value?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n required?: boolean;\n isInvalid?: boolean;\n autoFocus?: boolean;\n disabled?: boolean;\n\n /** Props to spread onto the underlying input element */\n inputProps?: React.ComponentPropsWithRef<\"select\">;\n qa?: object;\n onChange?: (e: React.SyntheticEvent<HTMLSelectElement>) => void;\n size?: \"large\" | \"small\" | \"default\";\n}\n","import Select from \"./Select\";\n\nexport default Select;\nexport { Select };\nexport * from \"./SelectTypes\";\nexport * from \"./styles\";\n"],"mappings":"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","names":["Icon","props","jsx","jsxs","Icon","jsx","Select"]}
package/dist/index.d.mts CHANGED
@@ -26,7 +26,15 @@ interface TypeSelectProps extends TypeStyledComponentsCommonProps, TypeSystemCom
26
26
  size?: "large" | "small" | "default";
27
27
  }
28
28
 
29
- declare const Select: ({ id, name, children, defaultValue, value, required, isInvalid, onChange, autoFocus, disabled, ariaLabel, ariaDescribedby, size, qa, inputProps, ...rest }: TypeSelectProps) => react_jsx_runtime.JSX.Element;
29
+ /**
30
+ * Select component. Automatically routes between the Tailwind implementation
31
+ * (preferred) and the styled-components implementation (for consumers using
32
+ * system props or styled() extension).
33
+ */
34
+ declare const Select: {
35
+ (props: TypeSelectProps): react_jsx_runtime.JSX.Element;
36
+ displayName: string;
37
+ };
30
38
 
31
39
  declare const Arrow: styled_components.StyledComponent<"span", styled_components.DefaultTheme, Pick<TypeSelectProps, "size">, never>;
32
40
 
package/dist/index.d.ts CHANGED
@@ -26,7 +26,15 @@ interface TypeSelectProps extends TypeStyledComponentsCommonProps, TypeSystemCom
26
26
  size?: "large" | "small" | "default";
27
27
  }
28
28
 
29
- declare const Select: ({ id, name, children, defaultValue, value, required, isInvalid, onChange, autoFocus, disabled, ariaLabel, ariaDescribedby, size, qa, inputProps, ...rest }: TypeSelectProps) => react_jsx_runtime.JSX.Element;
29
+ /**
30
+ * Select component. Automatically routes between the Tailwind implementation
31
+ * (preferred) and the styled-components implementation (for consumers using
32
+ * system props or styled() extension).
33
+ */
34
+ declare const Select: {
35
+ (props: TypeSelectProps): react_jsx_runtime.JSX.Element;
36
+ displayName: string;
37
+ };
30
38
 
31
39
  declare const Arrow: styled_components.StyledComponent<"span", styled_components.DefaultTheme, Pick<TypeSelectProps, "size">, never>;
32
40
 
package/dist/index.js CHANGED
@@ -37,8 +37,12 @@ __export(index_exports, {
37
37
  module.exports = __toCommonJS(index_exports);
38
38
 
39
39
  // src/Select.tsx
40
- var React = require("react");
41
- var import_seeds_react_icon = __toESM(require("@sproutsocial/seeds-react-icon"));
40
+ var React3 = require("react");
41
+
42
+ // src/SelectHybrid.tsx
43
+ var React2 = require("react");
44
+ var import_seeds_react_icon2 = __toESM(require("@sproutsocial/seeds-react-icon"));
45
+ var import_seeds_react_system_props2 = require("@sproutsocial/seeds-react-system-props");
42
46
 
43
47
  // src/styles.ts
44
48
  var import_styled_components = __toESM(require("styled-components"));
@@ -154,9 +158,27 @@ Container.displayName = "SelectContainer";
154
158
  Arrow.displayName = "Select Arrow";
155
159
  var styles_default = Container;
156
160
 
157
- // src/Select.tsx
161
+ // src/SelectTailwind.tsx
162
+ var React = require("react");
163
+ var import_seeds_react_icon = __toESM(require("@sproutsocial/seeds-react-icon"));
158
164
  var import_jsx_runtime = require("react/jsx-runtime");
159
- var Select = ({
165
+ function cn(...inputs) {
166
+ const classes = [];
167
+ for (const input of inputs) {
168
+ if (!input) continue;
169
+ if (typeof input === "string") {
170
+ classes.push(input);
171
+ } else if (typeof input === "object") {
172
+ for (const [key, value] of Object.entries(input)) {
173
+ if (value) {
174
+ classes.push(key);
175
+ }
176
+ }
177
+ }
178
+ }
179
+ return classes.join(" ");
180
+ }
181
+ var SelectTailwind = ({
160
182
  id,
161
183
  name,
162
184
  children,
@@ -172,6 +194,7 @@ var Select = ({
172
194
  size = "default",
173
195
  qa = {},
174
196
  inputProps = {},
197
+ className,
175
198
  ...rest
176
199
  }) => {
177
200
  const handleChange = (e) => {
@@ -179,44 +202,131 @@ var Select = ({
179
202
  onChange(e);
180
203
  }
181
204
  };
182
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(styles_default, { invalid: isInvalid, disabled, size, ...rest, children: [
183
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
184
- "select",
185
- {
186
- id,
187
- name,
188
- "aria-label": ariaLabel,
189
- "aria-describedby": ariaDescribedby,
190
- defaultValue,
191
- value,
192
- required,
193
- autoFocus,
194
- disabled,
195
- onChange: handleChange,
196
- "data-qa-select": name || "",
197
- "data-qa-select-value": value || "unselected",
198
- "data-qa-select-isrequired": required === true,
199
- "data-qa-select-isdisabled": disabled === true,
200
- ...qa,
201
- ...inputProps,
202
- children
203
- }
204
- ),
205
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Arrow, { size, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
206
- import_seeds_react_icon.default,
207
- {
208
- name: "chevron-down-outline",
209
- fixedWidth: true,
210
- size: size === "large" ? "medium" : "small",
211
- "aria-hidden": true
212
- }
213
- ) })
214
- ] });
205
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
206
+ "div",
207
+ {
208
+ className: cn(
209
+ "seeds-select",
210
+ `seeds-select-${size}`,
211
+ {
212
+ "seeds-select-invalid": !!isInvalid,
213
+ "seeds-select-disabled": !!disabled
214
+ },
215
+ className
216
+ ),
217
+ ...rest,
218
+ children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
220
+ "select",
221
+ {
222
+ className: "seeds-select-input",
223
+ id,
224
+ name,
225
+ "aria-label": ariaLabel,
226
+ "aria-describedby": ariaDescribedby,
227
+ defaultValue,
228
+ value,
229
+ required,
230
+ autoFocus,
231
+ disabled,
232
+ onChange: handleChange,
233
+ "data-qa-select": name || "",
234
+ "data-qa-select-value": value || "unselected",
235
+ "data-qa-select-isrequired": required === true,
236
+ "data-qa-select-isdisabled": disabled === true,
237
+ ...qa,
238
+ ...inputProps,
239
+ children
240
+ }
241
+ ),
242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn("seeds-select-arrow", `seeds-select-arrow-${size}`), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
243
+ import_seeds_react_icon.default,
244
+ {
245
+ name: "chevron-down-outline",
246
+ fixedWidth: true,
247
+ size: size === "large" ? "medium" : "small",
248
+ "aria-hidden": true
249
+ }
250
+ ) })
251
+ ]
252
+ }
253
+ );
254
+ };
255
+ SelectTailwind.displayName = "SelectTailwind";
256
+
257
+ // src/SelectHybrid.tsx
258
+ var import_jsx_runtime2 = require("react/jsx-runtime");
259
+ var Select = (props) => {
260
+ const {
261
+ id,
262
+ name,
263
+ children,
264
+ defaultValue,
265
+ value,
266
+ required,
267
+ isInvalid,
268
+ onChange,
269
+ autoFocus,
270
+ disabled,
271
+ ariaLabel,
272
+ ariaDescribedby,
273
+ size = "default",
274
+ qa = {},
275
+ inputProps = {},
276
+ ...rest
277
+ } = props;
278
+ const handleChange = (e) => {
279
+ if (onChange) {
280
+ onChange(e);
281
+ }
282
+ };
283
+ if ((0, import_seeds_react_system_props2.hasStyledProps)(rest)) {
284
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(styles_default, { invalid: isInvalid, disabled, size, ...rest, children: [
285
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
286
+ "select",
287
+ {
288
+ id,
289
+ name,
290
+ "aria-label": ariaLabel,
291
+ "aria-describedby": ariaDescribedby,
292
+ defaultValue,
293
+ value,
294
+ required,
295
+ autoFocus,
296
+ disabled,
297
+ onChange: handleChange,
298
+ "data-qa-select": name || "",
299
+ "data-qa-select-value": value || "unselected",
300
+ "data-qa-select-isrequired": required === true,
301
+ "data-qa-select-isdisabled": disabled === true,
302
+ ...qa,
303
+ ...inputProps,
304
+ children
305
+ }
306
+ ),
307
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Arrow, { size, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
308
+ import_seeds_react_icon2.default,
309
+ {
310
+ name: "chevron-down-outline",
311
+ fixedWidth: true,
312
+ size: size === "large" ? "medium" : "small",
313
+ "aria-hidden": true
314
+ }
315
+ ) })
316
+ ] });
317
+ }
318
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SelectTailwind, { ...props });
215
319
  };
216
- var Select_default = Select;
320
+ var SelectHybrid_default = Select;
321
+
322
+ // src/Select.tsx
323
+ var import_jsx_runtime3 = require("react/jsx-runtime");
324
+ var Select2 = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectHybrid_default, { ...props });
325
+ Select2.displayName = "Select";
326
+ var Select_default = Select2;
217
327
 
218
328
  // src/SelectTypes.ts
219
- var React2 = require("react");
329
+ var React4 = require("react");
220
330
 
221
331
  // src/index.ts
222
332
  var index_default = Select_default;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Select.tsx","../src/styles.ts","../src/SelectTypes.ts"],"sourcesContent":["import Select from \"./Select\";\n\nexport default Select;\nexport { Select };\nexport * from \"./SelectTypes\";\nexport * from \"./styles\";\n","import * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport Container, { Arrow } from \"./styles\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\nconst Select = ({\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n ...rest\n}: TypeSelectProps) => {\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>\n <select\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <Arrow size={size}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </Arrow>\n </Container>\n );\n};\n\nexport default Select;\n","import styled, { css } from \"styled-components\";\nimport { focusRing } from \"@sproutsocial/seeds-react-mixins\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\ninterface TypeSelectContainer extends Omit<TypeSelectProps, \"isInvalid\"> {\n invalid?: boolean;\n}\n\nconst Container = styled.div<TypeSelectContainer>`\n position: relative;\n box-sizing: border-box;\n\n select {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid ${(props) => props.theme.colors.form.border.base};\n border-radius: ${(props) => props.theme.radii[500]};\n background-color: ${(props) => props.theme.colors.form.background.base};\n color: ${(props) => props.theme.colors.text.body};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n outline: none;\n appearance: none;\n transition: border-color ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in},\n box-shadow ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in};\n font-family: ${(props) => props.theme.fontFamily};\n font-weight: ${(props) => props.theme.fontWeights.normal};\n margin: 0;\n /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */\n visibility: visible;\n\n padding: ${(props) => {\n switch (props.size) {\n case \"large\":\n return `${props.theme.space[350]} ${props.theme.space[600]} ${props.theme.space[350]} ${props.theme.space[400]}`;\n\n case \"small\":\n return `${props.theme.space[200]} ${props.theme.space[500]} ${props.theme.space[200]} ${props.theme.space[200]}`;\n\n case \"default\":\n default:\n return `${props.theme.space[300]} ${props.theme.space[500]} ${props.theme.space[300]} ${props.theme.space[300]}`;\n }\n }};\n font-size: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].fontSize;\n\n case \"small\":\n case \"default\":\n default:\n return props.theme.typography[200].fontSize;\n }\n }};\n\n line-height: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].lineHeight;\n\n /* hardcoded to 'normal' so the large change doesn't impact small/default */\n case \"small\":\n case \"default\":\n default:\n return \"normal\";\n }\n }};\n\n /* kill the dropdown arrow on IE 11 */\n &::-ms-expand {\n display: none;\n }\n\n &:focus {\n ${focusRing}\n }\n\n /* Fix for red ring when input is marked required in Firefox */\n &:not(output):not(:focus):-moz-ui-invalid {\n box-shadow: none;\n }\n }\n\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n `}\n\n ${(props) =>\n props.invalid &&\n css`\n select {\n border-color: ${(props) => props.theme.colors.form.border.error};\n }\n\n ${Arrow} {\n color: ${(props) => props.theme.colors.icon.error};\n }\n `}\n\n ${COMMON}\n`;\n\nexport const Arrow = styled.span<Pick<TypeSelectProps, \"size\">>`\n position: absolute;\n top: 50%;\n right: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.space[350];\n case \"small\":\n case \"default\":\n default:\n return props.theme.space[300];\n }\n }};\n transform: translateY(-50%);\n color: ${(props) => props.theme.colors.icon.base};\n pointer-events: none;\n`;\n\nContainer.displayName = \"SelectContainer\";\nArrow.displayName = \"Select Arrow\";\n\nexport default Container;\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeSelectProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\" | \"onChange\"> {\n /** ID of the form element, should match the \"for\" value of the associated label */\n id: string;\n name: string;\n\n /** Label used to describe the select if not used with an accompanying visual label */\n ariaLabel?: string;\n\n /** Attribute used to associate other elements that describe the Select, like an error */\n ariaDescribedby?: string;\n children: React.ReactNode;\n defaultValue?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n\n /** Current value of the input */\n value?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n required?: boolean;\n isInvalid?: boolean;\n autoFocus?: boolean;\n disabled?: boolean;\n\n /** Props to spread onto the underlying input element */\n inputProps?: React.ComponentPropsWithRef<\"select\">;\n qa?: object;\n onChange?: (e: React.SyntheticEvent<HTMLSelectElement>) => void;\n size?: \"large\" | \"small\" | \"default\";\n}\n"],"mappings":"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","names":["styled","props","Icon","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Select.tsx","../src/SelectHybrid.tsx","../src/styles.ts","../src/SelectTailwind.tsx","../src/SelectTypes.ts"],"sourcesContent":["import Select from \"./Select\";\n\nexport default Select;\nexport { Select };\nexport * from \"./SelectTypes\";\nexport * from \"./styles\";\n","import * as React from \"react\";\nimport SelectHybrid from \"./SelectHybrid\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\n/**\n * Select component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or styled() extension).\n */\nconst Select = (props: TypeSelectProps) => <SelectHybrid {...props} />;\n\nSelect.displayName = \"Select\";\n\nexport default Select;\n","/**\n * Hybrid Select Component\n * Automatically chooses between Tailwind and styled-components based on props.\n * Consumers passing styled-system props (e.g. `mb`, `width`, `bg`) get the\n * styled-components implementation; everyone else gets the Tailwind path.\n */\n\nimport * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\nimport Container, { Arrow } from \"./styles\";\nimport { SelectTailwind } from \"./SelectTailwind\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\nconst Select = (props: TypeSelectProps) => {\n const {\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n ...rest\n } = props;\n\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n if (hasStyledProps(rest)) {\n return (\n <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>\n <select\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <Arrow size={size}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </Arrow>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <SelectTailwind {...props} />;\n};\n\nexport default Select;\n","import styled, { css } from \"styled-components\";\nimport { focusRing } from \"@sproutsocial/seeds-react-mixins\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\ninterface TypeSelectContainer extends Omit<TypeSelectProps, \"isInvalid\"> {\n invalid?: boolean;\n}\n\nconst Container = styled.div<TypeSelectContainer>`\n position: relative;\n box-sizing: border-box;\n\n select {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid ${(props) => props.theme.colors.form.border.base};\n border-radius: ${(props) => props.theme.radii[500]};\n background-color: ${(props) => props.theme.colors.form.background.base};\n color: ${(props) => props.theme.colors.text.body};\n cursor: ${(props) => (props.disabled ? \"not-allowed\" : \"pointer\")};\n outline: none;\n appearance: none;\n transition: border-color ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in},\n box-shadow ${(props) => props.theme.duration.fast}\n ${(props) => props.theme.easing.ease_in};\n font-family: ${(props) => props.theme.fontFamily};\n font-weight: ${(props) => props.theme.fontWeights.normal};\n margin: 0;\n /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */\n visibility: visible;\n\n padding: ${(props) => {\n switch (props.size) {\n case \"large\":\n return `${props.theme.space[350]} ${props.theme.space[600]} ${props.theme.space[350]} ${props.theme.space[400]}`;\n\n case \"small\":\n return `${props.theme.space[200]} ${props.theme.space[500]} ${props.theme.space[200]} ${props.theme.space[200]}`;\n\n case \"default\":\n default:\n return `${props.theme.space[300]} ${props.theme.space[500]} ${props.theme.space[300]} ${props.theme.space[300]}`;\n }\n }};\n font-size: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].fontSize;\n\n case \"small\":\n case \"default\":\n default:\n return props.theme.typography[200].fontSize;\n }\n }};\n\n line-height: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.typography[300].lineHeight;\n\n /* hardcoded to 'normal' so the large change doesn't impact small/default */\n case \"small\":\n case \"default\":\n default:\n return \"normal\";\n }\n }};\n\n /* kill the dropdown arrow on IE 11 */\n &::-ms-expand {\n display: none;\n }\n\n &:focus {\n ${focusRing}\n }\n\n /* Fix for red ring when input is marked required in Firefox */\n &:not(output):not(:focus):-moz-ui-invalid {\n box-shadow: none;\n }\n }\n\n ${(props) =>\n props.disabled &&\n css`\n opacity: 0.4;\n `}\n\n ${(props) =>\n props.invalid &&\n css`\n select {\n border-color: ${(props) => props.theme.colors.form.border.error};\n }\n\n ${Arrow} {\n color: ${(props) => props.theme.colors.icon.error};\n }\n `}\n\n ${COMMON}\n`;\n\nexport const Arrow = styled.span<Pick<TypeSelectProps, \"size\">>`\n position: absolute;\n top: 50%;\n right: ${(props) => {\n switch (props.size) {\n case \"large\":\n return props.theme.space[350];\n case \"small\":\n case \"default\":\n default:\n return props.theme.space[300];\n }\n }};\n transform: translateY(-50%);\n color: ${(props) => props.theme.colors.icon.base};\n pointer-events: none;\n`;\n\nContainer.displayName = \"SelectContainer\";\nArrow.displayName = \"Select Arrow\";\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Select component\n * Uses Seeds select CSS classes from select.css\n */\n\nimport * as React from \"react\";\nimport Icon from \"@sproutsocial/seeds-react-icon\";\nimport type { TypeSelectProps } from \"./SelectTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const SelectTailwind = ({\n id,\n name,\n children,\n defaultValue,\n value,\n required,\n isInvalid,\n onChange,\n autoFocus,\n disabled,\n ariaLabel,\n ariaDescribedby,\n size = \"default\",\n qa = {},\n inputProps = {},\n className,\n ...rest\n}: TypeSelectProps) => {\n const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {\n if (onChange) {\n onChange(e);\n }\n };\n\n return (\n <div\n className={cn(\n \"seeds-select\",\n `seeds-select-${size}`,\n {\n \"seeds-select-invalid\": !!isInvalid,\n \"seeds-select-disabled\": !!disabled,\n },\n className\n )}\n {...(rest as any)}\n >\n <select\n className=\"seeds-select-input\"\n id={id}\n name={name}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedby}\n defaultValue={defaultValue}\n value={value}\n required={required}\n autoFocus={autoFocus}\n disabled={disabled}\n onChange={handleChange}\n data-qa-select={name || \"\"}\n data-qa-select-value={value || \"unselected\"}\n data-qa-select-isrequired={required === true}\n data-qa-select-isdisabled={disabled === true}\n {...qa}\n {...inputProps}\n >\n {children}\n </select>\n\n <span className={cn(\"seeds-select-arrow\", `seeds-select-arrow-${size}`)}>\n <Icon\n name=\"chevron-down-outline\"\n fixedWidth\n size={size === \"large\" ? \"medium\" : \"small\"}\n aria-hidden\n />\n </span>\n </div>\n );\n};\n\nSelectTailwind.displayName = \"SelectTailwind\";\n","import * as React from \"react\";\nimport type {\n TypeSystemCommonProps,\n TypeStyledComponentsCommonProps,\n} from \"@sproutsocial/seeds-react-system-props\";\n\nexport interface TypeSelectProps\n extends TypeStyledComponentsCommonProps,\n TypeSystemCommonProps,\n Omit<React.ComponentPropsWithoutRef<\"div\">, \"color\" | \"onChange\"> {\n /** ID of the form element, should match the \"for\" value of the associated label */\n id: string;\n name: string;\n\n /** Label used to describe the select if not used with an accompanying visual label */\n ariaLabel?: string;\n\n /** Attribute used to associate other elements that describe the Select, like an error */\n ariaDescribedby?: string;\n children: React.ReactNode;\n defaultValue?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n\n /** Current value of the input */\n value?: React.ComponentPropsWithoutRef<\"select\">[\"value\"];\n required?: boolean;\n isInvalid?: boolean;\n autoFocus?: boolean;\n disabled?: boolean;\n\n /** Props to spread onto the underlying input element */\n inputProps?: React.ComponentPropsWithRef<\"select\">;\n qa?: object;\n onChange?: (e: React.SyntheticEvent<HTMLSelectElement>) => void;\n size?: \"large\" | \"small\" | \"default\";\n}\n"],"mappings":"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","names":["React","React","import_seeds_react_icon","import_seeds_react_system_props","styled","props","Icon","import_jsx_runtime","Icon","import_jsx_runtime","Select","React"]}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Seeds Select component classes
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-select seeds-select-default">
10
+ * <select class="seeds-select-input">…</select>
11
+ * <span class="seeds-select-arrow seeds-select-arrow-default">…</span>
12
+ * </div>
13
+ */
14
+
15
+ @layer components {
16
+ .seeds-select {
17
+ position: relative;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ .seeds-select .seeds-select-input {
22
+ box-sizing: border-box;
23
+ width: 100%;
24
+ border: 1px solid var(--color-form-border-base);
25
+ border-radius: var(--radius-500);
26
+ background-color: var(--color-form-bg-base);
27
+ color: var(--color-text-body);
28
+ cursor: pointer;
29
+ outline: none;
30
+ appearance: none;
31
+ transition:
32
+ border-color var(--duration-fast) var(--ease-ease_in),
33
+ box-shadow var(--duration-fast) var(--ease-ease_in);
34
+ font-family: var(--font-family);
35
+ font-weight: var(--font-weight-normal);
36
+ margin: 0;
37
+ /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */
38
+ visibility: visible;
39
+ }
40
+
41
+ /* kill the dropdown arrow on IE 11 */
42
+ .seeds-select .seeds-select-input::-ms-expand {
43
+ display: none;
44
+ }
45
+
46
+ .seeds-select .seeds-select-input:focus {
47
+ box-shadow:
48
+ 0 0 0 1px var(--color-button-primary-bg-base),
49
+ 0 0px 0px 4px
50
+ color-mix(in srgb, var(--color-button-primary-bg-base), transparent 70%);
51
+ outline: none;
52
+ }
53
+
54
+ /* Fix for red ring when input is marked required in Firefox */
55
+ .seeds-select
56
+ .seeds-select-input:not(output):not(:focus):-moz-ui-invalid {
57
+ box-shadow: none;
58
+ }
59
+
60
+ /* size: default */
61
+ .seeds-select-default .seeds-select-input {
62
+ padding: var(--space-300) var(--space-500) var(--space-300) var(--space-300);
63
+ font-size: var(--font-size-200);
64
+ line-height: normal;
65
+ }
66
+
67
+ /* size: large */
68
+ .seeds-select-large .seeds-select-input {
69
+ padding: var(--space-350) var(--space-600) var(--space-350) var(--space-400);
70
+ font-size: var(--font-size-300);
71
+ line-height: var(--line-height-300);
72
+ }
73
+
74
+ /* size: small */
75
+ .seeds-select-small .seeds-select-input {
76
+ padding: var(--space-200) var(--space-500) var(--space-200) var(--space-200);
77
+ font-size: var(--font-size-200);
78
+ line-height: normal;
79
+ }
80
+
81
+ .seeds-select-arrow {
82
+ position: absolute;
83
+ top: 50%;
84
+ transform: translateY(-50%);
85
+ color: var(--color-icon-base);
86
+ pointer-events: none;
87
+ }
88
+
89
+ .seeds-select-arrow-default,
90
+ .seeds-select-arrow-small {
91
+ right: var(--space-300);
92
+ }
93
+
94
+ .seeds-select-arrow-large {
95
+ right: var(--space-350);
96
+ }
97
+
98
+ /* disabled */
99
+ .seeds-select-disabled {
100
+ opacity: 0.4;
101
+ }
102
+
103
+ .seeds-select-disabled .seeds-select-input {
104
+ cursor: not-allowed;
105
+ }
106
+
107
+ /* invalid */
108
+ .seeds-select-invalid .seeds-select-input {
109
+ border-color: var(--color-form-border-error);
110
+ }
111
+
112
+ .seeds-select-invalid .seeds-select-arrow {
113
+ color: var(--color-icon-error);
114
+ }
115
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-select",
3
- "version": "1.1.41",
3
+ "version": "1.1.43",
4
4
  "description": "Seeds React Select",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -8,8 +8,8 @@
8
8
  "module": "dist/esm/index.js",
9
9
  "types": "dist/index.d.ts",
10
10
  "scripts": {
11
- "build": "tsup --dts",
12
- "build:debug": "tsup --dts --metafile",
11
+ "build": "tsup --dts && cp src/select.css dist/select.css",
12
+ "build:debug": "tsup --dts --metafile && cp src/select.css dist/select.css",
13
13
  "dev": "tsup --watch --dts",
14
14
  "clean": "rm -rf .turbo dist",
15
15
  "clean:modules": "rm -rf node_modules",
@@ -18,10 +18,10 @@
18
18
  "test:watch": "jest --watch --coverage=false"
19
19
  },
20
20
  "dependencies": {
21
- "@sproutsocial/seeds-react-theme": "^4.1.1",
21
+ "@sproutsocial/seeds-react-theme": "^4.2.0",
22
22
  "@sproutsocial/seeds-react-system-props": "^3.1.1",
23
- "@sproutsocial/seeds-react-icon": "^2.4.1",
24
- "@sproutsocial/seeds-react-mixins": "^4.3.8"
23
+ "@sproutsocial/seeds-react-icon": "^2.4.2",
24
+ "@sproutsocial/seeds-react-mixins": "^4.3.9"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/react": "^18.0.0",
@@ -0,0 +1,6 @@
1
+ // Empty PostCSS config — prevents tsup from picking up the root postcss.config.js
2
+ // (which runs Tailwind CSS and would fail without a tailwind.config.js in scope).
3
+ // select.css uses plain CSS custom properties and needs no PostCSS processing.
4
+ export default {
5
+ plugins: {},
6
+ };
@@ -51,3 +51,10 @@ export const Large: Story = {
51
51
  size: "large",
52
52
  },
53
53
  };
54
+
55
+ export const TailwindClassOverride: Story = {
56
+ name: "🚀 Tailwind class override",
57
+ args: {
58
+ className: "mx-200 p-300 inline-flex",
59
+ },
60
+ };
package/src/Select.tsx CHANGED
@@ -1,65 +1,14 @@
1
1
  import * as React from "react";
2
- import Icon from "@sproutsocial/seeds-react-icon";
3
- import Container, { Arrow } from "./styles";
2
+ import SelectHybrid from "./SelectHybrid";
4
3
  import type { TypeSelectProps } from "./SelectTypes";
5
4
 
6
- const Select = ({
7
- id,
8
- name,
9
- children,
10
- defaultValue,
11
- value,
12
- required,
13
- isInvalid,
14
- onChange,
15
- autoFocus,
16
- disabled,
17
- ariaLabel,
18
- ariaDescribedby,
19
- size = "default",
20
- qa = {},
21
- inputProps = {},
22
- ...rest
23
- }: TypeSelectProps) => {
24
- const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
25
- if (onChange) {
26
- onChange(e);
27
- }
28
- };
5
+ /**
6
+ * Select component. Automatically routes between the Tailwind implementation
7
+ * (preferred) and the styled-components implementation (for consumers using
8
+ * system props or styled() extension).
9
+ */
10
+ const Select = (props: TypeSelectProps) => <SelectHybrid {...props} />;
29
11
 
30
- return (
31
- <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>
32
- <select
33
- id={id}
34
- name={name}
35
- aria-label={ariaLabel}
36
- aria-describedby={ariaDescribedby}
37
- defaultValue={defaultValue}
38
- value={value}
39
- required={required}
40
- autoFocus={autoFocus}
41
- disabled={disabled}
42
- onChange={handleChange}
43
- data-qa-select={name || ""}
44
- data-qa-select-value={value || "unselected"}
45
- data-qa-select-isrequired={required === true}
46
- data-qa-select-isdisabled={disabled === true}
47
- {...qa}
48
- {...inputProps}
49
- >
50
- {children}
51
- </select>
52
-
53
- <Arrow size={size}>
54
- <Icon
55
- name="chevron-down-outline"
56
- fixedWidth
57
- size={size === "large" ? "medium" : "small"}
58
- aria-hidden
59
- />
60
- </Arrow>
61
- </Container>
62
- );
63
- };
12
+ Select.displayName = "Select";
64
13
 
65
14
  export default Select;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Hybrid Select Component
3
+ * Automatically chooses between Tailwind and styled-components based on props.
4
+ * Consumers passing styled-system props (e.g. `mb`, `width`, `bg`) get the
5
+ * styled-components implementation; everyone else gets the Tailwind path.
6
+ */
7
+
8
+ import * as React from "react";
9
+ import Icon from "@sproutsocial/seeds-react-icon";
10
+ import { hasStyledProps } from "@sproutsocial/seeds-react-system-props";
11
+ import Container, { Arrow } from "./styles";
12
+ import { SelectTailwind } from "./SelectTailwind";
13
+ import type { TypeSelectProps } from "./SelectTypes";
14
+
15
+ const Select = (props: TypeSelectProps) => {
16
+ const {
17
+ id,
18
+ name,
19
+ children,
20
+ defaultValue,
21
+ value,
22
+ required,
23
+ isInvalid,
24
+ onChange,
25
+ autoFocus,
26
+ disabled,
27
+ ariaLabel,
28
+ ariaDescribedby,
29
+ size = "default",
30
+ qa = {},
31
+ inputProps = {},
32
+ ...rest
33
+ } = props;
34
+
35
+ const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
36
+ if (onChange) {
37
+ onChange(e);
38
+ }
39
+ };
40
+
41
+ if (hasStyledProps(rest)) {
42
+ return (
43
+ <Container invalid={isInvalid} disabled={disabled} size={size} {...rest}>
44
+ <select
45
+ id={id}
46
+ name={name}
47
+ aria-label={ariaLabel}
48
+ aria-describedby={ariaDescribedby}
49
+ defaultValue={defaultValue}
50
+ value={value}
51
+ required={required}
52
+ autoFocus={autoFocus}
53
+ disabled={disabled}
54
+ onChange={handleChange}
55
+ data-qa-select={name || ""}
56
+ data-qa-select-value={value || "unselected"}
57
+ data-qa-select-isrequired={required === true}
58
+ data-qa-select-isdisabled={disabled === true}
59
+ {...qa}
60
+ {...inputProps}
61
+ >
62
+ {children}
63
+ </select>
64
+
65
+ <Arrow size={size}>
66
+ <Icon
67
+ name="chevron-down-outline"
68
+ fixedWidth
69
+ size={size === "large" ? "medium" : "small"}
70
+ aria-hidden
71
+ />
72
+ </Arrow>
73
+ </Container>
74
+ );
75
+ }
76
+
77
+ // Use Tailwind version (preferred - better performance)
78
+ return <SelectTailwind {...props} />;
79
+ };
80
+
81
+ export default Select;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Tailwind CSS implementation of Select component
3
+ * Uses Seeds select CSS classes from select.css
4
+ */
5
+
6
+ import * as React from "react";
7
+ import Icon from "@sproutsocial/seeds-react-icon";
8
+ import type { TypeSelectProps } from "./SelectTypes";
9
+
10
+ // Utility for merging class names properly
11
+ function cn(
12
+ ...inputs: (string | undefined | null | false | Record<string, boolean>)[]
13
+ ): string {
14
+ const classes: string[] = [];
15
+
16
+ for (const input of inputs) {
17
+ if (!input) continue;
18
+
19
+ if (typeof input === "string") {
20
+ classes.push(input);
21
+ } else if (typeof input === "object") {
22
+ for (const [key, value] of Object.entries(input)) {
23
+ if (value) {
24
+ classes.push(key);
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ return classes.join(" ");
31
+ }
32
+
33
+ export const SelectTailwind = ({
34
+ id,
35
+ name,
36
+ children,
37
+ defaultValue,
38
+ value,
39
+ required,
40
+ isInvalid,
41
+ onChange,
42
+ autoFocus,
43
+ disabled,
44
+ ariaLabel,
45
+ ariaDescribedby,
46
+ size = "default",
47
+ qa = {},
48
+ inputProps = {},
49
+ className,
50
+ ...rest
51
+ }: TypeSelectProps) => {
52
+ const handleChange = (e: React.SyntheticEvent<HTMLSelectElement>) => {
53
+ if (onChange) {
54
+ onChange(e);
55
+ }
56
+ };
57
+
58
+ return (
59
+ <div
60
+ className={cn(
61
+ "seeds-select",
62
+ `seeds-select-${size}`,
63
+ {
64
+ "seeds-select-invalid": !!isInvalid,
65
+ "seeds-select-disabled": !!disabled,
66
+ },
67
+ className
68
+ )}
69
+ {...(rest as any)}
70
+ >
71
+ <select
72
+ className="seeds-select-input"
73
+ id={id}
74
+ name={name}
75
+ aria-label={ariaLabel}
76
+ aria-describedby={ariaDescribedby}
77
+ defaultValue={defaultValue}
78
+ value={value}
79
+ required={required}
80
+ autoFocus={autoFocus}
81
+ disabled={disabled}
82
+ onChange={handleChange}
83
+ data-qa-select={name || ""}
84
+ data-qa-select-value={value || "unselected"}
85
+ data-qa-select-isrequired={required === true}
86
+ data-qa-select-isdisabled={disabled === true}
87
+ {...qa}
88
+ {...inputProps}
89
+ >
90
+ {children}
91
+ </select>
92
+
93
+ <span className={cn("seeds-select-arrow", `seeds-select-arrow-${size}`)}>
94
+ <Icon
95
+ name="chevron-down-outline"
96
+ fixedWidth
97
+ size={size === "large" ? "medium" : "small"}
98
+ aria-hidden
99
+ />
100
+ </span>
101
+ </div>
102
+ );
103
+ };
104
+
105
+ SelectTailwind.displayName = "SelectTailwind";
@@ -43,6 +43,25 @@ describe("Select", () => {
43
43
  })
44
44
  ).toBeTruthy();
45
45
  });
46
+ it("should render the Tailwind (CSS-class) implementation by default", () => {
47
+ const { container } = render(
48
+ <Select id="select" name="select">
49
+ <option value="v">option1</option>
50
+ </Select>
51
+ );
52
+ expect(container.querySelector(".seeds-select")).toBeInTheDocument();
53
+ expect(
54
+ container.querySelector(".seeds-select .seeds-select-input")
55
+ ).toBeInTheDocument();
56
+ });
57
+ it("should render the styled-components implementation when styled-system props are passed", () => {
58
+ const { container } = render(
59
+ <Select id="select" name="select" mb={400}>
60
+ <option value="v">option1</option>
61
+ </Select>
62
+ );
63
+ expect(container.querySelector(".seeds-select")).not.toBeInTheDocument();
64
+ });
46
65
  it("should render with chevron-down", () => {
47
66
  render(
48
67
  <Select
@@ -0,0 +1,11 @@
1
+ import Select from "../";
2
+
3
+ // Regression guard for DS-4394: racine's `generate:props-docs` runs react-docgen
4
+ // over each package's entry component and keys the output on `displayName`. A bare
5
+ // cross-file re-export resolves to no local definition, so the entry must be a real
6
+ // local component with an explicit `displayName`.
7
+ describe("Select entry component", () => {
8
+ it("exposes an explicit displayName for react-docgen", () => {
9
+ expect((Select as { displayName?: string }).displayName).toBe("Select");
10
+ });
11
+ });
package/src/css.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module "*.css";
package/src/select.css ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Seeds Select component classes
3
+ * Use these instead of writing out individual Tailwind utility classes.
4
+ *
5
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
6
+ * CSS variable definitions and dark mode support.
7
+ *
8
+ * Usage:
9
+ * <div class="seeds-select seeds-select-default">
10
+ * <select class="seeds-select-input">…</select>
11
+ * <span class="seeds-select-arrow seeds-select-arrow-default">…</span>
12
+ * </div>
13
+ */
14
+
15
+ @layer components {
16
+ .seeds-select {
17
+ position: relative;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ .seeds-select .seeds-select-input {
22
+ box-sizing: border-box;
23
+ width: 100%;
24
+ border: 1px solid var(--color-form-border-base);
25
+ border-radius: var(--radius-500);
26
+ background-color: var(--color-form-bg-base);
27
+ color: var(--color-text-body);
28
+ cursor: pointer;
29
+ outline: none;
30
+ appearance: none;
31
+ transition:
32
+ border-color var(--duration-fast) var(--ease-ease_in),
33
+ box-shadow var(--duration-fast) var(--ease-ease_in);
34
+ font-family: var(--font-family);
35
+ font-weight: var(--font-weight-normal);
36
+ margin: 0;
37
+ /* We do this because the Sprout app sets it to hidden in Classic mode. We can delete after Nectar launches. */
38
+ visibility: visible;
39
+ }
40
+
41
+ /* kill the dropdown arrow on IE 11 */
42
+ .seeds-select .seeds-select-input::-ms-expand {
43
+ display: none;
44
+ }
45
+
46
+ .seeds-select .seeds-select-input:focus {
47
+ box-shadow:
48
+ 0 0 0 1px var(--color-button-primary-bg-base),
49
+ 0 0px 0px 4px
50
+ color-mix(in srgb, var(--color-button-primary-bg-base), transparent 70%);
51
+ outline: none;
52
+ }
53
+
54
+ /* Fix for red ring when input is marked required in Firefox */
55
+ .seeds-select
56
+ .seeds-select-input:not(output):not(:focus):-moz-ui-invalid {
57
+ box-shadow: none;
58
+ }
59
+
60
+ /* size: default */
61
+ .seeds-select-default .seeds-select-input {
62
+ padding: var(--space-300) var(--space-500) var(--space-300) var(--space-300);
63
+ font-size: var(--font-size-200);
64
+ line-height: normal;
65
+ }
66
+
67
+ /* size: large */
68
+ .seeds-select-large .seeds-select-input {
69
+ padding: var(--space-350) var(--space-600) var(--space-350) var(--space-400);
70
+ font-size: var(--font-size-300);
71
+ line-height: var(--line-height-300);
72
+ }
73
+
74
+ /* size: small */
75
+ .seeds-select-small .seeds-select-input {
76
+ padding: var(--space-200) var(--space-500) var(--space-200) var(--space-200);
77
+ font-size: var(--font-size-200);
78
+ line-height: normal;
79
+ }
80
+
81
+ .seeds-select-arrow {
82
+ position: absolute;
83
+ top: 50%;
84
+ transform: translateY(-50%);
85
+ color: var(--color-icon-base);
86
+ pointer-events: none;
87
+ }
88
+
89
+ .seeds-select-arrow-default,
90
+ .seeds-select-arrow-small {
91
+ right: var(--space-300);
92
+ }
93
+
94
+ .seeds-select-arrow-large {
95
+ right: var(--space-350);
96
+ }
97
+
98
+ /* disabled */
99
+ .seeds-select-disabled {
100
+ opacity: 0.4;
101
+ }
102
+
103
+ .seeds-select-disabled .seeds-select-input {
104
+ cursor: not-allowed;
105
+ }
106
+
107
+ /* invalid */
108
+ .seeds-select-invalid .seeds-select-input {
109
+ border-color: var(--color-form-border-error);
110
+ }
111
+
112
+ .seeds-select-invalid .seeds-select-arrow {
113
+ color: var(--color-icon-error);
114
+ }
115
+ }