Repository navigation
feat: add LabelSwap primitive and forward button gap to slot compositions - #4
Conversation
…ions - LabelSwap: width-tweening label swapper (named slots + active), the horizontal sibling of AutoHeight — natural per-label width, house-spring width transition, opacity crossfade, ResizeObserver-backed measurement - Button: forward gap through the display:contents content wrapper ([gap:inherit]) so nested compositions inherit the spacing contract instead of hand-writing icon margins - skills: register DeviceCodePanel + LabelSwap in the owner vocabulary, graduate OAuth device-flow out of the stay-hand-written list, add the icon-position-is-semantics rule and the button-gap-ownership rule
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7105185d47
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <template> | ||
| <span | ||
| data-slot="label-swap" | ||
| class="grid justify-center overflow-hidden [gap:inherit]" |
There was a problem hiding this comment.
Keep LabelSwap inline in inline hosts
When this exported primitive is used as inline status text rather than inside an existing flex container, grid makes the <span> a block-level grid, so it breaks the surrounding inline flow and can occupy the line until the measured width is applied. Use inline-grid here to preserve the label-sized inline behavior while keeping the overlapping grid layout.
Useful? React with 👍 / 👎.
… catalog Backend: - device-code OAuth flow for openai-codex providers (authorize/poll/status), persisted device session metadata (migration 0106_provider_oauth_metadata) - managed model catalog refresh for codex providers Web: - rebuild the provider OAuth card in the refactored design language: one account row (SettingsSection/SettingsRow) with a three-state Connect → Connecting → Cancel toggle (LabelSwap width transition), AutoHeight card growth, and a centered device-code moment - extract DeviceCodePanel owner (hero code, single copy-and-open action with popup-blocker-safe tab ordering, visibility-guarded countdown); registered in the ui-owners skill, three legacy call sites noted for follow-up migration - revoke gated behind ConfirmPopover; local cancel for pending device flow (no provider cancel API yet — noted in-code) - move panel copy to a deviceCode i18n namespace (en/zh/ja), drop orphaned provider.oauth keys Depends on felinics/ui#4 (LabelSwap + Button gap forwarding); submodule pointer references that branch and should be re-bumped to the merge commit once ui#4 lands.
… catalog (#780) Backend: - device-code OAuth flow for openai-codex providers (authorize/poll/status), persisted device session metadata (migration 0106_provider_oauth_metadata) - managed model catalog refresh for codex providers Web: - rebuild the provider OAuth card in the refactored design language: one account row (SettingsSection/SettingsRow) with a three-state Connect → Connecting → Cancel toggle (LabelSwap width transition), AutoHeight card growth, and a centered device-code moment - extract DeviceCodePanel owner (hero code, single copy-and-open action with popup-blocker-safe tab ordering, visibility-guarded countdown); registered in the ui-owners skill, three legacy call sites noted for follow-up migration - revoke gated behind ConfirmPopover; local cancel for pending device flow (no provider cancel API yet — noted in-code) - move panel copy to a deviceCode i18n namespace (en/zh/ja), drop orphaned provider.oauth keys Depends on felinics/ui#4 (LabelSwap + Button gap forwarding); submodule pointer references that branch and should be re-bumped to the merge commit once ui#4 lands.
Summary
AutoHeight. Named slot per candidate label,activepicks the visible one; each label keeps its natural width, the shell width transitions on the house spring (200ms, locked in-component), labels crossfade. Measurement via ResizeObserver +ceil(getBoundingClientRect().width)(survives late webfonts / locale swaps / subpixel clipping). Grid-overlap layout with centered tracks (the head comment documents the clipped-"Canc|" and zero-height traps it encodes).gapthrough thedisplay:contentscontent wrapper ([gap:inherit]).gapis not an inherited property and the contents span breaks the inheritance chain, so nested compositions (LabelSwap) previously resolved gap to 0 and callers had to hand-write icon margins — the recurring "icon drifted right" bug.DeviceCodePanel(host-app owner) +LabelSwapin the ui-owners vocabulary and decision map; graduate OAuth device-flow out of the stay-hand-written list; add two rules to the web skill icon section — icon position in a text button is semantics (leading = action identity, trailing = outcome/destination, with the device-code worked example) and spacing between a Button's direct children belongs to the Button.First consumer: Memoh provider OAuth device-authorization card (Connect → Connecting → Cancel three-state toggle button); shell-repo PR to follow with the submodule bump.
Test plan
check-ui-contract.mjspasses