A design system in a box. hip-ui.tngl.io/docs/introduction
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

inconsequential sidebar

+365 -131
+20 -16
apps/docs/src/components/navbar/Navbar.tsx
··· 17 17 18 18 const styles = stylex.create({ 19 19 wrapper: { 20 + zIndex: 1000, 20 21 borderBottomColor: uiColor.border1, 21 22 borderBottomStyle: "solid", 22 23 borderBottomWidth: 1, 23 - zIndex: 1000, 24 + top: 0, 24 25 width: "100%", 25 - top: 0, 26 26 }, 27 27 navbar: { 28 - marginLeft: "auto", 29 - marginRight: "auto", 30 - borderWidth: 0, 31 - maxWidth: "var(--page-content-max-width)", 32 28 "--separator-visibility": { 33 29 default: "none", 34 30 ":is([data-navbar-open]):has([data-navbar-action])": "flex", ··· 39 35 ":is([data-navbar-open])": "flex", 40 36 [containerBreakpoints.sm]: "none", 41 37 }, 38 + borderWidth: 0, 42 39 gridTemplateAreas: { 43 40 default: ` 44 41 "logo hamburger" ··· 94 91 ":is([data-navbar-open]):has([data-navbar-action])": `min-content min-content min-content min-content`, 95 92 }, 96 93 rowGap: spacing["8"], 94 + marginLeft: "auto", 95 + marginRight: "auto", 96 + maxWidth: "var(--page-content-max-width)", 97 97 minHeight: { 98 98 default: spacing["14"], 99 99 ":is([data-navbar-open])": "100%", ··· 175 175 link: { 176 176 "--underline-opacity": { 177 177 default: 0, 178 + ":is([aria-current=page])": 1, 178 179 ":is([aria-expanded=true])": 1, 179 180 ":is([data-active])": 1, 180 - ":is([data-status=active])": 1, 181 - ":is([aria-current=page])": 1, 182 181 ":is([data-breadcrumb] *)": 0, 183 182 ":is([data-hovered])": 1, 183 + ":is([data-status=active])": 1, 184 184 }, 185 185 gap: spacing["2"], 186 186 textDecoration: "none", ··· 219 219 }); 220 220 221 221 // Define subcomponents first so they can be referenced in Navbar 222 - export interface NavbarLogoProps 223 - extends StyleXComponentProps<React.ComponentProps<"div">> {} 222 + export interface NavbarLogoProps extends StyleXComponentProps< 223 + React.ComponentProps<"div"> 224 + > {} 224 225 225 226 /** 226 227 * NavbarLogo component for displaying the logo in the navbar. ··· 233 234 ); 234 235 }; 235 236 236 - export interface NavbarNavigationProps 237 - extends StyleXComponentProps<React.ComponentProps<"div">> { 237 + export interface NavbarNavigationProps extends StyleXComponentProps< 238 + React.ComponentProps<"div"> 239 + > { 238 240 /** 239 241 * Justify content alignment for the navigation items. 240 242 * @default "left" ··· 267 269 ); 268 270 }; 269 271 270 - export interface NavbarActionProps 271 - extends StyleXComponentProps<React.ComponentProps<"div">> { 272 + export interface NavbarActionProps extends StyleXComponentProps< 273 + React.ComponentProps<"div"> 274 + > { 272 275 /** 273 276 * Whether the action should be always visible on mobile. 274 277 * @default false ··· 311 314 ); 312 315 } 313 316 314 - export interface NavbarProps 315 - extends StyleXComponentProps<React.ComponentProps<"div">> { 317 + export interface NavbarProps extends StyleXComponentProps< 318 + React.ComponentProps<"div"> 319 + > { 316 320 size?: Size; 317 321 } 318 322
+67 -8
apps/docs/src/components/sidebar-layout/index.tsx
··· 12 12 13 13 const styles = stylex.create({ 14 14 wrapper: { 15 - backgroundColor: uiColor.bgSubtle, 15 + backgroundImage: `linear-gradient(to right, ${uiColor.bgSubtle} 50%, ${uiColor.bg} 50%)`, 16 16 position: "relative", 17 17 width: "100cqw", 18 18 }, ··· 24 24 marginLeft: "auto", 25 25 marginRight: "auto", 26 26 maxWidth: "var(--page-content-max-width)", 27 - minHeight: "100vh", 27 + minHeight: "100cqh", 28 28 width: "100%", 29 29 }, 30 + defaultSidebar: { 31 + overflow: "auto", 32 + overscrollBehavior: "contain", 33 + alignSelf: "start", 34 + flexShrink: 0, 35 + position: "sticky", 36 + maxHeight: "100cqh", 37 + top: 0, 38 + }, 30 39 sidebar: { 31 40 overflow: "auto", 32 41 overscrollBehavior: "contain", ··· 40 49 borderRightColor: uiColor.border1, 41 50 borderRightStyle: "solid", 42 51 borderRightWidth: 1, 43 - height: "100vh", 52 + height: "100cqh", 44 53 overflowX: "hidden", 45 54 overflowY: "auto", 46 55 top: 0, 47 56 }, 57 + visibleMd: { 58 + display: { 59 + default: "none", 60 + [containerBreakpoints.md]: "block", 61 + }, 62 + }, 63 + visibleLg: { 64 + display: { 65 + default: "none", 66 + [containerBreakpoints.lg]: "block", 67 + }, 68 + }, 48 69 drawer: { 49 70 display: { 50 71 default: "flex", ··· 73 94 }, 74 95 paddingRight: { 75 96 default: spacing["4"], 76 - [containerBreakpoints.sm]: spacing["16"], 97 + [containerBreakpoints.lg]: spacing["8"], 77 98 ":has(> [data-header-layout=true])": "0 !important", 99 + ":last-child": { 100 + default: spacing["4"], 101 + [containerBreakpoints.sm]: spacing["16"], 102 + }, 78 103 }, 79 104 paddingTop: { 80 105 default: spacing["2"], ··· 111 136 /** 112 137 * Sidebar layout sidebar component. Slot for sidebar content. 113 138 */ 114 - export interface SidebarLayoutSidebarProps extends StyleXComponentProps< 139 + export interface SidebarLayoutNavigationSidebarProps extends StyleXComponentProps< 115 140 React.ComponentProps<"aside"> 116 141 > {} 117 142 118 - export const SidebarLayoutSidebar = ({ 143 + export const SidebarLayoutNavigationSidebar = ({ 119 144 style, 120 145 children, 121 146 ...props 122 - }: SidebarLayoutSidebarProps) => { 147 + }: SidebarLayoutNavigationSidebarProps) => { 123 148 return ( 124 149 <> 125 150 <aside {...props} {...stylex.props(styles.sidebar, style)}> ··· 144 169 ); 145 170 }; 146 171 172 + export interface SidebarLayoutSidebarProps extends StyleXComponentProps< 173 + React.ComponentProps<"aside"> 174 + > { 175 + /** 176 + * At what breakpoint the sidebar should be visible. 177 + */ 178 + visible?: "md" | "lg"; 179 + } 180 + 181 + /** 182 + * A sidebar that is not part of the main content flow. 183 + */ 184 + export const SidebarLayoutInconsequentialSidebar = ({ 185 + style, 186 + children, 187 + visible = "md", 188 + ...props 189 + }: SidebarLayoutSidebarProps) => { 190 + return ( 191 + <aside 192 + {...props} 193 + {...stylex.props( 194 + styles.defaultSidebar, 195 + visible === "md" && styles.visibleMd, 196 + visible === "lg" && styles.visibleLg, 197 + style, 198 + )} 199 + > 200 + {children} 201 + </aside> 202 + ); 203 + }; 204 + 147 205 /** 148 206 * Sidebar layout page component. Slot for main page content. 149 207 */ ··· 164 222 // eslint-disable-next-line react-refresh/only-export-components 165 223 export const SidebarLayout = { 166 224 Root: SidebarLayoutRoot, 167 - Sidebar: SidebarLayoutSidebar, 225 + NavigationSidebar: SidebarLayoutNavigationSidebar, 168 226 Page: SidebarLayoutPage, 227 + InconsequentialSidebar: SidebarLayoutInconsequentialSidebar, 169 228 };
+6 -3
apps/docs/src/components/sidebar/index.tsx
··· 34 34 display: "flex", 35 35 flexDirection: "column", 36 36 paddingBottom: spacing["12"], 37 - paddingLeft: spacing["8"], 38 - paddingRight: spacing["8"], 37 + paddingLeft: spacing["6"], 38 + paddingRight: spacing["4"], 39 39 paddingTop: spacing["6"], 40 40 width: spacing["64"], 41 41 }, 42 42 sidebarHeader: { 43 - padding: spacing["3"], 44 43 alignItems: "center", 45 44 display: "flex", 46 45 justifyContent: "space-between", 46 + paddingBottom: spacing["3"], 47 + paddingLeft: spacing["2"], 48 + paddingRight: spacing["2"], 49 + paddingTop: spacing["3"], 47 50 }, 48 51 sidebarHeaderLink: { 49 52 textDecoration: "none",
+4 -11
apps/docs/src/components/table-of-contents/index.tsx
··· 31 31 flexShrink: 0, 32 32 paddingBottom: spacing["20"], 33 33 paddingTop: spacing["12"], 34 - }, 35 - sticky: { 36 - position: "sticky", 37 - height: "100vh", 38 - marginTop: spacing["12"], 39 - top: 0, 34 + width: "240px", 40 35 }, 41 36 itemList: { 42 37 margin: 0, ··· 132 127 */ 133 128 export interface TableOfContentsProps extends StyleXComponentProps<{ 134 129 toc: Toc; 135 - }> { 136 - sticky?: boolean; 137 - } 130 + }> {} 138 131 139 132 /** 140 133 * A table of contents component that displays a navigation tree based on document headings. 141 134 * Automatically highlights the currently visible heading using IntersectionObserver. 142 135 */ 143 - export function TableOfContents({ toc, style, sticky }: TableOfContentsProps) { 136 + export function TableOfContents({ toc, style }: TableOfContentsProps) { 144 137 const [activeHeaderId, setActiveHeaderId] = useState<string | null>(null); 145 138 146 139 useEffect(() => { ··· 165 158 166 159 return ( 167 160 <ActiveHeaderIdContext value={activeHeaderId}> 168 - <nav {...stylex.props(styles.wrapper, sticky && styles.sticky, style)}> 161 + <nav {...stylex.props(styles.wrapper, style)}> 169 162 <LevelContext value={1}> 170 163 <ul {...stylex.props(styles.itemList)}> 171 164 {toc.map((item) => (
+7 -10
apps/docs/src/components/typography/index.tsx
··· 105 105 whiteSpace: "nowrap", 106 106 }, 107 107 linkedHeadingLink: { 108 - color: "inherit", 109 108 textDecoration: "none", 109 + color: "inherit", 110 110 }, 111 111 linkedHeadingLinkButton: { 112 112 opacity: { 113 113 default: 0, 114 - ":is([data-heading-link]:hover *)": 1, 115 114 ":is([data-focus-visible])": 1, 115 + ":is([data-heading-link]:hover *)": 1, 116 116 }, 117 117 transitionDuration: animationDuration.fast, 118 118 transitionProperty: { ··· 416 416 * The link allows users to jump to the heading, and the button copies the full URL 417 417 * with the anchor to the clipboard. 418 418 */ 419 - export const LinkedHeading = ({ 420 - id, 421 - children, 422 - style, 423 - }: LinkedHeadingProps) => { 419 + export const LinkedHeading = ({ id, children, style }: LinkedHeadingProps) => { 424 420 if (!id) { 425 421 return <>{children}</>; 426 422 } 427 423 428 - const url = typeof window !== "undefined" 429 - ? `${window.location.origin}${window.location.pathname}#${id}` 430 - : `#${id}`; 424 + const url = 425 + globalThis.window === undefined 426 + ? `#${id}` 427 + : `${globalThis.location.origin}${globalThis.location.pathname}#${id}`; 431 428 432 429 return ( 433 430 <Flex
+22 -1
apps/docs/src/docs/components/navigation/sidebar-layout.mdx
··· 8 8 import { Basic } from '../../../examples/sidebar-layout/basic' 9 9 import { WithHeaderLayout } from '../../../examples/sidebar-layout/with-header-layout' 10 10 import { WithHeaderLayoutWrapper } from '../../../examples/sidebar-layout/with-header-layout-wrapper' 11 + import { InconsequentialSidebar } from '../../../examples/sidebar-layout/inconsequential-sidebar' 11 12 12 13 <Example src={Basic} noPadding /> 13 14 ··· 23 24 24 25 This is a custom component built for page layouts with sidebar and content slots. 25 26 26 - <PropDocs components={["SidebarLayoutRoot", "SidebarLayoutSidebar", "SidebarLayoutPage"]} /> 27 + <PropDocs components={["SidebarLayoutRoot", "SidebarLayoutNavigationSidebar", "SidebarLayoutPage", "SidebarLayoutInconsequentialSidebar"]} /> 27 28 28 29 ## Features 30 + 31 + ### InconsequentialSidebar 32 + 33 + The `InconsequentialSidebar` component is a secondary sidebar for supplementary content that is not critical for navigation or core functionality. 34 + 35 + Unlike `NavigationSidebar`, this component: 36 + 37 + - Does not include mobile drawer support 38 + - Simply hides on smaller screens when space is limited 39 + - Is designed for content that can be safely hidden without impacting usability 40 + 41 + #### Use Cases 42 + 43 + - **Table of Contents**: Display document structure and quick navigation 44 + - **Related Links**: Show related articles, resources, or supplementary content 45 + - **Filters & Controls**: Secondary filtering options that aren't critical 46 + - **Metadata**: Additional information like tags, categories, or timestamps 47 + - **Secondary Navigation**: Additional navigation that complements the main sidebar 48 + 49 + <Example src={InconsequentialSidebar} noPadding /> 29 50 30 51 ### With Header Layout 31 52
+2 -2
apps/docs/src/examples/sidebar-layout/basic.tsx
··· 27 27 export function Basic() { 28 28 return ( 29 29 <SidebarLayout.Root> 30 - <SidebarLayout.Sidebar> 30 + <SidebarLayout.NavigationSidebar> 31 31 <Sidebar> 32 32 <SidebarHeader href="/"> 33 33 <Logo /> ··· 38 38 <SidebarItem>Settings</SidebarItem> 39 39 </SidebarSection> 40 40 </Sidebar> 41 - </SidebarLayout.Sidebar> 41 + </SidebarLayout.NavigationSidebar> 42 42 <SidebarLayout.Page> 43 43 <Content> 44 44 <Heading1>Page Content</Heading1>
+116
apps/docs/src/examples/sidebar-layout/inconsequential-sidebar.tsx
··· 1 + import { SidebarLayout } from "@/components/sidebar-layout"; 2 + import { TableOfContents, Toc } from "@/components/table-of-contents"; 3 + import { Content } from "@/components/content"; 4 + import { Heading1, Heading2, Heading3, Body } from "@/components/typography"; 5 + import * as stylex from "@stylexjs/stylex"; 6 + 7 + const styles = stylex.create({ 8 + root: { 9 + maxHeight: "60vh", 10 + overflowY: "auto", 11 + }, 12 + }); 13 + 14 + // Mock table of contents data 15 + const toc: Toc = [ 16 + { 17 + id: "introduction", 18 + value: "Introduction", 19 + depth: 1, 20 + children: [], 21 + }, 22 + { 23 + id: "getting-started", 24 + value: "Getting Started", 25 + depth: 1, 26 + children: [ 27 + { 28 + id: "installation", 29 + value: "Installation", 30 + depth: 2, 31 + children: [], 32 + }, 33 + { 34 + id: "configuration", 35 + value: "Configuration", 36 + depth: 2, 37 + children: [], 38 + }, 39 + ], 40 + }, 41 + { 42 + id: "components", 43 + value: "Components", 44 + depth: 1, 45 + children: [ 46 + { 47 + id: "button", 48 + value: "Button", 49 + depth: 2, 50 + children: [], 51 + }, 52 + { 53 + id: "card", 54 + value: "Card", 55 + depth: 2, 56 + children: [], 57 + }, 58 + ], 59 + }, 60 + ]; 61 + 62 + export function InconsequentialSidebar() { 63 + return ( 64 + <SidebarLayout.Root style={styles.root}> 65 + <SidebarLayout.Page> 66 + <Content> 67 + <Heading1 id="introduction">Introduction</Heading1> 68 + <Body> 69 + This example demonstrates the InconsequentialSidebar component. The 70 + main navigation is on the left, and the table of contents appears on 71 + the right side on large screens. 72 + </Body> 73 + 74 + <Heading2 id="getting-started">Getting Started</Heading2> 75 + <Body> 76 + The InconsequentialSidebar is perfect for supplementary content like 77 + table of contents, related links, or metadata. 78 + </Body> 79 + 80 + <Heading3 id="installation">Installation</Heading3> 81 + <Body> 82 + Resize your browser window to see how the sidebar hides on smaller 83 + screens. It only appears on large screens (lg breakpoint). 84 + </Body> 85 + 86 + <Heading3 id="configuration">Configuration</Heading3> 87 + <Body> 88 + You can control when the sidebar appears using the visible prop. Set 89 + it to "md" for medium screens or "lg" for large screens only. 90 + </Body> 91 + 92 + <Heading2 id="components">Components</Heading2> 93 + <Body> 94 + The InconsequentialSidebar is ideal for content that enhances the 95 + user experience but isn't critical for core functionality. 96 + </Body> 97 + 98 + <Heading3 id="button">Button</Heading3> 99 + <Body> 100 + Unlike NavigationSidebar, this component doesn't include mobile 101 + drawer support. It simply hides when space is limited. 102 + </Body> 103 + 104 + <Heading3 id="card">Card</Heading3> 105 + <Body> 106 + This makes it perfect for supplementary content that can be safely 107 + hidden on smaller screens without impacting usability. 108 + </Body> 109 + </Content> 110 + </SidebarLayout.Page> 111 + <SidebarLayout.InconsequentialSidebar visible="md"> 112 + <TableOfContents toc={toc} /> 113 + </SidebarLayout.InconsequentialSidebar> 114 + </SidebarLayout.Root> 115 + ); 116 + }
+2 -2
apps/docs/src/examples/sidebar-layout/with-header-layout-wrapper.tsx
··· 48 48 </HeaderLayout.Header> 49 49 <HeaderLayout.Page> 50 50 <SidebarLayout.Root> 51 - <SidebarLayout.Sidebar> 51 + <SidebarLayout.NavigationSidebar> 52 52 <Sidebar> 53 53 <SidebarSection title="Navigation"> 54 54 <SidebarItem>Dashboard</SidebarItem> ··· 56 56 <SidebarItem>Settings</SidebarItem> 57 57 </SidebarSection> 58 58 </Sidebar> 59 - </SidebarLayout.Sidebar> 59 + </SidebarLayout.NavigationSidebar> 60 60 <SidebarLayout.Page> 61 61 <Content> 62 62 <Heading1>Page Content</Heading1>
+2 -2
apps/docs/src/examples/sidebar-layout/with-header-layout.tsx
··· 34 34 export function WithHeaderLayout() { 35 35 return ( 36 36 <SidebarLayout.Root> 37 - <SidebarLayout.Sidebar> 37 + <SidebarLayout.NavigationSidebar> 38 38 <Sidebar> 39 39 <SidebarHeader href="/"> 40 40 <Logo /> ··· 45 45 <SidebarItem>Settings</SidebarItem> 46 46 </SidebarSection> 47 47 </Sidebar> 48 - </SidebarLayout.Sidebar> 48 + </SidebarLayout.NavigationSidebar> 49 49 <SidebarLayout.Page> 50 50 <HeaderLayout.Root> 51 51 <HeaderLayout.Header>
+17 -33
apps/docs/src/routes/docs.$.tsx
··· 18 18 19 19 import * as stylex from "@stylexjs/stylex"; 20 20 import { allDocs } from "content-collections"; 21 - import { Suspense } from "react"; 22 21 import { modules, pages } from "virtual:content"; 23 22 24 23 import { Flex } from "@/components/flex"; ··· 43 42 44 43 import { spacing } from "../components/theme/spacing.stylex"; 45 44 import { Content } from "@/components/content"; 46 - import { containerBreakpoints } from "../components/theme/media-queries.stylex"; 45 + import { SidebarLayout } from "@/components/sidebar-layout"; 47 46 48 47 const TypographyRouterLink = createLink(TypographyLink); 49 48 50 49 const styles = stylex.create({ 51 - root: { 52 - width: "100%", 53 - gap: { 54 - default: spacing["4"], 55 - [containerBreakpoints.lg]: spacing["8"], 56 - }, 57 - display: "grid", 58 - gridTemplateColumns: { 59 - default: "minmax(0, 1fr)", 60 - [containerBreakpoints.lg]: "minmax(0, 1fr) 240px", 61 - }, 62 - }, 63 50 header: { 64 51 marginBottom: spacing["12"], 65 - }, 66 - tableOfContents: { 67 - display: { 68 - default: "none", 69 - [containerBreakpoints.lg]: "block", 70 - }, 71 52 }, 72 53 }); 73 54 ··· 170 151 } 171 152 172 153 return ( 173 - <div {...stylex.props(styles.root)}> 174 - <Content> 175 - <Flex direction="column" gap="4" style={styles.header}> 176 - <Heading1>{doc.title}</Heading1> 177 - <Text size="xl" variant="secondary"> 178 - {doc.description} 179 - </Text> 180 - </Flex> 181 - <Suspense fallback={<div>Loading...</div>}> 154 + <> 155 + <SidebarLayout.Page> 156 + <Content> 157 + <Flex direction="column" gap="4" style={styles.header}> 158 + <Heading1>{doc.title}</Heading1> 159 + <Text size="xl" variant="secondary"> 160 + {doc.description} 161 + </Text> 162 + </Flex> 182 163 <Page components={components} /> 183 - </Suspense> 184 - </Content> 164 + </Content> 165 + </SidebarLayout.Page> 166 + 185 167 {toc && ( 186 - <TableOfContents toc={toc} style={styles.tableOfContents} sticky /> 168 + <SidebarLayout.InconsequentialSidebar visible="md"> 169 + <TableOfContents toc={toc} /> 170 + </SidebarLayout.InconsequentialSidebar> 187 171 )} 188 - </div> 172 + </> 189 173 ); 190 174 }
+3 -5
apps/docs/src/routes/docs.tsx
··· 225 225 function RouteComponent() { 226 226 return ( 227 227 <SidebarLayout.Root> 228 - <SidebarLayout.Sidebar> 228 + <SidebarLayout.NavigationSidebar> 229 229 <DocSidebar /> 230 - </SidebarLayout.Sidebar> 231 - <SidebarLayout.Page> 232 - <Outlet /> 233 - </SidebarLayout.Page> 230 + </SidebarLayout.NavigationSidebar> 231 + <Outlet /> 234 232 </SidebarLayout.Root> 235 233 ); 236 234 }
+20 -16
packages/hip-ui/src/components/navbar/Navbar.tsx
··· 17 17 18 18 const styles = stylex.create({ 19 19 wrapper: { 20 + zIndex: 1000, 20 21 borderBottomColor: uiColor.border1, 21 22 borderBottomStyle: "solid", 22 23 borderBottomWidth: 1, 23 - zIndex: 1000, 24 + top: 0, 24 25 width: "100%", 25 - top: 0, 26 26 }, 27 27 navbar: { 28 - marginLeft: "auto", 29 - marginRight: "auto", 30 - borderWidth: 0, 31 - maxWidth: "var(--page-content-max-width)", 32 28 "--separator-visibility": { 33 29 default: "none", 34 30 ":is([data-navbar-open]):has([data-navbar-action])": "flex", ··· 39 35 ":is([data-navbar-open])": "flex", 40 36 [containerBreakpoints.sm]: "none", 41 37 }, 38 + borderWidth: 0, 42 39 gridTemplateAreas: { 43 40 default: ` 44 41 "logo hamburger" ··· 94 91 ":is([data-navbar-open]):has([data-navbar-action])": `min-content min-content min-content min-content`, 95 92 }, 96 93 rowGap: spacing["8"], 94 + marginLeft: "auto", 95 + marginRight: "auto", 96 + maxWidth: "var(--page-content-max-width)", 97 97 minHeight: { 98 98 default: spacing["14"], 99 99 ":is([data-navbar-open])": "100%", ··· 175 175 link: { 176 176 "--underline-opacity": { 177 177 default: 0, 178 + ":is([aria-current=page])": 1, 178 179 ":is([aria-expanded=true])": 1, 179 180 ":is([data-active])": 1, 180 - ":is([data-status=active])": 1, 181 - ":is([aria-current=page])": 1, 182 181 ":is([data-breadcrumb] *)": 0, 183 182 ":is([data-hovered])": 1, 183 + ":is([data-status=active])": 1, 184 184 }, 185 185 gap: spacing["2"], 186 186 textDecoration: "none", ··· 219 219 }); 220 220 221 221 // Define subcomponents first so they can be referenced in Navbar 222 - export interface NavbarLogoProps 223 - extends StyleXComponentProps<React.ComponentProps<"div">> {} 222 + export interface NavbarLogoProps extends StyleXComponentProps< 223 + React.ComponentProps<"div"> 224 + > {} 224 225 225 226 /** 226 227 * NavbarLogo component for displaying the logo in the navbar. ··· 233 234 ); 234 235 }; 235 236 236 - export interface NavbarNavigationProps 237 - extends StyleXComponentProps<React.ComponentProps<"div">> { 237 + export interface NavbarNavigationProps extends StyleXComponentProps< 238 + React.ComponentProps<"div"> 239 + > { 238 240 /** 239 241 * Justify content alignment for the navigation items. 240 242 * @default "left" ··· 267 269 ); 268 270 }; 269 271 270 - export interface NavbarActionProps 271 - extends StyleXComponentProps<React.ComponentProps<"div">> { 272 + export interface NavbarActionProps extends StyleXComponentProps< 273 + React.ComponentProps<"div"> 274 + > { 272 275 /** 273 276 * Whether the action should be always visible on mobile. 274 277 * @default false ··· 311 314 ); 312 315 } 313 316 314 - export interface NavbarProps 315 - extends StyleXComponentProps<React.ComponentProps<"div">> { 317 + export interface NavbarProps extends StyleXComponentProps< 318 + React.ComponentProps<"div"> 319 + > { 316 320 size?: Size; 317 321 } 318 322
+67 -8
packages/hip-ui/src/components/sidebar-layout/index.tsx
··· 12 12 13 13 const styles = stylex.create({ 14 14 wrapper: { 15 - backgroundColor: uiColor.bgSubtle, 15 + backgroundImage: `linear-gradient(to right, ${uiColor.bgSubtle} 50%, ${uiColor.bg} 50%)`, 16 16 position: "relative", 17 17 width: "100cqw", 18 18 }, ··· 24 24 marginLeft: "auto", 25 25 marginRight: "auto", 26 26 maxWidth: "var(--page-content-max-width)", 27 - minHeight: "100vh", 27 + minHeight: "100cqh", 28 28 width: "100%", 29 29 }, 30 + defaultSidebar: { 31 + overflow: "auto", 32 + overscrollBehavior: "contain", 33 + alignSelf: "start", 34 + flexShrink: 0, 35 + position: "sticky", 36 + maxHeight: "100cqh", 37 + top: 0, 38 + }, 30 39 sidebar: { 31 40 overflow: "auto", 32 41 overscrollBehavior: "contain", ··· 40 49 borderRightColor: uiColor.border1, 41 50 borderRightStyle: "solid", 42 51 borderRightWidth: 1, 43 - height: "100vh", 52 + height: "100cqh", 44 53 overflowX: "hidden", 45 54 overflowY: "auto", 46 55 top: 0, 47 56 }, 57 + visibleMd: { 58 + display: { 59 + default: "none", 60 + [containerBreakpoints.md]: "block", 61 + }, 62 + }, 63 + visibleLg: { 64 + display: { 65 + default: "none", 66 + [containerBreakpoints.lg]: "block", 67 + }, 68 + }, 48 69 drawer: { 49 70 display: { 50 71 default: "flex", ··· 73 94 }, 74 95 paddingRight: { 75 96 default: spacing["4"], 76 - [containerBreakpoints.sm]: spacing["16"], 97 + [containerBreakpoints.lg]: spacing["8"], 77 98 ":has(> [data-header-layout=true])": "0 !important", 99 + ":last-child": { 100 + default: spacing["4"], 101 + [containerBreakpoints.sm]: spacing["16"], 102 + }, 78 103 }, 79 104 paddingTop: { 80 105 default: spacing["2"], ··· 111 136 /** 112 137 * Sidebar layout sidebar component. Slot for sidebar content. 113 138 */ 114 - export interface SidebarLayoutSidebarProps extends StyleXComponentProps< 139 + export interface SidebarLayoutNavigationSidebarProps extends StyleXComponentProps< 115 140 React.ComponentProps<"aside"> 116 141 > {} 117 142 118 - export const SidebarLayoutSidebar = ({ 143 + export const SidebarLayoutNavigationSidebar = ({ 119 144 style, 120 145 children, 121 146 ...props 122 - }: SidebarLayoutSidebarProps) => { 147 + }: SidebarLayoutNavigationSidebarProps) => { 123 148 return ( 124 149 <> 125 150 <aside {...props} {...stylex.props(styles.sidebar, style)}> ··· 144 169 ); 145 170 }; 146 171 172 + export interface SidebarLayoutSidebarProps extends StyleXComponentProps< 173 + React.ComponentProps<"aside"> 174 + > { 175 + /** 176 + * At what breakpoint the sidebar should be visible. 177 + */ 178 + visible?: "md" | "lg"; 179 + } 180 + 181 + /** 182 + * A sidebar that is not part of the main content flow. 183 + */ 184 + export const SidebarLayoutInconsequentialSidebar = ({ 185 + style, 186 + children, 187 + visible = "md", 188 + ...props 189 + }: SidebarLayoutSidebarProps) => { 190 + return ( 191 + <aside 192 + {...props} 193 + {...stylex.props( 194 + styles.defaultSidebar, 195 + visible === "md" && styles.visibleMd, 196 + visible === "lg" && styles.visibleLg, 197 + style, 198 + )} 199 + > 200 + {children} 201 + </aside> 202 + ); 203 + }; 204 + 147 205 /** 148 206 * Sidebar layout page component. Slot for main page content. 149 207 */ ··· 164 222 // eslint-disable-next-line react-refresh/only-export-components 165 223 export const SidebarLayout = { 166 224 Root: SidebarLayoutRoot, 167 - Sidebar: SidebarLayoutSidebar, 225 + NavigationSidebar: SidebarLayoutNavigationSidebar, 168 226 Page: SidebarLayoutPage, 227 + InconsequentialSidebar: SidebarLayoutInconsequentialSidebar, 169 228 };
+6 -3
packages/hip-ui/src/components/sidebar/index.tsx
··· 34 34 display: "flex", 35 35 flexDirection: "column", 36 36 paddingBottom: spacing["12"], 37 - paddingLeft: spacing["8"], 38 - paddingRight: spacing["8"], 37 + paddingLeft: spacing["6"], 38 + paddingRight: spacing["4"], 39 39 paddingTop: spacing["6"], 40 40 width: spacing["64"], 41 41 }, 42 42 sidebarHeader: { 43 - padding: spacing["3"], 44 43 alignItems: "center", 45 44 display: "flex", 46 45 justifyContent: "space-between", 46 + paddingBottom: spacing["3"], 47 + paddingLeft: spacing["2"], 48 + paddingRight: spacing["2"], 49 + paddingTop: spacing["3"], 47 50 }, 48 51 sidebarHeaderLink: { 49 52 textDecoration: "none",
+4 -11
packages/hip-ui/src/components/table-of-contents/index.tsx
··· 31 31 flexShrink: 0, 32 32 paddingBottom: spacing["20"], 33 33 paddingTop: spacing["12"], 34 - }, 35 - sticky: { 36 - position: "sticky", 37 - height: "100vh", 38 - marginTop: spacing["12"], 39 - top: 0, 34 + width: "240px", 40 35 }, 41 36 itemList: { 42 37 margin: 0, ··· 132 127 */ 133 128 export interface TableOfContentsProps extends StyleXComponentProps<{ 134 129 toc: Toc; 135 - }> { 136 - sticky?: boolean; 137 - } 130 + }> {} 138 131 139 132 /** 140 133 * A table of contents component that displays a navigation tree based on document headings. 141 134 * Automatically highlights the currently visible heading using IntersectionObserver. 142 135 */ 143 - export function TableOfContents({ toc, style, sticky }: TableOfContentsProps) { 136 + export function TableOfContents({ toc, style }: TableOfContentsProps) { 144 137 const [activeHeaderId, setActiveHeaderId] = useState<string | null>(null); 145 138 146 139 useEffect(() => { ··· 165 158 166 159 return ( 167 160 <ActiveHeaderIdContext value={activeHeaderId}> 168 - <nav {...stylex.props(styles.wrapper, sticky && styles.sticky, style)}> 161 + <nav {...stylex.props(styles.wrapper, style)}> 169 162 <LevelContext value={1}> 170 163 <ul {...stylex.props(styles.itemList)}> 171 164 {toc.map((item) => (