@spark-web/field 0.0.0-snapshot-release-20260409001813
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +965 -0
- package/CLAUDE.md +80 -0
- package/README.md +132 -0
- package/dist/declarations/src/context.d.ts +15 -0
- package/dist/declarations/src/field.d.ts +53 -0
- package/dist/declarations/src/index.d.ts +4 -0
- package/dist/spark-web-field.cjs.d.ts +2 -0
- package/dist/spark-web-field.cjs.dev.js +212 -0
- package/dist/spark-web-field.cjs.js +7 -0
- package/dist/spark-web-field.cjs.prod.js +212 -0
- package/dist/spark-web-field.esm.js +204 -0
- package/package.json +39 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @spark-web/field — AI Context
|
|
2
|
+
|
|
3
|
+
## What this is
|
|
4
|
+
|
|
5
|
+
The form field wrapper. `Field` provides the label, optional description,
|
|
6
|
+
optional validation message, and the accessibility wiring (aria-describedby,
|
|
7
|
+
aria-invalid, id) that connects a label to its input. Every `TextInput`,
|
|
8
|
+
`Select`, and other form input **must** be wrapped in a `Field`.
|
|
9
|
+
|
|
10
|
+
## What this is NOT
|
|
11
|
+
|
|
12
|
+
- Not the input itself — `Field` only provides the label and context; the input
|
|
13
|
+
(`TextInput`, `Select`, etc.) is the `children`
|
|
14
|
+
- Not a layout component — use `Stack` or `Columns` to arrange multiple `Field`
|
|
15
|
+
components
|
|
16
|
+
|
|
17
|
+
## Props interface
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default | Notes |
|
|
20
|
+
| ----------------- | ------------------------------------------ | ----------- | --------------------------------------------------------------------------------------- |
|
|
21
|
+
| `label` | `string` | required | Always required — used for accessibility even if hidden |
|
|
22
|
+
| `labelVisibility` | `'visible' \| 'hidden' \| 'reserve-space'` | `'visible'` | `'hidden'` hides visually but keeps accessible; `'reserve-space'` reserves layout space |
|
|
23
|
+
| `description` | `string \| ReactNode` | — | Hint text rendered below the label |
|
|
24
|
+
| `message` | `string` | — | Validation message; tone controls its appearance |
|
|
25
|
+
| `tone` | `'neutral' \| 'critical' \| 'positive'` | `'neutral'` | `'critical'` marks the input invalid |
|
|
26
|
+
| `secondaryLabel` | `string` | — | Supplementary label text (e.g. "Optional") |
|
|
27
|
+
| `disabled` | `boolean` | `false` | Disables the child input via context |
|
|
28
|
+
| `readOnly` | `boolean` | `false` | Makes the child input read-only via context |
|
|
29
|
+
| `adornment` | `ReactElement` | — | Utility element placed inline with the label (e.g. tooltip) |
|
|
30
|
+
| `data` | `DataAttributeMap` | — | Test/analytics attributes |
|
|
31
|
+
|
|
32
|
+
## Common patterns
|
|
33
|
+
|
|
34
|
+
### Standard labeled input
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<Field label="Email address">
|
|
38
|
+
<TextInput type="email" placeholder="you@example.com" />
|
|
39
|
+
</Field>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Hidden label (filter context)
|
|
43
|
+
|
|
44
|
+
Use `labelVisibility="hidden"` when the placeholder or surrounding context makes
|
|
45
|
+
the label redundant visually, but the label is still required for a11y:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
<Field label="Search users" labelVisibility="hidden">
|
|
49
|
+
<TextInput placeholder="Search users">
|
|
50
|
+
<InputAdornment placement="start">
|
|
51
|
+
<SearchIcon size="xsmall" tone="placeholder" />
|
|
52
|
+
</InputAdornment>
|
|
53
|
+
</TextInput>
|
|
54
|
+
</Field>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Validation state
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
<Field label="Password" tone="critical" message="Password is required">
|
|
61
|
+
<TextInput type="password" />
|
|
62
|
+
</Field>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Optional field
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<Field label="Phone number" secondaryLabel="Optional">
|
|
69
|
+
<TextInput type="tel" />
|
|
70
|
+
</Field>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Do NOTs
|
|
74
|
+
|
|
75
|
+
- NEVER use `TextInput` or `Select` without wrapping them in `Field`
|
|
76
|
+
- NEVER omit `label` — it is always required for accessibility, even with
|
|
77
|
+
`labelVisibility="hidden"`
|
|
78
|
+
- NEVER pass `id` to the input directly — `Field` manages the id via context
|
|
79
|
+
- NEVER use `tone="critical"` without also providing `message` — the tone alone
|
|
80
|
+
does not communicate the error to the user
|
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Field
|
|
3
|
+
isExperimentalPackage: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Using context, the field component connects the label, description, and message
|
|
7
|
+
to the input element.
|
|
8
|
+
|
|
9
|
+
```jsx live
|
|
10
|
+
<Field label="Label">
|
|
11
|
+
<TextInput />
|
|
12
|
+
</Field>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
### Label
|
|
18
|
+
|
|
19
|
+
Each field must be accompanied by a label. Effective form labeling helps users
|
|
20
|
+
understand what information to enter into an input.
|
|
21
|
+
|
|
22
|
+
Using placeholder text in lieu of a label is sometimes employed as a
|
|
23
|
+
space-saving method. However, this is not recommended because it hides context
|
|
24
|
+
and presents accessibility issues.
|
|
25
|
+
|
|
26
|
+
```jsx live
|
|
27
|
+
<Field label="Name">
|
|
28
|
+
<TextInput />
|
|
29
|
+
</Field>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### Label visibility
|
|
33
|
+
|
|
34
|
+
The label must always be provided for assistive technology, but you may hide it
|
|
35
|
+
from sighted users when the intent can be inferred from context.
|
|
36
|
+
|
|
37
|
+
```jsx live
|
|
38
|
+
<Stack gap="xlarge">
|
|
39
|
+
<Field label="Name" labelVisibility="hidden">
|
|
40
|
+
<TextInput placeholder="hidden" />
|
|
41
|
+
</Field>
|
|
42
|
+
<Columns gap="small">
|
|
43
|
+
<Field label="Name">
|
|
44
|
+
<TextInput placeholder="visible" />
|
|
45
|
+
</Field>
|
|
46
|
+
<Field label="Name" labelVisibility="reserve-space">
|
|
47
|
+
<TextInput placeholder="reserve-space" />
|
|
48
|
+
</Field>
|
|
49
|
+
</Columns>
|
|
50
|
+
</Stack>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Secondary label
|
|
54
|
+
|
|
55
|
+
Provide additional context, typically used to indicate that the field is
|
|
56
|
+
optional.
|
|
57
|
+
|
|
58
|
+
```jsx live
|
|
59
|
+
<Field label="Name" secondaryLabel="(Optional)">
|
|
60
|
+
<TextInput />
|
|
61
|
+
</Field>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Adornment
|
|
65
|
+
|
|
66
|
+
Optionally provide a utility or contextual hint, related to the field.
|
|
67
|
+
|
|
68
|
+
```jsx live
|
|
69
|
+
<Field
|
|
70
|
+
label="Username"
|
|
71
|
+
adornment={
|
|
72
|
+
<Text>
|
|
73
|
+
<TextLink href="#">Forgot username?</TextLink>
|
|
74
|
+
</Text>
|
|
75
|
+
}
|
|
76
|
+
>
|
|
77
|
+
<TextInput />
|
|
78
|
+
</Field>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Description
|
|
82
|
+
|
|
83
|
+
Provides pertinent information that assists the user in completing a field.
|
|
84
|
+
Description text is always visible and appears underneath the label. Use
|
|
85
|
+
sentence-style capitalisation, and in most cases, write the text as full
|
|
86
|
+
sentences with punctuation.
|
|
87
|
+
|
|
88
|
+
```jsx live
|
|
89
|
+
<Field
|
|
90
|
+
label="Email"
|
|
91
|
+
description="We take your privacy seriously. We will never give your email to a third party."
|
|
92
|
+
>
|
|
93
|
+
<TextInput type="email" />
|
|
94
|
+
</Field>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Message and tone
|
|
98
|
+
|
|
99
|
+
The “message” is used to communicate the status of a field, such as an error
|
|
100
|
+
message. This will be announced on focus and can be combined with a “tone” to
|
|
101
|
+
illustrate intent.
|
|
102
|
+
|
|
103
|
+
```jsx live
|
|
104
|
+
<Stack gap="xlarge">
|
|
105
|
+
<Field label="Label" tone="critical" message="Critical message">
|
|
106
|
+
<TextInput />
|
|
107
|
+
</Field>
|
|
108
|
+
<Field label="Label" tone="positive" message="Positive message">
|
|
109
|
+
<TextInput />
|
|
110
|
+
</Field>
|
|
111
|
+
<Field label="Label" tone="neutral" message="Neutral message">
|
|
112
|
+
<TextInput />
|
|
113
|
+
</Field>
|
|
114
|
+
</Stack>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Disabled
|
|
118
|
+
|
|
119
|
+
Mark the field as disabled by passing true to the disabled prop.
|
|
120
|
+
|
|
121
|
+
```jsx live
|
|
122
|
+
<Field label="Label" secondaryLabel="Secondary label" disabled>
|
|
123
|
+
<TextInput value="Text in disabled field" />
|
|
124
|
+
</Field>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Props
|
|
128
|
+
|
|
129
|
+
<PropsTable displayName="Field" />
|
|
130
|
+
|
|
131
|
+
[data-attribute-map]:
|
|
132
|
+
https://github.com/brighte-labs/spark-web/blob/e7f6f4285b4cfd876312cc89fbdd094039aa239a/packages/utils/src/internal/buildDataAttributes.ts#L1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type FieldState = {
|
|
2
|
+
disabled: boolean;
|
|
3
|
+
invalid: boolean;
|
|
4
|
+
readOnly?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type InputPropsDerivedFromField = {
|
|
7
|
+
'aria-describedby'?: string;
|
|
8
|
+
'aria-invalid': true | undefined;
|
|
9
|
+
id: string;
|
|
10
|
+
};
|
|
11
|
+
export type FieldContextType = [FieldState, InputPropsDerivedFromField];
|
|
12
|
+
export declare const FieldContext: import("react").Context<FieldContextType | null>;
|
|
13
|
+
export declare const FieldContextProvider: import("react").Provider<FieldContextType | null>;
|
|
14
|
+
export declare const FIELD_CONTEXT_ERROR_MESSAGE = "Input components must be inside a `Field`.";
|
|
15
|
+
export declare function useFieldContext(): FieldContextType;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { DataAttributeMap } from '@spark-web/utils/internal';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
export type Tone = keyof typeof messageToneMap;
|
|
4
|
+
export type FieldProps = {
|
|
5
|
+
/** Sets a unique identifier for the component. */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Sets data attributes on the component. */
|
|
8
|
+
data?: DataAttributeMap;
|
|
9
|
+
/** Optionally provide a utility or contextual hint, related to the field. */
|
|
10
|
+
adornment?: ReactElement;
|
|
11
|
+
/** Input component */
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Indicates that the field is perceivable but disabled, so it is not editable
|
|
15
|
+
* or otherwise operable.
|
|
16
|
+
*/
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/** Provide additional information that will aid user input. */
|
|
19
|
+
description?: string | ReactNode;
|
|
20
|
+
/** Concisely label the field. */
|
|
21
|
+
label: string;
|
|
22
|
+
/**
|
|
23
|
+
* The label must always be provided for assistive technology, but you may
|
|
24
|
+
* hide it from sighted users when the intent can be inferred from context.
|
|
25
|
+
*/
|
|
26
|
+
labelVisibility?: 'hidden' | 'reserve-space' | 'visible';
|
|
27
|
+
/** Provide a message, informing the user about changes in state. */
|
|
28
|
+
message?: string;
|
|
29
|
+
/** Additional context, typically used to indicate that the field is optional. */
|
|
30
|
+
secondaryLabel?: string;
|
|
31
|
+
/** Provide a tone to influence elements of the field, and its input. */
|
|
32
|
+
tone?: Tone;
|
|
33
|
+
/** Sets input to readonly, which is focusable. */
|
|
34
|
+
readOnly?: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Using a [context](https://reactjs.org/docs/context.html), the field
|
|
38
|
+
* component connects the label, description, and message to the input element.
|
|
39
|
+
*/
|
|
40
|
+
export declare const Field: import("react").ForwardRefExoticComponent<FieldProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
41
|
+
export declare function useFieldIds(id?: string): {
|
|
42
|
+
descriptionId: string;
|
|
43
|
+
inputId: string;
|
|
44
|
+
messageId: string;
|
|
45
|
+
};
|
|
46
|
+
declare const messageToneMap: {
|
|
47
|
+
readonly critical: "critical";
|
|
48
|
+
readonly neutral: "muted";
|
|
49
|
+
readonly positive: "positive";
|
|
50
|
+
};
|
|
51
|
+
type FieldMessageProps = Required<Pick<FieldProps, 'message' | 'id' | 'tone'>>;
|
|
52
|
+
export declare const FieldMessage: ({ message, id, tone }: FieldMessageProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FieldContextProvider, useFieldContext } from "./context.js";
|
|
2
|
+
export { Field, FieldMessage, useFieldIds } from "./field.js";
|
|
3
|
+
export type { FieldContextType, FieldState, InputPropsDerivedFromField, } from "./context.js";
|
|
4
|
+
export type { FieldProps, Tone } from "./field.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./declarations/src/index.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Bhcmstd2ViLWZpZWxkLmNqcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi9kZWNsYXJhdGlvbnMvc3JjL2luZGV4LmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEifQ==
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var react$1 = require('@emotion/react');
|
|
7
|
+
var a11y = require('@spark-web/a11y');
|
|
8
|
+
var box = require('@spark-web/box');
|
|
9
|
+
var icon = require('@spark-web/icon');
|
|
10
|
+
var stack = require('@spark-web/stack');
|
|
11
|
+
var text = require('@spark-web/text');
|
|
12
|
+
var theme = require('@spark-web/theme');
|
|
13
|
+
var jsxRuntime = require('@emotion/react/jsx-runtime');
|
|
14
|
+
|
|
15
|
+
var FieldContext = /*#__PURE__*/react.createContext(null);
|
|
16
|
+
var FieldContextProvider = FieldContext.Provider;
|
|
17
|
+
var FIELD_CONTEXT_ERROR_MESSAGE = 'Input components must be inside a `Field`.';
|
|
18
|
+
function useFieldContext() {
|
|
19
|
+
var ctx = react.useContext(FieldContext);
|
|
20
|
+
if (!ctx) {
|
|
21
|
+
throw new Error(FIELD_CONTEXT_ERROR_MESSAGE);
|
|
22
|
+
}
|
|
23
|
+
return ctx;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Using a [context](https://reactjs.org/docs/context.html), the field
|
|
28
|
+
* component connects the label, description, and message to the input element.
|
|
29
|
+
*/
|
|
30
|
+
var Field = /*#__PURE__*/react.forwardRef(function (_ref, forwardedRef) {
|
|
31
|
+
var children = _ref.children,
|
|
32
|
+
idProp = _ref.id,
|
|
33
|
+
data = _ref.data,
|
|
34
|
+
description = _ref.description,
|
|
35
|
+
_ref$disabled = _ref.disabled,
|
|
36
|
+
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
|
|
37
|
+
label = _ref.label,
|
|
38
|
+
adornment = _ref.adornment,
|
|
39
|
+
_ref$labelVisibility = _ref.labelVisibility,
|
|
40
|
+
labelVisibility = _ref$labelVisibility === void 0 ? 'visible' : _ref$labelVisibility,
|
|
41
|
+
message = _ref.message,
|
|
42
|
+
secondaryLabel = _ref.secondaryLabel,
|
|
43
|
+
_ref$tone = _ref.tone,
|
|
44
|
+
tone = _ref$tone === void 0 ? 'neutral' : _ref$tone,
|
|
45
|
+
_ref$readOnly = _ref.readOnly,
|
|
46
|
+
readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly;
|
|
47
|
+
var _useFieldIds = useFieldIds(idProp),
|
|
48
|
+
descriptionId = _useFieldIds.descriptionId,
|
|
49
|
+
inputId = _useFieldIds.inputId,
|
|
50
|
+
messageId = _useFieldIds.messageId;
|
|
51
|
+
|
|
52
|
+
// field context
|
|
53
|
+
var invalid = Boolean(message && tone === 'critical');
|
|
54
|
+
var fieldContext = react.useMemo(function () {
|
|
55
|
+
return [{
|
|
56
|
+
disabled: disabled,
|
|
57
|
+
invalid: invalid,
|
|
58
|
+
readOnly: readOnly
|
|
59
|
+
}, {
|
|
60
|
+
'aria-describedby': a11y.mergeIds(message && messageId, description ? descriptionId : undefined),
|
|
61
|
+
'aria-invalid': invalid || undefined,
|
|
62
|
+
id: inputId
|
|
63
|
+
}];
|
|
64
|
+
}, [description, descriptionId, disabled, inputId, invalid, message, messageId, readOnly]);
|
|
65
|
+
|
|
66
|
+
// label prep
|
|
67
|
+
var hiddenLabel = jsxRuntime.jsxs(a11y.VisuallyHidden, {
|
|
68
|
+
as: "label",
|
|
69
|
+
htmlFor: inputId,
|
|
70
|
+
children: [label, " ", secondaryLabel]
|
|
71
|
+
});
|
|
72
|
+
var labelElement = {
|
|
73
|
+
hidden: hiddenLabel,
|
|
74
|
+
visible: jsxRuntime.jsx(box.Box, {
|
|
75
|
+
as: "label",
|
|
76
|
+
htmlFor: inputId,
|
|
77
|
+
children: jsxRuntime.jsxs(text.Text, {
|
|
78
|
+
tone: disabled || readOnly ? 'field' : 'neutral',
|
|
79
|
+
weight: "semibold",
|
|
80
|
+
children: [label, ' ', secondaryLabel && jsxRuntime.jsx(text.Text, {
|
|
81
|
+
inline: true,
|
|
82
|
+
tone: disabled || readOnly ? 'field' : 'muted',
|
|
83
|
+
weight: "regular",
|
|
84
|
+
children: secondaryLabel
|
|
85
|
+
})]
|
|
86
|
+
})
|
|
87
|
+
}),
|
|
88
|
+
'reserve-space': jsxRuntime.jsxs(react.Fragment, {
|
|
89
|
+
children: [hiddenLabel, jsxRuntime.jsx(text.Text, {
|
|
90
|
+
"aria-hidden": true,
|
|
91
|
+
children: "\xA0"
|
|
92
|
+
})]
|
|
93
|
+
})
|
|
94
|
+
};
|
|
95
|
+
var LabelWrapper = labelVisibility === 'hidden' ? react.Fragment : FieldLabelWrapper;
|
|
96
|
+
return jsxRuntime.jsx(FieldContextProvider, {
|
|
97
|
+
value: fieldContext,
|
|
98
|
+
children: jsxRuntime.jsxs(stack.Stack, {
|
|
99
|
+
ref: forwardedRef,
|
|
100
|
+
data: data,
|
|
101
|
+
gap: "medium",
|
|
102
|
+
children: [jsxRuntime.jsxs(LabelWrapper, {
|
|
103
|
+
children: [labelElement[labelVisibility], adornment]
|
|
104
|
+
}), description && (typeof description === 'string' ? jsxRuntime.jsx(text.Text, {
|
|
105
|
+
tone: "muted",
|
|
106
|
+
size: "small",
|
|
107
|
+
id: descriptionId,
|
|
108
|
+
children: description
|
|
109
|
+
}) : jsxRuntime.jsx(box.Box, {
|
|
110
|
+
as: "label",
|
|
111
|
+
htmlFor: descriptionId,
|
|
112
|
+
children: description
|
|
113
|
+
})), children, message && jsxRuntime.jsx(FieldMessage, {
|
|
114
|
+
tone: tone,
|
|
115
|
+
id: messageId,
|
|
116
|
+
message: message
|
|
117
|
+
})]
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
Field.displayName = 'Field';
|
|
122
|
+
|
|
123
|
+
// Utils
|
|
124
|
+
// ------------------------------
|
|
125
|
+
|
|
126
|
+
function useFieldIds(id) {
|
|
127
|
+
var inputId = a11y.useId(id);
|
|
128
|
+
var descriptionId = a11y.composeId(inputId, 'description');
|
|
129
|
+
var messageId = a11y.composeId(inputId, 'message');
|
|
130
|
+
return {
|
|
131
|
+
descriptionId: descriptionId,
|
|
132
|
+
inputId: inputId,
|
|
133
|
+
messageId: messageId
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Styled components
|
|
138
|
+
// ------------------------------
|
|
139
|
+
function FieldLabelWrapper(_ref2) {
|
|
140
|
+
var children = _ref2.children;
|
|
141
|
+
return jsxRuntime.jsx(box.Box, {
|
|
142
|
+
display: "flex",
|
|
143
|
+
alignItems: "center",
|
|
144
|
+
justifyContent: "spaceBetween",
|
|
145
|
+
gap: "large",
|
|
146
|
+
children: children
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
var messageToneMap = {
|
|
150
|
+
critical: 'critical',
|
|
151
|
+
neutral: 'muted',
|
|
152
|
+
positive: 'positive'
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// NOTE: use icons in addition to color for folks with visions issues
|
|
156
|
+
var messageIconMap = {
|
|
157
|
+
critical: icon.ExclamationCircleIcon,
|
|
158
|
+
neutral: null,
|
|
159
|
+
positive: icon.CheckCircleIcon
|
|
160
|
+
};
|
|
161
|
+
var FieldMessage = function FieldMessage(_ref3) {
|
|
162
|
+
var message = _ref3.message,
|
|
163
|
+
id = _ref3.id,
|
|
164
|
+
tone = _ref3.tone;
|
|
165
|
+
var textTone = messageToneMap[tone];
|
|
166
|
+
var Icon = messageIconMap[tone];
|
|
167
|
+
return jsxRuntime.jsxs(box.Box, {
|
|
168
|
+
display: "flex",
|
|
169
|
+
gap: "xsmall",
|
|
170
|
+
children: [Icon ? jsxRuntime.jsx(IndicatorContainer, {
|
|
171
|
+
children: jsxRuntime.jsx(Icon, {
|
|
172
|
+
size: "xxsmall",
|
|
173
|
+
tone: tone
|
|
174
|
+
})
|
|
175
|
+
}) : null, jsxRuntime.jsx(text.Text, {
|
|
176
|
+
tone: textTone,
|
|
177
|
+
size: "small",
|
|
178
|
+
id: id,
|
|
179
|
+
children: message
|
|
180
|
+
})]
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
function IndicatorContainer(_ref4) {
|
|
184
|
+
var children = _ref4.children;
|
|
185
|
+
var theme$1 = theme.useTheme();
|
|
186
|
+
var _theme$typography$tex = theme$1.typography.text.small,
|
|
187
|
+
mobile = _theme$typography$tex.mobile,
|
|
188
|
+
tablet = _theme$typography$tex.tablet;
|
|
189
|
+
var responsiveStyles = theme$1.utils.responsiveStyles({
|
|
190
|
+
mobile: {
|
|
191
|
+
height: mobile.capHeight
|
|
192
|
+
},
|
|
193
|
+
tablet: {
|
|
194
|
+
height: tablet.capHeight
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return jsxRuntime.jsx(box.Box, {
|
|
198
|
+
display: "flex",
|
|
199
|
+
alignItems: "center",
|
|
200
|
+
"aria-hidden": true,
|
|
201
|
+
cursor: "default",
|
|
202
|
+
flexShrink: 0,
|
|
203
|
+
css: react$1.css(responsiveStyles),
|
|
204
|
+
children: children
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
exports.Field = Field;
|
|
209
|
+
exports.FieldContextProvider = FieldContextProvider;
|
|
210
|
+
exports.FieldMessage = FieldMessage;
|
|
211
|
+
exports.useFieldContext = useFieldContext;
|
|
212
|
+
exports.useFieldIds = useFieldIds;
|