@igne-agency/react-web-ui 0.2.1 → 0.3.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.
Files changed (59) hide show
  1. package/README.md +39 -0
  2. package/dist/components/checkbox-field/tsf-checkbox-field.js +1 -1
  3. package/dist/components/checkbox-group-field/checkbox-group.d.ts +1 -1
  4. package/dist/components/checkbox-group-field/checkbox-group.js +1 -1
  5. package/dist/components/checkbox-group-field/tsf-checkbox-group-field.js +1 -1
  6. package/dist/components/combobox-field/tsf-combobox-field.js +2 -2
  7. package/dist/components/date-field/tsf-date-field.js +1 -1
  8. package/dist/components/date-range-field/tsf-date-range-field.js +1 -1
  9. package/dist/components/field/field-group-context.d.ts +21 -0
  10. package/dist/components/field/field-group-context.js +38 -0
  11. package/dist/components/field/field.css +27 -8
  12. package/dist/components/field/field.d.ts +6 -3
  13. package/dist/components/field/field.js +88 -45
  14. package/dist/components/field/field.module.js +12 -10
  15. package/dist/components/fieldset/field-group.d.ts +31 -0
  16. package/dist/components/fieldset/field-group.js +102 -0
  17. package/dist/components/fieldset/fieldset-root.d.ts +60 -0
  18. package/dist/components/fieldset/fieldset-root.js +285 -0
  19. package/dist/components/fieldset/fieldset.css +21 -0
  20. package/dist/components/fieldset/fieldset.d.ts +37 -0
  21. package/dist/components/fieldset/fieldset.js +127 -0
  22. package/dist/components/fieldset/fieldset.module.js +8 -0
  23. package/dist/components/fieldset/index.d.ts +4 -0
  24. package/dist/components/fieldset/index.js +4 -0
  25. package/dist/components/fieldset/tsf-field-group.d.ts +21 -0
  26. package/dist/components/fieldset/tsf-field-group.js +58 -0
  27. package/dist/components/file-field/tsf-file-field.js +1 -1
  28. package/dist/components/number-field/tsf-number-field.js +1 -1
  29. package/dist/components/otp-field/tsf-otp-field.js +1 -1
  30. package/dist/components/password-field/tsf-password-field.js +1 -1
  31. package/dist/components/photo-field/tsf-photo-field.js +1 -1
  32. package/dist/components/radio-group-field/radio-group.d.ts +1 -1
  33. package/dist/components/radio-group-field/radio-group.js +1 -1
  34. package/dist/components/radio-group-field/tsf-radio-group-field.js +1 -1
  35. package/dist/components/segmented-control-field/segmented-control.d.ts +1 -1
  36. package/dist/components/segmented-control-field/segmented-control.js +1 -1
  37. package/dist/components/segmented-control-field/tsf-segmented-control-field.js +1 -1
  38. package/dist/components/select-field/tsf-select-field.js +1 -1
  39. package/dist/components/switch-field/tsf-switch-field.js +1 -1
  40. package/dist/components/text-field/connect-text-preset.js +1 -1
  41. package/dist/components/text-field/text-field.css +28 -27
  42. package/dist/components/text-field/text-field.module.js +9 -9
  43. package/dist/components/text-field/tsf-text-field.js +1 -1
  44. package/dist/components/textarea-field/tsf-textarea-field.js +1 -1
  45. package/dist/components/time-field/tsf-time-field.js +1 -1
  46. package/dist/components/toggle-group-field/toggle-group.d.ts +1 -1
  47. package/dist/components/toggle-group-field/toggle-group.js +1 -1
  48. package/dist/components/toggle-group-field/tsf-toggle-group-field.js +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.js +6 -2
  51. package/dist/lib/forms/create-app-form.d.ts +18 -9
  52. package/dist/lib/forms/create-app-form.js +17 -8
  53. package/dist/lib/forms/index.d.ts +1 -0
  54. package/dist/lib/forms/index.js +2 -1
  55. package/dist/lib/forms/use-connected-field.d.ts +10 -7
  56. package/dist/lib/forms/use-connected-field.js +54 -28
  57. package/package.json +5 -1
  58. package/dist/components/field/fieldset.d.ts +0 -22
  59. package/dist/components/field/fieldset.js +0 -130
@@ -0,0 +1,58 @@
1
+ import { useFormContext } from "../../lib/forms/context.js";
2
+ import { getFieldErrors } from "../../lib/forms/errors.js";
3
+ import { FieldGroup } from "./field-group.js";
4
+ import { c } from "react/compiler-runtime";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import { useStore } from "@tanstack/react-form";
7
+ // src/components/fieldset/tsf-field-group.tsx
8
+ /**
9
+ * `FieldGroup` bound to the TanStack Form it renders in: it shows the errors
10
+ * of the fields it `names`. Registered as `form.FieldGroup`.
11
+ *
12
+ * @example
13
+ * <form.FieldGroup legend="Address" optionalLabel="optional" names={["postalCode", "houseNumber"]}>
14
+ * <form.AppField name="postalCode">
15
+ * {field => <field.TextField label="Postal code" optionalLabel="optional" />}
16
+ * </form.AppField>
17
+ * <form.AppField name="houseNumber">
18
+ * {field => <field.TextField label="House number" optionalLabel="optional" />}
19
+ * </form.AppField>
20
+ * </form.FieldGroup>
21
+ */
22
+ var TSFFieldGroup = (t0) => {
23
+ const $ = c(8);
24
+ let names;
25
+ let props;
26
+ if ($[0] !== t0) {
27
+ ({names, ...props} = t0);
28
+ $[0] = t0;
29
+ $[1] = names;
30
+ $[2] = props;
31
+ } else {
32
+ names = $[1];
33
+ props = $[2];
34
+ }
35
+ const form = useFormContext();
36
+ let t1;
37
+ if ($[3] !== names) {
38
+ t1 = (state) => names.map((name) => ({
39
+ name,
40
+ errors: getFieldErrors(state, [name])
41
+ }));
42
+ $[3] = names;
43
+ $[4] = t1;
44
+ } else t1 = $[4];
45
+ const members = useStore(form.store, t1);
46
+ let t2;
47
+ if ($[5] !== members || $[6] !== props) {
48
+ t2 = /* @__PURE__ */ jsx(FieldGroup, {
49
+ ...props,
50
+ members
51
+ });
52
+ $[5] = members;
53
+ $[6] = props;
54
+ $[7] = t2;
55
+ } else t2 = $[7];
56
+ return t2;
57
+ };
58
+ export { TSFFieldGroup };
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFFileField = (props) => {
16
16
  const $ = c(11);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== field) {
20
20
  t0 = (files) => field.handleChange(files);
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFNumberField = (props) => {
16
16
  const $ = c(5);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
20
20
  t0 = /* @__PURE__ */ jsx(NumberField, {
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFOtpField = (props) => {
16
16
  const $ = c(5);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
20
20
  t0 = /* @__PURE__ */ jsx(OtpField, {
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFPasswordField = (props) => {
16
16
  const $ = c(5);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
20
20
  t0 = /* @__PURE__ */ jsx(PasswordField, {
@@ -26,7 +26,7 @@ var TSFPhotoField = (t0) => {
26
26
  onValueChange = $[1];
27
27
  props = $[2];
28
28
  }
29
- const { field, props: connected } = useConnectedField();
29
+ const { field, props: connected } = useConnectedField(props.label);
30
30
  let t1;
31
31
  if ($[3] !== field || $[4] !== onValueChange) {
32
32
  t1 = (file) => {
@@ -3,7 +3,7 @@ import { Radio as BaseRadio } from "@base-ui/react/radio";
3
3
  import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
4
4
  import type { ReactNode } from "react";
5
5
  import { Field } from "../field/index.ts";
6
- import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../field/fieldset.tsx";
6
+ import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../fieldset/fieldset-root.tsx";
7
7
  export type RadioGroupRootProps = FieldsetRootProps;
8
8
  declare const RadioGroupGroup: <TValue>({ className, ...props }: BaseRadioGroup.Props<TValue>) => ReactNode;
9
9
  declare const RadioGroupItem: ({ className, ...props }: BaseField.Item.Props) => ReactNode;
@@ -1,7 +1,7 @@
1
1
  import { Field as Field$1 } from "../field/field.js";
2
2
  import { fieldStateAttributes } from "../field/field-state.js";
3
3
  import { useFieldFocus } from "../field/use-field-focus.js";
4
- import { FieldsetLegend, FieldsetRoot } from "../field/fieldset.js";
4
+ import { FieldsetLegend, FieldsetRoot } from "../fieldset/fieldset-root.js";
5
5
  import radio_group_module_default from "./radio-group.module.js";
6
6
  import { c } from "react/compiler-runtime";
7
7
  import { jsx } from "react/jsx-runtime";
@@ -15,7 +15,7 @@ import { jsx } from "react/jsx-runtime";
15
15
  */
16
16
  var TSFRadioGroupField = (props) => {
17
17
  const $ = c(7);
18
- const { field, props: connected } = useConnectedField();
18
+ const { field, props: connected } = useConnectedField(props.label);
19
19
  let t0;
20
20
  if ($[0] !== field) {
21
21
  t0 = (next) => field.handleChange(next);
@@ -2,7 +2,7 @@ import { Toggle as BaseToggle } from "@base-ui/react/toggle";
2
2
  import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
3
3
  import type { ReactNode } from "react";
4
4
  import { Field, type ChoiceOption } from "../field/index.ts";
5
- import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../field/fieldset.tsx";
5
+ import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../fieldset/fieldset-root.tsx";
6
6
  export type SegmentedControlRootProps = FieldsetRootProps;
7
7
  export type SegmentedControlGroupProps = Omit<BaseToggleGroup.Props, "multiple"> & Readonly<{
8
8
  /** Read-only groups still read, but no longer answer a press. */
@@ -1,7 +1,7 @@
1
1
  import { Field } from "../field/field.js";
2
2
  import { fieldStateAttributes } from "../field/field-state.js";
3
3
  import { useFieldFocus } from "../field/use-field-focus.js";
4
- import { FieldsetLegend, FieldsetRoot } from "../field/fieldset.js";
4
+ import { FieldsetLegend, FieldsetRoot } from "../fieldset/fieldset-root.js";
5
5
  import { useFormDisabled } from "../form/form-context.js";
6
6
  import { useSlidingIndicator } from "../../lib/sliding-indicator/use-sliding-indicator.js";
7
7
  import segmented_control_module_default from "./segmented-control.module.js";
@@ -15,7 +15,7 @@ import { jsx } from "react/jsx-runtime";
15
15
  */
16
16
  var TSFSegmentedControlField = (props) => {
17
17
  const $ = c(7);
18
- const { field, props: connected } = useConnectedField();
18
+ const { field, props: connected } = useConnectedField(props.label);
19
19
  let t0;
20
20
  if ($[0] !== field) {
21
21
  t0 = (value) => field.handleChange(value);
@@ -15,7 +15,7 @@ import { jsx } from "react/jsx-runtime";
15
15
  */
16
16
  var TSFSelectField = (props) => {
17
17
  const $ = c(7);
18
- const { field, props: connected } = useConnectedField();
18
+ const { field, props: connected } = useConnectedField(props.label);
19
19
  let t0;
20
20
  if ($[0] !== field) {
21
21
  t0 = (next) => field.handleChange(next);
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFSwitchField = (props) => {
16
16
  const $ = c(7);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== field) {
20
20
  t0 = (checked) => field.handleChange(checked);
@@ -12,7 +12,7 @@ import { jsx } from "react/jsx-runtime";
12
12
  var connectTextPreset = (Preset) => {
13
13
  const Connected = (props) => {
14
14
  const $ = c(5);
15
- const { field, props: connected } = useConnectedField();
15
+ const { field, props: connected } = useConnectedField(props.label);
16
16
  let t0;
17
17
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
18
18
  t0 = /* @__PURE__ */ jsx(Preset, {
@@ -1,9 +1,9 @@
1
1
  @layer kit.reset, kit.base, kit.components;
2
2
  @layer kit.components {
3
- ._root_1g29w_3 {
3
+ ._root_1kpis_3 {
4
4
  min-inline-size: 0;
5
5
  }
6
- ._group_1g29w_6 {
6
+ ._group_1kpis_6 {
7
7
  --field-fg: var(--sys-color-text);
8
8
  --field-muted-fg: var(--sys-color-text-muted);
9
9
  --field-placeholder-fg: var(--sys-color-text-placeholder);
@@ -17,33 +17,33 @@
17
17
  color: var(--field-fg);
18
18
  font: var(--sys-font-body-medium);
19
19
  }
20
- ._group_1g29w_6 {
20
+ ._group_1kpis_6 {
21
21
  outline: 0 solid var(--sys-color-focus-ring);
22
22
  outline-offset: var(--sys-focus-ring-offset);
23
23
  }
24
- ._group_1g29w_6[data-focus-visible] {
24
+ ._group_1kpis_6[data-focus-visible] {
25
25
  outline-width: var(--sys-focus-ring-width);
26
26
  }
27
27
  @media not (prefers-reduced-motion) {
28
- ._group_1g29w_6 {
28
+ ._group_1kpis_6 {
29
29
  transition: border-color var(--sys-motion-instant) var(--sys-motion-standard), background var(--sys-motion-instant) var(--sys-motion-standard);
30
30
  }
31
31
  }
32
- ._group_1g29w_6:hover:not([data-disabled], [data-readonly]), ._group_1g29w_6[data-focused], ._group_1g29w_6[data-popup-open] {
32
+ ._group_1kpis_6:hover:not([data-disabled], [data-readonly]), ._group_1kpis_6[data-focused], ._group_1kpis_6[data-popup-open] {
33
33
  border-color: var(--sys-color-primary);
34
34
  }
35
- ._group_1g29w_6[data-readonly] {
35
+ ._group_1kpis_6[data-readonly] {
36
36
  --field-fg: var(--sys-color-text);
37
37
  border-style: dashed;
38
38
  border-color: var(--sys-color-outline);
39
39
  background: var(--sys-color-surface-high);
40
40
  color: var(--field-fg);
41
41
  }
42
- ._group_1g29w_6[data-pending] {
42
+ ._group_1kpis_6[data-pending] {
43
43
  cursor: progress;
44
44
  caret-color: var(--sys-color-text-muted);
45
45
  }
46
- ._group_1g29w_6[data-invalid] {
46
+ ._group_1kpis_6[data-invalid] {
47
47
  --field-fg: var(--sys-color-error-fg);
48
48
  --field-muted-fg: var(--sys-color-error-fg);
49
49
  --field-placeholder-fg: var(--sys-color-error-fg);
@@ -51,7 +51,7 @@
51
51
  background-color: var(--sys-color-error-bg);
52
52
  color: var(--field-fg);
53
53
  }
54
- ._group_1g29w_6[data-disabled] {
54
+ ._group_1kpis_6[data-disabled] {
55
55
  --field-fg: var(--sys-color-disabled-fg);
56
56
  --field-muted-fg: var(--sys-color-disabled-fg);
57
57
  --field-placeholder-fg: var(--sys-color-disabled-fg);
@@ -59,16 +59,16 @@
59
59
  cursor: not-allowed;
60
60
  background: var(--sys-color-disabled-bg);
61
61
  }
62
- ._group_1g29w_6 {
62
+ ._group_1kpis_6 {
63
63
  position: relative;
64
64
  display: flex;
65
65
  gap: var(--sys-unit-4);
66
66
  }
67
- ._group_1g29w_6 {
67
+ ._group_1kpis_6 {
68
68
  inline-size: 100%;
69
69
  cursor: text;
70
70
  }
71
- ._control_1g29w_71 {
71
+ ._control_1kpis_71 {
72
72
  flex: 1;
73
73
  min-inline-size: 0;
74
74
  border: none;
@@ -77,31 +77,31 @@
77
77
  color: inherit;
78
78
  font: inherit;
79
79
  }
80
- ._control_1g29w_71::-webkit-search-cancel-button {
80
+ ._control_1kpis_71::-webkit-search-cancel-button {
81
81
  display: none;
82
82
  appearance: none;
83
83
  }
84
- ._control_1g29w_71::-webkit-search-decoration {
84
+ ._control_1kpis_71::-webkit-search-decoration {
85
85
  display: none;
86
86
  appearance: none;
87
87
  }
88
- ._control_1g29w_71 {
88
+ ._control_1kpis_71 {
89
89
  line-height: normal;
90
90
  }
91
- ._control_1g29w_71::placeholder {
91
+ ._control_1kpis_71::placeholder {
92
92
  color: var(--field-placeholder-fg);
93
93
  }
94
- ._bar_1g29w_94 {
94
+ ._bar_1kpis_94 {
95
95
  display: flex;
96
96
  align-items: center;
97
97
  justify-content: flex-end;
98
98
  gap: var(--sys-unit-4);
99
99
  pointer-events: none;
100
100
  }
101
- ._bar_1g29w_94:empty {
101
+ ._bar_1kpis_94:empty {
102
102
  display: none;
103
103
  }
104
- ._inlay_1g29w_104 {
104
+ ._inlay_1kpis_104 {
105
105
  display: inline-flex;
106
106
  flex: none;
107
107
  align-items: center;
@@ -112,14 +112,14 @@
112
112
  pointer-events: none;
113
113
  line-height: normal;
114
114
  }
115
- ._action_1g29w_115 {
115
+ ._action_1kpis_115 {
116
116
  position: relative;
117
117
  flex: none;
118
118
  margin-block: calc(-1 * var(--sys-unit-6));
119
119
  cursor: pointer;
120
120
  }
121
121
  @media (any-pointer: coarse) {
122
- ._action_1g29w_115::before {
122
+ ._action_1kpis_115::before {
123
123
  content: "";
124
124
  position: absolute;
125
125
  inset: 50%;
@@ -128,7 +128,7 @@
128
128
  block-size: var(--sys-unit-22);
129
129
  }
130
130
  }
131
- ._copyStatus_1g29w_131 {
131
+ ._copyStatus_1kpis_131 {
132
132
  position: absolute;
133
133
  overflow: hidden;
134
134
  clip-path: inset(50%);
@@ -136,30 +136,31 @@
136
136
  block-size: 1px;
137
137
  white-space: nowrap;
138
138
  }
139
- ._counter_1g29w_139 {
139
+ ._counter_1kpis_139 {
140
140
  --counter-fg: var(
141
141
  --text-field-counter-fg,
142
142
  var(--sys-color-text-muted)
143
143
  );
144
144
  align-self: flex-end;
145
+ justify-self: end;
145
146
  color: var(--counter-fg);
146
147
  font: var(--text-field-counter-font, var(--sys-font-body-small));
147
148
  font-variant-numeric: tabular-nums;
148
149
  cursor: default;
149
150
  }
150
- ._counter_1g29w_139[data-tone=warning] {
151
+ ._counter_1kpis_139[data-tone=warning] {
151
152
  --counter-fg: var(
152
153
  --text-field-counter-warning-fg,
153
154
  var(--sys-color-warning-fg)
154
155
  );
155
156
  }
156
- ._counter_1g29w_139[data-tone=error] {
157
+ ._counter_1kpis_139[data-tone=error] {
157
158
  --counter-fg: var(
158
159
  --text-field-counter-error-fg,
159
160
  var(--sys-color-error-fg)
160
161
  );
161
162
  }
162
- ._visuallyHidden_1g29w_162 {
163
+ ._visuallyHidden_1kpis_163 {
163
164
  position: absolute;
164
165
  overflow: hidden;
165
166
  clip-path: inset(50%);
@@ -1,13 +1,13 @@
1
1
  import './text-field.css';// src/components/text-field/text-field.module.scss
2
- var root = "_root_1g29w_3";
3
- var group = "_group_1g29w_6";
4
- var control = "_control_1g29w_71";
5
- var bar = "_bar_1g29w_94";
6
- var inlay = "_inlay_1g29w_104";
7
- var action = "_action_1g29w_115";
8
- var copyStatus = "_copyStatus_1g29w_131";
9
- var counter = "_counter_1g29w_139";
10
- var visuallyHidden = "_visuallyHidden_1g29w_162";
2
+ var root = "_root_1kpis_3";
3
+ var group = "_group_1kpis_6";
4
+ var control = "_control_1kpis_71";
5
+ var bar = "_bar_1kpis_94";
6
+ var inlay = "_inlay_1kpis_104";
7
+ var action = "_action_1kpis_115";
8
+ var copyStatus = "_copyStatus_1kpis_131";
9
+ var counter = "_counter_1kpis_139";
10
+ var visuallyHidden = "_visuallyHidden_1kpis_163";
11
11
  var text_field_module_default = {
12
12
  root,
13
13
  group,
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFTextField = (props) => {
16
16
  const $ = c(5);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
20
20
  t0 = /* @__PURE__ */ jsx(TextField, {
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFTextareaField = (props) => {
16
16
  const $ = c(5);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== connected || $[1] !== field.handleChange || $[2] !== field.state.value || $[3] !== props) {
20
20
  t0 = /* @__PURE__ */ jsx(TextareaField, {
@@ -14,7 +14,7 @@ import { jsx } from "react/jsx-runtime";
14
14
  */
15
15
  var TSFTimeField = (props) => {
16
16
  const $ = c(7);
17
- const { field, props: connected } = useConnectedField();
17
+ const { field, props: connected } = useConnectedField(props.label);
18
18
  let t0;
19
19
  if ($[0] !== field) {
20
20
  t0 = (next) => field.handleChange(next);
@@ -2,7 +2,7 @@ import { Toggle as BaseToggle } from "@base-ui/react/toggle";
2
2
  import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
3
3
  import type { ReactNode } from "react";
4
4
  import { Field } from "../field/index.ts";
5
- import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../field/fieldset.tsx";
5
+ import { FieldsetLegend, FieldsetRoot, type FieldsetRootProps } from "../fieldset/fieldset-root.tsx";
6
6
  export type ToggleGroupRootProps = FieldsetRootProps;
7
7
  export type ToggleGroupGroupProps = Omit<BaseToggleGroup.Props, "multiple"> & Readonly<{
8
8
  /** Read-only groups still read, but no longer answer a press. */
@@ -1,7 +1,7 @@
1
1
  import { Field } from "../field/field.js";
2
2
  import { fieldStateAttributes } from "../field/field-state.js";
3
3
  import { useFieldFocus } from "../field/use-field-focus.js";
4
- import { FieldsetLegend, FieldsetRoot } from "../field/fieldset.js";
4
+ import { FieldsetLegend, FieldsetRoot } from "../fieldset/fieldset-root.js";
5
5
  import { useFormDisabled } from "../form/form-context.js";
6
6
  import toggle_group_module_default from "./toggle-group.module.js";
7
7
  import { c } from "react/compiler-runtime";
@@ -15,7 +15,7 @@ import { jsx } from "react/jsx-runtime";
15
15
  */
16
16
  var TSFToggleGroupField = (props) => {
17
17
  const $ = c(7);
18
- const { field, props: connected } = useConnectedField();
18
+ const { field, props: connected } = useConnectedField(props.label);
19
19
  let t0;
20
20
  if ($[0] !== field) {
21
21
  t0 = (value) => field.handleChange(value);
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export * from "./components/error-message/index.ts";
25
25
  export * from "./components/error-text/index.ts";
26
26
  export * from "./components/field/index.ts";
27
27
  export * from "./components/field-placeholder/index.ts";
28
+ export * from "./components/fieldset/index.ts";
28
29
  export * from "./components/file-field/index.ts";
29
30
  export * from "./components/filter-bar/index.ts";
30
31
  export * from "./components/form/index.ts";
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { Breadcrumbs } from "./components/breadcrumbs/breadcrumbs.js";
21
21
  import { getFieldErrors, normalizeFieldErrors } from "./lib/forms/errors.js";
22
22
  import { ErrorText } from "./components/error-text/error-text.js";
23
23
  import { Spinner } from "./components/spinner/spinner.js";
24
+ import { useFieldContext, useFormContext } from "./lib/forms/context.js";
24
25
  import { Field, useFieldIds } from "./components/field/field.js";
25
26
  import { fieldStateAttributes } from "./components/field/field-state.js";
26
27
  import { optionsLoad } from "./components/field/options-load.js";
@@ -30,7 +31,7 @@ import { useFieldState } from "./components/field/use-field-state.js";
30
31
  import { CheckboxGlyph } from "./components/checkbox-field/checkbox-glyph.js";
31
32
  import { Checkbox } from "./components/checkbox-field/checkbox.js";
32
33
  import { CheckboxField } from "./components/checkbox-field/checkbox-field.js";
33
- import { useFieldContext, useFormContext } from "./lib/forms/context.js";
34
+ import { useConnectedField } from "./lib/forms/use-connected-field.js";
34
35
  import { TSFCheckboxField } from "./components/checkbox-field/tsf-checkbox-field.js";
35
36
  import { CheckboxGroup } from "./components/checkbox-group-field/checkbox-group.js";
36
37
  import { CheckboxGroupField } from "./components/checkbox-group-field/checkbox-group-field.js";
@@ -65,6 +66,9 @@ import { EmptyMessage } from "./components/empty-message/empty-message.js";
65
66
  import { ErrorMessage } from "./components/error-message/error-message.js";
66
67
  import { ErrorBoundary } from "./components/error-boundary/error-boundary.js";
67
68
  import { FieldPlaceholder } from "./components/field-placeholder/field-placeholder.js";
69
+ import { Fieldset } from "./components/fieldset/fieldset.js";
70
+ import { FieldGroup } from "./components/fieldset/field-group.js";
71
+ import { TSFFieldGroup } from "./components/fieldset/tsf-field-group.js";
68
72
  import { FileInput } from "./components/file-field/file-input.js";
69
73
  import { FileField } from "./components/file-field/file-field.js";
70
74
  import { TSFFileField } from "./components/file-field/tsf-file-field.js";
@@ -129,4 +133,4 @@ import { useTheme } from "./lib/hooks/use-theme.js";
129
133
  import { storedPageSize, tableStoredValue } from "./lib/table-storage.js";
130
134
  import { useBeforeUnload } from "./lib/unsaved-changes/before-unload.js";
131
135
  import { LeaveGuardDialog, useLeaveGuard } from "./lib/unsaved-changes/leave-guard.js";
132
- export { Accordion, ActiveFilters, AttachmentPreview, AttachmentTile, Avatar, AvatarGroup, Badge, Breadcrumbs, Button, Checkbox, CheckboxField, CheckboxGlyph, CheckboxGroup, CheckboxGroupField, Collapsible, Combobox, ComboboxField, ConfirmDialog, Conversation, DateField, DateInput, DateRangeField, DateRangeInput, DetailList, Dialog, Divider, Drawer, EmailField, EmptyMessage, ErrorBoundary, ErrorMessage, ErrorText, Field, FieldPlaceholder, FileField, FileInput, FilterBar, Form, Icon, LeaveGuardDialog, Link, LinkButton, LoadingMessage, LocaleProvider, Menu, Nav, NavItemView, NumberField, NumberInput, OtpField, OtpInput, Pagination, PasswordField, PasswordStrength, PhoneField, PhotoField, PhotoInput, Popover, RadioGroup, RadioGroupField, SearchField, SegmentedControl, SegmentedControlField, Select, SelectField, SentAttachmentTile, Skeleton, Spinner, Stale, StatusMessage, Switch, SwitchField, TSFCheckboxField, TSFCheckboxGroupField, TSFComboboxField, TSFDateField, TSFDateRangeField, TSFEmailField, TSFFileField, TSFNumberField, TSFOtpField, TSFPasswordField, TSFPhoneField, TSFPhotoField, TSFRadioGroupField, TSFSearchField, TSFSegmentedControlField, TSFSelectField, TSFSwitchField, TSFTextField, TSFTextareaField, TSFTimeField, TSFToggleGroupField, Tabs, Tag, TagGroup, TextField, TextInput, Textarea, TextareaField, TimeField, TimeInput, TimeZoneProvider, ToastProvider, ToggleGroup, ToggleGroupField, Tooltip, connectTextPreset, createAppForm, currencyFormat, describeFlag, describeList, describeValue, fieldStateAttributes, getFieldErrors, groupByBurst, groupByDay, isoDateRangeToInstants, never, normalizeFieldErrors, optionsLoad, percentFormat, storedPageSize, tableStoredValue, toast, toastManager, unitFormat, useAttachmentPreview, useBeforeUnload, useBusyPhase, useFieldContext, useFieldFocus, useFieldIds, useFieldState, useFilterView, useFold, useFormContext, useFormDisabled, useLeaveGuard, useLocale, useMediaQuery, usePresence, useReportUnsavedChanges, useRowSelection, useTheme, useTimeZone, useUnsavedChanges, whenDirty };
136
+ export { Accordion, ActiveFilters, AttachmentPreview, AttachmentTile, Avatar, AvatarGroup, Badge, Breadcrumbs, Button, Checkbox, CheckboxField, CheckboxGlyph, CheckboxGroup, CheckboxGroupField, Collapsible, Combobox, ComboboxField, ConfirmDialog, Conversation, DateField, DateInput, DateRangeField, DateRangeInput, DetailList, Dialog, Divider, Drawer, EmailField, EmptyMessage, ErrorBoundary, ErrorMessage, ErrorText, Field, FieldGroup, FieldPlaceholder, Fieldset, FileField, FileInput, FilterBar, Form, Icon, LeaveGuardDialog, Link, LinkButton, LoadingMessage, LocaleProvider, Menu, Nav, NavItemView, NumberField, NumberInput, OtpField, OtpInput, Pagination, PasswordField, PasswordStrength, PhoneField, PhotoField, PhotoInput, Popover, RadioGroup, RadioGroupField, SearchField, SegmentedControl, SegmentedControlField, Select, SelectField, SentAttachmentTile, Skeleton, Spinner, Stale, StatusMessage, Switch, SwitchField, TSFCheckboxField, TSFCheckboxGroupField, TSFComboboxField, TSFDateField, TSFDateRangeField, TSFEmailField, TSFFieldGroup, TSFFileField, TSFNumberField, TSFOtpField, TSFPasswordField, TSFPhoneField, TSFPhotoField, TSFRadioGroupField, TSFSearchField, TSFSegmentedControlField, TSFSelectField, TSFSwitchField, TSFTextField, TSFTextareaField, TSFTimeField, TSFToggleGroupField, Tabs, Tag, TagGroup, TextField, TextInput, Textarea, TextareaField, TimeField, TimeInput, TimeZoneProvider, ToastProvider, ToggleGroup, ToggleGroupField, Tooltip, connectTextPreset, createAppForm, currencyFormat, describeFlag, describeList, describeValue, fieldStateAttributes, getFieldErrors, groupByBurst, groupByDay, isoDateRangeToInstants, never, normalizeFieldErrors, optionsLoad, percentFormat, storedPageSize, tableStoredValue, toast, toastManager, unitFormat, useAttachmentPreview, useBeforeUnload, useBusyPhase, useConnectedField, useFieldContext, useFieldFocus, useFieldIds, useFieldState, useFilterView, useFold, useFormContext, useFormDisabled, useLeaveGuard, useLocale, useMediaQuery, usePresence, useReportUnsavedChanges, useRowSelection, useTheme, useTimeZone, useUnsavedChanges, whenDirty };
@@ -5,20 +5,29 @@ type Bridge = Readonly<{
5
5
  }>["bivarianceHack"];
6
6
  /** The bridges a form hook renders through `form.AppField`, by the name a field reaches each under. */
7
7
  export type AppFieldComponents = Readonly<Record<string, Bridge>>;
8
- type FormComponents = Readonly<Record<string, never>>;
9
- type AppFormHook<TFields extends AppFieldComponents> = ReturnType<typeof createFormHook<TFields, FormComponents>>;
8
+ /** The bridges that read a whole form rather than one field, such as `TSFFieldGroup`, by the name a form reaches each under. */
9
+ export type AppFormComponents = Readonly<Record<string, Bridge>>;
10
+ /** A form hook's form components when it registers none. */
11
+ export type NoFormComponents = Readonly<Record<string, never>>;
12
+ type AppFormHook<TFields extends AppFieldComponents, TForms extends AppFormComponents> = ReturnType<typeof createFormHook<TFields, TForms>>;
10
13
  /** The form hook `createAppForm` builds, with the form and field-group helpers bound to it. */
11
- export type AppForm<TFields extends AppFieldComponents> = Readonly<Pick<AppFormHook<TFields>, "useAppForm" | "withForm" | "withFieldGroup">>;
14
+ export type AppForm<TFields extends AppFieldComponents, TForms extends AppFormComponents = NoFormComponents> = Readonly<Pick<AppFormHook<TFields, TForms>, "useAppForm" | "withForm" | "withFieldGroup">>;
15
+ /** `createAppForm`, with or without form components. */
16
+ export type CreateAppForm = {
17
+ <TFields extends AppFieldComponents>(fieldComponents: TFields): AppForm<TFields>;
18
+ <TFields extends AppFieldComponents, TForms extends AppFormComponents>(fieldComponents: TFields, formComponents: TForms): AppForm<TFields, TForms>;
19
+ };
12
20
  /**
13
21
  * The app's form hook, with only the bridges it registers. A form reaches each
14
- * through `form.AppField` under its key, and a failed submit focuses the first
22
+ * field bridge through `form.AppField` under its key, and each form component,
23
+ * such as `TSFFieldGroup`, as `form.<key>`. A failed submit focuses the first
15
24
  * invalid control of the `Form.Root` the form renders in.
16
25
  *
17
26
  * @example
18
- * export const { useAppForm, withForm, withFieldGroup } = createAppForm({
19
- * TextField: TSFTextField,
20
- * SelectField: TSFSelectField,
21
- * });
27
+ * export const { useAppForm, withForm, withFieldGroup } = createAppForm(
28
+ * { TextField: TSFTextField, SelectField: TSFSelectField },
29
+ * { FieldGroup: TSFFieldGroup },
30
+ * );
22
31
  */
23
- export declare const createAppForm: <TFields extends AppFieldComponents>(fieldComponents: TFields) => AppForm<TFields>;
32
+ export declare const createAppForm: CreateAppForm;
24
33
  export {};
@@ -2,19 +2,15 @@ import { fieldContext, formContext } from "./context.js";
2
2
  import { focusFirstInvalidField } from "./failed-submit.js";
3
3
  import { createFormHook } from "@tanstack/react-form";
4
4
  // src/lib/forms/create-app-form.ts
5
- var formComponents = {};
5
+ var noFormComponents = {};
6
6
  /**
7
- * The app's form hook, with only the bridges it registers. A form reaches each
8
- * through `form.AppField` under its key, and a failed submit focuses the first
7
+ * A form hook over the given bridges, whose failed submit focuses the first
9
8
  * invalid control of the `Form.Root` the form renders in.
10
9
  *
11
10
  * @example
12
- * export const { useAppForm, withForm, withFieldGroup } = createAppForm({
13
- * TextField: TSFTextField,
14
- * SelectField: TSFSelectField,
15
- * });
11
+ * const { useAppForm } = buildAppForm({ TextField: TSFTextField }, {});
16
12
  */
17
- var createAppForm = (fieldComponents) => {
13
+ var buildAppForm = (fieldComponents, formComponents) => {
18
14
  const hook = createFormHook({
19
15
  fieldContext,
20
16
  formContext,
@@ -33,4 +29,17 @@ var createAppForm = (fieldComponents) => {
33
29
  withFieldGroup: hook.withFieldGroup
34
30
  };
35
31
  };
32
+ /**
33
+ * The app's form hook, with only the bridges it registers. A form reaches each
34
+ * field bridge through `form.AppField` under its key, and each form component,
35
+ * such as `TSFFieldGroup`, as `form.<key>`. A failed submit focuses the first
36
+ * invalid control of the `Form.Root` the form renders in.
37
+ *
38
+ * @example
39
+ * export const { useAppForm, withForm, withFieldGroup } = createAppForm(
40
+ * { TextField: TSFTextField, SelectField: TSFSelectField },
41
+ * { FieldGroup: TSFFieldGroup },
42
+ * );
43
+ */
44
+ var createAppForm = (fieldComponents, formComponents) => formComponents === void 0 ? buildAppForm(fieldComponents, noFormComponents) : buildAppForm(fieldComponents, formComponents);
36
45
  export { createAppForm };
@@ -1,3 +1,4 @@
1
1
  export * from "./create-app-form.ts";
2
2
  export { useFieldContext, useFormContext, } from "./context.tsx";
3
3
  export * from "./errors.ts";
4
+ export * from "./use-connected-field.ts";
@@ -1,4 +1,5 @@
1
1
  import { createAppForm } from "./create-app-form.js";
2
2
  import { useFieldContext, useFormContext } from "./context.js";
3
3
  import { getFieldErrors, normalizeFieldErrors } from "./errors.js";
4
- export { createAppForm, getFieldErrors, normalizeFieldErrors, useFieldContext, useFormContext };
4
+ import { useConnectedField } from "./use-connected-field.js";
5
+ export { createAppForm, getFieldErrors, normalizeFieldErrors, useConnectedField, useFieldContext, useFormContext };
@@ -15,13 +15,16 @@ export type ConnectedField<TValue> = Readonly<{
15
15
  props: ConnectedFieldProps;
16
16
  }>;
17
17
  /**
18
- * The field a bridge renders for, and the props every field takes from it:
19
- * its name, its errors as the validators returned them, `dirty`, `touched`,
20
- * `pending` while it validates, and the blur handler. The value and its change
21
- * handler are the control's own.
18
+ * The TanStack Form field a control renders in, and the props every field
19
+ * takes from it: its name, its errors as the validators returned them,
20
+ * `dirty`, `touched`, `pending` while it validates, and the blur handler. The
21
+ * value and its change handler are the control's own. Given the field's
22
+ * label, it tells an enclosing field group, whose `formatError` receives it.
22
23
  *
23
24
  * @example
24
- * const { field, props } = useConnectedField<string>();
25
- * <TextField {...props} value={field.state.value} onValueChange={field.handleChange} label={label} optionalLabel={optionalLabel} />
25
+ * const { field, props: { name, onBlur, ...state } } = useConnectedField<string>(label);
26
+ * <TextInput.Root {...state} value={field.state.value} onValueChange={field.handleChange} optionalLabel="optional">
27
+ * <TextInput.Input name={name} onBlur={onBlur} />
28
+ * </TextInput.Root>
26
29
  */
27
- export declare const useConnectedField: <TValue>() => ConnectedField<TValue>;
30
+ export declare const useConnectedField: <TValue>(label?: string) => ConnectedField<TValue>;