trc-ui 0.0.0-stage → 0.1.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 +14 -0
- package/LICENSE +21 -0
- package/README.md +120 -2
- package/dist/index.cjs +737 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +300 -0
- package/dist/index.d.ts +300 -0
- package/dist/index.js +685 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/package.json +78 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentPropsWithoutRef, ReactNode, ElementType, Ref, SVGProps } from 'react';
|
|
3
|
+
|
|
4
|
+
/** Joins CSS class names, skipping empty values. */
|
|
5
|
+
declare function cx(...classes: (string | false | null | undefined)[]): string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Colors the words between asterisks with the accent: "How it *works*".
|
|
9
|
+
* Without asterisks, `accentLast` colors the last words (titles coming from a CMS).
|
|
10
|
+
*/
|
|
11
|
+
declare function AccentText({ text, accentLast }: {
|
|
12
|
+
text: string;
|
|
13
|
+
accentLast?: number;
|
|
14
|
+
}): react.JSX.Element;
|
|
15
|
+
/** Plain text of a marked-up title, for attributes (`alt`, `title`, metadata). */
|
|
16
|
+
declare const plainText: (text: string) => string;
|
|
17
|
+
type HeadingSize = "display" | "xl" | "lg" | "md" | "sm";
|
|
18
|
+
type HeadingProps = Omit<ComponentPropsWithoutRef<"h2">, "children"> & {
|
|
19
|
+
/** Rendered tag; the visual size is set separately with `size`. */
|
|
20
|
+
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span";
|
|
21
|
+
size?: HeadingSize;
|
|
22
|
+
/** When `children` is a string without asterisks, number of trailing words in the accent color. */
|
|
23
|
+
accentLast?: number;
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
};
|
|
26
|
+
/** Thin Montserrat 400 heading; a string may contain an *accent word* between asterisks. */
|
|
27
|
+
declare function Heading({ as: Tag, size, accentLast, className, children, ...props }: HeadingProps): react.JSX.Element;
|
|
28
|
+
type TextProps<C extends ElementType = "p"> = {
|
|
29
|
+
as?: C;
|
|
30
|
+
size?: "lg" | "md" | "sm";
|
|
31
|
+
tone?: "default" | "muted" | "subtle";
|
|
32
|
+
} & Omit<ComponentPropsWithoutRef<C>, "as" | "size">;
|
|
33
|
+
/** Body text; `tone="muted"` (default) so that it does not compete with headings. */
|
|
34
|
+
declare function Text<C extends ElementType = "p">({ as, size, tone, className, ...props }: TextProps<C>): react.JSX.Element;
|
|
35
|
+
/** Large thin number in the accent color ("01", "02"…), reserved for steps in a real order. */
|
|
36
|
+
declare function StepNumber({ n, size, className }: {
|
|
37
|
+
n: number;
|
|
38
|
+
size?: "md" | "sm";
|
|
39
|
+
className?: string;
|
|
40
|
+
}): react.JSX.Element;
|
|
41
|
+
|
|
42
|
+
type PillStyle = {
|
|
43
|
+
/** White background: the main action of a screen. */
|
|
44
|
+
solid?: boolean;
|
|
45
|
+
/** Compact version (header, toolbars). */
|
|
46
|
+
size?: "md" | "sm";
|
|
47
|
+
/** Replaces the dot's arrow (for instance a left arrow for "Back"). */
|
|
48
|
+
icon?: ReactNode;
|
|
49
|
+
};
|
|
50
|
+
type PillButtonProps = ComponentPropsWithoutRef<"button"> & PillStyle & {
|
|
51
|
+
/** Replaces the icon with a spinner and disables the button. */
|
|
52
|
+
loading?: boolean;
|
|
53
|
+
};
|
|
54
|
+
/** Pill button: thin border, accent dot with an arrow that stretches on hover. */
|
|
55
|
+
declare const PillButton: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & PillStyle & {
|
|
56
|
+
/** Replaces the icon with a spinner and disables the button. */
|
|
57
|
+
loading?: boolean;
|
|
58
|
+
} & react.RefAttributes<HTMLButtonElement>>;
|
|
59
|
+
type PillLinkProps<C extends ElementType = "a"> = PillStyle & {
|
|
60
|
+
/** Router link component (Next.js or React Router `Link`…); `<a>` by default. */
|
|
61
|
+
as?: C;
|
|
62
|
+
} & Omit<ComponentPropsWithoutRef<C>, "as" | keyof PillStyle>;
|
|
63
|
+
/** Same pill as a link. With a router: `<PillLink as={Link} href="/">`. */
|
|
64
|
+
declare const PillLink: <C extends ElementType = "a">(props: PillLinkProps<C> & {
|
|
65
|
+
ref?: Ref<HTMLAnchorElement>;
|
|
66
|
+
}) => ReactNode;
|
|
67
|
+
|
|
68
|
+
type IconProps = SVGProps<SVGSVGElement>;
|
|
69
|
+
declare const ArrowRight: (props: IconProps) => react.JSX.Element;
|
|
70
|
+
declare const ArrowLeft: (props: IconProps) => react.JSX.Element;
|
|
71
|
+
declare const ChevronDown: (props: IconProps) => react.JSX.Element;
|
|
72
|
+
declare const Check: (props: IconProps) => react.JSX.Element;
|
|
73
|
+
declare const Menu: (props: IconProps) => react.JSX.Element;
|
|
74
|
+
declare const Close: (props: IconProps) => react.JSX.Element;
|
|
75
|
+
declare const ArrowUp: (props: IconProps) => react.JSX.Element;
|
|
76
|
+
|
|
77
|
+
type Polymorphic<C extends ElementType, P> = P & {
|
|
78
|
+
as?: C;
|
|
79
|
+
} & Omit<ComponentPropsWithoutRef<C>, "as" | keyof P>;
|
|
80
|
+
type ContainerProps<C extends ElementType = "div"> = Polymorphic<C, {
|
|
81
|
+
/** `default`: 1280 px, for text and grids; `wide`: 1600 px, for full-width cards; `narrow`: 768 px. */
|
|
82
|
+
size?: "default" | "wide" | "narrow";
|
|
83
|
+
}>;
|
|
84
|
+
/** Centered max width, with side gutters that grow with the screen. */
|
|
85
|
+
declare function Container<C extends ElementType = "div">({ as, size, className, ...props }: ContainerProps<C>): react.JSX.Element;
|
|
86
|
+
type SectionProps<C extends ElementType = "section"> = Polymorphic<C, {
|
|
87
|
+
/** Vertical spacing. */
|
|
88
|
+
spacing?: "sm" | "md" | "lg" | "none";
|
|
89
|
+
/**
|
|
90
|
+
* Card inset from the screen edges ("magazine" effect): graphite background and rounded corners,
|
|
91
|
+
* for banners, calls to action and heroes.
|
|
92
|
+
*/
|
|
93
|
+
inset?: boolean;
|
|
94
|
+
}>;
|
|
95
|
+
/** Vertical block of a page. With `inset`, it becomes a large rounded card a few pixels from the edges. */
|
|
96
|
+
declare function Section<C extends ElementType = "section">({ as, spacing, inset, className, children, ...props }: SectionProps<C>): react.JSX.Element;
|
|
97
|
+
type CardProps<C extends ElementType = "div"> = Polymorphic<C, {
|
|
98
|
+
/** `alt`: a slightly lighter grey, to tell two side-by-side blocks apart. */
|
|
99
|
+
tone?: "default" | "alt";
|
|
100
|
+
padding?: "none" | "sm" | "md" | "lg";
|
|
101
|
+
/** Lightens on hover (clickable cards: links, buttons). */
|
|
102
|
+
interactive?: boolean;
|
|
103
|
+
/** Decorative watermark icon: very large, thin stroke, half out of the corner; wakes up on hover. */
|
|
104
|
+
watermark?: ReactNode;
|
|
105
|
+
}>;
|
|
106
|
+
/** Graphite card, rounded corners, no shadow: depth comes from shades of grey. */
|
|
107
|
+
declare function Card<C extends ElementType = "div">({ as, tone, padding, interactive, watermark, className, children, ...props }: CardProps<C>): react.JSX.Element;
|
|
108
|
+
|
|
109
|
+
type FieldProps = {
|
|
110
|
+
label: ReactNode;
|
|
111
|
+
/** Hint shown under the control. */
|
|
112
|
+
hint?: ReactNode;
|
|
113
|
+
/** Error message: replaces the hint and marks the control as invalid. */
|
|
114
|
+
error?: ReactNode;
|
|
115
|
+
required?: boolean;
|
|
116
|
+
/** Control id; generated when omitted. */
|
|
117
|
+
id?: string;
|
|
118
|
+
className?: string;
|
|
119
|
+
children: ReactNode;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Label, hint and error of a form control. The control placed inside (`Input`, `Textarea`, `Select`)
|
|
123
|
+
* automatically receives its `id`, `aria-describedby` and `aria-invalid`.
|
|
124
|
+
*/
|
|
125
|
+
declare function Field({ label, hint, error, required, id, className, children }: FieldProps): react.JSX.Element;
|
|
126
|
+
type ControlProps = {
|
|
127
|
+
invalid?: boolean;
|
|
128
|
+
};
|
|
129
|
+
type InputProps = ComponentPropsWithoutRef<"input"> & ControlProps;
|
|
130
|
+
declare const Input: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & ControlProps & react.RefAttributes<HTMLInputElement>>;
|
|
131
|
+
type TextareaProps = ComponentPropsWithoutRef<"textarea"> & ControlProps;
|
|
132
|
+
declare const Textarea: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & ControlProps & react.RefAttributes<HTMLTextAreaElement>>;
|
|
133
|
+
type SelectProps = ComponentPropsWithoutRef<"select"> & ControlProps & {
|
|
134
|
+
/** Empty option shown until something is chosen. */
|
|
135
|
+
placeholder?: string;
|
|
136
|
+
};
|
|
137
|
+
/** Native select (accessible and mobile friendly), dressed with a thin chevron. */
|
|
138
|
+
declare const Select: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>, "ref"> & ControlProps & {
|
|
139
|
+
/** Empty option shown until something is chosen. */
|
|
140
|
+
placeholder?: string;
|
|
141
|
+
} & react.RefAttributes<HTMLSelectElement>>;
|
|
142
|
+
|
|
143
|
+
type ToggleProps = Omit<ComponentPropsWithoutRef<"input">, "type"> & {
|
|
144
|
+
label: ReactNode;
|
|
145
|
+
/** Extra detail under the label. */
|
|
146
|
+
description?: ReactNode;
|
|
147
|
+
};
|
|
148
|
+
type CheckboxProps = ToggleProps;
|
|
149
|
+
/** Native checkbox, filled with the accent color once checked. */
|
|
150
|
+
declare const Checkbox: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "type"> & {
|
|
151
|
+
label: ReactNode;
|
|
152
|
+
/** Extra detail under the label. */
|
|
153
|
+
description?: ReactNode;
|
|
154
|
+
} & react.RefAttributes<HTMLInputElement>>;
|
|
155
|
+
type SwitchProps = ToggleProps;
|
|
156
|
+
/** Switch: a native checkbox announced as a `switch` to screen readers. */
|
|
157
|
+
declare const Switch: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "type"> & {
|
|
158
|
+
label: ReactNode;
|
|
159
|
+
/** Extra detail under the label. */
|
|
160
|
+
description?: ReactNode;
|
|
161
|
+
} & react.RefAttributes<HTMLInputElement>>;
|
|
162
|
+
|
|
163
|
+
type NavLink = {
|
|
164
|
+
label: ReactNode;
|
|
165
|
+
href: string;
|
|
166
|
+
/** Current page: marked with an accent dot. */
|
|
167
|
+
active?: boolean;
|
|
168
|
+
};
|
|
169
|
+
type NavMenu = {
|
|
170
|
+
label: ReactNode;
|
|
171
|
+
/** Dropdown items, with an optional short description (no numbers). */
|
|
172
|
+
items: (NavLink & {
|
|
173
|
+
description?: ReactNode;
|
|
174
|
+
})[];
|
|
175
|
+
};
|
|
176
|
+
type NavItem = NavLink | NavMenu;
|
|
177
|
+
type SiteHeaderProps = {
|
|
178
|
+
/** Logo (white), wrapped in a link to `homeHref`. */
|
|
179
|
+
logo: ReactNode;
|
|
180
|
+
/** Accessible name of the logo link, usually the brand name. */
|
|
181
|
+
logoLabel: string;
|
|
182
|
+
homeHref?: string;
|
|
183
|
+
nav?: NavItem[];
|
|
184
|
+
/** Main action, shown as a compact pill (and a large one in the mobile menu). */
|
|
185
|
+
cta?: {
|
|
186
|
+
label: ReactNode;
|
|
187
|
+
href: string;
|
|
188
|
+
};
|
|
189
|
+
/** Extra elements on the right on large screens (language switcher…). */
|
|
190
|
+
actions?: ReactNode;
|
|
191
|
+
/** Content added at the bottom of the mobile menu. */
|
|
192
|
+
mobileFooter?: ReactNode;
|
|
193
|
+
/** Router link component (Next.js `Link`…); `<a>` by default. */
|
|
194
|
+
linkAs?: ElementType;
|
|
195
|
+
/** Scroll offset (px) from which the bar becomes blurred graphite. */
|
|
196
|
+
scrollThreshold?: number;
|
|
197
|
+
menuLabel?: string;
|
|
198
|
+
closeLabel?: string;
|
|
199
|
+
className?: string;
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Floating header: transparent over the hero at the top of the page, it becomes a blurred
|
|
203
|
+
* graphite bar as soon as the page scrolls. Dropdowns on large screens, side panel on mobile.
|
|
204
|
+
*/
|
|
205
|
+
declare function SiteHeader({ logo, logoLabel, homeHref, nav, cta, actions, mobileFooter, linkAs: LinkTag, scrollThreshold, menuLabel, closeLabel, className, }: SiteHeaderProps): react.JSX.Element;
|
|
206
|
+
|
|
207
|
+
type FooterLink = {
|
|
208
|
+
label: ReactNode;
|
|
209
|
+
href: string;
|
|
210
|
+
};
|
|
211
|
+
type SiteFooterProps = {
|
|
212
|
+
/** Logo (white), wrapped in a link to `homeHref`. */
|
|
213
|
+
logo?: ReactNode;
|
|
214
|
+
logoLabel?: string;
|
|
215
|
+
homeHref?: string;
|
|
216
|
+
/** Short sentence under the logo. */
|
|
217
|
+
tagline?: ReactNode;
|
|
218
|
+
/** Under the sentence: a pill, a contact… */
|
|
219
|
+
children?: ReactNode;
|
|
220
|
+
/** Site map in columns, each with a spaced small-caps title. */
|
|
221
|
+
columns?: {
|
|
222
|
+
title: ReactNode;
|
|
223
|
+
links: FooterLink[];
|
|
224
|
+
}[];
|
|
225
|
+
/** Accessible name of the site map. */
|
|
226
|
+
columnsLabel?: string;
|
|
227
|
+
/** Bottom line (copyright, credits…). */
|
|
228
|
+
copyright?: ReactNode;
|
|
229
|
+
/** Legal links, aligned right on large screens. */
|
|
230
|
+
legal?: FooterLink[];
|
|
231
|
+
legalLabel?: string;
|
|
232
|
+
/** Router link component (Next.js `Link`…); `<a>` by default. */
|
|
233
|
+
linkAs?: ElementType;
|
|
234
|
+
className?: string;
|
|
235
|
+
};
|
|
236
|
+
/** Graphite card footer: brand and call to action, site map in columns, legal links. */
|
|
237
|
+
declare function SiteFooter({ logo, logoLabel, homeHref, tagline, children, columns, columnsLabel, copyright, legal, legalLabel, linkAs: LinkTag, className, }: SiteFooterProps): react.JSX.Element;
|
|
238
|
+
|
|
239
|
+
type PageHeroProps = {
|
|
240
|
+
/** Title; the words between *asterisks* take the accent, otherwise the last words (`accentLast`). */
|
|
241
|
+
title: string;
|
|
242
|
+
/** Number of trailing words in the accent color when the title has no asterisks (2 for a long title, 1 otherwise). */
|
|
243
|
+
accentLast?: number;
|
|
244
|
+
description?: ReactNode;
|
|
245
|
+
/** Discreet line under the description (last updated date, breadcrumb…). */
|
|
246
|
+
meta?: ReactNode;
|
|
247
|
+
/**
|
|
248
|
+
* Background photo, heavily darkened: a URL, or a ready-made element (Next.js `<Image fill />`…).
|
|
249
|
+
* Without a photo, a subtle accent glow on a graphite background.
|
|
250
|
+
*/
|
|
251
|
+
image?: string | ReactNode;
|
|
252
|
+
/** Photo position (`object-position`). */
|
|
253
|
+
imagePosition?: string;
|
|
254
|
+
/** Content under the text (pills…). */
|
|
255
|
+
children?: ReactNode;
|
|
256
|
+
className?: string;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Header of inner pages: rounded card inset from the edges, darkened background photo,
|
|
260
|
+
* thin title whose last words take the accent. Leaves room for the floating header above.
|
|
261
|
+
*/
|
|
262
|
+
declare function PageHero({ title, accentLast, description, meta, image, imagePosition, children, className, }: PageHeroProps): react.JSX.Element;
|
|
263
|
+
type HeroClip = {
|
|
264
|
+
/** Muted video, 1280 px, without an audio track. Provide WebM and/or MP4. */
|
|
265
|
+
webm?: string;
|
|
266
|
+
mp4?: string;
|
|
267
|
+
/** Image shown before playback, and alone when the user prefers reduced motion. */
|
|
268
|
+
poster?: string;
|
|
269
|
+
};
|
|
270
|
+
type HeroVideoProps = {
|
|
271
|
+
/** Videos played one after another with a crossfade; the first one is picked at random. */
|
|
272
|
+
clips: HeroClip[];
|
|
273
|
+
/** Hero text (title, description, pills), pinned to the bottom left. */
|
|
274
|
+
children: ReactNode;
|
|
275
|
+
/** Optional block pinned to the bottom right on large screens. */
|
|
276
|
+
aside?: ReactNode;
|
|
277
|
+
/** Crossfade duration, in seconds. */
|
|
278
|
+
fade?: number;
|
|
279
|
+
/** Soft parallax: the video moves down slower than the page. */
|
|
280
|
+
parallax?: boolean;
|
|
281
|
+
className?: string;
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* Home page hero: rounded card inset from the edges, muted background videos that alternate with
|
|
285
|
+
* a crossfade, dark veils for legibility. No video in the server render: the pick happens
|
|
286
|
+
* after hydration, then the video fades in. Reduced motion: the still image only.
|
|
287
|
+
*/
|
|
288
|
+
declare function HeroVideo({ clips, children, aside, fade, parallax, className }: HeroVideoProps): react.JSX.Element;
|
|
289
|
+
|
|
290
|
+
type BackToTopProps = {
|
|
291
|
+
label?: string;
|
|
292
|
+
/** Scroll offset, in viewport heights, from which the button appears. */
|
|
293
|
+
threshold?: number;
|
|
294
|
+
className?: string;
|
|
295
|
+
};
|
|
296
|
+
/** Floating accent "Back to top" button: appears once the first screen is scrolled past. */
|
|
297
|
+
declare function BackToTop({ label, threshold, className }: BackToTopProps): react.JSX.Element;
|
|
298
|
+
|
|
299
|
+
export { AccentText, ArrowLeft, ArrowRight, ArrowUp, BackToTop, Card, Check, Checkbox, ChevronDown, Close, Container, Field, Heading, HeroVideo, Input, Menu, PageHero, PillButton, PillLink, Section, Select, SiteFooter, SiteHeader, StepNumber, Switch, Text, Textarea, cx, plainText };
|
|
300
|
+
export type { BackToTopProps, CardProps, CheckboxProps, ContainerProps, FieldProps, FooterLink, HeadingProps, HeadingSize, HeroClip, HeroVideoProps, InputProps, NavItem, NavLink, NavMenu, PageHeroProps, PillButtonProps, PillLinkProps, SectionProps, SelectProps, SiteFooterProps, SiteHeaderProps, SwitchProps, TextProps, TextareaProps };
|