docs(ui): expand bilingual component guides
This commit is contained in:
@@ -1,31 +1,98 @@
|
||||
---
|
||||
title: Add responsive behavior
|
||||
description: Use shared breakpoint and interaction hooks when CSS alone cannot express the behavior.
|
||||
title: Responsive and interaction hooks
|
||||
description: Synchronize breakpoints when behavior must follow the viewport and add ripple feedback to custom controls.
|
||||
order: 20
|
||||
toc:
|
||||
- id: breakpoints
|
||||
title: Breakpoints
|
||||
- id: breakpoint-contract
|
||||
title: Breakpoint contract
|
||||
- id: reading-breakpoints
|
||||
title: Read breakpoints
|
||||
- id: root-classes
|
||||
title: Root classes
|
||||
- id: server-rendering
|
||||
title: Server rendering
|
||||
- id: ripple
|
||||
title: Ripple interaction
|
||||
---
|
||||
|
||||
## Breakpoints {#breakpoints}
|
||||
## Breakpoint contract {#breakpoint-contract}
|
||||
|
||||
The shared breakpoint splits the viewport into three ranges:
|
||||
|
||||
| Value | Range |
|
||||
| --------- | -------------------- |
|
||||
| `mobile` | Below 768px |
|
||||
| `tablet` | 768px through 1023px |
|
||||
| `desktop` | 1024px and above |
|
||||
|
||||
Prefer CSS for visual changes. Read a breakpoint during rendering only when mounted content, interaction behavior, or data volume must change.
|
||||
|
||||
## Read breakpoints {#reading-breakpoints}
|
||||
|
||||
```tsx
|
||||
import { useBreakpoint, useIsMobile } from "@workspace/ui/hooks/use-breakpoint"
|
||||
import {
|
||||
useBreakpoint,
|
||||
useIsDesktop,
|
||||
useIsMobile,
|
||||
useIsTablet,
|
||||
useOnBreakpoint,
|
||||
} from "@workspace/ui/hooks/use-breakpoint"
|
||||
|
||||
const breakpoint = useBreakpoint()
|
||||
const isMobile = useIsMobile()
|
||||
```
|
||||
|
||||
Prefer CSS responsive variants for visual changes. Use these hooks only when component behavior or mounted content must change.
|
||||
Every hook subscribes to the same pair of `matchMedia` queries through `useSyncExternalStore`. `useOnBreakpoint(listener)` runs only after the breakpoint changes; it does not report the initial value as a change.
|
||||
|
||||
## Root classes {#root-classes}
|
||||
|
||||
After mounting `BreakpointReactor`, the document root has exactly one of `.ui:mobile`, `.ui:tablet`, or `.ui:desktop`:
|
||||
|
||||
```tsx
|
||||
import { BreakpointReactor } from "@workspace/ui/hooks/use-breakpoint"
|
||||
|
||||
;<>
|
||||
<BreakpointReactor />
|
||||
<App />
|
||||
</>
|
||||
```
|
||||
|
||||
`globals.css` registers these as the custom `mobile:`, `tablet:`, and `desktop:` variants, allowing CSS and behavioral code to share the same three-range definition.
|
||||
|
||||
## Server rendering {#server-rendering}
|
||||
|
||||
The breakpoint store uses a deterministic desktop server snapshot. `getBreakpointInitializationScript` can assign the matching root class before hydration when the application needs CSS and behavioral breakpoints to agree immediately.
|
||||
The server snapshot is fixed to `desktop` so SSR remains deterministic. To write the real class before hydration, place the result of `getBreakpointInitializationScript()` in an inline script in the document head:
|
||||
|
||||
```tsx
|
||||
import { getBreakpointInitializationScript } from "@workspace/ui/hooks/use-breakpoint"
|
||||
|
||||
;<script
|
||||
dangerouslySetInnerHTML={{ __html: getBreakpointInitializationScript() }}
|
||||
/>
|
||||
```
|
||||
|
||||
Pass the application's nonce under a strict CSP. The script only synchronizes the initial class; it does not replace `BreakpointReactor` for later viewport changes.
|
||||
|
||||
## Ripple interaction {#ripple}
|
||||
|
||||
`useRipple` returns a ref callback that adds pointer-driven feedback to an interactive element. The element should establish a positioned containing block so the generated overlay uses the correct bounds.
|
||||
`Button` already uses `useRippleRef`, so ordinary buttons need no extra setup. Use the hook directly for a custom interactive surface:
|
||||
|
||||
```tsx
|
||||
import { useRipple } from "@workspace/ui/hooks/use-ripple"
|
||||
|
||||
export function Tile() {
|
||||
const ref = useRipple<HTMLButtonElement>({
|
||||
duration: 500,
|
||||
opacity: 0.2,
|
||||
rippleClassName: "bg-primary",
|
||||
})
|
||||
|
||||
return (
|
||||
<button ref={ref} className="relative">
|
||||
Open project
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The element must establish a positioned containing block, normally with `relative`. The hook ignores disabled controls, `aria-disabled="true"`, and non-primary mouse buttons, and removes listeners and animation nodes when the ref changes or unmounts. Use `useRippleRef(ref, options)` when merging an external ref.
|
||||
|
||||
Reference in New Issue
Block a user