@carbonbits/sixr 1.3.0 → 1.5.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/README.md +204 -66
- package/dist/button.cjs +223 -0
- package/dist/button.cjs.map +1 -0
- package/dist/button.d.cts +34 -0
- package/dist/button.d.ts +34 -0
- package/dist/button.js +4 -0
- package/dist/button.js.map +1 -0
- package/dist/chunk-HDTW4FRT.js +111 -0
- package/dist/chunk-HDTW4FRT.js.map +1 -0
- package/dist/chunk-NZHHNVXZ.js +118 -0
- package/dist/chunk-NZHHNVXZ.js.map +1 -0
- package/dist/email-input.cjs +433 -0
- package/dist/email-input.cjs.map +1 -0
- package/dist/email-input.d.cts +12 -0
- package/dist/email-input.d.ts +12 -0
- package/dist/email-input.js +416 -0
- package/dist/email-input.js.map +1 -0
- package/dist/field.cjs +206 -0
- package/dist/field.cjs.map +1 -0
- package/dist/field.d.cts +80 -0
- package/dist/field.d.ts +80 -0
- package/dist/field.js +186 -0
- package/dist/field.js.map +1 -0
- package/dist/form.cjs +283 -42
- package/dist/form.cjs.map +1 -1
- package/dist/form.d.cts +79 -10
- package/dist/form.d.ts +79 -10
- package/dist/form.js +285 -45
- package/dist/form.js.map +1 -1
- package/dist/index-CdYkd6zz.d.cts +22 -0
- package/dist/index-CdYkd6zz.d.ts +22 -0
- package/dist/index.cjs +217 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +146 -46
- package/dist/index.d.ts +146 -46
- package/dist/index.js +2 -0
- package/dist/password-input.cjs +449 -0
- package/dist/password-input.cjs.map +1 -0
- package/dist/password-input.d.cts +19 -0
- package/dist/password-input.d.ts +19 -0
- package/dist/password-input.js +434 -0
- package/dist/password-input.js.map +1 -0
- package/dist/phone-input.cjs +429 -0
- package/dist/phone-input.cjs.map +1 -0
- package/dist/phone-input.d.cts +12 -0
- package/dist/phone-input.d.ts +12 -0
- package/dist/phone-input.js +412 -0
- package/dist/phone-input.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/text-input.cjs +359 -147
- package/dist/text-input.cjs.map +1 -1
- package/dist/text-input.d.cts +9 -58
- package/dist/text-input.d.ts +9 -58
- package/dist/text-input.js +365 -150
- package/dist/text-input.js.map +1 -1
- package/dist/typography.cjs +120 -0
- package/dist/typography.cjs.map +1 -0
- package/dist/typography.d.cts +46 -0
- package/dist/typography.d.ts +46 -0
- package/dist/typography.js +3 -0
- package/dist/typography.js.map +1 -0
- package/package.json +69 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,38 +1,22 @@
|
|
|
1
|
+
import { ButtonProps } from './button.js';
|
|
2
|
+
export { Button, ButtonSize, ButtonVariant } from './button.js';
|
|
1
3
|
export { Cart, CartProduct, CartProps } from './cart.js';
|
|
2
|
-
import {
|
|
4
|
+
import { ComponentPropsWithoutRef, ReactNode, FormHTMLAttributes } from 'react';
|
|
5
|
+
import { Label } from '@radix-ui/react-label';
|
|
6
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
7
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
8
|
+
import { FieldValues, UseFormReturn, DefaultValues, Mode } from 'react-hook-form';
|
|
9
|
+
export { Typography, TypographyElement, TypographyProps, TypographyTone, TypographyVariant, TypographyWeight } from './typography.js';
|
|
3
10
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* keeps zod out of this module's public types, so consumers who only want an
|
|
8
|
-
* input do not have to install zod to typecheck it.
|
|
9
|
-
*/
|
|
10
|
-
type TextInputSchema = {
|
|
11
|
-
safeParse: (value: unknown) => {
|
|
12
|
-
success: true;
|
|
13
|
-
} | {
|
|
14
|
-
success: false;
|
|
15
|
-
error: {
|
|
16
|
-
issues: readonly {
|
|
17
|
-
message: string;
|
|
18
|
-
}[];
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
/** Outcome of a single validation pass, handed to `onValidationChange`. */
|
|
23
|
-
type TextInputValidation = {
|
|
24
|
-
valid: boolean;
|
|
25
|
-
/** First issue reported by the schema, or `undefined` when valid. */
|
|
26
|
-
error?: string;
|
|
27
|
-
};
|
|
28
|
-
type TextInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "defaultValue" | "type"> & {
|
|
11
|
+
type InputFieldProps = Omit<ComponentPropsWithoutRef<"input">, "name" | "type"> & {
|
|
12
|
+
/** The form field this input edits — the key in the `Form`'s values. */
|
|
13
|
+
name: string;
|
|
29
14
|
label?: string;
|
|
30
15
|
/** Guidance under the field. Replaced by the error message while invalid. */
|
|
31
16
|
hint?: ReactNode;
|
|
32
17
|
/**
|
|
33
18
|
* Error supplied by the caller — a server-side or cross-field failure. Takes
|
|
34
|
-
* precedence over the schema
|
|
35
|
-
* of what `schema` makes of the value on its own.
|
|
19
|
+
* precedence over what the form's schema reports for this field.
|
|
36
20
|
*/
|
|
37
21
|
error?: string;
|
|
38
22
|
/** Renders the design's muted "Optional" marker at the end of the label. */
|
|
@@ -41,24 +25,140 @@ type TextInputProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "
|
|
|
41
25
|
action?: ReactNode;
|
|
42
26
|
/** Trailing in-field slot, for affordances like the design's password peek. */
|
|
43
27
|
trailing?: ReactNode;
|
|
44
|
-
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* An email address. Fixes `type="email"` and the keyboard and autofill hints
|
|
32
|
+
* that go with it. Validate it with `emailSchema` from
|
|
33
|
+
* `@carbonbits/sixr/validation` in the enclosing `Form`'s schema.
|
|
34
|
+
*/
|
|
35
|
+
type EmailInputProps = InputFieldProps;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The structure behind every form field, with no styling of its own: an id
|
|
39
|
+
* shared by label and control, the error and description ids the control is
|
|
40
|
+
* described by, the field's validity, and — inside a `Form` — the
|
|
41
|
+
* react-hook-form bindings (`value`, `onChange`, `onBlur`, `ref`) that keep
|
|
42
|
+
* the control registered.
|
|
43
|
+
*
|
|
44
|
+
* Styled components compose these primitives with their own classes
|
|
45
|
+
* (`TextInput` and friends do), and a screen that needs a control the
|
|
46
|
+
* library does not ship — a select, a code entry, a toggle — composes them
|
|
47
|
+
* the same way. Everything here is a plain element or a Radix `Slot`, so the
|
|
48
|
+
* styling decisions stay with whoever renders the field.
|
|
49
|
+
*
|
|
50
|
+
* Outside a `Form` the primitives still wire label, control and messages
|
|
51
|
+
* together; the control just isn't registered anywhere and the error comes
|
|
52
|
+
* from the `error` prop alone.
|
|
53
|
+
*/
|
|
54
|
+
type FieldBindings = {
|
|
55
|
+
name: string;
|
|
56
|
+
value?: unknown;
|
|
57
|
+
onChange?: (event: unknown) => void;
|
|
58
|
+
onBlur?: () => void;
|
|
59
|
+
ref?: (instance: HTMLElement | null) => void;
|
|
60
|
+
};
|
|
61
|
+
type FieldContextValue = {
|
|
62
|
+
id: string;
|
|
63
|
+
name: string;
|
|
64
|
+
descriptionId: string;
|
|
65
|
+
messageId: string;
|
|
66
|
+
error: string | undefined;
|
|
67
|
+
invalid: boolean;
|
|
68
|
+
required: boolean;
|
|
69
|
+
disabled: boolean;
|
|
70
|
+
hasDescription: boolean;
|
|
71
|
+
setHasDescription: (present: boolean) => void;
|
|
72
|
+
bindings: FieldBindings;
|
|
73
|
+
};
|
|
74
|
+
type FieldRootProps = ComponentPropsWithoutRef<"div"> & {
|
|
75
|
+
/** The form field this wires up — the key in the `Form`'s values. */
|
|
76
|
+
name: string;
|
|
77
|
+
/** A caller-supplied error. Outranks whatever the form's schema reports. */
|
|
78
|
+
error?: string;
|
|
79
|
+
required?: boolean;
|
|
80
|
+
disabled?: boolean;
|
|
81
|
+
/** Render the child element as the root instead of a `div`. */
|
|
82
|
+
asChild?: boolean;
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
};
|
|
85
|
+
type FieldLabelProps = ComponentPropsWithoutRef<typeof Label>;
|
|
86
|
+
type FieldControlProps = ComponentPropsWithoutRef<typeof Slot>;
|
|
87
|
+
type FieldDescriptionProps = ComponentPropsWithoutRef<"p"> & {
|
|
88
|
+
asChild?: boolean;
|
|
89
|
+
};
|
|
90
|
+
type FieldMessageProps = ComponentPropsWithoutRef<"p"> & {
|
|
91
|
+
asChild?: boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A `<form>` on react-hook-form. The schema — any Standard Schema, which
|
|
96
|
+
* every zod 4 schema is — validates the whole form: on first blur per field,
|
|
97
|
+
* then on every change once a field has gone invalid, and again on submit.
|
|
98
|
+
* Fields register themselves through `FieldRoot` (and so through every
|
|
99
|
+
* input in this library), so a form is the schema, the inputs and a submit.
|
|
100
|
+
*
|
|
101
|
+
* `onSubmit` only runs with values the schema accepted, typed as its output.
|
|
102
|
+
* Throwing from it — or calling `form.setError("root", …)` — surfaces the
|
|
103
|
+
* message through `FormError`. While it is pending the fields are disabled
|
|
104
|
+
* and `SubmitButton` shows its spinner.
|
|
105
|
+
*
|
|
106
|
+
* Pass your own `form` (from `useFormInstance`) when a screen needs to reach
|
|
107
|
+
* the instance itself, for `setError`, `reset` or `watch`.
|
|
108
|
+
*/
|
|
109
|
+
type FormSchema = StandardSchemaV1<FieldValues, FieldValues>;
|
|
110
|
+
type FormInput<Schema extends FormSchema> = StandardSchemaV1.InferInput<Schema>;
|
|
111
|
+
type FormOutput<Schema extends FormSchema> = StandardSchemaV1.InferOutput<Schema>;
|
|
112
|
+
type FormInstance<Schema extends FormSchema> = UseFormReturn<FormInput<Schema>, unknown, FormOutput<Schema>>;
|
|
113
|
+
type UseFormInstanceOptions<Schema extends FormSchema> = {
|
|
114
|
+
schema?: Schema;
|
|
115
|
+
defaultValues?: DefaultValues<FormInput<Schema>>;
|
|
116
|
+
/** When a field first validates. `onTouched`: first blur, then every change. */
|
|
117
|
+
mode?: Mode;
|
|
118
|
+
};
|
|
119
|
+
type FormProps<Schema extends FormSchema = FormSchema> = Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit"> & UseFormInstanceOptions<Schema> & {
|
|
120
|
+
onSubmit: (values: FormOutput<Schema>, form: FormInstance<Schema>) => void | Promise<void>;
|
|
121
|
+
/** An instance from `useFormInstance`, when the screen needs it too. */
|
|
122
|
+
form?: FormInstance<Schema>;
|
|
123
|
+
children: ReactNode;
|
|
124
|
+
};
|
|
125
|
+
type FormErrorProps = {
|
|
126
|
+
/** A message to show in place of the form's own root error. */
|
|
127
|
+
children?: ReactNode;
|
|
128
|
+
className?: string;
|
|
129
|
+
};
|
|
130
|
+
type SubmitButtonProps = Omit<ButtonProps, "type" | "loading" | "asChild">;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A password. Fixes `type="password"` and owns the design's in-field peek
|
|
134
|
+
* affordance, so the trailing slot is not exposed here — the toggle is it.
|
|
135
|
+
*/
|
|
136
|
+
type PasswordInputProps = Omit<InputFieldProps, "trailing"> & {
|
|
137
|
+
/** Show the "Show"/"Hide" toggle. On by default, as the design has it. */
|
|
138
|
+
revealable?: boolean;
|
|
139
|
+
/** Labels for the toggle, for localisation. */
|
|
140
|
+
revealLabels?: {
|
|
141
|
+
show: string;
|
|
142
|
+
hide: string;
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A phone number. Fixes `type="tel"` and the numeric keypad. Validate it with
|
|
148
|
+
* `phoneSchema` from `@carbonbits/sixr/validation` in the enclosing `Form`'s
|
|
149
|
+
* schema.
|
|
150
|
+
*/
|
|
151
|
+
type PhoneInputProps = InputFieldProps;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Plain free text: names, job titles, one-time codes. Anything with a format
|
|
155
|
+
* of its own — an email address, a phone number, a password — has its own
|
|
156
|
+
* component (`EmailInput`, `PhoneInput`, `PasswordInput`), which fixes the
|
|
157
|
+
* keyboard, autocomplete and input type that format needs.
|
|
158
|
+
*/
|
|
159
|
+
type TextInputProps = InputFieldProps & {
|
|
160
|
+
/** Renders the value in the design's monospace face, as the code entry does. */
|
|
45
161
|
mono?: boolean;
|
|
46
|
-
type?: "text" | "email" | "password" | "tel" | "url" | "search";
|
|
47
|
-
value?: string;
|
|
48
|
-
defaultValue?: string;
|
|
49
|
-
onChange?: (value: string) => void;
|
|
50
|
-
/**
|
|
51
|
-
* Any zod schema that accepts a string. Only `safeParse` is used, so a
|
|
52
|
-
* refined, transformed or preprocessed schema works as well as a plain one.
|
|
53
|
-
*/
|
|
54
|
-
schema?: TextInputSchema;
|
|
55
|
-
/**
|
|
56
|
-
* When the schema runs. `blur` — the default — avoids scolding someone
|
|
57
|
-
* mid-keystroke; once a field has gone invalid it revalidates on every
|
|
58
|
-
* keystroke so the message clears as soon as it is fixed.
|
|
59
|
-
*/
|
|
60
|
-
validateOn?: "blur" | "change" | "never";
|
|
61
|
-
onValidationChange?: (state: TextInputValidation) => void;
|
|
62
162
|
};
|
|
63
163
|
|
|
64
|
-
export type
|
|
164
|
+
export { ButtonProps, type EmailInputProps, type FieldBindings, type FieldContextValue, type FieldControlProps, type FieldDescriptionProps, type FieldLabelProps, type FieldMessageProps, type FieldRootProps, type FormErrorProps, type FormInput, type FormInstance, type FormOutput, type FormProps, type FormSchema, type InputFieldProps, type PasswordInputProps, type PhoneInputProps, type SubmitButtonProps, type TextInputProps, type UseFormInstanceOptions };
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/components/password-input/index.tsx
|
|
23
|
+
var password_input_exports = {};
|
|
24
|
+
__export(password_input_exports, {
|
|
25
|
+
PasswordInput: () => PasswordInput
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(password_input_exports);
|
|
28
|
+
var import_react2 = require("react");
|
|
29
|
+
|
|
30
|
+
// src/components/field/index.tsx
|
|
31
|
+
var import_react_label = require("@radix-ui/react-label");
|
|
32
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
33
|
+
var import_react = require("react");
|
|
34
|
+
var import_react_hook_form = require("react-hook-form");
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var FieldContext = (0, import_react.createContext)(null);
|
|
37
|
+
function useFieldContext() {
|
|
38
|
+
const context = (0, import_react.useContext)(FieldContext);
|
|
39
|
+
if (!context) {
|
|
40
|
+
throw new Error("Field primitives must be rendered inside FieldRoot");
|
|
41
|
+
}
|
|
42
|
+
return context;
|
|
43
|
+
}
|
|
44
|
+
function useFieldIds(id) {
|
|
45
|
+
const generated = (0, import_react.useId)();
|
|
46
|
+
const base = id ?? generated;
|
|
47
|
+
return {
|
|
48
|
+
id: base,
|
|
49
|
+
descriptionId: `${base}-description`,
|
|
50
|
+
messageId: `${base}-message`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function FieldShell({
|
|
54
|
+
value,
|
|
55
|
+
asChild = false,
|
|
56
|
+
children,
|
|
57
|
+
...rest
|
|
58
|
+
}) {
|
|
59
|
+
const [hasDescription, setHasDescription] = (0, import_react.useState)(false);
|
|
60
|
+
const Component = asChild ? import_react_slot.Slot : "div";
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
62
|
+
FieldContext.Provider,
|
|
63
|
+
{
|
|
64
|
+
value: { ...value, hasDescription, setHasDescription },
|
|
65
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
66
|
+
Component,
|
|
67
|
+
{
|
|
68
|
+
...rest,
|
|
69
|
+
"data-invalid": value.invalid ? "" : void 0,
|
|
70
|
+
"data-disabled": value.disabled ? "" : void 0,
|
|
71
|
+
children
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function ConnectedFieldRoot({
|
|
78
|
+
name,
|
|
79
|
+
error,
|
|
80
|
+
required = false,
|
|
81
|
+
disabled = false,
|
|
82
|
+
id,
|
|
83
|
+
...rest
|
|
84
|
+
}) {
|
|
85
|
+
const ids = useFieldIds(id);
|
|
86
|
+
const { field, fieldState } = (0, import_react_hook_form.useController)({ name, disabled });
|
|
87
|
+
const shownError = error ?? fieldState.error?.message;
|
|
88
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
89
|
+
FieldShell,
|
|
90
|
+
{
|
|
91
|
+
...rest,
|
|
92
|
+
value: {
|
|
93
|
+
...ids,
|
|
94
|
+
name,
|
|
95
|
+
error: shownError,
|
|
96
|
+
invalid: Boolean(shownError),
|
|
97
|
+
required,
|
|
98
|
+
disabled: Boolean(field.disabled ?? disabled),
|
|
99
|
+
bindings: {
|
|
100
|
+
name: field.name,
|
|
101
|
+
value: field.value ?? "",
|
|
102
|
+
onChange: field.onChange,
|
|
103
|
+
onBlur: field.onBlur,
|
|
104
|
+
ref: field.ref
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function StandaloneFieldRoot({
|
|
111
|
+
name,
|
|
112
|
+
error,
|
|
113
|
+
required = false,
|
|
114
|
+
disabled = false,
|
|
115
|
+
id,
|
|
116
|
+
...rest
|
|
117
|
+
}) {
|
|
118
|
+
const ids = useFieldIds(id);
|
|
119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
120
|
+
FieldShell,
|
|
121
|
+
{
|
|
122
|
+
...rest,
|
|
123
|
+
value: {
|
|
124
|
+
...ids,
|
|
125
|
+
name,
|
|
126
|
+
error,
|
|
127
|
+
invalid: Boolean(error),
|
|
128
|
+
required,
|
|
129
|
+
disabled,
|
|
130
|
+
bindings: { name }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function FieldRoot(props) {
|
|
136
|
+
const form = (0, import_react_hook_form.useFormContext)();
|
|
137
|
+
return form ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConnectedFieldRoot, { ...props }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StandaloneFieldRoot, { ...props });
|
|
138
|
+
}
|
|
139
|
+
function FieldLabel(props) {
|
|
140
|
+
const { id } = useFieldContext();
|
|
141
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_label.Label, { ...props, htmlFor: id });
|
|
142
|
+
}
|
|
143
|
+
function describedBy({
|
|
144
|
+
error,
|
|
145
|
+
messageId,
|
|
146
|
+
hasDescription,
|
|
147
|
+
descriptionId
|
|
148
|
+
}) {
|
|
149
|
+
if (error) {
|
|
150
|
+
return messageId;
|
|
151
|
+
}
|
|
152
|
+
return hasDescription ? descriptionId : void 0;
|
|
153
|
+
}
|
|
154
|
+
function FieldControl(props) {
|
|
155
|
+
const context = useFieldContext();
|
|
156
|
+
const { id, invalid, required, disabled, bindings } = context;
|
|
157
|
+
const controlProps = {
|
|
158
|
+
...bindings,
|
|
159
|
+
id,
|
|
160
|
+
"aria-invalid": invalid || void 0,
|
|
161
|
+
"aria-required": required || void 0,
|
|
162
|
+
"aria-describedby": describedBy(context),
|
|
163
|
+
disabled: disabled || void 0
|
|
164
|
+
};
|
|
165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_slot.Slot, { ...props, ...controlProps });
|
|
166
|
+
}
|
|
167
|
+
function FieldDescription({
|
|
168
|
+
asChild = false,
|
|
169
|
+
...props
|
|
170
|
+
}) {
|
|
171
|
+
const { descriptionId, error, setHasDescription } = useFieldContext();
|
|
172
|
+
(0, import_react.useEffect)(() => {
|
|
173
|
+
setHasDescription(true);
|
|
174
|
+
return () => setHasDescription(false);
|
|
175
|
+
}, [setHasDescription]);
|
|
176
|
+
if (error) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const Component = asChild ? import_react_slot.Slot : "p";
|
|
180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, id: descriptionId });
|
|
181
|
+
}
|
|
182
|
+
function FieldMessage({
|
|
183
|
+
asChild = false,
|
|
184
|
+
children,
|
|
185
|
+
...props
|
|
186
|
+
}) {
|
|
187
|
+
const { messageId, error } = useFieldContext();
|
|
188
|
+
const content = error ?? children;
|
|
189
|
+
if (!content) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
const Component = asChild ? import_react_slot.Slot : "p";
|
|
193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, id: messageId, role: "alert", children: content });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/components/typography/index.tsx
|
|
197
|
+
var import_react_slot2 = require("@radix-ui/react-slot");
|
|
198
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
199
|
+
var DEFAULT_ELEMENT = {
|
|
200
|
+
display: "h1",
|
|
201
|
+
heading: "h2",
|
|
202
|
+
subheading: "h3",
|
|
203
|
+
body: "p",
|
|
204
|
+
label: "span",
|
|
205
|
+
hint: "p",
|
|
206
|
+
code: "code"
|
|
207
|
+
};
|
|
208
|
+
var DEFAULT_WEIGHT = {
|
|
209
|
+
display: "semibold",
|
|
210
|
+
heading: "semibold",
|
|
211
|
+
subheading: "medium",
|
|
212
|
+
body: "regular",
|
|
213
|
+
label: "semibold",
|
|
214
|
+
hint: "regular",
|
|
215
|
+
code: "regular"
|
|
216
|
+
};
|
|
217
|
+
var VARIANT_CLASSES = {
|
|
218
|
+
display: "text-display leading-tight tracking-tight",
|
|
219
|
+
heading: "text-heading leading-tight tracking-tight",
|
|
220
|
+
subheading: "text-subheading leading-snug",
|
|
221
|
+
body: "text-field leading-normal",
|
|
222
|
+
label: "text-label leading-normal",
|
|
223
|
+
hint: "text-hint leading-normal",
|
|
224
|
+
code: "font-code text-field leading-normal"
|
|
225
|
+
};
|
|
226
|
+
var TONE_CLASSES = {
|
|
227
|
+
default: "text-fg",
|
|
228
|
+
muted: "text-fg-muted",
|
|
229
|
+
subtle: "text-fg-subtle",
|
|
230
|
+
accent: "text-accent",
|
|
231
|
+
"on-accent": "text-on-accent",
|
|
232
|
+
success: "text-success",
|
|
233
|
+
warning: "text-warning",
|
|
234
|
+
info: "text-info",
|
|
235
|
+
danger: "text-danger"
|
|
236
|
+
};
|
|
237
|
+
var WEIGHT_CLASSES = {
|
|
238
|
+
regular: "font-normal",
|
|
239
|
+
medium: "font-medium",
|
|
240
|
+
semibold: "font-semibold",
|
|
241
|
+
bold: "font-bold"
|
|
242
|
+
};
|
|
243
|
+
var ALIGN_CLASSES = {
|
|
244
|
+
start: "text-start",
|
|
245
|
+
center: "text-center",
|
|
246
|
+
end: "text-end"
|
|
247
|
+
};
|
|
248
|
+
var ICON_CLASSES = "inline-flex shrink-0 items-center [&>svg]:h-[1em] [&>svg]:w-[1em]";
|
|
249
|
+
function typographyClassName({
|
|
250
|
+
variant,
|
|
251
|
+
tone,
|
|
252
|
+
weight,
|
|
253
|
+
align,
|
|
254
|
+
truncate,
|
|
255
|
+
hasIcon,
|
|
256
|
+
className
|
|
257
|
+
}) {
|
|
258
|
+
return [
|
|
259
|
+
VARIANT_CLASSES[variant],
|
|
260
|
+
TONE_CLASSES[tone],
|
|
261
|
+
WEIGHT_CLASSES[weight],
|
|
262
|
+
align ? ALIGN_CLASSES[align] : "",
|
|
263
|
+
hasIcon ? "inline-flex items-center gap-1.5" : "",
|
|
264
|
+
// With an icon the root is a flex container, and text-overflow only
|
|
265
|
+
// clips block text, so the text span carries the truncation instead.
|
|
266
|
+
truncate && !hasIcon ? "truncate" : "",
|
|
267
|
+
className ?? ""
|
|
268
|
+
].filter(Boolean).join(" ");
|
|
269
|
+
}
|
|
270
|
+
function Typography({
|
|
271
|
+
variant = "body",
|
|
272
|
+
tone = "default",
|
|
273
|
+
weight,
|
|
274
|
+
align,
|
|
275
|
+
truncate = false,
|
|
276
|
+
icon,
|
|
277
|
+
iconPosition = "leading",
|
|
278
|
+
as,
|
|
279
|
+
asChild = false,
|
|
280
|
+
className,
|
|
281
|
+
children,
|
|
282
|
+
...rest
|
|
283
|
+
}) {
|
|
284
|
+
const hasIcon = icon !== void 0 && icon !== null;
|
|
285
|
+
const Component = asChild ? import_react_slot2.Slot : as ?? DEFAULT_ELEMENT[variant];
|
|
286
|
+
const iconNode = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { "aria-hidden": "true", className: ICON_CLASSES, children: icon }) : null;
|
|
287
|
+
const content = hasIcon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
288
|
+
iconPosition === "leading" ? iconNode : null,
|
|
289
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: truncate ? "min-w-0 truncate" : void 0, children }),
|
|
290
|
+
iconPosition === "trailing" ? iconNode : null
|
|
291
|
+
] }) : children;
|
|
292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
293
|
+
Component,
|
|
294
|
+
{
|
|
295
|
+
...rest,
|
|
296
|
+
className: typographyClassName({
|
|
297
|
+
variant,
|
|
298
|
+
tone,
|
|
299
|
+
weight: weight ?? DEFAULT_WEIGHT[variant],
|
|
300
|
+
align,
|
|
301
|
+
truncate,
|
|
302
|
+
hasIcon,
|
|
303
|
+
className
|
|
304
|
+
}),
|
|
305
|
+
children: content
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/components/input/index.tsx
|
|
311
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
312
|
+
var CONTROL_CLASSES = "h-10 w-full rounded-field border bg-surface px-3 font-[inherit] text-field text-fg outline-none placeholder:text-fg-subtle disabled:cursor-not-allowed disabled:opacity-45";
|
|
313
|
+
var VALID_CLASSES = "border-line focus:border-accent focus:ring-3 focus:ring-accent-soft";
|
|
314
|
+
var INVALID_CLASSES = "border-danger focus:border-danger focus:ring-3 focus:ring-danger-soft";
|
|
315
|
+
function InputLabel({
|
|
316
|
+
label,
|
|
317
|
+
optional,
|
|
318
|
+
action
|
|
319
|
+
}) {
|
|
320
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
321
|
+
Typography,
|
|
322
|
+
{
|
|
323
|
+
variant: "label",
|
|
324
|
+
tone: "muted",
|
|
325
|
+
className: "mb-1.5 flex items-center",
|
|
326
|
+
asChild: true,
|
|
327
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FieldLabel, { children: [
|
|
328
|
+
label,
|
|
329
|
+
optional ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
330
|
+
Typography,
|
|
331
|
+
{
|
|
332
|
+
as: "span",
|
|
333
|
+
variant: "hint",
|
|
334
|
+
tone: "subtle",
|
|
335
|
+
weight: "semibold",
|
|
336
|
+
className: "ml-auto",
|
|
337
|
+
children: "Optional"
|
|
338
|
+
}
|
|
339
|
+
) : null,
|
|
340
|
+
action ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "ml-auto", children: action }) : null
|
|
341
|
+
] })
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
function InputControl({
|
|
346
|
+
hasTrailing,
|
|
347
|
+
className,
|
|
348
|
+
...rest
|
|
349
|
+
}) {
|
|
350
|
+
const { invalid } = useFieldContext();
|
|
351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldControl, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
352
|
+
"input",
|
|
353
|
+
{
|
|
354
|
+
...rest,
|
|
355
|
+
className: [
|
|
356
|
+
CONTROL_CLASSES,
|
|
357
|
+
invalid ? INVALID_CLASSES : VALID_CLASSES,
|
|
358
|
+
hasTrailing ? "pr-16" : "",
|
|
359
|
+
className ?? ""
|
|
360
|
+
].filter(Boolean).join(" ")
|
|
361
|
+
}
|
|
362
|
+
) });
|
|
363
|
+
}
|
|
364
|
+
function InputMessages({ hint }) {
|
|
365
|
+
const { error } = useFieldContext();
|
|
366
|
+
if (error) {
|
|
367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Typography, { as: "p", variant: "hint", tone: "danger", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldMessage, { className: "mt-1.5" }) });
|
|
368
|
+
}
|
|
369
|
+
if (hint) {
|
|
370
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Typography, { as: "p", variant: "hint", tone: "subtle", asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FieldDescription, { className: "mt-1.5", children: hint }) });
|
|
371
|
+
}
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
function InputField({
|
|
375
|
+
name,
|
|
376
|
+
label,
|
|
377
|
+
hint,
|
|
378
|
+
error,
|
|
379
|
+
optional = false,
|
|
380
|
+
action,
|
|
381
|
+
trailing,
|
|
382
|
+
id,
|
|
383
|
+
disabled,
|
|
384
|
+
required,
|
|
385
|
+
type,
|
|
386
|
+
...rest
|
|
387
|
+
}) {
|
|
388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
389
|
+
FieldRoot,
|
|
390
|
+
{
|
|
391
|
+
name,
|
|
392
|
+
id,
|
|
393
|
+
error,
|
|
394
|
+
disabled,
|
|
395
|
+
required,
|
|
396
|
+
className: "flex flex-col",
|
|
397
|
+
children: [
|
|
398
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputLabel, { label, optional, action }) : null,
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: trailing ? "relative" : void 0, children: [
|
|
400
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputControl, { ...rest, type, hasTrailing: Boolean(trailing) }),
|
|
401
|
+
trailing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute top-1/2 right-[9px] flex -translate-y-1/2 items-center font-semibold text-fg-subtle text-hint", children: trailing }) : null
|
|
402
|
+
] }),
|
|
403
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InputMessages, { hint })
|
|
404
|
+
]
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/components/password-input/index.tsx
|
|
410
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
411
|
+
var DEFAULT_REVEAL_LABELS = { show: "Show", hide: "Hide" };
|
|
412
|
+
var TOGGLE_CLASSES = "cursor-pointer rounded-field font-[inherit] text-hint font-semibold text-fg-subtle outline-none hover:text-fg focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed";
|
|
413
|
+
function PasswordInput({
|
|
414
|
+
revealable = true,
|
|
415
|
+
revealLabels = DEFAULT_REVEAL_LABELS,
|
|
416
|
+
autoComplete = "current-password",
|
|
417
|
+
...rest
|
|
418
|
+
}) {
|
|
419
|
+
const [revealed, setRevealed] = (0, import_react2.useState)(false);
|
|
420
|
+
const toggleRevealed = (0, import_react2.useCallback)(
|
|
421
|
+
() => setRevealed((current) => !current),
|
|
422
|
+
[]
|
|
423
|
+
);
|
|
424
|
+
const toggle = revealable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
425
|
+
"button",
|
|
426
|
+
{
|
|
427
|
+
type: "button",
|
|
428
|
+
"aria-pressed": revealed,
|
|
429
|
+
"aria-label": revealed ? "Hide password" : "Show password",
|
|
430
|
+
className: TOGGLE_CLASSES,
|
|
431
|
+
onClick: toggleRevealed,
|
|
432
|
+
children: revealed ? revealLabels.hide : revealLabels.show
|
|
433
|
+
}
|
|
434
|
+
) : void 0;
|
|
435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
436
|
+
InputField,
|
|
437
|
+
{
|
|
438
|
+
...rest,
|
|
439
|
+
type: revealed ? "text" : "password",
|
|
440
|
+
autoComplete,
|
|
441
|
+
trailing: toggle
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
446
|
+
0 && (module.exports = {
|
|
447
|
+
PasswordInput
|
|
448
|
+
});
|
|
449
|
+
//# sourceMappingURL=password-input.cjs.map
|