@eduardoalvarez/arrecife 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +114 -0
- package/README.md +868 -467
- package/dist/brand/index.cjs +112 -95
- package/dist/brand/index.d.cts +40 -39
- package/dist/brand/index.d.ts +40 -39
- package/dist/brand/index.js +5 -4
- package/dist/catalog-D13txprv.d.cts +78 -0
- package/dist/catalog-D13txprv.d.ts +78 -0
- package/dist/chart/index.cjs +100 -83
- package/dist/chart/index.d.cts +66 -66
- package/dist/chart/index.d.ts +66 -66
- package/dist/chart/index.js +14 -12
- package/dist/chunk-2WPWEIMD.js +27 -0
- package/dist/chunk-45HVCTB7.js +70 -0
- package/dist/{chunk-ZEOQKRQ7.js → chunk-727HCBD4.js} +1 -1
- package/dist/chunk-CKRSQPTX.js +36 -0
- package/dist/chunk-E6KFUSKB.js +144 -0
- package/dist/chunk-GCRII2KQ.js +86 -0
- package/dist/{chunk-YZ2SDOVZ.js → chunk-JN3IS5OS.js} +30 -30
- package/dist/chunk-ODBFN44D.js +45 -0
- package/dist/chunk-OMKSESQB.js +300 -0
- package/dist/{chunk-VPT32GPG.js → chunk-TA7TLWW4.js} +2 -2
- package/dist/chunk-WGNIRIN7.js +42 -0
- package/dist/doctor.mjs +166 -0
- package/dist/form/index.cjs +109 -92
- package/dist/form/index.d.cts +43 -42
- package/dist/form/index.d.ts +43 -42
- package/dist/form/index.js +25 -23
- package/dist/icons/index.cjs +149 -0
- package/dist/icons/index.d.cts +94 -0
- package/dist/icons/index.d.ts +94 -0
- package/dist/icons/index.js +28 -0
- package/dist/index-DlAO2JZs.d.cts +47 -0
- package/dist/index-DlAO2JZs.d.ts +47 -0
- package/dist/index.cjs +1292 -983
- package/dist/index.d.cts +927 -806
- package/dist/index.d.ts +927 -806
- package/dist/index.js +809 -778
- package/dist/{label-DuTvJGxD.d.ts → label-MgHFKnFy.d.cts} +3 -3
- package/dist/{label-DuTvJGxD.d.cts → label-MgHFKnFy.d.ts} +3 -3
- package/dist/og/index.cjs +133 -132
- package/dist/og/index.d.cts +93 -89
- package/dist/og/index.d.ts +93 -89
- package/dist/og/index.js +106 -106
- package/dist/shiki/index.cjs +28 -30
- package/dist/shiki/index.d.cts +4 -4
- package/dist/shiki/index.d.ts +4 -4
- package/dist/shiki/index.js +12 -12
- package/dist/social/index.cjs +67 -0
- package/dist/social/index.d.cts +2 -0
- package/dist/social/index.d.ts +2 -0
- package/dist/social/index.js +2 -0
- package/dist/theme/index.cjs +97 -0
- package/dist/theme/index.d.cts +144 -0
- package/dist/theme/index.d.ts +144 -0
- package/dist/theme/index.js +2 -0
- package/dist/tokens/index.cjs +159 -88
- package/dist/tokens/index.d.cts +277 -165
- package/dist/tokens/index.d.ts +277 -165
- package/dist/tokens/index.js +2 -2
- package/dist/tokens/theme.css +165 -100
- package/dist/variants/index.cjs +195 -0
- package/dist/variants/index.d.cts +195 -0
- package/dist/variants/index.d.ts +195 -0
- package/dist/variants/index.js +3 -0
- package/llms.txt +1145 -746
- package/package.json +42 -11
- package/dist/catalogo-Du5ID-Hi.d.cts +0 -77
- package/dist/catalogo-Du5ID-Hi.d.ts +0 -77
- package/dist/chunk-E3OMP2DL.js +0 -36
- package/dist/chunk-KPZNNMV5.js +0 -83
- package/dist/chunk-NHS7ETKJ.js +0 -27
- package/dist/chunk-TSPJOM6K.js +0 -229
- package/dist/chunk-UOWIDFCB.js +0 -81
- package/dist/tema/index.cjs +0 -94
- package/dist/tema/index.d.cts +0 -110
- package/dist/tema/index.d.ts +0 -110
- package/dist/tema/index.js +0 -2
package/dist/form/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var react = require('react');
|
|
@@ -32,56 +33,56 @@ var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
|
32
33
|
// src/form/index.tsx
|
|
33
34
|
var typeScale = {
|
|
34
35
|
display: { family: "display", size: 76, lineHeight: 0.96, weight: 800, tracking: "-0.035em" },
|
|
35
|
-
/**
|
|
36
|
+
/** Large metrics. Numbers, not prose: line height 1 and no descenders. */
|
|
36
37
|
stat: { family: "display", size: 46, lineHeight: 1, weight: 800, tracking: "-0.035em" },
|
|
37
38
|
h1: { family: "display", size: 44, lineHeight: 1.05, weight: 700, tracking: "-0.03em" },
|
|
38
39
|
h2: { family: "display", size: 30, lineHeight: 1.1, weight: 600, tracking: "-0.02em" },
|
|
39
40
|
h3: { family: "display", size: 25, lineHeight: 1.15, weight: 600, tracking: "-0.02em" },
|
|
40
41
|
body: { family: "sans", size: 18, lineHeight: 1.75, weight: 400 },
|
|
41
42
|
/**
|
|
42
|
-
* 17px.
|
|
43
|
+
* 17px. The large button, and the deck on interior pages.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* It earns its own step because the identity document uses it TWICE, in two
|
|
46
|
+
* different pieces: «lg 15/30 r12» with 17px text, and «h1 44/700 · deck 17px
|
|
47
|
+
* · context paragraph 15px». One use would not have justified splitting the
|
|
48
|
+
* gap between `ui` (15) and `body` (18); two did.
|
|
48
49
|
*/
|
|
49
50
|
lead: { family: "sans", size: 17, lineHeight: 1.5, weight: 400 },
|
|
50
51
|
ui: { family: "sans", size: 15, lineHeight: 1.6, weight: 400 },
|
|
51
52
|
label: { family: "sans", size: 13, lineHeight: 1.5, weight: 500 },
|
|
52
53
|
/**
|
|
53
|
-
*
|
|
54
|
+
* The status-badge scale: sans 12.5/500, squared off.
|
|
54
55
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
56
|
+
* That is half a pixel below `label`, and this time the half pixel matters: a
|
|
57
|
+
* status badge sits inside a table or next to a title, and at 13 it competed
|
|
58
|
+
* with the text it accompanies. The document specifies 12.5 and it shows.
|
|
58
59
|
*/
|
|
59
60
|
tag: { family: "sans", size: 12.5, lineHeight: 1.4, weight: 500 },
|
|
60
61
|
/**
|
|
61
|
-
*
|
|
62
|
+
* The category and metric scale: mono 11.5.
|
|
62
63
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* 5.57:1
|
|
64
|
+
* It breaks the floor set by `limits.minScreenPx`, deliberately. That floor
|
|
65
|
+
* protects TEXT — what you read in a sentence — and a one-word pill is not
|
|
66
|
+
* running text: it is a mark. Contrast is still measured and still passes AA
|
|
67
|
+
* (plankton 5.57:1 over abyss), which is the part that is not negotiable.
|
|
67
68
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
69
|
+
* At 13 the three badge families grew past the size of a small button and
|
|
70
|
+
* outweighed the title they accompany. See `docs/decisions.md`.
|
|
70
71
|
*/
|
|
71
72
|
chip: { family: "mono", size: 11.5, lineHeight: 1.4, weight: 400 },
|
|
72
73
|
/**
|
|
73
|
-
* Mono
|
|
74
|
-
*
|
|
74
|
+
* Mono with NO transform: dates, paths, versions, file names, the footer
|
|
75
|
+
* signature and metric labels. It is most of the mono in the system.
|
|
75
76
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
77
|
+
* It exists because `eyebrow` ships `uppercase` and that is not a preference
|
|
78
|
+
* you can switch off: it IS the eyebrow scale. An `18 Aug 2026` in small caps
|
|
79
|
+
* or a `pose-laptop-coffee.png` in all caps are wrong, and without this step
|
|
80
|
+
* the only way out was a `normal-case` at every call site.
|
|
80
81
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* 12.5
|
|
82
|
+
* The document says 12.5. This is 13 for the same reason `textMuted` was
|
|
83
|
+
* corrected: `limits.minScreenPx` is 13 and plankton is «never under 13px».
|
|
84
|
+
* This scale is exactly where muted metadata gets written, so putting it at
|
|
85
|
+
* 12.5 would have made its most common use illegible by half a pixel.
|
|
85
86
|
*/
|
|
86
87
|
meta: { family: "mono", size: 13, lineHeight: 1.6, weight: 400 },
|
|
87
88
|
eyebrow: { family: "mono", size: 12, tracking: "0.12em", transform: "uppercase" }
|
|
@@ -97,8 +98,24 @@ var control = {
|
|
|
97
98
|
sm: 14,
|
|
98
99
|
md: 22,
|
|
99
100
|
lg: 30,
|
|
100
|
-
/**
|
|
101
|
-
icon: 42
|
|
101
|
+
/** Icon button: square, no text. */
|
|
102
|
+
icon: 42,
|
|
103
|
+
/**
|
|
104
|
+
* The dense icon button, 32×32.
|
|
105
|
+
*
|
|
106
|
+
* 42 is the right measure for a control you hit with a thumb, and the four
|
|
107
|
+
* reading sites are where that fits. `cursos` is the odd one out: it is the
|
|
108
|
+
* only admin app of the set, with three actions per table row, and at 42 the
|
|
109
|
+
* row grows with them — the original used 24 and 28.
|
|
110
|
+
*
|
|
111
|
+
* It is 32 and not 28 because 32 is `sm`'s height. A dense icon button lines
|
|
112
|
+
* up with a small text button, so a toolbar mixing the two stays on one
|
|
113
|
+
* baseline; 28 would have been a fifth height that matches nothing.
|
|
114
|
+
*
|
|
115
|
+
* It does not replace `icon`. A page's primary action stays at 42; this is for
|
|
116
|
+
* a row of a table. See `docs/decisions.md` § 22.
|
|
117
|
+
*/
|
|
118
|
+
iconSm: 32
|
|
102
119
|
};
|
|
103
120
|
var spacing = {
|
|
104
121
|
stepXs: 8,
|
|
@@ -110,21 +127,21 @@ var spacing = {
|
|
|
110
127
|
};
|
|
111
128
|
|
|
112
129
|
// src/lib/cn.ts
|
|
113
|
-
var kebab = (
|
|
114
|
-
var
|
|
115
|
-
var
|
|
116
|
-
var
|
|
117
|
-
var
|
|
130
|
+
var kebab = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
131
|
+
var scales = Object.keys(typeScale);
|
|
132
|
+
var radii = Object.keys(radius);
|
|
133
|
+
var namespaces = Object.keys(spacing).map(kebab);
|
|
134
|
+
var controls = Object.keys(control).map((name) => `control-${kebab(name)}`);
|
|
118
135
|
var twMerge = tailwindMerge.extendTailwindMerge({
|
|
119
136
|
extend: {
|
|
120
137
|
classGroups: {
|
|
121
|
-
"font-size": [{ text:
|
|
122
|
-
rounded: [{ rounded:
|
|
123
|
-
p: [{ p:
|
|
124
|
-
px: [{ px: [...
|
|
125
|
-
py: [{ py:
|
|
126
|
-
gap: [{ gap:
|
|
127
|
-
size: [{ size:
|
|
138
|
+
"font-size": [{ text: scales }],
|
|
139
|
+
rounded: [{ rounded: radii }],
|
|
140
|
+
p: [{ p: namespaces }],
|
|
141
|
+
px: [{ px: [...namespaces, ...controls] }],
|
|
142
|
+
py: [{ py: namespaces }],
|
|
143
|
+
gap: [{ gap: namespaces }],
|
|
144
|
+
size: [{ size: controls }]
|
|
128
145
|
}
|
|
129
146
|
}
|
|
130
147
|
});
|
|
@@ -144,46 +161,31 @@ function Label({ className, ...props }) {
|
|
|
144
161
|
}
|
|
145
162
|
);
|
|
146
163
|
}
|
|
147
|
-
var
|
|
148
|
-
display: "h1",
|
|
149
|
-
stat: "p",
|
|
150
|
-
h1: "h1",
|
|
151
|
-
h2: "h2",
|
|
152
|
-
h3: "h3",
|
|
153
|
-
body: "p",
|
|
154
|
-
lead: "p",
|
|
155
|
-
ui: "p",
|
|
156
|
-
label: "span",
|
|
157
|
-
tag: "span",
|
|
158
|
-
meta: "p",
|
|
159
|
-
chip: "span",
|
|
160
|
-
eyebrow: "p"
|
|
161
|
-
};
|
|
162
|
-
var texto = classVarianceAuthority.cva("", {
|
|
164
|
+
var text = classVarianceAuthority.cva("", {
|
|
163
165
|
variants: {
|
|
164
166
|
variant: {
|
|
165
167
|
display: "text-display font-display",
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
+
// Large metrics: 46px of display. It is the only scale designed for a
|
|
169
|
+
// number, which is why its line height is 1.
|
|
168
170
|
stat: "text-stat font-display",
|
|
169
171
|
h1: "text-h1 font-display",
|
|
170
172
|
h2: "text-h2 font-display",
|
|
171
173
|
h3: "text-h3 font-display",
|
|
172
174
|
body: "text-body font-sans",
|
|
173
|
-
// 17px:
|
|
175
|
+
// 17px: the deck on interior pages and the large button.
|
|
174
176
|
lead: "text-lead font-sans",
|
|
175
177
|
ui: "text-ui font-sans",
|
|
176
178
|
label: "text-label font-sans",
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
+
// The two badge scales. `tag` is status (sans 12.5/500) and `chip` is
|
|
180
|
+
// category and metric (mono 11.5). Neither transforms the text.
|
|
179
181
|
tag: "text-tag font-sans",
|
|
180
182
|
chip: "text-chip font-mono",
|
|
181
|
-
// Mono
|
|
182
|
-
//
|
|
183
|
-
//
|
|
183
|
+
// Mono with NO transform: dates, paths, versions, file names and the
|
|
184
|
+
// footer signature. It is the step that was missing, and the reason every
|
|
185
|
+
// call site ended up writing `variant="eyebrow" className="normal-case"`.
|
|
184
186
|
meta: "text-meta font-mono",
|
|
185
|
-
// `uppercase`
|
|
186
|
-
//
|
|
187
|
+
// `uppercase` does not fit in a size token: text-transform is not a
|
|
188
|
+
// modifier of --text-*. Which is why the variant sets it, not theme.css.
|
|
187
189
|
eyebrow: "text-eyebrow font-mono uppercase"
|
|
188
190
|
},
|
|
189
191
|
tone: {
|
|
@@ -199,6 +201,21 @@ var texto = classVarianceAuthority.cva("", {
|
|
|
199
201
|
},
|
|
200
202
|
defaultVariants: { variant: "body", tone: "primary" }
|
|
201
203
|
});
|
|
204
|
+
var LABEL = {
|
|
205
|
+
display: "h1",
|
|
206
|
+
stat: "p",
|
|
207
|
+
h1: "h1",
|
|
208
|
+
h2: "h2",
|
|
209
|
+
h3: "h3",
|
|
210
|
+
body: "p",
|
|
211
|
+
lead: "p",
|
|
212
|
+
ui: "p",
|
|
213
|
+
label: "span",
|
|
214
|
+
tag: "span",
|
|
215
|
+
meta: "p",
|
|
216
|
+
chip: "span",
|
|
217
|
+
eyebrow: "p"
|
|
218
|
+
};
|
|
202
219
|
function Text({
|
|
203
220
|
className,
|
|
204
221
|
variant,
|
|
@@ -209,34 +226,34 @@ function Text({
|
|
|
209
226
|
children,
|
|
210
227
|
...props
|
|
211
228
|
}) {
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
const
|
|
229
|
+
const scale = variant ?? "body";
|
|
230
|
+
const clamp = measure ?? scale === "body";
|
|
231
|
+
const classes = cn(text({ variant, tone }), clamp && "max-w-measure", className);
|
|
215
232
|
if (asChild) {
|
|
216
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactSlot.Slot, { className:
|
|
233
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactSlot.Slot, { className: classes, ...props, children });
|
|
217
234
|
}
|
|
218
|
-
const
|
|
219
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
235
|
+
const Label2 = as ?? LABEL[scale];
|
|
236
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Label2, { className: classes, ...props, children });
|
|
220
237
|
}
|
|
221
238
|
var Form = reactHookForm.FormProvider;
|
|
222
|
-
var
|
|
239
|
+
var Field = react.createContext(null);
|
|
223
240
|
var Item = react.createContext(null);
|
|
224
241
|
function FormField(props) {
|
|
225
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
242
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Field.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.Controller, { ...props }) });
|
|
226
243
|
}
|
|
227
244
|
function useFormField() {
|
|
228
|
-
const
|
|
245
|
+
const field = react.useContext(Field);
|
|
229
246
|
const item = react.useContext(Item);
|
|
230
247
|
const { getFieldState } = reactHookForm.useFormContext();
|
|
231
|
-
const
|
|
232
|
-
if (!
|
|
233
|
-
if (!item) throw new Error("useFormField
|
|
248
|
+
const state = reactHookForm.useFormState({ name: field?.name ?? "" });
|
|
249
|
+
if (!field) throw new Error("useFormField must be used inside a <FormField>.");
|
|
250
|
+
if (!item) throw new Error("useFormField must be used inside a <FormItem>.");
|
|
234
251
|
return {
|
|
235
|
-
name:
|
|
252
|
+
name: field.name,
|
|
236
253
|
id: item.id,
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
...getFieldState(
|
|
254
|
+
descriptionId: `${item.id}-descripcion`,
|
|
255
|
+
messageId: `${item.id}-mensaje`,
|
|
256
|
+
...getFieldState(field.name, state)
|
|
240
257
|
};
|
|
241
258
|
}
|
|
242
259
|
function FormItem({ className, ...props }) {
|
|
@@ -248,45 +265,45 @@ function FormLabel({ className, ...props }) {
|
|
|
248
265
|
return /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: id, className, ...props });
|
|
249
266
|
}
|
|
250
267
|
function FormControl({ ...props }) {
|
|
251
|
-
const { error, id,
|
|
268
|
+
const { error, id, descriptionId, messageId } = useFormField();
|
|
252
269
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
253
270
|
reactSlot.Slot,
|
|
254
271
|
{
|
|
255
272
|
id,
|
|
256
|
-
"aria-describedby": error ? `${
|
|
273
|
+
"aria-describedby": error ? `${descriptionId} ${messageId}` : descriptionId,
|
|
257
274
|
"aria-invalid": error ? true : void 0,
|
|
258
275
|
...props
|
|
259
276
|
}
|
|
260
277
|
);
|
|
261
278
|
}
|
|
262
279
|
function FormDescription({ className, ...props }) {
|
|
263
|
-
const {
|
|
280
|
+
const { descriptionId } = useFormField();
|
|
264
281
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
265
282
|
Text,
|
|
266
283
|
{
|
|
267
284
|
as: "p",
|
|
268
285
|
variant: "label",
|
|
269
286
|
tone: "muted",
|
|
270
|
-
id:
|
|
287
|
+
id: descriptionId,
|
|
271
288
|
className: cn("font-normal", className),
|
|
272
289
|
...props
|
|
273
290
|
}
|
|
274
291
|
);
|
|
275
292
|
}
|
|
276
293
|
function FormMessage({ className, children, ...props }) {
|
|
277
|
-
const { error,
|
|
278
|
-
const
|
|
279
|
-
if (!
|
|
294
|
+
const { error, messageId } = useFormField();
|
|
295
|
+
const body = error?.message ? String(error.message) : children;
|
|
296
|
+
if (!body) return null;
|
|
280
297
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
281
298
|
Text,
|
|
282
299
|
{
|
|
283
300
|
as: "p",
|
|
284
301
|
variant: "label",
|
|
285
302
|
tone: "error",
|
|
286
|
-
id:
|
|
303
|
+
id: messageId,
|
|
287
304
|
className,
|
|
288
305
|
...props,
|
|
289
|
-
children:
|
|
306
|
+
children: body
|
|
290
307
|
}
|
|
291
308
|
);
|
|
292
309
|
}
|
package/dist/form/index.d.cts
CHANGED
|
@@ -3,44 +3,45 @@ import { ComponentPropsWithoutRef } from 'react';
|
|
|
3
3
|
import * as react_hook_form from 'react-hook-form';
|
|
4
4
|
import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
|
|
5
5
|
import { Slot } from '@radix-ui/react-slot';
|
|
6
|
-
import { L as Label } from '../label-
|
|
6
|
+
import { L as Label } from '../label-MgHFKnFy.cjs';
|
|
7
7
|
import '@radix-ui/react-label';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* The layer that ties the controls to a form with validation and messages.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* `Textarea`,
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* The library already had `Input`, `Label`, `Checkbox`, `RadioGroup`, `Select`
|
|
13
|
+
* and `Textarea`, and none of them knew anything about the others: the
|
|
14
|
+
* `htmlFor`, the error message's `aria-describedby` and the `aria-invalid` had
|
|
15
|
+
* to be wired by hand on every field of every project. That gets forgotten, and
|
|
16
|
+
* when it does the failure is that a screen reader never announces why the field
|
|
17
|
+
* is red.
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* It is published at `@eduardoalvarez/arrecife/form`, NOT at the root, and that
|
|
20
|
+
* is deliberate. React Hook Form is an optional peer dependency: only one of the
|
|
21
|
+
* five projects uses it, and if this hung off the main index the other four
|
|
22
|
+
* would have to install it just so their bundler could resolve an import they
|
|
23
|
+
* never execute. It is the same reason `./og` and `./shiki` live apart, seen
|
|
24
|
+
* from the other side: there React is kept out of the way, here RHF is.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* The shape is shadcn's — `FormField` on `Controller`, field context and item
|
|
27
|
+
* context — because the project consuming it is already written against it and
|
|
28
|
+
* reinventing it would only cost them a migration. What changes is the visual
|
|
29
|
+
* vocabulary: the ids, the scale and the tone come from the system.
|
|
29
30
|
*/
|
|
30
31
|
declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>({ children, watch, getValues, getErrors, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
|
|
31
32
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* A controlled field. It wraps RHF's `Controller` and also publishes the name
|
|
34
|
+
* into context, which is where the label and the message read it from without
|
|
35
|
+
* having to repeat it three times.
|
|
35
36
|
*/
|
|
36
37
|
declare function FormField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>): react.JSX.Element;
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
39
|
+
* What any piece of the field needs: the name, the three ids and the validation
|
|
40
|
+
* state.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* It throws if used outside a `FormField` or a `FormItem`, with a message saying
|
|
43
|
+
* which of the two is missing. Returning something half-formed would be worse:
|
|
44
|
+
* the field would render with no `aria-describedby` and nothing would warn.
|
|
44
45
|
*/
|
|
45
46
|
declare function useFormField(): {
|
|
46
47
|
invalid: boolean;
|
|
@@ -50,36 +51,36 @@ declare function useFormField(): {
|
|
|
50
51
|
error?: react_hook_form.FieldError;
|
|
51
52
|
name: string;
|
|
52
53
|
id: string;
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
descriptionId: string;
|
|
55
|
+
messageId: string;
|
|
55
56
|
};
|
|
56
|
-
/**
|
|
57
|
+
/** The field's box: label, control, help and message, in a column. */
|
|
57
58
|
declare function FormItem({ className, ...props }: ComponentPropsWithoutRef<'div'>): react.JSX.Element;
|
|
58
59
|
/**
|
|
59
|
-
*
|
|
60
|
+
* The label is NOT tinted red when the field fails.
|
|
60
61
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
62
|
+
* The system keeps the semantic color on the border and on the glyph, and the
|
|
63
|
+
* text on a text token: the control's border is already in `error` and so is the
|
|
64
|
+
* message below it, so tinting the label as well is three reds for one failure.
|
|
64
65
|
*/
|
|
65
66
|
declare function FormLabel({ className, ...props }: ComponentPropsWithoutRef<typeof Label>): react.JSX.Element;
|
|
66
67
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
68
|
+
* Wraps the control and wires its attributes: the `id` the label points at, the
|
|
69
|
+
* `aria-describedby` with the help and the message, and the `aria-invalid`.
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* It is a `Slot`, so the child can be any of the system's controls — `Input`,
|
|
72
|
+
* `Textarea`, `SelectTrigger` — without this knowing which.
|
|
72
73
|
*/
|
|
73
74
|
declare function FormControl({ ...props }: ComponentPropsWithoutRef<typeof Slot>): react.JSX.Element;
|
|
74
|
-
/**
|
|
75
|
+
/** The field's help text. It is always announced, error or not. */
|
|
75
76
|
declare function FormDescription({ className, ...props }: ComponentPropsWithoutRef<'p'>): react.JSX.Element;
|
|
76
77
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
78
|
+
* The validation message. With no error it renders nothing: a gap reserved for
|
|
79
|
+
* the failure shifts the rest of the form every time it appears.
|
|
79
80
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
* It takes its text from RHF's error; `children` is for a message that does not
|
|
82
|
+
* come from the schema — the 409 the server returns and that no client-side
|
|
83
|
+
* validator can anticipate.
|
|
83
84
|
*/
|
|
84
85
|
declare function FormMessage({ className, children, ...props }: ComponentPropsWithoutRef<'p'>): react.JSX.Element | null;
|
|
85
86
|
|
package/dist/form/index.d.ts
CHANGED
|
@@ -3,44 +3,45 @@ import { ComponentPropsWithoutRef } from 'react';
|
|
|
3
3
|
import * as react_hook_form from 'react-hook-form';
|
|
4
4
|
import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
|
|
5
5
|
import { Slot } from '@radix-ui/react-slot';
|
|
6
|
-
import { L as Label } from '../label-
|
|
6
|
+
import { L as Label } from '../label-MgHFKnFy.js';
|
|
7
7
|
import '@radix-ui/react-label';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* The layer that ties the controls to a form with validation and messages.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* `Textarea`,
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* The library already had `Input`, `Label`, `Checkbox`, `RadioGroup`, `Select`
|
|
13
|
+
* and `Textarea`, and none of them knew anything about the others: the
|
|
14
|
+
* `htmlFor`, the error message's `aria-describedby` and the `aria-invalid` had
|
|
15
|
+
* to be wired by hand on every field of every project. That gets forgotten, and
|
|
16
|
+
* when it does the failure is that a screen reader never announces why the field
|
|
17
|
+
* is red.
|
|
17
18
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* It is published at `@eduardoalvarez/arrecife/form`, NOT at the root, and that
|
|
20
|
+
* is deliberate. React Hook Form is an optional peer dependency: only one of the
|
|
21
|
+
* five projects uses it, and if this hung off the main index the other four
|
|
22
|
+
* would have to install it just so their bundler could resolve an import they
|
|
23
|
+
* never execute. It is the same reason `./og` and `./shiki` live apart, seen
|
|
24
|
+
* from the other side: there React is kept out of the way, here RHF is.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* The shape is shadcn's — `FormField` on `Controller`, field context and item
|
|
27
|
+
* context — because the project consuming it is already written against it and
|
|
28
|
+
* reinventing it would only cost them a migration. What changes is the visual
|
|
29
|
+
* vocabulary: the ids, the scale and the tone come from the system.
|
|
29
30
|
*/
|
|
30
31
|
declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>({ children, watch, getValues, getErrors, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
|
|
31
32
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* A controlled field. It wraps RHF's `Controller` and also publishes the name
|
|
34
|
+
* into context, which is where the label and the message read it from without
|
|
35
|
+
* having to repeat it three times.
|
|
35
36
|
*/
|
|
36
37
|
declare function FormField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>): react.JSX.Element;
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
39
|
+
* What any piece of the field needs: the name, the three ids and the validation
|
|
40
|
+
* state.
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* It throws if used outside a `FormField` or a `FormItem`, with a message saying
|
|
43
|
+
* which of the two is missing. Returning something half-formed would be worse:
|
|
44
|
+
* the field would render with no `aria-describedby` and nothing would warn.
|
|
44
45
|
*/
|
|
45
46
|
declare function useFormField(): {
|
|
46
47
|
invalid: boolean;
|
|
@@ -50,36 +51,36 @@ declare function useFormField(): {
|
|
|
50
51
|
error?: react_hook_form.FieldError;
|
|
51
52
|
name: string;
|
|
52
53
|
id: string;
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
descriptionId: string;
|
|
55
|
+
messageId: string;
|
|
55
56
|
};
|
|
56
|
-
/**
|
|
57
|
+
/** The field's box: label, control, help and message, in a column. */
|
|
57
58
|
declare function FormItem({ className, ...props }: ComponentPropsWithoutRef<'div'>): react.JSX.Element;
|
|
58
59
|
/**
|
|
59
|
-
*
|
|
60
|
+
* The label is NOT tinted red when the field fails.
|
|
60
61
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
62
|
+
* The system keeps the semantic color on the border and on the glyph, and the
|
|
63
|
+
* text on a text token: the control's border is already in `error` and so is the
|
|
64
|
+
* message below it, so tinting the label as well is three reds for one failure.
|
|
64
65
|
*/
|
|
65
66
|
declare function FormLabel({ className, ...props }: ComponentPropsWithoutRef<typeof Label>): react.JSX.Element;
|
|
66
67
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
68
|
+
* Wraps the control and wires its attributes: the `id` the label points at, the
|
|
69
|
+
* `aria-describedby` with the help and the message, and the `aria-invalid`.
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* It is a `Slot`, so the child can be any of the system's controls — `Input`,
|
|
72
|
+
* `Textarea`, `SelectTrigger` — without this knowing which.
|
|
72
73
|
*/
|
|
73
74
|
declare function FormControl({ ...props }: ComponentPropsWithoutRef<typeof Slot>): react.JSX.Element;
|
|
74
|
-
/**
|
|
75
|
+
/** The field's help text. It is always announced, error or not. */
|
|
75
76
|
declare function FormDescription({ className, ...props }: ComponentPropsWithoutRef<'p'>): react.JSX.Element;
|
|
76
77
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
78
|
+
* The validation message. With no error it renders nothing: a gap reserved for
|
|
79
|
+
* the failure shifts the rest of the form every time it appears.
|
|
79
80
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
81
|
+
* It takes its text from RHF's error; `children` is for a message that does not
|
|
82
|
+
* come from the schema — the 409 the server returns and that no client-side
|
|
83
|
+
* validator can anticipate.
|
|
83
84
|
*/
|
|
84
85
|
declare function FormMessage({ className, children, ...props }: ComponentPropsWithoutRef<'p'>): react.JSX.Element | null;
|
|
85
86
|
|