@spark-web/field 1.0.2 → 2.0.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.
package/README.md CHANGED
@@ -140,4 +140,4 @@ Mark the field as disabled by passing true to the disabled prop.
140
140
  | tone? | 'critical' \| 'neutral' \| 'positive' | 'neutral' | Provide a tone to influence elements of the field, and its input. |
141
141
 
142
142
  [data-attribute-map]:
143
- https://bitbucket.org/brighte-energy/energy/src/14a694872cc43bb454981bada65f5f12b56f77c9/spark-web/packages/utils-spark/src/buildDataAttributes.ts#spark-web/packages/utils-spark/src/buildDataAttributes.ts-1
143
+ https://github.com/brighte-labs/spark-web/blob/e7f6f4285b4cfd876312cc89fbdd094039aa239a/packages/utils/src/internal/buildDataAttributes.ts#L1
@@ -1,10 +1,14 @@
1
1
  /// <reference types="react" />
2
- export declare type FieldContextType = {
3
- 'aria-describedby'?: string;
4
- id: string;
2
+ export declare type FieldState = {
5
3
  disabled: boolean;
6
4
  invalid: boolean;
7
5
  };
6
+ export declare type InputPropsDerivedFromField = {
7
+ 'aria-describedby'?: string;
8
+ 'aria-invalid': true | undefined;
9
+ id: string;
10
+ };
11
+ export declare type FieldContextType = [FieldState, InputPropsDerivedFromField];
8
12
  export declare const FieldContext: import("react").Context<FieldContextType | null>;
9
13
  export declare const FieldContextProvider: import("react").Provider<FieldContextType | null>;
10
14
  export declare const FIELD_CONTEXT_ERROR_MESSAGE = "Input components must be inside a `Field`.";
@@ -1,4 +1,4 @@
1
- export { useFieldContext } from './context';
1
+ export { FieldContextProvider, useFieldContext } from './context';
2
2
  export { Field, FieldMessage, useFieldIds } from './Field';
3
- export type { FieldContextType } from './context';
3
+ export type { FieldContextType, FieldState, InputPropsDerivedFromField, } from './context';
4
4
  export type { FieldProps, Tone } from './Field';
@@ -56,12 +56,15 @@ var Field = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
56
56
  messageId = _useFieldIds.messageId; // field context
57
57
 
58
58
 
59
- var fieldContext = {
60
- 'aria-describedby': a11y.mergeIds(message && messageId, description && descriptionId),
61
- id: inputId,
59
+ var invalid = Boolean(message && tone === 'critical');
60
+ var fieldContext = [{
62
61
  disabled: disabled,
63
- invalid: Boolean(message && tone === 'critical')
64
- }; // label prep
62
+ invalid: invalid
63
+ }, {
64
+ 'aria-describedby': a11y.mergeIds(message && messageId, description && descriptionId),
65
+ 'aria-invalid': invalid || undefined,
66
+ id: inputId
67
+ }]; // label prep
65
68
 
66
69
  var hiddenLabel = /*#__PURE__*/jsxRuntime.jsxs(a11y.VisuallyHidden, {
67
70
  as: "label",
@@ -77,7 +80,7 @@ var Field = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
77
80
  children: /*#__PURE__*/jsxRuntime.jsxs(text.Text, {
78
81
  inline: true,
79
82
  tone: disabled ? 'disabled' : 'neutral',
80
- weight: "strong",
83
+ weight: "semibold",
81
84
  children: [label, ' ', secondaryLabel && /*#__PURE__*/jsxRuntime.jsx(text.Text, {
82
85
  inline: true,
83
86
  tone: disabled ? 'disabled' : 'muted',
@@ -199,6 +202,7 @@ function IndicatorContainer(_ref3) {
199
202
  }
200
203
 
201
204
  exports.Field = Field;
205
+ exports.FieldContextProvider = FieldContextProvider;
202
206
  exports.FieldMessage = FieldMessage;
203
207
  exports.useFieldContext = useFieldContext;
204
208
  exports.useFieldIds = useFieldIds;
@@ -56,12 +56,15 @@ var Field = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
56
56
  messageId = _useFieldIds.messageId; // field context
57
57
 
58
58
 
59
- var fieldContext = {
60
- 'aria-describedby': a11y.mergeIds(message && messageId, description && descriptionId),
61
- id: inputId,
59
+ var invalid = Boolean(message && tone === 'critical');
60
+ var fieldContext = [{
62
61
  disabled: disabled,
63
- invalid: Boolean(message && tone === 'critical')
64
- }; // label prep
62
+ invalid: invalid
63
+ }, {
64
+ 'aria-describedby': a11y.mergeIds(message && messageId, description && descriptionId),
65
+ 'aria-invalid': invalid || undefined,
66
+ id: inputId
67
+ }]; // label prep
65
68
 
66
69
  var hiddenLabel = /*#__PURE__*/jsxRuntime.jsxs(a11y.VisuallyHidden, {
67
70
  as: "label",
@@ -77,7 +80,7 @@ var Field = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
77
80
  children: /*#__PURE__*/jsxRuntime.jsxs(text.Text, {
78
81
  inline: true,
79
82
  tone: disabled ? 'disabled' : 'neutral',
80
- weight: "strong",
83
+ weight: "semibold",
81
84
  children: [label, ' ', secondaryLabel && /*#__PURE__*/jsxRuntime.jsx(text.Text, {
82
85
  inline: true,
83
86
  tone: disabled ? 'disabled' : 'muted',
@@ -199,6 +202,7 @@ function IndicatorContainer(_ref3) {
199
202
  }
200
203
 
201
204
  exports.Field = Field;
205
+ exports.FieldContextProvider = FieldContextProvider;
202
206
  exports.FieldMessage = FieldMessage;
203
207
  exports.useFieldContext = useFieldContext;
204
208
  exports.useFieldIds = useFieldIds;
@@ -52,12 +52,15 @@ var Field = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
52
52
  messageId = _useFieldIds.messageId; // field context
53
53
 
54
54
 
55
- var fieldContext = {
56
- 'aria-describedby': mergeIds(message && messageId, description && descriptionId),
57
- id: inputId,
55
+ var invalid = Boolean(message && tone === 'critical');
56
+ var fieldContext = [{
58
57
  disabled: disabled,
59
- invalid: Boolean(message && tone === 'critical')
60
- }; // label prep
58
+ invalid: invalid
59
+ }, {
60
+ 'aria-describedby': mergeIds(message && messageId, description && descriptionId),
61
+ 'aria-invalid': invalid || undefined,
62
+ id: inputId
63
+ }]; // label prep
61
64
 
62
65
  var hiddenLabel = /*#__PURE__*/jsxs(VisuallyHidden, {
63
66
  as: "label",
@@ -73,7 +76,7 @@ var Field = /*#__PURE__*/forwardRef(function (_ref, forwardedRef) {
73
76
  children: /*#__PURE__*/jsxs(Text, {
74
77
  inline: true,
75
78
  tone: disabled ? 'disabled' : 'neutral',
76
- weight: "strong",
79
+ weight: "semibold",
77
80
  children: [label, ' ', secondaryLabel && /*#__PURE__*/jsx(Text, {
78
81
  inline: true,
79
82
  tone: disabled ? 'disabled' : 'muted',
@@ -194,4 +197,4 @@ function IndicatorContainer(_ref3) {
194
197
  }));
195
198
  }
196
199
 
197
- export { Field, FieldMessage, useFieldContext, useFieldIds };
200
+ export { Field, FieldContextProvider, FieldMessage, useFieldContext, useFieldIds };
package/package.json CHANGED
@@ -1,24 +1,30 @@
1
1
  {
2
2
  "name": "@spark-web/field",
3
+ "version": "2.0.0",
3
4
  "license": "MIT",
4
- "version": "1.0.2",
5
5
  "main": "dist/spark-web-field.cjs.js",
6
6
  "module": "dist/spark-web-field.esm.js",
7
- "devDependencies": {
8
- "@types/react": "^17.0.12"
9
- },
7
+ "files": [
8
+ "dist"
9
+ ],
10
10
  "dependencies": {
11
- "@babel/runtime": "^7.14.6",
12
- "@emotion/css": "^11.7.1",
13
- "@spark-web/a11y": "^1.0.2",
14
- "@spark-web/box": "^1.0.2",
15
- "@spark-web/icon": "^1.0.2",
16
- "@spark-web/stack": "^1.0.2",
17
- "@spark-web/text": "^1.0.2",
18
- "@spark-web/theme": "^2.0.1",
19
- "@spark-web/utils": "^1.0.2",
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/icon": "^1.1.3",
16
+ "@spark-web/stack": "^1.0.5",
17
+ "@spark-web/text": "^1.0.5",
18
+ "@spark-web/theme": "^3.0.1",
19
+ "@spark-web/utils": "^1.1.3"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "^17.0.12",
20
23
  "react": "^17.0.2"
21
24
  },
25
+ "peerDependencies": {
26
+ "react": ">=17.0.2"
27
+ },
22
28
  "engines": {
23
29
  "node": ">= 14.13"
24
30
  }
package/CHANGELOG.md DELETED
@@ -1,60 +0,0 @@
1
- # @spark-web/field
2
-
3
- ## 1.0.2
4
-
5
- ### Patch Changes
6
-
7
- - [#40](https://github.com/brighte-labs/spark-web/pull/40)
8
- [`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)
9
- Thanks [@lukebennett88](https://github.com/lukebennett88)! - Add
10
- @babel/transform-runtime
11
-
12
- - Updated dependencies
13
- [[`062c8ab`](https://github.com/brighte-labs/spark-web/commit/062c8ab8c7b4120f8d14c269b5f7801288c678ca)]:
14
- - @spark-web/a11y@1.0.2
15
- - @spark-web/box@1.0.2
16
- - @spark-web/icon@1.0.2
17
- - @spark-web/stack@1.0.2
18
- - @spark-web/text@1.0.2
19
- - @spark-web/theme@2.0.1
20
- - @spark-web/utils@1.0.2
21
-
22
- ## 1.0.1
23
-
24
- ### Patch Changes
25
-
26
- - [#36](https://github.com/brighte-labs/spark-web/pull/36)
27
- [`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)
28
- Thanks [@lukebennett88](https://github.com/lukebennett88)! - Update Babel
29
- config
30
-
31
- - Updated dependencies
32
- [[`aebff30`](https://github.com/brighte-labs/spark-web/commit/aebff30c86cb0a9db22b545c46159ce0d1c14afb),
33
- [`8546f8f`](https://github.com/brighte-labs/spark-web/commit/8546f8f05daaa79ea3ff954c6c4928a7a2d0622d)]:
34
- - @spark-web/theme@2.0.0
35
- - @spark-web/a11y@1.0.1
36
- - @spark-web/box@1.0.1
37
- - @spark-web/icon@1.0.1
38
- - @spark-web/stack@1.0.1
39
- - @spark-web/text@1.0.1
40
- - @spark-web/utils@1.0.1
41
-
42
- ## 1.0.0
43
-
44
- ### Major Changes
45
-
46
- - [#27](https://github.com/brighte-labs/spark-web/pull/27)
47
- [`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)
48
- Thanks [@JedWatson](https://github.com/JedWatson)! - Initial Version
49
-
50
- ### Patch Changes
51
-
52
- - Updated dependencies
53
- [[`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)]:
54
- - @spark-web/a11y@1.0.0
55
- - @spark-web/box@1.0.0
56
- - @spark-web/icon@1.0.0
57
- - @spark-web/stack@1.0.0
58
- - @spark-web/text@1.0.0
59
- - @spark-web/theme@1.0.0
60
- - @spark-web/utils@1.0.0
package/src/Field.tsx DELETED
@@ -1,214 +0,0 @@
1
- import { css } from '@emotion/css';
2
- import { composeId, mergeIds, useId, VisuallyHidden } from '@spark-web/a11y';
3
- import { Box } from '@spark-web/box';
4
- import { CheckCircleIcon, ExclamationCircleIcon } from '@spark-web/icon';
5
- import { Stack } from '@spark-web/stack';
6
- import { Text } 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 { ReactElement, ReactNode } from 'react';
11
- import { forwardRef, Fragment } from 'react';
12
-
13
- import { FieldContextProvider } from './context';
14
-
15
- export type Tone = keyof typeof messageToneMap;
16
-
17
- export type FieldProps = {
18
- id?: string;
19
- data?: DataAttributeMap;
20
-
21
- /** Optionally provide a utility or contextual hint, related to the field. */
22
- adornment?: ReactElement;
23
- /** Input component */
24
- children: ReactNode;
25
- /**
26
- * Indicates that the field is perceivable but disabled, so it is not editable
27
- * or otherwise operable.
28
- */
29
- disabled?: boolean;
30
- /** Provide additional information that will aid user input. */
31
- description?: string;
32
- /** Concisely label the field. */
33
- label: string;
34
- /**
35
- * The label must always be provided for assistive technology, but you may
36
- * hide it from sighted users when the intent can be inferred from context.
37
- */
38
- labelVisibility?: 'hidden' | 'reserve-space' | 'visible';
39
- /** Provide a message, informing the user about changes in state. */
40
- message?: string;
41
- /** Additional context, typically used to indicate that the field is optional. */
42
- secondaryLabel?: string;
43
- /** Provide a tone to influence elements of the field, and its input. */
44
- tone?: Tone;
45
- };
46
-
47
- /**
48
- * Using a [context](https://reactjs.org/docs/context.html), the field
49
- * component connects the label, description, and message to the input element.
50
- */
51
- export const Field = forwardRef<HTMLDivElement, FieldProps>(
52
- (
53
- {
54
- children,
55
- id: idProp,
56
- data,
57
-
58
- description,
59
- disabled = false,
60
- label,
61
- adornment,
62
- labelVisibility = 'visible',
63
- message,
64
- secondaryLabel,
65
- tone = 'neutral',
66
- },
67
- forwardedRef
68
- ) => {
69
- const { descriptionId, inputId, messageId } = useFieldIds(idProp);
70
-
71
- // field context
72
- const fieldContext = {
73
- 'aria-describedby': mergeIds(
74
- message && messageId,
75
- description && descriptionId
76
- ),
77
- id: inputId,
78
- disabled,
79
- invalid: Boolean(message && tone === 'critical'),
80
- };
81
-
82
- // label prep
83
- const hiddenLabel = (
84
- <VisuallyHidden as="label" htmlFor={inputId}>
85
- {label} {secondaryLabel}
86
- </VisuallyHidden>
87
- );
88
- const labelElement = {
89
- hidden: hiddenLabel,
90
- visible: (
91
- <Box as="label" htmlFor={inputId}>
92
- <Text inline tone={disabled ? 'disabled' : 'neutral'} weight="strong">
93
- {label}{' '}
94
- {secondaryLabel && (
95
- <Text inline tone={disabled ? 'disabled' : 'muted'}>
96
- {secondaryLabel}
97
- </Text>
98
- )}
99
- </Text>
100
- </Box>
101
- ),
102
- 'reserve-space': (
103
- <Fragment>
104
- {hiddenLabel}
105
- <Text inline aria-hidden>
106
- &nbsp;
107
- </Text>
108
- </Fragment>
109
- ),
110
- };
111
-
112
- return (
113
- <FieldContextProvider value={fieldContext}>
114
- <Stack
115
- gap={labelVisibility === 'hidden' ? undefined : 'small'}
116
- ref={forwardedRef}
117
- {...(data ? buildDataAttributes(data) : null)}
118
- >
119
- <Box
120
- display="flex"
121
- alignItems="center"
122
- justifyContent="spaceBetween"
123
- gap="large"
124
- >
125
- {labelElement[labelVisibility]}
126
- {adornment}
127
- </Box>
128
-
129
- {description && (
130
- <Text tone="muted" size="small" id={descriptionId}>
131
- {description}
132
- </Text>
133
- )}
134
-
135
- {children}
136
-
137
- {message && (
138
- <FieldMessage tone={tone} id={messageId} message={message} />
139
- )}
140
- </Stack>
141
- </FieldContextProvider>
142
- );
143
- }
144
- );
145
- Field.displayName = 'Field';
146
-
147
- // Utils
148
- // ------------------------------
149
-
150
- export function useFieldIds(id?: string) {
151
- const inputId = useId(id);
152
- const descriptionId = composeId(inputId, 'description');
153
- const messageId = composeId(inputId, 'message');
154
-
155
- return { descriptionId, inputId, messageId };
156
- }
157
-
158
- // Styled components
159
- // ------------------------------
160
-
161
- const messageToneMap = {
162
- critical: 'critical',
163
- neutral: 'muted',
164
- positive: 'positive',
165
- } as const;
166
-
167
- // NOTE: use icons in addition to color for folks with visions issues
168
- const messageIconMap = {
169
- critical: ExclamationCircleIcon,
170
- neutral: null,
171
- positive: CheckCircleIcon,
172
- } as const;
173
-
174
- type FieldMessageProps = Required<Pick<FieldProps, 'message' | 'id' | 'tone'>>;
175
- export const FieldMessage = ({ message, id, tone }: FieldMessageProps) => {
176
- const textTone = messageToneMap[tone];
177
- const Icon = messageIconMap[tone];
178
-
179
- return (
180
- <Box display="flex" gap="xsmall">
181
- {Icon ? (
182
- <IndicatorContainer>
183
- <Icon size="xxsmall" tone={tone} />
184
- </IndicatorContainer>
185
- ) : null}
186
- <Text tone={textTone} size="small" id={id}>
187
- {message}
188
- </Text>
189
- </Box>
190
- );
191
- };
192
-
193
- function IndicatorContainer({ children, ...props }: { children: ReactNode }) {
194
- const { typography, utils } = useTheme();
195
- const { mobile, tablet } = typography.text.small;
196
- const responsiveStyles = utils.responsiveStyles({
197
- mobile: { height: mobile.capHeight },
198
- tablet: { height: tablet.capHeight },
199
- });
200
-
201
- return (
202
- <Box
203
- display="flex"
204
- alignItems="center"
205
- aria-hidden
206
- cursor="default"
207
- flexShrink={0}
208
- className={css(responsiveStyles)}
209
- {...props}
210
- >
211
- {children}
212
- </Box>
213
- );
214
- }
package/src/context.ts DELETED
@@ -1,24 +0,0 @@
1
- import { createContext, useContext } from 'react';
2
-
3
- export type FieldContextType = {
4
- 'aria-describedby'?: string;
5
- id: string;
6
- disabled: boolean;
7
- invalid: boolean;
8
- };
9
-
10
- export const FieldContext = createContext<FieldContextType | null>(null);
11
- export const FieldContextProvider = FieldContext.Provider;
12
-
13
- export const FIELD_CONTEXT_ERROR_MESSAGE =
14
- 'Input components must be inside a `Field`.';
15
-
16
- export function useFieldContext() {
17
- const ctx = useContext(FieldContext);
18
-
19
- if (!ctx) {
20
- throw new Error(FIELD_CONTEXT_ERROR_MESSAGE);
21
- }
22
-
23
- return ctx;
24
- }
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- export { useFieldContext } from './context';
2
- export { Field, FieldMessage, useFieldIds } from './Field';
3
-
4
- // types
5
-
6
- export type { FieldContextType } from './context';
7
- export type { FieldProps, Tone } from './Field';