/** * `` — HeroUI-themed header bar for `@sigx/lynx-navigation`. * * Pairs with ``: * * ```tsx * * ``` * * Reads the focused screen's options + slot fills via `useScreenChrome()` and * applies hero theming (base-200 surface, bottom separator, centred title). * Icons themed through `` — resolved by ``'s * (zero's) icon-color resolver to the active hero palette hex. * * The navigation package's own `
` is headless; this is the * batteries-included variant for hero consumers. */ import { component, type Define, type JSXElement } from '@sigx/lynx'; import { Pressable } from '@sigx/lynx-gestures'; import { Icon, type IconSpec } from '@sigx/lynx-icons'; import { useScreenChrome } from '@sigx/lynx-navigation'; import { PRESSED_SCALE, PRESSED_OPACITY } from '@sigx/lynx-zero'; export type NavHeaderBackground = 'base-100' | 'base-200' | 'base-300' | 'transparent'; export type NavHeaderProps = /** Surface color token. Default 'base-200'. */ & Define.Prop<'background', NavHeaderBackground, false> /** Show a separator line at the bottom. Default true. */ & Define.Prop<'bordered', boolean, false> /** * Render the back chevron from an `IconSpec`. Rendered with * `variant="primary"`, mapped to the active hero palette hex and * substituted into the SVG `fill=`. Wrapped in a Pressable wired to the * stack's pop. Falls back to the default "‹ Back" text. Ignored when * `renderBack` or `` is supplied — those win. */ & Define.Prop<'backIcon', IconSpec, false> /** Full override: render any JSX for the back button. Takes priority over `backIcon`. */ & Define.Prop<'renderBack', (ctx: { pop: () => void }) => JSXElement, false>; const NAV_HEADER_ICON_SIZE = 22; const backgroundClass: Record = { 'base-100': 'bg-base-100', 'base-200': 'bg-base-200', 'base-300': 'bg-base-300', 'transparent': '', }; export const NavHeader = component(({ props }) => { const chrome = useScreenChrome(); return () => { if (!chrome.headerShown) return null; const override = chrome.header; if (override) return override(); const bg = backgroundClass[props.background ?? 'base-200']; const bordered = props.bordered ?? true; const borderClass = bordered ? 'border-b border-base-300' : ''; const containerClass = [ 'flex flex-row items-center px-3', 'h-12', bg, borderClass, ].filter(Boolean).join(' '); const left = chrome.headerLeft?.() ?? (chrome.canGoBack ? (props.renderBack ? props.renderBack({ pop: chrome.pop }) : (props.backIcon ? : )) : null); const right = chrome.headerRight?.() ?? null; return ( {left} {chrome.title} {right} ); }; }); const DefaultBackButton = component void, true>>(({ props }) => { return () => ( props.onPress()} > ‹ Back ); }); const BackIconButton = component< & Define.Prop<'spec', IconSpec, true> & Define.Prop<'onPress', () => void, true> >(({ props }) => { return () => ( props.onPress()} > {/* `variant="primary"` → resolved by the ThemeProvider's icon-color resolver to the active hero palette hex and substituted into the SVG `fill=` (Lynx's `` doesn't inherit host color or evaluate CSS vars in attribute values). */} ); });