@beautinique/frontend-components 1.0.6 → 1.0.8
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 +184 -20
- package/dist/auth/AuthBottomInstructions.d.cts +42 -0
- package/dist/auth/AuthBottomInstructions.d.cts.map +1 -0
- package/dist/auth/AuthBottomInstructions.d.ts +42 -0
- package/dist/auth/AuthBottomInstructions.d.ts.map +1 -0
- package/dist/auth/index.cjs +76 -0
- package/dist/auth/index.cjs.map +1 -0
- package/dist/auth/index.d.cts +2 -0
- package/dist/auth/index.d.cts.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +74 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/layout/ScrollToTop.d.cts +36 -0
- package/dist/layout/ScrollToTop.d.cts.map +1 -0
- package/dist/layout/ScrollToTop.d.ts +36 -0
- package/dist/layout/ScrollToTop.d.ts.map +1 -0
- package/dist/layout/index.cjs +33 -0
- package/dist/layout/index.cjs.map +1 -0
- package/dist/layout/index.d.cts +2 -0
- package/dist/layout/index.d.cts.map +1 -0
- package/dist/layout/index.d.ts +2 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +31 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/lib/content.d.cts +7 -0
- package/dist/lib/content.d.cts.map +1 -0
- package/dist/lib/content.d.ts +7 -0
- package/dist/lib/content.d.ts.map +1 -0
- package/dist/lib/countdown.d.cts +13 -0
- package/dist/lib/countdown.d.cts.map +1 -0
- package/dist/lib/countdown.d.ts +13 -0
- package/dist/lib/countdown.d.ts.map +1 -0
- package/dist/lib/stepper.d.cts +9 -0
- package/dist/lib/stepper.d.cts.map +1 -0
- package/dist/lib/stepper.d.ts +9 -0
- package/dist/lib/stepper.d.ts.map +1 -0
- package/dist/linear-gradient/LinearGradient.d.cts +13 -0
- package/dist/linear-gradient/LinearGradient.d.cts.map +1 -0
- package/dist/linear-gradient/LinearGradient.d.ts +13 -0
- package/dist/linear-gradient/LinearGradient.d.ts.map +1 -0
- package/dist/linear-gradient/index.cjs +25 -0
- package/dist/linear-gradient/index.cjs.map +1 -0
- package/dist/linear-gradient/index.d.cts +2 -0
- package/dist/linear-gradient/index.d.cts.map +1 -0
- package/dist/linear-gradient/index.d.ts +2 -0
- package/dist/linear-gradient/index.d.ts.map +1 -0
- package/dist/linear-gradient/index.js +23 -0
- package/dist/linear-gradient/index.js.map +1 -0
- package/dist/resend/Resend.d.cts +37 -0
- package/dist/resend/Resend.d.cts.map +1 -0
- package/dist/resend/Resend.d.ts +37 -0
- package/dist/resend/Resend.d.ts.map +1 -0
- package/dist/resend/index.cjs +138 -0
- package/dist/resend/index.cjs.map +1 -0
- package/dist/resend/index.d.cts +2 -0
- package/dist/resend/index.d.cts.map +1 -0
- package/dist/resend/index.d.ts +2 -0
- package/dist/resend/index.d.ts.map +1 -0
- package/dist/resend/index.js +136 -0
- package/dist/resend/index.js.map +1 -0
- package/dist/stepper/Stepper.d.cts +35 -0
- package/dist/stepper/Stepper.d.cts.map +1 -0
- package/dist/stepper/Stepper.d.ts +35 -0
- package/dist/stepper/Stepper.d.ts.map +1 -0
- package/dist/stepper/index.cjs +149 -0
- package/dist/stepper/index.cjs.map +1 -0
- package/dist/stepper/index.d.cts +2 -0
- package/dist/stepper/index.d.cts.map +1 -0
- package/dist/stepper/index.d.ts +2 -0
- package/dist/stepper/index.d.ts.map +1 -0
- package/dist/stepper/index.js +147 -0
- package/dist/stepper/index.js.map +1 -0
- package/dist/stepper/stepper-icons.d.cts +10 -0
- package/dist/stepper/stepper-icons.d.cts.map +1 -0
- package/dist/stepper/stepper-icons.d.ts +10 -0
- package/dist/stepper/stepper-icons.d.ts.map +1 -0
- package/dist/theme/Theme.d.cts +23 -0
- package/dist/theme/Theme.d.cts.map +1 -0
- package/dist/theme/Theme.d.ts +23 -0
- package/dist/theme/Theme.d.ts.map +1 -0
- package/dist/theme/index.cjs +76 -0
- package/dist/theme/index.cjs.map +1 -0
- package/dist/theme/index.d.cts +2 -0
- package/dist/theme/index.d.cts.map +1 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +74 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme-icons.d.cts +21 -0
- package/dist/theme/theme-icons.d.cts.map +1 -0
- package/dist/theme/theme-icons.d.ts +21 -0
- package/dist/theme/theme-icons.d.ts.map +1 -0
- package/dist/toast/index.cjs +0 -142
- package/dist/toast/index.cjs.map +1 -1
- package/dist/toast/index.d.cts +0 -1
- package/dist/toast/index.d.cts.map +1 -1
- package/dist/toast/index.d.ts +0 -1
- package/dist/toast/index.d.ts.map +1 -1
- package/dist/toast/index.js +1 -142
- package/dist/toast/index.js.map +1 -1
- package/dist/toast/types.d.cts +4 -37
- package/dist/toast/types.d.cts.map +1 -1
- package/dist/toast/types.d.ts +4 -37
- package/dist/toast/types.d.ts.map +1 -1
- package/dist/toast/uploads.d.cts +1 -31
- package/dist/toast/uploads.d.cts.map +1 -1
- package/dist/toast/uploads.d.ts +1 -31
- package/dist/toast/uploads.d.ts.map +1 -1
- package/dist/ui/Badge.d.cts +12 -0
- package/dist/ui/Badge.d.cts.map +1 -0
- package/dist/ui/Badge.d.ts +12 -0
- package/dist/ui/Badge.d.ts.map +1 -0
- package/dist/ui/Divider.d.cts +12 -0
- package/dist/ui/Divider.d.cts.map +1 -0
- package/dist/ui/Divider.d.ts +12 -0
- package/dist/ui/Divider.d.ts.map +1 -0
- package/dist/ui/GradientText.d.cts +30 -0
- package/dist/ui/GradientText.d.cts.map +1 -0
- package/dist/ui/GradientText.d.ts +30 -0
- package/dist/ui/GradientText.d.ts.map +1 -0
- package/dist/ui/index.cjs +37 -3
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +3 -0
- package/dist/ui/index.d.cts.map +1 -1
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +35 -4
- package/dist/ui/index.js.map +1 -1
- package/package.json +44 -8
- package/dist/toast/toaster.d.cts +0 -80
- package/dist/toast/toaster.d.cts.map +0 -1
- package/dist/toast/toaster.d.ts +0 -80
- package/dist/toast/toaster.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -29,21 +29,31 @@ generated and the components come out unstyled. (The playground has a page that
|
|
|
29
29
|
|
|
30
30
|
## Import paths
|
|
31
31
|
|
|
32
|
-
Components that most screens use live in `/ui`
|
|
33
|
-
use have a path of their own
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| `@beautinique/frontend-components
|
|
39
|
-
| `@beautinique/frontend-components/
|
|
40
|
-
| `@beautinique/frontend-components/
|
|
41
|
-
|
|
42
|
-
`
|
|
32
|
+
Components that most screens use live in `/ui`, `/layout`, `/theme` and `/toast`, and the root gives
|
|
33
|
+
all of them. Components that few screens use have a path of their own and are **not** in the root, so
|
|
34
|
+
an app only bundles what it imports.
|
|
35
|
+
|
|
36
|
+
| Import path | What it gives |
|
|
37
|
+
| -------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `@beautinique/frontend-components` | Everything `/ui`, `/layout`, `/theme` and `/toast` give (the very same values), and the types |
|
|
39
|
+
| `@beautinique/frontend-components/ui` | `Badge`, `Button`, `Divider`, `GradientText`, `Tooltip` |
|
|
40
|
+
| `@beautinique/frontend-components/layout` | `ScrollToTop` |
|
|
41
|
+
| `@beautinique/frontend-components/theme` | `Theme` (the dark / light button) |
|
|
42
|
+
| `@beautinique/frontend-components/toast` | `ToastContainer`, `Toaster`, the types of the toasts, and what works out what a toast shows |
|
|
43
|
+
| `@beautinique/frontend-components/auth` | `AuthBottomInstructions` |
|
|
44
|
+
| `@beautinique/frontend-components/linear-gradient` | `LinearGradient` |
|
|
45
|
+
| `@beautinique/frontend-components/resend` | `Resend` |
|
|
46
|
+
| `@beautinique/frontend-components/stepper` | `Stepper` |
|
|
47
|
+
| `@beautinique/frontend-components/source.css` | The `@source` line of the setup above |
|
|
48
|
+
|
|
49
|
+
What the root gives can be imported from the root or from its own path, it is the same component
|
|
50
|
+
either way:
|
|
43
51
|
|
|
44
52
|
```ts
|
|
45
53
|
import { Button } from '@beautinique/frontend-components'; // or
|
|
46
54
|
import { Button } from '@beautinique/frontend-components/ui';
|
|
55
|
+
|
|
56
|
+
import { Stepper } from '@beautinique/frontend-components/stepper'; // only from its own path
|
|
47
57
|
```
|
|
48
58
|
|
|
49
59
|
The root only re-exports, it does not copy: an app that imports only `Button` from the root bundles the
|
|
@@ -110,9 +120,156 @@ const hint = (
|
|
|
110
120
|
that is not there at all: the content is one level deeper in the DOM, so a css rule that looks at
|
|
111
121
|
the parent of the content (`space-y-*` on a parent, `> :first-child`) sees the wrapper.
|
|
112
122
|
|
|
123
|
+
### Badge, Divider, GradientText
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { Badge, Divider, GradientText } from '@beautinique/frontend-components';
|
|
127
|
+
|
|
128
|
+
<Badge content="New" />; // `content` is any React content: text, a number, an icon and a text
|
|
129
|
+
<Badge content={count > 0 && count} />; // nothing to show (null, undefined, false, '') draws no badge; 0 is shown
|
|
130
|
+
<Divider aria-hidden="true" />; // an <hr>; hide it from screen readers when it is only a line
|
|
131
|
+
<GradientText type="accent" text="Terms" />; // or <GradientText type="silver">any <b>content</b></GradientText>
|
|
132
|
+
<GradientText as={Link} to="/terms" type="accent" text="Terms" />; // the Link of the router, with its props
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- All three take the attributes of their element (`id`, `data-*`, `aria-*`, `ref`...), and the
|
|
136
|
+
classes you give are added after their own.
|
|
137
|
+
- `GradientText` takes `text` **or** `children`, not both (the compiler says so). In forced-colors mode
|
|
138
|
+
(Windows high contrast), where a gradient is not drawn, the text takes the colour of the system
|
|
139
|
+
instead of vanishing.
|
|
140
|
+
|
|
141
|
+
### LinearGradient
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
import { LinearGradient } from '@beautinique/frontend-components/linear-gradient';
|
|
145
|
+
|
|
146
|
+
<div className="relative overflow-x-auto">
|
|
147
|
+
<LinearGradient position="left" />
|
|
148
|
+
{/* the scrolling content */}
|
|
149
|
+
<LinearGradient position="right" />
|
|
150
|
+
</div>;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
A fade in the background colour over one edge (`top`, `bottom`, `left` or `right`) of a `relative`
|
|
154
|
+
container: it shows that there is more to scroll. It is decoration: the pointer goes through it and
|
|
155
|
+
assistive technology skips it.
|
|
156
|
+
|
|
157
|
+
### Stepper
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { Stepper } from '@beautinique/frontend-components/stepper';
|
|
161
|
+
|
|
162
|
+
<Stepper
|
|
163
|
+
label="Checkout progress"
|
|
164
|
+
activeStep={1}
|
|
165
|
+
steps={[
|
|
166
|
+
{ title: 'Account', description: 'Create your account' },
|
|
167
|
+
{ title: 'Address', description: 'Where to deliver', icon: 'solar:map-point-linear' },
|
|
168
|
+
{ title: 'Payment', disabled: true },
|
|
169
|
+
]}
|
|
170
|
+
onStepClick={(index) => setStep(index)} // optional: with it the steps are buttons
|
|
171
|
+
>
|
|
172
|
+
{/* optional: shown under the steps */}
|
|
173
|
+
</Stepper>;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
- The steps are an ordered list and the current one has `aria-current="step"`. A completed step shows a
|
|
177
|
+
tick, and says "Completed" to a screen reader (`completedLabel` for another word).
|
|
178
|
+
- `activeStep` is kept inside the steps (`99` is the last one, `NaN` the first).
|
|
179
|
+
- With `onStepClick` the steps are real buttons (keyboard, focus ring); a step with `disabled` cannot be
|
|
180
|
+
clicked. Without it nothing in the stepper is a button.
|
|
181
|
+
- The tick is bundled with the package (registered with Iconify when a stepper renders), so it needs no
|
|
182
|
+
network. The `icon` of a step is an Iconify name that Iconify downloads the first time it is shown;
|
|
183
|
+
to have one offline, add it to the app with `addCollection`.
|
|
184
|
+
|
|
185
|
+
### Resend
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { Resend } from '@beautinique/frontend-components/resend';
|
|
189
|
+
|
|
190
|
+
<Resend
|
|
191
|
+
label="Not received OTP?"
|
|
192
|
+
count={sendCount >= 3 ? 0 : 30} // seconds to wait; 0 = no wait
|
|
193
|
+
onResend={handleResendOtp} // may return a promise
|
|
194
|
+
/>;
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- "Resend in 30s", and when the wait is over a button. The wait starts when the component is shown and
|
|
198
|
+
again after each resend, with the `count` of that moment. A new email address? Give it a new `key`.
|
|
199
|
+
- **It is measured against the clock**, not counted tick by tick: a background tab, or a laptop that
|
|
200
|
+
slept, does not make people wait longer than the time that really went by.
|
|
201
|
+
- If `onResend` returns a promise the button waits for it (disabled, "Sending…", no double click)
|
|
202
|
+
and the wait starts when it resolves. If it rejects there is no wait, the button can be pressed
|
|
203
|
+
again and the error is reported to `window` (`reportError`). Handle the errors you can recover
|
|
204
|
+
from (a toast) inside it.
|
|
205
|
+
- A screen reader is not told the number every second (`role="timer"`), but is told once when the
|
|
206
|
+
button is back. The words (`resendLabel`, `countdownLabel`, `sendingLabel`, `readyLabel`,
|
|
207
|
+
`formatSeconds`) can be changed for another language.
|
|
208
|
+
|
|
209
|
+
### Theme
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { Theme } from '@beautinique/frontend-components';
|
|
213
|
+
import { createThemeStore } from '@beautinique/frontend-stores';
|
|
214
|
+
|
|
215
|
+
export const useThemeStore = createThemeStore(); // once, in a module of the app
|
|
216
|
+
|
|
217
|
+
<Theme store={useThemeStore} />;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
A button that switches between the dark and the light theme (a sun while it is dark, a moon while it
|
|
221
|
+
is light). It only changes the store, which remembers the choice; putting the theme on the page is the
|
|
222
|
+
app's. Its name for assistive technology follows the theme ("Switch to light theme"; `labels` changes
|
|
223
|
+
the words). The icons move; for a person who asked for less motion (`prefers-reduced-motion`) it
|
|
224
|
+
shows still ones.
|
|
225
|
+
|
|
226
|
+
### ScrollToTop
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
import { ScrollToTop } from '@beautinique/frontend-components';
|
|
230
|
+
|
|
231
|
+
const { pathname } = useLocation(); // from the router of the app
|
|
232
|
+
|
|
233
|
+
<div id="main">
|
|
234
|
+
<ScrollToTop pathname={pathname} />
|
|
235
|
+
</div>;
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Scrolls the element with `id="main"` to its top each time `pathname` changes (a router does not do it
|
|
239
|
+
for a single page app). It draws nothing. `id`, `behavior`, `block` and `inline` are the `id` of the
|
|
240
|
+
element and the options of `scrollIntoView` (`'auto'`, `'start'` and `'nearest'` unless told another);
|
|
241
|
+
a `'smooth'` scroll is made `'auto'` for a person who asked for less motion. `skipInitial` leaves the
|
|
242
|
+
first page where it is (when the browser restores the scroll on a reload).
|
|
243
|
+
|
|
244
|
+
### AuthBottomInstructions
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { AuthBottomInstructions } from '@beautinique/frontend-components/auth';
|
|
248
|
+
import { Link } from 'react-router-dom';
|
|
249
|
+
|
|
250
|
+
<AuthBottomInstructions as={Link} terms={{ to: '/terms' }} privacy={{ to: '/privacy' }} />;
|
|
251
|
+
// "By continuing, you agree to our Terms & Conditions and Privacy Policy."
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The small print under a sign-in form. `as` is what makes the links (`'a'` unless told another; for `'a'`
|
|
255
|
+
the compiler asks for `href`), `terms` and `privacy` are the props of those links. `termsLabel`,
|
|
256
|
+
`privacyLabel` and `message` change the words:
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
<AuthBottomInstructions
|
|
260
|
+
terms={{ href: '/terms' }}
|
|
261
|
+
privacy={{ href: '/privacy' }}
|
|
262
|
+
message={({ terms, privacy }) => (
|
|
263
|
+
<>
|
|
264
|
+
Entering means you accept our {terms} and our {privacy}.
|
|
265
|
+
</>
|
|
266
|
+
)}
|
|
267
|
+
/>
|
|
268
|
+
```
|
|
269
|
+
|
|
113
270
|
### Toasts
|
|
114
271
|
|
|
115
|
-
|
|
272
|
+
This package draws the toasts; the store that keeps them and the `toaster` that shows them are [`@beautinique/frontend-stores`](../stores/README.md)'s. The store is **made by the app**, once, with the toasts of this package, and given to the two things that need it: the `ToastContainer` here, as a prop, and `createToaster` of the stores package. This package holds no store and no toaster of its own, and exports none.
|
|
116
273
|
|
|
117
274
|
```ts
|
|
118
275
|
// src/stores/toast.store.ts
|
|
@@ -124,7 +281,7 @@ export const useToastStore = createToastStore<TToast>();
|
|
|
124
281
|
|
|
125
282
|
```ts
|
|
126
283
|
// src/utils/toaster.ts - the toaster and the helpers, for the rest of the app to import
|
|
127
|
-
import { createToaster } from '@beautinique/frontend-
|
|
284
|
+
import { createToaster } from '@beautinique/frontend-stores';
|
|
128
285
|
|
|
129
286
|
import { useToastStore } from '@/stores/toast.store';
|
|
130
287
|
|
|
@@ -156,19 +313,26 @@ toaster.custom({ type: 'custom', children: <p>Any React content</p> });
|
|
|
156
313
|
```
|
|
157
314
|
|
|
158
315
|
Toasts that follow uploads (`withProgressToast` for one request, `createUploadsToast`,
|
|
159
|
-
`withUploadsToast` and `runUploadsInToast` for several) come out of `createToaster` too, and are described in
|
|
160
|
-
`runUploadsInToast` shows one toast for the uploads of several fields: the overall progress on the
|
|
161
|
-
left and a row (waiting, uploading, done or failed) for each field that has files.
|
|
316
|
+
`withUploadsToast` and `runUploadsInToast` for several) come out of `createToaster` too, and are described in the [stores README](../stores/README.md#createtoasterstore). The toast draws what they show: the overall progress on the left and a row (waiting, uploading, done or failed) for each upload.
|
|
162
317
|
|
|
163
|
-
**The store has to be one.** The container and `createToaster` must be given the same store: a toast added to a store that no container draws is never shown. Make it once (a module of the app, imported from there) and the two cannot differ.
|
|
318
|
+
**The store has to be one.** The container and `createToaster` must be given the same store: a toast added to a store that no container draws is never shown. Make it once (a module of the app, imported from there) and the two cannot differ. The compiler checks it: the container takes a store of this package's `TToast`, and `createToaster` takes its types from the store it is given.
|
|
164
319
|
|
|
165
320
|
The icons of the toasts are bundled, so a toast shows its icon without a network.
|
|
166
321
|
|
|
167
322
|
## Rules for the code of this package
|
|
168
323
|
|
|
169
|
-
- **The package holds no state.** The toast store is made by the app (`createToastStore` of `@beautinique/frontend-stores`, with this package's `TToast`) and given in, to the `ToastContainer` as a prop
|
|
170
|
-
- **The root has what most screens use** (`/ui`,
|
|
171
|
-
screens use gets a path of its own and is not in the root.
|
|
324
|
+
- **The package holds no state.** The toast store is made by the app (`createToastStore` of `@beautinique/frontend-stores`, with this package's `TToast`) and given in, to the `ToastContainer` as a prop. The toaster is the stores package's too (`createToaster`). Nothing here makes a store or a toaster, or exports one, so the package can never be the cause of two stores. The root only re-exports `/ui`, `/layout`, `/theme` and `/toast` (`tsup.config.ts` keeps them external, and `built-files.test.ts` checks the built files after `npm run build`).
|
|
325
|
+
- **The root has what most screens use** (`/ui`, `/layout`, `/theme` and `/toast`). A component that
|
|
326
|
+
few screens use gets a path of its own and is not in the root.
|
|
327
|
+
- **Icons are Iconify icons, bundled and registered.** A component draws its icons with Iconify's
|
|
328
|
+
`Icon`, and the icon data is in the package (`toast-icons.ts`, `stepper-icons.ts`,
|
|
329
|
+
`theme-icons.ts`, registered with `addCollection`), so they show without a network and without
|
|
330
|
+
waiting for the Iconify API. A component registers its own icons when it renders (not when its file
|
|
331
|
+
is imported), so an app only carries the icons of the components it uses. Iconify draws icons in the
|
|
332
|
+
browser only: on a server a placeholder is in their place (fine for the Vite apps).
|
|
333
|
+
- **Components are accessible by default**: real elements (`button`, `ol`, `hr`), names for what has no
|
|
334
|
+
text, a focus ring for the keyboard (`focus-visible`), `prefers-reduced-motion` and forced-colors
|
|
335
|
+
mode taken care of, and nothing that moves or announces every second.
|
|
172
336
|
- **A component's own css lives next to the component** and is imported by it, not by the styles
|
|
173
337
|
package. It uses the variables of the styles package (`var(--smoke-eerie)`, ...) and does not
|
|
174
338
|
import them again: importing them a second time, after the app's own css, would undo the app's
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ComponentProps, ComponentPropsWithRef, ElementType, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* What the link to a page needs, as the component that makes the link asks for it: `{ to: '/terms' }`
|
|
4
|
+
* for the `Link` of a router, `{ href: '/terms' }` for a plain `<a>` (which has to have one).
|
|
5
|
+
*/
|
|
6
|
+
export type TAuthLinkProps<TAs extends ElementType> = Omit<ComponentPropsWithRef<TAs>, 'children' | 'className' | 'text' | 'type'> & (TAs extends 'a' ? {
|
|
7
|
+
href: string;
|
|
8
|
+
} : unknown);
|
|
9
|
+
/** The two links of the sentence, ready to be put in it. */
|
|
10
|
+
export interface IAuthLinks {
|
|
11
|
+
terms: ReactNode;
|
|
12
|
+
privacy: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
interface IAuthBottomInstructionsOwnProps<TAs extends ElementType> {
|
|
15
|
+
/**
|
|
16
|
+
* What makes the links: `'a'`, or the `Link` of the router of the app. The router is the app's,
|
|
17
|
+
* not this package's.
|
|
18
|
+
* @default 'a'
|
|
19
|
+
*/
|
|
20
|
+
as?: TAs;
|
|
21
|
+
/** The link to the terms and conditions, in the props of `as`. */
|
|
22
|
+
terms: TAuthLinkProps<TAs>;
|
|
23
|
+
/** The link to the privacy policy, in the props of `as`. */
|
|
24
|
+
privacy: TAuthLinkProps<TAs>;
|
|
25
|
+
/** @default 'Terms & Conditions' */
|
|
26
|
+
termsLabel?: string;
|
|
27
|
+
/** @default 'Privacy Policy' */
|
|
28
|
+
privacyLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* The sentence around the two links, for another wording or another language.
|
|
31
|
+
* @default ({ terms, privacy }) => <>By continuing, you agree to our {terms} and {privacy}.</>
|
|
32
|
+
*/
|
|
33
|
+
message?: (links: IAuthLinks) => ReactNode;
|
|
34
|
+
}
|
|
35
|
+
export type IAuthBottomInstructions<TAs extends ElementType = 'a'> = IAuthBottomInstructionsOwnProps<TAs> & Omit<ComponentProps<'p'>, 'children'>;
|
|
36
|
+
/**
|
|
37
|
+
* The small print under a sign-in or sign-up form: that going on means accepting the terms and the
|
|
38
|
+
* privacy policy, with a link to each.
|
|
39
|
+
*/
|
|
40
|
+
export declare const AuthBottomInstructions: <TAs extends ElementType = "a">({ as, terms, privacy, termsLabel, privacyLabel, message, className, ...pProps }: IAuthBottomInstructions<TAs>) => import("react").JSX.Element;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=AuthBottomInstructions.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthBottomInstructions.d.cts","sourceRoot":"","sources":["../../src/auth/AuthBottomInstructions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3F;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,WAAW,IAAI,IAAI,CACxD,qBAAqB,CAAC,GAAG,CAAC,EAC1B,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,CAC3C,GACC,CAAC,GAAG,SAAS,GAAG,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAEjD,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,UAAU,+BAA+B,CAAC,GAAG,SAAS,WAAW;IAC/D;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;IACT,kEAAkE;IAClE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC3B,4DAA4D;IAC5D,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC7B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC;CAC5C;AAED,MAAM,MAAM,uBAAuB,CAAC,GAAG,SAAS,WAAW,GAAG,GAAG,IAC/D,+BAA+B,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;AAU/E;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,GAAG,SAAS,WAAW,GAAG,GAAG,EAAE,iFASnE,uBAAuB,CAAC,GAAG,CAAC,gCA2B9B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ComponentProps, ComponentPropsWithRef, ElementType, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* What the link to a page needs, as the component that makes the link asks for it: `{ to: '/terms' }`
|
|
4
|
+
* for the `Link` of a router, `{ href: '/terms' }` for a plain `<a>` (which has to have one).
|
|
5
|
+
*/
|
|
6
|
+
export type TAuthLinkProps<TAs extends ElementType> = Omit<ComponentPropsWithRef<TAs>, 'children' | 'className' | 'text' | 'type'> & (TAs extends 'a' ? {
|
|
7
|
+
href: string;
|
|
8
|
+
} : unknown);
|
|
9
|
+
/** The two links of the sentence, ready to be put in it. */
|
|
10
|
+
export interface IAuthLinks {
|
|
11
|
+
terms: ReactNode;
|
|
12
|
+
privacy: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
interface IAuthBottomInstructionsOwnProps<TAs extends ElementType> {
|
|
15
|
+
/**
|
|
16
|
+
* What makes the links: `'a'`, or the `Link` of the router of the app. The router is the app's,
|
|
17
|
+
* not this package's.
|
|
18
|
+
* @default 'a'
|
|
19
|
+
*/
|
|
20
|
+
as?: TAs;
|
|
21
|
+
/** The link to the terms and conditions, in the props of `as`. */
|
|
22
|
+
terms: TAuthLinkProps<TAs>;
|
|
23
|
+
/** The link to the privacy policy, in the props of `as`. */
|
|
24
|
+
privacy: TAuthLinkProps<TAs>;
|
|
25
|
+
/** @default 'Terms & Conditions' */
|
|
26
|
+
termsLabel?: string;
|
|
27
|
+
/** @default 'Privacy Policy' */
|
|
28
|
+
privacyLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* The sentence around the two links, for another wording or another language.
|
|
31
|
+
* @default ({ terms, privacy }) => <>By continuing, you agree to our {terms} and {privacy}.</>
|
|
32
|
+
*/
|
|
33
|
+
message?: (links: IAuthLinks) => ReactNode;
|
|
34
|
+
}
|
|
35
|
+
export type IAuthBottomInstructions<TAs extends ElementType = 'a'> = IAuthBottomInstructionsOwnProps<TAs> & Omit<ComponentProps<'p'>, 'children'>;
|
|
36
|
+
/**
|
|
37
|
+
* The small print under a sign-in or sign-up form: that going on means accepting the terms and the
|
|
38
|
+
* privacy policy, with a link to each.
|
|
39
|
+
*/
|
|
40
|
+
export declare const AuthBottomInstructions: <TAs extends ElementType = "a">({ as, terms, privacy, termsLabel, privacyLabel, message, className, ...pProps }: IAuthBottomInstructions<TAs>) => import("react").JSX.Element;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=AuthBottomInstructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthBottomInstructions.d.ts","sourceRoot":"","sources":["../../src/auth/AuthBottomInstructions.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3F;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,WAAW,IAAI,IAAI,CACxD,qBAAqB,CAAC,GAAG,CAAC,EAC1B,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,CAC3C,GACC,CAAC,GAAG,SAAS,GAAG,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC;AAEjD,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,SAAS,CAAC;CACpB;AAED,UAAU,+BAA+B,CAAC,GAAG,SAAS,WAAW;IAC/D;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;IACT,kEAAkE;IAClE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC3B,4DAA4D;IAC5D,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC7B,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC;CAC5C;AAED,MAAM,MAAM,uBAAuB,CAAC,GAAG,SAAS,WAAW,GAAG,GAAG,IAC/D,+BAA+B,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;AAU/E;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,GAAG,SAAS,WAAW,GAAG,GAAG,EAAE,iFASnE,uBAAuB,CAAC,GAAG,CAAC,gCA2B9B,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var BASE_CSS = "text-fill-transparent w-fit";
|
|
8
|
+
var FORCED_COLORS_CSS = "forced-colors:bg-none forced-colors:[-webkit-text-fill-color:currentColor]";
|
|
9
|
+
var GRADIENT_CSS = {
|
|
10
|
+
accent: "bg-accent-duo",
|
|
11
|
+
silver: "bg-silver-duo"
|
|
12
|
+
};
|
|
13
|
+
var GradientText = /* @__PURE__ */ __name(({
|
|
14
|
+
as,
|
|
15
|
+
type,
|
|
16
|
+
text,
|
|
17
|
+
children,
|
|
18
|
+
className = "",
|
|
19
|
+
...rest
|
|
20
|
+
}) => {
|
|
21
|
+
const Component = as ?? "span";
|
|
22
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
23
|
+
Component,
|
|
24
|
+
{
|
|
25
|
+
...rest,
|
|
26
|
+
className: `${BASE_CSS} ${GRADIENT_CSS[type]} ${FORCED_COLORS_CSS} ${className}`,
|
|
27
|
+
children: children ?? text
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
}, "GradientText");
|
|
31
|
+
var defaultMessage = /* @__PURE__ */ __name(({ terms, privacy }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
32
|
+
"By continuing, you agree to our ",
|
|
33
|
+
terms,
|
|
34
|
+
" and ",
|
|
35
|
+
privacy,
|
|
36
|
+
"."
|
|
37
|
+
] }), "defaultMessage");
|
|
38
|
+
var LINK_CSS = "font-medium";
|
|
39
|
+
var AuthBottomInstructions = /* @__PURE__ */ __name(({
|
|
40
|
+
as,
|
|
41
|
+
terms,
|
|
42
|
+
privacy,
|
|
43
|
+
termsLabel = "Terms & Conditions",
|
|
44
|
+
privacyLabel = "Privacy Policy",
|
|
45
|
+
message = defaultMessage,
|
|
46
|
+
className = "",
|
|
47
|
+
...pProps
|
|
48
|
+
}) => {
|
|
49
|
+
const Link = as ?? "a";
|
|
50
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { ...pProps, className: `text-tertiary text-xs ${className}`, children: message({
|
|
51
|
+
terms: /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
|
+
GradientText,
|
|
53
|
+
{
|
|
54
|
+
...terms,
|
|
55
|
+
as: Link,
|
|
56
|
+
type: "accent",
|
|
57
|
+
text: termsLabel,
|
|
58
|
+
className: LINK_CSS
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
privacy: /* @__PURE__ */ jsxRuntime.jsx(
|
|
62
|
+
GradientText,
|
|
63
|
+
{
|
|
64
|
+
...privacy,
|
|
65
|
+
as: Link,
|
|
66
|
+
type: "accent",
|
|
67
|
+
text: privacyLabel,
|
|
68
|
+
className: LINK_CSS
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
}) });
|
|
72
|
+
}, "AuthBottomInstructions");
|
|
73
|
+
|
|
74
|
+
exports.AuthBottomInstructions = AuthBottomInstructions;
|
|
75
|
+
//# sourceMappingURL=index.cjs.map
|
|
76
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/ui/GradientText.tsx","../../src/auth/AuthBottomInstructions.tsx"],"names":["jsx","jsxs","Fragment"],"mappings":";;;;;;AAwBA,IAAM,QAAA,GAAW,6BAAA;AAGjB,IAAM,iBAAA,GACJ,4EAAA;AAEF,IAAM,YAAA,GAAkD;AAAA,EACtD,MAAA,EAAQ,eAAA;AAAA,EACR,MAAA,EAAQ;AACV,CAAA;AAOO,IAAM,+BAAe,MAAA,CAAA,CAAmC;AAAA,EAC7D,EAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAA0B;AACxB,EAAA,MAAM,YAAyB,EAAA,IAAM,MAAA;AAErC,EAAA,uBACEA,cAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,SAAA,EAAW,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,YAAA,CAAa,IAAI,CAAC,CAAA,CAAA,EAAI,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,MAE7E,QAAA,EAAA,QAAA,IAAY;AAAA;AAAA,GACf;AAEJ,CAAA,EAlB4B,cAAA,CAAA;ACK5B,IAAM,iCAAiB,MAAA,CAAA,CAAC,EAAE,KAAA,EAAO,OAAA,uBAC/BC,eAAA,CAAAC,mBAAA,EAAA,EAAE,QAAA,EAAA;AAAA,EAAA,kCAAA;AAAA,EACiC,KAAA;AAAA,EAAM,OAAA;AAAA,EAAM,OAAA;AAAA,EAAQ;AAAA,CAAA,EACvD,CAAA,EAHqB,gBAAA,CAAA;AAMvB,IAAM,QAAA,GAAW,aAAA;AAMV,IAAM,yCAAyB,MAAA,CAAA,CAAgC;AAAA,EACpE,EAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA,GAAa,oBAAA;AAAA,EACb,YAAA,GAAe,gBAAA;AAAA,EACf,OAAA,GAAU,cAAA;AAAA,EACV,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAAoC;AAClC,EAAA,MAAM,OAAoB,EAAA,IAAM,GAAA;AAEhC,EAAA,uBACEF,eAAC,GAAA,EAAA,EAAG,GAAG,QAAQ,SAAA,EAAW,CAAA,sBAAA,EAAyB,SAAS,CAAA,CAAA,EACzD,QAAA,EAAA,OAAA,CAAQ;AAAA,IACP,uBACEA,cAAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACE,GAAI,KAAA;AAAA,QACL,EAAA,EAAI,IAAA;AAAA,QACJ,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAM,UAAA;AAAA,QACN,SAAA,EAAW;AAAA;AAAA,KACb;AAAA,IAEF,yBACEA,cAAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACE,GAAI,OAAA;AAAA,QACL,EAAA,EAAI,IAAA;AAAA,QACJ,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAM,YAAA;AAAA,QACN,SAAA,EAAW;AAAA;AAAA;AACb,GAEH,CAAA,EACH,CAAA;AAEJ,CAAA,EApCsC,wBAAA","file":"index.cjs","sourcesContent":["import type { ComponentPropsWithRef, ElementType, ReactNode } from 'react';\n\n/** `accent`: the blue gradient of the brand. `silver`: the quiet grey one. */\nexport type TGradientTextType = 'accent' | 'silver';\n\n/** The text is given as `text`, or as `children` (anything React can show), not both. */\ntype TGradientTextContent =\n { text: string; children?: never } | { children: ReactNode; text?: never };\n\ninterface IGradientTextOwnProps<TAs extends ElementType> {\n /**\n * What renders the text: an element (`'a'`, `'p'`, ...) or a component, e.g. the `Link` of the\n * router, which then gets its own props (`to`) next to these.\n * @default 'span'\n */\n as?: TAs;\n type: TGradientTextType;\n className?: string;\n}\n\nexport type IGradientText<TAs extends ElementType = 'span'> = IGradientTextOwnProps<TAs> &\n TGradientTextContent &\n Omit<ComponentPropsWithRef<TAs>, 'as' | 'type' | 'className' | 'text' | 'children'>;\n\nconst BASE_CSS = 'text-fill-transparent w-fit';\n// In forced-colors mode (Windows high contrast) the browser draws no background, so a text that is\n// only a transparent fill over a gradient would vanish: there it takes the colour of the system.\nconst FORCED_COLORS_CSS =\n 'forced-colors:bg-none forced-colors:[-webkit-text-fill-color:currentColor]';\n\nconst GRADIENT_CSS: Record<TGradientTextType, string> = {\n accent: 'bg-accent-duo',\n silver: 'bg-silver-duo',\n};\n\n/**\n * Text filled with a gradient. A link is a text that is rendered by a link component:\n * `<GradientText as={Link} to=\"/terms\" type=\"accent\" text=\"Terms\" />`; the router is the app's, not\n * this package's.\n */\nexport const GradientText = <TAs extends ElementType = 'span'>({\n as,\n type,\n text,\n children,\n className = '',\n ...rest\n}: IGradientText<TAs>) => {\n const Component: ElementType = as ?? 'span';\n\n return (\n <Component\n {...rest}\n className={`${BASE_CSS} ${GRADIENT_CSS[type]} ${FORCED_COLORS_CSS} ${className}`}\n >\n {children ?? text}\n </Component>\n );\n};\n","import type { ComponentProps, ComponentPropsWithRef, ElementType, ReactNode } from 'react';\n\nimport { GradientText } from '../ui/GradientText.js';\n\n/**\n * What the link to a page needs, as the component that makes the link asks for it: `{ to: '/terms' }`\n * for the `Link` of a router, `{ href: '/terms' }` for a plain `<a>` (which has to have one).\n */\nexport type TAuthLinkProps<TAs extends ElementType> = Omit<\n ComponentPropsWithRef<TAs>,\n 'children' | 'className' | 'text' | 'type'\n> &\n (TAs extends 'a' ? { href: string } : unknown);\n\n/** The two links of the sentence, ready to be put in it. */\nexport interface IAuthLinks {\n terms: ReactNode;\n privacy: ReactNode;\n}\n\ninterface IAuthBottomInstructionsOwnProps<TAs extends ElementType> {\n /**\n * What makes the links: `'a'`, or the `Link` of the router of the app. The router is the app's,\n * not this package's.\n * @default 'a'\n */\n as?: TAs;\n /** The link to the terms and conditions, in the props of `as`. */\n terms: TAuthLinkProps<TAs>;\n /** The link to the privacy policy, in the props of `as`. */\n privacy: TAuthLinkProps<TAs>;\n /** @default 'Terms & Conditions' */\n termsLabel?: string;\n /** @default 'Privacy Policy' */\n privacyLabel?: string;\n /**\n * The sentence around the two links, for another wording or another language.\n * @default ({ terms, privacy }) => <>By continuing, you agree to our {terms} and {privacy}.</>\n */\n message?: (links: IAuthLinks) => ReactNode;\n}\n\nexport type IAuthBottomInstructions<TAs extends ElementType = 'a'> =\n IAuthBottomInstructionsOwnProps<TAs> & Omit<ComponentProps<'p'>, 'children'>;\n\nconst defaultMessage = ({ terms, privacy }: IAuthLinks) => (\n <>\n By continuing, you agree to our {terms} and {privacy}.\n </>\n);\n\nconst LINK_CSS = 'font-medium';\n\n/**\n * The small print under a sign-in or sign-up form: that going on means accepting the terms and the\n * privacy policy, with a link to each.\n */\nexport const AuthBottomInstructions = <TAs extends ElementType = 'a'>({\n as,\n terms,\n privacy,\n termsLabel = 'Terms & Conditions',\n privacyLabel = 'Privacy Policy',\n message = defaultMessage,\n className = '',\n ...pProps\n}: IAuthBottomInstructions<TAs>) => {\n const Link: ElementType = as ?? 'a';\n\n return (\n <p {...pProps} className={`text-tertiary text-xs ${className}`}>\n {message({\n terms: (\n <GradientText\n {...(terms as object)}\n as={Link}\n type=\"accent\"\n text={termsLabel}\n className={LINK_CSS}\n />\n ),\n privacy: (\n <GradientText\n {...(privacy as object)}\n as={Link}\n type=\"accent\"\n text={privacyLabel}\n className={LINK_CSS}\n />\n ),\n })}\n </p>\n );\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
5
|
+
var BASE_CSS = "text-fill-transparent w-fit";
|
|
6
|
+
var FORCED_COLORS_CSS = "forced-colors:bg-none forced-colors:[-webkit-text-fill-color:currentColor]";
|
|
7
|
+
var GRADIENT_CSS = {
|
|
8
|
+
accent: "bg-accent-duo",
|
|
9
|
+
silver: "bg-silver-duo"
|
|
10
|
+
};
|
|
11
|
+
var GradientText = /* @__PURE__ */ __name(({
|
|
12
|
+
as,
|
|
13
|
+
type,
|
|
14
|
+
text,
|
|
15
|
+
children,
|
|
16
|
+
className = "",
|
|
17
|
+
...rest
|
|
18
|
+
}) => {
|
|
19
|
+
const Component = as ?? "span";
|
|
20
|
+
return /* @__PURE__ */ jsx(
|
|
21
|
+
Component,
|
|
22
|
+
{
|
|
23
|
+
...rest,
|
|
24
|
+
className: `${BASE_CSS} ${GRADIENT_CSS[type]} ${FORCED_COLORS_CSS} ${className}`,
|
|
25
|
+
children: children ?? text
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}, "GradientText");
|
|
29
|
+
var defaultMessage = /* @__PURE__ */ __name(({ terms, privacy }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
|
+
"By continuing, you agree to our ",
|
|
31
|
+
terms,
|
|
32
|
+
" and ",
|
|
33
|
+
privacy,
|
|
34
|
+
"."
|
|
35
|
+
] }), "defaultMessage");
|
|
36
|
+
var LINK_CSS = "font-medium";
|
|
37
|
+
var AuthBottomInstructions = /* @__PURE__ */ __name(({
|
|
38
|
+
as,
|
|
39
|
+
terms,
|
|
40
|
+
privacy,
|
|
41
|
+
termsLabel = "Terms & Conditions",
|
|
42
|
+
privacyLabel = "Privacy Policy",
|
|
43
|
+
message = defaultMessage,
|
|
44
|
+
className = "",
|
|
45
|
+
...pProps
|
|
46
|
+
}) => {
|
|
47
|
+
const Link = as ?? "a";
|
|
48
|
+
return /* @__PURE__ */ jsx("p", { ...pProps, className: `text-tertiary text-xs ${className}`, children: message({
|
|
49
|
+
terms: /* @__PURE__ */ jsx(
|
|
50
|
+
GradientText,
|
|
51
|
+
{
|
|
52
|
+
...terms,
|
|
53
|
+
as: Link,
|
|
54
|
+
type: "accent",
|
|
55
|
+
text: termsLabel,
|
|
56
|
+
className: LINK_CSS
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
privacy: /* @__PURE__ */ jsx(
|
|
60
|
+
GradientText,
|
|
61
|
+
{
|
|
62
|
+
...privacy,
|
|
63
|
+
as: Link,
|
|
64
|
+
type: "accent",
|
|
65
|
+
text: privacyLabel,
|
|
66
|
+
className: LINK_CSS
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
}) });
|
|
70
|
+
}, "AuthBottomInstructions");
|
|
71
|
+
|
|
72
|
+
export { AuthBottomInstructions };
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/ui/GradientText.tsx","../../src/auth/AuthBottomInstructions.tsx"],"names":["jsx"],"mappings":";;;;AAwBA,IAAM,QAAA,GAAW,6BAAA;AAGjB,IAAM,iBAAA,GACJ,4EAAA;AAEF,IAAM,YAAA,GAAkD;AAAA,EACtD,MAAA,EAAQ,eAAA;AAAA,EACR,MAAA,EAAQ;AACV,CAAA;AAOO,IAAM,+BAAe,MAAA,CAAA,CAAmC;AAAA,EAC7D,EAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAA0B;AACxB,EAAA,MAAM,YAAyB,EAAA,IAAM,MAAA;AAErC,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,SAAA,EAAW,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,YAAA,CAAa,IAAI,CAAC,CAAA,CAAA,EAAI,iBAAiB,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,MAE7E,QAAA,EAAA,QAAA,IAAY;AAAA;AAAA,GACf;AAEJ,CAAA,EAlB4B,cAAA,CAAA;ACK5B,IAAM,iCAAiB,MAAA,CAAA,CAAC,EAAE,KAAA,EAAO,OAAA,uBAC/B,IAAA,CAAA,QAAA,EAAA,EAAE,QAAA,EAAA;AAAA,EAAA,kCAAA;AAAA,EACiC,KAAA;AAAA,EAAM,OAAA;AAAA,EAAM,OAAA;AAAA,EAAQ;AAAA,CAAA,EACvD,CAAA,EAHqB,gBAAA,CAAA;AAMvB,IAAM,QAAA,GAAW,aAAA;AAMV,IAAM,yCAAyB,MAAA,CAAA,CAAgC;AAAA,EACpE,EAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,UAAA,GAAa,oBAAA;AAAA,EACb,YAAA,GAAe,gBAAA;AAAA,EACf,OAAA,GAAU,cAAA;AAAA,EACV,SAAA,GAAY,EAAA;AAAA,EACZ,GAAG;AACL,CAAA,KAAoC;AAClC,EAAA,MAAM,OAAoB,EAAA,IAAM,GAAA;AAEhC,EAAA,uBACEA,IAAC,GAAA,EAAA,EAAG,GAAG,QAAQ,SAAA,EAAW,CAAA,sBAAA,EAAyB,SAAS,CAAA,CAAA,EACzD,QAAA,EAAA,OAAA,CAAQ;AAAA,IACP,uBACEA,GAAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACE,GAAI,KAAA;AAAA,QACL,EAAA,EAAI,IAAA;AAAA,QACJ,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAM,UAAA;AAAA,QACN,SAAA,EAAW;AAAA;AAAA,KACb;AAAA,IAEF,yBACEA,GAAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACE,GAAI,OAAA;AAAA,QACL,EAAA,EAAI,IAAA;AAAA,QACJ,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAM,YAAA;AAAA,QACN,SAAA,EAAW;AAAA;AAAA;AACb,GAEH,CAAA,EACH,CAAA;AAEJ,CAAA,EApCsC,wBAAA","file":"index.js","sourcesContent":["import type { ComponentPropsWithRef, ElementType, ReactNode } from 'react';\n\n/** `accent`: the blue gradient of the brand. `silver`: the quiet grey one. */\nexport type TGradientTextType = 'accent' | 'silver';\n\n/** The text is given as `text`, or as `children` (anything React can show), not both. */\ntype TGradientTextContent =\n { text: string; children?: never } | { children: ReactNode; text?: never };\n\ninterface IGradientTextOwnProps<TAs extends ElementType> {\n /**\n * What renders the text: an element (`'a'`, `'p'`, ...) or a component, e.g. the `Link` of the\n * router, which then gets its own props (`to`) next to these.\n * @default 'span'\n */\n as?: TAs;\n type: TGradientTextType;\n className?: string;\n}\n\nexport type IGradientText<TAs extends ElementType = 'span'> = IGradientTextOwnProps<TAs> &\n TGradientTextContent &\n Omit<ComponentPropsWithRef<TAs>, 'as' | 'type' | 'className' | 'text' | 'children'>;\n\nconst BASE_CSS = 'text-fill-transparent w-fit';\n// In forced-colors mode (Windows high contrast) the browser draws no background, so a text that is\n// only a transparent fill over a gradient would vanish: there it takes the colour of the system.\nconst FORCED_COLORS_CSS =\n 'forced-colors:bg-none forced-colors:[-webkit-text-fill-color:currentColor]';\n\nconst GRADIENT_CSS: Record<TGradientTextType, string> = {\n accent: 'bg-accent-duo',\n silver: 'bg-silver-duo',\n};\n\n/**\n * Text filled with a gradient. A link is a text that is rendered by a link component:\n * `<GradientText as={Link} to=\"/terms\" type=\"accent\" text=\"Terms\" />`; the router is the app's, not\n * this package's.\n */\nexport const GradientText = <TAs extends ElementType = 'span'>({\n as,\n type,\n text,\n children,\n className = '',\n ...rest\n}: IGradientText<TAs>) => {\n const Component: ElementType = as ?? 'span';\n\n return (\n <Component\n {...rest}\n className={`${BASE_CSS} ${GRADIENT_CSS[type]} ${FORCED_COLORS_CSS} ${className}`}\n >\n {children ?? text}\n </Component>\n );\n};\n","import type { ComponentProps, ComponentPropsWithRef, ElementType, ReactNode } from 'react';\n\nimport { GradientText } from '../ui/GradientText.js';\n\n/**\n * What the link to a page needs, as the component that makes the link asks for it: `{ to: '/terms' }`\n * for the `Link` of a router, `{ href: '/terms' }` for a plain `<a>` (which has to have one).\n */\nexport type TAuthLinkProps<TAs extends ElementType> = Omit<\n ComponentPropsWithRef<TAs>,\n 'children' | 'className' | 'text' | 'type'\n> &\n (TAs extends 'a' ? { href: string } : unknown);\n\n/** The two links of the sentence, ready to be put in it. */\nexport interface IAuthLinks {\n terms: ReactNode;\n privacy: ReactNode;\n}\n\ninterface IAuthBottomInstructionsOwnProps<TAs extends ElementType> {\n /**\n * What makes the links: `'a'`, or the `Link` of the router of the app. The router is the app's,\n * not this package's.\n * @default 'a'\n */\n as?: TAs;\n /** The link to the terms and conditions, in the props of `as`. */\n terms: TAuthLinkProps<TAs>;\n /** The link to the privacy policy, in the props of `as`. */\n privacy: TAuthLinkProps<TAs>;\n /** @default 'Terms & Conditions' */\n termsLabel?: string;\n /** @default 'Privacy Policy' */\n privacyLabel?: string;\n /**\n * The sentence around the two links, for another wording or another language.\n * @default ({ terms, privacy }) => <>By continuing, you agree to our {terms} and {privacy}.</>\n */\n message?: (links: IAuthLinks) => ReactNode;\n}\n\nexport type IAuthBottomInstructions<TAs extends ElementType = 'a'> =\n IAuthBottomInstructionsOwnProps<TAs> & Omit<ComponentProps<'p'>, 'children'>;\n\nconst defaultMessage = ({ terms, privacy }: IAuthLinks) => (\n <>\n By continuing, you agree to our {terms} and {privacy}.\n </>\n);\n\nconst LINK_CSS = 'font-medium';\n\n/**\n * The small print under a sign-in or sign-up form: that going on means accepting the terms and the\n * privacy policy, with a link to each.\n */\nexport const AuthBottomInstructions = <TAs extends ElementType = 'a'>({\n as,\n terms,\n privacy,\n termsLabel = 'Terms & Conditions',\n privacyLabel = 'Privacy Policy',\n message = defaultMessage,\n className = '',\n ...pProps\n}: IAuthBottomInstructions<TAs>) => {\n const Link: ElementType = as ?? 'a';\n\n return (\n <p {...pProps} className={`text-tertiary text-xs ${className}`}>\n {message({\n terms: (\n <GradientText\n {...(terms as object)}\n as={Link}\n type=\"accent\"\n text={termsLabel}\n className={LINK_CSS}\n />\n ),\n privacy: (\n <GradientText\n {...(privacy as object)}\n as={Link}\n type=\"accent\"\n text={privacyLabel}\n className={LINK_CSS}\n />\n ),\n })}\n </p>\n );\n};\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var layout = require('@beautinique/frontend-components/layout');
|
|
4
|
+
var theme = require('@beautinique/frontend-components/theme');
|
|
3
5
|
var toast = require('@beautinique/frontend-components/toast');
|
|
4
6
|
var ui = require('@beautinique/frontend-components/ui');
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
|
|
10
|
+
Object.keys(layout).forEach(function (k) {
|
|
11
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return layout[k]; }
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
Object.keys(theme).forEach(function (k) {
|
|
17
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return theme[k]; }
|
|
20
|
+
});
|
|
21
|
+
});
|
|
8
22
|
Object.keys(toast).forEach(function (k) {
|
|
9
23
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
10
24
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,mBAAmB,sBAAsB,CAAC;AAC1C,cAAc,eAAe,CAAC"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,mBAAmB,sBAAsB,CAAC;AAC1C,cAAc,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface IScrollToTop {
|
|
2
|
+
/**
|
|
3
|
+
* The current path of the page, from the router (`useLocation().pathname`). The scroll happens
|
|
4
|
+
* when it changes. The query and the hash are not part of it: a search that only changes `?page=2`
|
|
5
|
+
* does not throw people back to the top.
|
|
6
|
+
*/
|
|
7
|
+
pathname: string;
|
|
8
|
+
/**
|
|
9
|
+
* The `id` of the element that scrolls: the one that holds the page. Nothing happens when the page
|
|
10
|
+
* has no element with this id.
|
|
11
|
+
* @default 'main'
|
|
12
|
+
*/
|
|
13
|
+
id?: string;
|
|
14
|
+
/**
|
|
15
|
+
* `'smooth'` is turned into `'auto'` for a person who asked their system for less motion.
|
|
16
|
+
* @default 'auto'
|
|
17
|
+
*/
|
|
18
|
+
behavior?: ScrollBehavior;
|
|
19
|
+
/** @default 'start' */
|
|
20
|
+
block?: ScrollLogicalPosition;
|
|
21
|
+
/** @default 'nearest' */
|
|
22
|
+
inline?: ScrollLogicalPosition;
|
|
23
|
+
/**
|
|
24
|
+
* Leaves the page where it is when the component first shows, and scrolls only on the changes of
|
|
25
|
+
* `pathname` after that. Needed when the browser puts the page back where it was on a reload.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
skipInitial?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Scrolls an element of the page (`#main` unless told another) to the top each time the path
|
|
32
|
+
* changes, as a router does not do it for a single page app. It draws nothing; put it once, inside
|
|
33
|
+
* the layout that has the element.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ScrollToTop: ({ pathname, id, behavior, block, inline, skipInitial, }: IScrollToTop) => null;
|
|
36
|
+
//# sourceMappingURL=ScrollToTop.d.cts.map
|