@spark-web/text-input 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,50 +1,235 @@
1
- import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray';
2
1
  import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
2
+ import { Box } from '@spark-web/box';
3
+ import { useFieldContext, FieldContextProvider } from '@spark-web/field';
4
+ import { useTheme } from '@spark-web/theme';
5
+ import { useMemo, createContext, Children, isValidElement, forwardRef } from 'react';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+ import _slicedToArray from '@babel/runtime/helpers/esm/slicedToArray';
3
8
  import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
4
9
  import { css } from '@emotion/css';
5
10
  import { useFocusRing } from '@spark-web/a11y';
6
- import { Box } from '@spark-web/box';
7
- import { useFieldContext } from '@spark-web/field';
8
11
  import { useText } from '@spark-web/text';
9
- import { useTheme } from '@spark-web/theme';
10
- import { buildDataAttributes } from '@spark-web/utils/internal';
11
- import { forwardRef } from 'react';
12
- import { jsx } from 'react/jsx-runtime';
13
12
 
14
- var _excluded = ["data"],
15
- _excluded2 = ["disabled", "invalid"];
13
+ /**
14
+ * Components like the `SelectInput` may subscribe to the adornment context and
15
+ * change their appearance or behaviour.
16
+ */
17
+ var InputAdornmentContext = /*#__PURE__*/createContext(null);
18
+ var placementToPadding = {
19
+ start: {
20
+ paddingLeft: 'medium',
21
+ paddingRight: 'xsmall'
22
+ },
23
+ end: {
24
+ paddingLeft: 'xsmall',
25
+ paddingRight: 'medium'
26
+ }
27
+ };
28
+
29
+ /**
30
+ * Places an element at the "start" or "end" of the input, only one adornment
31
+ * may be provided for each placement. By default, the adornment element will be
32
+ * wrapped to provide alignment and spacing, use the "raw" property to opt-out
33
+ * of this behaviour.
34
+ *
35
+ * @example
36
+ * <TextInput>
37
+ * <InputAdornment placement="start">
38
+ * <Text tone="placeholder">$</Text>
39
+ * </InputAdornment>
40
+ * </TextInput>
41
+ */
42
+ var InputAdornment = function InputAdornment(_ref) {
43
+ var children = _ref.children,
44
+ fieldLabel = _ref.fieldLabel,
45
+ placement = _ref.placement,
46
+ raw = _ref.raw;
47
+
48
+ var _useTheme = useTheme(),
49
+ sizing = _useTheme.sizing;
50
+
51
+ var adornmentContext = useMemo(function () {
52
+ return {
53
+ placement: placement
54
+ };
55
+ }, [placement]);
56
+ var _placementToPadding$p = placementToPadding[placement],
57
+ paddingLeft = _placementToPadding$p.paddingLeft,
58
+ paddingRight = _placementToPadding$p.paddingRight;
59
+ var content = children;
60
+
61
+ if (!raw) {
62
+ content = /*#__PURE__*/jsx(Box, {
63
+ paddingLeft: paddingLeft,
64
+ paddingRight: paddingRight,
65
+ children: /*#__PURE__*/jsx(Box, {
66
+ display: "flex",
67
+ alignItems: "center",
68
+ justifyContent: "center",
69
+ style: {
70
+ minWidth: sizing.xxsmall
71
+ },
72
+ children: children
73
+ })
74
+ });
75
+ }
76
+
77
+ var wrappedContent = /*#__PURE__*/jsx(InputAdornmentContext.Provider, {
78
+ value: adornmentContext,
79
+ children: content
80
+ });
81
+
82
+ if (fieldLabel) {
83
+ return /*#__PURE__*/jsx(FieldAdornment, {
84
+ fieldLabel: fieldLabel,
85
+ children: wrappedContent
86
+ });
87
+ }
88
+
89
+ return wrappedContent;
90
+ };
91
+ /**
92
+ * Wrap the element with a field provider to override the parent field label.
93
+ * Only split-out from `InputAdornment` to avoid the conditional hook rule.
94
+ */
95
+
96
+ var FieldAdornment = function FieldAdornment(_ref2) {
97
+ var children = _ref2.children,
98
+ fieldLabel = _ref2.fieldLabel;
99
+ var parentFieldContext = useFieldContext();
100
+ var fieldContext = useMemo(function () {
101
+ return _objectSpread(_objectSpread({}, parentFieldContext), {}, {
102
+ accessibilityLabel: fieldLabel
103
+ });
104
+ }, [fieldLabel, parentFieldContext]);
105
+ return /*#__PURE__*/jsx(FieldContextProvider, {
106
+ value: fieldContext,
107
+ children: children
108
+ });
109
+ };
110
+
111
+ var _excluded$1 = ["children", "startAdornment", "endAdornment"];
112
+ var InputContainer = function InputContainer(_ref) {
113
+ var children = _ref.children,
114
+ startAdornment = _ref.startAdornment,
115
+ endAdornment = _ref.endAdornment,
116
+ boxProps = _objectWithoutProperties(_ref, _excluded$1);
117
+
118
+ var _useFieldContext = useFieldContext(),
119
+ _useFieldContext2 = _slicedToArray(_useFieldContext, 1),
120
+ _useFieldContext2$ = _useFieldContext2[0],
121
+ disabled = _useFieldContext2$.disabled,
122
+ invalid = _useFieldContext2$.invalid;
123
+
124
+ return /*#__PURE__*/jsxs(Box, _objectSpread(_objectSpread({
125
+ position: "relative",
126
+ background: disabled ? 'inputDisabled' : 'input'
127
+ }, boxProps), {}, {
128
+ children: [startAdornment, children, /*#__PURE__*/jsx(FocusIndicator, {
129
+ invalid: invalid
130
+ }), endAdornment]
131
+ }));
132
+ };
133
+
134
+ var FocusIndicator = function FocusIndicator(_ref2) {
135
+ var invalid = _ref2.invalid;
136
+ return /*#__PURE__*/jsx(Box, {
137
+ "aria-hidden": "true",
138
+ as: "span",
139
+ data: {
140
+ 'focus-indicator': 'true'
141
+ } // Styles
142
+ ,
143
+ border: invalid ? 'critical' : 'field',
144
+ borderRadius: "small",
145
+ position: "absolute",
146
+ bottom: 0,
147
+ left: 0,
148
+ right: 0,
149
+ top: 0,
150
+ className: css({
151
+ pointerEvents: 'none'
152
+ })
153
+ });
154
+ };
155
+
156
+ /**
157
+ * Map children for placement within the `TextInput` flex container. Ensures that
158
+ * placeholders are provided for unused placements.
159
+ */
160
+ var childrenToAdornments = function childrenToAdornments(children) {
161
+ var startAdornment = null;
162
+ var endAdornment = null;
163
+
164
+ if (!children) {
165
+ return {
166
+ startAdornment: startAdornment,
167
+ endAdornment: endAdornment
168
+ };
169
+ }
170
+
171
+ Children.forEach(children, function (child) {
172
+ if ( /*#__PURE__*/isValidElement(child)) {
173
+ if (child.props.placement === 'end') {
174
+ endAdornment = child;
175
+ }
176
+
177
+ if (child.props.placement === 'start') {
178
+ startAdornment = child;
179
+ }
180
+ }
181
+ });
182
+ return {
183
+ startAdornment: startAdornment,
184
+ endAdornment: endAdornment
185
+ };
186
+ };
187
+
188
+ var _excluded = ["children", "data"];
16
189
 
17
190
  /** Organize and emphasize information quickly and effectively in a list of text elements. */
18
191
  var TextInput = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
19
- var data = _ref.data,
192
+ var children = _ref.children,
193
+ data = _ref.data,
20
194
  consumerProps = _objectWithoutProperties(_ref, _excluded);
21
195
 
22
196
  var _useFieldContext = useFieldContext(),
23
- disabled = _useFieldContext.disabled,
24
- invalid = _useFieldContext.invalid,
25
- a11yProps = _objectWithoutProperties(_useFieldContext, _excluded2);
197
+ _useFieldContext2 = _slicedToArray(_useFieldContext, 2),
198
+ _useFieldContext2$ = _useFieldContext2[0],
199
+ disabled = _useFieldContext2$.disabled,
200
+ invalid = _useFieldContext2$.invalid,
201
+ a11yProps = _useFieldContext2[1];
26
202
 
27
- var inputStyles = useInput({
28
- disabled: disabled,
29
- invalid: invalid
203
+ var _childrenToAdornments = childrenToAdornments(children),
204
+ startAdornment = _childrenToAdornments.startAdornment,
205
+ endAdornment = _childrenToAdornments.endAdornment;
206
+
207
+ return /*#__PURE__*/jsx(InputContainer, {
208
+ display: "inline-flex",
209
+ alignItems: "center",
210
+ startAdornment: startAdornment,
211
+ endAdornment: endAdornment,
212
+ children: /*#__PURE__*/jsx(Box, _objectSpread(_objectSpread(_objectSpread({}, consumerProps), a11yProps), {}, {
213
+ as: "input",
214
+ ref: forwardedRef,
215
+ data: data,
216
+ disabled: disabled,
217
+ position: "relative" // Styles
218
+ ,
219
+ flex: 1,
220
+ height: "medium",
221
+ paddingX: "medium",
222
+ paddingLeft: startAdornment ? 'none' : 'medium',
223
+ paddingRight: endAdornment ? 'none' : 'medium',
224
+ className: css(useInput({
225
+ disabled: disabled,
226
+ invalid: invalid
227
+ }))
228
+ }))
30
229
  });
31
- return /*#__PURE__*/jsx(Box, _objectSpread(_objectSpread(_objectSpread({
32
- as: "input",
33
- disabled: disabled,
34
- ref: forwardedRef // styles
35
- ,
36
- background: disabled ? 'inputDisabled' : 'input',
37
- border: invalid ? 'critical' : 'field',
38
- borderRadius: "small",
39
- height: "medium",
40
- paddingX: "medium",
41
- className: css(inputStyles)
42
- }, data ? buildDataAttributes(data) : null), a11yProps), consumerProps));
43
230
  });
44
- TextInput.displayName = 'TextInput'; // Styled components
45
- // ------------------------------
46
-
47
- function useInput(_ref2) {
231
+ TextInput.displayName = 'TextInput';
232
+ var useInput = function useInput(_ref2) {
48
233
  var disabled = _ref2.disabled;
49
234
  var theme = useTheme();
50
235
  var focusRingStyles = useFocusRing({
@@ -62,15 +247,15 @@ function useInput(_ref2) {
62
247
  responsiveStyles = _textStyles[1];
63
248
 
64
249
  return _objectSpread(_objectSpread(_objectSpread({}, typographyStyles), responsiveStyles), {}, {
250
+ ':focus': {
251
+ outline: 'none'
252
+ },
65
253
  ':enabled': {
66
- '&:hover': {
67
- borderColor: theme.border.color.fieldHover
68
- },
69
- '&:focus': _objectSpread(_objectSpread({}, focusRingStyles), {}, {
254
+ ':focus + [data-focus-indicator]': _objectSpread({
70
255
  borderColor: theme.border.color.fieldAccent
71
- })
256
+ }, focusRingStyles)
72
257
  }
73
258
  });
74
- }
259
+ };
75
260
 
76
- export { TextInput, useInput };
261
+ export { InputAdornment, InputContainer, TextInput, useInput };
package/package.json CHANGED
@@ -1,18 +1,21 @@
1
1
  {
2
2
  "name": "@spark-web/text-input",
3
- "version": "1.0.3",
3
+ "version": "1.2.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/spark-web-text-input.cjs.js",
6
6
  "module": "dist/spark-web-text-input.esm.js",
7
+ "files": [
8
+ "dist"
9
+ ],
7
10
  "dependencies": {
8
- "@babel/runtime": "^7.14.6",
9
- "@emotion/css": "^11.7.1",
10
- "@spark-web/a11y": "^1.0.3",
11
- "@spark-web/box": "^1.0.3",
12
- "@spark-web/field": "^1.0.3",
13
- "@spark-web/text": "^1.0.3",
14
- "@spark-web/theme": "^2.0.2",
15
- "@spark-web/utils": "^1.1.1"
11
+ "@babel/runtime": "^7.18.0",
12
+ "@emotion/css": "^11.9.0",
13
+ "@spark-web/a11y": "^1.0.5",
14
+ "@spark-web/box": "^1.0.5",
15
+ "@spark-web/field": "^2.0.0",
16
+ "@spark-web/text": "^1.0.5",
17
+ "@spark-web/theme": "^3.0.1",
18
+ "@spark-web/utils": "^1.1.3"
16
19
  },
17
20
  "devDependencies": {
18
21
  "@types/react": "^17.0.12",
package/CHANGELOG.md DELETED
@@ -1,75 +0,0 @@
1
- # @spark-web/text-input
2
-
3
- ## 1.0.3
4
-
5
- ### Patch Changes
6
-
7
- - [#42](https://github.com/brighte-labs/spark-web/pull/42)
8
- [`435779a`](https://github.com/brighte-labs/spark-web/commit/435779aa42bd635bbf43e1fd41724c666402caa2)
9
- Thanks [@lukebennett88](https://github.com/lukebennett88)! - Prevent multiple
10
- versions of React
11
-
12
- - Updated dependencies
13
- [[`435779a`](https://github.com/brighte-labs/spark-web/commit/435779aa42bd635bbf43e1fd41724c666402caa2)]:
14
- - @spark-web/a11y@1.0.3
15
- - @spark-web/box@1.0.3
16
- - @spark-web/field@1.0.3
17
- - @spark-web/text@1.0.3
18
- - @spark-web/theme@2.0.2
19
- - @spark-web/utils@1.1.1
20
-
21
- ## 1.0.2
22
-
23
- ### Patch Changes
24
-
25
- - [#40](https://github.com/brighte-labs/spark-web/pull/40)
26
- [`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)
27
- Thanks [@lukebennett88](https://github.com/lukebennett88)! - Add
28
- @babel/transform-runtime
29
-
30
- - Updated dependencies
31
- [[`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)]:
32
- - @spark-web/a11y@1.0.2
33
- - @spark-web/box@1.0.2
34
- - @spark-web/field@1.0.2
35
- - @spark-web/text@1.0.2
36
- - @spark-web/theme@2.0.1
37
- - @spark-web/utils@1.0.2
38
-
39
- ## 1.0.1
40
-
41
- ### Patch Changes
42
-
43
- - [#36](https://github.com/brighte-labs/spark-web/pull/36)
44
- [`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)
45
- Thanks [@lukebennett88](https://github.com/lukebennett88)! - Update Babel
46
- config
47
-
48
- - Updated dependencies
49
- [[`aebff30`](https://github.com/brighte-labs/spark-web/commit/aebff30c86cb0a9db22b545c46159ce0d1c14afb),
50
- [`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)]:
51
- - @spark-web/theme@2.0.0
52
- - @spark-web/a11y@1.0.1
53
- - @spark-web/box@1.0.1
54
- - @spark-web/field@1.0.1
55
- - @spark-web/text@1.0.1
56
- - @spark-web/utils@1.0.1
57
-
58
- ## 1.0.0
59
-
60
- ### Major Changes
61
-
62
- - [#27](https://github.com/brighte-labs/spark-web/pull/27)
63
- [`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)
64
- Thanks [@JedWatson](https://github.com/JedWatson)! - Initial Version
65
-
66
- ### Patch Changes
67
-
68
- - Updated dependencies
69
- [[`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)]:
70
- - @spark-web/a11y@1.0.0
71
- - @spark-web/box@1.0.0
72
- - @spark-web/field@1.0.0
73
- - @spark-web/text@1.0.0
74
- - @spark-web/theme@1.0.0
75
- - @spark-web/utils@1.0.0
@@ -1,35 +0,0 @@
1
- import { Field } from '@spark-web/field';
2
- import { InformationCircleIcon } from '@spark-web/icon';
3
- import { Inline } from '@spark-web/inline';
4
- import { Stack } from '@spark-web/stack';
5
- import { Text } from '@spark-web/text';
6
- import type { ComponentMeta, ComponentStory } from '@storybook/react';
7
-
8
- import type { TextInputProps } from './TextInput';
9
- import { TextInput } from './TextInput';
10
-
11
- export default {
12
- title: 'Forms / TextInput',
13
- component: TextInput,
14
- } as ComponentMeta<typeof TextInput>;
15
-
16
- const TextInputStory: ComponentStory<typeof TextInput> = (
17
- args: TextInputProps
18
- ) => (
19
- <Stack gap="large">
20
- <Inline gap="xsmall" alignY="center">
21
- <InformationCircleIcon tone="info" size="xsmall" />
22
- <Text weight="medium" tone="info" baseline={false}>
23
- {`Must be used inside of a <Field/>`}
24
- </Text>
25
- </Inline>
26
- <Field label="Text input">
27
- <TextInput {...args} />
28
- </Field>
29
- </Stack>
30
- );
31
- export const Default = TextInputStory.bind({});
32
-
33
- Default.args = {
34
- displayName: 'Display name',
35
- } as TextInputProps;
package/src/TextInput.tsx DELETED
@@ -1,95 +0,0 @@
1
- import { css } from '@emotion/css';
2
- import { useFocusRing } from '@spark-web/a11y';
3
- import { Box } from '@spark-web/box';
4
- import type { FieldContextType } from '@spark-web/field';
5
- import { useFieldContext } from '@spark-web/field';
6
- import { useText } from '@spark-web/text';
7
- import { useTheme } from '@spark-web/theme';
8
- import type { DataAttributeMap } from '@spark-web/utils/internal';
9
- import { buildDataAttributes } from '@spark-web/utils/internal';
10
- import type { AllHTMLAttributes } from 'react';
11
- import { forwardRef } from 'react';
12
-
13
- const validTypes = {
14
- text: 'text',
15
- password: 'password',
16
- email: 'email',
17
- search: 'search',
18
- number: 'number',
19
- tel: 'tel',
20
- url: 'url',
21
- };
22
-
23
- type NativeInputProps = Pick<
24
- AllHTMLAttributes<HTMLInputElement>,
25
- 'onBlur' | 'onFocus' | 'onChange' | 'placeholder' | 'value'
26
- >;
27
-
28
- export type TextInputProps = {
29
- /** Map of data attributes. */
30
- data?: DataAttributeMap;
31
- /**
32
- * How an input behaves varies considerably depending on the value of its type
33
- * attribute. If this attribute is not specified, the default type "text".
34
- */
35
- type?: keyof typeof validTypes;
36
- } & NativeInputProps;
37
-
38
- /** Organize and emphasize information quickly and effectively in a list of text elements. */
39
- export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
40
- ({ data, ...consumerProps }, forwardedRef) => {
41
- const { disabled, invalid, ...a11yProps } = useFieldContext();
42
- const inputStyles = useInput({ disabled, invalid });
43
-
44
- return (
45
- <Box
46
- as="input"
47
- disabled={disabled}
48
- ref={forwardedRef}
49
- // styles
50
- background={disabled ? 'inputDisabled' : 'input'}
51
- border={invalid ? 'critical' : 'field'}
52
- borderRadius="small"
53
- height="medium"
54
- paddingX="medium"
55
- className={css(inputStyles)}
56
- {...(data ? buildDataAttributes(data) : null)}
57
- {...a11yProps}
58
- {...consumerProps}
59
- />
60
- );
61
- }
62
- );
63
- TextInput.displayName = 'TextInput';
64
-
65
- // Styled components
66
- // ------------------------------
67
-
68
- export type UseInputProps = Pick<FieldContextType, 'disabled' | 'invalid'>;
69
-
70
- export function useInput({ disabled }: UseInputProps) {
71
- const theme = useTheme();
72
- const focusRingStyles = useFocusRing({ always: true });
73
- const textStyles = useText({
74
- baseline: false,
75
- tone: disabled ? 'disabled' : 'neutral',
76
- size: 'standard',
77
- weight: 'regular',
78
- });
79
-
80
- const [typographyStyles, responsiveStyles] = textStyles;
81
-
82
- return {
83
- ...typographyStyles,
84
- ...responsiveStyles,
85
- ':enabled': {
86
- '&:hover': {
87
- borderColor: theme.border.color.fieldHover,
88
- },
89
- '&:focus': {
90
- ...focusRingStyles,
91
- borderColor: theme.border.color.fieldAccent,
92
- },
93
- },
94
- };
95
- }
package/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export { TextInput, useInput } from './TextInput';
2
-
3
- // types
4
-
5
- export type { TextInputProps, UseInputProps } from './TextInput';