@rtkelly-labs/design-system 0.0.0-bootstrap.0 → 0.16.0-dev.0.37dedac
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 +347 -0
- package/LICENSE +21 -0
- package/README.md +317 -2
- package/dist/components/AlertDialog.js +95 -0
- package/dist/components/AlertDialog.js.map +1 -0
- package/dist/components/AppShell.js +261 -0
- package/dist/components/AppShell.js.map +1 -0
- package/dist/components/AsciiDivider.js +8 -0
- package/dist/components/AsciiDivider.js.map +1 -0
- package/dist/components/AsciiGauge.js +130 -0
- package/dist/components/AsciiGauge.js.map +1 -0
- package/dist/components/Avatar.js +87 -0
- package/dist/components/Avatar.js.map +1 -0
- package/dist/components/Badge.js +25 -0
- package/dist/components/Badge.js.map +1 -0
- package/dist/components/BarChart.js +288 -0
- package/dist/components/BarChart.js.map +1 -0
- package/dist/components/BracketText.js +23 -0
- package/dist/components/BracketText.js.map +1 -0
- package/dist/components/BulletChart.js +50 -0
- package/dist/components/BulletChart.js.map +1 -0
- package/dist/components/Button.js +130 -0
- package/dist/components/Button.js.map +1 -0
- package/dist/components/Card.js +181 -0
- package/dist/components/Card.js.map +1 -0
- package/dist/components/ChartTooltip.js +54 -0
- package/dist/components/ChartTooltip.js.map +1 -0
- package/dist/components/Checkbox.js +55 -0
- package/dist/components/Checkbox.js.map +1 -0
- package/dist/components/ColophonCard.js +122 -0
- package/dist/components/ColophonCard.js.map +1 -0
- package/dist/components/DataTable.js +299 -0
- package/dist/components/DataTable.js.map +1 -0
- package/dist/components/Divider.js +42 -0
- package/dist/components/Divider.js.map +1 -0
- package/dist/components/Drawer.js +81 -0
- package/dist/components/Drawer.js.map +1 -0
- package/dist/components/EmptyState.js +39 -0
- package/dist/components/EmptyState.js.map +1 -0
- package/dist/components/ErrorSummary.js +122 -0
- package/dist/components/ErrorSummary.js.map +1 -0
- package/dist/components/Fieldset.js +37 -0
- package/dist/components/Fieldset.js.map +1 -0
- package/dist/components/Glyph.js +60 -0
- package/dist/components/Glyph.js.map +1 -0
- package/dist/components/Input.js +111 -0
- package/dist/components/Input.js.map +1 -0
- package/dist/components/LinkProvider.js +76 -0
- package/dist/components/LinkProvider.js.map +1 -0
- package/dist/components/Menu.js +144 -0
- package/dist/components/Menu.js.map +1 -0
- package/dist/components/MetadataGrid.js +184 -0
- package/dist/components/MetadataGrid.js.map +1 -0
- package/dist/components/MobileNav.js +120 -0
- package/dist/components/MobileNav.js.map +1 -0
- package/dist/components/Modal.js +79 -0
- package/dist/components/Modal.js.map +1 -0
- package/dist/components/NerdIcon.js +177 -0
- package/dist/components/NerdIcon.js.map +1 -0
- package/dist/components/NoteBlock.js +84 -0
- package/dist/components/NoteBlock.js.map +1 -0
- package/dist/components/PageHeader.js +34 -0
- package/dist/components/PageHeader.js.map +1 -0
- package/dist/components/PageTitle.js +21 -0
- package/dist/components/PageTitle.js.map +1 -0
- package/dist/components/Pagination.js +96 -0
- package/dist/components/Pagination.js.map +1 -0
- package/dist/components/Popover.js +87 -0
- package/dist/components/Popover.js.map +1 -0
- package/dist/components/Progress.js +83 -0
- package/dist/components/Progress.js.map +1 -0
- package/dist/components/RadioGroup.js +74 -0
- package/dist/components/RadioGroup.js.map +1 -0
- package/dist/components/ReportDocument.js +75 -0
- package/dist/components/ReportDocument.js.map +1 -0
- package/dist/components/SectionContainer.js +18 -0
- package/dist/components/SectionContainer.js.map +1 -0
- package/dist/components/Select.js +199 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/SiteFooter.js +29 -0
- package/dist/components/SiteFooter.js.map +1 -0
- package/dist/components/SiteHeader.js +59 -0
- package/dist/components/SiteHeader.js.map +1 -0
- package/dist/components/SiteNav.js +141 -0
- package/dist/components/SiteNav.js.map +1 -0
- package/dist/components/Skeleton.js +51 -0
- package/dist/components/Skeleton.js.map +1 -0
- package/dist/components/SocialIcon.js +77 -0
- package/dist/components/SocialIcon.js.map +1 -0
- package/dist/components/Sparkline.js +104 -0
- package/dist/components/Sparkline.js.map +1 -0
- package/dist/components/Spinner.js +65 -0
- package/dist/components/Spinner.js.map +1 -0
- package/dist/components/StatCard.js +53 -0
- package/dist/components/StatCard.js.map +1 -0
- package/dist/components/StatusPage.js +99 -0
- package/dist/components/StatusPage.js.map +1 -0
- package/dist/components/Swatch.js +55 -0
- package/dist/components/Swatch.js.map +1 -0
- package/dist/components/Switch.js +53 -0
- package/dist/components/Switch.js.map +1 -0
- package/dist/components/TLDR.js +53 -0
- package/dist/components/TLDR.js.map +1 -0
- package/dist/components/Table.js +155 -0
- package/dist/components/Table.js.map +1 -0
- package/dist/components/Tabs.js +325 -0
- package/dist/components/Tabs.js.map +1 -0
- package/dist/components/Tag.js +19 -0
- package/dist/components/Tag.js.map +1 -0
- package/dist/components/TelemetryGauge.js +112 -0
- package/dist/components/TelemetryGauge.js.map +1 -0
- package/dist/components/ThemeProvider.js +87 -0
- package/dist/components/ThemeProvider.js.map +1 -0
- package/dist/components/TickerTape.js +196 -0
- package/dist/components/TickerTape.js.map +1 -0
- package/dist/components/Toast.js +200 -0
- package/dist/components/Toast.js.map +1 -0
- package/dist/components/Tooltip.js +69 -0
- package/dist/components/Tooltip.js.map +1 -0
- package/dist/components/TrackCard.js +206 -0
- package/dist/components/TrackCard.js.map +1 -0
- package/dist/components/blog/BlogPost.js +116 -0
- package/dist/components/blog/BlogPost.js.map +1 -0
- package/dist/components/blog/LoremIpsumPost.js +62 -0
- package/dist/components/blog/LoremIpsumPost.js.map +1 -0
- package/dist/components/blog/author.js +25 -0
- package/dist/components/blog/author.js.map +1 -0
- package/dist/components/booleanControl.js +50 -0
- package/dist/components/booleanControl.js.map +1 -0
- package/dist/components/dialogPopupRef.js +28 -0
- package/dist/components/dialogPopupRef.js.map +1 -0
- package/dist/components/dialogSurface.js +75 -0
- package/dist/components/dialogSurface.js.map +1 -0
- package/dist/components/docs/AnchorHeading.js +80 -0
- package/dist/components/docs/AnchorHeading.js.map +1 -0
- package/dist/components/docs/Breadcrumbs.js +26 -0
- package/dist/components/docs/Breadcrumbs.js.map +1 -0
- package/dist/components/docs/CodeBlock.js +63 -0
- package/dist/components/docs/CodeBlock.js.map +1 -0
- package/dist/components/docs/CodeTabs.js +71 -0
- package/dist/components/docs/CodeTabs.js.map +1 -0
- package/dist/components/docs/DocPager.js +28 -0
- package/dist/components/docs/DocPager.js.map +1 -0
- package/dist/components/docs/DocsHeader.js +124 -0
- package/dist/components/docs/DocsHeader.js.map +1 -0
- package/dist/components/docs/DocsLayout.js +61 -0
- package/dist/components/docs/DocsLayout.js.map +1 -0
- package/dist/components/docs/DocsLinkProvider.js +25 -0
- package/dist/components/docs/DocsLinkProvider.js.map +1 -0
- package/dist/components/docs/DocsSidebar.js +147 -0
- package/dist/components/docs/DocsSidebar.js.map +1 -0
- package/dist/components/docs/Prose.js +56 -0
- package/dist/components/docs/Prose.js.map +1 -0
- package/dist/components/docs/TableOfContents.js +71 -0
- package/dist/components/docs/TableOfContents.js.map +1 -0
- package/dist/components/docs/codeTabsStore.js +75 -0
- package/dist/components/docs/codeTabsStore.js.map +1 -0
- package/dist/components/docs/figures/ActivityGrid.js +116 -0
- package/dist/components/docs/figures/ActivityGrid.js.map +1 -0
- package/dist/components/docs/figures/BeforeAfter.js +64 -0
- package/dist/components/docs/figures/BeforeAfter.js.map +1 -0
- package/dist/components/docs/figures/ChangeSummary.js +74 -0
- package/dist/components/docs/figures/ChangeSummary.js.map +1 -0
- package/dist/components/docs/figures/Decision.js +34 -0
- package/dist/components/docs/figures/Decision.js.map +1 -0
- package/dist/components/docs/figures/DrawingSheet.js +37 -0
- package/dist/components/docs/figures/DrawingSheet.js.map +1 -0
- package/dist/components/docs/figures/FigureFrame.js +226 -0
- package/dist/components/docs/figures/FigureFrame.js.map +1 -0
- package/dist/components/docs/figures/FileChangeTree.js +134 -0
- package/dist/components/docs/figures/FileChangeTree.js.map +1 -0
- package/dist/components/docs/figures/FlowDiagram.js +82 -0
- package/dist/components/docs/figures/FlowDiagram.js.map +1 -0
- package/dist/components/docs/figures/GanttChart.js +79 -0
- package/dist/components/docs/figures/GanttChart.js.map +1 -0
- package/dist/components/docs/figures/IndexedSection.js +45 -0
- package/dist/components/docs/figures/IndexedSection.js.map +1 -0
- package/dist/components/docs/figures/MetricStrip.js +23 -0
- package/dist/components/docs/figures/MetricStrip.js.map +1 -0
- package/dist/components/docs/figures/Steps.js +58 -0
- package/dist/components/docs/figures/Steps.js.map +1 -0
- package/dist/components/docs/figures/SwatchCompare.js +42 -0
- package/dist/components/docs/figures/SwatchCompare.js.map +1 -0
- package/dist/components/docs/figures/TermGrid.js +22 -0
- package/dist/components/docs/figures/TermGrid.js.map +1 -0
- package/dist/components/docs/figures/Terminal.js +37 -0
- package/dist/components/docs/figures/Terminal.js.map +1 -0
- package/dist/components/docs/figures/Timeline.js +61 -0
- package/dist/components/docs/figures/Timeline.js.map +1 -0
- package/dist/components/docs/figures/TokenTable.js +42 -0
- package/dist/components/docs/figures/TokenTable.js.map +1 -0
- package/dist/components/docs/figures/TreeDiagram.js +76 -0
- package/dist/components/docs/figures/TreeDiagram.js.map +1 -0
- package/dist/components/docs/figures/UptimeStrip.js +68 -0
- package/dist/components/docs/figures/UptimeStrip.js.map +1 -0
- package/dist/components/docs/figures/index.js +24 -0
- package/dist/components/docs/figures/index.js.map +1 -0
- package/dist/components/docs/index.js +15 -0
- package/dist/components/docs/index.js.map +1 -0
- package/dist/components/docs/mdxComponents.js +108 -0
- package/dist/components/docs/mdxComponents.js.map +1 -0
- package/dist/components/experiments/DesignSandbox.js +206 -0
- package/dist/components/experiments/DesignSandbox.js.map +1 -0
- package/dist/components/experiments/ExperimentsView.js +138 -0
- package/dist/components/experiments/ExperimentsView.js.map +1 -0
- package/dist/components/fieldFrame.js +200 -0
- package/dist/components/fieldFrame.js.map +1 -0
- package/dist/components/floatingSurface.js +35 -0
- package/dist/components/floatingSurface.js.map +1 -0
- package/dist/components/marketing/CTASection.js +47 -0
- package/dist/components/marketing/CTASection.js.map +1 -0
- package/dist/components/marketing/FeatureGrid.js +49 -0
- package/dist/components/marketing/FeatureGrid.js.map +1 -0
- package/dist/components/marketing/Hero.js +44 -0
- package/dist/components/marketing/Hero.js.map +1 -0
- package/dist/components/marketing/PricingGrid.js +65 -0
- package/dist/components/marketing/PricingGrid.js.map +1 -0
- package/dist/components/marketing/SectionGrid.js +51 -0
- package/dist/components/marketing/SectionGrid.js.map +1 -0
- package/dist/components/paginationRange.js +28 -0
- package/dist/components/paginationRange.js.map +1 -0
- package/dist/components/portalTheme.js +14 -0
- package/dist/components/portalTheme.js.map +1 -0
- package/dist/components/saas/SaasLandingPage.js +201 -0
- package/dist/components/saas/SaasLandingPage.js.map +1 -0
- package/dist/components/siteNavContext.js +24 -0
- package/dist/components/siteNavContext.js.map +1 -0
- package/dist/components/slides/Slide.js +84 -0
- package/dist/components/slides/Slide.js.map +1 -0
- package/dist/components/slides/SlideDeck.js +228 -0
- package/dist/components/slides/SlideDeck.js.map +1 -0
- package/dist/components/themeInitScript.js +16 -0
- package/dist/components/themeInitScript.js.map +1 -0
- package/dist/components/themeScope.js +9 -0
- package/dist/components/themeScope.js.map +1 -0
- package/dist/components/toastLifetime.js +21 -0
- package/dist/components/toastLifetime.js.map +1 -0
- package/dist/fonts/DSSymbols-OFL.txt +98 -0
- package/dist/fonts/DSSymbols-Regular.woff2 +0 -0
- package/dist/fonts/SymbolsNerdFontMono-Regular.woff2 +0 -0
- package/dist/hooks/useActiveHeading.js +59 -0
- package/dist/hooks/useActiveHeading.js.map +1 -0
- package/dist/hooks/useCopyToClipboard.js +58 -0
- package/dist/hooks/useCopyToClipboard.js.map +1 -0
- package/dist/index.d.ts +6394 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accentClasses.js +87 -0
- package/dist/lib/accentClasses.js.map +1 -0
- package/dist/lib/recipe.js +33 -0
- package/dist/lib/recipe.js.map +1 -0
- package/dist/lib/slug.js +39 -0
- package/dist/lib/slug.js.map +1 -0
- package/dist/lib/theme.js +76 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/tokenRules.js +51 -0
- package/dist/lib/tokenRules.js.map +1 -0
- package/dist/prose.css +766 -0
- package/dist/styles.css +203 -0
- package/dist/theme/ansi.js +77 -0
- package/dist/theme/ansi.js.map +1 -0
- package/dist/theme/contrast.js +342 -0
- package/dist/theme/contrast.js.map +1 -0
- package/dist/theme/levels.js +234 -0
- package/dist/theme/levels.js.map +1 -0
- package/dist/theme/media.js +115 -0
- package/dist/theme/media.js.map +1 -0
- package/dist/theme/recommended.js +105 -0
- package/dist/theme/recommended.js.map +1 -0
- package/dist/theme.css +538 -0
- package/dist/tokens.js +1 -0
- package/dist/tokens.js.map +1 -0
- package/package.json +209 -6
- package/skills/design-system-usage/SKILL.md +75 -0
- package/terminal/rtk-midnight.alacritty.toml +33 -0
- package/terminal/rtk-midnight.ghostty.conf +24 -0
- package/terminal/rtk-midnight.itermcolors +167 -0
- package/terminal/rtk-midnight.windows-terminal.json +23 -0
- package/terminal/rtk-sketch.alacritty.toml +33 -0
- package/terminal/rtk-sketch.ghostty.conf +24 -0
- package/terminal/rtk-sketch.itermcolors +167 -0
- package/terminal/rtk-sketch.windows-terminal.json +23 -0
- package/tokens/palette.midnight.tokens.json +477 -0
- package/tokens/palette.sketch.tokens.json +477 -0
package/README.md
CHANGED
|
@@ -1,3 +1,318 @@
|
|
|
1
|
-
# @rtkelly-labs/design-system
|
|
1
|
+
# 🎨 @rtkelly-labs/design-system
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The foundational visual design system for **ryankelly.dev** and every personal surface that has
|
|
4
|
+
to look like it. Built around a **brutalist / neon-terminal** aesthetic: hard edges, zero
|
|
5
|
+
border-radius, offset shadows, and two themes — `midnight`, neon on blue-black, and `sketch`,
|
|
6
|
+
warm paper and pen ink.
|
|
7
|
+
|
|
8
|
+
## This is a multi-surface system, and that is the foundational decision
|
|
9
|
+
|
|
10
|
+
**A colour originates exactly once**, as a literal in
|
|
11
|
+
[`src/theme/levels.ts`](./src/theme/levels.ts). Every consumable form is *generated* from it
|
|
12
|
+
and verified against it in CI. Nothing else may hold a colour literal — not a website, not a
|
|
13
|
+
video composition, not a graphic generator, not an editor theme.
|
|
14
|
+
|
|
15
|
+
| Surface | Form | State |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| **Websites** | Tailwind v4 tokens via generated `theme.css` | ships today |
|
|
18
|
+
| **Design tokens** | `tokens/palette.<level>.tokens.json`, DTCG 2025.10, OKLCH | ships today |
|
|
19
|
+
| **Developer themes** | VS Code · Zed · Shiki · Neovim · JetBrains, and a terminal's 16 ANSI slots | designed, blocked on a hue vocabulary |
|
|
20
|
+
| **Graphics** | generated diagrams, charts, ASCII-art panels | forked in the consumer — to be reclaimed |
|
|
21
|
+
| **Video** | Remotion frames at 1080p, where a 16px web type scale is wrong | groundwork only |
|
|
22
|
+
|
|
23
|
+
Two decisions carry this, and they are worth reading before changing anything about colour:
|
|
24
|
+
|
|
25
|
+
- [**ADR 0002 — One source of colour decisions, many emitted surfaces**](./docs/adr/0002-one-source-many-emitted-surfaces.md).
|
|
26
|
+
The root decision. Why per-surface palettes, manual ports and a runtime theming service were
|
|
27
|
+
all rejected, and why the source is TypeScript rather than JSON.
|
|
28
|
+
- [**ADR 0003 — Two Levels, each independently authored**](./docs/adr/0003-two-levels-independently-authored.md).
|
|
29
|
+
`midnight` and `sketch`, neither derived from the other. Neither is named for its polarity,
|
|
30
|
+
which is what keeps `Polarity` a real declared property.
|
|
31
|
+
- [**ADR 0001 — Hues are declared below Roles**](./docs/adr/0001-hues-declared-below-roles.md).
|
|
32
|
+
Components address a colour by its **job** (`accent.primary`), never its appearance (`cyan`).
|
|
33
|
+
But a terminal has sixteen positions named by colour and no concept of a keyword — so a hue
|
|
34
|
+
vocabulary is declared *underneath* the role vocabulary. Half the surfaces above cannot exist
|
|
35
|
+
without it.
|
|
36
|
+
|
|
37
|
+
[`docs/theme-taxonomy.md`](./docs/theme-taxonomy.md) is the full matrix: what every Level must
|
|
38
|
+
declare, which target needs which group, what is generated, and which gate covers each.
|
|
39
|
+
|
|
40
|
+
Published to the public **npm registry** as `@rtkelly-labs/design-system` (via npm trusted publishing — see `.github/workflows/publish-package.yml`).
|
|
41
|
+
|
|
42
|
+
**📖 Browse it: [design-system.ryankelly.dev](https://design-system.ryankelly.dev)** — the
|
|
43
|
+
full Storybook, with the blog's own Storybook composed into the sidebar. Unreleased work
|
|
44
|
+
lands at [preview.design-system.ryankelly.dev](https://preview.design-system.ryankelly.dev)
|
|
45
|
+
(the `preview` branch). Domains are declared in `rtkelly13/shared-utilities` at
|
|
46
|
+
[`infra/vercel/`](https://github.com/rtkelly13/shared-utilities/tree/main/infra/vercel);
|
|
47
|
+
see [AGENTS.md](./AGENTS.md#-hosted-storybook).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Documentation figures
|
|
52
|
+
|
|
53
|
+
`FigureFrame` supplies a caption and border. The visual components do not create
|
|
54
|
+
their own frame, so related views can share one. For example:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { FigureFrame, Timeline, UptimeStrip } from '@rtkelly-labs/design-system';
|
|
58
|
+
|
|
59
|
+
<FigureFrame title="SERVICE INCIDENT">
|
|
60
|
+
<Timeline events={[{ date: '14:02', label: 'Latency rose' }, { date: '14:11', label: 'Rolled back' }]} />
|
|
61
|
+
<UptimeStrip days="ok degraded down ok" />
|
|
62
|
+
</FigureFrame>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use `ActivityGrid` for dated counts such as commits or blog posts, and
|
|
66
|
+
`GanttChart` for work with start and end dates. `FlowDiagram`, `TreeDiagram`,
|
|
67
|
+
`ChangeSummary`, and `BeforeAfter` cover relationships and comparisons.
|
|
68
|
+
`SwatchCompare`, `TokenTable`, and `MetricStrip` are measured comparisons, and
|
|
69
|
+
`TermGrid` is a glossary. `Decision` is a standalone documentation block, not a
|
|
70
|
+
figure renderer. `Steps` and `Terminal` remain documentation blocks. See
|
|
71
|
+
[ADR 0006](./docs/adr/0006-document-visual-taxonomy.md) for the naming rules.
|
|
72
|
+
|
|
73
|
+
These components are adapted from [mdxcn](https://github.com/keshav-exe/mdxcn)
|
|
74
|
+
as source code, not imported from an mdxcn npm package. Every adapted component
|
|
75
|
+
links to its upstream source in the file header. See the
|
|
76
|
+
[license and attribution](./docs/attributions/mdxcn.md).
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 📸 Visual Regression Layer
|
|
81
|
+
|
|
82
|
+
Playwright screenshots of Storybook stories, asserted on every PR. The determinism contract and
|
|
83
|
+
operating instructions are in [`docs/visual-regression.md`](./docs/visual-regression.md).
|
|
84
|
+
|
|
85
|
+
- **What is asserted**: three tables in `tests/visual.spec.ts`: `CASES` (desktop), `MOBILE_CASES`
|
|
86
|
+
(narrow viewport) and `INTERACTIONS` (hover, focus and open states). They run against a static
|
|
87
|
+
Storybook build served on `http://localhost:6006`. `pnpm check:visual-coverage` requires every component to
|
|
88
|
+
have an asserted story or a stated reason.
|
|
89
|
+
- **Two projects**: `chromium` (desktop) and `mobile`. Baselines live in `tests/__snapshots__/`,
|
|
90
|
+
named by file rather than story id, so retitling a story does not orphan one.
|
|
91
|
+
- **Tolerance**: `maxDiffPixels: 0` at Playwright's default per-pixel `threshold` of `0.2`. A
|
|
92
|
+
flaky case is a defect to fix, not a threshold to loosen.
|
|
93
|
+
- **Linux only**: baselines are rendered on the CI runner, and font rasterisation differs by OS. On
|
|
94
|
+
macOS or Windows the suite skips every case (`test.skip(process.platform !== 'linux')`), so an
|
|
95
|
+
all-skipped run there has asserted nothing.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Regenerate baselines: comment on the PR (owner/member/collaborator only)
|
|
99
|
+
/update-snapshots # writes only missing baselines (new cases); never overwrites
|
|
100
|
+
/update-snapshots changed # also overwrites baselines that now differ: an intended visual change
|
|
101
|
+
/update-snapshots all # regenerates every baseline
|
|
102
|
+
|
|
103
|
+
# On a Linux machine matching CI:
|
|
104
|
+
pnpm test:visual # assert
|
|
105
|
+
pnpm test:visual:missing # write baselines only for new cases
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The bot's snapshot commit does not trigger CI. Push a fresh commit afterwards so the new baselines
|
|
109
|
+
are asserted.
|
|
110
|
+
|
|
111
|
+
### Capturing this package deterministically
|
|
112
|
+
|
|
113
|
+
If you screenshot, print, or render outside a live browser session, three switches decide whether
|
|
114
|
+
you get the same output twice:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
<ThemeProvider defaultLevel="midnight" scoped> {/* 1. no storage, no matchMedia, no documentElement */}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
await document.fonts.ready; // 2. or you capture the fallback face
|
|
122
|
+
// 3. suppress transitions:
|
|
123
|
+
// *, *::before, *::after { transition: none !important; animation: none !important }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`scoped` is the one that does the work — `persist={false} followSystem={false}` look like the
|
|
127
|
+
determinism controls and are redundant under it. Full reasoning in
|
|
128
|
+
[`docs/deterministic-rendering.md`](./docs/deterministic-rendering.md).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 📦 Installation & Prerelease Testing
|
|
133
|
+
|
|
134
|
+
### Stable Release
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pnpm add @rtkelly-labs/design-system
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
No registry configuration needed — it's a public npm package.
|
|
141
|
+
|
|
142
|
+
**ESM only, Node 22 or later.** The package is `"type": "module"` with one build. Bundlers
|
|
143
|
+
(Vite, Next, webpack, esbuild) and `import` need nothing. `require('@rtkelly-labs/design-system')`
|
|
144
|
+
works on Node 22.12+, which loads ES modules from `require()`; a toolchain that needs the package
|
|
145
|
+
to be CommonJS (Jest without ESM support, for one) does not. Server components can import it
|
|
146
|
+
directly — see [`docs/api-surface.md`](./docs/api-surface.md) for which components render on the
|
|
147
|
+
server.
|
|
148
|
+
|
|
149
|
+
### Dev Prerelease Testing
|
|
150
|
+
|
|
151
|
+
Comment `/publish-dev` on a Pull Request and CI publishes that branch as
|
|
152
|
+
`<version>-dev.<pr>.<short-sha>` under the `dev` dist-tag:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pnpm add @rtkelly-labs/design-system@dev # latest dev build
|
|
156
|
+
pnpm view @rtkelly-labs/design-system dist-tags # exact versions per PR
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## ⚡ Usage & Setup
|
|
162
|
+
|
|
163
|
+
### 1. Import Stylesheet & Theme Provider
|
|
164
|
+
|
|
165
|
+
In your app entrypoint (`_app.tsx`, `main.tsx`, or `layout.tsx`):
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import '@rtkelly-labs/design-system/styles.css';
|
|
169
|
+
import { ThemeProvider, Button, Card, PageTitle, Badge, Divider } from '@rtkelly-labs/design-system';
|
|
170
|
+
|
|
171
|
+
export function App() {
|
|
172
|
+
return (
|
|
173
|
+
<ThemeProvider defaultLevel="midnight">
|
|
174
|
+
<main style={{ padding: '2rem' }}>
|
|
175
|
+
<PageTitle subtitle="Foundation Design System Surface">
|
|
176
|
+
[ MY APPLICATION ]
|
|
177
|
+
</PageTitle>
|
|
178
|
+
|
|
179
|
+
<Card>
|
|
180
|
+
<Badge accent="primary">v1.2.0 ACTIVE</Badge>
|
|
181
|
+
<p style={{ margin: '1rem 0' }}>
|
|
182
|
+
Brutalist UI surface shared across all projects.
|
|
183
|
+
</p>
|
|
184
|
+
<Button bracketed variant="tertiary">
|
|
185
|
+
EXECUTE ACTION
|
|
186
|
+
</Button>
|
|
187
|
+
</Card>
|
|
188
|
+
|
|
189
|
+
{/* The mark follows the level's polarity: a terminal rule on the dark
|
|
190
|
+
rungs, a hand-ruled pencil dash on the light ones. */}
|
|
191
|
+
<Divider />
|
|
192
|
+
</main>
|
|
193
|
+
</ThemeProvider>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### 2. Tailwind CSS v4 token contract
|
|
201
|
+
|
|
202
|
+
Import the theme contract in your CSS entrypoint. It ships the `@theme` tokens,
|
|
203
|
+
one `[data-theme]` block per level, the per-level and polarity variants, and an
|
|
204
|
+
`@source` directive — that last one is load-bearing, because Tailwind v4 skips
|
|
205
|
+
`node_modules` during content detection and would otherwise generate none of the
|
|
206
|
+
utilities the compiled components use:
|
|
207
|
+
|
|
208
|
+
```css
|
|
209
|
+
@import "tailwindcss";
|
|
210
|
+
@import "@rtkelly-labs/design-system/theme.css";
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`theme.css` is **generated** from `src/theme/levels.ts`, which is the single place
|
|
214
|
+
any level name or colour is written.
|
|
215
|
+
|
|
216
|
+
`styles.css` = `theme.css` + `prose.css` + web-font imports + opinionated global
|
|
217
|
+
resets (zero border-radius everywhere, base typography). Import that, or compose
|
|
218
|
+
the pieces yourself — but not both.
|
|
219
|
+
|
|
220
|
+
**Peer requirements.** `tailwindcss` v4 for either stylesheet, and
|
|
221
|
+
`@tailwindcss/typography` if you import `prose.css`, which loads it as a
|
|
222
|
+
`@plugin`. Both are optional peers: a Tailwind plugin resolves from *your*
|
|
223
|
+
`node_modules` at your build time, so neither can be bundled.
|
|
224
|
+
|
|
225
|
+
### 3. Semantic tokens
|
|
226
|
+
|
|
227
|
+
Address **roles**, not hues. Each rung of the ladder declares its own mapping of
|
|
228
|
+
these roles, so a component that hard-codes `cyan` cannot be rethemed without
|
|
229
|
+
editing the component. Every pair is contrast-audited on every level by
|
|
230
|
+
`pnpm check:contrast`, which gates CI.
|
|
231
|
+
|
|
232
|
+
| Role group | Tokens | Use for |
|
|
233
|
+
|---|---|---|
|
|
234
|
+
| `--ds-accent-*` | `primary`, `secondary`, `tertiary`, `quiet` | Visual hierarchy |
|
|
235
|
+
| `--ds-intent-*` | `info`, `success`, `warning`, `danger` | Communicated meaning |
|
|
236
|
+
| `--ds-surface-*` | `base`, `raised`, `sunken`, `overlay` | Background elevation |
|
|
237
|
+
| `--ds-text-*` | `primary`, `secondary`, `muted`, `inverse` | Text prominence |
|
|
238
|
+
| `--ds-border-*` | `strong`, `default`, `subtle` | Rule weight |
|
|
239
|
+
| `--ds-font-*` | `display`, `body`, `mono`, `pixel` | Typography roles |
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
import { Badge, Tag, accentVar, semanticTokens } from '@rtkelly-labs/design-system';
|
|
243
|
+
|
|
244
|
+
<Badge accent="primary">HIERARCHY</Badge>
|
|
245
|
+
<Tag text="deprecated" accent="danger" /> {/* meaning, not colour */}
|
|
246
|
+
<div style={{ borderColor: accentVar('secondary') }} />
|
|
247
|
+
<div style={{ background: semanticTokens.surface.raised }} />
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Tailwind aliases are generated too: `text-accent-primary`, `bg-surface-raised`,
|
|
251
|
+
`border-edge-subtle`, `text-intent-danger`.
|
|
252
|
+
|
|
253
|
+
The legacy palette names (`'cyan' | 'pink' | 'yellow' | 'green'`) still resolve to
|
|
254
|
+
identical values, so existing call sites keep working — but they are deprecated.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 📚 Documentation Portal
|
|
259
|
+
|
|
260
|
+
A complete chrome kit for MDX documentation sites.
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import {
|
|
264
|
+
DocsLayout, DocsHeader, DocsSidebar, TableOfContents,
|
|
265
|
+
Breadcrumbs, DocPager, Prose, CodeBlock, CodeTabs, CodeTab, AnchorHeading,
|
|
266
|
+
DocsLinkProvider, mdxComponents,
|
|
267
|
+
} from '@rtkelly-labs/design-system';
|
|
268
|
+
import '@rtkelly-labs/design-system/prose.css';
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Every section is addressable.** Headings render through `AnchorHeading`, which gives
|
|
272
|
+
each one a `#slug` id and a hover affordance that copies the *absolute* URL including
|
|
273
|
+
the hash — the thing you actually paste into a ticket.
|
|
274
|
+
|
|
275
|
+
**The header is durable.** `DocsHeader` is sticky and measures its own height into
|
|
276
|
+
`--docs-header-height`. That single value feeds `scroll-padding-top`, the
|
|
277
|
+
`scroll-margin-top` on every heading, and the scroll-spy reading line — so anchors
|
|
278
|
+
never land underneath the bar, at any viewport width.
|
|
279
|
+
|
|
280
|
+
**Bring your own router.** Wrap the app in `DocsLinkProvider` and all chrome navigation
|
|
281
|
+
goes through it instead of hard-navigating:
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
import { Link } from 'react-router-dom';
|
|
285
|
+
|
|
286
|
+
<DocsLinkProvider component={({ href, ...props }) => <Link to={href} {...props} />}>
|
|
287
|
+
<App />
|
|
288
|
+
</DocsLinkProvider>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Code tabs switch together.** `CodeTabs` is the language / package-manager
|
|
292
|
+
switcher: a real `tablist` with arrow-key traversal. Blocks sharing a `group`
|
|
293
|
+
switch as one and the choice persists across pages, so a reader picks `pnpm`
|
|
294
|
+
once. Fenced blocks inside a `CodeTab` attach to the strip automatically.
|
|
295
|
+
|
|
296
|
+
**One MDX mapping.** `mdxComponents` maps `h1`–`h6` → anchored headings, `pre` →
|
|
297
|
+
`CodeBlock`, `a` → router-aware links, and exposes `NoteBlock` / `TLDR` / `Card` /
|
|
298
|
+
`Tag` to MDX authors. Pass it to any MDX provider so every site renders Markdown
|
|
299
|
+
identically.
|
|
300
|
+
|
|
301
|
+
`prose.css` styles the bare tags a Markdown pipeline emits (`ul`, `ol`, `table`,
|
|
302
|
+
`blockquote`, `hr`, inline `code`, task lists), plus GitHub alert syntax
|
|
303
|
+
(`> [!NOTE]`) as produced by `remark-github-blockquote-alert`, and code titles from
|
|
304
|
+
`remark-code-title`. It is plain CSS on purpose: the docs chrome is layout-critical,
|
|
305
|
+
and Tailwind v4 skips `node_modules` in automatic content detection, so a
|
|
306
|
+
misconfigured `@source` would half-break a sidebar rather than fail loudly.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 🛠 Repository & Publishing
|
|
311
|
+
|
|
312
|
+
- **Repository**: `https://github.com/rtkelly-labs/design-system`
|
|
313
|
+
- **npm**: `@rtkelly-labs/design-system` on `https://registry.npmjs.org`
|
|
314
|
+
- **CI Pipelines**:
|
|
315
|
+
- `ci.yml`: Typecheck, package build, Storybook build, and Linux visual regression testing.
|
|
316
|
+
- `publish-package.yml`: npm publishing (stable on main, dev prereleases via dispatch).
|
|
317
|
+
- `publish-dev-command.yml`: `/publish-dev` PR comment handler.
|
|
318
|
+
- `update-snapshots.yml`: On-demand visual snapshot regeneration.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/components/AlertDialog.tsx
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import { AlertDialog as BaseAlertDialog } from "@base-ui/react/alert-dialog";
|
|
6
|
+
import { cn } from "../lib/recipe.js";
|
|
7
|
+
import { usePortalThemeAttribute } from "./portalTheme.js";
|
|
8
|
+
import { dialogSurface } from "./dialogSurface.js";
|
|
9
|
+
import { Button } from "./Button.js";
|
|
10
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var AlertDialog = forwardRef(function AlertDialog2({
|
|
12
|
+
isOpen,
|
|
13
|
+
onClose,
|
|
14
|
+
onConfirm,
|
|
15
|
+
title,
|
|
16
|
+
children,
|
|
17
|
+
confirmLabel = "CONFIRM",
|
|
18
|
+
cancelLabel = "CANCEL",
|
|
19
|
+
footer,
|
|
20
|
+
className,
|
|
21
|
+
...props
|
|
22
|
+
}, ref) {
|
|
23
|
+
const slots = dialogSurface();
|
|
24
|
+
const portalTheme = usePortalThemeAttribute();
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
BaseAlertDialog.Root,
|
|
27
|
+
{
|
|
28
|
+
open: isOpen,
|
|
29
|
+
onOpenChange: (open) => {
|
|
30
|
+
if (!open) onClose();
|
|
31
|
+
},
|
|
32
|
+
children: /* @__PURE__ */ jsxs(BaseAlertDialog.Portal, { ...portalTheme, children: [
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
BaseAlertDialog.Backdrop,
|
|
35
|
+
{
|
|
36
|
+
"data-slot": "alert-dialog-backdrop",
|
|
37
|
+
className: slots.backdrop()
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
BaseAlertDialog.Viewport,
|
|
42
|
+
{
|
|
43
|
+
"data-slot": "alert-dialog-viewport",
|
|
44
|
+
className: slots.viewport(),
|
|
45
|
+
children: /* @__PURE__ */ jsxs(
|
|
46
|
+
BaseAlertDialog.Popup,
|
|
47
|
+
{
|
|
48
|
+
ref,
|
|
49
|
+
"data-slot": "alert-dialog",
|
|
50
|
+
className: cn(slots.popup(), "max-w-md", className),
|
|
51
|
+
...props,
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx("div", { "data-slot": "alert-dialog-header", className: slots.header(), children: /* @__PURE__ */ jsx(
|
|
54
|
+
BaseAlertDialog.Title,
|
|
55
|
+
{
|
|
56
|
+
"data-slot": "alert-dialog-title",
|
|
57
|
+
className: slots.title(),
|
|
58
|
+
render: /* @__PURE__ */ jsxs("h3", { children: [
|
|
59
|
+
"[ ",
|
|
60
|
+
title,
|
|
61
|
+
" ]"
|
|
62
|
+
] })
|
|
63
|
+
}
|
|
64
|
+
) }),
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
BaseAlertDialog.Description,
|
|
67
|
+
{
|
|
68
|
+
"data-slot": "alert-dialog-body",
|
|
69
|
+
className: slots.body(),
|
|
70
|
+
render: /* @__PURE__ */ jsx("div", {}),
|
|
71
|
+
children
|
|
72
|
+
}
|
|
73
|
+
),
|
|
74
|
+
/* @__PURE__ */ jsx("div", { "data-slot": "alert-dialog-footer", className: slots.footer(), children: footer || /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
BaseAlertDialog.Close,
|
|
77
|
+
{
|
|
78
|
+
render: /* @__PURE__ */ jsx(Button, { variant: "default", size: "sm", children: cancelLabel })
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
/* @__PURE__ */ jsx(Button, { onClick: onConfirm, variant: "tertiary", bracketed: true, size: "sm", children: confirmLabel })
|
|
82
|
+
] }) })
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] })
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
export {
|
|
93
|
+
AlertDialog
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=AlertDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/AlertDialog.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef } from 'react';\nimport type { HTMLAttributes, ReactNode } from 'react';\nimport { AlertDialog as BaseAlertDialog } from '@base-ui/react/alert-dialog';\nimport { cn } from '../lib/recipe';\nimport { usePortalThemeAttribute } from './portalTheme';\nimport { dialogSurface } from './dialogSurface';\nimport { Button } from './Button';\n\nexport interface AlertDialogProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'children' | 'className'> {\n isOpen: boolean;\n /** Dismissal — Escape, or the cancel control. Never a backdrop click. */\n onClose: () => void;\n /** The destructive action. Called instead of, not as well as, `onClose`. */\n onConfirm: () => void;\n title: string;\n /**\n * What the action does, and what it costs. Short: this is wired as the\n * dialog's accessible description, so a screen reader reads it immediately\n * after the title.\n */\n children: ReactNode;\n confirmLabel?: string;\n cancelLabel?: string;\n /**\n * Replaces the cancel/confirm pair outright, for the rare confirmation with\n * a third option. Supplying it means owning dismissal — nothing else in the\n * dialog closes it.\n */\n footer?: ReactNode;\n className?: string;\n}\n\n/**\n * A destructive-action confirmation, on Base UI's `alert-dialog`.\n *\n * ## Why this is not `Modal` with different buttons\n *\n * The difference is the dismissal contract, and it is the whole point.\n * `AlertDialog` cannot be dismissed by clicking outside it: Base UI's\n * `AlertDialog.Root` omits `disablePointerDismissal` from its props\n * altogether, because the answer is never \"yes\". A confirmation you can\n * dismiss with a stray click is a confirmation that has not confirmed\n * anything, and shipping `Modal` without this is how a delete dialog ends up\n * backdrop-dismissible by default.\n *\n * Escape still closes it. That is deliberate and not a contradiction: Escape\n * is deliberate, unambiguous and always means *cancel*, and removing it would\n * trap a keyboard user in the dialog.\n *\n * It renders `role=\"alertdialog\"` rather than `role=\"dialog\"`, which is what\n * tells a screen reader to announce the whole surface rather than just its\n * name — the reason the description below is wired rather than decorative.\n *\n * ## The cancel control is the close control\n *\n * There is no `×`. A confirmation asks a question with two answers and both\n * are buttons; adding a third dismissal affordance in the corner makes the\n * safe answer ambiguous. Cancel is `AlertDialog.Close`, so it is also what a\n * touch screen reader finds when it looks for the way out.\n */\nexport const AlertDialog = forwardRef<HTMLDivElement, AlertDialogProps>(function AlertDialog(\n {\n isOpen,\n onClose,\n onConfirm,\n title,\n children,\n confirmLabel = 'CONFIRM',\n cancelLabel = 'CANCEL',\n footer,\n className,\n ...props\n },\n ref,\n) {\n const slots = dialogSurface();\n\n const portalTheme = usePortalThemeAttribute();\n return (\n <BaseAlertDialog.Root\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <BaseAlertDialog.Portal {...portalTheme}>\n <BaseAlertDialog.Backdrop\n data-slot=\"alert-dialog-backdrop\"\n className={slots.backdrop()}\n />\n <BaseAlertDialog.Viewport\n data-slot=\"alert-dialog-viewport\"\n className={slots.viewport()}\n >\n <BaseAlertDialog.Popup\n ref={ref}\n data-slot=\"alert-dialog\"\n // Narrower than `Modal`'s `max-w-lg`: a confirmation is one\n // sentence and two buttons, and a wide one reads as a workflow the\n // reader is expected to study rather than a question to answer.\n className={cn(slots.popup(), 'max-w-md', className)}\n {...props}\n >\n <div data-slot=\"alert-dialog-header\" className={slots.header()}>\n <BaseAlertDialog.Title\n data-slot=\"alert-dialog-title\"\n className={slots.title()}\n render={<h3>[ {title} ]</h3>}\n />\n </div>\n\n <BaseAlertDialog.Description\n data-slot=\"alert-dialog-body\"\n className={slots.body()}\n // A `div`, not Base UI's default `p`: the body takes arbitrary\n // nodes, and a block element inside a paragraph is invalid HTML\n // that the parser silently repairs by closing the paragraph\n // early — which would leave the description pointing at nothing.\n render={<div />}\n >\n {children}\n </BaseAlertDialog.Description>\n\n <div data-slot=\"alert-dialog-footer\" className={slots.footer()}>\n {footer || (\n <>\n {/*\n * The label goes on the render element rather than on\n * `Close`: `Button`'s props are a union whose link arm\n * requires `children` and `href`, so an empty `<Button />`\n * does not typecheck even though Base UI would fill it in.\n */}\n <BaseAlertDialog.Close\n render={\n <Button variant=\"default\" size=\"sm\">\n {cancelLabel}\n </Button>\n }\n />\n <Button onClick={onConfirm} variant=\"tertiary\" bracketed size=\"sm\">\n {confirmLabel}\n </Button>\n </>\n )}\n </div>\n </BaseAlertDialog.Popup>\n </BaseAlertDialog.Viewport>\n </BaseAlertDialog.Portal>\n </BaseAlertDialog.Root>\n );\n});\n"],"mappings":";;;AAEA,SAAS,kBAAkB;AAE3B,SAAS,eAAe,uBAAuB;AAC/C,SAAS,UAAU;AACnB,SAAS,+BAA+B;AACxC,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AAiFf,SAuCQ,UAvCR,KAqBgB,YArBhB;AA1BD,IAAM,cAAc,WAA6C,SAASA,aAC/E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,QAAQ,cAAc;AAE5B,QAAM,cAAc,wBAAwB;AAC5C,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,MAAM;AAAA,MACN,cAAc,CAAC,SAAS;AACtB,YAAI,CAAC,KAAM,SAAQ;AAAA,MACrB;AAAA,MAEA,+BAAC,gBAAgB,QAAhB,EAAwB,GAAG,aAC1B;AAAA;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YACC,aAAU;AAAA,YACV,WAAW,MAAM,SAAS;AAAA;AAAA,QAC5B;AAAA,QACA;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YACC,aAAU;AAAA,YACV,WAAW,MAAM,SAAS;AAAA,YAE1B;AAAA,cAAC,gBAAgB;AAAA,cAAhB;AAAA,gBACC;AAAA,gBACA,aAAU;AAAA,gBAIV,WAAW,GAAG,MAAM,MAAM,GAAG,YAAY,SAAS;AAAA,gBACjD,GAAG;AAAA,gBAEJ;AAAA,sCAAC,SAAI,aAAU,uBAAsB,WAAW,MAAM,OAAO,GAC3D;AAAA,oBAAC,gBAAgB;AAAA,oBAAhB;AAAA,sBACC,aAAU;AAAA,sBACV,WAAW,MAAM,MAAM;AAAA,sBACvB,QAAQ,qBAAC,QAAG;AAAA;AAAA,wBAAG;AAAA,wBAAM;AAAA,yBAAE;AAAA;AAAA,kBACzB,GACF;AAAA,kBAEA;AAAA,oBAAC,gBAAgB;AAAA,oBAAhB;AAAA,sBACC,aAAU;AAAA,sBACV,WAAW,MAAM,KAAK;AAAA,sBAKtB,QAAQ,oBAAC,SAAI;AAAA,sBAEZ;AAAA;AAAA,kBACH;AAAA,kBAEA,oBAAC,SAAI,aAAU,uBAAsB,WAAW,MAAM,OAAO,GAC1D,oBACC,iCAOE;AAAA;AAAA,sBAAC,gBAAgB;AAAA,sBAAhB;AAAA,wBACC,QACE,oBAAC,UAAO,SAAQ,WAAU,MAAK,MAC5B,uBACH;AAAA;AAAA,oBAEJ;AAAA,oBACA,oBAAC,UAAO,SAAS,WAAW,SAAQ,YAAW,WAAS,MAAC,MAAK,MAC3D,wBACH;AAAA,qBACF,GAEJ;AAAA;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA,SACF;AAAA;AAAA,EACF;AAEJ,CAAC;","names":["AlertDialog"]}
|