@conform-to/react 0.9.1 → 1.0.0-pre.1

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/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
- export { type FieldsetConstraint, type Submission, parse, list, validate, requestIntent, isFieldElement, } from '@conform-to/dom';
2
- export { type Fieldset, type FieldConfig, type FieldsetConfig, type FormConfig, useForm, useFieldset, useFieldList, useInputEvent, validateConstraint, } from './hooks.js';
3
- export * as conform from './helpers.js';
1
+ export { type Submission, type SubmissionResult, type Intent, type FormId, type FieldName, requestIntent, requestSubmit, isFieldElement, intent, } from '@conform-to/dom';
2
+ export { type FieldProps, type FieldMetadata, type FormMetadata, FormProvider, FormStateInput, } from './context';
3
+ export { useForm, useFormMetadata, useField } from './hooks';
4
+ export { useInputControl } from './integrations';
5
+ export { validateConstraint } from './validitystate';
6
+ export { getFormProps, getFieldsetProps, getInputProps, getSelectProps, getTextareaProps, getCollectionProps, getControlButtonProps, } from './helpers';
package/index.js CHANGED
@@ -3,34 +3,41 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var dom = require('@conform-to/dom');
6
+ var context = require('./context.js');
6
7
  var hooks = require('./hooks.js');
8
+ var integrations = require('./integrations.js');
9
+ var validitystate = require('./validitystate.js');
7
10
  var helpers = require('./helpers.js');
8
11
 
9
12
 
10
13
 
11
- Object.defineProperty(exports, 'isFieldElement', {
12
- enumerable: true,
13
- get: function () { return dom.isFieldElement; }
14
- });
15
- Object.defineProperty(exports, 'list', {
14
+ Object.defineProperty(exports, 'intent', {
16
15
  enumerable: true,
17
- get: function () { return dom.list; }
16
+ get: function () { return dom.intent; }
18
17
  });
19
- Object.defineProperty(exports, 'parse', {
18
+ Object.defineProperty(exports, 'isFieldElement', {
20
19
  enumerable: true,
21
- get: function () { return dom.parse; }
20
+ get: function () { return dom.isFieldElement; }
22
21
  });
23
22
  Object.defineProperty(exports, 'requestIntent', {
24
23
  enumerable: true,
25
24
  get: function () { return dom.requestIntent; }
26
25
  });
27
- Object.defineProperty(exports, 'validate', {
26
+ Object.defineProperty(exports, 'requestSubmit', {
28
27
  enumerable: true,
29
- get: function () { return dom.validate; }
28
+ get: function () { return dom.requestSubmit; }
30
29
  });
31
- exports.useFieldList = hooks.useFieldList;
32
- exports.useFieldset = hooks.useFieldset;
30
+ exports.FormProvider = context.FormProvider;
31
+ exports.FormStateInput = context.FormStateInput;
32
+ exports.useField = hooks.useField;
33
33
  exports.useForm = hooks.useForm;
34
- exports.useInputEvent = hooks.useInputEvent;
35
- exports.validateConstraint = hooks.validateConstraint;
36
- exports.conform = helpers;
34
+ exports.useFormMetadata = hooks.useFormMetadata;
35
+ exports.useInputControl = integrations.useInputControl;
36
+ exports.validateConstraint = validitystate.validateConstraint;
37
+ exports.getCollectionProps = helpers.getCollectionProps;
38
+ exports.getControlButtonProps = helpers.getControlButtonProps;
39
+ exports.getFieldsetProps = helpers.getFieldsetProps;
40
+ exports.getFormProps = helpers.getFormProps;
41
+ exports.getInputProps = helpers.getInputProps;
42
+ exports.getSelectProps = helpers.getSelectProps;
43
+ exports.getTextareaProps = helpers.getTextareaProps;
package/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
- export { isFieldElement, list, parse, requestIntent, validate } from '@conform-to/dom';
2
- export { useFieldList, useFieldset, useForm, useInputEvent, validateConstraint } from './hooks.mjs';
3
- import * as helpers from './helpers.mjs';
4
- export { helpers as conform };
1
+ export { intent, isFieldElement, requestIntent, requestSubmit } from '@conform-to/dom';
2
+ export { FormProvider, FormStateInput } from './context.mjs';
3
+ export { useField, useForm, useFormMetadata } from './hooks.mjs';
4
+ export { useInputControl } from './integrations.mjs';
5
+ export { validateConstraint } from './validitystate.mjs';
6
+ export { getCollectionProps, getControlButtonProps, getFieldsetProps, getFormProps, getInputProps, getSelectProps, getTextareaProps } from './helpers.mjs';
@@ -0,0 +1,18 @@
1
+ import { type FieldElement, type FormValue } from '@conform-to/dom';
2
+ import { type FieldMetadata } from './context';
3
+ export type InputControl<Value> = {
4
+ value: Value;
5
+ change: (value: Value) => void;
6
+ focus: () => void;
7
+ blur: () => void;
8
+ };
9
+ export declare function getFieldElement(formId: string, name: string, match?: (element: FieldElement) => boolean): FieldElement | null;
10
+ export declare function getEventTarget(formId: string, name: string): FieldElement;
11
+ export declare function useInputControl<Schema>(metadata: FieldMetadata<Schema, any, any>, options?: {
12
+ onFocus?: (event: Event) => void;
13
+ }): InputControl<string | undefined>;
14
+ export declare function useInputControl<Schema, Value>(metadata: FieldMetadata<Schema, any, any>, options: {
15
+ initialize: (value: FormValue<Schema> | undefined) => Value;
16
+ serialize?: (value: Value) => string;
17
+ onFocus?: (event: Event) => void;
18
+ }): InputControl<Value>;
@@ -0,0 +1,161 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
6
+ var dom = require('@conform-to/dom');
7
+ var react = require('react');
8
+
9
+ function getFieldElement(formId, name) {
10
+ var _document$forms$named;
11
+ var match = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => true;
12
+ var element = (_document$forms$named = document.forms.namedItem(formId)) === null || _document$forms$named === void 0 ? void 0 : _document$forms$named.elements.namedItem(name);
13
+ if (element) {
14
+ var items = element instanceof Element ? [element] : Array.from(element.values());
15
+ for (var item of items) {
16
+ if (dom.isFieldElement(item) && match(item)) {
17
+ return item;
18
+ }
19
+ }
20
+ }
21
+ return null;
22
+ }
23
+ function getEventTarget(formId, name) {
24
+ var element = getFieldElement(formId, name);
25
+ if (element) {
26
+ return element;
27
+ }
28
+ var form = document.forms.namedItem(formId);
29
+ var input = document.createElement('input');
30
+ input.type = 'hidden';
31
+ input.name = name;
32
+ form === null || form === void 0 ? void 0 : form.appendChild(input);
33
+ return input;
34
+ }
35
+ function useInputControl(metadata, options) {
36
+ var _options$initialize;
37
+ var eventDispatched = react.useRef({
38
+ change: false,
39
+ focus: false,
40
+ blur: false
41
+ });
42
+ var [key, setKey] = react.useState(metadata.key);
43
+ var optionsRef = react.useRef(options);
44
+ var initialize = (_options$initialize = options === null || options === void 0 ? void 0 : options.initialize) !== null && _options$initialize !== void 0 ? _options$initialize : value => value === null || value === void 0 ? void 0 : value.toString();
45
+ var [value, setValue] = react.useState(() => initialize(metadata.initialValue));
46
+ if (key !== metadata.key) {
47
+ setValue(initialize(metadata.initialValue));
48
+ setKey(metadata.key);
49
+ }
50
+ react.useEffect(() => {
51
+ optionsRef.current = options;
52
+ });
53
+ react.useEffect(() => {
54
+ var createEventListener = listener => {
55
+ return event => {
56
+ var element = getFieldElement(metadata.formId, metadata.name, element => element === event.target);
57
+ if (element) {
58
+ if (listener === 'focus') {
59
+ var _optionsRef$current, _optionsRef$current$o;
60
+ (_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 || (_optionsRef$current$o = _optionsRef$current.onFocus) === null || _optionsRef$current$o === void 0 ? void 0 : _optionsRef$current$o.call(_optionsRef$current, event);
61
+ }
62
+ eventDispatched.current[listener] = true;
63
+ }
64
+ };
65
+ };
66
+ var inputHandler = createEventListener('change');
67
+ var focusHandler = createEventListener('focus');
68
+ var blurHandler = createEventListener('blur');
69
+ document.addEventListener('input', inputHandler, true);
70
+ document.addEventListener('focusin', focusHandler, true);
71
+ document.addEventListener('focusout', blurHandler, true);
72
+ return () => {
73
+ document.removeEventListener('input', inputHandler, true);
74
+ document.removeEventListener('focusin', focusHandler, true);
75
+ document.removeEventListener('focusout', blurHandler, true);
76
+ };
77
+ }, [metadata.formId, metadata.name]);
78
+ var handlers = react.useMemo(() => {
79
+ return {
80
+ change(value) {
81
+ if (!eventDispatched.current.change) {
82
+ var _ref, _optionsRef$current$s, _optionsRef$current2, _optionsRef$current2$;
83
+ var _element = getEventTarget(metadata.formId, metadata.name);
84
+ var serializedValue = (_ref = (_optionsRef$current$s = (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 || (_optionsRef$current2$ = _optionsRef$current2.serialize) === null || _optionsRef$current2$ === void 0 ? void 0 : _optionsRef$current2$.call(_optionsRef$current2, value)) !== null && _optionsRef$current$s !== void 0 ? _optionsRef$current$s : value === null || value === void 0 ? void 0 : value.toString()) !== null && _ref !== void 0 ? _ref : '';
85
+ eventDispatched.current.change = true;
86
+ if (_element instanceof HTMLInputElement && (_element.type === 'checkbox' || _element.type === 'radio')) {
87
+ if (_element.checked ? _element.value !== serializedValue : _element.value === serializedValue) {
88
+ _element.click();
89
+ }
90
+ } else {
91
+ // No change event will be triggered on React if `element.value` is already updated
92
+ if (_element.value !== serializedValue) {
93
+ /**
94
+ * Triggering react custom change event
95
+ * Solution based on dom-testing-library
96
+ * @see https://github.com/facebook/react/issues/10135#issuecomment-401496776
97
+ * @see https://github.com/testing-library/dom-testing-library/blob/main/src/events.js#L104-L123
98
+ */
99
+ var {
100
+ set: valueSetter
101
+ } = Object.getOwnPropertyDescriptor(_element, 'value') || {};
102
+ var prototype = Object.getPrototypeOf(_element);
103
+ var {
104
+ set: prototypeValueSetter
105
+ } = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
106
+ if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
107
+ prototypeValueSetter.call(_element, value);
108
+ } else {
109
+ if (valueSetter) {
110
+ valueSetter.call(_element, value);
111
+ } else {
112
+ throw new Error('The given element does not have a value setter');
113
+ }
114
+ }
115
+ }
116
+
117
+ // Dispatch input event with the updated input value
118
+ _element.dispatchEvent(new InputEvent('input', {
119
+ bubbles: true
120
+ }));
121
+ // Dispatch change event (necessary for select to update the selected option)
122
+ _element.dispatchEvent(new Event('change', {
123
+ bubbles: true
124
+ }));
125
+ }
126
+ }
127
+ setValue(value);
128
+ eventDispatched.current.change = false;
129
+ },
130
+ focus() {
131
+ if (!eventDispatched.current.focus) {
132
+ var _element2 = getEventTarget(metadata.formId, metadata.name);
133
+ eventDispatched.current.focus = true;
134
+ _element2.dispatchEvent(new FocusEvent('focusin', {
135
+ bubbles: true
136
+ }));
137
+ _element2.dispatchEvent(new FocusEvent('focus'));
138
+ }
139
+ eventDispatched.current.focus = false;
140
+ },
141
+ blur() {
142
+ if (!eventDispatched.current.blur) {
143
+ var _element3 = getEventTarget(metadata.formId, metadata.name);
144
+ eventDispatched.current.blur = true;
145
+ _element3.dispatchEvent(new FocusEvent('focusout', {
146
+ bubbles: true
147
+ }));
148
+ _element3.dispatchEvent(new FocusEvent('blur'));
149
+ }
150
+ eventDispatched.current.blur = false;
151
+ }
152
+ };
153
+ }, [metadata.formId, metadata.name]);
154
+ return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, handlers), {}, {
155
+ value
156
+ });
157
+ }
158
+
159
+ exports.getEventTarget = getEventTarget;
160
+ exports.getFieldElement = getFieldElement;
161
+ exports.useInputControl = useInputControl;
@@ -0,0 +1,155 @@
1
+ import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
+ import { isFieldElement } from '@conform-to/dom';
3
+ import { useRef, useState, useEffect, useMemo } from 'react';
4
+
5
+ function getFieldElement(formId, name) {
6
+ var _document$forms$named;
7
+ var match = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => true;
8
+ var element = (_document$forms$named = document.forms.namedItem(formId)) === null || _document$forms$named === void 0 ? void 0 : _document$forms$named.elements.namedItem(name);
9
+ if (element) {
10
+ var items = element instanceof Element ? [element] : Array.from(element.values());
11
+ for (var item of items) {
12
+ if (isFieldElement(item) && match(item)) {
13
+ return item;
14
+ }
15
+ }
16
+ }
17
+ return null;
18
+ }
19
+ function getEventTarget(formId, name) {
20
+ var element = getFieldElement(formId, name);
21
+ if (element) {
22
+ return element;
23
+ }
24
+ var form = document.forms.namedItem(formId);
25
+ var input = document.createElement('input');
26
+ input.type = 'hidden';
27
+ input.name = name;
28
+ form === null || form === void 0 ? void 0 : form.appendChild(input);
29
+ return input;
30
+ }
31
+ function useInputControl(metadata, options) {
32
+ var _options$initialize;
33
+ var eventDispatched = useRef({
34
+ change: false,
35
+ focus: false,
36
+ blur: false
37
+ });
38
+ var [key, setKey] = useState(metadata.key);
39
+ var optionsRef = useRef(options);
40
+ var initialize = (_options$initialize = options === null || options === void 0 ? void 0 : options.initialize) !== null && _options$initialize !== void 0 ? _options$initialize : value => value === null || value === void 0 ? void 0 : value.toString();
41
+ var [value, setValue] = useState(() => initialize(metadata.initialValue));
42
+ if (key !== metadata.key) {
43
+ setValue(initialize(metadata.initialValue));
44
+ setKey(metadata.key);
45
+ }
46
+ useEffect(() => {
47
+ optionsRef.current = options;
48
+ });
49
+ useEffect(() => {
50
+ var createEventListener = listener => {
51
+ return event => {
52
+ var element = getFieldElement(metadata.formId, metadata.name, element => element === event.target);
53
+ if (element) {
54
+ if (listener === 'focus') {
55
+ var _optionsRef$current, _optionsRef$current$o;
56
+ (_optionsRef$current = optionsRef.current) === null || _optionsRef$current === void 0 || (_optionsRef$current$o = _optionsRef$current.onFocus) === null || _optionsRef$current$o === void 0 ? void 0 : _optionsRef$current$o.call(_optionsRef$current, event);
57
+ }
58
+ eventDispatched.current[listener] = true;
59
+ }
60
+ };
61
+ };
62
+ var inputHandler = createEventListener('change');
63
+ var focusHandler = createEventListener('focus');
64
+ var blurHandler = createEventListener('blur');
65
+ document.addEventListener('input', inputHandler, true);
66
+ document.addEventListener('focusin', focusHandler, true);
67
+ document.addEventListener('focusout', blurHandler, true);
68
+ return () => {
69
+ document.removeEventListener('input', inputHandler, true);
70
+ document.removeEventListener('focusin', focusHandler, true);
71
+ document.removeEventListener('focusout', blurHandler, true);
72
+ };
73
+ }, [metadata.formId, metadata.name]);
74
+ var handlers = useMemo(() => {
75
+ return {
76
+ change(value) {
77
+ if (!eventDispatched.current.change) {
78
+ var _ref, _optionsRef$current$s, _optionsRef$current2, _optionsRef$current2$;
79
+ var _element = getEventTarget(metadata.formId, metadata.name);
80
+ var serializedValue = (_ref = (_optionsRef$current$s = (_optionsRef$current2 = optionsRef.current) === null || _optionsRef$current2 === void 0 || (_optionsRef$current2$ = _optionsRef$current2.serialize) === null || _optionsRef$current2$ === void 0 ? void 0 : _optionsRef$current2$.call(_optionsRef$current2, value)) !== null && _optionsRef$current$s !== void 0 ? _optionsRef$current$s : value === null || value === void 0 ? void 0 : value.toString()) !== null && _ref !== void 0 ? _ref : '';
81
+ eventDispatched.current.change = true;
82
+ if (_element instanceof HTMLInputElement && (_element.type === 'checkbox' || _element.type === 'radio')) {
83
+ if (_element.checked ? _element.value !== serializedValue : _element.value === serializedValue) {
84
+ _element.click();
85
+ }
86
+ } else {
87
+ // No change event will be triggered on React if `element.value` is already updated
88
+ if (_element.value !== serializedValue) {
89
+ /**
90
+ * Triggering react custom change event
91
+ * Solution based on dom-testing-library
92
+ * @see https://github.com/facebook/react/issues/10135#issuecomment-401496776
93
+ * @see https://github.com/testing-library/dom-testing-library/blob/main/src/events.js#L104-L123
94
+ */
95
+ var {
96
+ set: valueSetter
97
+ } = Object.getOwnPropertyDescriptor(_element, 'value') || {};
98
+ var prototype = Object.getPrototypeOf(_element);
99
+ var {
100
+ set: prototypeValueSetter
101
+ } = Object.getOwnPropertyDescriptor(prototype, 'value') || {};
102
+ if (prototypeValueSetter && valueSetter !== prototypeValueSetter) {
103
+ prototypeValueSetter.call(_element, value);
104
+ } else {
105
+ if (valueSetter) {
106
+ valueSetter.call(_element, value);
107
+ } else {
108
+ throw new Error('The given element does not have a value setter');
109
+ }
110
+ }
111
+ }
112
+
113
+ // Dispatch input event with the updated input value
114
+ _element.dispatchEvent(new InputEvent('input', {
115
+ bubbles: true
116
+ }));
117
+ // Dispatch change event (necessary for select to update the selected option)
118
+ _element.dispatchEvent(new Event('change', {
119
+ bubbles: true
120
+ }));
121
+ }
122
+ }
123
+ setValue(value);
124
+ eventDispatched.current.change = false;
125
+ },
126
+ focus() {
127
+ if (!eventDispatched.current.focus) {
128
+ var _element2 = getEventTarget(metadata.formId, metadata.name);
129
+ eventDispatched.current.focus = true;
130
+ _element2.dispatchEvent(new FocusEvent('focusin', {
131
+ bubbles: true
132
+ }));
133
+ _element2.dispatchEvent(new FocusEvent('focus'));
134
+ }
135
+ eventDispatched.current.focus = false;
136
+ },
137
+ blur() {
138
+ if (!eventDispatched.current.blur) {
139
+ var _element3 = getEventTarget(metadata.formId, metadata.name);
140
+ eventDispatched.current.blur = true;
141
+ _element3.dispatchEvent(new FocusEvent('focusout', {
142
+ bubbles: true
143
+ }));
144
+ _element3.dispatchEvent(new FocusEvent('blur'));
145
+ }
146
+ eventDispatched.current.blur = false;
147
+ }
148
+ };
149
+ }, [metadata.formId, metadata.name]);
150
+ return _objectSpread2(_objectSpread2({}, handlers), {}, {
151
+ value
152
+ });
153
+ }
154
+
155
+ export { getEventTarget, getFieldElement, useInputControl };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Conform view adapter for react",
4
4
  "homepage": "https://conform.guide",
5
5
  "license": "MIT",
6
- "version": "0.9.1",
6
+ "version": "1.0.0-pre.1",
7
7
  "main": "index.js",
8
8
  "module": "index.mjs",
9
9
  "types": "index.d.ts",
@@ -30,10 +30,10 @@
30
30
  "url": "https://github.com/edmundhung/conform/issues"
31
31
  },
32
32
  "dependencies": {
33
- "@conform-to/dom": "0.9.1"
33
+ "@conform-to/dom": "1.0.0-pre.1"
34
34
  },
35
35
  "peerDependencies": {
36
- "react": ">=16.8"
36
+ "react": ">=18"
37
37
  },
38
38
  "keywords": [
39
39
  "constraint-validation",
@@ -0,0 +1,12 @@
1
+ import { type Submission } from '@conform-to/dom';
2
+ /**
3
+ * Validate the form with the Constraint Validation API
4
+ * @see https://conform.guide/api/react#validateconstraint
5
+ */
6
+ export declare function validateConstraint(options: {
7
+ form: HTMLFormElement;
8
+ formData?: FormData;
9
+ }): Submission<Record<string, any>, {
10
+ validity: ValidityState;
11
+ validationMessage: string;
12
+ }>;
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
6
+ var dom = require('@conform-to/dom');
7
+
8
+ /**
9
+ * Validate the form with the Constraint Validation API
10
+ * @see https://conform.guide/api/react#validateconstraint
11
+ */
12
+ function validateConstraint(options) {
13
+ var _options$formData;
14
+ var formData = (_options$formData = options === null || options === void 0 ? void 0 : options.formData) !== null && _options$formData !== void 0 ? _options$formData : new FormData(options.form);
15
+ return dom.parse(formData, {
16
+ resolve(value) {
17
+ var error = {};
18
+ for (var element of options.form.elements) {
19
+ if (dom.isFieldElement(element) && element.name !== '' && !element.validity.valid) {
20
+ error[element.name] = {
21
+ validity: _rollupPluginBabelHelpers.objectSpread2({}, element.validity),
22
+ validationMessage: element.validationMessage
23
+ };
24
+ }
25
+ }
26
+ if (Object.entries(error).length > 0) {
27
+ return {
28
+ error
29
+ };
30
+ }
31
+ return {
32
+ value
33
+ };
34
+ }
35
+ });
36
+ }
37
+
38
+ exports.validateConstraint = validateConstraint;
@@ -0,0 +1,34 @@
1
+ import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.mjs';
2
+ import { parse, isFieldElement } from '@conform-to/dom';
3
+
4
+ /**
5
+ * Validate the form with the Constraint Validation API
6
+ * @see https://conform.guide/api/react#validateconstraint
7
+ */
8
+ function validateConstraint(options) {
9
+ var _options$formData;
10
+ var formData = (_options$formData = options === null || options === void 0 ? void 0 : options.formData) !== null && _options$formData !== void 0 ? _options$formData : new FormData(options.form);
11
+ return parse(formData, {
12
+ resolve(value) {
13
+ var error = {};
14
+ for (var element of options.form.elements) {
15
+ if (isFieldElement(element) && element.name !== '' && !element.validity.valid) {
16
+ error[element.name] = {
17
+ validity: _objectSpread2({}, element.validity),
18
+ validationMessage: element.validationMessage
19
+ };
20
+ }
21
+ }
22
+ if (Object.entries(error).length > 0) {
23
+ return {
24
+ error
25
+ };
26
+ }
27
+ return {
28
+ value
29
+ };
30
+ }
31
+ });
32
+ }
33
+
34
+ export { validateConstraint };