5f3f734b34
## Summary
Three independent front-end fixes.
### 1. Settings page header title overlaps the breadcrumb
On settings detail pages (e.g. an app's logic function), a long centered
title visually overlapped the breadcrumb.
`PageCardHeader` renders the header as a CSS grid (`minmax(0, 1fr) auto
minmax(0, 1fr)`) and the centered title used `justify-self: center`.
With grid, `justify-self: center` sizes the item to its own content
width (up to its `max-width`) instead of to its grid track, so a long
title grew wider than the center track and spilled sideways over the
breadcrumb column — its `overflow: hidden` only clipped its own children
to that oversized box, not to the track.
Fix: let the centered title fill and shrink to its grid track so it
clips (with ellipsis) inside its own column instead of overflowing into
the breadcrumb.
- Center column: `auto` → `minmax(0, auto)` so it can shrink when space
is tight.
- Centered title: `justify-self: center` → `justify-self: stretch` +
`min-width: 0`.
### 2. Cmd+K does nothing on standalone page layout pages
On standalone page layout pages (`/page/:pageLayoutId`, used to render
app front components), the command menu shortcut (Cmd+K) did nothing.
Cmd+K is a global hotkey with a modifier, so it only runs when the
active focus-stack config has `enableGlobalHotkeysWithModifiers: true`.
`RecordIndexPage` and `RecordShowPage` explicitly reset the focus stack
to enable it, but `PageChangeEffect` had no case for
`AppPath.PageLayoutPage`, so the stack kept a stale config (commonly the
Settings config, which disables modifier hotkeys) and swallowed the
shortcut.
Fix: add a `PageLayoutPage` case in `PageChangeEffect` that resets the
focus stack with modifier hotkeys enabled (mirroring `RecordShowPage`),
plus a new `PageFocusId.PageLayoutPage` value.
### 3. Ever-changing / unstable tooltip element id
`OverflowingTextWithTooltip` built its element id from `title-id-${+new
Date()}`, so a new id (the current epoch time in ms) was generated on
every render — the id visibly kept increasing in the DOM. This is
unstable (the tooltip anchor `#id` churns on each render) and
collision-prone (two tooltips rendering in the same millisecond get the
same id, producing duplicate DOM ids and an ambiguous anchor).
Fix: derive the id from React's `useId()` so it is stable per instance
and unique. The colons `useId()` produces are stripped, since the id is
used inside a CSS selector (`anchorSelect={#${id}}`) where colons are
invalid.
## Test plan
- [ ] Open a settings detail page with a long title (e.g. an app logic
function named `maintain-account-team-member-name-on-created`) and
confirm the title no longer overlaps the breadcrumb, and truncates with
an ellipsis when space is tight.
- [ ] Navigate to a standalone page layout page (an app's
front-component page) and confirm Cmd+K opens the command menu,
including after coming from Settings.
- [ ] Inspect an overflowing title/tooltip in DevTools and confirm its
`id` stays stable across re-renders (no longer increments), and tooltips
still show on hover of truncated text.
twenty-ui
Twenty's open-source React UI component library: components, icons, and design tokens built on a zero-runtime, CSS-variable styling layer.
Installation
npm install twenty-ui
react, react-dom, and monaco-editor are peer dependencies (install them in your app). monaco-editor is only required if you use the code editor components.
Usage
Import the base styles once, pick a theme stylesheet, and wrap your app in ThemeProvider:
import { ThemeProvider } from 'twenty-ui/theme-constants';
import { Button } from 'twenty-ui/input';
import 'twenty-ui/style.css';
import 'twenty-ui/theme-light.css';
export const App = () => (
<ThemeProvider colorScheme="light">
<Button title="Click me" />
</ThemeProvider>
);
Components are available from the root entry point or from a specific subpath for better tree-shaking:
import { Button } from 'twenty-ui';
import { Button } from 'twenty-ui/input';
Entry points
| Subpath | Contents |
|---|---|
twenty-ui |
All components, icons, theme tokens, and utilities |
twenty-ui/accessibility |
Accessibility helpers |
twenty-ui/assets |
Logos and static assets |
twenty-ui/data-display |
Avatars, chips, tags, and other display components |
twenty-ui/feedback |
Progress bars, loaders, and status feedback |
twenty-ui/icon |
Icon components and the icon provider |
twenty-ui/input |
Buttons, toggles, and form inputs |
twenty-ui/json-visualizer |
JSON tree viewer |
twenty-ui/layout |
Layout primitives |
twenty-ui/navigation |
Menus, links, and navigation components |
twenty-ui/surfaces |
Cards, tooltips, and surface components |
twenty-ui/testing |
Storybook and test decorators |
twenty-ui/theme |
Theme types and helpers |
twenty-ui/theme-constants |
Design tokens, ThemeProvider, and useTheme |
twenty-ui/typography |
Text and typography components |
twenty-ui/utilities |
Hooks and shared utilities |
Theming
twenty-ui/style.cssships the base reset and component styles. Import it once.twenty-ui/theme-light.cssandtwenty-ui/theme-dark.cssdefine the design-token CSS variables for each color scheme.ThemeProviderexposes the active theme throughuseTheme()and applies thelight/darkclass. PassapplyToRoot={false}withoverridesto scope a theme to a subtree instead of the document root.
Development
npx nx build twenty-ui # Build the library (dual ESM/CJS + types)
npx nx storybook:serve:dev twenty-ui # Run Storybook
npx nx test twenty-ui # Run unit tests
License
twenty-ui is released under the AGPL-3.0 license.
