@seed-design/react-field 1.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.
@@ -0,0 +1,196 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { composeRefs } from '@radix-ui/react-compose-refs';
4
+ import { elementProps, dataAttr, inputProps, labelProps, ariaAttr, mergeProps } from '@seed-design/dom-utils';
5
+ import { Primitive } from '@seed-design/react-primitive';
6
+ import { useId, useState, useCallback, createContext, useContext, forwardRef } from 'react';
7
+
8
+ const getLabelId = (id)=>`field:${id}:label`;
9
+ const getInputId = (id)=>`field:${id}:input`;
10
+ const getDescriptionId = (id)=>`field:${id}:description`;
11
+ const getErrorMessageId = (id)=>`field:${id}:error-message`;
12
+
13
+ function useFieldState() {
14
+ const [isHovered, setIsHovered] = useState(false);
15
+ const [isActive, setIsActive] = useState(false);
16
+ const [isFocused, setIsFocused] = useState(false);
17
+ const [isFocusVisible, setIsFocusVisible] = useState(false);
18
+ const [isLabelRendered, setIsLabelRendered] = useState(false);
19
+ const labelRef = useCallback((node)=>{
20
+ setIsLabelRendered(!!node);
21
+ }, []);
22
+ const [isDescriptionRendered, setIsDescriptionRendered] = useState(false);
23
+ const descriptionRef = useCallback((node)=>{
24
+ setIsDescriptionRendered(!!node);
25
+ }, []);
26
+ const [isErrorMessageRendered, setIsErrorMessageRendered] = useState(false);
27
+ const errorMessageRef = useCallback((node)=>{
28
+ setIsErrorMessageRendered(!!node);
29
+ }, []);
30
+ return {
31
+ refs: {
32
+ label: labelRef,
33
+ description: descriptionRef,
34
+ errorMessage: errorMessageRef
35
+ },
36
+ isHovered,
37
+ isActive,
38
+ isFocused,
39
+ isFocusVisible,
40
+ renderedElements: {
41
+ label: isLabelRendered,
42
+ description: isDescriptionRendered,
43
+ errorMessage: isErrorMessageRendered
44
+ },
45
+ setIsHovered,
46
+ setIsActive,
47
+ setIsFocused,
48
+ setIsFocusVisible
49
+ };
50
+ }
51
+ function useField(props) {
52
+ const id = useId();
53
+ const { disabled = false, invalid = false, readOnly = false, required = false } = props;
54
+ const { refs, renderedElements, isHovered, isActive, isFocused, isFocusVisible, setIsHovered, setIsActive, setIsFocused, setIsFocusVisible } = useFieldState();
55
+ const ariaDescribedBy = [
56
+ renderedElements.description ? getDescriptionId(id) : false,
57
+ renderedElements.errorMessage ? getErrorMessageId(id) : false
58
+ ].filter(Boolean).join(" ") || undefined;
59
+ const stateProps = elementProps({
60
+ "data-hover": dataAttr(isHovered),
61
+ "data-active": dataAttr(isActive),
62
+ "data-focus": dataAttr(isFocused),
63
+ "data-focus-visible": dataAttr(isFocusVisible),
64
+ "data-readonly": dataAttr(readOnly),
65
+ "data-disabled": dataAttr(disabled),
66
+ "data-invalid": dataAttr(invalid)
67
+ });
68
+ return {
69
+ refs,
70
+ active: isActive,
71
+ focused: isFocused,
72
+ invalid,
73
+ required,
74
+ setIsFocused,
75
+ setIsFocusVisible,
76
+ stateProps,
77
+ rootProps: elementProps({
78
+ ...stateProps,
79
+ onPointerMove () {
80
+ setIsHovered(true);
81
+ },
82
+ onPointerDown () {
83
+ setIsActive(true);
84
+ },
85
+ onPointerUp () {
86
+ setIsActive(false);
87
+ },
88
+ onPointerLeave () {
89
+ setIsHovered(false);
90
+ setIsActive(false);
91
+ }
92
+ }),
93
+ labelProps: labelProps({
94
+ ...stateProps,
95
+ id: getLabelId(id),
96
+ htmlFor: getInputId(id)
97
+ }),
98
+ inputProps: inputProps({
99
+ disabled,
100
+ readOnly,
101
+ name: props.name || id,
102
+ id: getInputId(id)
103
+ }),
104
+ inputAriaAttributes: elementProps({
105
+ ...renderedElements.label && {
106
+ "aria-labelledby": getLabelId(id)
107
+ },
108
+ "aria-describedby": ariaDescribedBy,
109
+ "aria-required": ariaAttr(required),
110
+ "aria-invalid": ariaAttr(invalid),
111
+ "aria-readonly": ariaAttr(readOnly),
112
+ "aria-disabled": ariaAttr(disabled)
113
+ }),
114
+ inputHandlers: inputProps({
115
+ onChange: (event)=>{
116
+ setIsFocusVisible(event.target.matches(":focus-visible"));
117
+ },
118
+ onBlur () {
119
+ setIsFocused(false);
120
+ setIsFocusVisible(false);
121
+ },
122
+ onFocus (event) {
123
+ setIsFocused(true);
124
+ setIsFocusVisible(event.target.matches(":focus-visible"));
125
+ }
126
+ }),
127
+ descriptionProps: elementProps({
128
+ ...stateProps,
129
+ id: getDescriptionId(id)
130
+ }),
131
+ errorMessageProps: elementProps({
132
+ ...stateProps,
133
+ id: getErrorMessageId(id),
134
+ "aria-live": "polite"
135
+ })
136
+ };
137
+ }
138
+
139
+ const FieldContext = /*#__PURE__*/ createContext(null);
140
+ const FieldProvider = FieldContext.Provider;
141
+ function useFieldContext({ strict = true } = {}) {
142
+ const context = useContext(FieldContext);
143
+ if (!context && strict) {
144
+ throw new Error("useFieldContext must be used within a Field");
145
+ }
146
+ return context;
147
+ }
148
+
149
+ const FieldRoot = /*#__PURE__*/ forwardRef((props, ref)=>{
150
+ const { readOnly, disabled, invalid, required, name, ...otherProps } = props;
151
+ const api = useField({
152
+ disabled,
153
+ invalid,
154
+ required,
155
+ readOnly,
156
+ name
157
+ });
158
+ const mergedProps = mergeProps(api.rootProps, otherProps);
159
+ return /*#__PURE__*/ jsx(FieldProvider, {
160
+ value: api,
161
+ children: /*#__PURE__*/ jsx(Primitive.div, {
162
+ ref: ref,
163
+ ...mergedProps
164
+ })
165
+ });
166
+ });
167
+ FieldRoot.displayName = "FieldRoot";
168
+ const FieldLabel = /*#__PURE__*/ forwardRef((props, ref)=>{
169
+ const { refs, labelProps } = useFieldContext();
170
+ const mergedProps = mergeProps(labelProps, props);
171
+ return /*#__PURE__*/ jsx(Primitive.label, {
172
+ ref: composeRefs(refs.label, ref),
173
+ ...mergedProps
174
+ });
175
+ });
176
+ FieldLabel.displayName = "FieldLabel";
177
+ const FieldDescription = /*#__PURE__*/ forwardRef((props, ref)=>{
178
+ const { refs, descriptionProps } = useFieldContext();
179
+ const mergedProps = mergeProps(descriptionProps, props);
180
+ return /*#__PURE__*/ jsx(Primitive.span, {
181
+ ref: composeRefs(refs.description, ref),
182
+ ...mergedProps
183
+ });
184
+ });
185
+ FieldDescription.displayName = "FieldDescription";
186
+ const FieldErrorMessage = /*#__PURE__*/ forwardRef((props, ref)=>{
187
+ const { refs, errorMessageProps } = useFieldContext();
188
+ const mergedProps = mergeProps(errorMessageProps, props);
189
+ return /*#__PURE__*/ jsx(Primitive.div, {
190
+ ref: composeRefs(refs.errorMessage, ref),
191
+ ...mergedProps
192
+ });
193
+ });
194
+ FieldErrorMessage.displayName = "FieldErrorMessage";
195
+
196
+ export { FieldDescription as F, FieldErrorMessage as a, FieldLabel as b, FieldRoot as c, useFieldContext as u };
@@ -0,0 +1,200 @@
1
+ 'use client';
2
+ var jsxRuntime = require('react/jsx-runtime');
3
+ var reactComposeRefs = require('@radix-ui/react-compose-refs');
4
+ var domUtils = require('@seed-design/dom-utils');
5
+ var reactPrimitive = require('@seed-design/react-primitive');
6
+ var react = require('react');
7
+
8
+ const getLabelId = (id)=>`field:${id}:label`;
9
+ const getInputId = (id)=>`field:${id}:input`;
10
+ const getDescriptionId = (id)=>`field:${id}:description`;
11
+ const getErrorMessageId = (id)=>`field:${id}:error-message`;
12
+
13
+ function useFieldState() {
14
+ const [isHovered, setIsHovered] = react.useState(false);
15
+ const [isActive, setIsActive] = react.useState(false);
16
+ const [isFocused, setIsFocused] = react.useState(false);
17
+ const [isFocusVisible, setIsFocusVisible] = react.useState(false);
18
+ const [isLabelRendered, setIsLabelRendered] = react.useState(false);
19
+ const labelRef = react.useCallback((node)=>{
20
+ setIsLabelRendered(!!node);
21
+ }, []);
22
+ const [isDescriptionRendered, setIsDescriptionRendered] = react.useState(false);
23
+ const descriptionRef = react.useCallback((node)=>{
24
+ setIsDescriptionRendered(!!node);
25
+ }, []);
26
+ const [isErrorMessageRendered, setIsErrorMessageRendered] = react.useState(false);
27
+ const errorMessageRef = react.useCallback((node)=>{
28
+ setIsErrorMessageRendered(!!node);
29
+ }, []);
30
+ return {
31
+ refs: {
32
+ label: labelRef,
33
+ description: descriptionRef,
34
+ errorMessage: errorMessageRef
35
+ },
36
+ isHovered,
37
+ isActive,
38
+ isFocused,
39
+ isFocusVisible,
40
+ renderedElements: {
41
+ label: isLabelRendered,
42
+ description: isDescriptionRendered,
43
+ errorMessage: isErrorMessageRendered
44
+ },
45
+ setIsHovered,
46
+ setIsActive,
47
+ setIsFocused,
48
+ setIsFocusVisible
49
+ };
50
+ }
51
+ function useField(props) {
52
+ const id = react.useId();
53
+ const { disabled = false, invalid = false, readOnly = false, required = false } = props;
54
+ const { refs, renderedElements, isHovered, isActive, isFocused, isFocusVisible, setIsHovered, setIsActive, setIsFocused, setIsFocusVisible } = useFieldState();
55
+ const ariaDescribedBy = [
56
+ renderedElements.description ? getDescriptionId(id) : false,
57
+ renderedElements.errorMessage ? getErrorMessageId(id) : false
58
+ ].filter(Boolean).join(" ") || undefined;
59
+ const stateProps = domUtils.elementProps({
60
+ "data-hover": domUtils.dataAttr(isHovered),
61
+ "data-active": domUtils.dataAttr(isActive),
62
+ "data-focus": domUtils.dataAttr(isFocused),
63
+ "data-focus-visible": domUtils.dataAttr(isFocusVisible),
64
+ "data-readonly": domUtils.dataAttr(readOnly),
65
+ "data-disabled": domUtils.dataAttr(disabled),
66
+ "data-invalid": domUtils.dataAttr(invalid)
67
+ });
68
+ return {
69
+ refs,
70
+ active: isActive,
71
+ focused: isFocused,
72
+ invalid,
73
+ required,
74
+ setIsFocused,
75
+ setIsFocusVisible,
76
+ stateProps,
77
+ rootProps: domUtils.elementProps({
78
+ ...stateProps,
79
+ onPointerMove () {
80
+ setIsHovered(true);
81
+ },
82
+ onPointerDown () {
83
+ setIsActive(true);
84
+ },
85
+ onPointerUp () {
86
+ setIsActive(false);
87
+ },
88
+ onPointerLeave () {
89
+ setIsHovered(false);
90
+ setIsActive(false);
91
+ }
92
+ }),
93
+ labelProps: domUtils.labelProps({
94
+ ...stateProps,
95
+ id: getLabelId(id),
96
+ htmlFor: getInputId(id)
97
+ }),
98
+ inputProps: domUtils.inputProps({
99
+ disabled,
100
+ readOnly,
101
+ name: props.name || id,
102
+ id: getInputId(id)
103
+ }),
104
+ inputAriaAttributes: domUtils.elementProps({
105
+ ...renderedElements.label && {
106
+ "aria-labelledby": getLabelId(id)
107
+ },
108
+ "aria-describedby": ariaDescribedBy,
109
+ "aria-required": domUtils.ariaAttr(required),
110
+ "aria-invalid": domUtils.ariaAttr(invalid),
111
+ "aria-readonly": domUtils.ariaAttr(readOnly),
112
+ "aria-disabled": domUtils.ariaAttr(disabled)
113
+ }),
114
+ inputHandlers: domUtils.inputProps({
115
+ onChange: (event)=>{
116
+ setIsFocusVisible(event.target.matches(":focus-visible"));
117
+ },
118
+ onBlur () {
119
+ setIsFocused(false);
120
+ setIsFocusVisible(false);
121
+ },
122
+ onFocus (event) {
123
+ setIsFocused(true);
124
+ setIsFocusVisible(event.target.matches(":focus-visible"));
125
+ }
126
+ }),
127
+ descriptionProps: domUtils.elementProps({
128
+ ...stateProps,
129
+ id: getDescriptionId(id)
130
+ }),
131
+ errorMessageProps: domUtils.elementProps({
132
+ ...stateProps,
133
+ id: getErrorMessageId(id),
134
+ "aria-live": "polite"
135
+ })
136
+ };
137
+ }
138
+
139
+ const FieldContext = /*#__PURE__*/ react.createContext(null);
140
+ const FieldProvider = FieldContext.Provider;
141
+ function useFieldContext({ strict = true } = {}) {
142
+ const context = react.useContext(FieldContext);
143
+ if (!context && strict) {
144
+ throw new Error("useFieldContext must be used within a Field");
145
+ }
146
+ return context;
147
+ }
148
+
149
+ const FieldRoot = /*#__PURE__*/ react.forwardRef((props, ref)=>{
150
+ const { readOnly, disabled, invalid, required, name, ...otherProps } = props;
151
+ const api = useField({
152
+ disabled,
153
+ invalid,
154
+ required,
155
+ readOnly,
156
+ name
157
+ });
158
+ const mergedProps = domUtils.mergeProps(api.rootProps, otherProps);
159
+ return /*#__PURE__*/ jsxRuntime.jsx(FieldProvider, {
160
+ value: api,
161
+ children: /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
162
+ ref: ref,
163
+ ...mergedProps
164
+ })
165
+ });
166
+ });
167
+ FieldRoot.displayName = "FieldRoot";
168
+ const FieldLabel = /*#__PURE__*/ react.forwardRef((props, ref)=>{
169
+ const { refs, labelProps } = useFieldContext();
170
+ const mergedProps = domUtils.mergeProps(labelProps, props);
171
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.label, {
172
+ ref: reactComposeRefs.composeRefs(refs.label, ref),
173
+ ...mergedProps
174
+ });
175
+ });
176
+ FieldLabel.displayName = "FieldLabel";
177
+ const FieldDescription = /*#__PURE__*/ react.forwardRef((props, ref)=>{
178
+ const { refs, descriptionProps } = useFieldContext();
179
+ const mergedProps = domUtils.mergeProps(descriptionProps, props);
180
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.span, {
181
+ ref: reactComposeRefs.composeRefs(refs.description, ref),
182
+ ...mergedProps
183
+ });
184
+ });
185
+ FieldDescription.displayName = "FieldDescription";
186
+ const FieldErrorMessage = /*#__PURE__*/ react.forwardRef((props, ref)=>{
187
+ const { refs, errorMessageProps } = useFieldContext();
188
+ const mergedProps = domUtils.mergeProps(errorMessageProps, props);
189
+ return /*#__PURE__*/ jsxRuntime.jsx(reactPrimitive.Primitive.div, {
190
+ ref: reactComposeRefs.composeRefs(refs.errorMessage, ref),
191
+ ...mergedProps
192
+ });
193
+ });
194
+ FieldErrorMessage.displayName = "FieldErrorMessage";
195
+
196
+ exports.FieldDescription = FieldDescription;
197
+ exports.FieldErrorMessage = FieldErrorMessage;
198
+ exports.FieldLabel = FieldLabel;
199
+ exports.FieldRoot = FieldRoot;
200
+ exports.useFieldContext = useFieldContext;
package/lib/index.cjs ADDED
@@ -0,0 +1,16 @@
1
+ var Field12s = require('./Field-12s-DIDZP1t4.cjs');
2
+
3
+ var Field_namespace = {
4
+ __proto__: null,
5
+ Description: Field12s.FieldDescription,
6
+ ErrorMessage: Field12s.FieldErrorMessage,
7
+ Label: Field12s.FieldLabel,
8
+ Root: Field12s.FieldRoot
9
+ };
10
+
11
+ exports.FieldDescription = Field12s.FieldDescription;
12
+ exports.FieldErrorMessage = Field12s.FieldErrorMessage;
13
+ exports.FieldLabel = Field12s.FieldLabel;
14
+ exports.FieldRoot = Field12s.FieldRoot;
15
+ exports.useFieldContext = Field12s.useFieldContext;
16
+ exports.Field = Field_namespace;