@zendir/ui 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +419 -406
  2. package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
  3. package/dist/react/3d/ZenSpace3D.js.map +1 -1
  4. package/dist/react/3d/ZenSpace3DCesium.js.map +1 -1
  5. package/dist/react/3d/ZenSpace3DShaders.js.map +1 -1
  6. package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
  7. package/dist/react/3d/capturePngAnalysis.js.map +1 -1
  8. package/dist/react/3d/threeLoader.js.map +1 -1
  9. package/dist/react/astro/ClassificationBanner.js.map +1 -1
  10. package/dist/react/astro/GlobalStatusBar.js.map +1 -1
  11. package/dist/react/astro/MissionClock.js.map +1 -1
  12. package/dist/react/astro/MonitoringIcon.js.map +1 -1
  13. package/dist/react/astro/Notification.js.map +1 -1
  14. package/dist/react/astro/Progress.js.map +1 -1
  15. package/dist/react/astro/SimulationControls.js.map +1 -1
  16. package/dist/react/astro/StatusIndicator.js.map +1 -1
  17. package/dist/react/astro/UnifiedTimeline.js.map +1 -1
  18. package/dist/react/cards/AccessCard.js.map +1 -1
  19. package/dist/react/cards/OrbitCard.js.map +1 -1
  20. package/dist/react/cards/SpacecraftCard.js.map +1 -1
  21. package/dist/react/cards/TelemetryCard.js.map +1 -1
  22. package/dist/react/cards/TelemetryStreamCard.js.map +1 -1
  23. package/dist/react/charts/GroundTrackMap.js.map +1 -1
  24. package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
  25. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
  26. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +1 -1
  27. package/dist/react/charts/unified/AstroChart.js.map +1 -1
  28. package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -1
  29. package/dist/react/charts/unified/domain.js.map +1 -1
  30. package/dist/react/charts/unified/generators.js.map +1 -1
  31. package/dist/react/charts/unified/presets.js.map +1 -1
  32. package/dist/react/charts/unified/sync.js.map +1 -1
  33. package/dist/react/charts/unified/theme.js.map +1 -1
  34. package/dist/react/charts/unified/useChartStream.js.map +1 -1
  35. package/dist/react/chatgpt/index.js.map +1 -1
  36. package/dist/react/context/CategoryContext.js.map +1 -1
  37. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  38. package/dist/react/context/SpatialSelectionContext.js.map +1 -1
  39. package/dist/react/core/data/DataTable.js.map +1 -1
  40. package/dist/react/core/data/DataValue.js.map +1 -1
  41. package/dist/react/core/data/propertyConfig.js.map +1 -1
  42. package/dist/react/core/display/AstroIcon.js.map +1 -1
  43. package/dist/react/core/display/Badge.js.map +1 -1
  44. package/dist/react/core/display/CardHeader.js.map +1 -1
  45. package/dist/react/core/display/Container.js.map +1 -1
  46. package/dist/react/core/display/CopyButton.js.map +1 -1
  47. package/dist/react/core/display/GlassCard.js.map +1 -1
  48. package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -1
  49. package/dist/react/core/display/Icon.js.map +1 -1
  50. package/dist/react/core/display/Typography.js.map +1 -1
  51. package/dist/react/core/feedback/ConfirmDialog.js.map +1 -1
  52. package/dist/react/core/feedback/Dialog.js.map +1 -1
  53. package/dist/react/core/feedback/Toast.js.map +1 -1
  54. package/dist/react/core/inputs/Button.js.map +1 -1
  55. package/dist/react/core/inputs/Checkbox.js.map +1 -1
  56. package/dist/react/core/inputs/Input.js.map +1 -1
  57. package/dist/react/core/inputs/LimitsBar.js.map +1 -1
  58. package/dist/react/core/inputs/NumberInput.js.map +1 -1
  59. package/dist/react/core/inputs/PinInput.js.map +1 -1
  60. package/dist/react/core/inputs/Select.js.map +1 -1
  61. package/dist/react/core/inputs/Toggle.js.map +1 -1
  62. package/dist/react/core/layout/Box.js.map +1 -1
  63. package/dist/react/core/layout/Center.js.map +1 -1
  64. package/dist/react/core/layout/Divider.js.map +1 -1
  65. package/dist/react/core/layout/Flex.js.map +1 -1
  66. package/dist/react/core/layout/Grid.js.map +1 -1
  67. package/dist/react/core/layout/Spacer.js.map +1 -1
  68. package/dist/react/core/layout/Stack.js.map +1 -1
  69. package/dist/react/core/layout/responsive.js.map +1 -1
  70. package/dist/react/core/layout/useBreakpoint.js.map +1 -1
  71. package/dist/react/core/navigation/AppBar.js.map +1 -1
  72. package/dist/react/core/navigation/Pagination.js.map +1 -1
  73. package/dist/react/core/navigation/SideNav.js.map +1 -1
  74. package/dist/react/core/navigation/Tabs.js.map +1 -1
  75. package/dist/react/core/overlays/Popover.js.map +1 -1
  76. package/dist/react/core/overlays/SidePanel.js.map +1 -1
  77. package/dist/react/core/overlays/Tooltip.js.map +1 -1
  78. package/dist/react/core/widgets/ActivityPlanner.js.map +1 -1
  79. package/dist/react/core/widgets/Capture.js.map +1 -1
  80. package/dist/react/core/widgets/ChatPanel.js.map +1 -1
  81. package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -1
  82. package/dist/react/core/widgets/CommandBuilder.js.map +1 -1
  83. package/dist/react/core/widgets/ConnectionForm.js.map +1 -1
  84. package/dist/react/core/widgets/FileExplorer.js.map +1 -1
  85. package/dist/react/core/widgets/HexViewer.js.map +1 -1
  86. package/dist/react/core/widgets/ImageFrame.js.map +1 -1
  87. package/dist/react/core/widgets/ImageGallery.js.map +1 -1
  88. package/dist/react/core/widgets/ImagePanel.js.map +1 -1
  89. package/dist/react/core/widgets/LogViewer.js.map +1 -1
  90. package/dist/react/core/widgets/MessageStream.js.map +1 -1
  91. package/dist/react/core/widgets/MissionCalendar.js.map +1 -1
  92. package/dist/react/core/widgets/PacketViewer.js.map +1 -1
  93. package/dist/react/hooks/useCompactMode.js.map +1 -1
  94. package/dist/react/hooks/useSimulationScene.js.map +1 -1
  95. package/dist/react/panels/LayerControlPanel.js.map +1 -1
  96. package/dist/react/panels/ObjectInventoryPanel.js.map +1 -1
  97. package/dist/react/shared/ErrorBoundary.js.map +1 -1
  98. package/dist/react/shared/Skeleton.js.map +1 -1
  99. package/dist/react/theme/ThemeProvider.js +2 -1
  100. package/dist/react/theme/ThemeProvider.js.map +1 -1
  101. package/dist/react/theme/cardAccent.js.map +1 -1
  102. package/dist/react/theme/config.js.map +1 -1
  103. package/dist/react/theme/types.js.map +1 -1
  104. package/dist/react/types.js.map +1 -1
  105. package/dist/react/utils/categoryPalette.js.map +1 -1
  106. package/dist/react/utils/index.js.map +1 -1
  107. package/dist/style.css +216 -216
  108. package/dist/tokens/core.js.map +1 -1
  109. package/dist/tokens/index.js.map +1 -1
  110. package/dist/tokens/palettes/astro.js.map +1 -1
  111. package/dist/tokens/palettes/index.js.map +1 -1
  112. package/dist/tokens/palettes/tailwind.js.map +1 -1
  113. package/dist/tokens/palettes/zendir.js.map +1 -1
  114. package/dist/tokens/themes.js.map +1 -1
  115. package/dist/tokens/tokens.css +533 -533
  116. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Flex.js","names":[],"sources":["../../../../src/react/core/layout/Flex.tsx"],"sourcesContent":["/**\n * @zendir/ui - Flex Layout Primitive\n *\n * Flexbox container with theme-aware spacing and responsive direction/alignment.\n * The workhorse layout component for horizontal and vertical arrangements.\n *\n * Astro UX Compliance:\n * - 4px grid spacing tokens\n * - Responsive gap for mobile → mission control\n *\n * @example\n * ```tsx\n * // Horizontal row with centered items\n * <Flex gap=\"md\" align=\"center\">\n * <StatusIndicator status=\"normal\" />\n * <Body1>All Systems Nominal</Body1>\n * </Flex>\n *\n * // Vertical column, responsive gap\n * <Flex direction=\"column\" gap={['sm', 'md', 'lg']}>\n * <TelemetryCard />\n * <LinkBudgetCard />\n * </Flex>\n *\n * // Space between items\n * <Flex justify=\"space-between\" align=\"center\">\n * <H3>Telemetry</H3>\n * <Button variant=\"secondary\">Refresh</Button>\n * </Flex>\n * ```\n */\n\nimport React, { memo, forwardRef } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { useBreakpoint } from \"./useBreakpoint\";\nimport { resolveResponsiveSpacing, resolveResponsive } from \"./responsive\";\nimport type { ResponsiveValue } from \"./useBreakpoint\";\nimport type { SpacingToken } from \"./responsive\";\nimport type { BoxProps } from \"./Box\";\n\ntype SpacingInput = SpacingToken | string | number;\n\nexport interface FlexProps extends BoxProps {\n /** Flex direction */\n direction?: ResponsiveValue<\n \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\"\n >;\n /** Flex wrap */\n wrap?: ResponsiveValue<\"nowrap\" | \"wrap\" | \"wrap-reverse\">;\n /** Gap between children (spacing token, px number, or CSS string) */\n gap?: ResponsiveValue<SpacingInput>;\n /** Row gap (overrides gap for rows) */\n rowGap?: ResponsiveValue<SpacingInput>;\n /** Column gap (overrides gap for columns) */\n columnGap?: ResponsiveValue<SpacingInput>;\n /** Align items (cross-axis) */\n align?: ResponsiveValue<\n \"flex-start\" | \"flex-end\" | \"center\" | \"baseline\" | \"stretch\"\n >;\n /** Justify content (main-axis) */\n justify?: ResponsiveValue<\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\"\n >;\n /** Shorthand: set both direction=\"column\" */\n column?: boolean;\n /** Shorthand: center both axes */\n center?: boolean;\n /** Make flex container inline */\n inline?: boolean;\n}\n\nexport const Flex = memo(\n forwardRef<HTMLDivElement, FlexProps>(function Flex(\n {\n direction,\n wrap,\n gap,\n rowGap,\n columnGap,\n align,\n justify,\n column = false,\n center = false,\n inline = false,\n style,\n children,\n // Extract BoxProps we handle ourselves\n padding,\n p,\n px,\n py,\n pt,\n pr,\n pb,\n pl,\n margin,\n m,\n mx,\n my,\n mt,\n mr,\n mb,\n ml,\n background,\n border,\n borderRadius,\n shadow,\n display: _display,\n width,\n height,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n overflow,\n position,\n flex: flexProp,\n flexGrow,\n flexShrink,\n as: Component = \"div\",\n ...rest\n },\n ref,\n ): React.ReactElement {\n const { tokens } = useTheme();\n const { breakpoint } = useBreakpoint();\n\n const resolveSpacing = (val: ResponsiveValue<SpacingInput> | undefined) =>\n resolveResponsiveSpacing(val, breakpoint, tokens);\n\n // Resolve padding\n const paddingAll = resolveSpacing(padding ?? p);\n const paddingXVal = resolveSpacing(px);\n const paddingYVal = resolveSpacing(py);\n\n // Resolve margin\n const marginAll = resolveSpacing(margin ?? m);\n const marginXVal = resolveSpacing(mx);\n const marginYVal = resolveSpacing(my);\n\n // Background color resolution\n const bgMap: Record<string, string> = {\n base: tokens.colors.background.base,\n surface: tokens.colors.background.surface,\n elevated: tokens.colors.background.elevated,\n overlay: tokens.colors.background.overlay,\n };\n\n const resolveSize = (\n val: string | number | undefined,\n ): string | undefined => {\n if (val === undefined) return undefined;\n if (typeof val === \"number\") return `${val}px`;\n return val;\n };\n\n const resolvedDirection = column\n ? \"column\"\n : (resolveResponsive(direction, breakpoint) ?? \"row\");\n\n // Resolve gap values — use conditional spreads to avoid setting\n // rowGap/columnGap to undefined, which clears the gap shorthand\n // in browsers (setting `style.rowGap = ''` removes the value\n // that `style.gap` set for row-gap).\n const resolvedGap = resolveSpacing(gap);\n const resolvedRowGap = resolveSpacing(rowGap);\n const resolvedColumnGap = resolveSpacing(columnGap);\n\n const computedStyle: React.CSSProperties = {\n display: inline ? \"inline-flex\" : \"flex\",\n flexDirection: resolvedDirection,\n flexWrap: resolveResponsive(wrap, breakpoint),\n ...(resolvedGap !== undefined ? { gap: resolvedGap } : {}),\n ...(resolvedRowGap !== undefined ? { rowGap: resolvedRowGap } : {}),\n ...(resolvedColumnGap !== undefined\n ? { columnGap: resolvedColumnGap }\n : {}),\n alignItems: center ? \"center\" : resolveResponsive(align, breakpoint),\n justifyContent: center\n ? \"center\"\n : resolveResponsive(justify, breakpoint),\n\n // Padding\n ...(paddingAll ? { padding: paddingAll } : {}),\n ...(paddingXVal\n ? { paddingLeft: paddingXVal, paddingRight: paddingXVal }\n : {}),\n ...(paddingYVal\n ? { paddingTop: paddingYVal, paddingBottom: paddingYVal }\n : {}),\n ...(resolveSpacing(pt) ? { paddingTop: resolveSpacing(pt) } : {}),\n ...(resolveSpacing(pr) ? { paddingRight: resolveSpacing(pr) } : {}),\n ...(resolveSpacing(pb) ? { paddingBottom: resolveSpacing(pb) } : {}),\n ...(resolveSpacing(pl) ? { paddingLeft: resolveSpacing(pl) } : {}),\n\n // Margin\n ...(marginAll ? { margin: marginAll } : {}),\n ...(marginXVal\n ? { marginLeft: marginXVal, marginRight: marginXVal }\n : {}),\n ...(marginYVal\n ? { marginTop: marginYVal, marginBottom: marginYVal }\n : {}),\n ...(resolveSpacing(mt) ? { marginTop: resolveSpacing(mt) } : {}),\n ...(resolveSpacing(mr) ? { marginRight: resolveSpacing(mr) } : {}),\n ...(resolveSpacing(mb) ? { marginBottom: resolveSpacing(mb) } : {}),\n ...(resolveSpacing(ml) ? { marginLeft: resolveSpacing(ml) } : {}),\n\n // Visual\n ...(background\n ? { backgroundColor: bgMap[background] || background }\n : {}),\n ...(border\n ? {\n border:\n border === true\n ? `1px solid ${tokens.colors.border.default}`\n : (border as string),\n }\n : {}),\n ...(borderRadius\n ? {\n borderRadius:\n (tokens.borderRadius as Record<string, string>)[\n borderRadius as string\n ] || borderRadius,\n }\n : {}),\n ...(shadow && shadow !== \"glow\"\n ? {\n boxShadow:\n (tokens.shadows as unknown as Record<string, string>)[\n shadow as string\n ] || shadow,\n }\n : {}),\n\n // Size\n width: resolveSize(resolveResponsive(width, breakpoint)),\n height: resolveSize(resolveResponsive(height, breakpoint)),\n minWidth: resolveSize(minWidth),\n minHeight: resolveSize(minHeight),\n maxWidth: resolveSize(maxWidth),\n maxHeight: resolveSize(maxHeight),\n overflow,\n position,\n flex: flexProp,\n flexGrow,\n flexShrink,\n\n ...style,\n };\n\n return (\n <Component ref={ref} style={computedStyle} {...rest}>\n {children}\n </Component>\n );\n }),\n);\n\nexport default Flex;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Flex.js","names":[],"sources":["../../../../src/react/core/layout/Flex.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Flex Layout Primitive\r\n *\r\n * Flexbox container with theme-aware spacing and responsive direction/alignment.\r\n * The workhorse layout component for horizontal and vertical arrangements.\r\n *\r\n * Astro UX Compliance:\r\n * - 4px grid spacing tokens\r\n * - Responsive gap for mobile → mission control\r\n *\r\n * @example\r\n * ```tsx\r\n * // Horizontal row with centered items\r\n * <Flex gap=\"md\" align=\"center\">\r\n * <StatusIndicator status=\"normal\" />\r\n * <Body1>All Systems Nominal</Body1>\r\n * </Flex>\r\n *\r\n * // Vertical column, responsive gap\r\n * <Flex direction=\"column\" gap={['sm', 'md', 'lg']}>\r\n * <TelemetryCard />\r\n * <LinkBudgetCard />\r\n * </Flex>\r\n *\r\n * // Space between items\r\n * <Flex justify=\"space-between\" align=\"center\">\r\n * <H3>Telemetry</H3>\r\n * <Button variant=\"secondary\">Refresh</Button>\r\n * </Flex>\r\n * ```\r\n */\r\n\r\nimport React, { memo, forwardRef } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { useBreakpoint } from \"./useBreakpoint\";\r\nimport { resolveResponsiveSpacing, resolveResponsive } from \"./responsive\";\r\nimport type { ResponsiveValue } from \"./useBreakpoint\";\r\nimport type { SpacingToken } from \"./responsive\";\r\nimport type { BoxProps } from \"./Box\";\r\n\r\ntype SpacingInput = SpacingToken | string | number;\r\n\r\nexport interface FlexProps extends BoxProps {\r\n /** Flex direction */\r\n direction?: ResponsiveValue<\r\n \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\"\r\n >;\r\n /** Flex wrap */\r\n wrap?: ResponsiveValue<\"nowrap\" | \"wrap\" | \"wrap-reverse\">;\r\n /** Gap between children (spacing token, px number, or CSS string) */\r\n gap?: ResponsiveValue<SpacingInput>;\r\n /** Row gap (overrides gap for rows) */\r\n rowGap?: ResponsiveValue<SpacingInput>;\r\n /** Column gap (overrides gap for columns) */\r\n columnGap?: ResponsiveValue<SpacingInput>;\r\n /** Align items (cross-axis) */\r\n align?: ResponsiveValue<\r\n \"flex-start\" | \"flex-end\" | \"center\" | \"baseline\" | \"stretch\"\r\n >;\r\n /** Justify content (main-axis) */\r\n justify?: ResponsiveValue<\r\n | \"flex-start\"\r\n | \"flex-end\"\r\n | \"center\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\"\r\n >;\r\n /** Shorthand: set both direction=\"column\" */\r\n column?: boolean;\r\n /** Shorthand: center both axes */\r\n center?: boolean;\r\n /** Make flex container inline */\r\n inline?: boolean;\r\n}\r\n\r\nexport const Flex = memo(\r\n forwardRef<HTMLDivElement, FlexProps>(function Flex(\r\n {\r\n direction,\r\n wrap,\r\n gap,\r\n rowGap,\r\n columnGap,\r\n align,\r\n justify,\r\n column = false,\r\n center = false,\r\n inline = false,\r\n style,\r\n children,\r\n // Extract BoxProps we handle ourselves\r\n padding,\r\n p,\r\n px,\r\n py,\r\n pt,\r\n pr,\r\n pb,\r\n pl,\r\n margin,\r\n m,\r\n mx,\r\n my,\r\n mt,\r\n mr,\r\n mb,\r\n ml,\r\n background,\r\n border,\r\n borderRadius,\r\n shadow,\r\n display: _display,\r\n width,\r\n height,\r\n minWidth,\r\n minHeight,\r\n maxWidth,\r\n maxHeight,\r\n overflow,\r\n position,\r\n flex: flexProp,\r\n flexGrow,\r\n flexShrink,\r\n as: Component = \"div\",\r\n ...rest\r\n },\r\n ref,\r\n ): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { breakpoint } = useBreakpoint();\r\n\r\n const resolveSpacing = (val: ResponsiveValue<SpacingInput> | undefined) =>\r\n resolveResponsiveSpacing(val, breakpoint, tokens);\r\n\r\n // Resolve padding\r\n const paddingAll = resolveSpacing(padding ?? p);\r\n const paddingXVal = resolveSpacing(px);\r\n const paddingYVal = resolveSpacing(py);\r\n\r\n // Resolve margin\r\n const marginAll = resolveSpacing(margin ?? m);\r\n const marginXVal = resolveSpacing(mx);\r\n const marginYVal = resolveSpacing(my);\r\n\r\n // Background color resolution\r\n const bgMap: Record<string, string> = {\r\n base: tokens.colors.background.base,\r\n surface: tokens.colors.background.surface,\r\n elevated: tokens.colors.background.elevated,\r\n overlay: tokens.colors.background.overlay,\r\n };\r\n\r\n const resolveSize = (\r\n val: string | number | undefined,\r\n ): string | undefined => {\r\n if (val === undefined) return undefined;\r\n if (typeof val === \"number\") return `${val}px`;\r\n return val;\r\n };\r\n\r\n const resolvedDirection = column\r\n ? \"column\"\r\n : (resolveResponsive(direction, breakpoint) ?? \"row\");\r\n\r\n // Resolve gap values — use conditional spreads to avoid setting\r\n // rowGap/columnGap to undefined, which clears the gap shorthand\r\n // in browsers (setting `style.rowGap = ''` removes the value\r\n // that `style.gap` set for row-gap).\r\n const resolvedGap = resolveSpacing(gap);\r\n const resolvedRowGap = resolveSpacing(rowGap);\r\n const resolvedColumnGap = resolveSpacing(columnGap);\r\n\r\n const computedStyle: React.CSSProperties = {\r\n display: inline ? \"inline-flex\" : \"flex\",\r\n flexDirection: resolvedDirection,\r\n flexWrap: resolveResponsive(wrap, breakpoint),\r\n ...(resolvedGap !== undefined ? { gap: resolvedGap } : {}),\r\n ...(resolvedRowGap !== undefined ? { rowGap: resolvedRowGap } : {}),\r\n ...(resolvedColumnGap !== undefined\r\n ? { columnGap: resolvedColumnGap }\r\n : {}),\r\n alignItems: center ? \"center\" : resolveResponsive(align, breakpoint),\r\n justifyContent: center\r\n ? \"center\"\r\n : resolveResponsive(justify, breakpoint),\r\n\r\n // Padding\r\n ...(paddingAll ? { padding: paddingAll } : {}),\r\n ...(paddingXVal\r\n ? { paddingLeft: paddingXVal, paddingRight: paddingXVal }\r\n : {}),\r\n ...(paddingYVal\r\n ? { paddingTop: paddingYVal, paddingBottom: paddingYVal }\r\n : {}),\r\n ...(resolveSpacing(pt) ? { paddingTop: resolveSpacing(pt) } : {}),\r\n ...(resolveSpacing(pr) ? { paddingRight: resolveSpacing(pr) } : {}),\r\n ...(resolveSpacing(pb) ? { paddingBottom: resolveSpacing(pb) } : {}),\r\n ...(resolveSpacing(pl) ? { paddingLeft: resolveSpacing(pl) } : {}),\r\n\r\n // Margin\r\n ...(marginAll ? { margin: marginAll } : {}),\r\n ...(marginXVal\r\n ? { marginLeft: marginXVal, marginRight: marginXVal }\r\n : {}),\r\n ...(marginYVal\r\n ? { marginTop: marginYVal, marginBottom: marginYVal }\r\n : {}),\r\n ...(resolveSpacing(mt) ? { marginTop: resolveSpacing(mt) } : {}),\r\n ...(resolveSpacing(mr) ? { marginRight: resolveSpacing(mr) } : {}),\r\n ...(resolveSpacing(mb) ? { marginBottom: resolveSpacing(mb) } : {}),\r\n ...(resolveSpacing(ml) ? { marginLeft: resolveSpacing(ml) } : {}),\r\n\r\n // Visual\r\n ...(background\r\n ? { backgroundColor: bgMap[background] || background }\r\n : {}),\r\n ...(border\r\n ? {\r\n border:\r\n border === true\r\n ? `1px solid ${tokens.colors.border.default}`\r\n : (border as string),\r\n }\r\n : {}),\r\n ...(borderRadius\r\n ? {\r\n borderRadius:\r\n (tokens.borderRadius as Record<string, string>)[\r\n borderRadius as string\r\n ] || borderRadius,\r\n }\r\n : {}),\r\n ...(shadow && shadow !== \"glow\"\r\n ? {\r\n boxShadow:\r\n (tokens.shadows as unknown as Record<string, string>)[\r\n shadow as string\r\n ] || shadow,\r\n }\r\n : {}),\r\n\r\n // Size\r\n width: resolveSize(resolveResponsive(width, breakpoint)),\r\n height: resolveSize(resolveResponsive(height, breakpoint)),\r\n minWidth: resolveSize(minWidth),\r\n minHeight: resolveSize(minHeight),\r\n maxWidth: resolveSize(maxWidth),\r\n maxHeight: resolveSize(maxHeight),\r\n overflow,\r\n position,\r\n flex: flexProp,\r\n flexGrow,\r\n flexShrink,\r\n\r\n ...style,\r\n };\r\n\r\n return (\r\n <Component ref={ref} style={computedStyle} {...rest}>\r\n {children}\r\n </Component>\r\n );\r\n }),\r\n);\r\n\r\nexport default Flex;\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,IAAa,OAAO,KAClB,WAAsC,SAAS,KAC7C,EACE,WACA,MACA,KACA,QACA,WACA,OACA,SACA,SAAS,OACT,SAAS,OACT,SAAS,OACT,OACA,UAEA,SACA,GACA,IACA,IACA,IACA,IACA,IACA,IACA,QACA,GACA,IACA,IACA,IACA,IACA,IACA,IACA,YACA,QACA,cACA,QACA,SAAS,UACT,OACA,QACA,UACA,WACA,UACA,WACA,UACA,UACA,MAAM,UACN,UACA,YACA,IAAI,YAAY,OAChB,GAAG,QAEL,KACoB;CACpB,MAAM,EAAE,WAAW,SAAS;CAC5B,MAAM,EAAE,eAAe,cAAc;CAErC,MAAM,kBAAkB,QACtB,yBAAyB,KAAK,YAAY,MAAM;CAGlD,MAAM,aAAa,eAAe,WAAW,CAAC;CAC9C,MAAM,cAAc,eAAe,EAAE;CACrC,MAAM,cAAc,eAAe,EAAE;CAGrC,MAAM,YAAY,eAAe,UAAU,CAAC;CAC5C,MAAM,aAAa,eAAe,EAAE;CACpC,MAAM,aAAa,eAAe,EAAE;CAGpC,MAAM,QAAgC;EACpC,MAAM,OAAO,OAAO,WAAW;EAC/B,SAAS,OAAO,OAAO,WAAW;EAClC,UAAU,OAAO,OAAO,WAAW;EACnC,SAAS,OAAO,OAAO,WAAW;CACpC;CAEA,MAAM,eACJ,QACuB;EACvB,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;EAC9B,IAAI,OAAO,QAAQ,UAAU,OAAO,GAAG,IAAI;EAC3C,OAAO;CACT;CAEA,MAAM,oBAAoB,SACtB,WACC,kBAAkB,WAAW,UAAU,KAAK;CAMjD,MAAM,cAAc,eAAe,GAAG;CACtC,MAAM,iBAAiB,eAAe,MAAM;CAC5C,MAAM,oBAAoB,eAAe,SAAS;CAuFlD,OACE,oBAAC,WAAD;EAAgB;EAAK,OAAO;GArF5B,SAAS,SAAS,gBAAgB;GAClC,eAAe;GACf,UAAU,kBAAkB,MAAM,UAAU;GAC5C,GAAI,gBAAgB,KAAA,IAAY,EAAE,KAAK,YAAY,IAAI,CAAC;GACxD,GAAI,mBAAmB,KAAA,IAAY,EAAE,QAAQ,eAAe,IAAI,CAAC;GACjE,GAAI,sBAAsB,KAAA,IACtB,EAAE,WAAW,kBAAkB,IAC/B,CAAC;GACL,YAAY,SAAS,WAAW,kBAAkB,OAAO,UAAU;GACnE,gBAAgB,SACZ,WACA,kBAAkB,SAAS,UAAU;GAGzC,GAAI,aAAa,EAAE,SAAS,WAAW,IAAI,CAAC;GAC5C,GAAI,cACA;IAAE,aAAa;IAAa,cAAc;GAAY,IACtD,CAAC;GACL,GAAI,cACA;IAAE,YAAY;IAAa,eAAe;GAAY,IACtD,CAAC;GACL,GAAI,eAAe,EAAE,IAAI,EAAE,YAAY,eAAe,EAAE,EAAE,IAAI,CAAC;GAC/D,GAAI,eAAe,EAAE,IAAI,EAAE,cAAc,eAAe,EAAE,EAAE,IAAI,CAAC;GACjE,GAAI,eAAe,EAAE,IAAI,EAAE,eAAe,eAAe,EAAE,EAAE,IAAI,CAAC;GAClE,GAAI,eAAe,EAAE,IAAI,EAAE,aAAa,eAAe,EAAE,EAAE,IAAI,CAAC;GAGhE,GAAI,YAAY,EAAE,QAAQ,UAAU,IAAI,CAAC;GACzC,GAAI,aACA;IAAE,YAAY;IAAY,aAAa;GAAW,IAClD,CAAC;GACL,GAAI,aACA;IAAE,WAAW;IAAY,cAAc;GAAW,IAClD,CAAC;GACL,GAAI,eAAe,EAAE,IAAI,EAAE,WAAW,eAAe,EAAE,EAAE,IAAI,CAAC;GAC9D,GAAI,eAAe,EAAE,IAAI,EAAE,aAAa,eAAe,EAAE,EAAE,IAAI,CAAC;GAChE,GAAI,eAAe,EAAE,IAAI,EAAE,cAAc,eAAe,EAAE,EAAE,IAAI,CAAC;GACjE,GAAI,eAAe,EAAE,IAAI,EAAE,YAAY,eAAe,EAAE,EAAE,IAAI,CAAC;GAG/D,GAAI,aACA,EAAE,iBAAiB,MAAM,eAAe,WAAW,IACnD,CAAC;GACL,GAAI,SACA,EACE,QACE,WAAW,OACP,aAAa,OAAO,OAAO,OAAO,YACjC,OACT,IACA,CAAC;GACL,GAAI,eACA,EACE,cACG,OAAO,aACN,iBACG,aACT,IACA,CAAC;GACL,GAAI,UAAU,WAAW,SACrB,EACE,WACG,OAAO,QACN,WACG,OACT,IACA,CAAC;GAGL,OAAO,YAAY,kBAAkB,OAAO,UAAU,CAAC;GACvD,QAAQ,YAAY,kBAAkB,QAAQ,UAAU,CAAC;GACzD,UAAU,YAAY,QAAQ;GAC9B,WAAW,YAAY,SAAS;GAChC,UAAU,YAAY,QAAQ;GAC9B,WAAW,YAAY,SAAS;GAChC;GACA;GACA,MAAM;GACN;GACA;GAEA,GAAG;EAIyB;EAAe,GAAI;EAC5C;CACQ,CAAA;AAEf,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"Grid.js","names":[],"sources":["../../../../src/react/core/layout/Grid.tsx"],"sourcesContent":["/**\n * @zendir/ui - Grid Layout Primitive\n *\n * CSS Grid container with responsive columns and auto-fit support.\n * Designed for operator dashboard layouts: telemetry grids, card layouts,\n * multi-panel mission control views.\n *\n * Astro UX Compliance:\n * - 4px grid spacing tokens\n * - Responsive column count for mobile → 4K mission control\n *\n * @example\n * ```tsx\n * // Fixed responsive columns\n * <Grid columns={[1, 2, 3]} gap=\"md\">\n * <TelemetryCard />\n * <LinkBudgetCard />\n * <SpacecraftCard />\n * </Grid>\n *\n * // Auto-fit: as many 300px-min columns as fit\n * <Grid autoFit={300} gap=\"md\">\n * {telemetryItems.map(item => <DataValue key={item.key} {...item} />)}\n * </Grid>\n *\n * // Template-based for complex layouts\n * <Grid template=\"1fr 2fr 1fr\" rows=\"auto 1fr\" gap=\"md\">\n * <SideNav />\n * <MainContent />\n * <DetailPanel />\n * </Grid>\n * ```\n */\n\nimport React, { memo, forwardRef } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { useBreakpoint } from \"./useBreakpoint\";\nimport { resolveResponsiveSpacing, resolveResponsive } from \"./responsive\";\nimport type { ResponsiveValue } from \"./useBreakpoint\";\nimport type { SpacingToken } from \"./responsive\";\nimport type { BoxProps } from \"./Box\";\n\ntype SpacingInput = SpacingToken | string | number;\n\nexport interface GridProps extends Omit<BoxProps, \"display\"> {\n /** Number of equal columns (responsive) */\n columns?: ResponsiveValue<number>;\n /** Auto-fit: minimum column width in px. Creates `repeat(auto-fit, minmax(Npx, 1fr))` */\n autoFit?: number;\n /** Auto-fill: minimum column width in px. Creates `repeat(auto-fill, minmax(Npx, 1fr))` */\n autoFill?: number;\n /** Explicit grid-template-columns CSS value */\n template?: ResponsiveValue<string>;\n /** Explicit grid-template-rows CSS value */\n rows?: string;\n /** Gap between grid items */\n gap?: ResponsiveValue<SpacingInput>;\n /** Row gap (overrides gap for rows) */\n rowGap?: ResponsiveValue<SpacingInput>;\n /** Column gap (overrides gap for columns) */\n columnGap?: ResponsiveValue<SpacingInput>;\n /** Align items (cross-axis per cell) */\n align?: \"start\" | \"end\" | \"center\" | \"stretch\" | \"baseline\";\n /** Justify items (main-axis per cell) */\n justifyItems?: \"start\" | \"end\" | \"center\" | \"stretch\";\n /** Align content (cross-axis for the grid as a whole) */\n alignContent?:\n | \"start\"\n | \"end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n /** Justify content (main-axis for the grid as a whole) */\n justifyContent?:\n | \"start\"\n | \"end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n /** Make grid inline */\n inline?: boolean;\n}\n\nexport const Grid = memo(\n forwardRef<HTMLDivElement, GridProps>(function Grid(\n {\n columns,\n autoFit,\n autoFill,\n template,\n rows,\n gap,\n rowGap,\n columnGap,\n align,\n justifyItems,\n alignContent,\n justifyContent,\n inline = false,\n // Box props\n padding,\n p,\n px,\n py,\n pt,\n pr,\n pb,\n pl,\n margin,\n m,\n mx,\n my,\n mt,\n mr,\n mb,\n ml,\n background,\n border,\n borderRadius,\n shadow,\n width,\n height,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n overflow,\n position,\n flex,\n flexGrow,\n flexShrink,\n as: Component = \"div\",\n style,\n children,\n ...rest\n },\n ref,\n ): React.ReactElement {\n const { tokens } = useTheme();\n const { breakpoint } = useBreakpoint();\n\n const resolveSpacing = (val: ResponsiveValue<SpacingInput> | undefined) =>\n resolveResponsiveSpacing(val, breakpoint, tokens);\n\n // Determine grid-template-columns\n let gridTemplateColumns: string | undefined;\n\n if (autoFit) {\n gridTemplateColumns = `repeat(auto-fit, minmax(${autoFit}px, 1fr))`;\n } else if (autoFill) {\n gridTemplateColumns = `repeat(auto-fill, minmax(${autoFill}px, 1fr))`;\n } else if (template) {\n gridTemplateColumns = resolveResponsive(template, breakpoint);\n } else if (columns !== undefined) {\n const cols = resolveResponsive(columns, breakpoint);\n gridTemplateColumns = cols ? `repeat(${cols}, 1fr)` : undefined;\n }\n\n // Background resolution\n const bgMap: Record<string, string> = {\n base: tokens.colors.background.base,\n surface: tokens.colors.background.surface,\n elevated: tokens.colors.background.elevated,\n overlay: tokens.colors.background.overlay,\n };\n\n const resolveSize = (\n val: string | number | undefined,\n ): string | undefined => {\n if (val === undefined) return undefined;\n if (typeof val === \"number\") return `${val}px`;\n return val;\n };\n\n // Resolve padding\n const paddingAll = resolveSpacing(padding ?? p);\n const paddingXVal = resolveSpacing(px);\n const paddingYVal = resolveSpacing(py);\n\n // Resolve margin\n const marginAll = resolveSpacing(margin ?? m);\n const marginXVal = resolveSpacing(mx);\n const marginYVal = resolveSpacing(my);\n\n // Resolve gap values — use conditional spreads to avoid setting\n // rowGap/columnGap to undefined, which clears the gap shorthand\n // in browsers (setting `style.rowGap = ''` removes the value\n // that `style.gap` set for row-gap).\n const resolvedGap = resolveSpacing(gap);\n const resolvedRowGap = resolveSpacing(rowGap);\n const resolvedColumnGap = resolveSpacing(columnGap);\n\n const computedStyle: React.CSSProperties = {\n display: inline ? \"inline-grid\" : \"grid\",\n gridTemplateColumns,\n gridTemplateRows: rows,\n ...(resolvedGap !== undefined ? { gap: resolvedGap } : {}),\n ...(resolvedRowGap !== undefined ? { rowGap: resolvedRowGap } : {}),\n ...(resolvedColumnGap !== undefined\n ? { columnGap: resolvedColumnGap }\n : {}),\n alignItems: align,\n justifyItems,\n alignContent,\n justifyContent,\n\n // Padding\n ...(paddingAll ? { padding: paddingAll } : {}),\n ...(paddingXVal\n ? { paddingLeft: paddingXVal, paddingRight: paddingXVal }\n : {}),\n ...(paddingYVal\n ? { paddingTop: paddingYVal, paddingBottom: paddingYVal }\n : {}),\n ...(resolveSpacing(pt) ? { paddingTop: resolveSpacing(pt) } : {}),\n ...(resolveSpacing(pr) ? { paddingRight: resolveSpacing(pr) } : {}),\n ...(resolveSpacing(pb) ? { paddingBottom: resolveSpacing(pb) } : {}),\n ...(resolveSpacing(pl) ? { paddingLeft: resolveSpacing(pl) } : {}),\n\n // Margin\n ...(marginAll ? { margin: marginAll } : {}),\n ...(marginXVal\n ? { marginLeft: marginXVal, marginRight: marginXVal }\n : {}),\n ...(marginYVal\n ? { marginTop: marginYVal, marginBottom: marginYVal }\n : {}),\n ...(resolveSpacing(mt) ? { marginTop: resolveSpacing(mt) } : {}),\n ...(resolveSpacing(mr) ? { marginRight: resolveSpacing(mr) } : {}),\n ...(resolveSpacing(mb) ? { marginBottom: resolveSpacing(mb) } : {}),\n ...(resolveSpacing(ml) ? { marginLeft: resolveSpacing(ml) } : {}),\n\n // Visual\n ...(background\n ? { backgroundColor: bgMap[background] || background }\n : {}),\n ...(border\n ? {\n border:\n border === true\n ? `1px solid ${tokens.colors.border.default}`\n : (border as string),\n }\n : {}),\n ...(borderRadius\n ? {\n borderRadius:\n (tokens.borderRadius as Record<string, string>)[\n borderRadius as string\n ] || borderRadius,\n }\n : {}),\n ...(shadow && shadow !== \"glow\"\n ? {\n boxShadow:\n (tokens.shadows as unknown as Record<string, string>)[\n shadow as string\n ] || shadow,\n }\n : {}),\n\n // Size\n width: resolveSize(resolveResponsive(width, breakpoint)),\n height: resolveSize(resolveResponsive(height, breakpoint)),\n minWidth: resolveSize(minWidth),\n minHeight: resolveSize(minHeight),\n maxWidth: resolveSize(maxWidth),\n maxHeight: resolveSize(maxHeight),\n overflow,\n position,\n flex,\n flexGrow,\n flexShrink,\n\n ...style,\n };\n\n return (\n <Component ref={ref} style={computedStyle} {...rest}>\n {children}\n </Component>\n );\n }),\n);\n\nexport default Grid;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Grid.js","names":[],"sources":["../../../../src/react/core/layout/Grid.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Grid Layout Primitive\r\n *\r\n * CSS Grid container with responsive columns and auto-fit support.\r\n * Designed for operator dashboard layouts: telemetry grids, card layouts,\r\n * multi-panel mission control views.\r\n *\r\n * Astro UX Compliance:\r\n * - 4px grid spacing tokens\r\n * - Responsive column count for mobile → 4K mission control\r\n *\r\n * @example\r\n * ```tsx\r\n * // Fixed responsive columns\r\n * <Grid columns={[1, 2, 3]} gap=\"md\">\r\n * <TelemetryCard />\r\n * <LinkBudgetCard />\r\n * <SpacecraftCard />\r\n * </Grid>\r\n *\r\n * // Auto-fit: as many 300px-min columns as fit\r\n * <Grid autoFit={300} gap=\"md\">\r\n * {telemetryItems.map(item => <DataValue key={item.key} {...item} />)}\r\n * </Grid>\r\n *\r\n * // Template-based for complex layouts\r\n * <Grid template=\"1fr 2fr 1fr\" rows=\"auto 1fr\" gap=\"md\">\r\n * <SideNav />\r\n * <MainContent />\r\n * <DetailPanel />\r\n * </Grid>\r\n * ```\r\n */\r\n\r\nimport React, { memo, forwardRef } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { useBreakpoint } from \"./useBreakpoint\";\r\nimport { resolveResponsiveSpacing, resolveResponsive } from \"./responsive\";\r\nimport type { ResponsiveValue } from \"./useBreakpoint\";\r\nimport type { SpacingToken } from \"./responsive\";\r\nimport type { BoxProps } from \"./Box\";\r\n\r\ntype SpacingInput = SpacingToken | string | number;\r\n\r\nexport interface GridProps extends Omit<BoxProps, \"display\"> {\r\n /** Number of equal columns (responsive) */\r\n columns?: ResponsiveValue<number>;\r\n /** Auto-fit: minimum column width in px. Creates `repeat(auto-fit, minmax(Npx, 1fr))` */\r\n autoFit?: number;\r\n /** Auto-fill: minimum column width in px. Creates `repeat(auto-fill, minmax(Npx, 1fr))` */\r\n autoFill?: number;\r\n /** Explicit grid-template-columns CSS value */\r\n template?: ResponsiveValue<string>;\r\n /** Explicit grid-template-rows CSS value */\r\n rows?: string;\r\n /** Gap between grid items */\r\n gap?: ResponsiveValue<SpacingInput>;\r\n /** Row gap (overrides gap for rows) */\r\n rowGap?: ResponsiveValue<SpacingInput>;\r\n /** Column gap (overrides gap for columns) */\r\n columnGap?: ResponsiveValue<SpacingInput>;\r\n /** Align items (cross-axis per cell) */\r\n align?: \"start\" | \"end\" | \"center\" | \"stretch\" | \"baseline\";\r\n /** Justify items (main-axis per cell) */\r\n justifyItems?: \"start\" | \"end\" | \"center\" | \"stretch\";\r\n /** Align content (cross-axis for the grid as a whole) */\r\n alignContent?:\r\n | \"start\"\r\n | \"end\"\r\n | \"center\"\r\n | \"stretch\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\n /** Justify content (main-axis for the grid as a whole) */\r\n justifyContent?:\r\n | \"start\"\r\n | \"end\"\r\n | \"center\"\r\n | \"stretch\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\n /** Make grid inline */\r\n inline?: boolean;\r\n}\r\n\r\nexport const Grid = memo(\r\n forwardRef<HTMLDivElement, GridProps>(function Grid(\r\n {\r\n columns,\r\n autoFit,\r\n autoFill,\r\n template,\r\n rows,\r\n gap,\r\n rowGap,\r\n columnGap,\r\n align,\r\n justifyItems,\r\n alignContent,\r\n justifyContent,\r\n inline = false,\r\n // Box props\r\n padding,\r\n p,\r\n px,\r\n py,\r\n pt,\r\n pr,\r\n pb,\r\n pl,\r\n margin,\r\n m,\r\n mx,\r\n my,\r\n mt,\r\n mr,\r\n mb,\r\n ml,\r\n background,\r\n border,\r\n borderRadius,\r\n shadow,\r\n width,\r\n height,\r\n minWidth,\r\n minHeight,\r\n maxWidth,\r\n maxHeight,\r\n overflow,\r\n position,\r\n flex,\r\n flexGrow,\r\n flexShrink,\r\n as: Component = \"div\",\r\n style,\r\n children,\r\n ...rest\r\n },\r\n ref,\r\n ): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { breakpoint } = useBreakpoint();\r\n\r\n const resolveSpacing = (val: ResponsiveValue<SpacingInput> | undefined) =>\r\n resolveResponsiveSpacing(val, breakpoint, tokens);\r\n\r\n // Determine grid-template-columns\r\n let gridTemplateColumns: string | undefined;\r\n\r\n if (autoFit) {\r\n gridTemplateColumns = `repeat(auto-fit, minmax(${autoFit}px, 1fr))`;\r\n } else if (autoFill) {\r\n gridTemplateColumns = `repeat(auto-fill, minmax(${autoFill}px, 1fr))`;\r\n } else if (template) {\r\n gridTemplateColumns = resolveResponsive(template, breakpoint);\r\n } else if (columns !== undefined) {\r\n const cols = resolveResponsive(columns, breakpoint);\r\n gridTemplateColumns = cols ? `repeat(${cols}, 1fr)` : undefined;\r\n }\r\n\r\n // Background resolution\r\n const bgMap: Record<string, string> = {\r\n base: tokens.colors.background.base,\r\n surface: tokens.colors.background.surface,\r\n elevated: tokens.colors.background.elevated,\r\n overlay: tokens.colors.background.overlay,\r\n };\r\n\r\n const resolveSize = (\r\n val: string | number | undefined,\r\n ): string | undefined => {\r\n if (val === undefined) return undefined;\r\n if (typeof val === \"number\") return `${val}px`;\r\n return val;\r\n };\r\n\r\n // Resolve padding\r\n const paddingAll = resolveSpacing(padding ?? p);\r\n const paddingXVal = resolveSpacing(px);\r\n const paddingYVal = resolveSpacing(py);\r\n\r\n // Resolve margin\r\n const marginAll = resolveSpacing(margin ?? m);\r\n const marginXVal = resolveSpacing(mx);\r\n const marginYVal = resolveSpacing(my);\r\n\r\n // Resolve gap values — use conditional spreads to avoid setting\r\n // rowGap/columnGap to undefined, which clears the gap shorthand\r\n // in browsers (setting `style.rowGap = ''` removes the value\r\n // that `style.gap` set for row-gap).\r\n const resolvedGap = resolveSpacing(gap);\r\n const resolvedRowGap = resolveSpacing(rowGap);\r\n const resolvedColumnGap = resolveSpacing(columnGap);\r\n\r\n const computedStyle: React.CSSProperties = {\r\n display: inline ? \"inline-grid\" : \"grid\",\r\n gridTemplateColumns,\r\n gridTemplateRows: rows,\r\n ...(resolvedGap !== undefined ? { gap: resolvedGap } : {}),\r\n ...(resolvedRowGap !== undefined ? { rowGap: resolvedRowGap } : {}),\r\n ...(resolvedColumnGap !== undefined\r\n ? { columnGap: resolvedColumnGap }\r\n : {}),\r\n alignItems: align,\r\n justifyItems,\r\n alignContent,\r\n justifyContent,\r\n\r\n // Padding\r\n ...(paddingAll ? { padding: paddingAll } : {}),\r\n ...(paddingXVal\r\n ? { paddingLeft: paddingXVal, paddingRight: paddingXVal }\r\n : {}),\r\n ...(paddingYVal\r\n ? { paddingTop: paddingYVal, paddingBottom: paddingYVal }\r\n : {}),\r\n ...(resolveSpacing(pt) ? { paddingTop: resolveSpacing(pt) } : {}),\r\n ...(resolveSpacing(pr) ? { paddingRight: resolveSpacing(pr) } : {}),\r\n ...(resolveSpacing(pb) ? { paddingBottom: resolveSpacing(pb) } : {}),\r\n ...(resolveSpacing(pl) ? { paddingLeft: resolveSpacing(pl) } : {}),\r\n\r\n // Margin\r\n ...(marginAll ? { margin: marginAll } : {}),\r\n ...(marginXVal\r\n ? { marginLeft: marginXVal, marginRight: marginXVal }\r\n : {}),\r\n ...(marginYVal\r\n ? { marginTop: marginYVal, marginBottom: marginYVal }\r\n : {}),\r\n ...(resolveSpacing(mt) ? { marginTop: resolveSpacing(mt) } : {}),\r\n ...(resolveSpacing(mr) ? { marginRight: resolveSpacing(mr) } : {}),\r\n ...(resolveSpacing(mb) ? { marginBottom: resolveSpacing(mb) } : {}),\r\n ...(resolveSpacing(ml) ? { marginLeft: resolveSpacing(ml) } : {}),\r\n\r\n // Visual\r\n ...(background\r\n ? { backgroundColor: bgMap[background] || background }\r\n : {}),\r\n ...(border\r\n ? {\r\n border:\r\n border === true\r\n ? `1px solid ${tokens.colors.border.default}`\r\n : (border as string),\r\n }\r\n : {}),\r\n ...(borderRadius\r\n ? {\r\n borderRadius:\r\n (tokens.borderRadius as Record<string, string>)[\r\n borderRadius as string\r\n ] || borderRadius,\r\n }\r\n : {}),\r\n ...(shadow && shadow !== \"glow\"\r\n ? {\r\n boxShadow:\r\n (tokens.shadows as unknown as Record<string, string>)[\r\n shadow as string\r\n ] || shadow,\r\n }\r\n : {}),\r\n\r\n // Size\r\n width: resolveSize(resolveResponsive(width, breakpoint)),\r\n height: resolveSize(resolveResponsive(height, breakpoint)),\r\n minWidth: resolveSize(minWidth),\r\n minHeight: resolveSize(minHeight),\r\n maxWidth: resolveSize(maxWidth),\r\n maxHeight: resolveSize(maxHeight),\r\n overflow,\r\n position,\r\n flex,\r\n flexGrow,\r\n flexShrink,\r\n\r\n ...style,\r\n };\r\n\r\n return (\r\n <Component ref={ref} style={computedStyle} {...rest}>\r\n {children}\r\n </Component>\r\n );\r\n }),\r\n);\r\n\r\nexport default Grid;\r\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Spacer.js","names":[],"sources":["../../../../src/react/core/layout/Spacer.tsx"],"sourcesContent":["/**\n * @zendir/ui - Spacer Layout Primitive\n *\n * Flexible space filler for Flex and Stack layouts.\n * Expands to fill available space, pushing siblings apart.\n *\n * @example\n * ```tsx\n * <Flex align=\"center\" gap=\"sm\">\n * <H3>Telemetry</H3>\n * <Spacer />\n * <Button variant=\"secondary\" size=\"small\">Refresh</Button>\n * <Button size=\"small\">Export</Button>\n * </Flex>\n * ```\n */\n\nimport React, { memo } from \"react\";\n\nexport interface SpacerProps {\n /** Fixed size instead of flexible (spacing token compatible, number → px) */\n size?: string | number;\n}\n\nexport const Spacer = memo(function Spacer({\n size,\n}: SpacerProps): React.ReactElement {\n const resolvedSize = typeof size === \"number\" ? `${size}px` : size;\n\n if (resolvedSize) {\n return (\n <div\n aria-hidden=\"true\"\n style={{\n flexShrink: 0,\n width: resolvedSize,\n height: resolvedSize,\n }}\n />\n );\n }\n\n return (\n <div\n aria-hidden=\"true\"\n style={{\n flex: \"1 1 0%\",\n }}\n />\n );\n});\n\nexport default Spacer;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAwBA,IAAa,SAAS,KAAK,SAAS,OAAO,EACzC,QACkC;CAClC,MAAM,eAAe,OAAO,SAAS,WAAW,GAAG,KAAK,MAAM;CAE9D,IAAI,cACF,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,OAAO;GACL,YAAY;GACZ,OAAO;GACP,QAAQ;EACV;CACD,CAAA;CAIL,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,OAAO,EACL,MAAM,SACR;CACD,CAAA;AAEL,CAAC"}
1
+ {"version":3,"file":"Spacer.js","names":[],"sources":["../../../../src/react/core/layout/Spacer.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Spacer Layout Primitive\r\n *\r\n * Flexible space filler for Flex and Stack layouts.\r\n * Expands to fill available space, pushing siblings apart.\r\n *\r\n * @example\r\n * ```tsx\r\n * <Flex align=\"center\" gap=\"sm\">\r\n * <H3>Telemetry</H3>\r\n * <Spacer />\r\n * <Button variant=\"secondary\" size=\"small\">Refresh</Button>\r\n * <Button size=\"small\">Export</Button>\r\n * </Flex>\r\n * ```\r\n */\r\n\r\nimport React, { memo } from \"react\";\r\n\r\nexport interface SpacerProps {\r\n /** Fixed size instead of flexible (spacing token compatible, number → px) */\r\n size?: string | number;\r\n}\r\n\r\nexport const Spacer = memo(function Spacer({\r\n size,\r\n}: SpacerProps): React.ReactElement {\r\n const resolvedSize = typeof size === \"number\" ? `${size}px` : size;\r\n\r\n if (resolvedSize) {\r\n return (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n flexShrink: 0,\r\n width: resolvedSize,\r\n height: resolvedSize,\r\n }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n flex: \"1 1 0%\",\r\n }}\r\n />\r\n );\r\n});\r\n\r\nexport default Spacer;\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAwBA,IAAa,SAAS,KAAK,SAAS,OAAO,EACzC,QACkC;CAClC,MAAM,eAAe,OAAO,SAAS,WAAW,GAAG,KAAK,MAAM;CAE9D,IAAI,cACF,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,OAAO;GACL,YAAY;GACZ,OAAO;GACP,QAAQ;EACV;CACD,CAAA;CAIL,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,OAAO,EACL,MAAM,SACR;CACD,CAAA;AAEL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Stack.js","names":[],"sources":["../../../../src/react/core/layout/Stack.tsx"],"sourcesContent":["/**\n * @zendir/ui - Stack Layout Primitives\n *\n * Consistent spacing stacks — the most common layout pattern in operator dashboards.\n * Stack, HStack, and VStack provide directional flex with uniform gaps.\n *\n * @example\n * ```tsx\n * // Vertical stack (default)\n * <Stack spacing=\"md\">\n * <TelemetryCard />\n * <LinkBudgetCard />\n * <SpacecraftCard />\n * </Stack>\n *\n * // Horizontal stack\n * <HStack spacing=\"sm\" align=\"center\">\n * <StatusIndicator status=\"normal\" />\n * <Body1>Connected</Body1>\n * </HStack>\n *\n * // Responsive spacing\n * <VStack spacing={['sm', 'md', 'lg']}>\n * <Content />\n * </VStack>\n * ```\n */\n\nimport React, { memo, forwardRef } from \"react\";\nimport { useTheme } from \"../../theme\";\nimport { useBreakpoint } from \"./useBreakpoint\";\nimport { resolveResponsiveSpacing } from \"./responsive\";\nimport type { ResponsiveValue } from \"./useBreakpoint\";\nimport type { SpacingToken } from \"./responsive\";\n\ntype SpacingInput = SpacingToken | string | number;\n\nexport interface StackProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Element type to render */\n as?: React.ElementType;\n /** Stack direction */\n direction?: ResponsiveValue<\n \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\"\n >;\n /** Space between children (spacing token, px, or CSS string) */\n spacing?: ResponsiveValue<SpacingInput>;\n /** Align items (cross-axis) */\n align?: \"flex-start\" | \"flex-end\" | \"center\" | \"baseline\" | \"stretch\";\n /** Justify content (main-axis) */\n justify?:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n /** Flex wrap */\n wrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n /** Full width */\n fullWidth?: boolean;\n /** Full height */\n fullHeight?: boolean;\n /** Divider between items — renders a themed line */\n divider?: boolean;\n /** Children */\n children?: React.ReactNode;\n}\n\nexport const Stack = memo(\n forwardRef<HTMLDivElement, StackProps>(function Stack(\n {\n as: Component = \"div\",\n direction = \"column\",\n spacing = \"md\",\n align,\n justify,\n wrap,\n fullWidth = false,\n fullHeight = false,\n divider = false,\n style,\n children,\n ...rest\n },\n ref,\n ): React.ReactElement {\n const { tokens } = useTheme();\n const { breakpoint } = useBreakpoint();\n\n const resolvedSpacing = resolveResponsiveSpacing(\n spacing,\n breakpoint,\n tokens,\n );\n const resolvedDirection = Array.isArray(direction)\n ? (direction[\n Math.min(\n [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\"].indexOf(breakpoint),\n direction.length - 1,\n )\n ] ?? direction[direction.length - 1])\n : direction;\n const isVertical =\n resolvedDirection === \"column\" || resolvedDirection === \"column-reverse\";\n\n const computedStyle: React.CSSProperties = {\n display: \"flex\",\n flexDirection: resolvedDirection as\n | \"row\"\n | \"column\"\n | \"row-reverse\"\n | \"column-reverse\",\n ...(divider || !resolvedSpacing ? {} : { gap: resolvedSpacing }),\n alignItems: align,\n justifyContent: justify,\n flexWrap: wrap,\n ...(fullWidth ? { width: \"100%\" } : {}),\n ...(fullHeight ? { height: \"100%\" } : {}),\n ...style,\n };\n\n // If divider is enabled, interleave divider elements\n if (divider) {\n const items = React.Children.toArray(children).filter(Boolean);\n const dividerStyle: React.CSSProperties = isVertical\n ? {\n width: \"100%\",\n height: \"1px\",\n backgroundColor: tokens.colors.border.muted,\n flexShrink: 0,\n margin: `${resolvedSpacing} 0`,\n }\n : {\n height: \"100%\",\n width: \"1px\",\n backgroundColor: tokens.colors.border.muted,\n flexShrink: 0,\n alignSelf: \"stretch\",\n margin: `0 ${resolvedSpacing}`,\n };\n\n return (\n <Component ref={ref} style={computedStyle} {...rest}>\n {items.map((child, index) => (\n <React.Fragment key={index}>\n {child}\n {index < items.length - 1 && (\n <div style={dividerStyle} aria-hidden=\"true\" />\n )}\n </React.Fragment>\n ))}\n </Component>\n );\n }\n\n return (\n <Component ref={ref} style={computedStyle} {...rest}>\n {children}\n </Component>\n );\n }),\n);\n\n/**\n * Horizontal Stack — `<Stack direction=\"row\">` shorthand.\n *\n * @example\n * ```tsx\n * <HStack spacing=\"sm\" align=\"center\">\n * <Icon name=\"satellite\" />\n * <Body1>SAT-1</Body1>\n * <Badge status=\"normal\">Nominal</Badge>\n * </HStack>\n * ```\n */\nexport const HStack = memo(\n forwardRef<HTMLDivElement, Omit<StackProps, \"direction\">>(\n function HStack(props, ref) {\n return <Stack ref={ref} direction=\"row\" {...props} />;\n },\n ),\n);\n\n/**\n * Vertical Stack — `<Stack direction=\"column\">` shorthand.\n *\n * @example\n * ```tsx\n * <VStack spacing=\"md\">\n * <TelemetryCard />\n * <LinkBudgetCard />\n * </VStack>\n * ```\n */\nexport const VStack = memo(\n forwardRef<HTMLDivElement, Omit<StackProps, \"direction\">>(\n function VStack(props, ref) {\n return <Stack ref={ref} direction=\"column\" {...props} />;\n },\n ),\n);\n\nexport default Stack;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,IAAa,QAAQ,KACnB,WAAuC,SAAS,MAC9C,EACE,IAAI,YAAY,OAChB,YAAY,UACZ,UAAU,MACV,OACA,SACA,MACA,YAAY,OACZ,aAAa,OACb,UAAU,OACV,OACA,UACA,GAAG,QAEL,KACoB;CACpB,MAAM,EAAE,WAAW,SAAS;CAC5B,MAAM,EAAE,eAAe,cAAc;CAErC,MAAM,kBAAkB,yBACtB,SACA,YACA,MACF;CACA,MAAM,oBAAoB,MAAM,QAAQ,SAAS,IAC5C,UACC,KAAK,IACH;EAAC;EAAQ;EAAM;EAAM;EAAM;EAAM;CAAK,CAAC,CAAC,QAAQ,UAAU,GAC1D,UAAU,SAAS,CACrB,MACG,UAAU,UAAU,SAAS,KAClC;CACJ,MAAM,aACJ,sBAAsB,YAAY,sBAAsB;CAE1D,MAAM,gBAAqC;EACzC,SAAS;EACT,eAAe;EAKf,GAAI,WAAW,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,gBAAgB;EAC9D,YAAY;EACZ,gBAAgB;EAChB,UAAU;EACV,GAAI,YAAY,EAAE,OAAO,OAAO,IAAI,CAAC;EACrC,GAAI,aAAa,EAAE,QAAQ,OAAO,IAAI,CAAC;EACvC,GAAG;CACL;CAGA,IAAI,SAAS;EACX,MAAM,QAAQ,MAAM,SAAS,QAAQ,QAAQ,CAAC,CAAC,OAAO,OAAO;EAC7D,MAAM,eAAoC,aACtC;GACE,OAAO;GACP,QAAQ;GACR,iBAAiB,OAAO,OAAO,OAAO;GACtC,YAAY;GACZ,QAAQ,GAAG,gBAAgB;EAC7B,IACA;GACE,QAAQ;GACR,OAAO;GACP,iBAAiB,OAAO,OAAO,OAAO;GACtC,YAAY;GACZ,WAAW;GACX,QAAQ,KAAK;EACf;EAEJ,OACE,oBAAC,WAAD;GAAgB;GAAK,OAAO;GAAe,GAAI;aAC5C,MAAM,KAAK,OAAO,UACjB,qBAAC,MAAM,UAAP,EAAA,UAAA,CACG,OACA,QAAQ,MAAM,SAAS,KACtB,oBAAC,OAAD;IAAK,OAAO;IAAc,eAAY;GAAQ,CAAA,CAElC,EAAA,GALK,KAKL,CACjB;EACQ,CAAA;CAEf;CAEA,OACE,oBAAC,WAAD;EAAgB;EAAK,OAAO;EAAe,GAAI;EAC5C;CACQ,CAAA;AAEf,CAAC,CACH;;;;;;;;;;;;;AAcA,IAAa,SAAS,KACpB,WACE,SAAS,OAAO,OAAO,KAAK;CAC1B,OAAO,oBAAC,OAAD;EAAY;EAAK,WAAU;EAAM,GAAI;CAAQ,CAAA;AACtD,CACF,CACF;;;;;;;;;;;;AAaA,IAAa,SAAS,KACpB,WACE,SAAS,OAAO,OAAO,KAAK;CAC1B,OAAO,oBAAC,OAAD;EAAY;EAAK,WAAU;EAAS,GAAI;CAAQ,CAAA;AACzD,CACF,CACF"}
1
+ {"version":3,"file":"Stack.js","names":[],"sources":["../../../../src/react/core/layout/Stack.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - Stack Layout Primitives\r\n *\r\n * Consistent spacing stacks — the most common layout pattern in operator dashboards.\r\n * Stack, HStack, and VStack provide directional flex with uniform gaps.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Vertical stack (default)\r\n * <Stack spacing=\"md\">\r\n * <TelemetryCard />\r\n * <LinkBudgetCard />\r\n * <SpacecraftCard />\r\n * </Stack>\r\n *\r\n * // Horizontal stack\r\n * <HStack spacing=\"sm\" align=\"center\">\r\n * <StatusIndicator status=\"normal\" />\r\n * <Body1>Connected</Body1>\r\n * </HStack>\r\n *\r\n * // Responsive spacing\r\n * <VStack spacing={['sm', 'md', 'lg']}>\r\n * <Content />\r\n * </VStack>\r\n * ```\r\n */\r\n\r\nimport React, { memo, forwardRef } from \"react\";\r\nimport { useTheme } from \"../../theme\";\r\nimport { useBreakpoint } from \"./useBreakpoint\";\r\nimport { resolveResponsiveSpacing } from \"./responsive\";\r\nimport type { ResponsiveValue } from \"./useBreakpoint\";\r\nimport type { SpacingToken } from \"./responsive\";\r\n\r\ntype SpacingInput = SpacingToken | string | number;\r\n\r\nexport interface StackProps extends React.HTMLAttributes<HTMLDivElement> {\r\n /** Element type to render */\r\n as?: React.ElementType;\r\n /** Stack direction */\r\n direction?: ResponsiveValue<\r\n \"row\" | \"column\" | \"row-reverse\" | \"column-reverse\"\r\n >;\r\n /** Space between children (spacing token, px, or CSS string) */\r\n spacing?: ResponsiveValue<SpacingInput>;\r\n /** Align items (cross-axis) */\r\n align?: \"flex-start\" | \"flex-end\" | \"center\" | \"baseline\" | \"stretch\";\r\n /** Justify content (main-axis) */\r\n justify?:\r\n | \"flex-start\"\r\n | \"flex-end\"\r\n | \"center\"\r\n | \"space-between\"\r\n | \"space-around\"\r\n | \"space-evenly\";\r\n /** Flex wrap */\r\n wrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\r\n /** Full width */\r\n fullWidth?: boolean;\r\n /** Full height */\r\n fullHeight?: boolean;\r\n /** Divider between items — renders a themed line */\r\n divider?: boolean;\r\n /** Children */\r\n children?: React.ReactNode;\r\n}\r\n\r\nexport const Stack = memo(\r\n forwardRef<HTMLDivElement, StackProps>(function Stack(\r\n {\r\n as: Component = \"div\",\r\n direction = \"column\",\r\n spacing = \"md\",\r\n align,\r\n justify,\r\n wrap,\r\n fullWidth = false,\r\n fullHeight = false,\r\n divider = false,\r\n style,\r\n children,\r\n ...rest\r\n },\r\n ref,\r\n ): React.ReactElement {\r\n const { tokens } = useTheme();\r\n const { breakpoint } = useBreakpoint();\r\n\r\n const resolvedSpacing = resolveResponsiveSpacing(\r\n spacing,\r\n breakpoint,\r\n tokens,\r\n );\r\n const resolvedDirection = Array.isArray(direction)\r\n ? (direction[\r\n Math.min(\r\n [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\"].indexOf(breakpoint),\r\n direction.length - 1,\r\n )\r\n ] ?? direction[direction.length - 1])\r\n : direction;\r\n const isVertical =\r\n resolvedDirection === \"column\" || resolvedDirection === \"column-reverse\";\r\n\r\n const computedStyle: React.CSSProperties = {\r\n display: \"flex\",\r\n flexDirection: resolvedDirection as\r\n | \"row\"\r\n | \"column\"\r\n | \"row-reverse\"\r\n | \"column-reverse\",\r\n ...(divider || !resolvedSpacing ? {} : { gap: resolvedSpacing }),\r\n alignItems: align,\r\n justifyContent: justify,\r\n flexWrap: wrap,\r\n ...(fullWidth ? { width: \"100%\" } : {}),\r\n ...(fullHeight ? { height: \"100%\" } : {}),\r\n ...style,\r\n };\r\n\r\n // If divider is enabled, interleave divider elements\r\n if (divider) {\r\n const items = React.Children.toArray(children).filter(Boolean);\r\n const dividerStyle: React.CSSProperties = isVertical\r\n ? {\r\n width: \"100%\",\r\n height: \"1px\",\r\n backgroundColor: tokens.colors.border.muted,\r\n flexShrink: 0,\r\n margin: `${resolvedSpacing} 0`,\r\n }\r\n : {\r\n height: \"100%\",\r\n width: \"1px\",\r\n backgroundColor: tokens.colors.border.muted,\r\n flexShrink: 0,\r\n alignSelf: \"stretch\",\r\n margin: `0 ${resolvedSpacing}`,\r\n };\r\n\r\n return (\r\n <Component ref={ref} style={computedStyle} {...rest}>\r\n {items.map((child, index) => (\r\n <React.Fragment key={index}>\r\n {child}\r\n {index < items.length - 1 && (\r\n <div style={dividerStyle} aria-hidden=\"true\" />\r\n )}\r\n </React.Fragment>\r\n ))}\r\n </Component>\r\n );\r\n }\r\n\r\n return (\r\n <Component ref={ref} style={computedStyle} {...rest}>\r\n {children}\r\n </Component>\r\n );\r\n }),\r\n);\r\n\r\n/**\r\n * Horizontal Stack — `<Stack direction=\"row\">` shorthand.\r\n *\r\n * @example\r\n * ```tsx\r\n * <HStack spacing=\"sm\" align=\"center\">\r\n * <Icon name=\"satellite\" />\r\n * <Body1>SAT-1</Body1>\r\n * <Badge status=\"normal\">Nominal</Badge>\r\n * </HStack>\r\n * ```\r\n */\r\nexport const HStack = memo(\r\n forwardRef<HTMLDivElement, Omit<StackProps, \"direction\">>(\r\n function HStack(props, ref) {\r\n return <Stack ref={ref} direction=\"row\" {...props} />;\r\n },\r\n ),\r\n);\r\n\r\n/**\r\n * Vertical Stack — `<Stack direction=\"column\">` shorthand.\r\n *\r\n * @example\r\n * ```tsx\r\n * <VStack spacing=\"md\">\r\n * <TelemetryCard />\r\n * <LinkBudgetCard />\r\n * </VStack>\r\n * ```\r\n */\r\nexport const VStack = memo(\r\n forwardRef<HTMLDivElement, Omit<StackProps, \"direction\">>(\r\n function VStack(props, ref) {\r\n return <Stack ref={ref} direction=\"column\" {...props} />;\r\n },\r\n ),\r\n);\r\n\r\nexport default Stack;\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,IAAa,QAAQ,KACnB,WAAuC,SAAS,MAC9C,EACE,IAAI,YAAY,OAChB,YAAY,UACZ,UAAU,MACV,OACA,SACA,MACA,YAAY,OACZ,aAAa,OACb,UAAU,OACV,OACA,UACA,GAAG,QAEL,KACoB;CACpB,MAAM,EAAE,WAAW,SAAS;CAC5B,MAAM,EAAE,eAAe,cAAc;CAErC,MAAM,kBAAkB,yBACtB,SACA,YACA,MACF;CACA,MAAM,oBAAoB,MAAM,QAAQ,SAAS,IAC5C,UACC,KAAK,IACH;EAAC;EAAQ;EAAM;EAAM;EAAM;EAAM;CAAK,CAAC,CAAC,QAAQ,UAAU,GAC1D,UAAU,SAAS,CACrB,MACG,UAAU,UAAU,SAAS,KAClC;CACJ,MAAM,aACJ,sBAAsB,YAAY,sBAAsB;CAE1D,MAAM,gBAAqC;EACzC,SAAS;EACT,eAAe;EAKf,GAAI,WAAW,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,gBAAgB;EAC9D,YAAY;EACZ,gBAAgB;EAChB,UAAU;EACV,GAAI,YAAY,EAAE,OAAO,OAAO,IAAI,CAAC;EACrC,GAAI,aAAa,EAAE,QAAQ,OAAO,IAAI,CAAC;EACvC,GAAG;CACL;CAGA,IAAI,SAAS;EACX,MAAM,QAAQ,MAAM,SAAS,QAAQ,QAAQ,CAAC,CAAC,OAAO,OAAO;EAC7D,MAAM,eAAoC,aACtC;GACE,OAAO;GACP,QAAQ;GACR,iBAAiB,OAAO,OAAO,OAAO;GACtC,YAAY;GACZ,QAAQ,GAAG,gBAAgB;EAC7B,IACA;GACE,QAAQ;GACR,OAAO;GACP,iBAAiB,OAAO,OAAO,OAAO;GACtC,YAAY;GACZ,WAAW;GACX,QAAQ,KAAK;EACf;EAEJ,OACE,oBAAC,WAAD;GAAgB;GAAK,OAAO;GAAe,GAAI;aAC5C,MAAM,KAAK,OAAO,UACjB,qBAAC,MAAM,UAAP,EAAA,UAAA,CACG,OACA,QAAQ,MAAM,SAAS,KACtB,oBAAC,OAAD;IAAK,OAAO;IAAc,eAAY;GAAQ,CAAA,CAElC,EAAA,GALK,KAKL,CACjB;EACQ,CAAA;CAEf;CAEA,OACE,oBAAC,WAAD;EAAgB;EAAK,OAAO;EAAe,GAAI;EAC5C;CACQ,CAAA;AAEf,CAAC,CACH;;;;;;;;;;;;;AAcA,IAAa,SAAS,KACpB,WACE,SAAS,OAAO,OAAO,KAAK;CAC1B,OAAO,oBAAC,OAAD;EAAY;EAAK,WAAU;EAAM,GAAI;CAAQ,CAAA;AACtD,CACF,CACF;;;;;;;;;;;;AAaA,IAAa,SAAS,KACpB,WACE,SAAS,OAAO,OAAO,KAAK;CAC1B,OAAO,oBAAC,OAAD;EAAY;EAAK,WAAU;EAAS,GAAI;CAAQ,CAAA;AACzD,CACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"responsive.js","names":[],"sources":["../../../../src/react/core/layout/responsive.ts"],"sourcesContent":["/**\n * @zendir/ui - Responsive Utilities\n *\n * Helpers for resolving responsive values and spacing tokens to CSS values.\n * Used internally by layout primitives (Box, Flex, Grid, Stack).\n */\n\nimport type { ThemeTokens } from \"../../theme\";\nimport type { Breakpoint, ResponsiveValue } from \"./useBreakpoint\";\nimport { resolveResponsiveValue } from \"./useBreakpoint\";\n\n/** Spacing token names matching ThemeTokens.spacing */\nexport type SpacingToken =\n | \"xxs\"\n | \"xs\"\n | \"sm\"\n | \"smd\"\n | \"md\"\n | \"mdl\"\n | \"lg\"\n | \"xl\"\n | \"xxl\";\n\n/** Value that can be a spacing token, a CSS string, or a number (px) */\ntype SpacingInput = SpacingToken | string | number;\n\n/**\n * Resolve a spacing value to a CSS string.\n * - SpacingToken ('xs', 'sm', etc.) → looks up token value\n * - number → converts to px string\n * - string → passes through (e.g., '1rem', '50%')\n */\nexport function resolveSpacing(\n value: SpacingInput | undefined,\n tokens: ThemeTokens,\n): string | undefined {\n if (value === undefined || value === null) return undefined;\n\n // Spacing token\n if (typeof value === \"string\" && value in tokens.spacing) {\n return tokens.spacing[value as SpacingToken];\n }\n\n // Number → px\n if (typeof value === \"number\") {\n return `${value}px`;\n }\n\n // CSS string passthrough\n return value;\n}\n\n/**\n * Resolve a responsive spacing value at the current breakpoint.\n */\nexport function resolveResponsiveSpacing(\n value: ResponsiveValue<SpacingInput> | undefined,\n breakpoint: Breakpoint,\n tokens: ThemeTokens,\n): string | undefined {\n if (value === undefined || value === null) return undefined;\n\n const resolved = Array.isArray(value)\n ? resolveResponsiveValue(value, breakpoint)\n : value;\n\n return resolveSpacing(resolved, tokens);\n}\n\n/**\n * Resolve a responsive value (non-spacing) at the current breakpoint.\n */\nexport function resolveResponsive<T>(\n value: ResponsiveValue<T> | undefined,\n breakpoint: Breakpoint,\n): T | undefined {\n if (value === undefined || value === null) return undefined;\n return Array.isArray(value)\n ? resolveResponsiveValue(value, breakpoint)\n : value;\n}\n"],"mappings":";;;;;;;;AAgCA,SAAgB,eACd,OACA,QACoB;CACpB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAGlD,IAAI,OAAO,UAAU,YAAY,SAAS,OAAO,SAC/C,OAAO,OAAO,QAAQ;CAIxB,IAAI,OAAO,UAAU,UACnB,OAAO,GAAG,MAAM;CAIlB,OAAO;AACT;;;;AAKA,SAAgB,yBACd,OACA,YACA,QACoB;CACpB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAMlD,OAAO,eAJU,MAAM,QAAQ,KAAK,IAChC,uBAAuB,OAAO,UAAU,IACxC,OAE4B,MAAM;AACxC;;;;AAKA,SAAgB,kBACd,OACA,YACe;CACf,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAClD,OAAO,MAAM,QAAQ,KAAK,IACtB,uBAAuB,OAAO,UAAU,IACxC;AACN"}
1
+ {"version":3,"file":"responsive.js","names":[],"sources":["../../../../src/react/core/layout/responsive.ts"],"sourcesContent":["/**\r\n * @zendir/ui - Responsive Utilities\r\n *\r\n * Helpers for resolving responsive values and spacing tokens to CSS values.\r\n * Used internally by layout primitives (Box, Flex, Grid, Stack).\r\n */\r\n\r\nimport type { ThemeTokens } from \"../../theme\";\r\nimport type { Breakpoint, ResponsiveValue } from \"./useBreakpoint\";\r\nimport { resolveResponsiveValue } from \"./useBreakpoint\";\r\n\r\n/** Spacing token names matching ThemeTokens.spacing */\r\nexport type SpacingToken =\r\n | \"xxs\"\r\n | \"xs\"\r\n | \"sm\"\r\n | \"smd\"\r\n | \"md\"\r\n | \"mdl\"\r\n | \"lg\"\r\n | \"xl\"\r\n | \"xxl\";\r\n\r\n/** Value that can be a spacing token, a CSS string, or a number (px) */\r\ntype SpacingInput = SpacingToken | string | number;\r\n\r\n/**\r\n * Resolve a spacing value to a CSS string.\r\n * - SpacingToken ('xs', 'sm', etc.) → looks up token value\r\n * - number → converts to px string\r\n * - string → passes through (e.g., '1rem', '50%')\r\n */\r\nexport function resolveSpacing(\r\n value: SpacingInput | undefined,\r\n tokens: ThemeTokens,\r\n): string | undefined {\r\n if (value === undefined || value === null) return undefined;\r\n\r\n // Spacing token\r\n if (typeof value === \"string\" && value in tokens.spacing) {\r\n return tokens.spacing[value as SpacingToken];\r\n }\r\n\r\n // Number → px\r\n if (typeof value === \"number\") {\r\n return `${value}px`;\r\n }\r\n\r\n // CSS string passthrough\r\n return value;\r\n}\r\n\r\n/**\r\n * Resolve a responsive spacing value at the current breakpoint.\r\n */\r\nexport function resolveResponsiveSpacing(\r\n value: ResponsiveValue<SpacingInput> | undefined,\r\n breakpoint: Breakpoint,\r\n tokens: ThemeTokens,\r\n): string | undefined {\r\n if (value === undefined || value === null) return undefined;\r\n\r\n const resolved = Array.isArray(value)\r\n ? resolveResponsiveValue(value, breakpoint)\r\n : value;\r\n\r\n return resolveSpacing(resolved, tokens);\r\n}\r\n\r\n/**\r\n * Resolve a responsive value (non-spacing) at the current breakpoint.\r\n */\r\nexport function resolveResponsive<T>(\r\n value: ResponsiveValue<T> | undefined,\r\n breakpoint: Breakpoint,\r\n): T | undefined {\r\n if (value === undefined || value === null) return undefined;\r\n return Array.isArray(value)\r\n ? resolveResponsiveValue(value, breakpoint)\r\n : value;\r\n}\r\n"],"mappings":";;;;;;;;AAgCA,SAAgB,eACd,OACA,QACoB;CACpB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAGlD,IAAI,OAAO,UAAU,YAAY,SAAS,OAAO,SAC/C,OAAO,OAAO,QAAQ;CAIxB,IAAI,OAAO,UAAU,UACnB,OAAO,GAAG,MAAM;CAIlB,OAAO;AACT;;;;AAKA,SAAgB,yBACd,OACA,YACA,QACoB;CACpB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAMlD,OAAO,eAJU,MAAM,QAAQ,KAAK,IAChC,uBAAuB,OAAO,UAAU,IACxC,OAE4B,MAAM;AACxC;;;;AAKA,SAAgB,kBACd,OACA,YACe;CACf,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM,OAAO,KAAA;CAClD,OAAO,MAAM,QAAQ,KAAK,IACtB,uBAAuB,OAAO,UAAU,IACxC;AACN"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBreakpoint.js","names":[],"sources":["../../../../src/react/core/layout/useBreakpoint.ts"],"sourcesContent":["/**\n * @zendir/ui - Responsive Breakpoint System\n *\n * Breakpoints aligned with Astro UX Design System responsive guidelines.\n * Supports mission control displays (4K) down to mobile field devices.\n *\n * Breakpoints:\n * - sm: 640px — Mobile landscape / small tablets\n * - md: 768px — Tablets\n * - lg: 1024px — Laptops / desktop\n * - xl: 1280px — Large monitors\n * - xxl: 1920px — Mission control displays (HD)\n *\n * @example\n * ```tsx\n * const { isMobile, isTablet, isDesktop, breakpoint, width } = useBreakpoint();\n * ```\n */\n\nimport { useState, useEffect, useCallback, useMemo } from \"react\";\n\nexport type Breakpoint = \"base\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"xxl\";\n\n/** Responsive value: single value or [base, sm?, md?, lg?, xl?, xxl?] */\nexport type ResponsiveValue<T> = T | [T, T?, T?, T?, T?, T?];\n\nexport const BREAKPOINTS = {\n base: 0,\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n xxl: 1920,\n} as const;\n\nconst BREAKPOINT_ORDER: Breakpoint[] = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\"];\n\nfunction getBreakpoint(width: number): Breakpoint {\n if (width >= BREAKPOINTS.xxl) return \"xxl\";\n if (width >= BREAKPOINTS.xl) return \"xl\";\n if (width >= BREAKPOINTS.lg) return \"lg\";\n if (width >= BREAKPOINTS.md) return \"md\";\n if (width >= BREAKPOINTS.sm) return \"sm\";\n return \"base\";\n}\n\nexport interface UseBreakpointReturn {\n /** Current breakpoint name */\n breakpoint: Breakpoint;\n /** Current viewport width in px */\n width: number;\n /** True when viewport < 768px (base, sm) */\n isMobile: boolean;\n /** True when viewport >= 768px and < 1024px */\n isTablet: boolean;\n /** True when viewport >= 1024px */\n isDesktop: boolean;\n /** True when viewport >= 1920px (mission control) */\n isWidescreen: boolean;\n /** Check if viewport is at or above a given breakpoint */\n isAbove: (bp: Breakpoint) => boolean;\n /** Check if viewport is below a given breakpoint */\n isBelow: (bp: Breakpoint) => boolean;\n}\n\n/**\n * Hook for responsive breakpoint detection.\n *\n * Uses matchMedia for efficient, debounce-free breakpoint tracking.\n * Respects SSR by defaulting to 'lg' (desktop).\n *\n * @example\n * ```tsx\n * const { isMobile, isDesktop, breakpoint } = useBreakpoint();\n *\n * return (\n * <Grid columns={isMobile ? 1 : 3}>\n * ...\n * </Grid>\n * );\n * ```\n */\nexport function useBreakpoint(): UseBreakpointReturn {\n const [width, setWidth] = useState(() => {\n if (typeof window !== \"undefined\") return window.innerWidth;\n return 1024; // SSR default: desktop\n });\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n let rafId: number;\n const handleResize = () => {\n cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n setWidth(window.innerWidth);\n });\n };\n\n window.addEventListener(\"resize\", handleResize, { passive: true });\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n cancelAnimationFrame(rafId);\n };\n }, []);\n\n const breakpoint = useMemo(() => getBreakpoint(width), [width]);\n\n const isAbove = useCallback(\n (bp: Breakpoint) => {\n return width >= BREAKPOINTS[bp];\n },\n [width],\n );\n\n const isBelow = useCallback(\n (bp: Breakpoint) => {\n return width < BREAKPOINTS[bp];\n },\n [width],\n );\n\n return useMemo(\n () => ({\n breakpoint,\n width,\n isMobile: width < BREAKPOINTS.md,\n isTablet: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,\n isDesktop: width >= BREAKPOINTS.lg,\n isWidescreen: width >= BREAKPOINTS.xxl,\n isAbove,\n isBelow,\n }),\n [breakpoint, width, isAbove, isBelow],\n );\n}\n\n/**\n * Resolve a responsive value based on current breakpoint.\n *\n * Given `[1, 2, 3]` at breakpoint 'lg', returns 3.\n * Falls back to the last defined value for higher breakpoints.\n *\n * @example\n * resolveResponsiveValue([1, 2, 3], 'lg') // → 3\n * resolveResponsiveValue([1, 2], 'xl') // → 2 (falls back to last defined)\n * resolveResponsiveValue(5, 'md') // → 5 (non-array passthrough)\n */\nexport function resolveResponsiveValue<T>(\n value: ResponsiveValue<T>,\n breakpoint: Breakpoint,\n): T {\n if (!Array.isArray(value)) return value;\n\n const index = BREAKPOINT_ORDER.indexOf(breakpoint);\n\n // Walk backwards from current breakpoint to find a defined value\n for (let i = Math.min(index, value.length - 1); i >= 0; i--) {\n if (value[i] !== undefined && value[i] !== null) return value[i] as T;\n }\n\n // Fallback: find first defined value in the responsive array.\n for (let i = 0; i < value.length; i++) {\n if (value[i] !== undefined && value[i] !== null) return value[i] as T;\n }\n\n return value[0] as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,cAAc;CACzB,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;AACP;AAEA,IAAM,mBAAiC;CAAC;CAAQ;CAAM;CAAM;CAAM;CAAM;AAAK;AAE7E,SAAS,cAAc,OAA2B;CAChD,IAAI,SAAS,YAAY,KAAK,OAAO;CACrC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,OAAO;AACT;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,gBAAqC;CACnD,MAAM,CAAC,OAAO,YAAY,eAAe;EACvC,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;EACjD,OAAO;CACT,CAAC;CAED,gBAAgB;EACd,IAAI,OAAO,WAAW,aAAa;EAEnC,IAAI;EACJ,MAAM,qBAAqB;GACzB,qBAAqB,KAAK;GAC1B,QAAQ,4BAA4B;IAClC,SAAS,OAAO,UAAU;GAC5B,CAAC;EACH;EAEA,OAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;EACjE,aAAa;GACX,OAAO,oBAAoB,UAAU,YAAY;GACjD,qBAAqB,KAAK;EAC5B;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,cAAc,cAAc,KAAK,GAAG,CAAC,KAAK,CAAC;CAE9D,MAAM,UAAU,aACb,OAAmB;EAClB,OAAO,SAAS,YAAY;CAC9B,GACA,CAAC,KAAK,CACR;CAEA,MAAM,UAAU,aACb,OAAmB;EAClB,OAAO,QAAQ,YAAY;CAC7B,GACA,CAAC,KAAK,CACR;CAEA,OAAO,eACE;EACL;EACA;EACA,UAAU,QAAQ,YAAY;EAC9B,UAAU,SAAS,YAAY,MAAM,QAAQ,YAAY;EACzD,WAAW,SAAS,YAAY;EAChC,cAAc,SAAS,YAAY;EACnC;EACA;CACF,IACA;EAAC;EAAY;EAAO;EAAS;CAAO,CACtC;AACF;;;;;;;;;;;;AAaA,SAAgB,uBACd,OACA,YACG;CACH,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,MAAM,QAAQ,iBAAiB,QAAQ,UAAU;CAGjD,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC,GAAG,KAAK,GAAG,KACtD,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,MAAM,OAAO,MAAM;CAIhE,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,MAAM,OAAO,MAAM;CAGhE,OAAO,MAAM;AACf"}
1
+ {"version":3,"file":"useBreakpoint.js","names":[],"sources":["../../../../src/react/core/layout/useBreakpoint.ts"],"sourcesContent":["/**\r\n * @zendir/ui - Responsive Breakpoint System\r\n *\r\n * Breakpoints aligned with Astro UX Design System responsive guidelines.\r\n * Supports mission control displays (4K) down to mobile field devices.\r\n *\r\n * Breakpoints:\r\n * - sm: 640px — Mobile landscape / small tablets\r\n * - md: 768px — Tablets\r\n * - lg: 1024px — Laptops / desktop\r\n * - xl: 1280px — Large monitors\r\n * - xxl: 1920px — Mission control displays (HD)\r\n *\r\n * @example\r\n * ```tsx\r\n * const { isMobile, isTablet, isDesktop, breakpoint, width } = useBreakpoint();\r\n * ```\r\n */\r\n\r\nimport { useState, useEffect, useCallback, useMemo } from \"react\";\r\n\r\nexport type Breakpoint = \"base\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"xxl\";\r\n\r\n/** Responsive value: single value or [base, sm?, md?, lg?, xl?, xxl?] */\r\nexport type ResponsiveValue<T> = T | [T, T?, T?, T?, T?, T?];\r\n\r\nexport const BREAKPOINTS = {\r\n base: 0,\r\n sm: 640,\r\n md: 768,\r\n lg: 1024,\r\n xl: 1280,\r\n xxl: 1920,\r\n} as const;\r\n\r\nconst BREAKPOINT_ORDER: Breakpoint[] = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\"];\r\n\r\nfunction getBreakpoint(width: number): Breakpoint {\r\n if (width >= BREAKPOINTS.xxl) return \"xxl\";\r\n if (width >= BREAKPOINTS.xl) return \"xl\";\r\n if (width >= BREAKPOINTS.lg) return \"lg\";\r\n if (width >= BREAKPOINTS.md) return \"md\";\r\n if (width >= BREAKPOINTS.sm) return \"sm\";\r\n return \"base\";\r\n}\r\n\r\nexport interface UseBreakpointReturn {\r\n /** Current breakpoint name */\r\n breakpoint: Breakpoint;\r\n /** Current viewport width in px */\r\n width: number;\r\n /** True when viewport < 768px (base, sm) */\r\n isMobile: boolean;\r\n /** True when viewport >= 768px and < 1024px */\r\n isTablet: boolean;\r\n /** True when viewport >= 1024px */\r\n isDesktop: boolean;\r\n /** True when viewport >= 1920px (mission control) */\r\n isWidescreen: boolean;\r\n /** Check if viewport is at or above a given breakpoint */\r\n isAbove: (bp: Breakpoint) => boolean;\r\n /** Check if viewport is below a given breakpoint */\r\n isBelow: (bp: Breakpoint) => boolean;\r\n}\r\n\r\n/**\r\n * Hook for responsive breakpoint detection.\r\n *\r\n * Uses matchMedia for efficient, debounce-free breakpoint tracking.\r\n * Respects SSR by defaulting to 'lg' (desktop).\r\n *\r\n * @example\r\n * ```tsx\r\n * const { isMobile, isDesktop, breakpoint } = useBreakpoint();\r\n *\r\n * return (\r\n * <Grid columns={isMobile ? 1 : 3}>\r\n * ...\r\n * </Grid>\r\n * );\r\n * ```\r\n */\r\nexport function useBreakpoint(): UseBreakpointReturn {\r\n const [width, setWidth] = useState(() => {\r\n if (typeof window !== \"undefined\") return window.innerWidth;\r\n return 1024; // SSR default: desktop\r\n });\r\n\r\n useEffect(() => {\r\n if (typeof window === \"undefined\") return;\r\n\r\n let rafId: number;\r\n const handleResize = () => {\r\n cancelAnimationFrame(rafId);\r\n rafId = requestAnimationFrame(() => {\r\n setWidth(window.innerWidth);\r\n });\r\n };\r\n\r\n window.addEventListener(\"resize\", handleResize, { passive: true });\r\n return () => {\r\n window.removeEventListener(\"resize\", handleResize);\r\n cancelAnimationFrame(rafId);\r\n };\r\n }, []);\r\n\r\n const breakpoint = useMemo(() => getBreakpoint(width), [width]);\r\n\r\n const isAbove = useCallback(\r\n (bp: Breakpoint) => {\r\n return width >= BREAKPOINTS[bp];\r\n },\r\n [width],\r\n );\r\n\r\n const isBelow = useCallback(\r\n (bp: Breakpoint) => {\r\n return width < BREAKPOINTS[bp];\r\n },\r\n [width],\r\n );\r\n\r\n return useMemo(\r\n () => ({\r\n breakpoint,\r\n width,\r\n isMobile: width < BREAKPOINTS.md,\r\n isTablet: width >= BREAKPOINTS.md && width < BREAKPOINTS.lg,\r\n isDesktop: width >= BREAKPOINTS.lg,\r\n isWidescreen: width >= BREAKPOINTS.xxl,\r\n isAbove,\r\n isBelow,\r\n }),\r\n [breakpoint, width, isAbove, isBelow],\r\n );\r\n}\r\n\r\n/**\r\n * Resolve a responsive value based on current breakpoint.\r\n *\r\n * Given `[1, 2, 3]` at breakpoint 'lg', returns 3.\r\n * Falls back to the last defined value for higher breakpoints.\r\n *\r\n * @example\r\n * resolveResponsiveValue([1, 2, 3], 'lg') // → 3\r\n * resolveResponsiveValue([1, 2], 'xl') // → 2 (falls back to last defined)\r\n * resolveResponsiveValue(5, 'md') // → 5 (non-array passthrough)\r\n */\r\nexport function resolveResponsiveValue<T>(\r\n value: ResponsiveValue<T>,\r\n breakpoint: Breakpoint,\r\n): T {\r\n if (!Array.isArray(value)) return value;\r\n\r\n const index = BREAKPOINT_ORDER.indexOf(breakpoint);\r\n\r\n // Walk backwards from current breakpoint to find a defined value\r\n for (let i = Math.min(index, value.length - 1); i >= 0; i--) {\r\n if (value[i] !== undefined && value[i] !== null) return value[i] as T;\r\n }\r\n\r\n // Fallback: find first defined value in the responsive array.\r\n for (let i = 0; i < value.length; i++) {\r\n if (value[i] !== undefined && value[i] !== null) return value[i] as T;\r\n }\r\n\r\n return value[0] as T;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,cAAc;CACzB,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,KAAK;AACP;AAEA,IAAM,mBAAiC;CAAC;CAAQ;CAAM;CAAM;CAAM;CAAM;AAAK;AAE7E,SAAS,cAAc,OAA2B;CAChD,IAAI,SAAS,YAAY,KAAK,OAAO;CACrC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,IAAI,SAAS,YAAY,IAAI,OAAO;CACpC,OAAO;AACT;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,gBAAqC;CACnD,MAAM,CAAC,OAAO,YAAY,eAAe;EACvC,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;EACjD,OAAO;CACT,CAAC;CAED,gBAAgB;EACd,IAAI,OAAO,WAAW,aAAa;EAEnC,IAAI;EACJ,MAAM,qBAAqB;GACzB,qBAAqB,KAAK;GAC1B,QAAQ,4BAA4B;IAClC,SAAS,OAAO,UAAU;GAC5B,CAAC;EACH;EAEA,OAAO,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;EACjE,aAAa;GACX,OAAO,oBAAoB,UAAU,YAAY;GACjD,qBAAqB,KAAK;EAC5B;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,cAAc,cAAc,KAAK,GAAG,CAAC,KAAK,CAAC;CAE9D,MAAM,UAAU,aACb,OAAmB;EAClB,OAAO,SAAS,YAAY;CAC9B,GACA,CAAC,KAAK,CACR;CAEA,MAAM,UAAU,aACb,OAAmB;EAClB,OAAO,QAAQ,YAAY;CAC7B,GACA,CAAC,KAAK,CACR;CAEA,OAAO,eACE;EACL;EACA;EACA,UAAU,QAAQ,YAAY;EAC9B,UAAU,SAAS,YAAY,MAAM,QAAQ,YAAY;EACzD,WAAW,SAAS,YAAY;EAChC,cAAc,SAAS,YAAY;EACnC;EACA;CACF,IACA;EAAC;EAAY;EAAO;EAAS;CAAO,CACtC;AACF;;;;;;;;;;;;AAaA,SAAgB,uBACd,OACA,YACG;CACH,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,MAAM,QAAQ,iBAAiB,QAAQ,UAAU;CAGjD,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM,SAAS,CAAC,GAAG,KAAK,GAAG,KACtD,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,MAAM,OAAO,MAAM;CAIhE,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,MAAM,OAAO,MAAM;CAGhE,OAAO,MAAM;AACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"AppBar.js","names":[],"sources":["../../../../src/react/core/navigation/AppBar.tsx"],"sourcesContent":["/**\n * @zendir/ui - AppBar Component\n *\n * Enterprise-grade application bar with integrated theme controls,\n * compact mode toggle, and display settings management.\n *\n * Features:\n * - Customizable branding (logo, name, domain, version)\n * - Dark/light mode toggle\n * - Theme variant selector\n * - Color picker (accent + glass tint)\n * - Compact mode toggle (affects all cards globally)\n * - Integrates with DisplaySettingsProvider\n * - Responsive design\n * - AstroUXDS compliant\n *\n * @example\n * ```tsx\n * import { AppBar, ThemeProvider, DisplaySettingsProvider } from '@zendir/ui';\n *\n * <ThemeProvider>\n * <DisplaySettingsProvider>\n * <AppBar\n * appName=\"Mission Control\"\n * appDomain=\"NASA\"\n * appVersion=\"1.0.0\"\n * showThemeControls\n * showCompactToggle\n * />\n * <App />\n * </DisplaySettingsProvider>\n * </ThemeProvider>\n * ```\n */\n\nimport React, {\n memo,\n useMemo,\n useState,\n useRef,\n useEffect,\n type ReactNode,\n} from \"react\";\nimport { useTheme, type ThemeVariant, type ThemeMode } from \"../../theme\";\nimport { useDisplaySettingsOptional } from \"../../context/DisplaySettingsContext\";\nimport { classNames, safeAccentText } from \"../../utils\";\nimport { AstroIcon } from \"../display/AstroIcon\";\nimport { ColorPickerPanel } from \"../widgets/ColorPickerPanel\";\nimport { Tooltip } from \"../overlays/Tooltip\";\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface AppBarBranding {\n /** Logo image URL (takes precedence over text) */\n logoUrl?: string;\n /** Logo as React node (takes precedence over logoUrl) */\n logo?: ReactNode;\n /** Logo alt text for accessibility */\n logoAlt?: string;\n /** Logo height in pixels (default: 28) */\n logoHeight?: number;\n /** Link URL when clicking on branding */\n href?: string;\n}\n\nexport interface AppBarProps {\n /** Application name */\n appName?: string;\n /** Application domain/organization (shown above app name) */\n appDomain?: string;\n /** Application version (shown smaller) */\n appVersion?: string;\n /** Logo/branding configuration */\n branding?: AppBarBranding;\n\n // Control visibility\n /** Show theme controls (mode toggle, theme selector, color picker) */\n showThemeControls?: boolean;\n /** Show compact mode toggle */\n showCompactToggle?: boolean;\n /** Show color picker (only visible for transparent themes) */\n showColorPicker?: boolean;\n /** Show theme variant selector */\n showThemeSelector?: boolean;\n /** Show only mode toggle (hide other theme controls) */\n showModeOnly?: boolean;\n /** Use compact dropdown for theme controls instead of buttons */\n compactThemeControls?: boolean;\n\n // Default values (for when controls are hidden)\n /** Default theme to apply if not already set */\n defaultTheme?: ThemeVariant;\n /** Default mode to apply if not already set */\n defaultMode?: ThemeMode;\n /** Default compact mode */\n defaultCompactMode?: boolean;\n\n // Slots\n /** Left slot content (after branding, or only content when showBranding is false) */\n leftSlot?: ReactNode;\n /** Center slot content */\n centerSlot?: ReactNode;\n /** Right slot content (before theme controls) */\n rightSlot?: ReactNode;\n /** Optional title shown above right slot (e.g. \"Data\" for metrics/refresh section) */\n rightSectionTitle?: string;\n\n // Layout (operator / mission-control style)\n /** Show branding block (app name, logo). Set false for control-only bars. */\n showBranding?: boolean;\n /** Let center slot grow to fill space and stay centered (e.g. simulation controls). */\n centerGrow?: boolean;\n /** Bar variant: default (52px) or dense (44px min height, tighter padding/gap). */\n variant?: \"default\" | \"dense\";\n\n // Callbacks\n /** Callback when theme changes */\n onThemeChange?: (theme: ThemeVariant) => void;\n /** Callback when mode changes */\n onModeChange?: (mode: ThemeMode) => void;\n /** Callback when compact mode changes */\n onCompactModeChange?: (compact: boolean) => void;\n\n // Styling\n /** Custom className */\n className?: string;\n /** Custom height (default: 52) */\n height?: number;\n /** Sticky positioning */\n sticky?: boolean;\n}\n\n// =============================================================================\n// Theme Variants for Selector\n// =============================================================================\n\nconst THEME_VARIANTS: { key: ThemeVariant; label: string; tooltip: string }[] =\n [\n {\n key: \"hybrid\",\n label: \"Zen (Hybrid)\",\n tooltip: \"Default theme - Astro status colors with purple accents\",\n },\n {\n key: \"purple-hue\",\n label: \"Zen (Purple Hue)\",\n tooltip: \"Purple accent theme - vibrant purple tones\",\n },\n {\n key: \"astro\",\n label: \"Astro\",\n tooltip: \"Astro UX Design System theme - dark blue tones\",\n },\n {\n key: \"transparent\",\n label: \"Glass\",\n tooltip: \"Glassmorphism theme - transparent with blur effects\",\n },\n {\n key: \"transparent-bold\",\n label: \"Bold\",\n tooltip: \"Bold glass theme - stronger transparency effects\",\n },\n {\n key: \"transparent-minimal\",\n label: \"Minimal\",\n tooltip: \"Minimal glass theme - ultra-subtle borders, clean surfaces\",\n },\n ];\n\n// =============================================================================\n// Mode Toggle Component\n// =============================================================================\n\ninterface ModeToggleProps {\n mode: ThemeMode;\n onToggle: () => void;\n tokens: any;\n}\n\nconst ModeToggle = memo(function ModeToggle({\n mode,\n onToggle,\n tokens,\n}: ModeToggleProps) {\n const isDark = mode === \"dark\";\n const tooltipText = isDark ? \"Switch to Light Mode\" : \"Switch to Dark Mode\";\n\n return (\n <Tooltip content={tooltipText} placement=\"bottom\">\n <button\n onClick={onToggle}\n aria-label={tooltipText}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 32,\n height: 32,\n padding: 0,\n border: \"none\",\n borderRadius: tokens.borderRadius.md,\n backgroundColor: \"rgba(255,255,255,0.08)\",\n color: tokens.colors.text.primary,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.08)\";\n }}\n >\n <AstroIcon\n name={isDark ? \"brightness-3\" : \"brightness-high\"}\n size={16}\n color={tokens.colors.text.primary}\n />\n </button>\n </Tooltip>\n );\n});\n\n// =============================================================================\n// Compact Mode Toggle Component\n// =============================================================================\n\ninterface CompactToggleProps {\n isCompact: boolean;\n onToggle: () => void;\n tokens: any;\n}\n\nconst CompactToggle = memo(function CompactToggle({\n isCompact,\n onToggle,\n tokens,\n}: CompactToggleProps) {\n const tooltipText = isCompact\n ? \"Switch to Expanded View\"\n : \"Switch to Compact View\";\n\n return (\n <Tooltip content={tooltipText} placement=\"bottom\">\n <button\n onClick={onToggle}\n aria-label={tooltipText}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 32,\n height: 32,\n padding: 0,\n border: \"none\",\n borderRadius: tokens.borderRadius.md,\n backgroundColor: isCompact\n ? `${tokens.colors.accent.primary}40`\n : \"rgba(255,255,255,0.08)\",\n color: isCompact\n ? tokens.colors.accent.secondary\n : tokens.colors.text.primary,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isCompact\n ? `${tokens.colors.accent.primary}59`\n : \"rgba(255,255,255,0.15)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = isCompact\n ? `${tokens.colors.accent.primary}40`\n : \"rgba(255,255,255,0.08)\";\n }}\n >\n <AstroIcon\n name={isCompact ? \"view-comfy\" : \"view-module\"}\n size={16}\n color={\n isCompact\n ? tokens.colors.accent.secondary\n : tokens.colors.text.primary\n }\n />\n </button>\n </Tooltip>\n );\n});\n\n// =============================================================================\n// Theme Selector Component\n// =============================================================================\n\ninterface ThemeSelectorProps {\n currentTheme: ThemeVariant;\n onSelect: (theme: ThemeVariant) => void;\n tokens: any;\n}\n\nconst ThemeSelector = memo(function ThemeSelector({\n currentTheme,\n onSelect,\n tokens,\n}: ThemeSelectorProps) {\n // WCAG AA: compute a safe background for selected theme buttons (white text)\n const safeAccentBg = useMemo(() => {\n const hex = tokens.colors.accent.primary.replace(\"#\", \"\");\n if (hex.length < 6) return tokens.colors.accent.primary;\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n const r = parseInt(hex.slice(0, 2), 16) / 255;\n const g = parseInt(hex.slice(2, 4), 16) / 255;\n const b = parseInt(hex.slice(4, 6), 16) / 255;\n const L =\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n if (1.05 / (L + 0.05) >= 4.5) return tokens.colors.accent.primary;\n const factor = 0.88;\n const dr = Math.min(255, Math.round(r * 255 * factor));\n const dg = Math.min(255, Math.round(g * 255 * factor));\n const db = Math.min(255, Math.round(b * 255 * factor));\n return `#${dr.toString(16).padStart(2, \"0\")}${dg.toString(16).padStart(2, \"0\")}${db.toString(16).padStart(2, \"0\")}`;\n }, [tokens.colors.accent.primary]);\n\n // Group themes for better organization\n const coreThemes = THEME_VARIANTS.filter(\n (t) => !t.key.startsWith(\"transparent\"),\n );\n const glassThemes = THEME_VARIANTS.filter((t) =>\n t.key.startsWith(\"transparent\"),\n );\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: 2,\n backgroundColor: \"rgba(255,255,255,0.05)\",\n borderRadius: tokens.borderRadius.md,\n }}\n role=\"group\"\n aria-label=\"Theme selector\"\n >\n {/* Core themes */}\n {coreThemes.map(({ key, label, tooltip }) => (\n <Tooltip key={key} content={tooltip} placement=\"bottom\">\n <button\n onClick={() => onSelect(key)}\n aria-label={`Select ${label} theme`}\n style={{\n padding: \"4px 10px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor:\n currentTheme === key ? safeAccentBg : \"transparent\",\n color:\n currentTheme === key ? \"#ffffff\" : tokens.colors.text.secondary,\n fontSize: \"0.6875rem\", // 11px in rem\n fontWeight: currentTheme === key ? 500 : 400, // AstroUXDS: 500 (medium) not 600\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n whiteSpace: \"nowrap\",\n }}\n onMouseEnter={(e) => {\n if (currentTheme !== key) {\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.1)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n currentTheme === key ? safeAccentBg : \"transparent\";\n }}\n >\n {label}\n </button>\n </Tooltip>\n ))}\n\n {/* Separator */}\n <div\n style={{\n width: 1,\n height: 16,\n backgroundColor: \"rgba(255,255,255,0.15)\",\n margin: \"0 2px\",\n }}\n />\n\n {/* Glass themes */}\n {glassThemes.map(({ key, label, tooltip }) => (\n <Tooltip key={key} content={tooltip} placement=\"bottom\">\n <button\n onClick={() => onSelect(key)}\n aria-label={`Select ${label} theme`}\n style={{\n padding: \"4px 10px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor:\n currentTheme === key ? safeAccentBg : \"transparent\",\n color:\n currentTheme === key ? \"#ffffff\" : tokens.colors.text.secondary,\n fontSize: \"0.6875rem\", // 11px in rem\n fontWeight: currentTheme === key ? 500 : 400, // AstroUXDS: 500 (medium) not 600\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n whiteSpace: \"nowrap\",\n }}\n onMouseEnter={(e) => {\n if (currentTheme !== key) {\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.1)\";\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n currentTheme === key ? safeAccentBg : \"transparent\";\n }}\n >\n {label}\n </button>\n </Tooltip>\n ))}\n </div>\n );\n});\n\n// =============================================================================\n// Accent Borders Toggle Component\n// =============================================================================\n\ninterface AccentBordersToggleProps {\n enabled: boolean;\n onToggle: () => void;\n tokens: any;\n}\n\nconst AccentBordersToggle = memo(function AccentBordersToggle({\n enabled,\n onToggle,\n tokens,\n}: AccentBordersToggleProps) {\n return (\n <Tooltip\n content={\n enabled\n ? \"Accent borders enabled - Click to disable\"\n : \"Accent borders disabled - Click to enable\"\n }\n placement=\"bottom\"\n >\n <button\n onClick={onToggle}\n aria-label={\n enabled ? \"Disable accent borders\" : \"Enable accent borders\"\n }\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 4,\n padding: \"4px 8px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor: enabled\n ? `${tokens.colors.accent.primary}30`\n : \"rgba(255,255,255,0.05)\",\n color: enabled\n ? safeAccentText(tokens.colors.accent.primary)\n : tokens.colors.text.tertiary,\n fontSize: \"0.625rem\", // 10px in rem\n fontWeight: 500,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n whiteSpace: \"nowrap\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = enabled\n ? `${tokens.colors.accent.primary}40`\n : \"rgba(255,255,255,0.1)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = enabled\n ? `${tokens.colors.accent.primary}30`\n : \"rgba(255,255,255,0.05)\";\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n border: `2px solid ${enabled ? tokens.colors.accent.primary : tokens.colors.text.tertiary}`,\n backgroundColor: \"transparent\",\n }}\n />\n <span>Borders</span>\n </button>\n </Tooltip>\n );\n});\n\n// =============================================================================\n// Theme Controls Dropdown (Compact)\n// =============================================================================\n\ninterface ThemeControlsDropdownProps {\n currentTheme: ThemeVariant;\n mode: ThemeMode;\n onThemeSelect: (theme: ThemeVariant) => void;\n onModeToggle: () => void;\n accentBordersEnabled?: boolean;\n onAccentBordersToggle?: () => void;\n showAccentBorders?: boolean;\n tokens: any;\n}\n\nconst ThemeControlsDropdown = memo(function ThemeControlsDropdown({\n currentTheme,\n mode,\n onThemeSelect,\n onModeToggle,\n accentBordersEnabled = true,\n onAccentBordersToggle,\n showAccentBorders = false,\n tokens,\n}: ThemeControlsDropdownProps) {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Close on click outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }\n }, [isOpen]);\n\n // Get current theme label\n const currentLabel =\n THEME_VARIANTS.find((t) => t.key === currentTheme)?.label || \"Theme\";\n\n // Group themes\n const coreThemes = THEME_VARIANTS.filter(\n (t) => !t.key.startsWith(\"transparent\"),\n );\n const glassThemes = THEME_VARIANTS.filter((t) =>\n t.key.startsWith(\"transparent\"),\n );\n\n return (\n <div ref={dropdownRef} style={{ position: \"relative\" }}>\n {/* Trigger Button */}\n <Tooltip content=\"Theme settings\" placement=\"bottom\">\n <button\n onClick={() => setIsOpen(!isOpen)}\n aria-label=\"Theme settings\"\n aria-expanded={isOpen}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 10px\",\n border: `1px solid ${tokens.colors.border.muted}`,\n borderRadius: tokens.borderRadius.md,\n backgroundColor: isOpen\n ? tokens.colors.background.elevated\n : \"transparent\",\n color: tokens.colors.text.secondary,\n fontSize: \"0.6875rem\", // 11px in rem\n fontWeight: 500,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n }}\n onMouseEnter={(e) => {\n if (!isOpen) {\n e.currentTarget.style.backgroundColor =\n tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n if (!isOpen) {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }\n }}\n >\n <AstroIcon\n name=\"settings\"\n size={14}\n color={tokens.colors.text.secondary}\n />\n <span>{currentLabel}</span>\n <AstroIcon\n name={isOpen ? \"arrow-up\" : \"arrow-down\"}\n size={10}\n color={tokens.colors.text.tertiary}\n />\n </button>\n </Tooltip>\n\n {/* Dropdown Panel */}\n {isOpen && (\n <div\n style={{\n position: \"absolute\",\n top: \"100%\",\n right: 0,\n marginTop: 4,\n minWidth: 220,\n padding: tokens.spacing.sm,\n backgroundColor: tokens.colors.background.surface,\n border: `1px solid ${tokens.colors.border.muted}`,\n borderRadius: tokens.borderRadius.lg,\n boxShadow: \"0 8px 32px rgba(0,0,0,0.3)\",\n zIndex: 1000,\n }}\n >\n {/* Theme Section */}\n <div style={{ marginBottom: tokens.spacing.sm }}>\n <div\n style={{\n fontSize: \"0.625rem\", // 10px in rem\n color: tokens.colors.text.muted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n marginBottom: 8,\n paddingLeft: 4,\n }}\n >\n Theme\n </div>\n\n {/* Core Themes */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\n {coreThemes.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => {\n onThemeSelect(key);\n setIsOpen(false);\n }}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"8px 12px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor:\n currentTheme === key\n ? `${tokens.colors.accent.primary}20`\n : \"transparent\",\n color:\n currentTheme === key\n ? tokens.colors.accent.primary\n : tokens.colors.text.primary,\n fontSize: \"0.75rem\", // 12px in rem\n fontWeight: currentTheme === key ? 600 : 400,\n cursor: \"pointer\",\n textAlign: \"left\",\n transition: \"all 0.1s ease\",\n }}\n onMouseEnter={(e) => {\n if (currentTheme !== key) {\n e.currentTarget.style.backgroundColor =\n tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n currentTheme === key\n ? `${tokens.colors.accent.primary}20`\n : \"transparent\";\n }}\n >\n {currentTheme === key && (\n <AstroIcon\n name=\"check\"\n size={12}\n color={tokens.colors.accent.primary}\n />\n )}\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>\n {label}\n </span>\n </button>\n ))}\n </div>\n\n {/* Separator */}\n <div\n style={{\n height: 1,\n backgroundColor: tokens.colors.border.muted,\n margin: `${tokens.spacing.xs} 0`,\n }}\n />\n\n {/* Glass Themes */}\n <div\n style={{\n fontSize: \"0.625rem\", // 10px in rem\n color: tokens.colors.text.muted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n marginBottom: 6,\n paddingLeft: 4,\n }}\n >\n Glass\n </div>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\n {glassThemes.map(({ key, label }) => (\n <button\n key={key}\n onClick={() => {\n onThemeSelect(key);\n setIsOpen(false);\n }}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"8px 12px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor:\n currentTheme === key\n ? `${tokens.colors.accent.primary}20`\n : \"transparent\",\n color:\n currentTheme === key\n ? tokens.colors.accent.primary\n : tokens.colors.text.primary,\n fontSize: \"0.75rem\", // 12px in rem\n fontWeight: currentTheme === key ? 600 : 400,\n cursor: \"pointer\",\n textAlign: \"left\",\n transition: \"all 0.1s ease\",\n }}\n onMouseEnter={(e) => {\n if (currentTheme !== key) {\n e.currentTarget.style.backgroundColor =\n tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n currentTheme === key\n ? `${tokens.colors.accent.primary}20`\n : \"transparent\";\n }}\n >\n {currentTheme === key && (\n <AstroIcon\n name=\"check\"\n size={12}\n color={tokens.colors.accent.primary}\n />\n )}\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>\n {label}\n </span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Separator */}\n <div\n style={{\n height: 1,\n backgroundColor: tokens.colors.border.muted,\n margin: `${tokens.spacing.sm} 0`,\n }}\n />\n\n {/* Options Section */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 4 }}>\n {/* Mode Toggle */}\n <button\n onClick={() => {\n onModeToggle();\n }}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"8px 12px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor: \"transparent\",\n color: tokens.colors.text.primary,\n fontSize: \"0.75rem\", // 12px in rem\n cursor: \"pointer\",\n transition: \"all 0.1s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n tokens.colors.background.elevated;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <AstroIcon\n name={mode === \"dark\" ? \"brightness-high\" : \"brightness-low\"}\n size={14}\n color={tokens.colors.text.secondary}\n />\n {mode === \"dark\" ? \"Dark Mode\" : \"Light Mode\"}\n </span>\n <div\n style={{\n width: 32,\n height: 18,\n borderRadius: 9,\n backgroundColor:\n mode === \"dark\"\n ? tokens.colors.accent.primary\n : tokens.colors.border.default,\n padding: 2,\n transition: \"all 0.15s ease\",\n }}\n >\n <div\n style={{\n width: 14,\n height: 14,\n borderRadius: \"50%\",\n backgroundColor: \"#fff\",\n transition: \"all 0.15s ease\",\n transform:\n mode === \"dark\" ? \"translateX(14px)\" : \"translateX(0)\",\n }}\n />\n </div>\n </button>\n\n {/* Accent Borders (only for glass themes) */}\n {showAccentBorders && onAccentBordersToggle && (\n <button\n onClick={onAccentBordersToggle}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"8px 12px\",\n border: \"none\",\n borderRadius: tokens.borderRadius.sm,\n backgroundColor: \"transparent\",\n color: tokens.colors.text.primary,\n fontSize: \"0.75rem\", // 12px in rem\n cursor: \"pointer\",\n transition: \"all 0.1s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor =\n tokens.colors.background.elevated;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"transparent\";\n }}\n >\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <span\n style={{\n width: 14,\n height: 14,\n borderRadius: 3,\n border: `2px solid ${tokens.colors.text.secondary}`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n {accentBordersEnabled && (\n <AstroIcon\n name=\"check\"\n size={10}\n color={tokens.colors.text.secondary}\n />\n )}\n </span>\n Accent Borders\n </span>\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n});\n\n// =============================================================================\n// AppBar Component\n// =============================================================================\n\n// =============================================================================\n// Section header for right slot (operator-style \"Data\" header)\n// =============================================================================\n\ninterface SectionHeaderProps {\n title: string;\n tokens: { typography: any; spacing: any; colors: any; borders: any };\n}\n\nconst SectionHeader = memo(function SectionHeader({\n title,\n tokens,\n}: SectionHeaderProps) {\n return (\n <div style={{ textAlign: \"center\", marginBottom: tokens.spacing.xs }}>\n <span\n style={{\n fontSize: tokens.typography.fontSize.xxs,\n fontFamily: tokens.typography.fontFamily.primary,\n color:\n tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\n fontWeight: tokens.typography.fontWeight.bold,\n }}\n >\n {title}\n </span>\n <div\n style={{\n width: \"100%\",\n height: tokens.borders.width.thin,\n background:\n tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\n opacity: 0.5,\n marginTop: tokens.spacing.xs,\n }}\n />\n </div>\n );\n});\n\n// =============================================================================\n// AppBar Component\n// =============================================================================\n\nexport const AppBar = memo(function AppBar({\n appName = \"Zendir\",\n appDomain,\n appVersion,\n branding,\n showThemeControls = true,\n showCompactToggle = true,\n showColorPicker = true,\n showThemeSelector = true,\n showModeOnly = false,\n compactThemeControls = false,\n defaultTheme,\n defaultMode,\n defaultCompactMode,\n leftSlot,\n centerSlot,\n rightSlot,\n rightSectionTitle,\n showBranding = true,\n centerGrow = false,\n variant = \"default\",\n onThemeChange,\n onModeChange,\n onCompactModeChange,\n className = \"\",\n height = 52,\n sticky = true,\n}: AppBarProps): React.ReactElement {\n const { tokens, theme, mode, setTheme, setMode, toggleMode } = useTheme();\n const { isMobile } = useBreakpoint();\n const displaySettings = useDisplaySettingsOptional();\n\n const isTransparentTheme =\n theme === \"transparent\" ||\n theme === \"transparent-bold\" ||\n theme === \"transparent-minimal\";\n\n // Get compact mode from context or default\n const compactMode =\n displaySettings?.compactMode ?? defaultCompactMode ?? false;\n\n // Apply defaults on first render if specified\n React.useEffect(() => {\n if (defaultTheme && theme !== defaultTheme) {\n setTheme(defaultTheme);\n onThemeChange?.(defaultTheme);\n }\n if (defaultMode && mode !== defaultMode) {\n setMode(defaultMode);\n onModeChange?.(defaultMode);\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Handle mode toggle\n const handleModeToggle = () => {\n toggleMode();\n onModeChange?.(mode === \"dark\" ? \"light\" : \"dark\");\n };\n\n // Handle theme change\n const handleThemeChange = (newTheme: ThemeVariant) => {\n setTheme(newTheme);\n onThemeChange?.(newTheme);\n };\n\n // Handle compact mode toggle\n const handleCompactToggle = () => {\n if (displaySettings) {\n displaySettings.toggleCompactMode();\n onCompactModeChange?.(!compactMode);\n } else {\n onCompactModeChange?.(!compactMode);\n }\n };\n\n // Variant-driven layout (operator / mission-control style)\n const isDense = variant === \"dense\";\n const effectiveHeight = height ?? (isDense ? 44 : 52);\n const paddingH = isDense\n ? isMobile\n ? tokens.spacing.xs\n : tokens.spacing.sm\n : isMobile\n ? tokens.spacing.md\n : tokens.spacing.lg;\n const paddingV = isDense ? tokens.spacing.xs : 0;\n const gap = isDense\n ? isMobile\n ? tokens.spacing.sm\n : tokens.spacing.md\n : tokens.spacing.sm;\n const minHeight = isDense && isMobile ? 44 : undefined;\n\n // Render branding section\n const renderBranding = () => {\n // Custom logo node\n if (branding?.logo) {\n const content = branding.logo;\n if (branding.href) {\n return (\n <a\n href={branding.href}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n textDecoration: \"none\",\n }}\n >\n {content}\n </a>\n );\n }\n return <>{content}</>;\n }\n\n // Logo image URL\n if (branding?.logoUrl) {\n const img = (\n <img\n src={branding.logoUrl}\n alt={branding.logoAlt || appName}\n style={{\n height: branding.logoHeight || 28,\n width: \"auto\",\n objectFit: \"contain\",\n }}\n />\n );\n\n if (branding.href) {\n return (\n <a\n href={branding.href}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n textDecoration: \"none\",\n }}\n >\n {img}\n </a>\n );\n }\n return img;\n }\n\n // Text branding\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"baseline\",\n gap: tokens.spacing.sm,\n }}\n >\n {appDomain && (\n <span\n style={{\n fontSize: tokens.typography.fontSize.sm,\n fontWeight: 400,\n color: tokens.colors.text.secondary,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n }}\n >\n {appDomain}\n </span>\n )}\n <span\n style={{\n fontSize: tokens.typography.fontSize.lg,\n fontWeight: 500, // AstroUXDS medium for app title\n color: tokens.colors.text.primary,\n }}\n >\n {appName}\n </span>\n {appVersion && (\n <span\n style={{\n fontSize: tokens.typography.fontSize.xs,\n color: tokens.colors.text.tertiary,\n }}\n >\n v{appVersion.replace(/^v/, \"\")}\n </span>\n )}\n </div>\n );\n };\n\n return (\n <header\n className={classNames(\"zendir-app-bar\", className)}\n role=\"banner\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n height: effectiveHeight,\n padding: paddingV ? `${paddingV} ${paddingH}` : `0 ${paddingH}`,\n backgroundColor: isTransparentTheme\n ? \"rgba(0,0,0,0.4)\"\n : tokens.colors.background.surface,\n ...(isTransparentTheme && {\n backdropFilter: \"blur(16px)\",\n WebkitBackdropFilter: \"blur(16px)\" as const,\n }),\n borderBottom: tokens.borders.divider,\n color: tokens.colors.text.primary,\n fontFamily: tokens.typography.fontFamily.primary,\n gap,\n ...(minHeight && { minHeight }),\n ...(sticky && {\n position: \"sticky\",\n top: 0,\n zIndex: 100,\n }),\n }}\n >\n {/* Left section: Branding (optional) + leftSlot */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: isDense ? gap : isMobile ? tokens.spacing.md : tokens.spacing.lg,\n flex: \"1 1 0\",\n minWidth: 0,\n }}\n >\n {showBranding && renderBranding()}\n {leftSlot}\n </div>\n\n {/* Center section (optionally grows to fill and center content) */}\n {centerSlot && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flex: centerGrow ? \"1 1 0\" : \"0 0 auto\",\n minWidth: 0,\n }}\n >\n {centerSlot}\n </div>\n )}\n\n {/* Right section: optional section title + rightSlot + theme controls + compact toggle */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n gap: tokens.spacing.sm,\n flex: \"1 1 0\",\n minWidth: 0,\n }}\n >\n {rightSectionTitle != null && rightSectionTitle !== \"\" ? (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n flexShrink: 0,\n }}\n >\n <SectionHeader title={rightSectionTitle} tokens={tokens} />\n {rightSlot}\n </div>\n ) : (\n rightSlot\n )}\n\n {/* Theme Controls Group */}\n {showThemeControls && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: isMobile ? 6 : 8,\n marginLeft: isMobile ? tokens.spacing.xs : tokens.spacing.sm,\n minWidth: 0,\n }}\n >\n {/* Compact Dropdown Mode */}\n {compactThemeControls ? (\n <ThemeControlsDropdown\n currentTheme={theme}\n mode={mode}\n onThemeSelect={handleThemeChange}\n onModeToggle={handleModeToggle}\n accentBordersEnabled={displaySettings?.accentBorders ?? true}\n onAccentBordersToggle={displaySettings?.toggleAccentBorders}\n showAccentBorders={isTransparentTheme && !!displaySettings}\n tokens={tokens}\n />\n ) : (\n <>\n {/* Theme Selector */}\n {showThemeSelector && !showModeOnly && (\n <ThemeSelector\n currentTheme={theme}\n onSelect={handleThemeChange}\n tokens={tokens}\n />\n )}\n\n {/* Accent Borders Toggle (only for transparent themes) */}\n {!showModeOnly && isTransparentTheme && displaySettings && (\n <AccentBordersToggle\n enabled={displaySettings.accentBorders}\n onToggle={displaySettings.toggleAccentBorders}\n tokens={tokens}\n />\n )}\n\n {/* Color Picker (only for transparent themes) */}\n {showColorPicker &&\n !showModeOnly &&\n isTransparentTheme &&\n displaySettings && (\n <ColorPickerPanel\n accentColor={displaySettings.accentColor}\n glassTint={displaySettings.glassTint}\n colorTarget={displaySettings.colorTarget}\n onAccentChange={displaySettings.setAccentColor}\n onGlassTintChange={displaySettings.setGlassTint}\n onTargetChange={displaySettings.setColorTarget}\n onColorSelect={displaySettings.setColor}\n compact\n />\n )}\n\n {/* Dark/Light Mode Toggle */}\n <ModeToggle\n mode={mode}\n onToggle={handleModeToggle}\n tokens={tokens}\n />\n </>\n )}\n </div>\n )}\n\n {/* Compact Mode Toggle */}\n {showCompactToggle && (\n <CompactToggle\n isCompact={compactMode}\n onToggle={handleCompactToggle}\n tokens={tokens}\n />\n )}\n </div>\n </header>\n );\n});\n\nexport default AppBar;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AppBar.js","names":[],"sources":["../../../../src/react/core/navigation/AppBar.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - AppBar Component\r\n *\r\n * Enterprise-grade application bar with integrated theme controls,\r\n * compact mode toggle, and display settings management.\r\n *\r\n * Features:\r\n * - Customizable branding (logo, name, domain, version)\r\n * - Dark/light mode toggle\r\n * - Theme variant selector\r\n * - Color picker (accent + glass tint)\r\n * - Compact mode toggle (affects all cards globally)\r\n * - Integrates with DisplaySettingsProvider\r\n * - Responsive design\r\n * - AstroUXDS compliant\r\n *\r\n * @example\r\n * ```tsx\r\n * import { AppBar, ThemeProvider, DisplaySettingsProvider } from '@zendir/ui';\r\n *\r\n * <ThemeProvider>\r\n * <DisplaySettingsProvider>\r\n * <AppBar\r\n * appName=\"Mission Control\"\r\n * appDomain=\"NASA\"\r\n * appVersion=\"1.0.0\"\r\n * showThemeControls\r\n * showCompactToggle\r\n * />\r\n * <App />\r\n * </DisplaySettingsProvider>\r\n * </ThemeProvider>\r\n * ```\r\n */\r\n\r\nimport React, {\r\n memo,\r\n useMemo,\r\n useState,\r\n useRef,\r\n useEffect,\r\n type ReactNode,\r\n} from \"react\";\r\nimport { useTheme, type ThemeVariant, type ThemeMode } from \"../../theme\";\r\nimport { useDisplaySettingsOptional } from \"../../context/DisplaySettingsContext\";\r\nimport { classNames, safeAccentText } from \"../../utils\";\r\nimport { AstroIcon } from \"../display/AstroIcon\";\r\nimport { ColorPickerPanel } from \"../widgets/ColorPickerPanel\";\r\nimport { Tooltip } from \"../overlays/Tooltip\";\r\nimport { useBreakpoint } from \"../layout/useBreakpoint\";\r\n\r\n// =============================================================================\r\n// Types\r\n// =============================================================================\r\n\r\nexport interface AppBarBranding {\r\n /** Logo image URL (takes precedence over text) */\r\n logoUrl?: string;\r\n /** Logo as React node (takes precedence over logoUrl) */\r\n logo?: ReactNode;\r\n /** Logo alt text for accessibility */\r\n logoAlt?: string;\r\n /** Logo height in pixels (default: 28) */\r\n logoHeight?: number;\r\n /** Link URL when clicking on branding */\r\n href?: string;\r\n}\r\n\r\nexport interface AppBarProps {\r\n /** Application name */\r\n appName?: string;\r\n /** Application domain/organization (shown above app name) */\r\n appDomain?: string;\r\n /** Application version (shown smaller) */\r\n appVersion?: string;\r\n /** Logo/branding configuration */\r\n branding?: AppBarBranding;\r\n\r\n // Control visibility\r\n /** Show theme controls (mode toggle, theme selector, color picker) */\r\n showThemeControls?: boolean;\r\n /** Show compact mode toggle */\r\n showCompactToggle?: boolean;\r\n /** Show color picker (only visible for transparent themes) */\r\n showColorPicker?: boolean;\r\n /** Show theme variant selector */\r\n showThemeSelector?: boolean;\r\n /** Show only mode toggle (hide other theme controls) */\r\n showModeOnly?: boolean;\r\n /** Use compact dropdown for theme controls instead of buttons */\r\n compactThemeControls?: boolean;\r\n\r\n // Default values (for when controls are hidden)\r\n /** Default theme to apply if not already set */\r\n defaultTheme?: ThemeVariant;\r\n /** Default mode to apply if not already set */\r\n defaultMode?: ThemeMode;\r\n /** Default compact mode */\r\n defaultCompactMode?: boolean;\r\n\r\n // Slots\r\n /** Left slot content (after branding, or only content when showBranding is false) */\r\n leftSlot?: ReactNode;\r\n /** Center slot content */\r\n centerSlot?: ReactNode;\r\n /** Right slot content (before theme controls) */\r\n rightSlot?: ReactNode;\r\n /** Optional title shown above right slot (e.g. \"Data\" for metrics/refresh section) */\r\n rightSectionTitle?: string;\r\n\r\n // Layout (operator / mission-control style)\r\n /** Show branding block (app name, logo). Set false for control-only bars. */\r\n showBranding?: boolean;\r\n /** Let center slot grow to fill space and stay centered (e.g. simulation controls). */\r\n centerGrow?: boolean;\r\n /** Bar variant: default (52px) or dense (44px min height, tighter padding/gap). */\r\n variant?: \"default\" | \"dense\";\r\n\r\n // Callbacks\r\n /** Callback when theme changes */\r\n onThemeChange?: (theme: ThemeVariant) => void;\r\n /** Callback when mode changes */\r\n onModeChange?: (mode: ThemeMode) => void;\r\n /** Callback when compact mode changes */\r\n onCompactModeChange?: (compact: boolean) => void;\r\n\r\n // Styling\r\n /** Custom className */\r\n className?: string;\r\n /** Custom height (default: 52) */\r\n height?: number;\r\n /** Sticky positioning */\r\n sticky?: boolean;\r\n}\r\n\r\n// =============================================================================\r\n// Theme Variants for Selector\r\n// =============================================================================\r\n\r\nconst THEME_VARIANTS: { key: ThemeVariant; label: string; tooltip: string }[] =\r\n [\r\n {\r\n key: \"hybrid\",\r\n label: \"Zen (Hybrid)\",\r\n tooltip: \"Default theme - Astro status colors with purple accents\",\r\n },\r\n {\r\n key: \"purple-hue\",\r\n label: \"Zen (Purple Hue)\",\r\n tooltip: \"Purple accent theme - vibrant purple tones\",\r\n },\r\n {\r\n key: \"astro\",\r\n label: \"Astro\",\r\n tooltip: \"Astro UX Design System theme - dark blue tones\",\r\n },\r\n {\r\n key: \"transparent\",\r\n label: \"Glass\",\r\n tooltip: \"Glassmorphism theme - transparent with blur effects\",\r\n },\r\n {\r\n key: \"transparent-bold\",\r\n label: \"Bold\",\r\n tooltip: \"Bold glass theme - stronger transparency effects\",\r\n },\r\n {\r\n key: \"transparent-minimal\",\r\n label: \"Minimal\",\r\n tooltip: \"Minimal glass theme - ultra-subtle borders, clean surfaces\",\r\n },\r\n ];\r\n\r\n// =============================================================================\r\n// Mode Toggle Component\r\n// =============================================================================\r\n\r\ninterface ModeToggleProps {\r\n mode: ThemeMode;\r\n onToggle: () => void;\r\n tokens: any;\r\n}\r\n\r\nconst ModeToggle = memo(function ModeToggle({\r\n mode,\r\n onToggle,\r\n tokens,\r\n}: ModeToggleProps) {\r\n const isDark = mode === \"dark\";\r\n const tooltipText = isDark ? \"Switch to Light Mode\" : \"Switch to Dark Mode\";\r\n\r\n return (\r\n <Tooltip content={tooltipText} placement=\"bottom\">\r\n <button\r\n onClick={onToggle}\r\n aria-label={tooltipText}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n width: 32,\r\n height: 32,\r\n padding: 0,\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.md,\r\n backgroundColor: \"rgba(255,255,255,0.08)\",\r\n color: tokens.colors.text.primary,\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.15)\";\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.08)\";\r\n }}\r\n >\r\n <AstroIcon\r\n name={isDark ? \"brightness-3\" : \"brightness-high\"}\r\n size={16}\r\n color={tokens.colors.text.primary}\r\n />\r\n </button>\r\n </Tooltip>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// Compact Mode Toggle Component\r\n// =============================================================================\r\n\r\ninterface CompactToggleProps {\r\n isCompact: boolean;\r\n onToggle: () => void;\r\n tokens: any;\r\n}\r\n\r\nconst CompactToggle = memo(function CompactToggle({\r\n isCompact,\r\n onToggle,\r\n tokens,\r\n}: CompactToggleProps) {\r\n const tooltipText = isCompact\r\n ? \"Switch to Expanded View\"\r\n : \"Switch to Compact View\";\r\n\r\n return (\r\n <Tooltip content={tooltipText} placement=\"bottom\">\r\n <button\r\n onClick={onToggle}\r\n aria-label={tooltipText}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n width: 32,\r\n height: 32,\r\n padding: 0,\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.md,\r\n backgroundColor: isCompact\r\n ? `${tokens.colors.accent.primary}40`\r\n : \"rgba(255,255,255,0.08)\",\r\n color: isCompact\r\n ? tokens.colors.accent.secondary\r\n : tokens.colors.text.primary,\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = isCompact\r\n ? `${tokens.colors.accent.primary}59`\r\n : \"rgba(255,255,255,0.15)\";\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = isCompact\r\n ? `${tokens.colors.accent.primary}40`\r\n : \"rgba(255,255,255,0.08)\";\r\n }}\r\n >\r\n <AstroIcon\r\n name={isCompact ? \"view-comfy\" : \"view-module\"}\r\n size={16}\r\n color={\r\n isCompact\r\n ? tokens.colors.accent.secondary\r\n : tokens.colors.text.primary\r\n }\r\n />\r\n </button>\r\n </Tooltip>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// Theme Selector Component\r\n// =============================================================================\r\n\r\ninterface ThemeSelectorProps {\r\n currentTheme: ThemeVariant;\r\n onSelect: (theme: ThemeVariant) => void;\r\n tokens: any;\r\n}\r\n\r\nconst ThemeSelector = memo(function ThemeSelector({\r\n currentTheme,\r\n onSelect,\r\n tokens,\r\n}: ThemeSelectorProps) {\r\n // WCAG AA: compute a safe background for selected theme buttons (white text)\r\n const safeAccentBg = useMemo(() => {\r\n const hex = tokens.colors.accent.primary.replace(\"#\", \"\");\r\n if (hex.length < 6) return tokens.colors.accent.primary;\r\n const toLinear = (c: number) =>\r\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\r\n const r = parseInt(hex.slice(0, 2), 16) / 255;\r\n const g = parseInt(hex.slice(2, 4), 16) / 255;\r\n const b = parseInt(hex.slice(4, 6), 16) / 255;\r\n const L =\r\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\r\n if (1.05 / (L + 0.05) >= 4.5) return tokens.colors.accent.primary;\r\n const factor = 0.88;\r\n const dr = Math.min(255, Math.round(r * 255 * factor));\r\n const dg = Math.min(255, Math.round(g * 255 * factor));\r\n const db = Math.min(255, Math.round(b * 255 * factor));\r\n return `#${dr.toString(16).padStart(2, \"0\")}${dg.toString(16).padStart(2, \"0\")}${db.toString(16).padStart(2, \"0\")}`;\r\n }, [tokens.colors.accent.primary]);\r\n\r\n // Group themes for better organization\r\n const coreThemes = THEME_VARIANTS.filter(\r\n (t) => !t.key.startsWith(\"transparent\"),\r\n );\r\n const glassThemes = THEME_VARIANTS.filter((t) =>\r\n t.key.startsWith(\"transparent\"),\r\n );\r\n\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 4,\r\n padding: 2,\r\n backgroundColor: \"rgba(255,255,255,0.05)\",\r\n borderRadius: tokens.borderRadius.md,\r\n }}\r\n role=\"group\"\r\n aria-label=\"Theme selector\"\r\n >\r\n {/* Core themes */}\r\n {coreThemes.map(({ key, label, tooltip }) => (\r\n <Tooltip key={key} content={tooltip} placement=\"bottom\">\r\n <button\r\n onClick={() => onSelect(key)}\r\n aria-label={`Select ${label} theme`}\r\n style={{\r\n padding: \"4px 10px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor:\r\n currentTheme === key ? safeAccentBg : \"transparent\",\r\n color:\r\n currentTheme === key ? \"#ffffff\" : tokens.colors.text.secondary,\r\n fontSize: \"0.6875rem\", // 11px in rem\r\n fontWeight: currentTheme === key ? 500 : 400, // AstroUXDS: 500 (medium) not 600\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (currentTheme !== key) {\r\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.1)\";\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n currentTheme === key ? safeAccentBg : \"transparent\";\r\n }}\r\n >\r\n {label}\r\n </button>\r\n </Tooltip>\r\n ))}\r\n\r\n {/* Separator */}\r\n <div\r\n style={{\r\n width: 1,\r\n height: 16,\r\n backgroundColor: \"rgba(255,255,255,0.15)\",\r\n margin: \"0 2px\",\r\n }}\r\n />\r\n\r\n {/* Glass themes */}\r\n {glassThemes.map(({ key, label, tooltip }) => (\r\n <Tooltip key={key} content={tooltip} placement=\"bottom\">\r\n <button\r\n onClick={() => onSelect(key)}\r\n aria-label={`Select ${label} theme`}\r\n style={{\r\n padding: \"4px 10px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor:\r\n currentTheme === key ? safeAccentBg : \"transparent\",\r\n color:\r\n currentTheme === key ? \"#ffffff\" : tokens.colors.text.secondary,\r\n fontSize: \"0.6875rem\", // 11px in rem\r\n fontWeight: currentTheme === key ? 500 : 400, // AstroUXDS: 500 (medium) not 600\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (currentTheme !== key) {\r\n e.currentTarget.style.backgroundColor = \"rgba(255,255,255,0.1)\";\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n currentTheme === key ? safeAccentBg : \"transparent\";\r\n }}\r\n >\r\n {label}\r\n </button>\r\n </Tooltip>\r\n ))}\r\n </div>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// Accent Borders Toggle Component\r\n// =============================================================================\r\n\r\ninterface AccentBordersToggleProps {\r\n enabled: boolean;\r\n onToggle: () => void;\r\n tokens: any;\r\n}\r\n\r\nconst AccentBordersToggle = memo(function AccentBordersToggle({\r\n enabled,\r\n onToggle,\r\n tokens,\r\n}: AccentBordersToggleProps) {\r\n return (\r\n <Tooltip\r\n content={\r\n enabled\r\n ? \"Accent borders enabled - Click to disable\"\r\n : \"Accent borders disabled - Click to enable\"\r\n }\r\n placement=\"bottom\"\r\n >\r\n <button\r\n onClick={onToggle}\r\n aria-label={\r\n enabled ? \"Disable accent borders\" : \"Enable accent borders\"\r\n }\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n gap: 4,\r\n padding: \"4px 8px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor: enabled\r\n ? `${tokens.colors.accent.primary}30`\r\n : \"rgba(255,255,255,0.05)\",\r\n color: enabled\r\n ? safeAccentText(tokens.colors.accent.primary)\r\n : tokens.colors.text.tertiary,\r\n fontSize: \"0.625rem\", // 10px in rem\r\n fontWeight: 500,\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n whiteSpace: \"nowrap\",\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = enabled\r\n ? `${tokens.colors.accent.primary}40`\r\n : \"rgba(255,255,255,0.1)\";\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = enabled\r\n ? `${tokens.colors.accent.primary}30`\r\n : \"rgba(255,255,255,0.05)\";\r\n }}\r\n >\r\n <span\r\n style={{\r\n width: 8,\r\n height: 8,\r\n borderRadius: 2,\r\n border: `2px solid ${enabled ? tokens.colors.accent.primary : tokens.colors.text.tertiary}`,\r\n backgroundColor: \"transparent\",\r\n }}\r\n />\r\n <span>Borders</span>\r\n </button>\r\n </Tooltip>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// Theme Controls Dropdown (Compact)\r\n// =============================================================================\r\n\r\ninterface ThemeControlsDropdownProps {\r\n currentTheme: ThemeVariant;\r\n mode: ThemeMode;\r\n onThemeSelect: (theme: ThemeVariant) => void;\r\n onModeToggle: () => void;\r\n accentBordersEnabled?: boolean;\r\n onAccentBordersToggle?: () => void;\r\n showAccentBorders?: boolean;\r\n tokens: any;\r\n}\r\n\r\nconst ThemeControlsDropdown = memo(function ThemeControlsDropdown({\r\n currentTheme,\r\n mode,\r\n onThemeSelect,\r\n onModeToggle,\r\n accentBordersEnabled = true,\r\n onAccentBordersToggle,\r\n showAccentBorders = false,\r\n tokens,\r\n}: ThemeControlsDropdownProps) {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const dropdownRef = useRef<HTMLDivElement>(null);\r\n\r\n // Close on click outside\r\n useEffect(() => {\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (\r\n dropdownRef.current &&\r\n !dropdownRef.current.contains(event.target as Node)\r\n ) {\r\n setIsOpen(false);\r\n }\r\n };\r\n\r\n if (isOpen) {\r\n document.addEventListener(\"mousedown\", handleClickOutside);\r\n return () =>\r\n document.removeEventListener(\"mousedown\", handleClickOutside);\r\n }\r\n }, [isOpen]);\r\n\r\n // Get current theme label\r\n const currentLabel =\r\n THEME_VARIANTS.find((t) => t.key === currentTheme)?.label || \"Theme\";\r\n\r\n // Group themes\r\n const coreThemes = THEME_VARIANTS.filter(\r\n (t) => !t.key.startsWith(\"transparent\"),\r\n );\r\n const glassThemes = THEME_VARIANTS.filter((t) =>\r\n t.key.startsWith(\"transparent\"),\r\n );\r\n\r\n return (\r\n <div ref={dropdownRef} style={{ position: \"relative\" }}>\r\n {/* Trigger Button */}\r\n <Tooltip content=\"Theme settings\" placement=\"bottom\">\r\n <button\r\n onClick={() => setIsOpen(!isOpen)}\r\n aria-label=\"Theme settings\"\r\n aria-expanded={isOpen}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 6,\r\n padding: \"6px 10px\",\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n borderRadius: tokens.borderRadius.md,\r\n backgroundColor: isOpen\r\n ? tokens.colors.background.elevated\r\n : \"transparent\",\r\n color: tokens.colors.text.secondary,\r\n fontSize: \"0.6875rem\", // 11px in rem\r\n fontWeight: 500,\r\n cursor: \"pointer\",\r\n transition: \"all 0.15s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (!isOpen) {\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.elevated;\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n if (!isOpen) {\r\n e.currentTarget.style.backgroundColor = \"transparent\";\r\n }\r\n }}\r\n >\r\n <AstroIcon\r\n name=\"settings\"\r\n size={14}\r\n color={tokens.colors.text.secondary}\r\n />\r\n <span>{currentLabel}</span>\r\n <AstroIcon\r\n name={isOpen ? \"arrow-up\" : \"arrow-down\"}\r\n size={10}\r\n color={tokens.colors.text.tertiary}\r\n />\r\n </button>\r\n </Tooltip>\r\n\r\n {/* Dropdown Panel */}\r\n {isOpen && (\r\n <div\r\n style={{\r\n position: \"absolute\",\r\n top: \"100%\",\r\n right: 0,\r\n marginTop: 4,\r\n minWidth: 220,\r\n padding: tokens.spacing.sm,\r\n backgroundColor: tokens.colors.background.surface,\r\n border: `1px solid ${tokens.colors.border.muted}`,\r\n borderRadius: tokens.borderRadius.lg,\r\n boxShadow: \"0 8px 32px rgba(0,0,0,0.3)\",\r\n zIndex: 1000,\r\n }}\r\n >\r\n {/* Theme Section */}\r\n <div style={{ marginBottom: tokens.spacing.sm }}>\r\n <div\r\n style={{\r\n fontSize: \"0.625rem\", // 10px in rem\r\n color: tokens.colors.text.muted,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.05em\",\r\n marginBottom: 8,\r\n paddingLeft: 4,\r\n }}\r\n >\r\n Theme\r\n </div>\r\n\r\n {/* Core Themes */}\r\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\r\n {coreThemes.map(({ key, label }) => (\r\n <button\r\n key={key}\r\n onClick={() => {\r\n onThemeSelect(key);\r\n setIsOpen(false);\r\n }}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 8,\r\n padding: \"8px 12px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor:\r\n currentTheme === key\r\n ? `${tokens.colors.accent.primary}20`\r\n : \"transparent\",\r\n color:\r\n currentTheme === key\r\n ? tokens.colors.accent.primary\r\n : tokens.colors.text.primary,\r\n fontSize: \"0.75rem\", // 12px in rem\r\n fontWeight: currentTheme === key ? 600 : 400,\r\n cursor: \"pointer\",\r\n textAlign: \"left\",\r\n transition: \"all 0.1s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (currentTheme !== key) {\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.elevated;\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n currentTheme === key\r\n ? `${tokens.colors.accent.primary}20`\r\n : \"transparent\";\r\n }}\r\n >\r\n {currentTheme === key && (\r\n <AstroIcon\r\n name=\"check\"\r\n size={12}\r\n color={tokens.colors.accent.primary}\r\n />\r\n )}\r\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>\r\n {label}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n\r\n {/* Separator */}\r\n <div\r\n style={{\r\n height: 1,\r\n backgroundColor: tokens.colors.border.muted,\r\n margin: `${tokens.spacing.xs} 0`,\r\n }}\r\n />\r\n\r\n {/* Glass Themes */}\r\n <div\r\n style={{\r\n fontSize: \"0.625rem\", // 10px in rem\r\n color: tokens.colors.text.muted,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.05em\",\r\n marginBottom: 6,\r\n paddingLeft: 4,\r\n }}\r\n >\r\n Glass\r\n </div>\r\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\r\n {glassThemes.map(({ key, label }) => (\r\n <button\r\n key={key}\r\n onClick={() => {\r\n onThemeSelect(key);\r\n setIsOpen(false);\r\n }}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: 8,\r\n padding: \"8px 12px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor:\r\n currentTheme === key\r\n ? `${tokens.colors.accent.primary}20`\r\n : \"transparent\",\r\n color:\r\n currentTheme === key\r\n ? tokens.colors.accent.primary\r\n : tokens.colors.text.primary,\r\n fontSize: \"0.75rem\", // 12px in rem\r\n fontWeight: currentTheme === key ? 600 : 400,\r\n cursor: \"pointer\",\r\n textAlign: \"left\",\r\n transition: \"all 0.1s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n if (currentTheme !== key) {\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.elevated;\r\n }\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n currentTheme === key\r\n ? `${tokens.colors.accent.primary}20`\r\n : \"transparent\";\r\n }}\r\n >\r\n {currentTheme === key && (\r\n <AstroIcon\r\n name=\"check\"\r\n size={12}\r\n color={tokens.colors.accent.primary}\r\n />\r\n )}\r\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>\r\n {label}\r\n </span>\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n\r\n {/* Separator */}\r\n <div\r\n style={{\r\n height: 1,\r\n backgroundColor: tokens.colors.border.muted,\r\n margin: `${tokens.spacing.sm} 0`,\r\n }}\r\n />\r\n\r\n {/* Options Section */}\r\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 4 }}>\r\n {/* Mode Toggle */}\r\n <button\r\n onClick={() => {\r\n onModeToggle();\r\n }}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: \"8px 12px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor: \"transparent\",\r\n color: tokens.colors.text.primary,\r\n fontSize: \"0.75rem\", // 12px in rem\r\n cursor: \"pointer\",\r\n transition: \"all 0.1s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.elevated;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = \"transparent\";\r\n }}\r\n >\r\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\r\n <AstroIcon\r\n name={mode === \"dark\" ? \"brightness-high\" : \"brightness-low\"}\r\n size={14}\r\n color={tokens.colors.text.secondary}\r\n />\r\n {mode === \"dark\" ? \"Dark Mode\" : \"Light Mode\"}\r\n </span>\r\n <div\r\n style={{\r\n width: 32,\r\n height: 18,\r\n borderRadius: 9,\r\n backgroundColor:\r\n mode === \"dark\"\r\n ? tokens.colors.accent.primary\r\n : tokens.colors.border.default,\r\n padding: 2,\r\n transition: \"all 0.15s ease\",\r\n }}\r\n >\r\n <div\r\n style={{\r\n width: 14,\r\n height: 14,\r\n borderRadius: \"50%\",\r\n backgroundColor: \"#fff\",\r\n transition: \"all 0.15s ease\",\r\n transform:\r\n mode === \"dark\" ? \"translateX(14px)\" : \"translateX(0)\",\r\n }}\r\n />\r\n </div>\r\n </button>\r\n\r\n {/* Accent Borders (only for glass themes) */}\r\n {showAccentBorders && onAccentBordersToggle && (\r\n <button\r\n onClick={onAccentBordersToggle}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n padding: \"8px 12px\",\r\n border: \"none\",\r\n borderRadius: tokens.borderRadius.sm,\r\n backgroundColor: \"transparent\",\r\n color: tokens.colors.text.primary,\r\n fontSize: \"0.75rem\", // 12px in rem\r\n cursor: \"pointer\",\r\n transition: \"all 0.1s ease\",\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor =\r\n tokens.colors.background.elevated;\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = \"transparent\";\r\n }}\r\n >\r\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\r\n <span\r\n style={{\r\n width: 14,\r\n height: 14,\r\n borderRadius: 3,\r\n border: `2px solid ${tokens.colors.text.secondary}`,\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n }}\r\n >\r\n {accentBordersEnabled && (\r\n <AstroIcon\r\n name=\"check\"\r\n size={10}\r\n color={tokens.colors.text.secondary}\r\n />\r\n )}\r\n </span>\r\n Accent Borders\r\n </span>\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// AppBar Component\r\n// =============================================================================\r\n\r\n// =============================================================================\r\n// Section header for right slot (operator-style \"Data\" header)\r\n// =============================================================================\r\n\r\ninterface SectionHeaderProps {\r\n title: string;\r\n tokens: { typography: any; spacing: any; colors: any; borders: any };\r\n}\r\n\r\nconst SectionHeader = memo(function SectionHeader({\r\n title,\r\n tokens,\r\n}: SectionHeaderProps) {\r\n return (\r\n <div style={{ textAlign: \"center\", marginBottom: tokens.spacing.xs }}>\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xxs,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n color:\r\n tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\r\n fontWeight: tokens.typography.fontWeight.bold,\r\n }}\r\n >\r\n {title}\r\n </span>\r\n <div\r\n style={{\r\n width: \"100%\",\r\n height: tokens.borders.width.thin,\r\n background:\r\n tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\r\n opacity: 0.5,\r\n marginTop: tokens.spacing.xs,\r\n }}\r\n />\r\n </div>\r\n );\r\n});\r\n\r\n// =============================================================================\r\n// AppBar Component\r\n// =============================================================================\r\n\r\nexport const AppBar = memo(function AppBar({\r\n appName = \"Zendir\",\r\n appDomain,\r\n appVersion,\r\n branding,\r\n showThemeControls = true,\r\n showCompactToggle = true,\r\n showColorPicker = true,\r\n showThemeSelector = true,\r\n showModeOnly = false,\r\n compactThemeControls = false,\r\n defaultTheme,\r\n defaultMode,\r\n defaultCompactMode,\r\n leftSlot,\r\n centerSlot,\r\n rightSlot,\r\n rightSectionTitle,\r\n showBranding = true,\r\n centerGrow = false,\r\n variant = \"default\",\r\n onThemeChange,\r\n onModeChange,\r\n onCompactModeChange,\r\n className = \"\",\r\n height = 52,\r\n sticky = true,\r\n}: AppBarProps): React.ReactElement {\r\n const { tokens, theme, mode, setTheme, setMode, toggleMode } = useTheme();\r\n const { isMobile } = useBreakpoint();\r\n const displaySettings = useDisplaySettingsOptional();\r\n\r\n const isTransparentTheme =\r\n theme === \"transparent\" ||\r\n theme === \"transparent-bold\" ||\r\n theme === \"transparent-minimal\";\r\n\r\n // Get compact mode from context or default\r\n const compactMode =\r\n displaySettings?.compactMode ?? defaultCompactMode ?? false;\r\n\r\n // Apply defaults on first render if specified\r\n React.useEffect(() => {\r\n if (defaultTheme && theme !== defaultTheme) {\r\n setTheme(defaultTheme);\r\n onThemeChange?.(defaultTheme);\r\n }\r\n if (defaultMode && mode !== defaultMode) {\r\n setMode(defaultMode);\r\n onModeChange?.(defaultMode);\r\n }\r\n // Only run on mount\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n\r\n // Handle mode toggle\r\n const handleModeToggle = () => {\r\n toggleMode();\r\n onModeChange?.(mode === \"dark\" ? \"light\" : \"dark\");\r\n };\r\n\r\n // Handle theme change\r\n const handleThemeChange = (newTheme: ThemeVariant) => {\r\n setTheme(newTheme);\r\n onThemeChange?.(newTheme);\r\n };\r\n\r\n // Handle compact mode toggle\r\n const handleCompactToggle = () => {\r\n if (displaySettings) {\r\n displaySettings.toggleCompactMode();\r\n onCompactModeChange?.(!compactMode);\r\n } else {\r\n onCompactModeChange?.(!compactMode);\r\n }\r\n };\r\n\r\n // Variant-driven layout (operator / mission-control style)\r\n const isDense = variant === \"dense\";\r\n const effectiveHeight = height ?? (isDense ? 44 : 52);\r\n const paddingH = isDense\r\n ? isMobile\r\n ? tokens.spacing.xs\r\n : tokens.spacing.sm\r\n : isMobile\r\n ? tokens.spacing.md\r\n : tokens.spacing.lg;\r\n const paddingV = isDense ? tokens.spacing.xs : 0;\r\n const gap = isDense\r\n ? isMobile\r\n ? tokens.spacing.sm\r\n : tokens.spacing.md\r\n : tokens.spacing.sm;\r\n const minHeight = isDense && isMobile ? 44 : undefined;\r\n\r\n // Render branding section\r\n const renderBranding = () => {\r\n // Custom logo node\r\n if (branding?.logo) {\r\n const content = branding.logo;\r\n if (branding.href) {\r\n return (\r\n <a\r\n href={branding.href}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n textDecoration: \"none\",\r\n }}\r\n >\r\n {content}\r\n </a>\r\n );\r\n }\r\n return <>{content}</>;\r\n }\r\n\r\n // Logo image URL\r\n if (branding?.logoUrl) {\r\n const img = (\r\n <img\r\n src={branding.logoUrl}\r\n alt={branding.logoAlt || appName}\r\n style={{\r\n height: branding.logoHeight || 28,\r\n width: \"auto\",\r\n objectFit: \"contain\",\r\n }}\r\n />\r\n );\r\n\r\n if (branding.href) {\r\n return (\r\n <a\r\n href={branding.href}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n textDecoration: \"none\",\r\n }}\r\n >\r\n {img}\r\n </a>\r\n );\r\n }\r\n return img;\r\n }\r\n\r\n // Text branding\r\n return (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"baseline\",\r\n gap: tokens.spacing.sm,\r\n }}\r\n >\r\n {appDomain && (\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.sm,\r\n fontWeight: 400,\r\n color: tokens.colors.text.secondary,\r\n textTransform: \"uppercase\",\r\n letterSpacing: \"0.05em\",\r\n }}\r\n >\r\n {appDomain}\r\n </span>\r\n )}\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.lg,\r\n fontWeight: 500, // AstroUXDS medium for app title\r\n color: tokens.colors.text.primary,\r\n }}\r\n >\r\n {appName}\r\n </span>\r\n {appVersion && (\r\n <span\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n color: tokens.colors.text.tertiary,\r\n }}\r\n >\r\n v{appVersion.replace(/^v/, \"\")}\r\n </span>\r\n )}\r\n </div>\r\n );\r\n };\r\n\r\n return (\r\n <header\r\n className={classNames(\"zendir-app-bar\", className)}\r\n role=\"banner\"\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n height: effectiveHeight,\r\n padding: paddingV ? `${paddingV} ${paddingH}` : `0 ${paddingH}`,\r\n backgroundColor: isTransparentTheme\r\n ? \"rgba(0,0,0,0.4)\"\r\n : tokens.colors.background.surface,\r\n ...(isTransparentTheme && {\r\n backdropFilter: \"blur(16px)\",\r\n WebkitBackdropFilter: \"blur(16px)\" as const,\r\n }),\r\n borderBottom: tokens.borders.divider,\r\n color: tokens.colors.text.primary,\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n gap,\r\n ...(minHeight && { minHeight }),\r\n ...(sticky && {\r\n position: \"sticky\",\r\n top: 0,\r\n zIndex: 100,\r\n }),\r\n }}\r\n >\r\n {/* Left section: Branding (optional) + leftSlot */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: isDense ? gap : isMobile ? tokens.spacing.md : tokens.spacing.lg,\r\n flex: \"1 1 0\",\r\n minWidth: 0,\r\n }}\r\n >\r\n {showBranding && renderBranding()}\r\n {leftSlot}\r\n </div>\r\n\r\n {/* Center section (optionally grows to fill and center content) */}\r\n {centerSlot && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n flex: centerGrow ? \"1 1 0\" : \"0 0 auto\",\r\n minWidth: 0,\r\n }}\r\n >\r\n {centerSlot}\r\n </div>\r\n )}\r\n\r\n {/* Right section: optional section title + rightSlot + theme controls + compact toggle */}\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-end\",\r\n gap: tokens.spacing.sm,\r\n flex: \"1 1 0\",\r\n minWidth: 0,\r\n }}\r\n >\r\n {rightSectionTitle != null && rightSectionTitle !== \"\" ? (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n alignItems: \"center\",\r\n flexShrink: 0,\r\n }}\r\n >\r\n <SectionHeader title={rightSectionTitle} tokens={tokens} />\r\n {rightSlot}\r\n </div>\r\n ) : (\r\n rightSlot\r\n )}\r\n\r\n {/* Theme Controls Group */}\r\n {showThemeControls && (\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: isMobile ? 6 : 8,\r\n marginLeft: isMobile ? tokens.spacing.xs : tokens.spacing.sm,\r\n minWidth: 0,\r\n }}\r\n >\r\n {/* Compact Dropdown Mode */}\r\n {compactThemeControls ? (\r\n <ThemeControlsDropdown\r\n currentTheme={theme}\r\n mode={mode}\r\n onThemeSelect={handleThemeChange}\r\n onModeToggle={handleModeToggle}\r\n accentBordersEnabled={displaySettings?.accentBorders ?? true}\r\n onAccentBordersToggle={displaySettings?.toggleAccentBorders}\r\n showAccentBorders={isTransparentTheme && !!displaySettings}\r\n tokens={tokens}\r\n />\r\n ) : (\r\n <>\r\n {/* Theme Selector */}\r\n {showThemeSelector && !showModeOnly && (\r\n <ThemeSelector\r\n currentTheme={theme}\r\n onSelect={handleThemeChange}\r\n tokens={tokens}\r\n />\r\n )}\r\n\r\n {/* Accent Borders Toggle (only for transparent themes) */}\r\n {!showModeOnly && isTransparentTheme && displaySettings && (\r\n <AccentBordersToggle\r\n enabled={displaySettings.accentBorders}\r\n onToggle={displaySettings.toggleAccentBorders}\r\n tokens={tokens}\r\n />\r\n )}\r\n\r\n {/* Color Picker (only for transparent themes) */}\r\n {showColorPicker &&\r\n !showModeOnly &&\r\n isTransparentTheme &&\r\n displaySettings && (\r\n <ColorPickerPanel\r\n accentColor={displaySettings.accentColor}\r\n glassTint={displaySettings.glassTint}\r\n colorTarget={displaySettings.colorTarget}\r\n onAccentChange={displaySettings.setAccentColor}\r\n onGlassTintChange={displaySettings.setGlassTint}\r\n onTargetChange={displaySettings.setColorTarget}\r\n onColorSelect={displaySettings.setColor}\r\n compact\r\n />\r\n )}\r\n\r\n {/* Dark/Light Mode Toggle */}\r\n <ModeToggle\r\n mode={mode}\r\n onToggle={handleModeToggle}\r\n tokens={tokens}\r\n />\r\n </>\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Compact Mode Toggle */}\r\n {showCompactToggle && (\r\n <CompactToggle\r\n isCompact={compactMode}\r\n onToggle={handleCompactToggle}\r\n tokens={tokens}\r\n />\r\n )}\r\n </div>\r\n </header>\r\n );\r\n});\r\n\r\nexport default AppBar;\r\n"],"mappings":"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"}