mirror of
https://github.com/langgenius/dify.git
synced 2026-10-16 07:20:34 +08:00
docs: record overlay ownership and focus lessons (#44126)
This commit is contained in:
@@ -16,10 +16,12 @@ Read this document when a change involves application hotkeys, focus, dialogs, m
|
||||
## Secondary Surfaces
|
||||
|
||||
- Follow the [overlay contract] for primitive choice and shared mechanics. The nearest consumer `AGENTS.md` owns application-specific composite reuse policy.
|
||||
- Separate behavior ownership from placement ownership: the action may own trigger, open state, and menu content while the caller owns slots, offsets, and alignment.
|
||||
- Compose Root, Trigger, and content at the entry that owns the business behavior, so the whole anatomy is visible there. A shared layer exports content and state parts; it does not take a trigger prop or wrap the Root and hide the content it renders. The caller owns slots, offsets, and alignment.
|
||||
- Keep menu and dialog surfaces as siblings when a menu command opens a dialog. Mount the dialog outside popup content.
|
||||
- Use the [overlay contract] to determine content lifetime and preserve the Root's closing lifecycle. Follow [state ownership] for draft placement and semantic identity; portal placement alone does not locate the state owner.
|
||||
- Place query subscriptions and mutation observers at the owner whose lifetime matches when they should run. Mounted-session work may belong inside content; work that must start or stop exactly with `open` needs an explicit open-state condition.
|
||||
- Data inside a surface follows its owner's mount, not the `open` flag. A query declared in popup content under a Suspense boundary takes the content lifetime; a result the surface displays stays with its owner until that owner unmounts.
|
||||
- Anything read while a surface closes, such as the return-focus target, must come from an owner that outlives the close. The element that opened the surface may unmount with its data, and a per-call mutation callback is dropped when its component unmounts.
|
||||
- Prefer primitive-owned open state unless another owner must observe or coordinate it. Analytics callbacks and local cleanup alone do not require a controlled root.
|
||||
|
||||
[overlay contract]: ../../../../packages/dify-ui/docs/overlays.md
|
||||
|
||||
@@ -39,6 +39,7 @@ Read this document when adding, moving, splitting, or refactoring React componen
|
||||
|
||||
- Choose component declaration and export forms from the actual component contract, framework requirements, and enforced package rules. Existing style is context, not authority; do not rewrite unaffected code solely to normalize `FC`, `function`, arrow-function, named-export, or default-export forms.
|
||||
- Use API-generated or API-returned types at component boundaries. Keep one-off UI refinements and conversions beside their owner.
|
||||
- Derive prop types from their source instead of writing them by hand. A prop that lands on a primitive part is typed from that part, not from a neighbouring part.
|
||||
- Name props and converted data after their domain/API role, preserving traceability to the original contract.
|
||||
- Preserve domain value types for selections. Do not widen enums, unions, booleans, numbers, objects, or nullable values to `string` before a real boundary requires it.
|
||||
- Avoid generic `common.tsx` buckets and aliases that only rename another type. Name files, values, and public types after their domain role.
|
||||
|
||||
@@ -66,6 +66,8 @@ clipped, `display: none` or unmounted, and the shared positioner class turns tha
|
||||
|
||||
- Use `Dialog` for modal content that needs focus containment and scroll locking.
|
||||
- Use `AlertDialog` only for a destructive or must-confirm decision requiring an explicit answer.
|
||||
It blocks outside-press dismissal but still closes on Escape; cancel that close in
|
||||
`onOpenChange` when the answer must be explicit.
|
||||
- Use `Drawer` for side-panel interactions that follow the drawer model.
|
||||
- Use `DropdownMenu` for button-triggered action lists and `ContextMenu` for context actions.
|
||||
A long action list filters with `DropdownMenuFilterProvider`; choosing a value is
|
||||
|
||||
@@ -54,6 +54,10 @@ pending state only to `loading`; keep independent availability conditions in `di
|
||||
Pass `focusableWhenDisabled={false}` only when a loading button should opt into native disabled
|
||||
behavior and may leave the tab order.
|
||||
|
||||
Pass `focusableWhenDisabled` on a `disabled` button only when focus must still land on it. That
|
||||
holds for the return target of a closing surface, and for a control whose tooltip explains why it
|
||||
is unavailable.
|
||||
|
||||
### Accessible loading feedback
|
||||
|
||||
The spinner is decorative. Keep a non-empty visible label throughout loading. If the visible label
|
||||
|
||||
Reference in New Issue
Block a user