@carbonbits/sixr 1.4.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 +139 -60
- 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/email-input.cjs +213 -170
- package/dist/email-input.cjs.map +1 -1
- package/dist/email-input.d.cts +4 -6
- package/dist/email-input.d.ts +4 -6
- package/dist/email-input.js +219 -170
- package/dist/email-input.js.map +1 -1
- 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 +138 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -55
- package/dist/index.d.ts +116 -55
- package/dist/index.js +1 -0
- package/dist/password-input.cjs +217 -174
- package/dist/password-input.cjs.map +1 -1
- package/dist/password-input.d.cts +2 -3
- package/dist/password-input.d.ts +2 -3
- package/dist/password-input.js +222 -173
- package/dist/password-input.js.map +1 -1
- package/dist/phone-input.cjs +213 -170
- package/dist/phone-input.cjs.map +1 -1
- package/dist/phone-input.d.cts +5 -5
- package/dist/phone-input.d.ts +5 -5
- package/dist/phone-input.js +219 -170
- package/dist/phone-input.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/text-input.cjs +213 -170
- package/dist/text-input.cjs.map +1 -1
- package/dist/text-input.d.cts +2 -3
- package/dist/text-input.d.ts +2 -3
- package/dist/text-input.js +219 -170
- package/dist/text-input.js.map +1 -1
- package/package.json +26 -2
- package/dist/index-DwjxC4l4.d.cts +0 -62
- package/dist/index-DwjxC4l4.d.ts +0 -62
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type InputFieldProps = Omit<ComponentPropsWithoutRef<"input">, "name" | "type"> & {
|
|
4
|
+
/** The form field this input edits — the key in the `Form`'s values. */
|
|
5
|
+
name: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
/** Guidance under the field. Replaced by the error message while invalid. */
|
|
8
|
+
hint?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Error supplied by the caller — a server-side or cross-field failure. Takes
|
|
11
|
+
* precedence over what the form's schema reports for this field.
|
|
12
|
+
*/
|
|
13
|
+
error?: string;
|
|
14
|
+
/** Renders the design's muted "Optional" marker at the end of the label. */
|
|
15
|
+
optional?: boolean;
|
|
16
|
+
/** Trailing label slot, for affordances like the design's "Forgot?" link. */
|
|
17
|
+
action?: ReactNode;
|
|
18
|
+
/** Trailing in-field slot, for affordances like the design's password peek. */
|
|
19
|
+
trailing?: ReactNode;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type { InputFieldProps as I };
|
package/dist/index.cjs
CHANGED
|
@@ -1,41 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
4
3
|
var reactSlot = require('@radix-ui/react-slot');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
|
|
6
|
-
// src/components/
|
|
7
|
-
function formatPrice(value, currency, locale) {
|
|
8
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
9
|
-
value
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
function Cart({
|
|
13
|
-
products = [],
|
|
14
|
-
currency = "KES",
|
|
15
|
-
locale = "en-KE"
|
|
16
|
-
}) {
|
|
17
|
-
const total = products.reduce((sum, product) => sum + product.price, 0);
|
|
18
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4", children: [
|
|
19
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-900", children: "Cart" }),
|
|
20
|
-
products.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Your cart is empty." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
21
|
-
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y divide-gray-100", children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
22
|
-
"li",
|
|
23
|
-
{
|
|
24
|
-
className: "flex items-baseline justify-between gap-4 py-2",
|
|
25
|
-
children: [
|
|
26
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800", children: product.name }),
|
|
27
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm tabular-nums text-gray-600", children: formatPrice(product.price, currency, locale) })
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
product.id ?? product.name
|
|
31
|
-
)) }),
|
|
32
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2", children: [
|
|
33
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: "Total" }),
|
|
34
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: formatPrice(total, currency, locale) })
|
|
35
|
-
] })
|
|
36
|
-
] })
|
|
37
|
-
] });
|
|
38
|
-
}
|
|
6
|
+
// src/components/button/index.tsx
|
|
39
7
|
var DEFAULT_ELEMENT = {
|
|
40
8
|
display: "h1",
|
|
41
9
|
heading: "h2",
|
|
@@ -146,7 +114,143 @@ function Typography({
|
|
|
146
114
|
}
|
|
147
115
|
);
|
|
148
116
|
}
|
|
117
|
+
var BASE_CLASSES = "inline-flex shrink-0 items-center justify-center gap-2 rounded-field border font-[inherit] text-field font-semibold outline-none transition-colors focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed disabled:opacity-45";
|
|
118
|
+
var VARIANT_CLASSES2 = {
|
|
119
|
+
primary: "border-transparent bg-accent text-on-accent enabled:hover:bg-accent-2",
|
|
120
|
+
secondary: "border-line bg-surface text-fg enabled:hover:bg-surface-2",
|
|
121
|
+
ghost: "border-transparent bg-transparent text-fg enabled:hover:bg-surface-2"
|
|
122
|
+
};
|
|
123
|
+
var SIZE_CLASSES = {
|
|
124
|
+
md: "h-10 px-4",
|
|
125
|
+
lg: "h-11 px-5"
|
|
126
|
+
};
|
|
127
|
+
var LABEL_TONE = {
|
|
128
|
+
primary: "on-accent",
|
|
129
|
+
secondary: "default",
|
|
130
|
+
ghost: "default"
|
|
131
|
+
};
|
|
132
|
+
function buttonClassName({
|
|
133
|
+
variant,
|
|
134
|
+
size,
|
|
135
|
+
fullWidth,
|
|
136
|
+
className
|
|
137
|
+
}) {
|
|
138
|
+
return [
|
|
139
|
+
BASE_CLASSES,
|
|
140
|
+
VARIANT_CLASSES2[variant],
|
|
141
|
+
SIZE_CLASSES[size],
|
|
142
|
+
fullWidth ? "w-full" : "",
|
|
143
|
+
className ?? ""
|
|
144
|
+
].filter(Boolean).join(" ");
|
|
145
|
+
}
|
|
146
|
+
function Spinner() {
|
|
147
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
148
|
+
"svg",
|
|
149
|
+
{
|
|
150
|
+
className: "h-4 w-4 animate-spin",
|
|
151
|
+
viewBox: "0 0 24 24",
|
|
152
|
+
fill: "none",
|
|
153
|
+
"aria-hidden": "true",
|
|
154
|
+
"data-testid": "button-spinner",
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
157
|
+
"circle",
|
|
158
|
+
{
|
|
159
|
+
className: "opacity-25",
|
|
160
|
+
cx: "12",
|
|
161
|
+
cy: "12",
|
|
162
|
+
r: "10",
|
|
163
|
+
stroke: "currentColor",
|
|
164
|
+
strokeWidth: "4"
|
|
165
|
+
}
|
|
166
|
+
),
|
|
167
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
168
|
+
"path",
|
|
169
|
+
{
|
|
170
|
+
className: "opacity-75",
|
|
171
|
+
fill: "currentColor",
|
|
172
|
+
d: "M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12H4Z"
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
function Button({
|
|
180
|
+
variant = "primary",
|
|
181
|
+
size = "md",
|
|
182
|
+
fullWidth = false,
|
|
183
|
+
loading = false,
|
|
184
|
+
loadingLabel,
|
|
185
|
+
asChild = false,
|
|
186
|
+
type = "button",
|
|
187
|
+
disabled,
|
|
188
|
+
className,
|
|
189
|
+
children,
|
|
190
|
+
...rest
|
|
191
|
+
}) {
|
|
192
|
+
const classes = buttonClassName({ variant, size, fullWidth, className });
|
|
193
|
+
if (asChild) {
|
|
194
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactSlot.Slot, { ...rest, className: classes, children });
|
|
195
|
+
}
|
|
196
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
197
|
+
"button",
|
|
198
|
+
{
|
|
199
|
+
...rest,
|
|
200
|
+
type,
|
|
201
|
+
disabled: disabled || loading,
|
|
202
|
+
"aria-busy": loading || void 0,
|
|
203
|
+
className: classes,
|
|
204
|
+
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, {}),
|
|
206
|
+
loadingLabel
|
|
207
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
208
|
+
Typography,
|
|
209
|
+
{
|
|
210
|
+
as: "span",
|
|
211
|
+
variant: "body",
|
|
212
|
+
weight: "semibold",
|
|
213
|
+
tone: LABEL_TONE[variant],
|
|
214
|
+
children
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
function formatPrice(value, currency, locale) {
|
|
221
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
222
|
+
value
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
function Cart({
|
|
226
|
+
products = [],
|
|
227
|
+
currency = "KES",
|
|
228
|
+
locale = "en-KE"
|
|
229
|
+
}) {
|
|
230
|
+
const total = products.reduce((sum, product) => sum + product.price, 0);
|
|
231
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4", children: [
|
|
232
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-900", children: "Cart" }),
|
|
233
|
+
products.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Your cart is empty." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y divide-gray-100", children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
235
|
+
"li",
|
|
236
|
+
{
|
|
237
|
+
className: "flex items-baseline justify-between gap-4 py-2",
|
|
238
|
+
children: [
|
|
239
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800", children: product.name }),
|
|
240
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm tabular-nums text-gray-600", children: formatPrice(product.price, currency, locale) })
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
product.id ?? product.name
|
|
244
|
+
)) }),
|
|
245
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2", children: [
|
|
246
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: "Total" }),
|
|
247
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: formatPrice(total, currency, locale) })
|
|
248
|
+
] })
|
|
249
|
+
] })
|
|
250
|
+
] });
|
|
251
|
+
}
|
|
149
252
|
|
|
253
|
+
exports.Button = Button;
|
|
150
254
|
exports.Cart = Cart;
|
|
151
255
|
exports.Typography = Typography;
|
|
152
256
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/cart/index.tsx","../src/components/typography/index.tsx"],"names":["jsxs","jsx","Fragment","Slot"],"mappings":"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","file":"index.cjs","sourcesContent":["export type CartProduct = {\n /**\n * Stable identity for this line, used as the React key. Falls back to `name`,\n * so pass an `id` whenever a cart can hold two lines with the same name.\n */\n id?: string;\n name: string;\n price: number;\n};\n\nexport type CartProps = {\n products?: CartProduct[];\n /** ISO 4217 code used to format prices. */\n currency?: string;\n /** BCP 47 locale used to format prices. */\n locale?: string;\n};\n\nfunction formatPrice(value: number, currency: string, locale: string) {\n return new Intl.NumberFormat(locale, { style: \"currency\", currency }).format(\n value,\n );\n}\n\nexport function Cart({\n products = [],\n currency = \"KES\",\n locale = \"en-KE\",\n}: CartProps) {\n const total = products.reduce((sum, product) => sum + product.price, 0);\n\n return (\n <div className=\"cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4\">\n <h1 className=\"text-xl font-semibold text-gray-900\">Cart</h1>\n\n {products.length === 0 ? (\n <p className=\"text-sm text-gray-500\">Your cart is empty.</p>\n ) : (\n <>\n <ul className=\"flex flex-col divide-y divide-gray-100\">\n {products.map((product) => (\n <li\n key={product.id ?? product.name}\n className=\"flex items-baseline justify-between gap-4 py-2\"\n >\n <span className=\"text-sm text-gray-800\">{product.name}</span>\n <span className=\"text-sm tabular-nums text-gray-600\">\n {formatPrice(product.price, currency, locale)}\n </span>\n </li>\n ))}\n </ul>\n\n <div className=\"flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2\">\n <span className=\"text-sm font-medium text-gray-900\">Total</span>\n <span className=\"text-sm font-semibold tabular-nums text-gray-900\">\n {formatPrice(total, currency, locale)}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport type { ElementType, HTMLAttributes, ReactNode, Ref } from \"react\";\n\n/**\n * The library's type scale. Everything that renders text — field labels, hints,\n * form errors, headings — goes through here, so a size or colour lives in one\n * place and the tokens in `src/styles/index.css` stay the single source of\n * truth for what \"hint\" or \"muted\" means.\n *\n * Server-safe: no state, no handlers, no directive. It composes Radix `Slot`\n * for `asChild`, which is how a consumer puts these styles on their own\n * element (a `next/link`, a Radix `Label`) without an extra wrapper.\n */\n\nexport type TypographyVariant =\n | \"display\"\n | \"heading\"\n | \"subheading\"\n | \"body\"\n | \"label\"\n | \"hint\"\n | \"code\";\n\nexport type TypographyTone =\n | \"default\"\n | \"muted\"\n | \"subtle\"\n | \"accent\"\n | \"on-accent\"\n | \"success\"\n | \"warning\"\n | \"info\"\n | \"danger\";\n\nexport type TypographyWeight = \"regular\" | \"medium\" | \"semibold\" | \"bold\";\n\nexport type TypographyElement =\n | \"p\"\n | \"span\"\n | \"div\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\"\n | \"label\"\n | \"code\"\n | \"strong\"\n | \"em\"\n | \"small\";\n\nexport type TypographyProps = Omit<HTMLAttributes<HTMLElement>, \"color\"> & {\n /** Size and default element. `body` unless told otherwise. */\n variant?: TypographyVariant;\n /** Colour role, from the design tokens. */\n tone?: TypographyTone;\n /** Overrides the variant's default weight. */\n weight?: TypographyWeight;\n align?: \"start\" | \"center\" | \"end\";\n /** Clip to one line with an ellipsis. */\n truncate?: boolean;\n /**\n * An icon rendered beside the text, hidden from assistive tech. Sized to the\n * text with `1em`, so the same SVG fits every variant.\n */\n icon?: ReactNode;\n iconPosition?: \"leading\" | \"trailing\";\n /** The element to render. Defaults per variant (`h2` for a heading, and so on). */\n as?: TypographyElement;\n /**\n * Radix-style composition: render the child element itself, with these\n * styles merged onto it, instead of a wrapper. Takes precedence over `as`.\n */\n asChild?: boolean;\n ref?: Ref<HTMLElement>;\n children?: ReactNode;\n};\n\nconst DEFAULT_ELEMENT: Record<TypographyVariant, TypographyElement> = {\n display: \"h1\",\n heading: \"h2\",\n subheading: \"h3\",\n body: \"p\",\n label: \"span\",\n hint: \"p\",\n code: \"code\",\n};\n\nconst DEFAULT_WEIGHT: Record<TypographyVariant, TypographyWeight> = {\n display: \"semibold\",\n heading: \"semibold\",\n subheading: \"medium\",\n body: \"regular\",\n label: \"semibold\",\n hint: \"regular\",\n code: \"regular\",\n};\n\nconst VARIANT_CLASSES: Record<TypographyVariant, string> = {\n display: \"text-display leading-tight tracking-tight\",\n heading: \"text-heading leading-tight tracking-tight\",\n subheading: \"text-subheading leading-snug\",\n body: \"text-field leading-normal\",\n label: \"text-label leading-normal\",\n hint: \"text-hint leading-normal\",\n code: \"font-code text-field leading-normal\",\n};\n\nconst TONE_CLASSES: Record<TypographyTone, string> = {\n default: \"text-fg\",\n muted: \"text-fg-muted\",\n subtle: \"text-fg-subtle\",\n accent: \"text-accent\",\n \"on-accent\": \"text-on-accent\",\n success: \"text-success\",\n warning: \"text-warning\",\n info: \"text-info\",\n danger: \"text-danger\",\n};\n\nconst WEIGHT_CLASSES: Record<TypographyWeight, string> = {\n regular: \"font-normal\",\n medium: \"font-medium\",\n semibold: \"font-semibold\",\n bold: \"font-bold\",\n};\n\nconst ALIGN_CLASSES = {\n start: \"text-start\",\n center: \"text-center\",\n end: \"text-end\",\n} as const;\n\nconst ICON_CLASSES =\n \"inline-flex shrink-0 items-center [&>svg]:h-[1em] [&>svg]:w-[1em]\";\n\nfunction typographyClassName({\n variant,\n tone,\n weight,\n align,\n truncate,\n hasIcon,\n className,\n}: {\n variant: TypographyVariant;\n tone: TypographyTone;\n weight: TypographyWeight;\n align: \"start\" | \"center\" | \"end\" | undefined;\n truncate: boolean;\n hasIcon: boolean;\n className: string | undefined;\n}): string {\n return [\n VARIANT_CLASSES[variant],\n TONE_CLASSES[tone],\n WEIGHT_CLASSES[weight],\n align ? ALIGN_CLASSES[align] : \"\",\n hasIcon ? \"inline-flex items-center gap-1.5\" : \"\",\n // With an icon the root is a flex container, and text-overflow only\n // clips block text, so the text span carries the truncation instead.\n truncate && !hasIcon ? \"truncate\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function Typography({\n variant = \"body\",\n tone = \"default\",\n weight,\n align,\n truncate = false,\n icon,\n iconPosition = \"leading\",\n as,\n asChild = false,\n className,\n children,\n ...rest\n}: TypographyProps) {\n const hasIcon = icon !== undefined && icon !== null;\n // Widened to `ElementType`: the union of intrinsic tags would otherwise\n // demand a `ref` typed to one specific element.\n const Component: ElementType = asChild\n ? Slot\n : (as ?? DEFAULT_ELEMENT[variant]);\n\n const iconNode = hasIcon ? (\n <span aria-hidden=\"true\" className={ICON_CLASSES}>\n {icon}\n </span>\n ) : null;\n\n const content = hasIcon ? (\n <>\n {iconPosition === \"leading\" ? iconNode : null}\n <span className={truncate ? \"min-w-0 truncate\" : undefined}>\n {children}\n </span>\n {iconPosition === \"trailing\" ? iconNode : null}\n </>\n ) : (\n children\n );\n\n return (\n <Component\n {...rest}\n className={typographyClassName({\n variant,\n tone,\n weight: weight ?? DEFAULT_WEIGHT[variant],\n align,\n truncate,\n hasIcon,\n className,\n })}\n >\n {content}\n </Component>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/typography/index.tsx","../src/components/button/index.tsx","../src/components/cart/index.tsx"],"names":["Slot","jsx","jsxs","Fragment","VARIANT_CLASSES"],"mappings":";;;;;;AA+EA,IAAM,eAAA,GAAgE;AAAA,EACpE,OAAA,EAAS,IAAA;AAAA,EACT,OAAA,EAAS,IAAA;AAAA,EACT,UAAA,EAAY,IAAA;AAAA,EACZ,IAAA,EAAM,GAAA;AAAA,EACN,KAAA,EAAO,MAAA;AAAA,EACP,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,cAAA,GAA8D;AAAA,EAClE,OAAA,EAAS,UAAA;AAAA,EACT,OAAA,EAAS,UAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,IAAA,EAAM,SAAA;AAAA,EACN,KAAA,EAAO,UAAA;AAAA,EACP,IAAA,EAAM,SAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,eAAA,GAAqD;AAAA,EACzD,OAAA,EAAS,2CAAA;AAAA,EACT,OAAA,EAAS,2CAAA;AAAA,EACT,UAAA,EAAY,8BAAA;AAAA,EACZ,IAAA,EAAM,2BAAA;AAAA,EACN,KAAA,EAAO,2BAAA;AAAA,EACP,IAAA,EAAM,0BAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,YAAA,GAA+C;AAAA,EACnD,OAAA,EAAS,SAAA;AAAA,EACT,KAAA,EAAO,eAAA;AAAA,EACP,MAAA,EAAQ,gBAAA;AAAA,EACR,MAAA,EAAQ,aAAA;AAAA,EACR,WAAA,EAAa,gBAAA;AAAA,EACb,OAAA,EAAS,cAAA;AAAA,EACT,OAAA,EAAS,cAAA;AAAA,EACT,IAAA,EAAM,WAAA;AAAA,EACN,MAAA,EAAQ;AACV,CAAA;AAEA,IAAM,cAAA,GAAmD;AAAA,EACvD,OAAA,EAAS,aAAA;AAAA,EACT,MAAA,EAAQ,aAAA;AAAA,EACR,QAAA,EAAU,eAAA;AAAA,EACV,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,aAAA,GAAgB;AAAA,EACpB,KAAA,EAAO,YAAA;AAAA,EACP,MAAA,EAAQ,aAAA;AAAA,EACR,GAAA,EAAK;AACP,CAAA;AAEA,IAAM,YAAA,GACJ,mEAAA;AAEF,SAAS,mBAAA,CAAoB;AAAA,EAC3B,OAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAQW;AACT,EAAA,OAAO;AAAA,IACL,gBAAgB,OAAO,CAAA;AAAA,IACvB,aAAa,IAAI,CAAA;AAAA,IACjB,eAAe,MAAM,CAAA;AAAA,IACrB,KAAA,GAAQ,aAAA,CAAc,KAAK,CAAA,GAAI,EAAA;AAAA,IAC/B,UAAU,kCAAA,GAAqC,EAAA;AAAA;AAAA;AAAA,IAG/C,QAAA,IAAY,CAAC,OAAA,GAAU,UAAA,GAAa,EAAA;AAAA,IACpC,SAAA,IAAa;AAAA,GACf,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AACb;AAEO,SAAS,UAAA,CAAW;AAAA,EACzB,OAAA,GAAU,MAAA;AAAA,EACV,IAAA,GAAO,SAAA;AAAA,EACP,MAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,IAAA;AAAA,EACA,YAAA,GAAe,SAAA;AAAA,EACf,EAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAoB;AAClB,EAAA,MAAM,OAAA,GAAU,IAAA,KAAS,MAAA,IAAa,IAAA,KAAS,IAAA;AAG/C,EAAA,MAAM,SAAA,GAAyB,OAAA,GAC3BA,cAAA,GACC,EAAA,IAAM,gBAAgB,OAAO,CAAA;AAElC,EAAA,MAAM,QAAA,GAAW,0BACfC,cAAA,CAAC,MAAA,EAAA,EAAK,eAAY,MAAA,EAAO,SAAA,EAAW,YAAA,EACjC,QAAA,EAAA,IAAA,EACH,CAAA,GACE,IAAA;AAEJ,EAAA,MAAM,OAAA,GAAU,0BACdC,eAAA,CAAAC,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,YAAA,KAAiB,YAAY,QAAA,GAAW,IAAA;AAAA,mCACxC,MAAA,EAAA,EAAK,SAAA,EAAW,QAAA,GAAW,kBAAA,GAAqB,QAC9C,QAAA,EACH,CAAA;AAAA,IACC,YAAA,KAAiB,aAAa,QAAA,GAAW;AAAA,GAAA,EAC5C,CAAA,GAEA,QAAA;AAGF,EAAA,uBACEF,cAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,WAAW,mBAAA,CAAoB;AAAA,QAC7B,OAAA;AAAA,QACA,IAAA;AAAA,QACA,MAAA,EAAQ,MAAA,IAAU,cAAA,CAAe,OAAO,CAAA;AAAA,QACxC,KAAA;AAAA,QACA,QAAA;AAAA,QACA,OAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,MAEA,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;AC1LA,IAAM,YAAA,GACJ,wPAAA;AAEF,IAAMG,gBAAAA,GAAiD;AAAA,EACrD,OAAA,EACE,uEAAA;AAAA,EACF,SAAA,EAAW,2DAAA;AAAA,EACX,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,YAAA,GAA2C;AAAA,EAC/C,EAAA,EAAI,WAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAEA,IAAM,UAAA,GAAoD;AAAA,EACxD,OAAA,EAAS,WAAA;AAAA,EACT,SAAA,EAAW,SAAA;AAAA,EACX,KAAA,EAAO;AACT,CAAA;AAEA,SAAS,eAAA,CAAgB;AAAA,EACvB,OAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAKW;AACT,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACAA,iBAAgB,OAAO,CAAA;AAAA,IACvB,aAAa,IAAI,CAAA;AAAA,IACjB,YAAY,QAAA,GAAW,EAAA;AAAA,IACvB,SAAA,IAAa;AAAA,GACf,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AACb;AAEA,SAAS,OAAA,GAAU;AACjB,EAAA,uBACEF,eAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,sBAAA;AAAA,MACV,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,aAAA,EAAY,MAAA;AAAA,MACZ,aAAA,EAAY,gBAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,wBAAAD,cAAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,YAAA;AAAA,YACV,EAAA,EAAG,IAAA;AAAA,YACH,EAAA,EAAG,IAAA;AAAA,YACH,CAAA,EAAE,IAAA;AAAA,YACF,MAAA,EAAO,cAAA;AAAA,YACP,WAAA,EAAY;AAAA;AAAA,SACd;AAAA,wBACAA,cAAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,YAAA;AAAA,YACV,IAAA,EAAK,cAAA;AAAA,YACL,CAAA,EAAE;AAAA;AAAA;AACJ;AAAA;AAAA,GACF;AAEJ;AAEO,SAAS,MAAA,CAAO;AAAA,EACrB,OAAA,GAAU,SAAA;AAAA,EACV,IAAA,GAAO,IAAA;AAAA,EACP,SAAA,GAAY,KAAA;AAAA,EACZ,OAAA,GAAU,KAAA;AAAA,EACV,YAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,IAAA,GAAO,QAAA;AAAA,EACP,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAgB;AACd,EAAA,MAAM,UAAU,eAAA,CAAgB,EAAE,SAAS,IAAA,EAAM,SAAA,EAAW,WAAW,CAAA;AAEvE,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACEA,eAACD,cAAAA,EAAA,EAAM,GAAG,IAAA,EAAM,SAAA,EAAW,SACxB,QAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEC,cAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,IAAA;AAAA,MACA,UAAU,QAAA,IAAY,OAAA;AAAA,MACtB,aAAW,OAAA,IAAW,MAAA;AAAA,MACtB,SAAA,EAAW,OAAA;AAAA,MAEV,QAAA,EAAA,OAAA,mBACCC,eAAAA,CAAAC,mBAAAA,EAAA,EACE,QAAA,EAAA;AAAA,wBAAAF,eAAC,OAAA,EAAA,EAAQ,CAAA;AAAA,QACR;AAAA,OAAA,EACH,oBAEAA,cAAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,EAAA,EAAG,MAAA;AAAA,UACH,OAAA,EAAQ,MAAA;AAAA,UACR,MAAA,EAAO,UAAA;AAAA,UACP,IAAA,EAAM,WAAW,OAAO,CAAA;AAAA,UAEvB;AAAA;AAAA;AACH;AAAA,GAEJ;AAEJ;ACzIA,SAAS,WAAA,CAAY,KAAA,EAAe,QAAA,EAAkB,MAAA,EAAgB;AACpE,EAAA,OAAO,IAAI,KAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAE,MAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEO,SAAS,IAAA,CAAK;AAAA,EACnB,WAAW,EAAC;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,GAAS;AACX,CAAA,EAAc;AACZ,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,CAAO,CAAC,KAAK,OAAA,KAAY,GAAA,GAAM,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAEtE,EAAA,uBACEC,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yFAAA,EACb,QAAA,EAAA;AAAA,oBAAAD,cAAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,IAEvD,QAAA,CAAS,MAAA,KAAW,CAAA,mBACnBA,cAAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,qBAAA,EAAmB,CAAA,mBAExDC,eAAAA,CAAAC,qBAAA,EACE,QAAA,EAAA;AAAA,sBAAAF,cAAAA,CAAC,QAAG,SAAA,EAAU,wCAAA,EACX,mBAAS,GAAA,CAAI,CAAC,4BACbC,eAAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,gDAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAAD,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,kBAAQ,IAAA,EAAK,CAAA;AAAA,4BACtDA,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAA,EACb,sBAAY,OAAA,CAAQ,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EAC9C;AAAA;AAAA,SAAA;AAAA,QANK,OAAA,CAAQ,MAAM,OAAA,CAAQ;AAAA,OAQ9B,CAAA,EACH,CAAA;AAAA,sBAEAC,eAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yEAAA,EACb,QAAA,EAAA;AAAA,wBAAAD,cAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAoC,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,wBACzDA,eAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oDACb,QAAA,EAAA,WAAA,CAAY,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EACtC;AAAA,OAAA,EACF;AAAA,KAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"index.cjs","sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport type { ElementType, HTMLAttributes, ReactNode, Ref } from \"react\";\n\n/**\n * The library's type scale. Everything that renders text — field labels, hints,\n * form errors, headings — goes through here, so a size or colour lives in one\n * place and the tokens in `src/styles/index.css` stay the single source of\n * truth for what \"hint\" or \"muted\" means.\n *\n * Server-safe: no state, no handlers, no directive. It composes Radix `Slot`\n * for `asChild`, which is how a consumer puts these styles on their own\n * element (a `next/link`, a Radix `Label`) without an extra wrapper.\n */\n\nexport type TypographyVariant =\n | \"display\"\n | \"heading\"\n | \"subheading\"\n | \"body\"\n | \"label\"\n | \"hint\"\n | \"code\";\n\nexport type TypographyTone =\n | \"default\"\n | \"muted\"\n | \"subtle\"\n | \"accent\"\n | \"on-accent\"\n | \"success\"\n | \"warning\"\n | \"info\"\n | \"danger\";\n\nexport type TypographyWeight = \"regular\" | \"medium\" | \"semibold\" | \"bold\";\n\nexport type TypographyElement =\n | \"p\"\n | \"span\"\n | \"div\"\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"h5\"\n | \"h6\"\n | \"label\"\n | \"code\"\n | \"strong\"\n | \"em\"\n | \"small\";\n\nexport type TypographyProps = Omit<HTMLAttributes<HTMLElement>, \"color\"> & {\n /** Size and default element. `body` unless told otherwise. */\n variant?: TypographyVariant;\n /** Colour role, from the design tokens. */\n tone?: TypographyTone;\n /** Overrides the variant's default weight. */\n weight?: TypographyWeight;\n align?: \"start\" | \"center\" | \"end\";\n /** Clip to one line with an ellipsis. */\n truncate?: boolean;\n /**\n * An icon rendered beside the text, hidden from assistive tech. Sized to the\n * text with `1em`, so the same SVG fits every variant.\n */\n icon?: ReactNode;\n iconPosition?: \"leading\" | \"trailing\";\n /** The element to render. Defaults per variant (`h2` for a heading, and so on). */\n as?: TypographyElement;\n /**\n * Radix-style composition: render the child element itself, with these\n * styles merged onto it, instead of a wrapper. Takes precedence over `as`.\n */\n asChild?: boolean;\n ref?: Ref<HTMLElement>;\n children?: ReactNode;\n};\n\nconst DEFAULT_ELEMENT: Record<TypographyVariant, TypographyElement> = {\n display: \"h1\",\n heading: \"h2\",\n subheading: \"h3\",\n body: \"p\",\n label: \"span\",\n hint: \"p\",\n code: \"code\",\n};\n\nconst DEFAULT_WEIGHT: Record<TypographyVariant, TypographyWeight> = {\n display: \"semibold\",\n heading: \"semibold\",\n subheading: \"medium\",\n body: \"regular\",\n label: \"semibold\",\n hint: \"regular\",\n code: \"regular\",\n};\n\nconst VARIANT_CLASSES: Record<TypographyVariant, string> = {\n display: \"text-display leading-tight tracking-tight\",\n heading: \"text-heading leading-tight tracking-tight\",\n subheading: \"text-subheading leading-snug\",\n body: \"text-field leading-normal\",\n label: \"text-label leading-normal\",\n hint: \"text-hint leading-normal\",\n code: \"font-code text-field leading-normal\",\n};\n\nconst TONE_CLASSES: Record<TypographyTone, string> = {\n default: \"text-fg\",\n muted: \"text-fg-muted\",\n subtle: \"text-fg-subtle\",\n accent: \"text-accent\",\n \"on-accent\": \"text-on-accent\",\n success: \"text-success\",\n warning: \"text-warning\",\n info: \"text-info\",\n danger: \"text-danger\",\n};\n\nconst WEIGHT_CLASSES: Record<TypographyWeight, string> = {\n regular: \"font-normal\",\n medium: \"font-medium\",\n semibold: \"font-semibold\",\n bold: \"font-bold\",\n};\n\nconst ALIGN_CLASSES = {\n start: \"text-start\",\n center: \"text-center\",\n end: \"text-end\",\n} as const;\n\nconst ICON_CLASSES =\n \"inline-flex shrink-0 items-center [&>svg]:h-[1em] [&>svg]:w-[1em]\";\n\nfunction typographyClassName({\n variant,\n tone,\n weight,\n align,\n truncate,\n hasIcon,\n className,\n}: {\n variant: TypographyVariant;\n tone: TypographyTone;\n weight: TypographyWeight;\n align: \"start\" | \"center\" | \"end\" | undefined;\n truncate: boolean;\n hasIcon: boolean;\n className: string | undefined;\n}): string {\n return [\n VARIANT_CLASSES[variant],\n TONE_CLASSES[tone],\n WEIGHT_CLASSES[weight],\n align ? ALIGN_CLASSES[align] : \"\",\n hasIcon ? \"inline-flex items-center gap-1.5\" : \"\",\n // With an icon the root is a flex container, and text-overflow only\n // clips block text, so the text span carries the truncation instead.\n truncate && !hasIcon ? \"truncate\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nexport function Typography({\n variant = \"body\",\n tone = \"default\",\n weight,\n align,\n truncate = false,\n icon,\n iconPosition = \"leading\",\n as,\n asChild = false,\n className,\n children,\n ...rest\n}: TypographyProps) {\n const hasIcon = icon !== undefined && icon !== null;\n // Widened to `ElementType`: the union of intrinsic tags would otherwise\n // demand a `ref` typed to one specific element.\n const Component: ElementType = asChild\n ? Slot\n : (as ?? DEFAULT_ELEMENT[variant]);\n\n const iconNode = hasIcon ? (\n <span aria-hidden=\"true\" className={ICON_CLASSES}>\n {icon}\n </span>\n ) : null;\n\n const content = hasIcon ? (\n <>\n {iconPosition === \"leading\" ? iconNode : null}\n <span className={truncate ? \"min-w-0 truncate\" : undefined}>\n {children}\n </span>\n {iconPosition === \"trailing\" ? iconNode : null}\n </>\n ) : (\n children\n );\n\n return (\n <Component\n {...rest}\n className={typographyClassName({\n variant,\n tone,\n weight: weight ?? DEFAULT_WEIGHT[variant],\n align,\n truncate,\n hasIcon,\n className,\n })}\n >\n {content}\n </Component>\n );\n}\n","import { Slot } from \"@radix-ui/react-slot\";\nimport type { ButtonHTMLAttributes, ReactNode, Ref } from \"react\";\nimport { Typography, type TypographyTone } from \"@/components/typography\";\n\n/**\n * The design's primary action, as the auth screens use it: a 40px (or 44px)\n * accent-filled control with the field type scale, a 4px radius and the\n * shared 45% disabled opacity. `secondary` and `ghost` cover the quieter\n * actions that sit beside it.\n *\n * Server-safe: no state, no handlers of its own. `asChild` composes onto a\n * consumer's element — a `next/link` for a navigation styled as a button —\n * through Radix `Slot`, so the link keeps its own semantics. `loading` swaps\n * the label for a spinner and disables the control; it applies to the\n * rendered `<button>` only, since a child element owns its own content.\n */\n\nexport type ButtonVariant = \"primary\" | \"secondary\" | \"ghost\";\nexport type ButtonSize = \"md\" | \"lg\";\n\nexport type ButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> & {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Stretch to the container, as the auth forms' submit does. */\n fullWidth?: boolean;\n /** Shows a spinner in place of the label and disables the control. */\n loading?: boolean;\n /** Shown next to the spinner while `loading`; nothing but the spinner otherwise. */\n loadingLabel?: ReactNode;\n /** Merge the styles onto the child element instead of rendering a button. */\n asChild?: boolean;\n ref?: Ref<HTMLButtonElement>;\n children: ReactNode;\n};\n\nconst BASE_CLASSES =\n \"inline-flex shrink-0 items-center justify-center gap-2 rounded-field border font-[inherit] text-field font-semibold outline-none transition-colors focus-visible:ring-3 focus-visible:ring-accent-soft disabled:cursor-not-allowed disabled:opacity-45\";\n\nconst VARIANT_CLASSES: Record<ButtonVariant, string> = {\n primary:\n \"border-transparent bg-accent text-on-accent enabled:hover:bg-accent-2\",\n secondary: \"border-line bg-surface text-fg enabled:hover:bg-surface-2\",\n ghost: \"border-transparent bg-transparent text-fg enabled:hover:bg-surface-2\",\n};\n\nconst SIZE_CLASSES: Record<ButtonSize, string> = {\n md: \"h-10 px-4\",\n lg: \"h-11 px-5\",\n};\n\nconst LABEL_TONE: Record<ButtonVariant, TypographyTone> = {\n primary: \"on-accent\",\n secondary: \"default\",\n ghost: \"default\",\n};\n\nfunction buttonClassName({\n variant,\n size,\n fullWidth,\n className,\n}: {\n variant: ButtonVariant;\n size: ButtonSize;\n fullWidth: boolean;\n className: string | undefined;\n}): string {\n return [\n BASE_CLASSES,\n VARIANT_CLASSES[variant],\n SIZE_CLASSES[size],\n fullWidth ? \"w-full\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\nfunction Spinner() {\n return (\n <svg\n className=\"h-4 w-4 animate-spin\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\"\n data-testid=\"button-spinner\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12H4Z\"\n />\n </svg>\n );\n}\n\nexport function Button({\n variant = \"primary\",\n size = \"md\",\n fullWidth = false,\n loading = false,\n loadingLabel,\n asChild = false,\n type = \"button\",\n disabled,\n className,\n children,\n ...rest\n}: ButtonProps) {\n const classes = buttonClassName({ variant, size, fullWidth, className });\n\n if (asChild) {\n return (\n <Slot {...rest} className={classes}>\n {children}\n </Slot>\n );\n }\n\n return (\n <button\n {...rest}\n type={type}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n className={classes}\n >\n {loading ? (\n <>\n <Spinner />\n {loadingLabel}\n </>\n ) : (\n <Typography\n as=\"span\"\n variant=\"body\"\n weight=\"semibold\"\n tone={LABEL_TONE[variant]}\n >\n {children}\n </Typography>\n )}\n </button>\n );\n}\n","export type CartProduct = {\n /**\n * Stable identity for this line, used as the React key. Falls back to `name`,\n * so pass an `id` whenever a cart can hold two lines with the same name.\n */\n id?: string;\n name: string;\n price: number;\n};\n\nexport type CartProps = {\n products?: CartProduct[];\n /** ISO 4217 code used to format prices. */\n currency?: string;\n /** BCP 47 locale used to format prices. */\n locale?: string;\n};\n\nfunction formatPrice(value: number, currency: string, locale: string) {\n return new Intl.NumberFormat(locale, { style: \"currency\", currency }).format(\n value,\n );\n}\n\nexport function Cart({\n products = [],\n currency = \"KES\",\n locale = \"en-KE\",\n}: CartProps) {\n const total = products.reduce((sum, product) => sum + product.price, 0);\n\n return (\n <div className=\"cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4\">\n <h1 className=\"text-xl font-semibold text-gray-900\">Cart</h1>\n\n {products.length === 0 ? (\n <p className=\"text-sm text-gray-500\">Your cart is empty.</p>\n ) : (\n <>\n <ul className=\"flex flex-col divide-y divide-gray-100\">\n {products.map((product) => (\n <li\n key={product.id ?? product.name}\n className=\"flex items-baseline justify-between gap-4 py-2\"\n >\n <span className=\"text-sm text-gray-800\">{product.name}</span>\n <span className=\"text-sm tabular-nums text-gray-600\">\n {formatPrice(product.price, currency, locale)}\n </span>\n </li>\n ))}\n </ul>\n\n <div className=\"flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2\">\n <span className=\"text-sm font-medium text-gray-900\">Total</span>\n <span className=\"text-sm font-semibold tabular-nums text-gray-900\">\n {formatPrice(total, currency, locale)}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,41 +1,22 @@
|
|
|
1
|
+
import { ButtonProps } from './button.cjs';
|
|
2
|
+
export { Button, ButtonSize, ButtonVariant } from './button.cjs';
|
|
1
3
|
export { Cart, CartProduct, CartProps } from './cart.cjs';
|
|
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';
|
|
3
9
|
export { Typography, TypographyElement, TypographyProps, TypographyTone, TypographyVariant, TypographyWeight } from './typography.cjs';
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* keeps zod out of this module's public types, so consumers who only want an
|
|
9
|
-
* input do not have to install zod to typecheck it.
|
|
10
|
-
*/
|
|
11
|
-
type FieldSchema = {
|
|
12
|
-
safeParse: (value: unknown) => {
|
|
13
|
-
success: true;
|
|
14
|
-
} | {
|
|
15
|
-
success: false;
|
|
16
|
-
error: {
|
|
17
|
-
issues: readonly {
|
|
18
|
-
message: string;
|
|
19
|
-
}[];
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
/** Outcome of a single validation pass, handed to `onValidationChange`. */
|
|
24
|
-
type FieldValidation = {
|
|
25
|
-
valid: boolean;
|
|
26
|
-
/** First issue reported by the schema, or `undefined` when valid. */
|
|
27
|
-
error?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** Props every specialised input shares. `type` is fixed by the wrapper. */
|
|
31
|
-
type FieldProps = 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;
|
|
32
14
|
label?: string;
|
|
33
15
|
/** Guidance under the field. Replaced by the error message while invalid. */
|
|
34
16
|
hint?: ReactNode;
|
|
35
17
|
/**
|
|
36
18
|
* Error supplied by the caller — a server-side or cross-field failure. Takes
|
|
37
|
-
* precedence over the schema
|
|
38
|
-
* of what `schema` makes of the value on its own.
|
|
19
|
+
* precedence over what the form's schema reports for this field.
|
|
39
20
|
*/
|
|
40
21
|
error?: string;
|
|
41
22
|
/** Renders the design's muted "Optional" marker at the end of the label. */
|
|
@@ -44,36 +25,115 @@ type FieldProps = Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "valu
|
|
|
44
25
|
action?: ReactNode;
|
|
45
26
|
/** Trailing in-field slot, for affordances like the design's password peek. */
|
|
46
27
|
trailing?: ReactNode;
|
|
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?: FieldSchema;
|
|
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: FieldValidation) => void;
|
|
62
28
|
};
|
|
63
29
|
|
|
64
30
|
/**
|
|
65
31
|
* An email address. Fixes `type="email"` and the keyboard and autofill hints
|
|
66
|
-
* that go with it.
|
|
67
|
-
*
|
|
68
|
-
|
|
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.
|
|
69
53
|
*/
|
|
70
|
-
type
|
|
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">;
|
|
71
131
|
|
|
72
132
|
/**
|
|
73
133
|
* A password. Fixes `type="password"` and owns the design's in-field peek
|
|
74
134
|
* affordance, so the trailing slot is not exposed here — the toggle is it.
|
|
75
135
|
*/
|
|
76
|
-
type PasswordInputProps = Omit<
|
|
136
|
+
type PasswordInputProps = Omit<InputFieldProps, "trailing"> & {
|
|
77
137
|
/** Show the "Show"/"Hide" toggle. On by default, as the design has it. */
|
|
78
138
|
revealable?: boolean;
|
|
79
139
|
/** Labels for the toggle, for localisation. */
|
|
@@ -84,10 +144,11 @@ type PasswordInputProps = Omit<FieldProps, "trailing"> & {
|
|
|
84
144
|
};
|
|
85
145
|
|
|
86
146
|
/**
|
|
87
|
-
* A phone number. Fixes `type="tel"` and the numeric keypad.
|
|
88
|
-
* `phoneSchema` from `@carbonbits/sixr/validation`
|
|
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.
|
|
89
150
|
*/
|
|
90
|
-
type PhoneInputProps =
|
|
151
|
+
type PhoneInputProps = InputFieldProps;
|
|
91
152
|
|
|
92
153
|
/**
|
|
93
154
|
* Plain free text: names, job titles, one-time codes. Anything with a format
|
|
@@ -95,9 +156,9 @@ type PhoneInputProps = FieldProps;
|
|
|
95
156
|
* component (`EmailInput`, `PhoneInput`, `PasswordInput`), which fixes the
|
|
96
157
|
* keyboard, autocomplete and input type that format needs.
|
|
97
158
|
*/
|
|
98
|
-
type TextInputProps =
|
|
159
|
+
type TextInputProps = InputFieldProps & {
|
|
99
160
|
/** Renders the value in the design's monospace face, as the code entry does. */
|
|
100
161
|
mono?: boolean;
|
|
101
162
|
};
|
|
102
163
|
|
|
103
|
-
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 };
|