diff --git a/AGENTS.md b/AGENTS.md index a7764e789d..827fb9e704 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,6 +44,10 @@ Annotate every endpoint with the resource role of its domain, e.g. `read:alarms` Access control belongs in the resource implementation, not in the service. Extend `ManagerWebResource` and use its checks rather than reaching for the identity provider: `throwIfNotRealmActiveAndAccessible` and `throwIfRestrictedUser` reject with a 403, and `isRealmActiveAndAccessible` and `isRestrictedUser` are there for conditions that need more than a rejection. Resolve the entity first and return 404 when it is missing, then require access to its realm, and apply restricted user rules in the same place. Service methods take already authorised input and state that in their javadoc with "Callers are responsible for enforcing realm authorization." Alarms and notifications are the reference for this shape; equivalent endpoints across the two must enforce the same way. Flows that never pass through a resource, such as notifications published to the message broker, authorise inside the service instead. +## Spelling + +Write code, comments and docs in US English, e.g. `color`, not `colour`. + ## UI Frontend conventions live in `ui/AGENTS.md`. Read it before changing anything under `ui/`. diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 7f80a3a554..9f6921940c 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -38,20 +38,31 @@ The date and time picker wrappers set their `i18n` themselves: the date order, c ### Styling the component's shadow-DOM internals -Pick the approach by how much of the base component you need to keep. The base + Lumo styles are keyed off the element's `static get is()`, so a wrapper that does _not_ override `is` still reports the base tag (e.g. `vaadin-checkbox-group`) and inherits the full base + Lumo theme. +**How Vaadin applies styles.** A Vaadin element's shadow root has three layers, later ones winning at equal specificity: -**Small tweaks to an existing component (preferred default).** Do NOT override `is`, since that detaches the element from the base + Lumo styles keyed off `is` and strips the inherited theme/layout entirely. Do NOT use `static get styles()` — ThemableMixin injects those _before_ Lumo, so Lumo wins; and for wrapper classes that don't override `is`, ThemableMixin may not associate the child's `static get styles()` with the finalized element at all. Instead apply styles in one of these ways: +1. Base styles defined in `static get styles()` of the Vaadin component class or our `or-vaadin-*` classes. The Lumo theme drops these when it injects, unless the component sets `includeBaseStyles: true` (badge, slider). Components without `LumoInjectionMixin`, such as `vaadin-dialog`, always keep them. +2. Lumo modules defined through `@media lumo_` blocks are injected per tag as listed in `--_lumo--inject-modules`. Lumo defines its modules and lists them this way in `@vaadin/vaadin-lumo-styles/components/.css`. The list in our `ui/component/theme/src/components/or-vaadin-.css` overwrites Lumo's list for that tag, so we include Lumo's declared list and include our own `@media lumo_` blocks. `components/index.css` therefore imports our file after every other file that declares a list for the same tag, including through a Lumo import. +3. Styles registered with ``registerStyles("", css`…`)`` are added after Lumo to elements whose `is` matches the tag, and are inherited by subclasses. Register them before `customElements.define` runs for that tag, otherwise existing instances are restyled and a console warning is logged. For our own tag that means on module level above the class. -- **External `::part()` rule (preferred for part properties).** Add the rule in `ui/component/theme/src/components/or-vaadin-.css` (imported from that dir's `index.css`), keyed on the real tag name: `or-vaadin-::part() { … }`. This is a plain browser CSS feature — the global stylesheet pierces the shadow DOM boundary through the exposed part with no ThemableMixin involvement. It scopes cleanly to that tag only and is invisible to the `is`-based lookup. -- **Lumo `@media` module injection (for rules that must live inside the shadow DOM).** Use this only when `::part()` is insufficient — e.g. `:host` pseudo-class selectors, `::slotted`, or pseudo-elements that cannot be reached from outside. Define the rules in a named `@media ` block in the theme CSS file and add that name to `--_lumo-vaadin--inject-modules`. The injector stamps those rules into the shadow DOM _after_ Lumo, so they always win. -- **Slotted native inputs (`