@zendir/ui 0.2.21 → 0.3.0
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.
- package/CHANGELOG.md +183 -1
- package/README.md +70 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +51 -42
- package/dist/index.js.map +1 -1
- package/dist/react/3d/CesiumCaptureSource.d.ts +1 -1
- package/dist/react/3d/CesiumCaptureSource.js +1 -1
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.js +1253 -0
- package/dist/react/3d/ZenSpace3D.js.map +1 -0
- package/dist/react/3d/ZenSpace3DCesium.js +579 -0
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
- package/dist/react/3d/ZenSpace3DTypes.d.ts +28 -1
- package/dist/react/3d/ZenSpace3DUtils.d.ts +17 -173
- package/dist/react/3d/ZenSpace3DUtils.js +20 -1
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/index.d.ts +6 -12
- package/dist/react/3d/threeLoader.js +18 -0
- package/dist/react/3d/threeLoader.js.map +1 -0
- package/dist/react/astro/MonitoringIcon.js +1 -1
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/SimulationControls.js +2 -2
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/UnifiedTimeline.js +4 -4
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/charts/GroundTrackMap.d.ts +2 -15
- package/dist/react/charts/GroundTrackMap.js +1 -1
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/unified/AstroChart.js +34 -13
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/chatgpt/AppCard.d.ts +0 -4
- package/dist/react/chatgpt/index.d.ts +0 -19
- package/dist/react/context/SpatialSelectionContext.d.ts +40 -0
- package/dist/react/context/SpatialSelectionContext.js +10 -0
- package/dist/react/context/SpatialSelectionContext.js.map +1 -0
- package/dist/react/context/index.d.ts +2 -0
- package/dist/react/core/{DataTable.d.ts → data/DataTable.d.ts} +1 -1
- package/dist/react/core/{DataTable.js → data/DataTable.js} +4 -4
- package/dist/react/core/data/DataTable.js.map +1 -0
- package/dist/react/core/{DataValue.d.ts → data/DataValue.d.ts} +2 -2
- package/dist/react/core/{DataValue.js → data/DataValue.js} +2 -2
- package/dist/react/core/data/DataValue.js.map +1 -0
- package/dist/react/core/{propertyConfig.d.ts → data/propertyConfig.d.ts} +2 -2
- package/dist/react/core/data/propertyConfig.js.map +1 -0
- package/dist/react/core/{AstroIcon.js → display/AstroIcon.js} +1 -1
- package/dist/react/core/display/AstroIcon.js.map +1 -0
- package/dist/react/core/{Badge.d.ts → display/Badge.d.ts} +1 -1
- package/dist/react/core/{Badge.js → display/Badge.js} +2 -2
- package/dist/react/core/display/Badge.js.map +1 -0
- package/dist/react/core/{CardHeader.d.ts → display/CardHeader.d.ts} +1 -1
- package/dist/react/core/{CardHeader.js → display/CardHeader.js} +2 -2
- package/dist/react/core/display/CardHeader.js.map +1 -0
- package/dist/react/core/{Container.d.ts → display/Container.d.ts} +1 -1
- package/dist/react/core/{Container.js → display/Container.js} +3 -3
- package/dist/react/core/display/Container.js.map +1 -0
- package/dist/react/core/{CopyButton.js → display/CopyButton.js} +1 -1
- package/dist/react/core/display/CopyButton.js.map +1 -0
- package/dist/react/core/{GlassCard.d.ts → display/GlassCard.d.ts} +1 -1
- package/dist/react/core/{GlassCard.js → display/GlassCard.js} +2 -2
- package/dist/react/core/display/GlassCard.js.map +1 -0
- package/dist/react/core/{HeaderIconWithStatus.d.ts → display/HeaderIconWithStatus.d.ts} +1 -1
- package/dist/react/core/{HeaderIconWithStatus.js → display/HeaderIconWithStatus.js} +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -0
- package/dist/react/core/{Icon.d.ts → display/Icon.d.ts} +1 -1
- package/dist/react/core/{Icon.js → display/Icon.js} +1 -1
- package/dist/react/core/display/Icon.js.map +1 -0
- package/dist/react/core/{Typography.d.ts → display/Typography.d.ts} +13 -4
- package/dist/react/core/{Typography.js → display/Typography.js} +1 -1
- package/dist/react/core/display/Typography.js.map +1 -0
- package/dist/react/core/{ConfirmDialog.js → feedback/ConfirmDialog.js} +1 -1
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -0
- package/dist/react/core/{Dialog.js → feedback/Dialog.js} +2 -2
- package/dist/react/core/feedback/Dialog.js.map +1 -0
- package/dist/react/core/{Toast.js → feedback/Toast.js} +3 -3
- package/dist/react/core/feedback/Toast.js.map +1 -0
- package/dist/react/core/index.d.ts +85 -85
- package/dist/react/core/{Button.js → inputs/Button.js} +2 -2
- package/dist/react/core/inputs/Button.js.map +1 -0
- package/dist/react/core/{Checkbox.js → inputs/Checkbox.js} +2 -2
- package/dist/react/core/inputs/Checkbox.js.map +1 -0
- package/dist/react/core/{Input.d.ts → inputs/Input.d.ts} +1 -1
- package/dist/react/core/{Input.js → inputs/Input.js} +3 -3
- package/dist/react/core/inputs/Input.js.map +1 -0
- package/dist/react/core/{LimitsBar.js → inputs/LimitsBar.js} +1 -1
- package/dist/react/core/inputs/LimitsBar.js.map +1 -0
- package/dist/react/core/{NumberInput.d.ts → inputs/NumberInput.d.ts} +2 -2
- package/dist/react/core/{NumberInput.js → inputs/NumberInput.js} +3 -3
- package/dist/react/core/inputs/NumberInput.js.map +1 -0
- package/dist/react/core/{PinInput.js → inputs/PinInput.js} +2 -2
- package/dist/react/core/inputs/PinInput.js.map +1 -0
- package/dist/react/core/{Select.js → inputs/Select.js} +3 -3
- package/dist/react/core/inputs/Select.js.map +1 -0
- package/dist/react/core/{Toggle.js → inputs/Toggle.js} +2 -2
- package/dist/react/core/inputs/Toggle.js.map +1 -0
- package/dist/react/core/{AppBar.d.ts → navigation/AppBar.d.ts} +1 -1
- package/dist/react/core/{AppBar.js → navigation/AppBar.js} +7 -7
- package/dist/react/core/navigation/AppBar.js.map +1 -0
- package/dist/react/core/{Pagination.js → navigation/Pagination.js} +2 -2
- package/dist/react/core/navigation/Pagination.js.map +1 -0
- package/dist/react/core/{SideNav.d.ts → navigation/SideNav.d.ts} +1 -1
- package/dist/react/core/{SideNav.js → navigation/SideNav.js} +3 -3
- package/dist/react/core/navigation/SideNav.js.map +1 -0
- package/dist/react/core/{Tabs.js → navigation/Tabs.js} +2 -2
- package/dist/react/core/navigation/Tabs.js.map +1 -0
- package/dist/react/core/{Popover.js → overlays/Popover.js} +1 -1
- package/dist/react/core/overlays/Popover.js.map +1 -0
- package/dist/react/core/{SidePanel.js → overlays/SidePanel.js} +3 -3
- package/dist/react/core/overlays/SidePanel.js.map +1 -0
- package/dist/react/core/{Tooltip.js → overlays/Tooltip.js} +2 -2
- package/dist/react/core/overlays/Tooltip.js.map +1 -0
- package/dist/react/core/{ActivityPlanner.js → widgets/ActivityPlanner.js} +1 -1
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -0
- package/dist/react/core/{Capture.js → widgets/Capture.js} +3 -3
- package/dist/react/core/widgets/Capture.js.map +1 -0
- package/dist/react/core/{ChatPanel.d.ts → widgets/ChatPanel.d.ts} +1 -1
- package/dist/react/core/{ChatPanel.js → widgets/ChatPanel.js} +2 -2
- package/dist/react/core/widgets/ChatPanel.js.map +1 -0
- package/dist/react/core/{ColorPickerPanel.d.ts → widgets/ColorPickerPanel.d.ts} +1 -1
- package/dist/react/core/{ColorPickerPanel.js → widgets/ColorPickerPanel.js} +3 -3
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -0
- package/dist/react/core/{CommandBuilder.js → widgets/CommandBuilder.js} +1 -1
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -0
- package/dist/react/core/{ConnectionForm.d.ts → widgets/ConnectionForm.d.ts} +1 -1
- package/dist/react/core/{ConnectionForm.js → widgets/ConnectionForm.js} +2 -2
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -0
- package/dist/react/core/{FileExplorer.js → widgets/FileExplorer.js} +2 -2
- package/dist/react/core/widgets/FileExplorer.js.map +1 -0
- package/dist/react/core/{HexViewer.js → widgets/HexViewer.js} +1 -1
- package/dist/react/core/widgets/HexViewer.js.map +1 -0
- package/dist/react/core/{ImageGallery.d.ts → widgets/ImageGallery.d.ts} +1 -1
- package/dist/react/core/{ImageGallery.js → widgets/ImageGallery.js} +3 -3
- package/dist/react/core/widgets/ImageGallery.js.map +1 -0
- package/dist/react/core/{LogViewer.d.ts → widgets/LogViewer.d.ts} +13 -3
- package/dist/react/core/{LogViewer.js → widgets/LogViewer.js} +28 -8
- package/dist/react/core/widgets/LogViewer.js.map +1 -0
- package/dist/react/core/{MessageStream.d.ts → widgets/MessageStream.d.ts} +2 -2
- package/dist/react/core/{MessageStream.js → widgets/MessageStream.js} +4 -4
- package/dist/react/core/widgets/MessageStream.js.map +1 -0
- package/dist/react/core/{MissionCalendar.js → widgets/MissionCalendar.js} +2 -2
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -0
- package/dist/react/core/{PacketViewer.js → widgets/PacketViewer.js} +1 -1
- package/dist/react/core/widgets/PacketViewer.js.map +1 -0
- package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -0
- package/dist/react/hooks/index.d.ts +9 -11
- package/dist/react/hooks/useAccessWindows.d.ts +15 -19
- package/dist/react/hooks/useGroundTrackHistory.d.ts +34 -0
- package/dist/react/hooks/useSimulationScene.d.ts +141 -0
- package/dist/react/hooks/useSimulationScene.js +401 -0
- package/dist/react/hooks/useSimulationScene.js.map +1 -0
- package/dist/react/hooks/useZendirSession.d.ts +44 -69
- package/dist/react/index.d.ts +7 -3
- package/dist/react/panels/LayerControlPanel.d.ts +54 -0
- package/dist/react/panels/LayerControlPanel.js +184 -0
- package/dist/react/panels/LayerControlPanel.js.map +1 -0
- package/dist/react/panels/ObjectInventoryPanel.d.ts +57 -0
- package/dist/react/panels/ObjectInventoryPanel.js +261 -0
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -0
- package/dist/react/panels/index.d.ts +15 -0
- package/dist/react/theme/ThemeProvider.d.ts +2 -0
- package/dist/react/theme/ThemeProvider.js +50 -72
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/types.d.ts +32 -3
- package/dist/react/types.js.map +1 -1
- package/dist/react.js +51 -42
- package/dist/react.js.map +1 -1
- package/dist/shaders/atmosphere.frag.js +5 -0
- package/dist/shaders/atmosphere.frag.js.map +1 -0
- package/dist/shaders/atmosphere.vert.js +5 -0
- package/dist/shaders/atmosphere.vert.js.map +1 -0
- package/dist/shaders/stars.frag.js +5 -0
- package/dist/shaders/stars.frag.js.map +1 -0
- package/dist/shaders/stars.vert.js +5 -0
- package/dist/shaders/stars.vert.js.map +1 -0
- package/dist/style.css +6 -4
- package/dist/tokens/css-vars.d.ts +91 -0
- package/dist/tokens/css-vars.js +228 -0
- package/dist/tokens/css-vars.js.map +1 -0
- package/dist/tokens/index.d.ts +71 -18
- package/dist/tokens/index.js +206 -97
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/tokens.css +50 -50
- package/package.json +26 -22
- package/sdk-stub.js +10 -5
- package/dist/react/3d/EarthViewer.d.ts +0 -46
- package/dist/react/3d/SolarSystemViewer.d.ts +0 -43
- package/dist/react/chatgpt/ChatGPTCard.d.ts +0 -6
- package/dist/react/core/ActivityPlanner.js.map +0 -1
- package/dist/react/core/AppBar.js.map +0 -1
- package/dist/react/core/AstroIcon.js.map +0 -1
- package/dist/react/core/Badge.js.map +0 -1
- package/dist/react/core/Button.js.map +0 -1
- package/dist/react/core/Capture.js.map +0 -1
- package/dist/react/core/CardHeader.js.map +0 -1
- package/dist/react/core/ChatPanel.js.map +0 -1
- package/dist/react/core/Checkbox.js.map +0 -1
- package/dist/react/core/ColorPickerPanel.js.map +0 -1
- package/dist/react/core/CommandBuilder.js.map +0 -1
- package/dist/react/core/ConfirmDialog.js.map +0 -1
- package/dist/react/core/ConnectionForm.js.map +0 -1
- package/dist/react/core/Container.js.map +0 -1
- package/dist/react/core/CopyButton.js.map +0 -1
- package/dist/react/core/DataTable.js.map +0 -1
- package/dist/react/core/DataValue.js.map +0 -1
- package/dist/react/core/Dialog.js.map +0 -1
- package/dist/react/core/FileExplorer.js.map +0 -1
- package/dist/react/core/GlassCard.js.map +0 -1
- package/dist/react/core/HeaderIconWithStatus.js.map +0 -1
- package/dist/react/core/HexViewer.js.map +0 -1
- package/dist/react/core/Icon.js.map +0 -1
- package/dist/react/core/ImageGallery.js.map +0 -1
- package/dist/react/core/Input.js.map +0 -1
- package/dist/react/core/LimitsBar.js.map +0 -1
- package/dist/react/core/LogViewer.js.map +0 -1
- package/dist/react/core/MessageStream.js.map +0 -1
- package/dist/react/core/MissionCalendar.js.map +0 -1
- package/dist/react/core/NumberInput.js.map +0 -1
- package/dist/react/core/PacketViewer.js.map +0 -1
- package/dist/react/core/Pagination.js.map +0 -1
- package/dist/react/core/PinInput.js.map +0 -1
- package/dist/react/core/Popover.js.map +0 -1
- package/dist/react/core/Select.js.map +0 -1
- package/dist/react/core/SideNav.js.map +0 -1
- package/dist/react/core/SidePanel.js.map +0 -1
- package/dist/react/core/Tabs.js.map +0 -1
- package/dist/react/core/Toast.js.map +0 -1
- package/dist/react/core/Toggle.js.map +0 -1
- package/dist/react/core/Tooltip.js.map +0 -1
- package/dist/react/core/Typography.js.map +0 -1
- package/dist/react/core/capture-placeholder.png.js.map +0 -1
- package/dist/react/core/propertyConfig.js.map +0 -1
- package/dist/react/hooks/useSimulationTime.d.ts +0 -61
- package/dist/react/hooks/useSpacecraftPosition.d.ts +0 -50
- package/dist/react/hooks/useTelemetry.d.ts +0 -55
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- /package/dist/react/core/{propertyConfig.js → data/propertyConfig.js} +0 -0
- /package/dist/react/core/{AstroIcon.d.ts → display/AstroIcon.d.ts} +0 -0
- /package/dist/react/core/{CopyButton.d.ts → display/CopyButton.d.ts} +0 -0
- /package/dist/react/core/{ConfirmDialog.d.ts → feedback/ConfirmDialog.d.ts} +0 -0
- /package/dist/react/core/{Dialog.d.ts → feedback/Dialog.d.ts} +0 -0
- /package/dist/react/core/{Toast.d.ts → feedback/Toast.d.ts} +0 -0
- /package/dist/react/core/{Button.d.ts → inputs/Button.d.ts} +0 -0
- /package/dist/react/core/{Checkbox.d.ts → inputs/Checkbox.d.ts} +0 -0
- /package/dist/react/core/{LimitsBar.d.ts → inputs/LimitsBar.d.ts} +0 -0
- /package/dist/react/core/{PinInput.d.ts → inputs/PinInput.d.ts} +0 -0
- /package/dist/react/core/{Select.d.ts → inputs/Select.d.ts} +0 -0
- /package/dist/react/core/{Toggle.d.ts → inputs/Toggle.d.ts} +0 -0
- /package/dist/react/core/{Pagination.d.ts → navigation/Pagination.d.ts} +0 -0
- /package/dist/react/core/{Tabs.d.ts → navigation/Tabs.d.ts} +0 -0
- /package/dist/react/core/{Popover.d.ts → overlays/Popover.d.ts} +0 -0
- /package/dist/react/core/{SidePanel.d.ts → overlays/SidePanel.d.ts} +0 -0
- /package/dist/react/core/{Tooltip.d.ts → overlays/Tooltip.d.ts} +0 -0
- /package/dist/react/core/{ActivityPlanner.d.ts → widgets/ActivityPlanner.d.ts} +0 -0
- /package/dist/react/core/{Capture.d.ts → widgets/Capture.d.ts} +0 -0
- /package/dist/react/core/{CommandBuilder.d.ts → widgets/CommandBuilder.d.ts} +0 -0
- /package/dist/react/core/{FileExplorer.d.ts → widgets/FileExplorer.d.ts} +0 -0
- /package/dist/react/core/{HexViewer.d.ts → widgets/HexViewer.d.ts} +0 -0
- /package/dist/react/core/{MissionCalendar.d.ts → widgets/MissionCalendar.d.ts} +0 -0
- /package/dist/react/core/{PacketViewer.d.ts → widgets/PacketViewer.d.ts} +0 -0
- /package/dist/react/core/{capture-placeholder.png.js → widgets/capture-placeholder.png.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Input.js","sources":["../../../../src/react/core/inputs/Input.tsx"],"sourcesContent":["/**\n * @zendir/ui - Input Component\n * \n * Text input field following Astro UX Design System with Zendir purple accents.\n * \n * Astro UX Compliance:\n * - Stacked inputs left-justified\n * - Consistent spacing\n * - Help text for validation (not placeholder)\n * - Required/optional indicators\n * - States: default, hover, focus, invalid, disabled\n * \n * Zendir Enhancements:\n * - Purple focus glow\n * - Smooth transitions\n * - Modern glassmorphism effects\n * \n * @example\n * ```tsx\n * <Input label=\"Spacecraft ID\" placeholder=\"Enter ID...\" />\n * <Input label=\"Password\" type=\"password\" />\n * <Input label=\"Search\" icon={<Icon name=\"search\" />} />\n * <Input label=\"Email\" error=\"Invalid email format\" />\n * ```\n */\n\nimport React, { memo, forwardRef, useState, useId } from 'react';\nimport { useTheme } from '../../theme';\nimport { classNames, safeAccentText, type StatusLevel } from '../../utils';\nimport { useBreakpoint } from '../layout/useBreakpoint';\n\nexport type InputSize = 'small' | 'medium' | 'large';\n\n/** Label placement relative to the input field */\nexport type LabelPlacement = 'above' | 'outlined';\n\nexport interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n /** Label text or ReactNode (supports rich content like tooltip icons) */\n label?: React.ReactNode;\n /** Helper text below input */\n helperText?: string;\n /** Error message (shows error state) */\n error?: string;\n /** Size variant */\n size?: InputSize;\n /** Status for styling */\n status?: StatusLevel;\n /** Icon at start of input */\n icon?: React.ReactNode;\n /** Icon at end of input */\n iconEnd?: React.ReactNode;\n /** Full width */\n fullWidth?: boolean;\n /** Required indicator */\n required?: boolean;\n /** Optional indicator (shows \"optional\" text) */\n optional?: boolean;\n /** Custom className */\n className?: string;\n /**\n * Label placement style.\n * - `'outlined'` — label sits on the input border (notched/Material-style). **Default.**\n * - `'above'` — label sits above the input with a gap (classic stack).\n */\n labelPlacement?: LabelPlacement;\n}\n\nexport const Input = memo(forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n label,\n helperText,\n error,\n size = 'medium',\n status,\n icon,\n iconEnd,\n fullWidth = false,\n required,\n optional,\n disabled,\n className = '',\n id: propId,\n style,\n onFocus,\n onBlur,\n labelPlacement = 'outlined',\n type = 'text',\n autoComplete,\n inputMode,\n onPaste: onPasteUser,\n ...rest\n },\n ref\n): React.ReactElement {\n // Mobile: email keyboard when type is email (industry standard).\n const resolvedInputMode = inputMode ?? (type === 'email' ? 'email' : undefined);\n const { tokens, theme } = useTheme();\n const { isMobile } = useBreakpoint();\n const [focused, setFocused] = useState(false);\n const [hovered, setHovered] = useState(false);\n const generatedId = useId();\n const inputId = propId ?? generatedId;\n\n // Trim pasted content for password, email, and username (industry standard: avoid auth/validation failures).\n const shouldTrimOnPaste = type === 'password' || type === 'email' || autoComplete === 'email' || autoComplete === 'username';\n const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {\n if (shouldTrimOnPaste) {\n const pasted = e.clipboardData.getData('text');\n const trimmed = pasted.trim();\n if (trimmed !== pasted) {\n e.preventDefault();\n const input = e.currentTarget;\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n const cur = ((rest as { value?: string }).value ?? input.value) ?? '';\n const newValue = cur.slice(0, start) + trimmed + cur.slice(end);\n rest.onChange?.({ target: { ...input, value: newValue } } as React.ChangeEvent<HTMLInputElement>);\n requestAnimationFrame(() => {\n input.setSelectionRange(start + trimmed.length, start + trimmed.length);\n });\n }\n }\n onPasteUser?.(e);\n };\n\n // Trim on blur for email/username so \" user@example.com \" becomes \"user@example.com\" when leaving the field.\n const shouldTrimOnBlur = type === 'email' || autoComplete === 'email' || autoComplete === 'username';\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n if (shouldTrimOnBlur) {\n const input = e.currentTarget;\n const cur = input.value;\n const trimmed = cur.trim();\n if (trimmed !== cur && rest.onChange) {\n rest.onChange({ target: { ...input, value: trimmed } } as React.ChangeEvent<HTMLInputElement>);\n }\n }\n setFocused(false);\n onBlur?.(e);\n };\n \n // Transparent theme detection (purple-hue transparent bg)\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n const _transparentInputBg = tokens.colors.interactive.transparentInputBg;\n \n const hasError = !!error;\n const isOutlined = labelPlacement === 'outlined';\n \n // Determine border color based on state\n const getBorder = () => {\n if (hasError) return tokens.borders.input.error;\n if (status) return `${tokens.borders.width.thin} solid ${tokens.colors.status[status]}`;\n if (focused) return tokens.borders.input.focus;\n if (hovered && !disabled) return tokens.borders.input.hover;\n return tokens.borders.input.default;\n };\n \n const sizeConfig = {\n small: {\n padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`,\n fontSize: tokens.typography.fontSize.xs,\n height: tokens.elementSize.sm,\n iconSize: 14,\n labelSize: '0.6875rem',\n outlinedLabelSize: '0.625rem',\n inputPaddingLeft: 10,\n },\n medium: {\n padding: `${tokens.spacing.sm} ${tokens.spacing.smd}`,\n fontSize: tokens.typography.fontSize.sm,\n height: tokens.elementSize.md,\n iconSize: 18,\n labelSize: '0.75rem',\n outlinedLabelSize: '0.6875rem',\n inputPaddingLeft: 12,\n },\n large: {\n padding: `${tokens.spacing.smd} ${tokens.spacing.md}`,\n fontSize: tokens.typography.fontSize.base,\n height: tokens.elementSize.lg,\n iconSize: 20,\n labelSize: '0.875rem',\n outlinedLabelSize: '0.75rem',\n inputPaddingLeft: 16,\n },\n };\n \n const config = sizeConfig[size];\n const controlHeight = isMobile ? '44px' : config.height;\n \n // Focus glow effect\n const focusGlow = focused && !hasError\n ? tokens.borders.focusRing.default\n : hasError && focused\n ? `0 0 0 3px ${tokens.colors.status.critical}20`\n : 'none';\n \n // Background for the outlined label \"notch\" (must be opaque to mask the border)\n const labelBg = isTransparentTheme\n ? tokens.colors.background.base\n : tokens.colors.background.surface;\n \n // Shared label content (text + required/optional indicators)\n const labelContent = (\n <>\n {label}\n {required && (\n <span style={{ color: tokens.colors.status.critical, marginLeft: '2px' }}>*</span>\n )}\n {optional && (\n <span style={{ \n color: tokens.colors.text.tertiary, \n fontWeight: 400,\n fontStyle: 'italic',\n }}>\n {' '}(optional)\n </span>\n )}\n </>\n );\n \n return (\n <div\n className={classNames('zendir-input-wrapper', className)}\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: tokens.spacing.xs,\n width: fullWidth ? '100%' : 'auto',\n minWidth: fullWidth ? undefined : (isMobile ? '100%' : '200px'),\n ...style,\n }}\n >\n {/* Label: 'above' variant — sits above the input with gap */}\n {label && !isOutlined && (\n <label\n htmlFor={inputId}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: tokens.spacing.xs,\n fontSize: config.labelSize,\n fontWeight: 500,\n color: tokens.colors.text.secondary,\n letterSpacing: '0.01em',\n }}\n >\n {labelContent}\n </label>\n )}\n \n <div\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n }}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n >\n {/* Label: 'outlined' variant — positioned on the input border */}\n {label && isOutlined && (\n <label\n htmlFor={inputId}\n style={{\n position: 'absolute',\n top: 0,\n left: icon ? '34px' : `${config.inputPaddingLeft - 6}px`,\n transform: 'translateY(-50%)',\n backgroundColor: labelBg,\n padding: `0 ${tokens.spacing.xs}`,\n fontSize: config.outlinedLabelSize,\n fontWeight: 500,\n color: focused\n ? (hasError ? tokens.colors.status.critical : tokens.colors.accent.primary)\n : hasError\n ? tokens.colors.status.critical\n : tokens.colors.text.secondary,\n letterSpacing: '0.01em',\n zIndex: 1,\n pointerEvents: 'none',\n transition: 'color 200ms cubic-bezier(0.4, 0, 0.2, 1)',\n lineHeight: 1.2,\n whiteSpace: 'nowrap',\n }}\n >\n {labelContent}\n </label>\n )}\n \n {icon && (\n <span\n style={{\n position: 'absolute',\n left: tokens.spacing.smd,\n display: 'flex',\n alignItems: 'center',\n color: focused ? safeAccentText(tokens.colors.accent.primary) : tokens.colors.text.tertiary,\n pointerEvents: 'none',\n transition: tokens.animation.fast,\n }}\n >\n {icon}\n </span>\n )}\n \n <input\n ref={ref}\n id={inputId}\n disabled={disabled}\n required={required}\n aria-invalid={hasError}\n aria-describedby={helperText || error ? `${inputId}-helper` : undefined}\n onFocus={(e) => {\n setFocused(true);\n onFocus?.(e);\n }}\n onBlur={handleBlur}\n onPaste={handlePaste}\n type={type}\n autoComplete={autoComplete}\n inputMode={resolvedInputMode}\n style={{\n width: '100%',\n height: controlHeight,\n padding: config.padding,\n paddingLeft: icon ? '40px' : config.padding,\n paddingRight: iconEnd ? '40px' : config.padding,\n fontSize: config.fontSize,\n fontFamily: tokens.typography.fontFamily.primary,\n color: tokens.colors.text.primary,\n backgroundColor: isTransparentTheme ? 'rgba(10, 15, 25, 0.4)' : tokens.colors.background.surface,\n border: getBorder(),\n borderRadius: tokens.borderRadius.md,\n outline: 'none',\n transition: 'all 200ms cubic-bezier(0.4, 0, 0.2, 1)',\n cursor: disabled ? 'not-allowed' : 'text',\n opacity: disabled ? 0.5 : 1,\n boxShadow: focusGlow,\n }}\n {...rest}\n />\n \n {iconEnd && (\n <span\n style={{\n position: 'absolute',\n right: tokens.spacing.smd,\n display: 'flex',\n alignItems: 'center',\n color: tokens.colors.text.tertiary,\n cursor: 'pointer',\n }}\n >\n {iconEnd}\n </span>\n )}\n </div>\n \n {(helperText || error) && (\n <span\n id={`${inputId}-helper`}\n role={hasError ? 'alert' : undefined}\n style={{\n fontSize: '0.6875rem',\n fontWeight: hasError ? 500 : 400,\n color: hasError ? tokens.colors.status.critical : tokens.colors.text.tertiary,\n display: 'flex',\n alignItems: 'center',\n gap: tokens.spacing.xs,\n }}\n >\n {hasError && (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill={tokens.colors.status.critical} aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/>\n </svg>\n )}\n {error || helperText}\n </span>\n )}\n </div>\n );\n}));\n\nexport default Input;\n"],"names":["Input"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useMemo } from "react";
|
|
3
|
-
import { useTheme } from "
|
|
3
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
4
4
|
function getLimitsState(value, redLow, yellowLow, greenLow, greenHigh, yellowHigh, redHigh) {
|
|
5
5
|
if (redLow !== void 0 && value < redLow) return "red_low";
|
|
6
6
|
if (yellowLow !== void 0 && value < yellowLow) return "yellow_low";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LimitsBar.js","sources":["../../../../src/react/core/inputs/LimitsBar.tsx"],"sourcesContent":["/**\n * @zendir/ui - LimitsBar Component\n * \n * Visual limits indicator for telemetry monitoring and spacecraft health assessment.\n * Displays a horizontal bar with colored zones (red-low, yellow-low, green, yellow-high, red-high)\n * and a marker showing the current value position within the range.\n * \n * Supports:\n * - 5-zone limits (red-low, yellow-low, green/normal, yellow-high, red-high)\n * - 3-zone limits (low, nominal, high) \n * - Blue zone for \"out of range\" / stale\n * - Animated value transitions\n * - Compact and full display modes\n * - Value label with units\n * - Configurable thresholds\n * \n * Astro UX Compliance:\n * - Uses official Astro status colors\n * - Consistent with Astro monitoring patterns\n * \n * @example\n * ```tsx\n * <LimitsBar\n * value={72.5}\n * redLow={10} yellowLow={25} greenLow={40}\n * greenHigh={80} yellowHigh={90} redHigh={100}\n * label=\"Temperature\" unit=\"°C\"\n * />\n * ```\n */\n\nimport React, { useMemo, memo } from 'react';\nimport { useTheme } from '../../theme';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type LimitsState = 'red_low' | 'yellow_low' | 'green' | 'yellow_high' | 'red_high' | 'blue' | 'stale';\n\nexport interface LimitsBarProps {\n /** Current value */\n value: number;\n /** Red low threshold (minimum critical) */\n redLow?: number;\n /** Yellow low threshold (minimum warning) */\n yellowLow?: number;\n /** Green low threshold (start of nominal) */\n greenLow?: number;\n /** Green high threshold (end of nominal) */\n greenHigh?: number;\n /** Yellow high threshold (maximum warning) */\n yellowHigh?: number;\n /** Red high threshold (maximum critical) */\n redHigh?: number;\n /** Overall min for the bar (defaults to redLow - 10%) */\n min?: number;\n /** Overall max for the bar (defaults to redHigh + 10%) */\n max?: number;\n /** Label text */\n label?: string;\n /** Unit string */\n unit?: string;\n /** Whether the value is stale / not updating */\n stale?: boolean;\n /** Compact mode (thinner bar, less text) */\n compact?: boolean;\n /** Show the numeric value on the bar */\n showValue?: boolean;\n /** Show limit threshold labels */\n showThresholds?: boolean;\n /** Width (default: '100%') */\n width?: number | string;\n /** Height of the bar (default: 20 for normal, 12 for compact) */\n barHeight?: number;\n /** Custom status override (forces a specific status regardless of value) */\n statusOverride?: LimitsState;\n /** Called when status changes */\n onStatusChange?: (status: LimitsState, value: number) => void;\n /** When false, lower-limit zones (red-low, yellow-low, green-low) are hidden even if threshold values are provided */\n showLower?: boolean;\n /** When false, upper-limit zones (green-high, yellow-high, red-high) are hidden even if threshold values are provided */\n showUpper?: boolean;\n /** CSS class */\n className?: string;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction getLimitsState(\n value: number,\n redLow?: number,\n yellowLow?: number,\n greenLow?: number,\n greenHigh?: number,\n yellowHigh?: number,\n redHigh?: number,\n): LimitsState {\n if (redLow !== undefined && value < redLow) return 'red_low';\n if (yellowLow !== undefined && value < yellowLow) return 'yellow_low';\n if (greenLow !== undefined && value < greenLow) return 'yellow_low';\n if (redHigh !== undefined && value > redHigh) return 'red_high';\n if (yellowHigh !== undefined && value > yellowHigh) return 'yellow_high';\n if (greenHigh !== undefined && value > greenHigh) return 'yellow_high';\n return 'green';\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport const LimitsBar = memo(function LimitsBar({\n value,\n redLow: redLowProp,\n yellowLow: yellowLowProp,\n greenLow: greenLowProp,\n greenHigh: greenHighProp,\n yellowHigh: yellowHighProp,\n redHigh: redHighProp,\n min: minProp,\n max: maxProp,\n label,\n unit,\n stale = false,\n compact = false,\n showValue = true,\n showThresholds = false,\n showLower = true,\n showUpper = true,\n width = '100%',\n barHeight: barHeightProp,\n statusOverride,\n className = '',\n}: LimitsBarProps): React.ReactElement {\n // Mask thresholds based on showLower / showUpper flags\n const redLow = showLower ? redLowProp : undefined;\n const yellowLow = showLower ? yellowLowProp : undefined;\n const greenLow = showLower ? greenLowProp : undefined;\n const greenHigh = showUpper ? greenHighProp : undefined;\n const yellowHigh = showUpper ? yellowHighProp : undefined;\n const redHigh = showUpper ? redHighProp : undefined;\n const { tokens } = useTheme();\n const softStatusColors = useMemo(() => ({\n normal: tokens.colors.status.normal,\n caution: tokens.colors.status.caution,\n serious: tokens.colors.status.serious,\n critical: tokens.colors.status.critical,\n off: tokens.colors.status.off,\n standby: tokens.colors.status.standby,\n }), [tokens]);\n\n const barHeight = barHeightProp ?? (compact ? 12 : 20);\n \n const _thresholds = useMemo(() => {\n const rl = redLow ?? -Infinity;\n const yl = yellowLow ?? redLow ?? -Infinity;\n const gl = greenLow ?? yellowLow ?? redLow ?? -Infinity;\n const gh = greenHigh ?? yellowHigh ?? redHigh ?? Infinity;\n const yh = yellowHigh ?? redHigh ?? Infinity;\n const rh = redHigh ?? Infinity;\n return { rl, yl, gl, gh, yh, rh };\n }, [redLow, yellowLow, greenLow, greenHigh, yellowHigh, redHigh]);\n\n const rangeMin = minProp ?? (redLow !== undefined ? redLow - (redHigh !== undefined ? (redHigh - redLow) * 0.1 : 10) : 0);\n const rangeMax = maxProp ?? (redHigh !== undefined ? redHigh + (redLow !== undefined ? (redHigh - redLow) * 0.1 : 10) : 100);\n const range = rangeMax - rangeMin;\n\n const status = stale ? 'stale' : (statusOverride ?? getLimitsState(value, redLow, yellowLow, greenLow, greenHigh, yellowHigh, redHigh));\n\n const statusColors: Record<LimitsState, string> = {\n red_low: softStatusColors.critical,\n red_high: softStatusColors.critical,\n yellow_low: softStatusColors.caution,\n yellow_high: softStatusColors.caution,\n green: softStatusColors.normal,\n blue: softStatusColors.standby,\n stale: softStatusColors.off,\n };\n\n const valuePercent = range > 0 ? Math.max(0, Math.min(100, ((value - rangeMin) / range) * 100)) : 50;\n\n // Build zone segments\n const zones = useMemo(() => {\n const segs: { start: number; end: number; color: string }[] = [];\n const toPercent = (v: number) => Math.max(0, Math.min(100, ((v - rangeMin) / range) * 100));\n\n const critical = softStatusColors.critical;\n const caution = softStatusColors.caution;\n const normal = softStatusColors.normal;\n\n if (redLow !== undefined) {\n segs.push({ start: 0, end: toPercent(redLow), color: `${critical}66` });\n }\n if (yellowLow !== undefined) {\n const s = redLow !== undefined ? toPercent(redLow) : 0;\n segs.push({ start: s, end: toPercent(yellowLow), color: `${caution}66` });\n }\n {\n const s = yellowLow !== undefined ? toPercent(yellowLow) : (redLow !== undefined ? toPercent(redLow) : 0);\n const e = yellowHigh !== undefined ? toPercent(yellowHigh) : (redHigh !== undefined ? toPercent(redHigh) : 100);\n segs.push({ start: s, end: e, color: `${normal}44` });\n }\n if (yellowHigh !== undefined) {\n const e = redHigh !== undefined ? toPercent(redHigh) : 100;\n segs.push({ start: toPercent(yellowHigh), end: e, color: `${caution}66` });\n }\n if (redHigh !== undefined) {\n segs.push({ start: toPercent(redHigh), end: 100, color: `${critical}66` });\n }\n\n return segs;\n }, [redLow, yellowLow, yellowHigh, redHigh, rangeMin, range, softStatusColors]);\n\n const markerColor = statusColors[status];\n\n return (\n <div\n className={`limits-bar ${className}`}\n role=\"meter\"\n aria-valuenow={value}\n aria-valuemin={rangeMin}\n aria-valuemax={rangeMax}\n aria-label={label ? `${label}: ${value}${unit ? ' ' + unit : ''}` : `${value}${unit ? ' ' + unit : ''}`}\n style={{ width, fontFamily: tokens.typography.fontFamily.primary }}\n >\n {/* Label row */}\n {(label || showValue) && !compact && (\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: tokens.spacing.xs, fontSize: tokens.typography.fontSize.sm }}>\n {label && <span style={{ color: tokens.colors.text.secondary, fontWeight: tokens.typography.fontWeight.medium }}>{label}</span>}\n {showValue && (\n <span style={{ color: markerColor, fontWeight: tokens.typography.fontWeight.medium, fontFamily: tokens.typography.fontFamily.mono }}>\n {typeof value === 'number' ? value.toFixed(2) : value}\n {unit && <span style={{ fontSize: tokens.typography.fontSize.xxs, marginLeft: tokens.spacing.xxs, color: tokens.colors.text.muted }}>{unit}</span>}\n </span>\n )}\n </div>\n )}\n\n {/* Bar */}\n <div style={{\n position: 'relative',\n height: barHeight,\n borderRadius: tokens.borderRadius.full,\n background: tokens.colors.background.base,\n border: `1px solid ${tokens.colors.border.muted}`,\n overflow: 'hidden',\n }}>\n {/* Zone segments */}\n {zones.map((z, i) => (\n <div\n key={i}\n style={{\n position: 'absolute',\n left: `${z.start}%`,\n width: `${z.end - z.start}%`,\n height: '100%',\n background: z.color,\n }}\n />\n ))}\n\n {/* Value marker */}\n <div style={{\n position: 'absolute',\n left: `${valuePercent}%`,\n top: 0,\n bottom: 0,\n width: compact ? 3 : 4,\n marginLeft: compact ? -1.5 : -2,\n background: markerColor,\n borderRadius: tokens.borderRadius.sm,\n boxShadow: `0 0 8px ${markerColor}66, 0 0 3px ${markerColor}44`,\n transition: 'left 300ms cubic-bezier(0.4, 0, 0.2, 1), background 300ms ease',\n }} />\n\n {/* Compact label */}\n {compact && showValue && (\n <div style={{\n position: 'absolute',\n right: tokens.spacing.xs,\n top: '50%',\n transform: 'translateY(-50%)',\n fontSize: tokens.typography.fontSize.micro,\n fontWeight: tokens.typography.fontWeight.medium,\n color: markerColor,\n fontFamily: tokens.typography.fontFamily.mono,\n textShadow: `0 0 4px ${tokens.colors.background.base}`,\n }}>\n {typeof value === 'number' ? value.toFixed(1) : value}{unit || ''}\n </div>\n )}\n </div>\n\n {/* Threshold labels */}\n {showThresholds && !compact && (\n <div style={{ position: 'relative', height: 14, marginTop: tokens.spacing.xxs }}>\n {[\n { val: redLow, color: softStatusColors.critical },\n { val: yellowLow, color: softStatusColors.caution },\n { val: greenHigh ?? yellowHigh, color: softStatusColors.caution },\n { val: redHigh, color: softStatusColors.critical },\n ].filter(t => t.val !== undefined).map((t, i) => {\n const pct = range > 0 ? ((t.val! - rangeMin) / range) * 100 : 0;\n return (\n <span\n key={i}\n aria-label={`Threshold: ${t.val}`}\n style={{\n position: 'absolute',\n left: `${pct}%`,\n transform: 'translateX(-50%)',\n fontSize: tokens.typography.fontSize.micro,\n color: t.color,\n fontFamily: tokens.typography.fontFamily.mono,\n }}\n >\n {t.val}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n});\n\nexport default LimitsBar;\n"],"names":["LimitsBar"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { LabelPlacement } from './Input';
|
|
3
|
-
import { StatusLevel } from '
|
|
4
|
-
import { StatusThresholds } from '
|
|
3
|
+
import { StatusLevel } from '../../utils';
|
|
4
|
+
import { StatusThresholds } from '../data/propertyConfig';
|
|
5
5
|
|
|
6
6
|
export type NumberInputSize = 'small' | 'medium' | 'large';
|
|
7
7
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, forwardRef, useState, useRef, useId, useMemo, useEffect, useCallback } from "react";
|
|
3
|
-
import { deriveStatus } from "
|
|
4
|
-
import { StatusIndicator } from "
|
|
5
|
-
import { useTheme } from "
|
|
3
|
+
import { deriveStatus } from "../data/propertyConfig.js";
|
|
4
|
+
import { StatusIndicator } from "../../astro/StatusIndicator.js";
|
|
5
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
6
6
|
const DEFAULT_DECIMAL_PLACES = 0;
|
|
7
7
|
const NumberInput = memo(forwardRef(function NumberInput2({
|
|
8
8
|
value,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NumberInput.js","sources":["../../../../src/react/core/inputs/NumberInput.tsx"],"sourcesContent":["/**\n * @zendir/ui - NumberInput Component\n * \n * Numeric input with optional slider, min/max bounds, step, precision,\n * and unit display. Essential for operator dashboards (frequency, power,\n * aperture, field of view, etc.).\n * \n * Astro UX Compliance:\n * - Consistent sizing with Input component (small/medium/large)\n * - Focus ring for accessibility (WCAG 2.1 AA)\n * - Status-based border colors\n * - Tabular numbers for value alignment\n * \n * @example\n * ```tsx\n * // Each instance can set precision (decimal places); default is 2\n * <NumberInput value={500} onChange={setFreq} min={300} max={900} unit=\"MHz\" label=\"Frequency\" />\n * <NumberInput value={45.2} onChange={setPower} min={0.1} max={100} step={0.1} precision={1} unit=\"W\" slider />\n * <NumberInput value={1024} onChange={setRes} min={128} max={2048} step={128} precision={0} unit=\"px\" label=\"Resolution\" slider />\n * // Status mode with automatic threshold-based coloring:\n * <NumberInput value={temp} onChange={setTemp} min={0} max={100} unit=\"°C\" slider\n * statusMode statusThresholds={{ critical: 90, serious: 75, caution: 50, normal: 20, standby: 0 }} />\n * ```\n */\n\nimport React, { memo, forwardRef, useState, useCallback, useRef, useEffect, useId, useMemo } from 'react';\nimport { useTheme } from '../../theme';\nimport type { LabelPlacement } from './Input';\nimport type { StatusLevel } from '../../utils';\nimport type { StatusThresholds } from '../data/propertyConfig';\nimport { deriveStatus } from '../data/propertyConfig';\nimport { StatusIndicator } from '../../astro/StatusIndicator';\n\nexport type NumberInputSize = 'small' | 'medium' | 'large';\n\n/**\n * Re-export SliderStatus as an alias for StatusLevel for convenience.\n * Includes: 'normal' | 'standby' | 'caution' | 'serious' | 'critical' | 'off'\n */\nexport type SliderStatus = StatusLevel;\n\n/** Default decimal places when precision is not specified: 0 = integer display. Set precision (e.g. 2) to show decimals. */\nconst DEFAULT_DECIMAL_PLACES = 0;\n\nexport interface NumberInputProps {\n /** Current value */\n value: number;\n /** Change handler */\n onChange: (value: number) => void;\n /** Minimum value */\n min?: number;\n /** Maximum value */\n max?: number;\n /** Step increment */\n step?: number;\n /** Number of decimal places to show and round to. Omit or 0 = integer. Use 2 (or any positive number) to show decimals; 2 is typical when decimals are needed. */\n precision?: number;\n /** Unit label displayed after the input (e.g., \"MHz\", \"W\", \"°C\") */\n unit?: string;\n /** Label text or ReactNode (supports rich content like tooltip icons) */\n label?: React.ReactNode;\n /** Helper text below the input */\n helperText?: string;\n /** Error state / message */\n error?: boolean | string;\n /** Show slider below the input */\n slider?: boolean;\n /** Size variant */\n size?: NumberInputSize;\n /** Disabled state */\n disabled?: boolean;\n /** Full width */\n fullWidth?: boolean;\n /** Custom width */\n width?: string | number;\n /** ID for accessibility */\n id?: string;\n /** Custom className */\n className?: string;\n /** Custom style */\n style?: React.CSSProperties;\n /** Text alignment inside the input field */\n textAlign?: 'left' | 'center' | 'right';\n /**\n * Label placement style.\n * - `'outlined'` — label sits on the input border (notched/Material-style). **Default.**\n * - `'above'` — label sits above the input with a gap (classic stack).\n */\n labelPlacement?: LabelPlacement;\n /** Required indicator */\n required?: boolean;\n\n // ── Status Mode ──────────────────────────────────────────────────────\n /**\n * Enable status-based coloring on the slider track, thumb, and glow.\n * When enabled, the slider color reflects the current status instead of\n * the default accent color.\n */\n statusMode?: boolean;\n /**\n * Manual status override. When provided, this status is used directly\n * instead of computing from thresholds.\n */\n status?: SliderStatus;\n /**\n * Threshold map for automatic status resolution based on current value.\n * Supports both high thresholds (critical, serious, caution) and low\n * thresholds (criticalLow, seriousLow, cautionLow) from the shared\n * Astro UX StatusThresholds type.\n * Requires `statusMode` to be enabled.\n */\n statusThresholds?: StatusThresholds;\n /**\n * Callback fired whenever the computed/resolved status changes.\n * Useful for parent components to react to status transitions.\n */\n onStatusChange?: (status: SliderStatus) => void;\n}\n\n// Status resolution is delegated to the shared deriveStatus() utility from propertyConfig.\n\nexport const NumberInput = memo(forwardRef<HTMLInputElement, NumberInputProps>(function NumberInput(\n {\n value,\n onChange,\n min,\n max,\n step = 1,\n precision,\n unit,\n label,\n helperText,\n error,\n slider = false,\n size = 'medium',\n disabled = false,\n fullWidth = false,\n width,\n id,\n className,\n style,\n textAlign = 'right',\n labelPlacement = 'outlined',\n required,\n statusMode = false,\n status: statusOverride,\n statusThresholds,\n onStatusChange,\n },\n ref\n): React.ReactElement {\n const { tokens, theme } = useTheme();\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n const isOutlined = labelPlacement === 'outlined';\n const decimalPlaces = precision ?? DEFAULT_DECIMAL_PLACES;\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [isSliderActive, setIsSliderActive] = useState(false);\n const [localValue, setLocalValue] = useState(() => value.toFixed(decimalPlaces));\n const inputRef = useRef<HTMLInputElement>(null);\n const sliderContainerRef = useRef<HTMLDivElement>(null);\n const sliderId = useId().replace(/:/g, '');\n \n // ── Status resolution ──────────────────────────────────────────────────\n const resolvedStatus: SliderStatus | undefined = useMemo(() => {\n if (!statusMode) return undefined;\n if (statusOverride) return statusOverride;\n return deriveStatus(value, statusThresholds);\n }, [statusMode, statusOverride, statusThresholds, value]);\n\n // Fire onStatusChange when status changes\n const prevStatusRef = useRef<SliderStatus | undefined>(undefined);\n useEffect(() => {\n if (resolvedStatus !== undefined && resolvedStatus !== prevStatusRef.current) {\n prevStatusRef.current = resolvedStatus;\n onStatusChange?.(resolvedStatus);\n }\n }, [resolvedStatus, onStatusChange]);\n\n /** Resolve the active color: status color or accent */\n const activeColor = useMemo(() => {\n if (resolvedStatus && tokens.colors.status[resolvedStatus]) {\n return tokens.colors.status[resolvedStatus];\n }\n return tokens.colors.accent.primary;\n }, [resolvedStatus, tokens.colors.status, tokens.colors.accent.primary]);\n\n // Sync external value to local state\n useEffect(() => {\n if (!isFocused) {\n setLocalValue(value.toFixed(decimalPlaces));\n }\n }, [value, decimalPlaces, isFocused]);\n \n const clamp = useCallback((v: number): number => {\n let result = v;\n if (min !== undefined) result = Math.max(min, result);\n if (max !== undefined) result = Math.min(max, result);\n result = Number(result.toFixed(decimalPlaces));\n return result;\n }, [min, max, decimalPlaces]);\n \n const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value;\n setLocalValue(raw);\n \n const parsed = parseFloat(raw);\n if (!isNaN(parsed)) {\n onChange(clamp(parsed));\n }\n }, [onChange, clamp]);\n \n const handleBlur = useCallback(() => {\n setIsFocused(false);\n const parsed = parseFloat(localValue);\n if (isNaN(parsed)) {\n setLocalValue(value.toFixed(decimalPlaces));\n } else {\n const clamped = clamp(parsed);\n onChange(clamped);\n setLocalValue(clamped.toFixed(decimalPlaces));\n }\n }, [localValue, value, onChange, clamp, decimalPlaces]);\n \n const handleSliderChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const parsed = parseFloat(e.target.value);\n const clamped = clamp(parsed);\n onChange(clamped);\n setLocalValue(clamped.toFixed(decimalPlaces));\n }, [onChange, clamp, decimalPlaces]);\n \n const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n onChange(clamp(value + step));\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n onChange(clamp(value - step));\n }\n }, [value, step, onChange, clamp]);\n \n // Wheel handler: scroll on slider or input changes value\n const handleWheel = useCallback((e: WheelEvent) => {\n if (disabled || min === undefined || max === undefined) return;\n e.preventDefault();\n const direction = e.deltaY < 0 ? 1 : -1;\n onChange(clamp(value + step * direction));\n }, [value, step, onChange, clamp, disabled, min, max]);\n \n // Attach wheel listener to slider container AND input element\n useEffect(() => {\n const sliderContainer = sliderContainerRef.current;\n const inputElement = inputRef.current;\n \n // Always attach to input if min/max defined, regardless of slider prop\n if (min !== undefined && max !== undefined) {\n if (slider && sliderContainer) {\n sliderContainer.addEventListener('wheel', handleWheel, { passive: false });\n }\n if (inputElement) {\n inputElement.addEventListener('wheel', handleWheel, { passive: false });\n }\n }\n \n return () => {\n if (sliderContainer) sliderContainer.removeEventListener('wheel', handleWheel);\n if (inputElement) inputElement.removeEventListener('wheel', handleWheel);\n };\n }, [handleWheel, slider, min, max]);\n \n // Release slider active state when mouse is released anywhere\n useEffect(() => {\n if (!isSliderActive) return;\n const handleUp = () => setIsSliderActive(false);\n window.addEventListener('mouseup', handleUp);\n window.addEventListener('touchend', handleUp);\n return () => {\n window.removeEventListener('mouseup', handleUp);\n window.removeEventListener('touchend', handleUp);\n };\n }, [isSliderActive]);\n\n const [isUnitDragging, setIsUnitDragging] = useState(false);\n const dragStartValueRef = useRef<number>(0);\n const dragStartYRef = useRef<number>(0);\n const unitRef = useRef<HTMLSpanElement>(null);\n\n // Unit Drag Handler\n const handleUnitMouseDown = useCallback((e: React.MouseEvent) => {\n if (disabled) return;\n \n e.preventDefault();\n setIsUnitDragging(true);\n dragStartValueRef.current = value;\n dragStartYRef.current = e.clientY;\n \n // Lock cursor if supported for infinite drag\n if (document.body.requestPointerLock) {\n document.body.requestPointerLock();\n }\n }, [value, disabled]);\n\n const handleUnitMouseMove = useCallback((e: MouseEvent) => {\n if (!isUnitDragging) return;\n \n // Use movementY if pointer is locked (infinite drag), otherwise fallback to delta\n // Invert Y because dragging UP (negative Y) should INCREASE value\n const deltaY = document.pointerLockElement \n ? -e.movementY \n : (dragStartYRef.current - e.clientY);\n \n if (deltaY === 0) return;\n\n // Velocity / Precision Logic\n // Shift key = Precision mode (0.1x speed)\n // Ctrl/Cmd key = Fast mode (10x speed)\n let speedMultiplier = 1;\n if (e.shiftKey) speedMultiplier = 0.1;\n else if (e.ctrlKey || e.metaKey) speedMultiplier = 10;\n \n // Scale sensitivity: 1 pixel = 1 step * multiplier\n // For non-locked pointer, we might want to dampen it slightly to 0.5 step per pixel\n const sensitivity = document.pointerLockElement ? 1 : 0.5;\n \n const change = deltaY * sensitivity * (step || 1) * speedMultiplier;\n \n // If pointer is NOT locked, we update reference to prevent jumpiness\n if (!document.pointerLockElement) {\n dragStartYRef.current = e.clientY;\n dragStartValueRef.current = clamp(value + change);\n onChange(clamp(value + change));\n } else {\n // For locked pointer, we accumulate on the start value or current value\n // Better to accumulate on current value to handle continuous flow\n onChange(clamp(value + change));\n }\n \n }, [isUnitDragging, value, step, onChange, clamp]);\n\n const handleUnitMouseUp = useCallback(() => {\n if (isUnitDragging) {\n setIsUnitDragging(false);\n if (document.exitPointerLock) {\n document.exitPointerLock();\n }\n }\n }, [isUnitDragging]);\n\n // Global mouse listeners for drag\n useEffect(() => {\n if (isUnitDragging) {\n window.addEventListener('mousemove', handleUnitMouseMove);\n window.addEventListener('mouseup', handleUnitMouseUp);\n }\n return () => {\n window.removeEventListener('mousemove', handleUnitMouseMove);\n window.removeEventListener('mouseup', handleUnitMouseUp);\n };\n }, [isUnitDragging, handleUnitMouseMove, handleUnitMouseUp]);\n\n // Attach wheel listener to unit element too\n useEffect(() => {\n const unitEl = unitRef.current;\n if (unitEl && !disabled) {\n unitEl.addEventListener('wheel', handleWheel, { passive: false });\n }\n return () => {\n if (unitEl) unitEl.removeEventListener('wheel', handleWheel);\n };\n }, [handleWheel, disabled]);\n \n // Size config — heights match Input & Select via elementSize tokens\n const sizeConfig = {\n small: { height: tokens.elementSize.sm, fontSize: tokens.typography.fontSize.xs, padding: `${tokens.spacing.xs} ${tokens.spacing.sm}`, sliderHeight: 3, inputPaddingLeft: 8 },\n medium: { height: tokens.elementSize.md, fontSize: tokens.typography.fontSize.sm, padding: `${tokens.spacing.xs} ${tokens.spacing.smd}`, sliderHeight: 4, inputPaddingLeft: 12 },\n large: { height: tokens.elementSize.lg, fontSize: tokens.typography.fontSize.base, padding: `${tokens.spacing.sm} ${tokens.spacing.md}`, sliderHeight: 5, inputPaddingLeft: 16 },\n };\n const config = sizeConfig[size];\n \n const hasError = !!error;\n const errorMessage = typeof error === 'string' ? error : undefined;\n \n const computedBorder = hasError\n ? tokens.borders.input.error\n : isFocused\n ? tokens.borders.input.focus\n : isHovered\n ? tokens.borders.input.hover\n : tokens.borders.input.default;\n \n const inputBg = isTransparentTheme\n ? (tokens.colors.interactive.transparentInputBg || 'rgba(139, 92, 246, 0.08)')\n : tokens.colors.background.surface;\n\n // Slider track gradient (filled portion)\n const sliderPercent = (min !== undefined && max !== undefined)\n ? ((value - min) / (max - min)) * 100\n : 50;\n\n const inputId = id || (typeof label === 'string' ? `zendir-number-${label.replace(/\\s+/g, '-').toLowerCase()}` : undefined);\n\n // ── Thumb dimensions ─────────────────────────────────────────────────\n const thumbWidth = 24;\n const thumbHeight = config.sliderHeight + 8;\n const trackH = config.sliderHeight;\n\n return (\n <div\n className={className}\n style={{\n display: 'inline-flex',\n flexDirection: 'column',\n // No gap when slider is present — slider sits flush on the input bottom edge\n gap: slider ? 0 : tokens.spacing.xs,\n width: fullWidth ? '100%' : (typeof width === 'number' ? `${width}px` : width),\n fontFamily: tokens.typography.fontFamily.primary,\n ...style,\n }}\n >\n {/* Label: 'above' variant */}\n {label && !isOutlined && (\n <label\n htmlFor={inputId}\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.medium,\n color: tokens.colors.text.secondary,\n letterSpacing: tokens.typography.letterSpacing.wide,\n }}\n >\n {label}\n {required && (\n <span style={{ color: tokens.colors.status.critical, marginLeft: '2px' }}>*</span>\n )}\n </label>\n )}\n \n {/* Input row */}\n <div\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n height: config.height,\n backgroundColor: inputBg,\n border: computedBorder,\n borderRadius: tokens.borderRadius.md,\n transition: tokens.animation.fast,\n opacity: disabled ? 0.5 : 1,\n overflow: isOutlined ? 'visible' : 'hidden',\n }}\n onMouseEnter={() => !disabled && setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {/* Label: 'outlined' variant — positioned on the input row border */}\n {label && isOutlined && (\n <label\n htmlFor={inputId}\n style={{\n position: 'absolute',\n top: 0,\n left: `${config.inputPaddingLeft - 6}px`,\n transform: 'translateY(-50%)',\n backgroundColor: isTransparentTheme\n ? tokens.colors.background.base\n : tokens.colors.background.surface,\n padding: '0 6px',\n fontSize: { small: '0.625rem', medium: '0.6875rem', large: '0.75rem' }[size],\n fontWeight: tokens.typography.fontWeight.medium,\n color: isFocused\n ? (hasError ? tokens.colors.status.critical : tokens.colors.accent.primary)\n : hasError\n ? tokens.colors.status.critical\n : tokens.colors.text.secondary,\n letterSpacing: tokens.typography.letterSpacing.wide,\n zIndex: 1,\n pointerEvents: 'none',\n transition: tokens.animation.fast,\n lineHeight: 1.2,\n whiteSpace: 'nowrap',\n }}\n >\n {label}\n {required && (\n <span style={{ color: tokens.colors.status.critical, marginLeft: '2px' }}>*</span>\n )}\n </label>\n )}\n <input\n ref={ref || inputRef}\n id={inputId}\n type=\"text\"\n inputMode=\"decimal\"\n value={localValue}\n onChange={handleInputChange}\n onFocus={() => setIsFocused(true)}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n aria-invalid={hasError}\n aria-describedby={errorMessage ? `${inputId}-error` : helperText ? `${inputId}-helper` : undefined}\n style={{\n flex: 1,\n height: '100%',\n padding: config.padding,\n fontSize: config.fontSize,\n fontWeight: tokens.typography.fontWeight.medium,\n fontFamily: tokens.typography.fontFamily.mono,\n fontVariantNumeric: 'tabular-nums',\n color: tokens.colors.text.primary,\n backgroundColor: 'transparent',\n border: 'none',\n outline: 'none',\n minWidth: 0,\n textAlign,\n }}\n />\n \n {/* Unit */}\n {unit && (\n <span\n ref={unitRef}\n onMouseDown={handleUnitMouseDown}\n style={{\n padding: `0 ${tokens.spacing.sm}`,\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.medium,\n color: isUnitDragging ? activeColor : tokens.colors.text.tertiary,\n fontFamily: tokens.typography.fontFamily.primary,\n flexShrink: 0,\n borderLeft: tokens.borders.separator,\n height: '100%',\n display: 'flex',\n alignItems: 'center',\n backgroundColor: isTransparentTheme\n ? 'rgba(139, 92, 246, 0.04)'\n : 'rgba(0, 0, 0, 0.15)',\n cursor: disabled ? 'not-allowed' : 'ns-resize',\n userSelect: 'none',\n transition: 'color 0.2s ease',\n }}\n title={disabled ? undefined : \"Drag to adjust value\"}\n >\n {unit}\n </span>\n )}\n </div>\n \n {/* Slider — directly below input with no gap */}\n {slider && min !== undefined && max !== undefined && (() => {\n const sliderH = thumbHeight;\n const cy = sliderH / 2;\n const pct = sliderPercent / 100; // 0..1\n\n // Thumb left-edge position: maps 0% → 0px, 100% → (containerWidth - thumbWidth)\n // CSS calc: pct * (100% - thumbWidth)\n const thumbLeftCalc = `calc(${pct} * (100% - ${thumbWidth}px))`;\n\n // Filled track width = thumb left edge + 1px overlap for seamless join\n const filledWidthCalc = `calc(${pct} * (100% - ${thumbWidth}px) + 1px)`;\n\n return (\n <div\n ref={sliderContainerRef}\n style={{\n position: 'relative',\n height: `${sliderH}px`,\n marginTop: `-${sliderH / 1.42}px`,\n }}\n >\n {/* Unfilled track */}\n <div style={{\n position: 'absolute',\n top: `${cy}px`,\n left: 0,\n right: 0,\n height: `${trackH}px`,\n transform: 'translateY(-50%)',\n borderRadius: `${trackH / 2}px`,\n backgroundColor: `${tokens.colors.border.muted}60`,\n }} />\n {/* Filled track — flat right edge for flush join with thumb */}\n <div style={{\n position: 'absolute',\n top: `${cy}px`,\n left: 0,\n width: filledWidthCalc,\n height: `${trackH}px`,\n transform: 'translateY(-50%)',\n borderRadius: `${trackH / 2}px 0 0 ${trackH / 2}px`,\n background: activeColor,\n transition: 'background 300ms ease',\n }} />\n {/* Invisible range input */}\n <input\n type=\"range\"\n className={`zendir-slider-${sliderId}`}\n min={min}\n max={max}\n step={step}\n value={value}\n onChange={handleSliderChange}\n onMouseDown={() => setIsSliderActive(true)}\n onMouseUp={() => setIsSliderActive(false)}\n onTouchStart={() => setIsSliderActive(true)}\n onTouchEnd={() => setIsSliderActive(false)}\n disabled={disabled}\n aria-label={typeof label === 'string' ? label : 'Value slider'}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n margin: 0,\n padding: 0,\n opacity: 0,\n cursor: disabled ? 'not-allowed' : 'pointer',\n zIndex: 2,\n }}\n />\n {/* Smooth-blob thumb — left edge flush with filled track end */}\n <div\n style={{\n position: 'absolute',\n top: `${cy}px`,\n left: thumbLeftCalc,\n width: `${thumbWidth}px`,\n height: `${thumbHeight}px`,\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n zIndex: 1,\n }}\n >\n <svg\n width={thumbWidth}\n height={thumbHeight}\n viewBox={`0 0 ${thumbWidth} ${thumbHeight}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ display: 'block', overflow: 'visible' }}\n >\n {(() => {\n const w = thumbWidth;\n const h = thumbHeight;\n const svgCy = h / 2;\n const trackHalf = trackH / 2;\n const r = 2;\n\n const ltop = svgCy - trackHalf;\n const lbot = svgCy + trackHalf;\n const rtop = r;\n const rbot = h - r;\n\n const cp1x = w * 0.28;\n const cp2x = w * 0.48;\n\n const d = [\n `M 0 ${ltop}`,\n `C ${cp1x} ${ltop}, ${cp2x} ${rtop}, ${w - r} ${rtop}`,\n `A ${r} ${r} 0 0 1 ${w} ${rtop + r}`,\n `L ${w} ${rbot - r}`,\n `A ${r} ${r} 0 0 1 ${w - r} ${rbot}`,\n `C ${cp2x} ${rbot}, ${cp1x} ${lbot}, 0 ${lbot}`,\n `Z`,\n ].join(' ');\n\n return <path d={d} fill={activeColor} />;\n })()}\n </svg>\n </div>\n\n {/* Astro UXDS status symbol (shape-coded: circle/square/diamond/triangle) */}\n {statusMode && resolvedStatus && (\n <div\n style={{\n position: 'absolute',\n bottom: `-${size === 'large' ? 10 : 8}px`,\n left: `calc(${pct} * (100% - ${thumbWidth}px) + ${thumbWidth / 2}px)`,\n transform: 'translateX(-50%)',\n zIndex: 1,\n lineHeight: 0,\n }}\n >\n <StatusIndicator\n status={resolvedStatus}\n small\n />\n </div>\n )}\n </div>\n );\n })()}\n \n {/* Helper / Error text */}\n {(helperText || errorMessage) && (\n <div\n id={errorMessage ? `${inputId}-error` : `${inputId}-helper`}\n role={errorMessage ? 'alert' : undefined}\n style={{\n fontSize: tokens.typography.fontSize.xs,\n color: hasError ? tokens.colors.status.critical : tokens.colors.text.tertiary,\n }}\n >\n {errorMessage || helperText}\n </div>\n )}\n </div>\n );\n}));\n\nexport default NumberInput;\n"],"names":["NumberInput"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useRef, useState, useEffect, useCallback } from "react";
|
|
3
|
-
import { useBreakpoint } from "
|
|
4
|
-
import { useTheme } from "
|
|
3
|
+
import { useBreakpoint } from "../layout/useBreakpoint.js";
|
|
4
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
5
|
const PinInput = memo(function PinInput2({
|
|
6
6
|
length = 6,
|
|
7
7
|
type = "alphanumeric",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PinInput.js","sources":["../../../../src/react/core/inputs/PinInput.tsx"],"sourcesContent":["/**\r\n * @zendir/ui - PinInput Component\r\n * \r\n * Multi-character code entry for passwords, verification codes, and team IDs.\r\n * Auto-advances focus between cells. Supports numeric and alphanumeric modes.\r\n * \r\n * Astro UX Compliance:\r\n * - Consistent styling with Input component\r\n * - Focus ring for accessibility\r\n * - Monospace tabular numbers\r\n * \r\n * @example\r\n * ```tsx\r\n * <PinInput length={6} type=\"alphanumeric\" value={password} onChange={setPassword} label=\"Team Password\" />\r\n * <PinInput length={4} type=\"numeric\" value={code} onChange={setCode} label=\"Verification Code\" />\r\n * <PinInput length={8} value={token} onChange={setToken} label=\"API Token\" />\r\n * ```\r\n */\r\n\r\nimport React, { memo, useState, useRef, useCallback, useEffect } from 'react';\r\nimport { useTheme } from '../../theme';\r\nimport type { LabelPlacement } from './Input';\r\nimport { useBreakpoint } from '../layout/useBreakpoint';\r\n\r\nexport interface PinInputProps {\r\n /** Number of character cells (default 6; any positive number, e.g. 4, 6, 8) */\r\n length?: number;\r\n /** Input type */\r\n type?: 'numeric' | 'alphanumeric';\r\n /** Current value */\r\n value: string;\r\n /** Change handler */\r\n onChange: (value: string) => void;\r\n /** Label text or ReactNode (supports rich content like tooltip icons) */\r\n label?: React.ReactNode;\r\n /** Helper text */\r\n helperText?: string;\r\n /** Error state */\r\n error?: boolean | string;\r\n /** Disabled */\r\n disabled?: boolean;\r\n /** Mask characters (password mode) */\r\n mask?: boolean;\r\n /** Size */\r\n size?: 'small' | 'medium' | 'large';\r\n /** Auto-focus first cell on mount */\r\n autoFocus?: boolean;\r\n /** Callback when all cells filled */\r\n onComplete?: (value: string) => void;\r\n /**\r\n * Label placement style.\r\n * - `'outlined'` — label sits on the border of a surrounding container. **Default.**\r\n * - `'above'` — label sits above the cells with a gap (classic stack).\r\n */\r\n labelPlacement?: LabelPlacement;\r\n /** Required indicator */\r\n required?: boolean;\r\n /** Stretch to full width of container (cells share width equally, same as standard inputs) */\r\n fullWidth?: boolean;\r\n}\r\n\r\nexport const PinInput = memo(function PinInput({\r\n length = 6,\r\n type = 'alphanumeric',\r\n value,\r\n onChange,\r\n label,\r\n helperText,\r\n error,\r\n disabled = false,\r\n mask = false,\r\n size = 'medium',\r\n autoFocus = false,\r\n onComplete,\r\n labelPlacement = 'outlined',\r\n required,\r\n fullWidth = false,\r\n}: PinInputProps): React.ReactElement {\r\n const { tokens, theme } = useTheme();\r\n const { isMobile } = useBreakpoint();\r\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\r\n const refs = useRef<(HTMLInputElement | null)[]>([]);\r\n const [focusedIndex, setFocusedIndex] = useState<number | null>(null);\r\n \r\n const chars = value.split('').concat(Array(length).fill('')).slice(0, length);\r\n \r\n useEffect(() => {\r\n if (autoFocus && refs.current[0]) {\r\n refs.current[0].focus();\r\n }\r\n }, [autoFocus]);\r\n \r\n // Between original tokens and the reduced set: slightly more height than 24/32/40, still less than 28/36/44\r\n const reducedHeight = size === 'small' ? '26px' : size === 'medium' ? '34px' : '42px';\r\n const controlHeight = isMobile ? '44px' : reducedHeight;\r\n const sizeConfig = {\r\n small: { fontSize: tokens.typography.fontSize.xs },\r\n medium: { fontSize: tokens.typography.fontSize.sm },\r\n large: { fontSize: tokens.typography.fontSize.base },\r\n };\r\n const config = { ...sizeConfig[size], height: controlHeight } as { height: string; fontSize: string };\r\n \r\n const isValid = (char: string): boolean => {\r\n if (type === 'numeric') return /^[0-9]$/.test(char);\r\n return /^[a-zA-Z0-9]$/.test(char);\r\n };\r\n \r\n const handleChange = useCallback((index: number, inputValue: string) => {\r\n // Handle paste (multiple characters). Strip spaces so pasted codes like \"12 34 56\" work.\r\n if (inputValue.length > 1) {\r\n const normalized = inputValue.replace(/\\s/g, '');\r\n const filtered = normalized.split('').filter(isValid).slice(0, length);\r\n const newValue = filtered.join('');\r\n onChange(newValue);\r\n const nextIndex = Math.min(filtered.length, length - 1);\r\n refs.current[nextIndex]?.focus();\r\n if (filtered.length === length) onComplete?.(newValue);\r\n return;\r\n }\r\n \r\n const char = inputValue;\r\n if (char && !isValid(char)) return;\r\n \r\n const newChars = [...chars];\r\n newChars[index] = char.toUpperCase();\r\n const newValue = newChars.join('').replace(/\\s/g, '');\r\n onChange(newValue);\r\n \r\n // Auto-advance\r\n if (char && index < length - 1) {\r\n refs.current[index + 1]?.focus();\r\n }\r\n \r\n if (newValue.length === length) {\r\n onComplete?.(newValue);\r\n }\r\n }, [chars, length, onChange, onComplete, type]);\r\n \r\n const handleKeyDown = useCallback((index: number, e: React.KeyboardEvent) => {\r\n if (e.key === 'Backspace') {\r\n if (!chars[index] && index > 0) {\r\n refs.current[index - 1]?.focus();\r\n const newChars = [...chars];\r\n newChars[index - 1] = '';\r\n onChange(newChars.join(''));\r\n }\r\n } else if (e.key === 'ArrowLeft' && index > 0) {\r\n refs.current[index - 1]?.focus();\r\n } else if (e.key === 'ArrowRight' && index < length - 1) {\r\n refs.current[index + 1]?.focus();\r\n }\r\n }, [chars, length, onChange]);\r\n \r\n const hasError = !!error;\r\n const errorMessage = typeof error === 'string' ? error : undefined;\r\n \r\n const inputBg = isTransparentTheme\r\n ? (tokens.colors.interactive.transparentInputBg || 'rgba(139, 92, 246, 0.08)')\r\n : tokens.colors.background.surface;\r\n \r\n const isOutlined = labelPlacement === 'outlined';\r\n const isFocused = focusedIndex !== null;\r\n \r\n // Background for the outlined label \"notch\"\r\n const labelBg = isTransparentTheme\r\n ? tokens.colors.background.base\r\n : tokens.colors.background.surface;\r\n \r\n // Outlined label font sizes\r\n const outlinedLabelSizeMap = { small: '0.625rem', medium: '0.6875rem', large: '0.75rem' };\r\n // Container always uses spacing.sm (8px) horizontal padding, so label left is always 8-6=2px\r\n const outlinedLabelLeftMap = { small: '2px', medium: '2px', large: '2px' };\r\n \r\n // Shared label content\r\n const labelContent = (\r\n <>\r\n {label}\r\n {required && (\r\n <span style={{ color: tokens.colors.status.critical, marginLeft: '2px' }}>*</span>\r\n )}\r\n </>\r\n );\r\n \r\n // Cells renderer: fullWidth = cells share space (same total width as standard inputs); otherwise fixed square cells\r\n const cellsEl = (\r\n <div style={{\r\n display: 'flex',\r\n gap: tokens.spacing.xs,\r\n width: fullWidth ? '100%' : undefined,\r\n }}>\r\n {Array.from({ length }, (_, i) => (\r\n <input\r\n key={i}\r\n ref={el => { refs.current[i] = el; }}\r\n type={mask ? 'password' : 'text'}\r\n inputMode={type === 'numeric' ? 'numeric' : 'text'}\r\n maxLength={1}\r\n value={chars[i] || ''}\r\n onChange={e => handleChange(i, e.target.value)}\r\n onKeyDown={e => handleKeyDown(i, e)}\r\n onFocus={() => setFocusedIndex(i)}\r\n onBlur={() => setFocusedIndex(null)}\r\n onPaste={e => {\r\n e.preventDefault();\r\n handleChange(i, e.clipboardData.getData('text'));\r\n }}\r\n disabled={disabled}\r\n aria-label={`Character ${i + 1} of ${length}`}\r\n aria-invalid={hasError || undefined}\r\n aria-describedby={errorMessage ? 'zendir-pin-error' : helperText ? 'zendir-pin-helper' : undefined}\r\n style={{\r\n ...(fullWidth ? { flex: 1, minWidth: 0 } : { width: controlHeight }),\r\n height: config.height,\r\n textAlign: 'center',\r\n fontSize: config.fontSize,\r\n fontWeight: tokens.typography.fontWeight.bold,\r\n fontFamily: tokens.typography.fontFamily.mono,\r\n fontVariantNumeric: 'tabular-nums',\r\n color: tokens.colors.text.primary,\r\n backgroundColor: isOutlined ? 'transparent' : inputBg,\r\n border: isOutlined ? 'none' : (\r\n hasError\r\n ? `${tokens.borders.width.medium} solid ${tokens.colors.status.critical}`\r\n : focusedIndex === i\r\n ? `${tokens.borders.width.medium} solid ${tokens.colors.accent.primary}`\r\n : chars[i]\r\n ? `${tokens.borders.width.medium} solid ${tokens.colors.border.default}`\r\n : `${tokens.borders.width.medium} solid ${tokens.colors.border.muted}`\r\n ),\r\n borderRadius: isOutlined ? 0 : tokens.borderRadius.md,\r\n outline: 'none',\r\n transition: tokens.animation.fast,\r\n opacity: disabled ? 0.5 : 1,\r\n cursor: disabled ? 'not-allowed' : 'text',\r\n ...(!isOutlined && focusedIndex === i ? {\r\n boxShadow: tokens.borders.focusRing.subtle,\r\n } : {}),\r\n }}\r\n />\r\n ))}\r\n </div>\r\n );\r\n \r\n return (\r\n <div style={{\r\n fontFamily: tokens.typography.fontFamily.primary,\r\n width: fullWidth ? '100%' : undefined,\r\n }}>\r\n {/* Label: 'above' variant */}\r\n {label && !isOutlined && (\r\n <div style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n fontWeight: tokens.typography.fontWeight.medium,\r\n color: tokens.colors.text.secondary,\r\n letterSpacing: tokens.typography.letterSpacing.wide,\r\n marginBottom: tokens.spacing.xs,\r\n }}>\r\n {labelContent}\r\n </div>\r\n )}\r\n \r\n {/* Outlined variant: wrap cells in a bordered container with the label on the border */}\r\n {isOutlined ? (\r\n <div style={{\r\n position: 'relative',\r\n width: fullWidth ? '100%' : undefined,\r\n minHeight: controlHeight,\r\n border: hasError\r\n ? tokens.borders.input.error\r\n : isFocused\r\n ? tokens.borders.input.focus\r\n : tokens.borders.input.default,\r\n borderRadius: tokens.borderRadius.md,\r\n padding: `0 ${tokens.spacing.sm}`,\r\n display: 'flex',\r\n alignItems: 'center',\r\n backgroundColor: inputBg,\r\n transition: tokens.animation.fast,\r\n boxSizing: 'border-box',\r\n ...(isFocused ? {\r\n boxShadow: tokens.borders.focusRing.subtle,\r\n } : {}),\r\n }}>\r\n {label && (\r\n <div style={{\r\n position: 'absolute',\r\n top: 0,\r\n left: outlinedLabelLeftMap[size],\r\n transform: 'translateY(-50%)',\r\n backgroundColor: labelBg,\r\n padding: `0 ${tokens.spacing.xs}`,\r\n fontSize: outlinedLabelSizeMap[size],\r\n fontWeight: tokens.typography.fontWeight.medium,\r\n color: isFocused\r\n ? (hasError ? tokens.colors.status.critical : tokens.colors.accent.primary)\r\n : hasError\r\n ? tokens.colors.status.critical\r\n : tokens.colors.text.secondary,\r\n letterSpacing: tokens.typography.letterSpacing.wide,\r\n zIndex: 1,\r\n pointerEvents: 'none',\r\n transition: tokens.animation.fast,\r\n lineHeight: 1.2,\r\n whiteSpace: 'nowrap',\r\n }}>\r\n {labelContent}\r\n </div>\r\n )}\r\n {cellsEl}\r\n </div>\r\n ) : (\r\n cellsEl\r\n )}\r\n \r\n {(helperText || errorMessage) && (\r\n <div\r\n id={errorMessage ? 'zendir-pin-error' : 'zendir-pin-helper'}\r\n role={errorMessage ? 'alert' : undefined}\r\n style={{\r\n fontSize: tokens.typography.fontSize.xs,\r\n color: hasError ? tokens.colors.status.critical : tokens.colors.text.tertiary,\r\n marginTop: tokens.spacing.xs,\r\n }}\r\n >\r\n {errorMessage || helperText}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n});\r\n\r\nexport default PinInput;\r\n"],"names":["PinInput","newValue"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, forwardRef, useState, useRef, useId, useLayoutEffect, useEffect } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
|
-
import { classNames } from "
|
|
5
|
-
import { useBreakpoint } from "
|
|
6
|
-
import { useTheme } from "
|
|
4
|
+
import { classNames } from "../../utils/index.js";
|
|
5
|
+
import { useBreakpoint } from "../layout/useBreakpoint.js";
|
|
6
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
7
7
|
const Select = memo(forwardRef(function Select2({
|
|
8
8
|
label,
|
|
9
9
|
options,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select.js","sources":["../../../../src/react/core/inputs/Select.tsx"],"sourcesContent":["/**\n * @zendir/ui - Select Component\n * \n * Dropdown select following Astro UX Design System.\n * \n * @example\n * ```tsx\n * <Select\n * label=\"Spacecraft\"\n * options={[\n * { value: 'sat-001', label: 'Explorer-1' },\n * { value: 'sat-002', label: 'Voyager-2' },\n * ]}\n * value={selected}\n * onChange={setSelected}\n * />\n * ```\n */\n\nimport React, { memo, forwardRef, useState, useId, useRef, useEffect, useLayoutEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTheme } from '../../theme';\nimport { classNames } from '../../utils';\nimport type { LabelPlacement } from './Input';\nimport { useBreakpoint } from '../layout/useBreakpoint';\n\nexport interface SelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps {\n /** Label text or ReactNode (supports rich content like tooltip icons) */\n label?: React.ReactNode;\n /** Options array */\n options: SelectOption[];\n /** Selected value */\n value?: string;\n /** Change handler */\n onChange?: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Helper text */\n helperText?: string;\n /** Error message */\n error?: string;\n /** Disabled state */\n disabled?: boolean;\n /** Full width */\n fullWidth?: boolean;\n /** Size variant */\n size?: 'small' | 'medium' | 'large';\n /** Custom className */\n className?: string;\n /**\n * Label placement style.\n * - `'outlined'` — label sits on the input border (notched/Material-style). **Default.**\n * - `'above'` — label sits above the input with a gap (classic stack).\n */\n labelPlacement?: LabelPlacement;\n /** Required indicator */\n required?: boolean;\n}\n\nexport const Select = memo(forwardRef<HTMLDivElement, SelectProps>(function Select(\n {\n label,\n options,\n value,\n onChange,\n placeholder = 'Select...',\n helperText,\n error,\n disabled = false,\n fullWidth = false,\n size = 'medium',\n className = '',\n labelPlacement = 'outlined',\n required,\n },\n ref\n): React.ReactElement {\n const { tokens, theme } = useTheme();\n const { isMobile } = useBreakpoint();\n const [isOpen, setIsOpen] = useState(false);\n const [focused, setFocused] = useState(false);\n const [dropdownRect, setDropdownRect] = useState<{ top: number; left: number; width: number; openUp?: boolean } | null>(null);\n const selectRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const dropdownRef = useRef<HTMLUListElement>(null);\n const generatedId = useId();\n \n // Transparent theme detection (purple-hue transparent bg)\n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n const _transparentDefault = tokens.colors.interactive.transparentDefault;\n const _transparentInputBg = tokens.colors.interactive.transparentInputBg;\n \n const hasError = !!error;\n const selectedOption = options.find(o => o.value === value);\n const isOutlined = labelPlacement === 'outlined';\n \n const sizeConfig = {\n small: { height: tokens.elementSize.sm, fontSize: tokens.typography.fontSize.xs, padding: tokens.spacing.sm, inputPaddingLeft: 8 },\n medium: { height: tokens.elementSize.md, fontSize: tokens.typography.fontSize.sm, padding: tokens.spacing.md, inputPaddingLeft: 16 },\n large: { height: tokens.elementSize.lg, fontSize: tokens.typography.fontSize.base, padding: tokens.spacing.lg, inputPaddingLeft: 24 },\n };\n const config = sizeConfig[size];\n const controlHeight = isMobile ? '44px' : config.height;\n const optionRowHeight = isMobile\n ? 40\n : (size === 'small' ? 30 : size === 'medium' ? 34 : 38);\n \n // Position dropdown when open (for portal) - keep in viewport\n const DROPDOWN_MAX_HEIGHT = 200;\n const GAP = 4;\n useLayoutEffect(() => {\n if (!isOpen || !triggerRef.current) {\n setDropdownRect(null);\n return;\n }\n const update = () => {\n if (triggerRef.current) {\n const rect = triggerRef.current.getBoundingClientRect();\n const spaceBelow = window.innerHeight - rect.bottom - GAP;\n const spaceAbove = rect.top - GAP;\n const openUp = spaceBelow < Math.min(DROPDOWN_MAX_HEIGHT, options.length * optionRowHeight) && spaceAbove > spaceBelow;\n setDropdownRect({\n top: openUp ? rect.top - GAP : rect.bottom + GAP,\n left: rect.left,\n width: rect.width,\n openUp,\n });\n }\n };\n update();\n window.addEventListener('scroll', update, true);\n window.addEventListener('resize', update);\n return () => {\n window.removeEventListener('scroll', update, true);\n window.removeEventListener('resize', update);\n };\n }, [isOpen, options.length, optionRowHeight]);\n\n // Close dropdown on outside click (include portaled dropdown)\n useEffect(() => {\n if (!isOpen) return;\n \n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n // Check if click is inside the trigger or the portaled dropdown\n if (\n selectRef.current?.contains(target) ||\n dropdownRef.current?.contains(target)\n ) {\n return;\n }\n setIsOpen(false);\n };\n // Use click instead of mousedown to avoid race condition with option onClick\n document.addEventListener('click', handleClickOutside, true);\n return () => document.removeEventListener('click', handleClickOutside, true);\n }, [isOpen]);\n \n const computedBorder = hasError\n ? tokens.borders.input.error\n : focused || isOpen\n ? tokens.borders.input.focus\n : tokens.borders.input.default;\n \n // Background for the outlined label \"notch\"\n const labelBg = isTransparentTheme\n ? tokens.colors.background.base\n : tokens.colors.background.surface;\n \n // Outlined label font sizes\n const outlinedLabelSizeMap = { small: '0.625rem', medium: '0.6875rem', large: '0.75rem' };\n const outlinedLabelLeftMap = { small: '2px', medium: '10px', large: '18px' };\n \n // Shared label content\n const labelContent = (\n <>\n {label}\n {required && (\n <span style={{ color: tokens.colors.status.critical, marginLeft: '2px' }}>*</span>\n )}\n </>\n );\n\n return (\n <div\n ref={ref}\n className={classNames('zendir-select-wrapper', className)}\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: tokens.spacing.xs,\n width: fullWidth ? '100%' : undefined,\n }}\n >\n {/* Label: 'above' variant */}\n {label && !isOutlined && (\n <span\n id={`${generatedId}-label`}\n style={{\n fontSize: tokens.typography.fontSize.xs,\n fontWeight: tokens.typography.fontWeight.medium,\n color: tokens.colors.text.secondary,\n }}\n >\n {labelContent}\n </span>\n )}\n \n <div ref={selectRef} style={{ position: 'relative' }}>\n {/* Label: 'outlined' variant — positioned on the trigger border */}\n {label && isOutlined && (\n <span\n id={`${generatedId}-label`}\n style={{\n position: 'absolute',\n top: 0,\n left: outlinedLabelLeftMap[size],\n transform: 'translateY(-50%)',\n backgroundColor: labelBg,\n padding: `0 ${tokens.spacing.xs}`,\n fontSize: outlinedLabelSizeMap[size],\n fontWeight: tokens.typography.fontWeight.medium,\n color: focused || isOpen\n ? (hasError ? tokens.colors.status.critical : tokens.colors.accent.primary)\n : hasError\n ? tokens.colors.status.critical\n : tokens.colors.text.secondary,\n zIndex: 1,\n pointerEvents: 'none',\n transition: `color ${tokens.animation.fast}`,\n lineHeight: 1.2,\n whiteSpace: 'nowrap',\n letterSpacing: '0.01em',\n }}\n >\n {labelContent}\n </span>\n )}\n \n <button\n ref={triggerRef}\n type=\"button\"\n disabled={disabled}\n onClick={() => !disabled && setIsOpen(!isOpen)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-labelledby={label ? `${generatedId}-label` : undefined}\n aria-describedby={(helperText || error) ? `${generatedId}-hint` : undefined}\n style={{\n width: '100%',\n height: controlHeight,\n padding: `0 ${config.padding}`,\n fontSize: config.fontSize,\n fontFamily: tokens.typography.fontFamily.primary,\n color: selectedOption ? tokens.colors.text.primary : tokens.colors.text.muted,\n backgroundColor: isTransparentTheme ? 'rgba(10, 15, 25, 0.4)' : tokens.colors.background.surface,\n border: computedBorder,\n borderRadius: tokens.borderRadius.md,\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n textAlign: 'left',\n outline: 'none',\n transition: `border-color ${tokens.animation.fast}`,\n boxShadow: focused || isOpen ? tokens.borders.focusRing.default : 'none',\n }}\n >\n <span>{selectedOption?.label ?? placeholder}</span>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill={tokens.colors.text.muted}\n style={{\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0)',\n transition: `transform ${tokens.animation.fast}`,\n }}\n >\n <path d=\"M7 10l5 5 5-5z\" />\n </svg>\n </button>\n \n {isOpen && dropdownRect &&\n createPortal(\n <ul\n ref={dropdownRef}\n role=\"listbox\"\n style={{\n position: 'fixed',\n top: dropdownRect.openUp ? undefined : dropdownRect.top,\n bottom: dropdownRect.openUp ? window.innerHeight - dropdownRect.top : undefined,\n left: dropdownRect.left,\n width: dropdownRect.width,\n padding: tokens.spacing.xs,\n backgroundColor: isTransparentTheme ? 'rgba(139, 92, 246, 0.12)' : tokens.colors.background.elevated,\n backdropFilter: isTransparentTheme ? 'blur(12px)' : undefined,\n WebkitBackdropFilter: isTransparentTheme ? 'blur(12px)' : undefined,\n border: tokens.borders.dropdown,\n borderRadius: tokens.borderRadius.md,\n boxShadow: `${tokens.shadows.lg}, 0 0 30px ${tokens.colors.accent.primary}10`,\n zIndex: 10000,\n maxHeight: '200px',\n overflowY: 'auto',\n listStyle: 'none',\n margin: 0,\n animation: `zendir-dropdown ${tokens.animation.duration.normal}ms ${tokens.animation.easing.default} both`,\n }}\n >\n <style>{`@keyframes zendir-dropdown { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }`}</style>\n {options.map((option) => (\n <li\n key={option.value}\n role=\"option\"\n aria-selected={option.value === value}\n tabIndex={option.disabled ? -1 : 0}\n onMouseDown={(e) => {\n // Prevent the document click handler from firing before we process this\n e.stopPropagation();\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (!option.disabled) {\n onChange?.(option.value);\n setIsOpen(false);\n }\n }}\n onKeyDown={(e) => {\n if (option.disabled) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onChange?.(option.value);\n setIsOpen(false);\n }\n }}\n style={{\n padding: `0 ${tokens.spacing.md}`,\n height: optionRowHeight,\n minHeight: optionRowHeight,\n display: 'flex',\n alignItems: 'center',\n fontSize: config.fontSize,\n lineHeight: 1.2,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: option.disabled ? tokens.colors.text.muted : tokens.colors.text.primary,\n backgroundColor: option.value === value ? `${tokens.colors.accent.primary}15` : 'transparent',\n borderRadius: tokens.borderRadius.sm,\n cursor: option.disabled ? 'not-allowed' : 'pointer',\n opacity: option.disabled ? 0.5 : 1,\n transition: `background-color ${tokens.animation.fast}`,\n }}\n onMouseEnter={(e) => {\n if (!option.disabled) {\n e.currentTarget.style.backgroundColor = `${tokens.colors.accent.primary}10`;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n option.value === value ? `${tokens.colors.accent.primary}15` : 'transparent';\n }}\n >\n {option.label}\n </li>\n ))}\n </ul>,\n document.body\n )}\n </div>\n \n {(helperText || error) && (\n <span\n id={`${generatedId}-hint`}\n role={hasError ? 'alert' : undefined}\n style={{\n fontSize: tokens.typography.fontSize.xs,\n color: hasError ? tokens.colors.status.critical : tokens.colors.text.muted,\n }}\n >\n {error || helperText}\n </span>\n )}\n </div>\n );\n}));\n\nexport default Select;\n"],"names":["Select"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, forwardRef, useState, useId } from "react";
|
|
3
|
-
import { classNames } from "
|
|
4
|
-
import { useTheme } from "
|
|
3
|
+
import { classNames } from "../../utils/index.js";
|
|
4
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
5
|
const Toggle = memo(forwardRef(function Toggle2({
|
|
6
6
|
checked = false,
|
|
7
7
|
onChange,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toggle.js","sources":["../../../../src/react/core/inputs/Toggle.tsx"],"sourcesContent":["/**\n * @zendir/ui - Toggle/Switch Component\n * \n * Toggle switch following Astro UX Design System with Zendir purple accents.\n * \n * Astro UX Compliance:\n * - Binary on/off control\n * - Clear visual states\n * - Accessible keyboard support\n * \n * Zendir Enhancements:\n * - Purple accent when active\n * - Subtle glow effect\n * - Smooth spring animation\n * \n * @example\n * ```tsx\n * <Toggle checked={enabled} onChange={setEnabled} label=\"Enable telemetry\" />\n * ```\n */\n\nimport React, { memo, forwardRef, useId, useState } from 'react';\nimport { useTheme } from '../../theme';\nimport { classNames } from '../../utils';\n\nexport interface ToggleProps {\n /** Checked state */\n checked?: boolean;\n /** Change handler */\n onChange?: (checked: boolean) => void;\n /** Label text */\n label?: string;\n /** Label position */\n labelPosition?: 'left' | 'right';\n /** Disabled state */\n disabled?: boolean;\n /** Size variant */\n size?: 'small' | 'medium';\n /** Custom className */\n className?: string;\n /** Name attribute */\n name?: string;\n}\n\nexport const Toggle = memo(forwardRef<HTMLInputElement, ToggleProps>(function Toggle(\n {\n checked = false,\n onChange,\n label,\n labelPosition = 'right',\n disabled = false,\n size = 'medium',\n className = '',\n name,\n },\n ref\n): React.ReactElement {\n const { tokens, theme } = useTheme();\n const [focused, setFocused] = useState(false);\n const [hovered, setHovered] = useState(false);\n const id = useId();\n \n const sizeConfig = {\n small: { width: 34, height: 18, knobSize: 14 },\n medium: { width: 40, height: 22, knobSize: 16 },\n };\n const config = sizeConfig[size];\n // Touch target: 44px minimum via padding around the visual toggle\n const touchPadV = Math.max(0, (44 - config.height) / 2);\n const touchPadH = Math.max(0, (44 - config.width) / 2);\n \n const handleClick = () => {\n if (!disabled) {\n onChange?.(!checked);\n }\n };\n \n const isTransparentTheme = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n const transparentDefault = tokens.colors.interactive.transparentDefault;\n const transparentHover = tokens.colors.interactive.transparentHover;\n const bgColor = checked\n ? tokens.colors.accent.primary\n : isTransparentTheme && transparentDefault && transparentHover\n ? (hovered && !disabled ? transparentHover : transparentDefault)\n : hovered && !disabled\n ? `${tokens.colors.border.muted}`\n : tokens.colors.border.muted;\n \n const toggle = (\n <div\n role=\"switch\"\n aria-checked={checked}\n aria-disabled={disabled}\n aria-label={!label ? (name ?? 'Toggle') : undefined}\n tabIndex={disabled ? -1 : 0}\n onClick={handleClick}\n onKeyDown={(e) => (e.key === ' ' || e.key === 'Enter') && (e.preventDefault(), handleClick())}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n style={{\n padding: `${touchPadV}px ${touchPadH}px`,\n cursor: disabled ? 'not-allowed' : 'pointer',\n flexShrink: 0,\n outline: 'none',\n display: 'inline-flex',\n alignItems: 'center',\n }}\n >\n <div\n style={{\n width: config.width,\n height: config.height,\n backgroundColor: bgColor,\n ...(isTransparentTheme && !checked && { backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)' }),\n borderRadius: config.height / 2,\n opacity: disabled ? 0.5 : 1,\n position: 'relative',\n transition: `${tokens.animation.normal}, opacity ${tokens.animation.duration.normal}ms ${tokens.animation.easing.default}`,\n flexShrink: 0,\n boxShadow: checked \n ? `0 0 10px ${tokens.colors.accent.primary}25, inset 0 1px 1px rgba(255,255,255,0.08)` \n : focused \n ? `0 0 0 2px ${tokens.colors.accent.primary}25` \n : 'inset 0 1px 2px rgba(0,0,0,0.15)',\n }}\n >\n <div\n style={{\n position: 'absolute',\n top: (config.height - config.knobSize) / 2,\n left: checked ? config.width - config.knobSize - 3 : 3,\n width: config.knobSize,\n height: config.knobSize,\n backgroundColor: '#ffffff',\n borderRadius: '50%',\n boxShadow: checked \n ? '0 1px 4px rgba(0,0,0,0.25)' \n : '0 1px 3px rgba(0,0,0,0.2)',\n transition: tokens.animation.spring,\n transform: hovered && !disabled ? 'scale(1.05)' : 'scale(1)',\n }}\n />\n </div>\n <input\n ref={ref}\n type=\"checkbox\"\n id={id}\n name={name}\n checked={checked}\n disabled={disabled}\n onChange={() => {}}\n tabIndex={-1}\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n opacity: 0,\n width: 0,\n height: 0,\n pointerEvents: 'none',\n }}\n />\n </div>\n );\n \n if (!label) {\n return (\n <div className={classNames('zendir-toggle', className)}>\n {toggle}\n </div>\n );\n }\n \n return (\n <label\n htmlFor={id}\n className={classNames('zendir-toggle', className)}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: tokens.spacing.sm,\n cursor: disabled ? 'not-allowed' : 'pointer',\n flexDirection: labelPosition === 'left' ? 'row-reverse' : 'row',\n }}\n >\n {toggle}\n <span\n style={{\n fontSize: tokens.typography.fontSize.sm,\n color: disabled ? tokens.colors.text.muted : tokens.colors.text.primary,\n }}\n >\n {label}\n </span>\n </label>\n );\n}));\n\nexport default Toggle;\n"],"names":["Toggle"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React, { memo, useState, useRef, useEffect, useMemo } from "react";
|
|
3
|
-
import { useDisplaySettingsOptional } from "
|
|
4
|
-
import { classNames, safeAccentText } from "
|
|
5
|
-
import { AstroIcon } from "
|
|
6
|
-
import { ColorPickerPanel } from "
|
|
7
|
-
import { Tooltip } from "
|
|
8
|
-
import { useBreakpoint } from "
|
|
9
|
-
import { useTheme } from "
|
|
3
|
+
import { useDisplaySettingsOptional } from "../../context/DisplaySettingsContext.js";
|
|
4
|
+
import { classNames, safeAccentText } from "../../utils/index.js";
|
|
5
|
+
import { AstroIcon } from "../display/AstroIcon.js";
|
|
6
|
+
import { ColorPickerPanel } from "../widgets/ColorPickerPanel.js";
|
|
7
|
+
import { Tooltip } from "../overlays/Tooltip.js";
|
|
8
|
+
import { useBreakpoint } from "../layout/useBreakpoint.js";
|
|
9
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
10
10
|
const THEME_VARIANTS = [
|
|
11
11
|
{ key: "hybrid", label: "Zen (Hybrid)", tooltip: "Default theme - Astro status colors with purple accents" },
|
|
12
12
|
{ key: "purple-hue", label: "Zen (Purple Hue)", tooltip: "Purple accent theme - vibrant purple tones" },
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppBar.js","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, { memo, useMemo, useState, useRef, useEffect, type ReactNode } 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 { key: 'hybrid', label: 'Zen (Hybrid)', tooltip: 'Default theme - Astro status colors with purple accents' },\n { key: 'purple-hue', label: 'Zen (Purple Hue)', tooltip: 'Purple accent theme - vibrant purple tones' },\n { key: 'astro', label: 'Astro', tooltip: 'Astro UX Design System theme - dark blue tones' },\n { key: 'transparent', label: 'Glass', tooltip: 'Glassmorphism theme - transparent with blur effects' },\n { key: 'transparent-bold', label: 'Bold', tooltip: 'Bold glass theme - stronger transparency effects' },\n { key: 'transparent-minimal', label: 'Minimal', tooltip: 'Minimal glass theme - ultra-subtle borders, clean surfaces' },\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({ mode, onToggle, tokens }: 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({ isCompact, onToggle, tokens }: CompactToggleProps) {\n const tooltipText = isCompact ? 'Switch to Expanded View' : '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 ? 'rgba(139, 92, 246, 0.25)' : 'rgba(255,255,255,0.08)',\n color: isCompact ? '#a78bfa' : tokens.colors.text.primary,\n cursor: 'pointer',\n transition: 'all 0.15s ease',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isCompact \n ? 'rgba(139, 92, 246, 0.35)' \n : 'rgba(255,255,255,0.15)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = isCompact \n ? 'rgba(139, 92, 246, 0.25)' \n : 'rgba(255,255,255,0.08)';\n }}\n >\n <AstroIcon \n name={isCompact ? 'view-comfy' : 'view-module'} \n size={16} \n color={isCompact ? '#a78bfa' : tokens.colors.text.primary}\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({ currentTheme, onSelect, tokens }: 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) => 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 = 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(t => !t.key.startsWith('transparent'));\n const glassThemes = THEME_VARIANTS.filter(t => t.key.startsWith('transparent'));\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: currentTheme === key \n ? safeAccentBg \n : 'transparent',\n color: currentTheme === key \n ? '#ffffff' \n : 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 = currentTheme === key \n ? safeAccentBg \n : 'transparent';\n }}\n >\n {label}\n </button>\n </Tooltip>\n ))}\n \n {/* Separator */}\n <div style={{ width: 1, height: 16, backgroundColor: 'rgba(255,255,255,0.15)', margin: '0 2px' }} />\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: currentTheme === key \n ? safeAccentBg \n : 'transparent',\n color: currentTheme === key \n ? '#ffffff' \n : 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 = currentTheme === key \n ? safeAccentBg \n : '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({ enabled, onToggle, tokens }: AccentBordersToggleProps) {\n return (\n <Tooltip content={enabled ? 'Accent borders enabled - Click to disable' : 'Accent borders disabled - Click to enable'} placement=\"bottom\">\n <button\n onClick={onToggle}\n aria-label={enabled ? 'Disable accent borders' : 'Enable accent borders'}\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 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 <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 (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n \n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n \n // Get current theme label\n const currentLabel = THEME_VARIANTS.find(t => t.key === currentTheme)?.label || 'Theme';\n \n // Group themes\n const coreThemes = THEME_VARIANTS.filter(t => !t.key.startsWith('transparent'));\n const glassThemes = THEME_VARIANTS.filter(t => t.key.startsWith('transparent'));\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 ? tokens.colors.background.elevated : '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 = tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n if (!isOpen) {\n e.currentTarget.style.backgroundColor = 'transparent';\n }\n }}\n >\n <AstroIcon name=\"settings\" size={14} color={tokens.colors.text.secondary} />\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 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 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: currentTheme === key \n ? `${tokens.colors.accent.primary}20`\n : 'transparent',\n color: 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 = tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = currentTheme === key \n ? `${tokens.colors.accent.primary}20`\n : 'transparent';\n }}\n >\n {currentTheme === key && (\n <AstroIcon name=\"check\" size={12} color={tokens.colors.accent.primary} />\n )}\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>{label}</span>\n </button>\n ))}\n </div>\n \n {/* Separator */}\n <div style={{ \n height: 1, \n backgroundColor: tokens.colors.border.muted, \n margin: `${tokens.spacing.xs} 0`,\n }} />\n \n {/* Glass Themes */}\n <div 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 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: currentTheme === key \n ? `${tokens.colors.accent.primary}20`\n : 'transparent',\n color: 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 = tokens.colors.background.elevated;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = currentTheme === key \n ? `${tokens.colors.accent.primary}20`\n : 'transparent';\n }}\n >\n {currentTheme === key && (\n <AstroIcon name=\"check\" size={12} color={tokens.colors.accent.primary} />\n )}\n <span style={{ marginLeft: currentTheme === key ? 0 : 20 }}>{label}</span>\n </button>\n ))}\n </div>\n </div>\n \n {/* Separator */}\n <div style={{ \n height: 1, \n backgroundColor: tokens.colors.border.muted, \n margin: `${tokens.spacing.sm} 0`,\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 = 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 style={{\n width: 32,\n height: 18,\n borderRadius: 9,\n backgroundColor: mode === 'dark' ? tokens.colors.accent.primary : tokens.colors.border.default,\n padding: 2,\n transition: 'all 0.15s ease',\n }}>\n <div style={{\n width: 14,\n height: 14,\n borderRadius: '50%',\n backgroundColor: '#fff',\n transition: 'all 0.15s ease',\n transform: mode === 'dark' ? 'translateX(14px)' : 'translateX(0)',\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 = 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 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 {accentBordersEnabled && (\n <AstroIcon name=\"check\" size={10} color={tokens.colors.text.secondary} />\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({ title, tokens }: SectionHeaderProps) {\n return (\n <div style={{ textAlign: 'center', marginBottom: tokens.spacing.xs }}>\n <span style={{\n fontSize: tokens.typography.fontSize.xxs,\n fontFamily: tokens.typography.fontFamily.primary,\n color: tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\n fontWeight: tokens.typography.fontWeight.bold,\n }}>\n {title}\n </span>\n <div style={{\n width: '100%',\n height: tokens.borders.width.thin,\n background: tokens.colors.interactive?.default ?? tokens.colors.text.secondary,\n opacity: 0.5,\n marginTop: tokens.spacing.xs,\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 = theme === 'transparent' || theme === 'transparent-bold' || theme === 'transparent-minimal';\n \n // Get compact mode from context or default\n const compactMode = 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 ? tokens.spacing.xs : tokens.spacing.sm)\n : (isMobile ? tokens.spacing.md : tokens.spacing.lg);\n const paddingV = isDense ? tokens.spacing.xs : 0;\n const gap = isDense ? (isMobile ? tokens.spacing.sm : tokens.spacing.md) : 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 href={branding.href} style={{ display: 'flex', alignItems: 'center', textDecoration: 'none' }}>\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 href={branding.href} style={{ display: 'flex', alignItems: 'center', textDecoration: 'none' }}>\n {img}\n </a>\n );\n }\n return img;\n }\n \n // Text branding\n return (\n <div style={{ display: 'flex', alignItems: 'baseline', gap: tokens.spacing.sm }}>\n {appDomain && (\n <span 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 {appDomain}\n </span>\n )}\n <span style={{\n fontSize: tokens.typography.fontSize.lg,\n fontWeight: 500, // AstroUXDS medium for app title\n color: tokens.colors.text.primary,\n }}>\n {appName}\n </span>\n {appVersion && (\n <span style={{\n fontSize: tokens.typography.fontSize.xs,\n color: tokens.colors.text.tertiary,\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 style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flexShrink: 0 }}>\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 && !showModeOnly && isTransparentTheme && 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"],"names":["ModeToggle","CompactToggle","ThemeSelector","AccentBordersToggle","ThemeControlsDropdown","SectionHeader","AppBar"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useMemo } from "react";
|
|
3
|
-
import { classNames } from "
|
|
4
|
-
import { useTheme } from "
|
|
3
|
+
import { classNames } from "../../utils/index.js";
|
|
4
|
+
import { useTheme } from "../../theme/ThemeProvider.js";
|
|
5
5
|
const Pagination = memo(function Pagination2({
|
|
6
6
|
currentPage,
|
|
7
7
|
totalPages,
|