themelia-ui 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/themelia-ui/SKILL.md +38 -9
- package/.agents/skills/themelia-ui/manifest.json +23 -0
- package/.agents/skills/themelia-ui/references/api-compatibility.md +3 -2
- package/.agents/skills/themelia-ui/references/blocks.md +123 -0
- package/.agents/skills/themelia-ui/references/composition-ladder.md +8 -8
- package/.agents/skills/themelia-ui/references/composition.md +98 -1
- package/.agents/skills/themelia-ui/references/forms.md +23 -3
- package/.agents/skills/themelia-ui/references/framework-wiring.md +34 -6
- package/.agents/skills/themelia-ui/references/i18n.md +4 -2
- package/.agents/skills/themelia-ui/references/imports.md +1 -1
- package/.agents/skills/themelia-ui/references/installation.md +5 -4
- package/.agents/skills/themelia-ui/references/migration.md +22 -2
- package/.agents/skills/themelia-ui/references/provider-and-scoping.md +27 -9
- package/.agents/skills/themelia-ui/references/reference-workflows.md +43 -0
- package/.agents/skills/themelia-ui/references/structure-and-spacing.md +147 -0
- package/.agents/skills/themelia-ui/references/theming.md +6 -2
- package/.agents/skills/themelia-ui/references/troubleshooting.md +28 -5
- package/.agents/skills/themelia-ui/references/verification.md +58 -2
- package/CHANGELOG.md +25 -0
- package/README.md +3 -0
- package/dist/{alert-dialog-Bmo1YrTm.js → alert-dialog-Cg2HhuBe.js} +1 -1
- package/dist/base/alert-dialog.js +1 -1
- package/dist/base/cards.js +1 -1
- package/dist/base/choice-inputs.js +1 -1
- package/dist/base/combobox.js +1 -1
- package/dist/base/command.js +1 -1
- package/dist/base/date-pickers.js +1 -1
- package/dist/base/dialog.js +1 -1
- package/dist/base/display.js +1 -1
- package/dist/base/forms-numeric.js +1 -1
- package/dist/base/forms.js +1 -1
- package/dist/base/item.js +1 -1
- package/dist/base/navigation.js +1 -1
- package/dist/base/otp-input.js +1 -1
- package/dist/base/overlay.js +1 -1
- package/dist/base/popover-menu.js +1 -1
- package/dist/base/repeaters.js +1 -1
- package/dist/base/sheet.js +1 -1
- package/dist/base/sidebar.js +1 -1
- package/dist/base/skeleton.js +1 -1
- package/dist/base/structure.js +1 -1
- package/dist/base/timeline.js +1 -1
- package/dist/base/upload.js +1 -1
- package/dist/base/value-inputs.js +1 -1
- package/dist/blocks/admin/access.js +2 -2
- package/dist/blocks/admin/commerce.js +9 -9
- package/dist/blocks/analytics.js +3 -3
- package/dist/blocks/onboarding.js +1 -1
- package/dist/blocks/timelines.js +1 -1
- package/dist/{cards-DdiICdMM.js → cards-Ddhz43Bz.js} +2 -2
- package/dist/{choice-inputs-CCw-0gD6.js → choice-inputs-NwRxvmZN.js} +2 -2
- package/dist/combobox-519ubijc.js +292 -0
- package/dist/{command-CnB_IZSo.js → command-JjApYFds.js} +2 -2
- package/dist/{comments-C6Y_ddMt.js → comments-CCQ2QRaU.js} +4 -4
- package/dist/components/base/display/icon-badge.d.ts +2 -2
- package/dist/components/base/forms/form-field.d.ts +2 -2
- package/dist/components/base/structure/bleed.d.ts +1 -0
- package/dist/components/base/structure/grid.d.ts +8 -2
- package/dist/components/base/structure/split.d.ts +1 -0
- package/dist/components/features/combobox/fetching-combobox.d.ts +2 -1
- package/dist/components/features/combobox/resource-combobox.d.ts +3 -0
- package/dist/components/features/combobox/use-suggestions.d.ts +7 -0
- package/dist/css/structure.css +1 -1
- package/dist/{date-pickers-C2HgjpFU.js → date-pickers-BwCwKIVM.js} +1 -1
- package/dist/{dialog-0nRFg5Zs.js → dialog-CAnwRNrm.js} +1 -1
- package/dist/{display-BGN834xV.js → display-a7AoX_u7.js} +1 -1
- package/dist/features/actions.js +1 -1
- package/dist/features/activities.js +3 -3
- package/dist/features/ai-chat.js +2 -2
- package/dist/features/combobox.js +285 -273
- package/dist/features/comments.js +1 -1
- package/dist/features/data-view.js +5 -5
- package/dist/features/event-calendar.js +3 -3
- package/dist/features/filters.js +1 -1
- package/dist/features/global-search.js +4 -4
- package/dist/features/map.js +2 -2
- package/dist/features/media-library.js +8 -8
- package/dist/features/mentions.js +1 -1
- package/dist/features/overlays.js +1 -1
- package/dist/features/products.js +9 -9
- package/dist/features/resource-assignment.js +3 -3
- package/dist/features/resource.js +3 -3
- package/dist/features/schema-form.js +6 -6
- package/dist/features/sync.js +2 -2
- package/dist/features/table.js +1 -1
- package/dist/features/theme-tweaker.js +10 -10
- package/dist/{filters-geLuSlFL.js → filters-BhsTkWpZ.js} +9 -9
- package/dist/{forms-NxbJK4Mh.js → forms-C0WeNPFF.js} +1 -1
- package/dist/{forms-numeric-C6NMdj6G.js → forms-numeric-IwQ1ltNf.js} +1 -1
- package/dist/hooks/use-native-dialog.d.ts +1 -1
- package/dist/{item-CuUJyETl.js → item-M2pmpWXh.js} +1 -1
- package/dist/layout/app-shell.js +1 -1
- package/dist/layout/auth.js +1 -1
- package/dist/layout/header.js +3 -3
- package/dist/layout/navigation.js +1 -1
- package/dist/layout/page.js +2 -2
- package/dist/layout/settings.js +2 -2
- package/dist/layout/sidebar.js +10 -6
- package/dist/layout/workspace.js +3 -3
- package/dist/lib/ui-provider/ui-scope.d.ts +1 -1
- package/dist/{mentions-oeYNv_j1.js → mentions-BOxbigwp.js} +2 -2
- package/dist/{navigation-BTX5Ti0Z.js → navigation-Bgu7Vc0M.js} +2 -2
- package/dist/{navigation-WYKjDhZq.js → navigation-DiYACqpE.js} +2 -2
- package/dist/{overlay-C8RAgi2_.js → overlay-BuQOl8aP.js} +5 -5
- package/dist/{overlays-9BxwFTou.js → overlays-1sULyytH.js} +5 -5
- package/dist/{popover-menu-DcLeiw9r.js → popover-menu-QXgQeWeG.js} +1 -1
- package/dist/{repeaters-DfptvbGA.js → repeaters-CeH20dvr.js} +4 -4
- package/dist/{sheet-D-DVZH_b.js → sheet-CJ1-OAla.js} +1 -1
- package/dist/{sidebar-DXQOy_Cb.js → sidebar-D8uGqxio.js} +4 -4
- package/dist/{skeleton-CubvHel9.js → skeleton-BTKNKTdj.js} +1 -1
- package/dist/{structure-B9Y5NkP_.js → structure-CynEZ-OY.js} +1 -2
- package/dist/style.css +1 -1
- package/dist/styles/TOKENS.md +4 -3
- package/dist/{table-DT_20ity.js → table-B7dtIFUx.js} +4 -4
- package/dist/{timeline-BRZbSdhf.js → timeline-BR_jNgvz.js} +1 -1
- package/dist/{timelines-DczZKW5p.js → timelines-DXG1BfIN.js} +1 -1
- package/dist/{upload-C_6mlbfl.js → upload-CYuoJykZ.js} +1 -1
- package/dist/{value-inputs-CnO6RZeT.js → value-inputs-ng8aVJJZ.js} +4 -4
- package/docs/README.md +11 -1
- package/docs/build/browser-composition-fixture.ts +28 -0
- package/docs/build/recipes.md +398 -1
- package/docs/generated/component-index.json +1993 -862
- package/docs/generated/components/base--display.md +2 -2
- package/docs/generated/components/base--forms.md +72 -1
- package/docs/generated/components/base--structure.md +56 -5
- package/docs/generated/components/base--typography.md +38 -0
- package/docs/generated/components/blocks--admin--access.md +10 -0
- package/docs/generated/components/blocks--analytics.md +44 -0
- package/docs/generated/components/features--combobox.md +67 -0
- package/docs/generated/components/features--data-view.md +59 -3
- package/docs/generated/components/features--filters.md +10 -0
- package/docs/generated/components/features--media-library.md +68 -0
- package/docs/generated/components/features--overlays.md +54 -0
- package/docs/generated/components/features--rich-text-editor.md +38 -0
- package/docs/generated/components/layout--app-shell.md +31 -0
- package/docs/generated/components/layout--containers.md +40 -0
- package/docs/generated/components/layout--page.md +30 -1
- package/docs/generated/components/layout--sidebar.md +41 -0
- package/docs/generated/components/ui-provider.md +1 -1
- package/docs/generated/composition-ladder.md +8 -8
- package/docs/generated/consumer-contract.json +5736 -0
- package/docs/generated/imports.md +1 -1
- package/docs/generated/recipes.json +171 -1
- package/docs/generated/workflows/communications-overview/analytics/communications-reference.tsx +19 -0
- package/docs/generated/workflows/index.json +691 -0
- package/docs/generated/workflows/media-picking/media-library/media-picking-reference.tsx +63 -0
- package/docs/generated/workflows/media-picking/media-library/reference-data.ts +3 -0
- package/docs/generated/workflows/multi-section-form/form-workflow/multi-section-reference.tsx +46 -0
- package/docs/generated/workflows/nested-action-flow/action-overlays/nested-action-reference.tsx +39 -0
- package/docs/generated/workflows/record-detail/page-layout/record-detail-reference.tsx +24 -0
- package/docs/generated/workflows/resource-index/data-view/resource-index-reference.tsx +51 -0
- package/docs/generated/workflows/scoped-resource-selection/combobox/scoped-resource-reference.tsx +50 -0
- package/docs/generated/workflows/website-content-editor/media-library/reference-data.ts +3 -0
- package/docs/generated/workflows/website-content-editor/rich-text-editor/website-content-reference.tsx +33 -0
- package/docs/generated/workflows/workspace-navigation/app-shell/workspace-navigation-reference.tsx +26 -0
- package/docs/learn/api-compatibility.md +3 -2
- package/docs/learn/blocks.md +123 -0
- package/docs/learn/composition.md +98 -1
- package/docs/learn/forms.md +23 -3
- package/docs/learn/framework-wiring.md +34 -6
- package/docs/learn/i18n.md +4 -2
- package/docs/learn/installation.md +5 -4
- package/docs/learn/migration.md +22 -2
- package/docs/learn/provider-and-scoping.md +27 -9
- package/docs/learn/reference-workflows.md +43 -0
- package/docs/learn/structure-and-spacing.md +147 -0
- package/docs/learn/theming.md +6 -2
- package/docs/learn/troubleshooting.md +28 -5
- package/docs/learn/verification.md +58 -2
- package/package.json +4 -1
- package/scripts/consumer/codemod.mjs +3 -24
- package/scripts/consumer/contract-reader.mjs +42 -0
- package/scripts/consumer/css-scan.mjs +51 -0
- package/scripts/consumer/diagnose.mjs +136 -0
- package/scripts/consumer/find-component.mjs +28 -13
- package/scripts/consumer/install-skill.mjs +93 -11
- package/src/styles/TOKENS.md +4 -3
- package/dist/combobox-Byu8N-Oe.js +0 -274
package/docs/learn/forms.md
CHANGED
|
@@ -69,9 +69,10 @@ consumer on plain state never resolves react-hook-form.
|
|
|
69
69
|
|
|
70
70
|
## Field chrome
|
|
71
71
|
|
|
72
|
-
`FormField` renders
|
|
73
|
-
hint`. They replace each other rather than stacking
|
|
74
|
-
|
|
72
|
+
`FormField` renders at most **one** supporting message, resolved as `error || helperText ||
|
|
73
|
+
hint`. They replace each other rather than stacking. A message can wrap, and adding or
|
|
74
|
+
changing it can change field height; check long translated errors at narrow widths.
|
|
75
|
+
It also owns the wiring: it associates the label, points
|
|
75
76
|
`aria-describedby` at the supporting line, and sets `aria-invalid` on the control when there
|
|
76
77
|
is an error, without overriding any of these that the caller set explicitly. Errors are
|
|
77
78
|
announced politely (`role="status"`), so validation firing on each keystroke does not
|
|
@@ -80,6 +81,25 @@ interrupt typing.
|
|
|
80
81
|
`FieldGroup` covers several controls sharing one label and one supporting line — a date
|
|
81
82
|
range, a name split in two.
|
|
82
83
|
|
|
84
|
+
## Sections and completion
|
|
85
|
+
|
|
86
|
+
Use FormSection for an editable region inside a form, Card for an independent subject,
|
|
87
|
+
and ContentBlock for supporting read-only prose. Flat FormSections retain region padding;
|
|
88
|
+
an enclosing Stack can use `gap="none"` when that padding supplies the desired separation.
|
|
89
|
+
FieldGroup supplies fieldset/legend semantics. Each child FormField still needs a distinct
|
|
90
|
+
label. A section heading is not a field label.
|
|
91
|
+
|
|
92
|
+
A resolved promise is not evidence that validation succeeded. ActionDialog normally closes
|
|
93
|
+
after its confirmation callback resolves. Set `closeOnAsyncComplete={false}` when the app
|
|
94
|
+
resolves with errors, and close controlled `open` only after explicit success. For a native
|
|
95
|
+
form, use `formId` to associate the dialog's submit action with that form; avoid also invoking
|
|
96
|
+
the mutation in `onConfirm`. Native constraint validation, the submit handler and domain
|
|
97
|
+
validation then each have one owner. Prevent duplicate submissions while pending, retain
|
|
98
|
+
drafts after rejection and associate errors with the relevant field or root region.
|
|
99
|
+
|
|
100
|
+
See the complete [multi-section form and nested action](./reference-workflows.md) sources.
|
|
101
|
+
For the inset and gap contract, see [Structure and spacing](./structure-and-spacing.md#use-the-two-spacing-roles).
|
|
102
|
+
|
|
83
103
|
## Generated forms
|
|
84
104
|
|
|
85
105
|
When the fields come from a schema at runtime, use `features/schema-form`. When they are
|
|
@@ -22,7 +22,9 @@ cells. Write it once:
|
|
|
22
22
|
import type { LinkRenderer } from "themelia-ui/layout/sidebar"
|
|
23
23
|
|
|
24
24
|
export const renderLink: LinkRenderer = ({ href, children, active, disabled, external, ...rest }) =>
|
|
25
|
-
disabled || !href ? <span {...rest}>{children}</span>
|
|
25
|
+
disabled || !href ? <span {...rest}>{children}</span>
|
|
26
|
+
: external ? <a href={href} {...rest}>{children}</a>
|
|
27
|
+
: <AppLink to={href} {...rest}>{children}</AppLink>
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
Return one element and spread the rest of the props onto it: they carry the class, the
|
|
@@ -50,6 +52,20 @@ async lifecycle; the application decides cache invalidation, retries, and error
|
|
|
50
52
|
</ResourceIndexShell>
|
|
51
53
|
```
|
|
52
54
|
|
|
55
|
+
## Lookup and navigation lifetimes
|
|
56
|
+
|
|
57
|
+
Pass a stable `scopeKey` to ResourceCombobox, SuggestionsCombobox or useSuggestions when the lookup's workspace, locale or
|
|
58
|
+
permission context changes. Changing callback identity alone does not refetch. A scope
|
|
59
|
+
change aborts old work, hides old results/errors and refetches an eligible open query while
|
|
60
|
+
retaining query, controlled value and open state. Late responses from an old scope cannot
|
|
61
|
+
complete the current lookup. The app owns whether the selected id remains valid.
|
|
62
|
+
|
|
63
|
+
Sidebar workspace disclosure keeps the mobile sheet open. A selected workspace marked
|
|
64
|
+
`external: false` dismisses the sheet after selection; external destinations retain native
|
|
65
|
+
target/rel behavior. Forward renderer props, including the click handler, to the real link.
|
|
66
|
+
The app's router handles same-app addresses and preserves modifiers and new-tab gestures.
|
|
67
|
+
See the [workspace reference](./reference-workflows.md).
|
|
68
|
+
|
|
53
69
|
## Permissions
|
|
54
70
|
|
|
55
71
|
Resolve authorization before constructing actions. Omit an action the user cannot perform;
|
|
@@ -58,16 +74,28 @@ through the module's tooltip or description seam.
|
|
|
58
74
|
|
|
59
75
|
## Translation
|
|
60
76
|
|
|
61
|
-
Supply
|
|
77
|
+
Supply component-owned copy through the selected API's documented `strings` prop. Passive
|
|
78
|
+
components whose copy comes from children need no strings object. Keep product copy
|
|
62
79
|
in application data or children. The default objects are exported so a locale can start
|
|
63
80
|
from the complete shape rather than guessing keys; see [Internationalization](./i18n.md).
|
|
64
81
|
|
|
65
82
|
## Server rendering and client boundaries
|
|
66
83
|
|
|
67
|
-
|
|
68
|
-
`
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
Interactive and provider-dependent entrypoints carry `"use client"`, including
|
|
85
|
+
`themelia-ui/primitives` and `themelia-ui/ui-provider`; passive modules such as
|
|
86
|
+
`themelia-ui/base/structure` can remain server-pure. Inspect the exact published entrypoint
|
|
87
|
+
rather than inferring its boundary from its name. In a React Server Components framework, a server component
|
|
88
|
+
can render those client components with serializable props; callbacks, hooks and live
|
|
89
|
+
controlled state belong in an application client component. A provider can receive server
|
|
90
|
+
rendered children, so keep the boundary around the interactive region rather than the whole
|
|
91
|
+
page. Check your framework's serialization rules for config containing functions or modules.
|
|
92
|
+
|
|
93
|
+
Formatting helpers exported from `primitives` share its client boundary: do not call them
|
|
94
|
+
from an RSC server component as if they came from a server-pure subpath. Format server data
|
|
95
|
+
with the application's server utilities or render the corresponding display primitive.
|
|
96
|
+
`themelia-ui/theming` exports pure derivation helpers without a client directive. Exact
|
|
97
|
+
subpaths also keep optional peers isolated. Ordinary Node SSR can load and render the
|
|
98
|
+
component modules; that does not make their exports server-callable in RSC.
|
|
71
99
|
|
|
72
100
|
For CSP, portals, nested theme regions, and defaults, use
|
|
73
101
|
[Provider and scoping](./provider-and-scoping.md). Do not recreate provider context in an
|
package/docs/learn/i18n.md
CHANGED
|
@@ -5,8 +5,10 @@ overridable, and nothing in it inspects `navigator.language` or imports a transl
|
|
|
5
5
|
|
|
6
6
|
## Strings
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Components that own visible or accessible copy document a `strings` prop; their modules
|
|
9
|
+
export the matching `*Strings` interface and `default*Strings` object. Passive structures
|
|
10
|
+
and components whose copy comes entirely from children need no strings object. Read the
|
|
11
|
+
selected API rather than adding `strings` by analogy:
|
|
10
12
|
|
|
11
13
|
```tsx fragment — shape only, not a program
|
|
12
14
|
<Copyable strings={{ copy: "Kopieren", copied: "Kopiert" }} value={apiKey} />
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
npm install themelia-ui
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
React 19 and `react-dom` are required peers.
|
|
8
|
-
|
|
7
|
+
React 19 and `react-dom` are required peers. The package's regular dependencies install
|
|
8
|
+
automatically; additional peer packages are optional and resolved only by the modules
|
|
9
|
+
that need them. See [Optional peers](#optional-peers).
|
|
9
10
|
|
|
10
11
|
## Browser support
|
|
11
12
|
|
|
@@ -107,8 +108,8 @@ releases.
|
|
|
107
108
|
|
|
108
109
|
## Optional peers
|
|
109
110
|
|
|
110
|
-
Every peer other than
|
|
111
|
-
use it: a consumer who never imports `features/map` never resolves Leaflet.
|
|
111
|
+
Every peer other than `react` and `react-dom` is optional, and each is reachable only from
|
|
112
|
+
the modules that use it: a consumer who never imports `features/map` never resolves Leaflet.
|
|
112
113
|
|
|
113
114
|
The peer-to-module table is in [`docs/generated/imports.md`](../generated/imports.md).
|
|
114
115
|
|
package/docs/learn/migration.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
3
3
|
What changes between versions, what to do when you upgrade, and which changes a stable major
|
|
4
4
|
allows.
|
|
5
5
|
|
|
6
|
+
## Upgrading to 3.2
|
|
7
|
+
|
|
8
|
+
3.2 adds consumer diagnostics, complete reference workflows and optional `scopeKey` support
|
|
9
|
+
for asynchronous combobox lookups, alongside responsive grid, dialog and navigation fixes.
|
|
10
|
+
Applications already on 3.1 need no new codemod replacements. Applications upgrading from
|
|
11
|
+
3.0 or earlier must also follow [Upgrading to 3.1](#upgrading-to-31).
|
|
12
|
+
|
|
13
|
+
After updating the package, refresh the installed consumer skill with the
|
|
14
|
+
[packaged installer](./verification.md#offline-diagnosis-and-skill-freshness). Review any
|
|
15
|
+
local edits before replacing them, then run the read-only diagnostics and your application's
|
|
16
|
+
type, build and interaction checks. The [structural guide](./structure-and-spacing.md),
|
|
17
|
+
[blocks guide](./blocks.md) and [complete workflows](./reference-workflows.md) describe the
|
|
18
|
+
public composition contracts.
|
|
19
|
+
|
|
20
|
+
For lookups whose results depend on a workspace, tenant or similar context, pass a stable
|
|
21
|
+
`scopeKey` that changes with that context. The lookup aborts and invalidates old responses;
|
|
22
|
+
the application still owns clearing a selection or query that is no longer valid. See the
|
|
23
|
+
[scoped resource selection workflow](./reference-workflows.md).
|
|
24
|
+
|
|
6
25
|
## Upgrading to 3.1
|
|
7
26
|
|
|
8
27
|
3.1 renames and removes public API as well as adding to it. Upgrade deliberately, not
|
|
@@ -83,8 +102,9 @@ selects `[data-row-density]`, `[data-media-density]` or `[data-activity-density]
|
|
|
83
102
|
colour a `light-dark(light, dark)` pair. For a theme of your own:
|
|
84
103
|
|
|
85
104
|
- Declare it on `:root` alone. The selector list 3.0 asked for (`:root, [data-ui-scope],
|
|
86
|
-
[data-density], [data-theme], .light, .dark`) is not needed:
|
|
87
|
-
|
|
105
|
+
[data-density], [data-theme], .light, .dark`) is not needed: component styles inherit the
|
|
106
|
+
root defaults. Explicit regional overrides and density presets replace their corresponding
|
|
107
|
+
inherited values; set a preset-specific spacing override on that preset.
|
|
88
108
|
- Write a dark value into the colour's pair, `--primary: light-dark(#2563eb, #60a5fa)`, rather
|
|
89
109
|
than a `.dark { … }` block, which colours a dark page but misses a dark region inside a light
|
|
90
110
|
one.
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Provider and scoping
|
|
2
2
|
|
|
3
|
+
Choose one document density owner, then use UIScope for a deliberately different region.
|
|
4
|
+
Changing density changes spacing; keep primary copy in Text and headings in Heading or their
|
|
5
|
+
component owners. Check the last field/next heading together: CardContent, FormSection and
|
|
6
|
+
Stack can each contribute separation. A portal must stay inside its intended token scope;
|
|
7
|
+
UIPortalHost provides that boundary. Test open popups as well as the page beneath them.
|
|
8
|
+
|
|
3
9
|
Three components, and the difference between them is what they are allowed to touch.
|
|
4
10
|
|
|
5
11
|
| | Renders | Reaches | Use for |
|
|
@@ -71,8 +77,10 @@ value, and a value is replaced, not merged.
|
|
|
71
77
|
|
|
72
78
|
That is the configuration components read, and the CSS follows it: each scope writes the
|
|
73
79
|
merged overrides on its element, so inside the nested scope above `--primary` is red and
|
|
74
|
-
`--secondary` is green.
|
|
75
|
-
|
|
80
|
+
`--secondary` is green. Component styles inherit global tokens rather than redeclaring
|
|
81
|
+
theme defaults. Explicit Scope/UIScope overrides replace inherited values; a density preset
|
|
82
|
+
also resets its spacing and control heights on that region. A value outside that boundary
|
|
83
|
+
does not override its local declaration; see
|
|
76
84
|
[Theming](./theming.md#setting-a-theme).
|
|
77
85
|
|
|
78
86
|
## Scope — tokens only
|
|
@@ -85,17 +93,18 @@ inherits through any element, a `Scope` or a `data-density` region included; see
|
|
|
85
93
|
</Scope>
|
|
86
94
|
```
|
|
87
95
|
|
|
88
|
-
`Scope` renders a `div` without layout. `render` picks another element
|
|
89
|
-
|
|
96
|
+
`Scope` renders a `div` without layout. Its `render` prop picks another element
|
|
97
|
+
(`render={<section />}`), and `transparent={false}` gives it a box. Every
|
|
90
98
|
component inside reads the variables it sets, because components compute from the theme where
|
|
91
99
|
they use it; any element with a `style` does the same, and `Scope` only adds the missing
|
|
92
100
|
layout rule and the `data-ui-scope` marker.
|
|
93
101
|
|
|
94
102
|
## Portals and scopes
|
|
95
103
|
|
|
96
|
-
A scope
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
A scope uses CSS custom properties; its `data-density` and `data-theme` attributes establish
|
|
105
|
+
spacing and colour-scheme values that inherit through the DOM subtree. The attributes
|
|
106
|
+
themselves are not copied to descendants. A portal renders elsewhere in the document, so
|
|
107
|
+
those inherited values do not follow it by default:
|
|
99
108
|
|
|
100
109
|
```tsx fragment — a template with a hole in it
|
|
101
110
|
<UIScope config={{ density: "compact" }}>
|
|
@@ -136,7 +145,7 @@ in — a shadow root, or a positioned overlay element it manages itself.
|
|
|
136
145
|
|
|
137
146
|
## Strict Content Security Policy
|
|
138
147
|
|
|
139
|
-
Some Base UI-backed controls emit a tiny inline style or pre-hydration script for behavior
|
|
148
|
+
Some Base UI-backed controls emit a tiny inline style element or pre-hydration script for behavior
|
|
140
149
|
the component stylesheet cannot express. Put `CSPProvider` at the same application boundary
|
|
141
150
|
as `UIRoot` and pass the request nonce through:
|
|
142
151
|
|
|
@@ -154,7 +163,7 @@ React 19 hoists styles that carry `precedence`. During streaming SSR, configure
|
|
|
154
163
|
renderer with the same style nonce as the provider; otherwise React omits the attribute and
|
|
155
164
|
warns about the mismatch.
|
|
156
165
|
|
|
157
|
-
When the policy
|
|
166
|
+
When the policy forbids inline style elements, suppress Base UI's style elements and
|
|
158
167
|
ship the scrollbar rule in the consuming application's stylesheet:
|
|
159
168
|
|
|
160
169
|
```tsx fragment — App comes from the consuming application
|
|
@@ -171,6 +180,15 @@ ship the scrollbar rule in the consuming application's stylesheet:
|
|
|
171
180
|
`disableStyleElements` does not disable kit behavior; it moves those small rules into the
|
|
172
181
|
consuming app. It does not change how the kit's CSS loads.
|
|
173
182
|
|
|
183
|
+
This option does not remove inline scripts or `style` attributes. A nonce authorizes the
|
|
184
|
+
matching style/script elements; it does not authorize style attributes in server-rendered
|
|
185
|
+
HTML. Providers, responsive structure and popup positioning can use style attributes, so
|
|
186
|
+
a policy that blocks them needs a separate SSR strategy for the adopted components.
|
|
187
|
+
Inspect the rendered HTML and browser CSP reports; `disableStyleElements` alone does not
|
|
188
|
+
establish compatibility with that policy. See the
|
|
189
|
+
[Base UI CSP reference](https://base-ui.com/react/utils/csp-provider#inline-style-attributes)
|
|
190
|
+
for the distinction and available integration strategies.
|
|
191
|
+
|
|
174
192
|
## Reading the config
|
|
175
193
|
|
|
176
194
|
Resolution, in every component:
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Complete reference workflows
|
|
2
|
+
|
|
3
|
+
These sources use public package imports and fixed local mock operations. Copy the complete
|
|
4
|
+
workflow directory, including relative helpers, then replace its transport and policy with
|
|
5
|
+
your application's. The [versioned inventory](../generated/workflows/index.json) lists every
|
|
6
|
+
file, import and API reference. Its package version must match the installed package.
|
|
7
|
+
|
|
8
|
+
| Workflow | Owners and application seam | Complete entry source |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| Record detail | Page owns route heading; sibling Cards own subjects; MetadataList owns facts; app owns record commands | [Record detail](../generated/workflows/record-detail/page-layout/record-detail-reference.tsx) |
|
|
11
|
+
| Server resource index | DataView owns browser presentation; app owns server matching, unknown totals, cursor and page selection | [Resource index](../generated/workflows/resource-index/data-view/resource-index-reference.tsx) |
|
|
12
|
+
| Multi-section form | Card owns surface; flat FormSections retain insets; FieldGroup and FormField own names; app owns validation and completion | [Form](../generated/workflows/multi-section-form/form-workflow/multi-section-reference.tsx) |
|
|
13
|
+
| Scoped resource selection | ResourceCombobox owns lookup; app owns scopeKey and selection validity; Overlay owns task | [Selector](../generated/workflows/scoped-resource-selection/combobox/scoped-resource-reference.tsx) |
|
|
14
|
+
| Nested action flow | Parent owns draft; child owns confirmation; app closes explicitly after successful mutation | [Nested action](../generated/workflows/nested-action-flow/action-overlays/nested-action-reference.tsx) |
|
|
15
|
+
| Workspace navigation | Shell owns geometry; workspace owns disclosure; app owns router and same-app policy | [Workspace](../generated/workflows/workspace-navigation/app-shell/workspace-navigation-reference.tsx) |
|
|
16
|
+
| Media picking | MediaLibraryDialog owns query/picking UI; app commits a separate picker draft on confirmation, pages through footer slots, hydrates saved ids independently, reports unavailable selection and authorizes fetches | [Media](../generated/workflows/media-picking/media-library/media-picking-reference.tsx) |
|
|
17
|
+
| Communications overview | MetricGrid owns quantities; MetadataList owns prose facts; app owns period, delivery state and retry | [Communications](../generated/workflows/communications-overview/analytics/communications-reference.tsx) |
|
|
18
|
+
| Website editor | RichTextEditor owns editing; app retains locale drafts and alt text; RichText sanitizes preview | [Website editor](../generated/workflows/website-content-editor/rich-text-editor/website-content-reference.tsx) |
|
|
19
|
+
|
|
20
|
+
Forms using plain state need no form peer. The optional forms-rhf adapter connects existing
|
|
21
|
+
React Hook Form state without duplicating it. The resource-index workflow uses features/table and
|
|
22
|
+
needs its table peer; record-detail uses peer-free base/table; analytics and rich editing require the peers listed in their generated
|
|
23
|
+
API pages. The general reference consumer stays free of optional peers; the admin reference
|
|
24
|
+
consumer demonstrates adopted adapters.
|
|
25
|
+
|
|
26
|
+
Pending, empty, failed refresh, unavailable selection and resolved validation errors are
|
|
27
|
+
different states. These fixtures demonstrate local feedback and retained drafts. They do
|
|
28
|
+
not establish real persistence, permissions, cache invalidation or backend sanitization.
|
|
29
|
+
Exercise the named cases in your app; [record the evidence](./verification.md#completion-record)
|
|
30
|
+
and identify conditions you could not inspect.
|
|
31
|
+
|
|
32
|
+
The inventory's `verification` entries map required cases to behavioral tests or visual
|
|
33
|
+
inspection conditions. They specify coverage to run, not a claim that your application passed.
|
|
34
|
+
`repositoryFile` identifies a maintainer test in the source repository; copy workflow files
|
|
35
|
+
from the inventory's generated source list and adapt the named behaviors to your test runner.
|
|
36
|
+
The browser cases use explicit mock actions; the read-only observer supplies advisory geometry
|
|
37
|
+
findings. Review screenshots and semantics separately in both themes and densities at mobile,
|
|
38
|
+
desktop and wide widths, including long copy and RTL. Build/type checks prove the complete
|
|
39
|
+
sources and public imports; rich-text security tests exercise the sanitization boundary.
|
|
40
|
+
|
|
41
|
+
When embedding a contained app shell in an existing main landmark, use `contentRender={<div />}`
|
|
42
|
+
so the composition keeps one main. For a shell that owns the application's main, omit that
|
|
43
|
+
override. The reference uses the embedded form because it also appears inside a documentation page.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Structure and spacing
|
|
2
|
+
|
|
3
|
+
Choose the semantic owner first, then arrange its siblings. A Page owns route geometry;
|
|
4
|
+
Card owns an independent subject; ContentBlock owns supporting content; FormSection owns
|
|
5
|
+
an editable region. Stack and Grid arrange those owners without adding a heading, landmark,
|
|
6
|
+
surface or inset. See [Composition](./composition.md#decide-the-owners-before-jsx) for names,
|
|
7
|
+
commands and field ownership, and [Blocks](./blocks.md) for ready subject arrangements.
|
|
8
|
+
|
|
9
|
+
## Choose a structural block
|
|
10
|
+
|
|
11
|
+
| Need | Public owner | What it supplies |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| Route title, description and commands | `Page` from `layout/page` | Container, page header and body rhythm. It does not create a main landmark or own scrolling. |
|
|
14
|
+
| Page scroll inside a bounded shell | `PageViewport` from `layout/containers` | Scroll region and an inline-size query container. Focusable by default for keyboard scrolling. |
|
|
15
|
+
| Centred width and inline gutter | `Container` from `layout/containers` | Width and gutter only. Page already includes it. |
|
|
16
|
+
| Semantic section with rhythm between groups | `Section` from `layout/containers` | A native section and twice the group gap; supply its heading or accessible name. |
|
|
17
|
+
| Primary work beside a secondary summary | `TwoColumnLayout` from `layout/containers` | Main/aside arrangement, optional full-width header/footer; stacks below `lg`. Aside stays second in the DOM. |
|
|
18
|
+
| One row or column of passive siblings | `Stack` from `base/structure` | Direction, gap, alignment, distribution and optional wrapping. No padding prop. |
|
|
19
|
+
| An explicit column count | `Grid` and `GridCell` from `base/structure` | One to four columns, responsive gaps and cell spans. |
|
|
20
|
+
| As many equal columns as fit | `AdaptiveGrid` from `base/structure` | Auto-fit tracks; `minColumnWidth` is `default` (16rem), `sm` (12rem) or a CSS length. |
|
|
21
|
+
| A fluid main region and a constrained rail | `Split` from `base/structure` | Two direct children: main first, side second. `sideWidth` defaults to 18rem; `collapseBelow` defaults to `md`. |
|
|
22
|
+
| Intentional edge-to-edge content in an inset | `Bleed` from `base/structure` | Negative margins on the selected axis. Match `amount` to the inset it cancels. |
|
|
23
|
+
|
|
24
|
+
Read the exact [structure API](../generated/components/base--structure.md),
|
|
25
|
+
[containers API](../generated/components/layout--containers.md) and
|
|
26
|
+
[page API](../generated/components/layout--page.md) before adding props. Container's
|
|
27
|
+
`maxWidth` (`sm`, `md`, `lg`, `xl`, `2xl`, `full`) and `gutter` (`none`, `sm`, `md`, `lg`)
|
|
28
|
+
are a different contract from Stack/Grid widths (`default`, `sm`, `full`, `none` or a CSS
|
|
29
|
+
length). Container gutters are zero, one, one-and-a-half or twice `--padding`; they do not
|
|
30
|
+
add spacing tokens. Stack/Grid `maxWidth` caps width without centring it or adding a gutter.
|
|
31
|
+
|
|
32
|
+
An app shell normally owns the single main landmark and page scroller. Do not add another
|
|
33
|
+
PageViewport around each section. For document scrolling without a bounded shell, Page can
|
|
34
|
+
live in the application's existing main. When embedding a shell inside another main, use
|
|
35
|
+
its documented `contentRender` seam; see [complete workflows](./reference-workflows.md).
|
|
36
|
+
|
|
37
|
+
## Use the two spacing roles
|
|
38
|
+
|
|
39
|
+
| Role | Public tokens | Typical use |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Container inset | `--padding` | Card regions and decorated ContentBlocks |
|
|
42
|
+
| Item inset | `--padding-sm` | Rows, cells and compact items |
|
|
43
|
+
| Between groups | `--gap`, `gap="default"` | Fields, sibling Cards, sections |
|
|
44
|
+
| Within a group | `--gap-sm`, `gap="sm"` | Title/description, icon/label, toolbar controls |
|
|
45
|
+
|
|
46
|
+
The omitted structure gap is `default`. `gap="none"` removes separation; it is not a third
|
|
47
|
+
spacing step. Insets belong to the child surface and gaps to the parent arrangement. Avoid
|
|
48
|
+
giving both the same separation job. Density changes these lengths together; it does not
|
|
49
|
+
choose smaller text roles. [Theming](./theming.md#scale-and-density) explains density, scale
|
|
50
|
+
and typography scale, including overriding a preset's values.
|
|
51
|
+
|
|
52
|
+
CardContent supplies its inset and a group gap between direct children; it drops its top
|
|
53
|
+
padding after an undivided CardHeader. Card `surface="flat"` removes decoration and retains
|
|
54
|
+
region insets. FormSection is a Card composition, so a flat FormSection inside CardContent
|
|
55
|
+
still adds its own inset. Use `Stack gap="none"` between such sections when their insets
|
|
56
|
+
already supply the intended rhythm; do not assume flat means flush.
|
|
57
|
+
|
|
58
|
+
ContentBlock is different: its default `surface="plain"` supplies heading/content spacing
|
|
59
|
+
without an inset or frame. Its `bordered`, `muted` and `card` surfaces add an inset.
|
|
60
|
+
`flush` drops that decorated surface's inset for children that own their own padding.
|
|
61
|
+
Neither flat nor flush changes field associations or heading semantics.
|
|
62
|
+
|
|
63
|
+
```tsx compile
|
|
64
|
+
import { Card } from "themelia-ui/base/cards"
|
|
65
|
+
import { ContentBlock, MetadataList } from "themelia-ui/base/display"
|
|
66
|
+
import { Grid, Stack } from "themelia-ui/base/structure"
|
|
67
|
+
import { Text } from "themelia-ui/base/typography"
|
|
68
|
+
import { Page } from "themelia-ui/layout/page"
|
|
69
|
+
import { TwoColumnLayout } from "themelia-ui/layout/containers"
|
|
70
|
+
|
|
71
|
+
export function AccountOverview() {
|
|
72
|
+
return <Page header={{ title: "Account" }} maxWidth="lg">
|
|
73
|
+
<TwoColumnLayout
|
|
74
|
+
main={<Stack>
|
|
75
|
+
<Grid columns={{ base: 1, md: 2 }}>
|
|
76
|
+
<Card title="Contact" titleLevel={2}>
|
|
77
|
+
<MetadataList items={[{ id: "email", label: "Email", value: "alex@example.com" }]} />
|
|
78
|
+
</Card>
|
|
79
|
+
<Card title="Billing" titleLevel={2}>
|
|
80
|
+
<MetadataList items={[{ id: "status", label: "Status", value: "Active" }]} />
|
|
81
|
+
</Card>
|
|
82
|
+
</Grid>
|
|
83
|
+
<Card title="Notes" titleLevel={2}>
|
|
84
|
+
<ContentBlock description="Context for the next account review.">
|
|
85
|
+
<Text>The customer prefers email updates.</Text>
|
|
86
|
+
</ContentBlock>
|
|
87
|
+
</Card>
|
|
88
|
+
</Stack>}
|
|
89
|
+
aside={<Card title="Summary" titleLevel={2}><Text>Review due next month.</Text></Card>}
|
|
90
|
+
/>
|
|
91
|
+
</Page>
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The example has one route heading, three independent subjects in the main region and a
|
|
96
|
+
secondary summary. Page supplies the gutter; TwoColumnLayout supplies main/aside separation;
|
|
97
|
+
Stack/Grid separate subjects; each Card supplies its inset. The complete record and form
|
|
98
|
+
workflows add application-owned commands, validation and asynchronous states.
|
|
99
|
+
|
|
100
|
+
## Know which width drives responsiveness
|
|
101
|
+
|
|
102
|
+
A responsive structure prop accepts a single value or an object such as
|
|
103
|
+
`gap={{ base: "sm", md: "default" }}`. Values carry forward until another named step replaces
|
|
104
|
+
them; omitted lower steps use the component's defaults. `sm` as a gap value means the small
|
|
105
|
+
gap; `sm` as an object key means a breakpoint.
|
|
106
|
+
|
|
107
|
+
| Step | Viewport minimum | Grid's nearest query-container minimum |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `base` | All widths | All widths |
|
|
110
|
+
| `sm` | 40rem | 24rem |
|
|
111
|
+
| `md` | 48rem | 32rem |
|
|
112
|
+
| `lg` | 64rem | 40rem |
|
|
113
|
+
| `xl` | 80rem | 52rem |
|
|
114
|
+
| `2xl` | 96rem | 64rem |
|
|
115
|
+
|
|
116
|
+
Grid uses viewport steps when no ancestor establishes inline-size containment. With a query
|
|
117
|
+
container, such as PageViewport or ContentBlock, Grid's columns, gaps, alignment and maximum
|
|
118
|
+
width use the nearest container and the smaller thresholds above. Grid does not create its
|
|
119
|
+
own query container. Stack, Split, Bleed, AdaptiveGrid's responsive gap/alignment and
|
|
120
|
+
GridCell spans use viewport steps. AdaptiveGrid's **column count** always follows available
|
|
121
|
+
width through auto-fit. TwoColumnLayout stacks below the viewport's `lg` step.
|
|
122
|
+
|
|
123
|
+
Grid defaults to one column and two from `md`; `columns={1}` stays one at every width.
|
|
124
|
+
Use `GridCell span="full"` for a full row at every width. Numeric spans must fit the current
|
|
125
|
+
column count; `span={{ base: 1, md: "full", xl: 2 }}` can switch between numeric and full
|
|
126
|
+
placement. Coordinate responsive spans with the Grid, especially inside a query
|
|
127
|
+
container where their thresholds differ. Prefer AdaptiveGrid when the available panel width
|
|
128
|
+
should decide the count without coordinating breakpoints. Visual side positioning in Split
|
|
129
|
+
or TwoColumnLayout does not change reading or keyboard order.
|
|
130
|
+
|
|
131
|
+
## Bleed, custom CSS and verification
|
|
132
|
+
|
|
133
|
+
Bleed's default amount is `none` and its default axis is `inline`. An intentional image
|
|
134
|
+
escape can use `amount="default"` inside an inset of `--padding`, or `sm` inside
|
|
135
|
+
`--padding-sm`. The shipped spacing pairs have matching padding/gap values; a custom theme
|
|
136
|
+
that separates those values must account for the actual inset. Bleed does not create a
|
|
137
|
+
surface or crop media. Check edges and focus visibility in the surrounding surface.
|
|
138
|
+
|
|
139
|
+
Application-specific geometry can use `className` and CSS over public tokens; use the
|
|
140
|
+
documented props first. Do not target private `--_…` variables or CSS Module hashes. Keep
|
|
141
|
+
copy in Text/Heading and field labels in FormField rather than setting local type styles.
|
|
142
|
+
For product CSS, prefer logical properties so inline start/end follow RTL.
|
|
143
|
+
|
|
144
|
+
Check a narrow **parent** as well as a narrow viewport, long headings and translated labels,
|
|
145
|
+
both themes and densities, and keyboard access to the scroller. Verify that additional
|
|
146
|
+
surfaces or gaps serve an independent subject. [Consumer verification](./verification.md)
|
|
147
|
+
separates compiled examples, interaction evidence and visual inspection.
|
package/docs/learn/theming.md
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
The theme is about eighty variables, declared once at `:root` in `src/styles/theme/`. Each
|
|
4
4
|
colour holds both modes as `light-dark(light, dark)`, and every length, shadow, tint and
|
|
5
5
|
duration comes as a pair. Components derive everything else where they use it, so a value
|
|
6
|
-
you set
|
|
6
|
+
you set on a region reaches its descendants unless another scope or preset overrides it.
|
|
7
|
+
[`src/styles/TOKENS.md`](../../src/styles/TOKENS.md)
|
|
7
8
|
names the variable for each role.
|
|
8
9
|
|
|
9
10
|
## Setting a theme
|
|
@@ -22,7 +23,8 @@ for both modes:
|
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
That one block reaches every region, including popups portalled to `<body>` and a dark
|
|
25
|
-
region inside a light page
|
|
26
|
+
region inside a light page. Component styles do not redeclare theme colour defaults;
|
|
27
|
+
an explicit regional theme override takes precedence within that region.
|
|
26
28
|
|
|
27
29
|
The same values work on any element, for a region of their own:
|
|
28
30
|
|
|
@@ -139,6 +141,8 @@ and headings fall back to the interface font.
|
|
|
139
141
|
Compose title and description regions with CardHeader, ContentBlock or OverlayHeader, action
|
|
140
142
|
regions with CardFooter or OverlayFooter, and label/value facts with MetadataList. These
|
|
141
143
|
components own their spacing, so the application does not reproduce it.
|
|
144
|
+
See [Structure and spacing](./structure-and-spacing.md) for the owner and responsive-width
|
|
145
|
+
contracts before changing layout values.
|
|
142
146
|
|
|
143
147
|
## Scale and density
|
|
144
148
|
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Troubleshooting
|
|
2
2
|
|
|
3
|
+
Before patching a shared component, trace its callers and inspect one representative of
|
|
4
|
+
every affected surface. Recheck open portals, nested forms and small screens when shared
|
|
5
|
+
spacing or naming changes. Use the [read-only diagnosis and completion record](./verification.md)
|
|
6
|
+
to distinguish contract errors, advisory composition findings and unavailable coverage.
|
|
7
|
+
|
|
8
|
+
## A lookup still shows another workspace
|
|
9
|
+
|
|
10
|
+
Set `scopeKey` on ResourceCombobox, SuggestionsCombobox or useSuggestions. Callback identity is not an invalidation API.
|
|
11
|
+
The key invalidates answers and errors while keeping query/open/value ownership; explicitly
|
|
12
|
+
clear a selected id if it is invalid in the new scope. See the [complete selector](./reference-workflows.md).
|
|
13
|
+
|
|
14
|
+
## Validation resolves but the dialog closes
|
|
15
|
+
|
|
16
|
+
Set `closeOnAsyncComplete={false}` and close controlled `open` after successful validation
|
|
17
|
+
and mutation. Use `formId` for native submission and keep one mutation owner. Nested child
|
|
18
|
+
cancel/Escape should leave the parent draft visible; verify focus returns to the child invoker.
|
|
19
|
+
|
|
3
20
|
## A component is unstyled
|
|
4
21
|
|
|
5
22
|
A component brings its own CSS in a bundler. When it arrives unstyled:
|
|
@@ -74,8 +91,8 @@ listed there, report it as a package containment defect.
|
|
|
74
91
|
|
|
75
92
|
## A theme or density override does not apply
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
an override does not show:
|
|
94
|
+
Theme defaults are declared at `:root` and inherit until an explicit scope override or
|
|
95
|
+
density preset establishes another value. When an override does not show:
|
|
79
96
|
|
|
80
97
|
- **Is it the theme's name?** A 3.0 name such as `--space-md`, `--control-h` or
|
|
81
98
|
`--primary-10` is gone; the codemod renames or reports each one, and
|
|
@@ -121,6 +138,10 @@ set `disableStyleElements` and serve the documented Base UI behaviour rules from
|
|
|
121
138
|
stylesheet. The kit's stylesheets are ordinary static CSS. See
|
|
122
139
|
[Provider and scoping](./provider-and-scoping.md#strict-content-security-policy).
|
|
123
140
|
|
|
141
|
+
If the report names `style-src-attr`, a nonce or `disableStyleElements` will not authorize
|
|
142
|
+
server-rendered style attributes. Inspect the adopted components' SSR output and use the
|
|
143
|
+
separate attribute-policy strategy described in that guide.
|
|
144
|
+
|
|
124
145
|
In a bundled app the kit's CSS follows your own pipeline: stylesheet files in production,
|
|
125
146
|
while a dev server or `style-loader` that injects `<style>` elements needs the nonce, as your
|
|
126
147
|
own CSS does.
|
|
@@ -128,11 +149,13 @@ own CSS does.
|
|
|
128
149
|
## The design looks inconsistent after overrides
|
|
129
150
|
|
|
130
151
|
Override global semantic tokens first: colour roles, radius, spacing and density,
|
|
131
|
-
typography, and control geometry.
|
|
132
|
-
|
|
152
|
+
typography, and control geometry. Variables prefixed `--_` are private implementation detail.
|
|
153
|
+
Use a component-level variable only when its module reference documents a public extension
|
|
154
|
+
point. Do not target hashed CSS
|
|
133
155
|
Module names; use the stable `data-slot` attributes and BEM hooks such as
|
|
134
156
|
`{name}--component`, and for a state the attributes the primitives set (`data-open`, `data-checked`, `data-disabled`,
|
|
135
|
-
`data-highlighted`, `data-popup-open`). Radix's `[data-state="open"]`
|
|
157
|
+
`data-highlighted`, `data-popup-open`). Do not assume Radix's `[data-state="open"]` for Base
|
|
158
|
+
UI primitives. Use a module's own `data-state` only when its API documents that contract.
|
|
136
159
|
|
|
137
160
|
## Rich text and untrusted HTML
|
|
138
161
|
|
|
@@ -32,8 +32,9 @@ test("global search returns focus after dismissal", async ({ page }) => {
|
|
|
32
32
|
Prefer role- and name-based assertions over CSS Module selectors. When a visual or state
|
|
33
33
|
assertion needs a DOM hook, use `data-slot`, documented BEM hooks, or the state attributes
|
|
34
34
|
the primitives set (`data-open`, `data-checked`, `data-disabled`, `data-highlighted`,
|
|
35
|
-
`data-popup-open`).
|
|
36
|
-
|
|
35
|
+
`data-popup-open`). Use Base UI's documented attributes for its primitive states rather
|
|
36
|
+
than assuming Radix's `[data-state="open"]`. Some kit modules expose their own `data-state`
|
|
37
|
+
contract; use it only where the selected API documents it.
|
|
37
38
|
|
|
38
39
|
## Theme contract check
|
|
39
40
|
|
|
@@ -41,6 +42,61 @@ Create one application fixture that changes primary colour, surface/background r
|
|
|
41
42
|
radius, density, and typography scale at a scope boundary. If a component ignores it, report
|
|
42
43
|
the module and token before adding a local patch: the package may be missing a derivation.
|
|
43
44
|
|
|
45
|
+
## Offline diagnosis and skill freshness
|
|
46
|
+
|
|
47
|
+
Run the commands from the package installed in this application:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
node node_modules/themelia-ui/scripts/consumer/install-skill.mjs --project=. --check --json
|
|
51
|
+
node node_modules/themelia-ui/scripts/consumer/diagnose.mjs --project=. --json src/
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both checks are read-only. Diagnostics use the consumer's installed TypeScript parser and
|
|
55
|
+
the package's generated export/migration facts. Supply explicit paths. Unsupported formats,
|
|
56
|
+
parse failures, missing paths, metadata or parser produce exit 2 (incomplete); definite
|
|
57
|
+
contract errors produce exit 1; complete checks without errors produce exit 0. Advisory
|
|
58
|
+
composition/private-style warnings do not establish a defect. Excluded build/dependency
|
|
59
|
+
directories and symlinks are not followed. Reports name the checked and skipped rules/files.
|
|
60
|
+
|
|
61
|
+
Freshness reports expected and installed versions plus missing, stale, modified or unmanaged
|
|
62
|
+
copies. Review modifications before reinstalling a generated copy. The installer refuses local edits
|
|
63
|
+
until `--overwrite-modified` explicitly replaces reviewed generated content. Keep application policy
|
|
64
|
+
in a separate skill; an unmanaged same-name skill is preserved. Missing metadata requires
|
|
65
|
+
repairing the package installation or consulting the matching release, never inventing an API.
|
|
66
|
+
|
|
67
|
+
If an installed copy's manifest is missing or invalid, the installer repairs it automatically
|
|
68
|
+
only when its remaining files match the packaged content. Differing or extra files require
|
|
69
|
+
review and `--overwrite-modified`, just like edits to a copy with a valid manifest.
|
|
70
|
+
|
|
71
|
+
Replacements are staged before writes, and caught write failures restore backups. An abrupt
|
|
72
|
+
process termination can leave mixed versions across targets and sibling `.backup-*` or
|
|
73
|
+
`.installing-*` directories. Run `--check`, review those retained directories, preserve any
|
|
74
|
+
local policy, and reinstall the intended generated copies. A backup-cleanup error means the
|
|
75
|
+
new copies were installed; the error names the retained backup for review and manual cleanup.
|
|
76
|
+
|
|
77
|
+
The [browser observer](../build/browser-composition-fixture.ts) accepts an already open caller
|
|
78
|
+
fixture and observes overflow, repeated sibling headings and control visibility. It performs
|
|
79
|
+
no navigation, click or submission. These geometry/semantic observations are advisory; they
|
|
80
|
+
do not establish accessibility or business acceptance. Optional browser tooling belongs in
|
|
81
|
+
the application's test dependencies, not the UI runtime.
|
|
82
|
+
|
|
83
|
+
Opt into interaction tests only against explicit mock actions. The [complete workflows](./reference-workflows.md)
|
|
84
|
+
provide scoped late responses, pending/empty/error lists, nested cancel, resolved validation,
|
|
85
|
+
workspace selection and retained locale drafts. Assert keyboard selection without accidental
|
|
86
|
+
form submission, one Escape layer at a time, focus return, associated errors and explicit
|
|
87
|
+
successful completion. Do not crawl unknown application routes or submit business forms.
|
|
88
|
+
|
|
89
|
+
## Completion record
|
|
90
|
+
|
|
91
|
+
Record installed package/skill versions; selected owners and seams; shared callers inspected;
|
|
92
|
+
fixture routes and states; viewport widths; themes, densities and locales; keyboard/focus
|
|
93
|
+
interactions; commands and observed results. Separate type/build evidence, behavior tests,
|
|
94
|
+
visual inspection and application acceptance. Name unavailable conditions explicitly.
|
|
95
|
+
|
|
96
|
+
When no browser is available, report types/build/static findings and mark interaction and
|
|
97
|
+
visual checks unverified. Passing named static/browser checks does not establish permissions,
|
|
98
|
+
data integrity, persistence, backend sanitization or every product workflow.
|
|
99
|
+
|
|
44
100
|
## Upgrade check
|
|
45
101
|
|
|
46
102
|
Read the [changelog](../../CHANGELOG.md), run the package's codemod when a release names one
|