@tonycodes-ui/mortar 0.0.0-stage → 0.11.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 (104) hide show
  1. package/AGENTS.md +10 -0
  2. package/CHANGELOG.md +276 -0
  3. package/CONTRIBUTING.md +48 -0
  4. package/DESIGN.md +51 -0
  5. package/LICENSE +21 -0
  6. package/README.md +155 -2
  7. package/TESTING.md +83 -0
  8. package/baseline-policy.json +16 -0
  9. package/bin/mortar.mjs +258 -0
  10. package/catalog.json +9703 -0
  11. package/cli/audit.mjs +943 -0
  12. package/cli/data.mjs +176 -0
  13. package/cli/mcp.mjs +216 -0
  14. package/cli/migrations.mjs +128 -0
  15. package/cli/packet.mjs +267 -0
  16. package/cli/search.mjs +246 -0
  17. package/cli/tools.mjs +229 -0
  18. package/design-principles.json +30 -0
  19. package/dist/agent-data.json +1 -0
  20. package/dist/application.d.ts +340 -0
  21. package/dist/application.js +240 -0
  22. package/dist/auth.d.ts +121 -0
  23. package/dist/auth.js +97 -0
  24. package/dist/brand.d.ts +69 -0
  25. package/dist/brand.js +266 -0
  26. package/dist/calendar.d.ts +75 -0
  27. package/dist/calendar.js +310 -0
  28. package/dist/choice.d.ts +36 -0
  29. package/dist/choice.js +36 -0
  30. package/dist/composer.d.ts +28 -0
  31. package/dist/composer.js +47 -0
  32. package/dist/display.d.ts +136 -0
  33. package/dist/display.js +75 -0
  34. package/dist/docs.d.ts +145 -0
  35. package/dist/docs.js +141 -0
  36. package/dist/ecommerce.d.ts +261 -0
  37. package/dist/ecommerce.js +177 -0
  38. package/dist/feedback.d.ts +80 -0
  39. package/dist/feedback.js +98 -0
  40. package/dist/foundation.d.ts +42 -0
  41. package/dist/foundation.js +121 -0
  42. package/dist/heading.d.ts +5 -0
  43. package/dist/heading.js +9 -0
  44. package/dist/icons.d.ts +50 -0
  45. package/dist/icons.js +70 -0
  46. package/dist/index.d.ts +34 -0
  47. package/dist/index.js +17 -0
  48. package/dist/inspection.d.ts +24 -0
  49. package/dist/inspection.js +14 -0
  50. package/dist/internal.d.ts +492 -0
  51. package/dist/internal.js +273 -0
  52. package/dist/layout.d.ts +107 -0
  53. package/dist/layout.js +66 -0
  54. package/dist/marketing-sections.d.ts +161 -0
  55. package/dist/marketing-sections.js +58 -0
  56. package/dist/marketing.d.ts +254 -0
  57. package/dist/marketing.js +150 -0
  58. package/dist/navigation.d.ts +35 -0
  59. package/dist/navigation.js +44 -0
  60. package/dist/primitives.d.ts +258 -0
  61. package/dist/primitives.js +244 -0
  62. package/dist/showcase.d.ts +29 -0
  63. package/dist/showcase.js +10 -0
  64. package/dist/workspace.d.ts +80 -0
  65. package/dist/workspace.js +48 -0
  66. package/docs/agents.md +127 -0
  67. package/docs/auth-flows.md +71 -0
  68. package/docs/migrating-to-0.6.md +94 -0
  69. package/docs/theming.md +170 -0
  70. package/package.json +94 -4
  71. package/skills/mortar/SKILL.md +36 -0
  72. package/src/application.css +1487 -0
  73. package/src/application.tsx +1413 -0
  74. package/src/auth.tsx +452 -0
  75. package/src/brand.ts +335 -0
  76. package/src/calendar.css +468 -0
  77. package/src/calendar.tsx +868 -0
  78. package/src/choice.tsx +240 -0
  79. package/src/composer.tsx +158 -0
  80. package/src/data.css +690 -0
  81. package/src/display.tsx +452 -0
  82. package/src/docs.css +704 -0
  83. package/src/docs.tsx +737 -0
  84. package/src/ecommerce.css +810 -0
  85. package/src/ecommerce.tsx +1033 -0
  86. package/src/feedback.tsx +388 -0
  87. package/src/foundation.css +1867 -0
  88. package/src/foundation.tsx +227 -0
  89. package/src/heading.ts +13 -0
  90. package/src/icons.tsx +237 -0
  91. package/src/index.ts +230 -0
  92. package/src/inspection.tsx +91 -0
  93. package/src/internal.tsx +614 -0
  94. package/src/layout.tsx +342 -0
  95. package/src/marketing-sections.tsx +621 -0
  96. package/src/marketing.css +2400 -0
  97. package/src/marketing.tsx +1156 -0
  98. package/src/navigation.tsx +118 -0
  99. package/src/overlays.css +350 -0
  100. package/src/primitives.tsx +1135 -0
  101. package/src/showcase.tsx +120 -0
  102. package/src/tokens.css +449 -0
  103. package/src/workspace.tsx +333 -0
  104. package/styles.css +56 -0
package/AGENTS.md ADDED
@@ -0,0 +1,10 @@
1
+ # Agent instructions
2
+
3
+ [CONTRIBUTING.md](CONTRIBUTING.md) is the contribution workflow. This page lists only what a coding agent must not miss.
4
+
5
+ - To build an app with Mortar, use the kit's own MCP server and CLI (`npx -y @tonycodes-ui/mortar mcp`, `npx mortar search|component|packet|audit`) and the [agent skill](skills/mortar/SKILL.md). See [Mortar for coding agents](docs/agents.md). They run locally against the installed package; no account or hosted service is involved.
6
+ - Read [DESIGN.md](DESIGN.md) before composing UI. It holds the design principles and the API conventions that every new prop must follow. Read [TESTING.md](TESTING.md) before changing a component or its test contract.
7
+ - Fix shared problems centrally in `src`, with the fixture in `previews` and the contract in `manifests`. Do not copy components or override their styles in a consumer.
8
+ - Run `npm run check` first. If it reports M007 or M008, review what changed in your diff, then run `npm run catalog`. It prints which components' fingerprints and contracts changed. Never run `npm run catalog` just to make a failing check pass.
9
+ - Run `npm run test:browser` and `npm run test:visual` before opening a PR, and report the actual results.
10
+ - Never approve, merge, publish or bump the version on your own initiative, and never weaken a protected check, policy or workflow to make a change pass.
package/CHANGELOG.md ADDED
@@ -0,0 +1,276 @@
1
+ # Changelog
2
+
3
+ Mortar follows [semantic versioning](https://semver.org/). Before 1.0, a minor release may contain breaking changes, and it says so. Each release is published from its `v<version>` tag to [npmjs.com](https://www.npmjs.com/package/@tonycodes-ui/mortar) with npm provenance. Its GitHub release carries the exact archive and a `provenance.json` with the commit and SHA-512 integrity.
4
+
5
+ ## Unreleased
6
+
7
+ ### Added
8
+
9
+ - **Surfaces in the brand contract.** A brand can set `paper`, `surface` and `sunken` for each appearance (`--m-brand-l-paper|surface|sunken`, `--m-brand-d-paper|surface|sunken`), for example a navy dark page. Omitted, they keep today's values, and inverse bands take them from the other appearance. Mortar's text and status colours stay fixed, so check them against tinted surfaces: the brand builder's contrast table now does ([#59](https://github.com/tonycodes/mortar/issues/59)).
10
+ - **Accent gradients.** `accentGradient` per appearance (`--m-brand-{l,d}-accent-gradient`) takes a `linear-`, `radial-` or `conic-gradient()` (or a `repeating-` form) whose stops are colours. It is painted only where a component opts in: Button and ActionLink `variant="accent"`, and `tone="accent"` on CallToAction, Hero and Banner, all with `onAccent` text. Without a gradient these paint the flat accent. The appearance exposes the fill as `--m-accent-fill` (an image, painted over `background-color: var(--m-accent)`) and `--m-inv-accent-fill` for inverse bands. On hover and active the fill takes a white or black wash chosen from the on-accent text (`--m-accent-wash`), so contrast rises instead of falling; browsers without relative colours keep the plain fill. The brand builder checks on-accent text against every stop at rest, hover and active.
11
+ - **Heading font.** Headings and component titles (page, section, hero, card, settings, sign-in, auth, post, calendar and stacked-list titles, and prose headings) read `--m-font-heading`. It is unset by default, so headings keep the font they inherit; nothing changes until you set it. A brand can set `fonts: { body, heading }` (`--m-brand-font`, `--m-brand-font-heading`), which apply wherever the brand does, including a container-scoped ThemeProvider. Tailwind gains a `font-heading` utility, and `font-sans` follows a brand's body font.
12
+ - `isBrandColour`, `isBrandGradient` and `isBrandFont` in `@tonycodes-ui/mortar/brand` check a value before you save it. Fonts accept bare `var(--name)` entries, as framework font loaders such as `next/font` hand out.
13
+ - The brand builder checks strong lines (`--m-line-strong`, control borders) at 3:1 on page, surface and sunken.
14
+
15
+ ### Fixed
16
+
17
+ - **Brand values are checked as colour syntax.** `brandToStyle`, `brandToCss`, `registerBrand` and `brandTokens` accepted any value made of letters, digits and brackets, so `accent: "linear-gradient(…)"` or `url(…)` passed and then failed silently in the browser. A colour is now hex, a colour name (including `transparent` and `currentcolor`), or `rgb()`, `rgba()`, `hsl()`, `hsla()`, `hwb()`, `lab()`, `lch()`, `oklab()`, `oklch()`, `color()`, `color-mix()`, `light-dark()` or `var()`, with nested functions checked the same way. Anything else throws an error that names the key, such as `dark.accent`.
18
+ - **The audit no longer flags brand colours as `raw-colour`.** Colours inside a `brandTokens={…}` value (and a `const` it references in the same file), the arguments of `brandToCss`, `brandToStyle` and `registerBrand`, objects typed as or satisfying `BrandDefinition`, and `--m-brand-*` values are where colours belong. Other colours in the same file are still reported.
19
+
20
+ ### Changed
21
+
22
+ - **`--m-line-strong` in light is `#8b8b90`** (was `#8e8e93`), and `--m-inv-line-strong` in dark with it. The old value was 2.99:1 on the default sunken surface, just under the 3:1 that control borders need.
23
+
24
+ - **Packages are published to npmjs.com.** Install with a plain `npm install @tonycodes-ui/mortar`; no registry configuration, account or token is needed. Releases are published from GitHub Actions with npm trusted publishing (OIDC, no long-lived token) and `--provenance`, so each version on npmjs.com links to the workflow run and commit that built it.
25
+ - **The playground moved to GitHub Pages**, at https://mortar.tony.codes/playground/. The site root links the playground, GitHub, npm and the docs. The package `homepage` points there.
26
+ - **Everything is free and in this repository.** The hosted Mortar Cloud preview (agent identities, OAuth MCP connections, hosted audits and planned paid plans) is retired. The kit, docs, playground and agent tooling are MIT licensed here, with no accounts, licence checks, telemetry or hosted service. GitHub maintainer review is the only review gate.
27
+
28
+ ### Migration
29
+
30
+ Versions up to 0.11 of the private-registry package `@tony-ui/mortar` were published only to the previous owner-hosted registry, `https://git.tony.codes/api/packages/tony/npm/`, which will be retired. New versions are on npmjs.com only. To upgrade, remove the scope override and install from npmjs.com:
31
+
32
+ ```sh
33
+ npm config delete @tony-ui:registry --location=project
34
+ npm install @tonycodes-ui/mortar@latest
35
+ ```
36
+
37
+ A project that must stay on 0.11 or earlier keeps its scope override (`@tony-ui:registry=https://git.tony.codes/api/packages/tony/npm/` in `.npmrc`) while that registry remains available, or installs the archive attached to the version's [GitHub release](https://github.com/tonycodes/mortar/releases).
38
+
39
+ ## Unreleased
40
+
41
+ ### Added
42
+
43
+ - **Open agent tooling in the package: an MCP server and the `mortar` CLI.** They read the installed version's catalogue, contracts, examples and guides, run locally, work offline and need no account. They add no runtime dependencies. See [Mortar for coding agents](https://github.com/tonycodes/mortar/blob/main/docs/agents.md).
44
+ - `mortar mcp` is a stdio MCP server (`claude mcp add mortar -- npx -y @tonycodes-ui/mortar mcp`) with six tools: `search_components`, `get_component` (props with types and defaults, usage notes, dependencies, marker, tested states and a JSX example), `get_build_packet` (for component names or a free-text brief: the dependency closure, imports, CSS and ThemeProvider setup, design principles, API conventions and matching page templates), `get_guide`, `list_kits` and `audit_app`.
45
+ - `mortar search`, `component`, `packet`, `audit`, `guide` and `kits` give the same answers on the command line, with `--json`.
46
+ - `mortar audit [path]` is a read-only static audit of an application: version range, imports and props that the installed version does not have (with 0.6 rename suggestions), invalid prop values, CSS overriding `.m-*` classes or `[data-m-component]`, raw colours beside Mortar components, a missing `styles.css` import or ThemeProvider, deep imports and local copies of Mortar source. It exits 1 when it finds errors.
47
+ - An agent skill, `skills/mortar/SKILL.md` (`npx mortar skill`), with the workflow defaults: search, packet, compose, audit, and contribute by pull request.
48
+ - The package now also ships `AGENTS.md`, `CONTRIBUTING.md`, `TESTING.md` and the guides in `docs/`, which the tools read.
49
+
50
+ ## Unreleased
51
+
52
+ ### Added
53
+
54
+ - **`ErrorSummary`** (Foundation › Form controls): the problems that stopped a form submitting, listed above the form with a link to each field. Props: `errors` (`{ message; href?; target? }[]`; renders nothing when empty), `title` (default "There is a problem"), `headingLevel` (default 2), `autoFocus` (default true), `submitCount`, `id` and `className`. It is a `role="alert"` region named by its heading with `tabIndex={-1}`: it takes focus when it appears and whenever `submitCount` changes, but not while a fixed field's error clears. A link focuses its field without changing the URL hash; for a group such as a RadioGroup the checked or first radio takes focus, and the label or legend scrolls into view.
55
+ - **Checkbox `error`**: the message is announced when it appears (`role="alert"`), the box is `aria-invalid` and `aria-describedby` links the description and the error. `required` adds the decorative `*` after the label, as on Input and Select. Without these props the markup is unchanged.
56
+ - **RadioGroup `error`, `hint`, `required` and `id`**: the hint or error sits under the legend and describes the fieldset; with an error each radio is `aria-invalid`, and `required` marks every radio and adds `*` to the legend. Without these props the markup is unchanged.
57
+
58
+ ### Changed
59
+
60
+ - The sign-up and other auth page templates use `ErrorSummary` and `Checkbox error` instead of a local summary and a hand-wired terms error. The terms checkbox is now `required`.
61
+
62
+ ## 0.11.0 (2026-10-20)
63
+
64
+ ### Added
65
+
66
+ - **Sign-in and registration building blocks** (Application UI › Sign-in and registration). See [Sign-in and registration flows](https://github.com/tonycodes/mortar/blob/main/docs/auth-flows.md).
67
+ - `AuthLayout`: the page shell for auth screens. It renders the page's `main` and `h1` (`headingLevel`, default 1), with `logo`, `description`, `footer` and `layout="center" | "cards" | "split"`. With `split`, the `aside` sits beside the form; on narrow screens a text aside follows the form and a lone image or video is hidden.
68
+ - `PasswordInput`: a password field with a show/hide toggle (`aria-pressed`, keeps focus), `purpose="current" | "new"` for `current-password`/`new-password` autocomplete, an optional `requirements` checklist (each item met or not met, announced only when the whole set changes) and a `strength` meter.
69
+ - `CodeInput`: a one-time code field. It is one `autocomplete="one-time-code"` input drawn as `length` cells (default 6), so typing, Backspace, paste and autofill behave as in a text field. Digits only, or `alphanumeric`. `onChange(value)` gets the cleaned code; the optional `onComplete(code)` fires when it is full.
70
+ - `ProviderButtons`: one secondary button per sign-in provider, as a `list` or a `grid`, optionally a named group.
71
+ - **Page templates** for sign in (card and split screen), sign up, forgot password, check your email, reset password, verify email and two-factor, with validation, error summaries, loading and success states, and resend cooldowns.
72
+
73
+ ### Changed
74
+
75
+ - **SignInPanel** renders its providers with `ProviderButtons` and its divider with `Divider`. Its props are unchanged. The markup differs in three places: the providers wrapper is `div.m-provider-buttons` (was `div.m-sign-in-providers`); a provider icon is Button's `span.m-button-icon` (was `span.m-sign-in-icon`); the divider is `<div class="m-divider" role="separator" aria-label="or">` (was `<p class="m-sign-in-divider">`); it looks the same.
76
+ - The playground's "Forms and settings" category no longer lists SignInPanel; it is in the new "Sign-in and registration" category.
77
+
78
+ ## 0.10.0 (2026-10-20)
79
+
80
+ ### Added
81
+
82
+ - **Playground brand builder** (`?page=brand`, [open it](https://mortar.tony.codes/playground/?page=brand)): edit a brand's light and dark values, including the optional tokens, and see them live in light, dark and inverse previews with overlays. It reports WCAG contrast for on-primary, hover, active, accent, link and focus as the browser resolves them, exports the CSS rule and the `brandTokens` object, and keeps the brand in the URL so it can be shared. Playground only; the package is unchanged.
83
+
84
+ ### Changed
85
+
86
+ - **Scale tokens drive component styles:** component font weights now read `--m-weight-*`, and corner radii, letter spacing and line heights that equal a scale value read `--m-radius-*`, `--m-tracking-*` and `--m-leading-*`. At the default token values nothing renders differently. Overriding a token on `:root` or a container now restyles the components inside it. Padding, gaps and margins do not read `--m-space-*` yet. See [Scales](https://github.com/tonycodes/mortar/blob/main/docs/theming.md#scales).
87
+
88
+ ### Fixed
89
+
90
+ - **Runtime brands that change:** ThemeProvider renders `brandTokens` as an ordinary `<style>` beside its content instead of a hoisted stylesheet. React 19 never removes hoisted styles, so switching back to an earlier set of tokens could show the wrong brand. The stylesheet now updates in place and is removed on unmount. It is still server-rendered.
91
+
92
+ ## 0.9.0 (2026-10-20)
93
+
94
+ Theming. See [Theming](https://github.com/tonycodes/mortar/blob/main/docs/theming.md).
95
+
96
+ ### Added
97
+
98
+ - **Brand contract:** a brand declares only `--m-brand-l-*` and `--m-brand-d-*`. Light, dark and inverse sections resolve from it. Hover, active, selected, accent, focus and link derive from `primary` when omitted, so a complete brand can be four values.
99
+ - **Runtime brands:** `ThemeProvider` accepts `brandTokens` and any brand name. The brand renders as a hoisted, server-rendered stylesheet that overlays share, and its values are validated so tenant data cannot inject CSS. `@tonycodes-ui/mortar/brand` exports `brandToCss`, `brandToStyle` and `registerBrand`.
100
+ - **Scale tokens:** `--m-weight-*`, `--m-tracking-*`, `--m-leading-*`, `--m-space-*`, `--m-radius-xs` and `--m-radius-xl`.
101
+ - **Tailwind:** `info`, `secondary`, `selected` and `link` colours, `rounded-m*`, `shadow-float`, `tracking-display|heading|caps`, and font weights that follow the tokens.
102
+
103
+ ### Changed
104
+
105
+ - **No dark flash:** before `data-mortar-appearance` is set (server rendering, or no JavaScript), Mortar follows the operating system's colour scheme. Set `data-mortar-appearance="light"` on `<html>` to keep the old always-light start.
106
+ - **Green in dark mode:** primary buttons use mint `#6ee7b7` with dark text, as green's inverse sections already did, instead of dark green `#047857`. Each brand now has one dark-side primary, and mint has 3:1 or more contrast against the black page where dark green had 2.7:1. Everything else in neutral and green is unchanged.
107
+ - **Baseline policy 1.4.0:** M009 now requires brands to declare only the brand contract and each appearance to resolve the accent pair and its inverse.
108
+
109
+ ### Fixed
110
+
111
+ - **Branded element in a dark page:** a `data-mortar-brand` element inside a dark page without its own `data-mortar-appearance` now resolves dark. Before, it got light-mode accent, focus and link colours.
112
+ - **Density in nested containers:** a container nested in a compact or spacious one keeps that density unless it sets its own. `density="comfortable"` now sets the comfortable sizes explicitly, instead of relying on the light appearance to reset them.
113
+
114
+ ## 0.8.0 (2026-10-20)
115
+
116
+ - **Component marker:** the root element of every exported component now carries `data-m-component="<ExportName>"`, not only the marketing sections. It is a hook for tests and consumers, not for styles. Dialogs mark their dialog root. No other markup changes.
117
+ - **Prose:** prose styles now stop at nested component roots (`[data-m-component]`) instead of at any element with an `m-` class, so a utility class such as `m-4` inside prose no longer opts that element out.
118
+
119
+ ### Internal
120
+
121
+ - **Playground:** page templates load on demand, and React and Headless UI get their own chunks, so the main chunk drops from 821 kB to 320 kB. The published package is unchanged.
122
+
123
+ ## 0.7.0 (2026-10-19)
124
+
125
+ Additive: no exports removed, no prop types narrowed, and every default renders unchanged.
126
+
127
+ ### Marketing
128
+
129
+ - **Hero:** a phone mockup (new `MockWindow variant="phone"`), image tiles (`images`) and an angled image (`layout="angled"`).
130
+ - **FeatureSection:** an `offset` screenshot. A code example is a composition with `CodeBlock`.
131
+ - **BentoGrid:** a section `tone` and tall tiles through the item `rowSpan`.
132
+ - **StatGroup:** a `background` image band, and `layout="timeline" | "stepped"`.
133
+ - **Pricing:** four tiers, and an `extra` full-width tier band (new `PricingExtra` type).
134
+ - **ContentSection:** `stats` and a `testimonial`.
135
+ - **NotFound:** a `background` image.
136
+ - **MarketingHeader:** `layout="center"`, and `mobileMenu="panel"` for a full-screen menu dialog.
137
+ - **Flyout:** `layout="columns" | "full"`.
138
+ - **Footer:** `layout="center"` and a `newsletter` row.
139
+ - **Banner:** `variant="floating"`, and `placement="bottom"`, which can always be dismissed.
140
+ - **Newsletter:** `layout="center"` and `variant="panel"`.
141
+ - **ContactSection:** a `media` image and `offices`. The form is optional.
142
+ - **TeamGrid:** `layout="large" | "list"`.
143
+ - **PostList:** a `featured` post.
144
+ - **TestimonialGrid:** `layout="grid"` and a `featured` testimonial.
145
+
146
+ ### Ecommerce and application
147
+
148
+ - **Calendar:** `agenda`, a small calendar with the selected day's meetings, and `CalendarEvent.media`.
149
+ - **ProgressSteps:** `variant="bar"`, and `navigation={false}` for status trackers.
150
+ - **OrderHistory:** `Order.progress`.
151
+ - **ShoppingCart:** a `summary` slot and `related` products.
152
+ - **OrderSummary:** line `hint`.
153
+ - **ProductReviews:** `avatars`.
154
+ - **ProductList:** `variant="overlay"`.
155
+ - **DescriptionList:** `variant="striped"`.
156
+ - **StackedList:** an item `meta` column and `chevrons`.
157
+
158
+ ### Fixed
159
+
160
+ - Dismissing a component no longer drops focus to the page body when the next focusable element is inside a closed `<details>`.
161
+
162
+ ### Internal
163
+
164
+ - The stylesheet is split into one file per family (foundation, overlays, application, data, calendar, marketing, docs, ecommerce), with one section per component. Rendering is unchanged. `@tonycodes-ui/mortar/styles.css` is still the only entry point.
165
+
166
+ ## 0.6.0 (2026-10-19)
167
+
168
+ **Breaking.** Every component now follows one set of API conventions ([DESIGN.md](https://github.com/tonycodes/mortar/blob/main/DESIGN.md#api-conventions)). Old prop names were removed rather than aliased. **See [Migrating to 0.6](https://github.com/tonycodes/mortar/blob/main/docs/migrating-to-0.6.md)** for every old → new change.
169
+
170
+ ### Added
171
+
172
+ - **TabNav:** tabs that are page links.
173
+ - **SectionHeading:** a `tabs` row.
174
+ - **EmptyState:** `dashed`, `align`, `headingLevel` and starting-point `children`. `description` is optional.
175
+ - **Avatar:** an icon `placeholder`, `statusPosition` and `decorative`.
176
+ - **Grouping:** Table `groups` and DataTable `groupBy` (sorting stays within each group).
177
+ - **MetricGroup:** `trend`, `previous` and `variant="cards"`.
178
+ - **GridList:** `details` and split actions.
179
+ - **Hero:** `background`.
180
+ - **FAQ:** `center` and `grid` layouts.
181
+ - **Pricing:** `layout="detailed"`.
182
+ - **StatGroup:** descriptions.
183
+ - **LogoCloud:** `grid` and `split` layouts.
184
+ - **ProductList:** cards with swatches and actions.
185
+ - **ProductOverview:** `gallery="grid"`.
186
+ - **OrderHistory:** quick actions.
187
+ - **Everywhere:** `className` on every component root, `id` on every section-level component, and `headingLevel` (1–6) wherever a heading was hard-coded.
188
+ - **Exported types:** `XProps` for each component, plus `HeadingLevel`, `LinkItem` and `ItemGroup`.
189
+
190
+ ### Fixed
191
+
192
+ - **Themes:** menus, listboxes, popovers and dialogs inside `ThemeProvider scope="container"` keep the container's theme and focus ring. A light container inside a dark page stays light.
193
+ - **ThemeProvider:** a nested provider keeps the router adapter, and server rendering no longer causes a hydration mismatch.
194
+ - **Focus no longer drops to the page body:**
195
+ - on loading buttons
196
+ - at either end of Pagination
197
+ - when dismissing a Toast, Notice or Banner
198
+ - when removing a FilterChip, cart line or filter
199
+ - **Screen readers:**
200
+ - errors on Input, Select, TextArea, Listbox and Combobox are announced
201
+ - status messages use persistent live regions
202
+ - a toast is announced once
203
+ - the composer announces its count only near the limit
204
+ - **Tabs:** stay reachable when the value matches no tab, and follow right-to-left arrow keys. CodeTabs supports Home/End.
205
+ - **DataTable:** select-all keeps selections made on other pages.
206
+ - **Calendar:** switching view shows the current date, it follows a changed `selected` prop, and week event names are spaced.
207
+ - **ProductFilters:** Clear all clears every facet.
208
+ - **ProductOverview:** the gallery resets when its images change, and the add button submits the form.
209
+ - **Pricing:** no longer mixes annual and monthly prices.
210
+ - **Accessibility:**
211
+ - PlanComparison reads "Included"/"Not included".
212
+ - MarketingHeader no longer creates duplicate ids.
213
+ - Menu buttons pass label-in-name.
214
+ - Sidebar and DocsShell group labels are no longer headings.
215
+ - **CSS:**
216
+ - link colour no longer leaks under the green brand
217
+ - stripes no longer hide selected rows
218
+ - selected states are visible in forced-colours mode
219
+ - component styles no longer leak into slot content
220
+ - tab-panel padding is scoped to Mortar's tabs
221
+
222
+ ### Internal
223
+
224
+ - **Manifests:** they hold only the hand-written contract. `npm run catalog` generates each entry's version, fingerprints and `contract.propTypes` from TypeScript into `catalog.json`.
225
+ - **Baseline policy 1.3.0:** adds M010, which requires manifest dependencies to match what each component renders.
226
+ - **Releases:** a merged version bump publishes automatically ([CONTRIBUTING.md](https://github.com/tonycodes/mortar/blob/main/CONTRIBUTING.md)).
227
+
228
+ ## 0.5.0 (2026-10-18)
229
+
230
+ - **AttachmentList:** file rows with an accessible download link.
231
+ - **CallToAction:** `media`.
232
+ - **NotFound:** illustration.
233
+ - **SignInPanel:** `aside`.
234
+ - **MetricGroup:** icons.
235
+ - **Toast:** `secondaryAction`.
236
+ - **PageHeading:** `meta` and `avatar`.
237
+ - **CommandPalette:** item icons.
238
+
239
+ ## 0.4.0
240
+
241
+ - **Info tone:** `Tone` gains `info`, backed by `--m-info` tokens. Every status tone meets 4.5:1 on every background.
242
+ - **Toast:** leading avatars.
243
+ - **ActivityFeed:** actors and comments.
244
+ - **StackedList:** groups with sticky headings.
245
+ - **SlideOver:** `lg` and `xl` sizes.
246
+ - **Testimonial:** logo and avatar.
247
+ - **TeamGrid:** bios and profile links.
248
+ - **Footer:** social links.
249
+ - **Fixed:** restored contract docs for Input and AppShell props that were missing from the 0.2.0 and 0.3.0 catalogues.
250
+
251
+ ## 0.3.0
252
+
253
+ - **Calendar:** week, day and year views, with events gaining start and end times.
254
+ - **CommentComposer:** a new component.
255
+ - **Dropdown:** icons, descriptions and sections.
256
+ - **Button:** sizes and icons.
257
+ - **Notice:** actions and dismiss.
258
+ - **Tabs:** counts and icons.
259
+ - **Pagination:** numbered pages.
260
+ - **EmptyState:** icons.
261
+ - **Checkbox and Switch:** descriptions.
262
+ - **RadioGroup:** cards and swatches.
263
+ - **Navigation:** expandable groups.
264
+ - **Avatar:** `xs` and `xl` sizes.
265
+
266
+ ## 0.2.0
267
+
268
+ - **Components:** 107 components across five kits, up from 80. Ecommerce is a new kit.
269
+ - **Marketing:** inverse tones, accent tokens, flyouts, and HeaderSection, ContentSection and Banner.
270
+ - **Foundation:** Divider, Card, ButtonGroup, MediaObject, Fieldset, Listbox and Combobox.
271
+ - **Application:** DescriptionList, GridList, SectionHeading, Breadcrumbs, Sidebar, Navbar, ActionPanel, Calendar and StackedShell.
272
+ - **Playground:** browse by kit and category, a Preview/Code switch, and ten page templates.
273
+
274
+ ## 0.1.0
275
+
276
+ - First release.
@@ -0,0 +1,48 @@
1
+ # Contribute
2
+
3
+ Clone https://github.com/tonycodes/mortar, run `npm ci`, `npm run check` and `npm run dev`. Use `npm run test:browser` for both-theme accessibility/rendering checks. The local playground defaults to port 4340. No service registration or npm token is required.
4
+
5
+ Run `npm run check` before regenerating anything. When you change a component, its preview or shared styles, the check fails with M007 (a source or preview fingerprint changed) or M008 (the catalogue no longer matches the manifests). Review what you changed, then run `npm run catalog`. It rewrites catalog.json and prints which components' fingerprints and contracts changed; check that list matches your intent before committing. Running `npm run catalog` first would accept any drift unseen.
6
+
7
+ Use src for central implementations, previews for fixtures and manifests for contracts. Read DESIGN.md (principles and API conventions) and TESTING.md; AGENTS.md summarises the rules for coding agents. A manifest documents every prop the component declares; `tests/manifest-props.test.mjs` compares it with the TypeScript types, and rule M010 requires `contract.dependencies` to list exactly the catalogue components the source renders. `npm run catalog` generates the prop types, capabilities derived from the test contract, provenance, version and fingerprints into catalog.json. Include a reproducible issue and a regression test for fixes. Open a PR with actual check results and visual evidence. Shared shells are versioned alongside controls; applications supply content through props.
8
+
9
+ Baseline rules are versioned in baseline-policy.json. CI must use the same rules but contributors cannot authorize weakening protected checks; policy, workflow and dependency changes require maintainer review. Branch protection requires successful checks. The solo maintainer reviews and authorizes merges; a second GitHub approval is not required. Public PR runners must be isolated from release credentials and production networks.
10
+
11
+ Releases are automatic and version-driven. To release, merge a PR that bumps the version with `npm version <x.y.z> --no-git-tag-version`. `npm run check` then fails with M008 until `npm run catalog` stamps the new version onto every catalogue entry (tests/versioning.test.mjs enforces they match). The same PR renames CHANGELOG.md's `## Unreleased` section to `## <x.y.z> (<date>)`. That section becomes the GitHub release notes; a test requires it, and a release without one stops before tagging. Breaking changes before 1.0 also get a migration guide in docs/, such as [Migrating to 0.6](docs/migrating-to-0.6.md). After the required checks pass on that merge commit, the Release package workflow (.github/workflows/release.yml) acts only if the version is neither tagged on another commit nor already on npmjs.com. Its credential-free prepare job builds the exact commit with npm run release:prepare and checks the provenance record. Its publish job runs in the protected npm-release environment and never checks out or runs repository code. It holds no registry secret: it authenticates with npm trusted publishing, exchanging a short-lived GitHub OIDC token (`id-token: write`) for a short-lived publish credential, and only a job in this repository, workflow file and environment can do that. It re-verifies the archive and creates the immutable v<version> tag on that commit. It then creates the GitHub release with the archive and provenance.json, publishes that exact archive to npmjs.com with `npm publish --provenance`, and confirms (allowing for registry propagation) that npmjs.com serves the integrity recorded in the provenance. The provenance attestation on npmjs.com links the version to the workflow run that built it. Merges that do not change the version publish nothing. A version is never overwritten: an existing tag on another commit stops the release, and a rerun publishes the archive already attached to the GitHub release. Prerelease versions such as 1.0.0-rc.1 are published under the next dist-tag. The maintainer's merge of the version bump is the release authorization; agents must not open or merge version bumps on their own initiative.
12
+
13
+ Versions up to 0.11 were published to the previous owner-hosted registry (see the CHANGELOG.md migration note); new releases go to npmjs.com.
14
+
15
+ ### Maintainer setup
16
+
17
+ This is one-time configuration in npmjs.com and the GitHub repository settings; no secret is created.
18
+
19
+ 1. On npmjs.com, create the `tonycodes-ui` organisation (the `@tonycodes-ui` scope), or confirm it exists and that you own it.
20
+ 2. Add a trusted publisher to the `@tonycodes-ui/mortar` package (package settings, Trusted publisher, GitHub Actions): organisation or user `tonycodes`, repository `mortar`, workflow filename `release.yml`, environment `npm-release`. A trusted publisher is configured on an existing package. If `@tonycodes-ui/mortar` is not on npmjs.com yet, bootstrap it from a maintainer machine (with 2FA) by publishing the archive this repository packs (`npm pack` writes `tonycodes-ui-mortar-<version>.tgz`): `npm publish ./tonycodes-ui-mortar-<version>.tgz --registry https://registry.npmjs.org/ --access public`. Do not republish 0.11 under the retired package name. Then add the trusted publisher, and under the package's publishing access choose "Require two-factor authentication and disallow tokens".
21
+ 3. In GitHub, keep the `npm-release` environment restricted to `main` (and optionally add yourself as a required reviewer).
22
+ 4. In GitHub Settings › Pages, set the source to "GitHub Actions". The `github-pages` environment is created on first deployment; keep it restricted to `main`.
23
+ 5. Optional custom domain: set it in Settings › Pages (with an Actions deployment the setting, not a `CNAME` file, is what counts) and add the DNS record GitHub shows. The playground is built with a relative base, so it works at any path without a rebuild; then update `homepage` in package.json, the links in README.md, site/index.html and tests/domain.test.mjs.
24
+ 6. After the first npmjs.com release, deprecate and retire the previous owner-hosted registry and the old playground/cloud server, then delete the now-unused GitHub secrets `MORTAR_REGISTRY_TOKEN` and `PLAYGROUND_DEPLOY_KEY`, the variables `PLAYGROUND_DEPLOY_HOST` and `PLAYGROUND_KNOWN_HOSTS`, and the `playground-production` environment.
25
+
26
+ ## Pull request review
27
+
28
+ GitHub is the component review authority. Include the evidence in the PR template. CI uploads a runnable `mortar-playground-<commit>` artifact and a browser report with screenshots for both themes. Download and extract the playground, run `python3 -m http.server 4340 --bind 127.0.0.1` in that directory, and open http://127.0.0.1:4340. No package install or account is needed for this preview. Use an isolated browser profile for untrusted PR code. Never deploy PR artifacts to the production site.
29
+
30
+ Preview artifacts are review evidence, not approved releases. GitHub maintainer review and successful required checks apply to the current PR commit. Source changes invalidate prior approval. A merged change needs a new immutable package version before consumers adopt it. There is no other approval step.
31
+
32
+ ## Contributor identity
33
+
34
+ Use a contributor identity or dedicated GitHub App where available. Do not give contributors package-publishing or repository-administration credentials. For this solo-maintainer repository, passing required CI and the owner's explicit merge authorization are the review gate; no second GitHub reviewer is required. Agents must not self-authorize a merge or release.
35
+
36
+ ## Executable test contract
37
+
38
+ See [TESTING.md](TESTING.md) for profiles, state fixtures, integrity checks, execution reports and visual baselines. Run both `npm run test:browser` and `npm run test:visual`; catalogue presence or an axe pass on playground chrome is not sufficient. Baseline images and changes to the test policy require maintainer review in the PR.
39
+
40
+ ## Browsing the playground
41
+
42
+ The playground opens on an overview of the five kits: Foundation, Application, Marketing, Docs and Ecommerce (`playground/taxonomy.json`). Each kit is split into categories (for example Foundation › Form controls), shown as cards with a live, inert thumbnail and a component count. A category page lists every component in it as a framed example; a component page adds breadcrumbs, preview settings and previous/next links. Every example has a Preview/Code switch, and the Code view shows the JSX the preview renders, extracted from the fixture source with the TypeScript parser (`playground/examples.mjs`; `tests/playground-code.test.mjs` checks every component). Categories live in `playground/taxonomy.json`; `tests/playground.test.mjs` fails if a component is missing from it or listed twice, so add new components there.
43
+
44
+ Search by component, kit or category name. On narrow screens, Menu opens the same catalogue. Kit, category, component, brand, density, appearance, declared example states and the Code view are reflected in the URL, so a page can be shared or revisited. Open “Usage and component contract” for imports and prop metadata. The explorer composes the shared DocsShell with its `wide` layout; shell fixes belong in the kit, not playground CSS.
45
+
46
+ ## Automatic playground deployment
47
+
48
+ Merges to `main` automatically deploy the GitHub Pages site at https://mortar.tony.codes/ (the repository's Pages custom domain; DNS is a CNAME from `mortar.tony.codes` to `tonycodes.github.io`, not proxied), with the playground at https://mortar.tony.codes/playground/, after the required checks pass on the merged commit. On a push to `main`, the checks workflow builds the site with no deployment credential: `site/index.html` at the root and the playground under `playground/`, built with a relative base (`--base ./`) so it also works on a custom domain. The separate Deploy playground workflow (.github/workflows/deploy-playground.yml) downloads that exact artifact, skips superseded commits, and deploys it with `actions/deploy-pages` in the `github-pages` environment; it never checks out or runs repository code. Failed checks leave the current site unchanged. This does not publish a package; only a merged version bump does (see above).
package/DESIGN.md ADDED
@@ -0,0 +1,51 @@
1
+ # Mortar design principles
2
+
3
+ 1. **shell-first** — Choose the shared purpose shell before composing a page. Use AppShell for application screens and MarketingHeader for public pages. Document deliberate standalone exceptions.
4
+
5
+ 2. **page-pattern-reuse** — Reuse complete page patterns: navigation, headings, filters, list/detail workspaces, states and action placement. Reusing controls alone is insufficient.
6
+
7
+ 3. **project-agnostic-chrome** — Keep product names, routes, user data, permissions and actions in props and slots. Shared chrome must remain project agnostic. The marketing header logo is a slot. Every component root exposes `data-m-component` with the component's name for tests and consumers. It is not a styling hook.
8
+
9
+ 4. **central-fixes** — Contribute missing patterns centrally. Do not duplicate source, create repeated local wrappers or apply consumer CSS overrides.
10
+
11
+ 5. **semantic-themes** — Use semantic tokens; keep brand separate from appearance and feedback colours. Verify every supported theme. Accent is a brand token, separate from ink, surface, and the feedback colours. Brands declare only the `--m-brand-*` contract (`--m-brand-l-*`, `--m-brand-d-*` and the brand fonts); each appearance resolves `--m-accent`, `--m-on-accent`, `--m-accent-fill`, the surfaces and their `--m-inv-*` twins from it, so every brand gets both without brand-specific CSS. A runtime brand comes from ThemeProvider `brandTokens`. CallToAction and a featured Pricing card use the page surface unless `tone="inverse"` opts into the inverse token remap. `ThemeProvider` `scope="container"` paints those tokens on a wrapper and leaves the document unchanged. The default scope is `document`.
12
+
13
+ 6. **interaction-quality** — Verify responsive layout, accessible names, keyboard operation, focus and loading/empty/error states. Automated checks alone cannot prove visual quality. A plan that is not available exposes a status and does not offer a purchase link. Column titles accept an explicit heading level so a page can keep a single `h1`.
14
+
15
+ The machine-readable contract is design-principles.json. Both the local contribution workflow and the open MCP server (`mortar mcp`, [docs/agents.md](docs/agents.md)) expose these principles. Detection is split between structural checks and visual maintainer review.
16
+
17
+ ## API conventions
18
+
19
+ Every component follows these rules. New props must fit them, and the code review checks them.
20
+
21
+ - **Headings.** `headingLevel` sets the component's outermost heading (`1`–`6`, using the shared `HeadingLevel` type). Nested headings derive from it (`level + 1`). `itemHeadingLevel` is added only where items need their own level. No component hard-codes a heading that sits inside a page section. `h1` belongs to the page, so only components that open a page default to it: PageHeading, NotFound, Hero, HeaderSection, ProductOverview, AuthLayout and SignInPanel. Use a lower level when one of them sits below another page heading.
22
+ - **Layout, variant and align.**
23
+ - `layout` chooses the structural arrangement, for example `"split" | "grid" | "center"`.
24
+ - `variant` chooses the visual treatment, for example `"underline" | "pills"` or `"plain" | "cards"`.
25
+ - `align` only ever takes `"start" | "center" | "end"`.
26
+ - Values are single words in the same form everywhere: `center`, never `centered`; `cards`, never `card`.
27
+ - Tables align columns with `start | end`, not `left | right`.
28
+ - **Tone.**
29
+ - Status uses `Tone` (`neutral | info | success | warning | danger`).
30
+ - Section surfaces use `tone: "default" | "muted" | "inverse"`. Promotional bands (CallToAction, Hero and Banner) also take `"accent"`: the brand's accent fill, which is its accent gradient when it defines one, with on-accent text. Button and ActionLink take the same fill as `variant="accent"`. Each component offers only the tones it styles.
31
+ - A destructive action is `tone="danger"`, and a destructive item in a list is `danger: true`.
32
+ - Tone renders as `data-tone`.
33
+ - **State.** Busy work is `loading`. Empty content is `empty?: { title; description?; action? }`. Errors are `error` (string).
34
+ - A loading button stays focusable: it sets `aria-busy` and `aria-disabled` and ignores activation instead of becoming natively disabled.
35
+ - A field `error` is announced when it appears (`role="alert"`). `required` marks the control (native `required` or `aria-required`) and adds a decorative `*` after the label. A group (RadioGroup) puts its message under the legend and describes the fieldset with it.
36
+ - A failed submit also lists its field errors in an ErrorSummary above the form. It takes focus after each failed submit, and each link focuses its field.
37
+ - Status and alert regions stay mounted, and their content changes, so each message is announced once.
38
+ - Dismissing or removing an element that holds focus moves focus to the next control, never to the page body.
39
+ - **Callbacks.** Value changes use `onChange(value)`. Choosing an item or action uses `onSelect`. Dismissal uses `onDismiss` and closing uses `onClose`.
40
+ - **Items.**
41
+ - Links share `LinkItem` (`label`, `href`, `current?`, `icon?`, `count?`, `description?`), and grouped items share `{ label; items }`.
42
+ - A visible heading prop is `title`, and an accessible name prop is `label`.
43
+ - **Identity.** Every section-level component accepts `id` so in-page links can target it. Generated ids come from `useId`; ids are never hard-coded.
44
+ - **className.** Every component accepts `className` on its root element, merged with the kit's classes. It is for layout such as margins or grid placement. Colour and type come from tokens and props, never consumer overrides (principle 4).
45
+ - **Component marker.** The root element of every exported component carries `data-m-component="<ExportName>"`, set through `componentRoot()` in `src/internal.tsx`. The root is the outermost element the component renders. A dialog marks its dialog root, which is portalled to the document body and exists only while open. A component that renders sibling elements marks the first one it always renders (SaveBar's status message). When one component renders another as its root, the root carries the outer name (SearchDialog, not CommandPalette). ThemeProvider marks its wrapper only with `scope="container"`; with the default document scope it renders no element of its own. Nested components keep their own markers. The marker is for tests and consumers to find components, never for consumer styles. Its one selector in the kit is internal: Prose styles stop at a nested component root, so a utility class such as `m-4` inside prose keeps its prose styles.
46
+ - **Data attributes.** A boolean attribute appears only when true (`data-x="true"`). An enum attribute is omitted for the default value. Styles select on these attributes, never on text or `aria-label`.
47
+ - **Icons and decoration.** Shared icons come from `src/icons.tsx` and are `aria-hidden`. Decorative glyphs such as arrows are hidden from assistive technology, and their meaning is carried by text.
48
+
49
+ ## Composing flows
50
+
51
+ A multi-step flow is a set of pages built from the same shell and fields, not a new component per step. Sign-in and registration use AuthLayout as the page, with ProviderButtons, PasswordInput and CodeInput: [Sign-in and registration flows](docs/auth-flows.md) maps every step (sign in, sign up, reset, verify, two-factor) to components, autocomplete values and accessibility and security rules. The playground has a page template for each step.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tony James and Mortar contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,156 @@
1
- # Temporary Holding Version
1
+ # Mortar
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A shared design foundation and purpose-built Application UI, Marketing UI, Docs UI and Ecommerce kits for React 19 and Tailwind CSS 4. MIT licensed. No account, token, registry connection or subscription is required to use the kit, including use by coding agents.
4
+
5
+ The package is [`@tonycodes-ui/mortar` on npmjs.com](https://www.npmjs.com/package/@tonycodes-ui/mortar). Releases are immutable, publicly installable without any account or token, and published with npm provenance that links each version to the GitHub Actions run that built it. Publishing is automatic and version-driven: merging a version bump to `main` publishes that version once the required checks pass ([release workflow](.github/workflows/release.yml), [process](CONTRIBUTING.md)). The current version is listed on the [GitHub releases](https://github.com/tonycodes/mortar/releases) page. Source, issues and contributions live at [github.com/tonycodes/mortar](https://github.com/tonycodes/mortar).
6
+
7
+ [Explore the live playground](https://mortar.tony.codes/playground/) · [Contribute](CONTRIBUTING.md) · [Free and open](#free-and-open)
8
+
9
+ ## See the kit
10
+
11
+ These screenshots show the kit running in the public playground. All product names,
12
+ plans, prices and support labels inside the examples are demonstration content,
13
+ not Mortar offers. The playground follows `main`; screenshots may show components
14
+ that are not yet in the latest npm release.
15
+
16
+ **Marketing UI — a composed landing page in light mode.**
17
+
18
+ [![Mortar marketing components composing a landing page with navigation, hero, actions and a chat preview](docs/images/marketing-light.jpg)](https://mortar.tony.codes/playground/?recipe=saas-landing&theme=light)
19
+
20
+ **Application UI — a semantic table in dark mode, inside the shared explorer.**
21
+
22
+ [![Mortar dark-mode playground showing the Table component and preview controls](docs/images/application-dark.jpg)](https://mortar.tony.codes/playground/?component=Table&theme=dark)
23
+
24
+ **Docs UI — navigation, search and an article outline using the shared DocsShell.**
25
+
26
+ [![Mortar light-mode DocsShell preview with grouped navigation, search and a table of contents](docs/images/documentation-light.jpg)](https://mortar.tony.codes/playground/?component=DocsShell&theme=light)
27
+
28
+ Open any screenshot to try its live example. Switch appearance, brand, density and
29
+ example states in the playground.
30
+
31
+ ## Install
32
+
33
+ ```sh
34
+ npm install @tonycodes-ui/mortar react react-dom tailwindcss
35
+ ```
36
+
37
+ No account, token or registry configuration is needed: the package is public on npmjs.com. Versions 0.11 and earlier were published only to the previous owner-hosted registry; if a project pins one of them, or still has that registry's scope override in its `.npmrc`, see the [CHANGELOG](CHANGELOG.md) migration note.
38
+
39
+ ## Agents and MCP
40
+
41
+ The package includes a free, local MCP server and CLI for coding agents. They read the installed version's catalogue, contracts, examples and guides, work offline and need no account:
42
+
43
+ ```sh
44
+ claude mcp add mortar -- npx -y @tonycodes-ui/mortar mcp
45
+ npx mortar search "sign in"
46
+ npx mortar audit .
47
+ ```
48
+
49
+ Tools: `search_components`, `get_component`, `get_build_packet`, `get_guide`, `list_kits` and `audit_app`. See [Mortar for coding agents](docs/agents.md) for other MCP clients, the workflow and the audit rules, and [skills/mortar/SKILL.md](skills/mortar/SKILL.md) for a ready-made agent skill.
50
+
51
+ ## Changes and upgrades
52
+
53
+ See [CHANGELOG.md](CHANGELOG.md) for every release. [Theming](docs/theming.md) explains brands, appearance, density and the token scales. [Sign-in and registration flows](docs/auth-flows.md) maps each auth step to components, autocomplete values and security notes. Upgrading from 0.5 or earlier? [Migrating to 0.6](docs/migrating-to-0.6.md) lists every renamed prop.
54
+
55
+ ## Local install
56
+
57
+ Pack from this workspace (`npm pack` builds `dist` first):
58
+
59
+ ```sh
60
+ npm pack
61
+ ```
62
+
63
+ Install the resulting `tonycodes-ui-mortar-<version>.tgz` in the consuming app, with React 19, React DOM 19 and Tailwind 4. Public releases come from npmjs.com.
64
+
65
+ In the app's Tailwind CSS entry:
66
+
67
+ ```css
68
+ @import "tailwindcss";
69
+ @import "@tonycodes-ui/mortar/styles.css";
70
+ ```
71
+
72
+ The package ships its component styles. No source scanning or account is required.
73
+
74
+ ```tsx
75
+ import { ThemeProvider, AppShell, Button } from "@tonycodes-ui/mortar";
76
+
77
+ <ThemeProvider brand="neutral" density="comfortable" initialAppearance="system">
78
+ <AppShell
79
+ brand="Example"
80
+ navigation={[{ label: "Overview", href: "/", current: true }]}
81
+ >
82
+ <Button onClick={save}>Save changes</Button>
83
+ </AppShell>
84
+ </ThemeProvider>;
85
+ ```
86
+
87
+ `brand` (`neutral | green`) and `density` (`compact | comfortable | spacious`) are controlled provider props. Appearance (`light | dark | system`) is changed using `AppearanceControl`; system changes are observed. Use one root provider. It restores document attributes on unmount. The provider uses effects: SSR applications should set matching initial document attributes to prevent a first-paint theme flash.
88
+
89
+ ## Purpose kits
90
+
91
+ The catalogue assigns each export to one purpose. Foundation primitives serve all purpose kits. Application UI provides shells, page headings, metrics, selectable tables, settings and activity. Marketing UI provides headers, heroes, features, social proof, pricing, FAQs, calls to action and footers. Docs UI provides a shared documentation shell, search, code examples, API references and article navigation. Ecommerce provides product lists, product overviews with option pickers, shopping carts and order summaries; prices arrive preformatted so currency and locale stay with the consumer. Product content and callbacks remain in the consumer. Sample names and prices belong only in the catalogue demonstrations.
92
+
93
+ Controls use native HTML and Headless UI. Tabs support arrow/Home/End navigation; dialogs and menus use Headless UI focus management. Density has a 44px control floor on coarse pointers. Feedback colours remain separate from the brand.
94
+
95
+ ## Free and open
96
+
97
+ Everything is free and lives in this repository under the MIT licence: the kit,
98
+ its documentation, the playground and the agent tooling. Use, customise and
99
+ contribute to it, including in commercial projects and agent-assisted development.
100
+ There are no accounts, licence checks, telemetry, paid plans or hosted service;
101
+ the kit makes no network calls of its own.
102
+
103
+ - **Packages** are published to [npmjs.com](https://www.npmjs.com/package/@tonycodes-ui/mortar)
104
+ from GitHub Actions with provenance.
105
+ - **The playground** is hosted on [GitHub Pages](https://mortar.tony.codes/playground/).
106
+ - **Bugs and contributions** go through [GitHub issues](https://github.com/tonycodes/mortar/issues)
107
+ and [pull requests](CONTRIBUTING.md); GitHub maintainer review is the only review
108
+ gate. This is community maintenance, not a paid support entitlement. Do not put
109
+ credentials or private project details in issues.
110
+
111
+ ## Run the playground locally
112
+
113
+ ```sh
114
+ npm ci
115
+ npm run dev
116
+ ```
117
+
118
+ Open `http://127.0.0.1:4340`. The playground is this repository's standalone Vite
119
+ application, built directly from `src`, `previews` and the component catalogue.
120
+ It is the local visual development surface for new and updated components.
121
+ No service account or backend is required.
122
+
123
+ In production it is deployed to GitHub Pages at
124
+ [mortar.tony.codes/playground/](https://mortar.tony.codes/playground/).
125
+ Merges to `main` deploy it after checks pass; the Pages site root
126
+ (`site/index.html`) links the playground, GitHub, npm and the docs. Package
127
+ releases have their own workflow (see [CONTRIBUTING.md](CONTRIBUTING.md)).
128
+
129
+ ## Client-side routing
130
+
131
+ Connect your application's router once at the provider. All kit-owned links
132
+ (including AppShell, DocsShell, MarketingHeader, breadcrumbs, tables and action
133
+ links) use this adapter for ordinary same-origin navigation:
134
+
135
+ ```tsx
136
+ <ThemeProvider
137
+ navigate={(href) => {
138
+ router.push(href);
139
+ }}
140
+ >
141
+ <App />
142
+ </ThemeProvider>
143
+ ```
144
+
145
+ For React Router, pass its `useNavigate()` function through a void-returning
146
+ callback. The router must render the destination and manage route focus/scroll.
147
+ Return `false` for routes your router does not handle. Without an adapter, links
148
+ retain native browser navigation. External links, downloads, same-page fragments,
149
+ modified clicks and new-tab links remain native. Consumer-authored anchors still
150
+ belong to the consumer's router; this does not intercept the whole document.
151
+
152
+ Theme selection can also be controlled with `appearance` and
153
+ `onAppearanceChange`; `initialAppearance` remains the uncontrolled starting value.
154
+ Brand and density already update through their provider props. None of these
155
+ settings requires reloading the page. Existing apps must install a release
156
+ containing this API, wire their router, and rebuild to adopt it.