@sableui/react 0.1.0 → 0.2.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/{_contract-CYScOdf5.d.ts → _contract-o3tUc8Ig.d.ts} +1 -1
  3. package/dist/{chunk-J23ELQQZ.js → chunk-AOWBYEQ6.js} +4177 -1917
  4. package/dist/{chunk-RWP4XBSK.js → chunk-KFZ43RKU.js} +1 -1
  5. package/dist/{chunk-JI7WJP2L.js → chunk-X276MF2W.js} +5 -0
  6. package/dist/foundations/index.js +1 -1
  7. package/dist/index.d.ts +155 -101
  8. package/dist/index.js +582 -2778
  9. package/dist/ios/index.d.ts +6 -1
  10. package/dist/ios/index.js +4 -4
  11. package/dist/ios/preview.js +1 -1
  12. package/dist/ios/styles.css +20 -6
  13. package/dist/patterns/index.js +1683 -469
  14. package/dist/presets/index.d.ts +1 -1
  15. package/dist/presets/index.js +1 -1
  16. package/dist/styles.css +238 -40
  17. package/dist/{theme-provider-BWcizhAt.d.ts → theme-provider-BE-KqUG-.d.ts} +1 -1
  18. package/dist/themes/atelier/atelier.css +3 -0
  19. package/dist/themes/atelier/index.d.ts +1 -1
  20. package/dist/themes/base/base.css +11 -4
  21. package/dist/themes/base/index.d.ts +1 -1
  22. package/dist/themes/ember/ember.css +3 -0
  23. package/dist/themes/ember/index.d.ts +1 -1
  24. package/dist/themes/index.d.ts +2 -2
  25. package/dist/themes/meridian/index.d.ts +1 -1
  26. package/dist/themes/meridian/meridian.css +10 -5
  27. package/dist/themes/poppy/index.d.ts +1 -1
  28. package/dist/themes/poppy/poppy.css +16 -0
  29. package/dist/themes/prism/index.d.ts +1 -1
  30. package/dist/themes/prism/prism.css +4 -1
  31. package/dist/themes/verdant/index.d.ts +1 -1
  32. package/dist/themes/verdant/verdant.css +7 -2
  33. package/llms/components/bubble.md +5 -5
  34. package/llms/components/checkbox-card.md +1 -1
  35. package/llms/components/context-card.md +2 -2
  36. package/llms/components/dialog.md +1 -1
  37. package/llms/components/empty-state.md +4 -4
  38. package/llms/components/entity.md +1 -1
  39. package/llms/components/fieldset.md +1 -1
  40. package/llms/components/kbd.md +18 -6
  41. package/llms/components/pill.md +1 -1
  42. package/llms/components/side-nav.md +1 -1
  43. package/llms/components/skeleton.md +1 -1
  44. package/llms/components/theme-selector.md +1 -1
  45. package/llms/foundations/shape.md +1 -1
  46. package/llms/patterns/auth-page.md +132 -42
  47. package/llms/patterns/brand-landing-page.md +271 -175
  48. package/llms/patterns/chat-panel.md +120 -39
  49. package/llms/patterns/dashboard-page.md +277 -65
  50. package/llms/patterns/feed-page.md +245 -64
  51. package/llms/patterns/landing-page.md +473 -75
  52. package/llms/patterns/list-detail-page.md +385 -68
  53. package/llms/patterns/settings-page.md +279 -67
  54. package/llms/reference/token-intent.md +4 -2
  55. package/llms/reference/utilities.md +20 -5
  56. package/llms-full.txt +2244 -727
  57. package/llms.txt +14 -15
  58. package/package.json +1 -1
  59. package/registry.json +261 -238
  60. package/targets/ios.json +4 -15
  61. package/llms/components/description.md +0 -96
@@ -1,67 +1,157 @@
1
1
  # AuthPage
2
2
 
3
- Centered auth card: a form-width region vertically centered in the viewport, one Card holding the Form, an alternate-action divider, and a quiet switch-to-sign-up link beneath it.
3
+ Split sign-in page: a form column (brand mark, heading, email + password, primary sign-in, passkey and wallet alternatives, sign-up switch, terms) beside a brand panel painted from the theme's tones with a featured release card. Below lg the panel drops away and the form is the whole screen.
4
4
 
5
5
  **Intent:** Reach for this for sign-in, sign-up, forgot-password, and any single-purpose one-column form route (invite accept, unsubscribe). Not for multi-section forms (use SettingsPage).
6
6
 
7
7
  ## Notes
8
8
 
9
- - Region cap is `form` (480px) — the narrowest named cap; auth never needs more.
10
- - The card is the only surface on the page: no app chrome, no sidebar — minimal exit paths.
11
- - min-h-dvh + grid place-items-center centers the card without magic offsets.
12
- - Field handles label/error wiring; the submit button is full-width — the primary (and only) action.
13
- - Secondary actions (here, switch to sign-up; add forgot password the same way) are quiet `link-underline` links, never competing buttons.
9
+ - The form column is a `form`-capped Region (480px), so the controls keep the same measure whether the panel is present or not.
10
+ - No card around the form: the page itself is the surface, and the brand panel carries the identity. A card on a blank page reads as a template.
11
+ - The heading is `text-heading-1` in an h1 — it is the page outline, so it takes a heading tier, not a card title.
12
+ - Brand mark, form and terms are a three-part column: mark pinned to the top, form vertically centred in the remaining space, terms pinned to the bottom.
13
+ - Forgot password sits under the password field, right-aligned, before the submit button — so it comes right after the field in tab order. Field has no label-row action slot yet.
14
+ - One primary action. Passkey and wallet are outline buttons under an `or` Separator; switching to sign-up is a quiet `link-underline` link.
15
+ - Validation uses Field `validate` for product copy instead of the browser's generic required message. A rejected sign-in comes back through Form `errors` on the password field; the submit Button shows `loading` while the request is in flight.
16
+ - The brand panel artwork is a mesh of the theme's decorative tones over `--primary`, so it re-paints for every theme and mode. The relative-colour `oklch(from var(--tone-*) …)` lift needs an `inline-color` disable with a reason.
17
+ - The panel is `hidden lg:flex`: on a phone the form is the whole screen, with no decorative scroll above it.
14
18
 
15
19
  ## Accessibility
16
20
 
17
- - The route renders inside <main> with the page h1 in the card header (an h1 inside CardTitle, which carries the type).
18
- - Field auto-wires labels, describedby, and invalid state onto the inputs.
19
- - Autocomplete attributes (email, current-password) keep password managers working.
21
+ - The route renders inside <main> with one h1; the brand panel is an <aside> labelled "Featured release".
22
+ - Field auto-wires labels, describedby, and invalid state onto the inputs; on submit, the first invalid field is focused.
23
+ - Autocomplete attributes (`email webauthn`, `current-password`) keep password managers and passkey autofill working.
24
+ - The Forgot password and Create one links use `hit-target` to meet the 44px touch floor without changing layout.
25
+ - The artwork swatches are aria-hidden decoration; the brand link's accessible name is the wordmark.
20
26
 
21
27
  ## Source
22
28
 
23
29
  ```tsx
24
- import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Field, Form, Input, Region, Separator, Stack } from "@sableui/react"
30
+ import { useState } from "react"
31
+ import { Avatar, Badge, Button, Card, CardContent, Entity, Field, Form, Icon, Input, Region, Separator, Stack } from "@sableui/react"
32
+
33
+ // A soft mesh of the theme's decorative tones over its brand colour, so the
34
+ // artwork follows every theme and mode. Each tone is lifted from its text
35
+ // strength (dark, restrained) to an art strength.
36
+ const artwork = [
37
+ // design-lint-disable-next-line inline-color -- relative colour derived from the theme's own --tone token, so it follows every look
38
+ "radial-gradient(in oklab at 18% 22%, oklch(from var(--tone-info) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h), transparent 58%)",
39
+ // design-lint-disable-next-line inline-color -- relative colour derived from the theme's own --tone token, so it follows every look
40
+ "radial-gradient(in oklab at 82% 18%, oklch(from var(--tone-collectible) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h), transparent 55%)",
41
+ // design-lint-disable-next-line inline-color -- relative colour derived from the theme's own --tone token, so it follows every look
42
+ "radial-gradient(in oklab at 70% 88%, oklch(from var(--tone-edition) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h), transparent 60%)",
43
+ // design-lint-disable-next-line inline-color -- relative colour derived from the theme's own --tone token, so it follows every look
44
+ "radial-gradient(in oklab at 12% 92%, oklch(from var(--tone-standard) clamp(0.5, calc(l + 0.16), 0.9) max(calc(c * 1.25), 0.1) h), transparent 55%)",
45
+ "var(--primary)",
46
+ ].join(", ")
25
47
 
26
48
  export function AuthPage() {
49
+ const [pending, setPending] = useState(false)
50
+ const [errors, setErrors] = useState<Record<string, string>>({})
51
+
27
52
  return (
28
- <main className="grid min-h-dvh place-items-center bg-background">
29
- <Region max="form" safeArea={["top", "bottom"]}>
30
- <Stack gap={3}>
31
- <Card>
32
- <CardHeader>
33
- {/* CardTitle carries the type; the h1 inside it is the page heading. */}
34
- <CardTitle>
35
- <h1>Sign in</h1>
36
- </CardTitle>
37
- <CardDescription>Welcome back — pick up where you left off.</CardDescription>
38
- </CardHeader>
39
- <CardContent>
40
- <Form onSubmit={(event) => event.preventDefault()}>
41
- <Field label="Email" required>
42
- <Input type="email" name="email" autoComplete="email" placeholder="you@example.com" />
43
- </Field>
44
- <Field label="Password" required>
45
- <Input type="password" name="password" autoComplete="current-password" />
53
+ <main className="grid min-h-dvh bg-background lg:grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)]">
54
+ <Region max="form" safeArea={["top", "bottom"]} className="flex flex-col">
55
+ {/* safeArea owns the region's own padding, so the breathing room sits one level in. */}
56
+ <Stack gap={0} className="flex-1 py-8 sm:py-10">
57
+ <a href="/" className="flex items-center gap-2.5 self-start rounded-sm motion-interactive motion-press">
58
+ {/* The same mark the app shell's sidebar and header carry. */}
59
+ <Icon name="gem" variant="solid" className="text-2xl" />
60
+ <span className="text-title-lg">Atelier</span>
61
+ </a>
62
+
63
+ <Stack gap={4} justify="center" className="flex-1 py-12">
64
+ <Stack gap={1.5}>
65
+ <h1 className="text-heading-1">Welcome back</h1>
66
+ <p className="text-body-lg text-muted-foreground">
67
+ Sign in to collect new releases and manage your editions.
68
+ </p>
69
+ </Stack>
70
+
71
+ <Form
72
+ className="gap-5"
73
+ errors={errors}
74
+ onFormSubmit={() => {
75
+ setPending(true)
76
+ // Replace with your auth call; a rejected sign-in comes back as a field error.
77
+ setTimeout(() => {
78
+ setPending(false)
79
+ setErrors({ password: "That email and password don’t match. Try again or reset your password." })
80
+ }, 900)
81
+ }}
82
+ >
83
+ <Field label="Email" name="email" validate={(value) => (value ? null : "Enter your email address.")}>
84
+ <Input type="email" autoComplete="email webauthn" placeholder="you@example.com" />
85
+ </Field>
86
+ <Stack gap={1.5}>
87
+ <Field label="Password" name="password" validate={(value) => (value ? null : "Enter your password.")}>
88
+ <Input type="password" autoComplete="current-password" />
46
89
  </Field>
47
- <Button type="submit" className="w-full">
48
- Sign in
49
- </Button>
50
- <Separator label="or" />
51
- <Button variant="outline" className="w-full">
52
- Continue with wallet
53
- </Button>
54
- </Form>
55
- </CardContent>
56
- </Card>
57
- <p className="text-center text-body-sm text-muted-foreground">
58
- No account?{" "}
59
- <a href="/signup" className="link-underline motion-interactive text-foreground">
60
- Create one
90
+ <a href="/forgot-password" className="hit-target self-end text-body-sm text-muted-foreground link-underline motion-interactive">
91
+ Forgot password?
92
+ </a>
93
+ </Stack>
94
+ <Button type="submit" size="cta" loading={pending} loadingLabel="Signing in" className="w-full">
95
+ Sign in
96
+ </Button>
97
+ </Form>
98
+
99
+ <Separator label="or" />
100
+
101
+ <Stack gap={1.5}>
102
+ <Button variant="outline" size="cta" className="w-full">
103
+ Sign in with a passkey
104
+ </Button>
105
+ <Button variant="outline" size="cta" className="w-full">
106
+ Connect a wallet
107
+ </Button>
108
+ </Stack>
109
+
110
+ <p className="text-body-md text-muted-foreground">
111
+ No account?{" "}
112
+ <a href="/signup" className="hit-target link-underline motion-interactive text-foreground">
113
+ Create one
114
+ </a>
115
+ </p>
116
+ </Stack>
117
+
118
+ <p className="text-body-xs text-muted-foreground">
119
+ By signing in you agree to the{" "}
120
+ <a href="/terms" className="link-underline motion-interactive">
121
+ Terms
122
+ </a>{" "}
123
+ and{" "}
124
+ <a href="/privacy" className="link-underline motion-interactive">
125
+ Privacy Policy
61
126
  </a>
127
+ .
62
128
  </p>
63
129
  </Stack>
64
130
  </Region>
131
+
132
+ {/* The brand panel is decoration: on a phone the form is the whole screen. */}
133
+ <aside aria-label="Featured release" className="hidden p-3 lg:flex">
134
+ <div className="flex flex-1 flex-col justify-end rounded-xl p-8" style={{ background: artwork }}>
135
+ <Card className="max-w-md">
136
+ <CardContent>
137
+ <Stack gap={3}>
138
+ <Badge tone="edition" className="self-start">
139
+ Edition of 50
140
+ </Badge>
141
+ <p className="text-title-lg">
142
+ “Every edition is a conversation with whoever holds it next.”
143
+ </p>
144
+ <Entity
145
+ className="p-0"
146
+ leading={<Avatar fallback="MO" />}
147
+ title="Mara Okafor"
148
+ subtitle="Untitled (gold rush), 2026"
149
+ />
150
+ </Stack>
151
+ </CardContent>
152
+ </Card>
153
+ </div>
154
+ </aside>
65
155
  </main>
66
156
  )
67
157
  }