@persona/design-system 0.10.5 → 0.10.6
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 +15 -0
- package/dist/Badge-8YzapjWf.mjs.map +1 -1
- package/dist/Breadcrumbs-Dft2TR4v.mjs.map +1 -1
- package/dist/Card-DuQHyroh.mjs.map +1 -1
- package/dist/CardV2-BRJbRSts.mjs.map +1 -1
- package/dist/Checkbox-Dr4LMKHV.mjs.map +1 -1
- package/dist/{CheckboxGroupField-UHpA38U5.d.mts → CheckboxGroupField-CjeEoiPa.d.mts} +2 -2
- package/dist/CheckboxGroupField.d.mts +1 -1
- package/dist/Combobox-DQxaOCLA.mjs.map +1 -1
- package/dist/{Combobox-BXkcQ2aY.d.mts → Combobox-O6LbofT2.d.mts} +3 -3
- package/dist/Combobox.d.mts +2 -2
- package/dist/{ComboboxBase-D2rDQHYZ.d.mts → ComboboxBase-5aSDuY-E.d.mts} +2 -2
- package/dist/ComboboxBase.d.mts +1 -1
- package/dist/{ComboboxMultiSelect-CrvB6ap5.d.mts → ComboboxMultiSelect-D3mX4Dzq.d.mts} +2 -2
- package/dist/ComboboxMultiSelect.d.mts +1 -1
- package/dist/{ComboboxSingleSelect-Dp0iTdDO.d.mts → ComboboxSingleSelect-CfSy6sCU.d.mts} +3 -3
- package/dist/ComboboxSingleSelect.d.mts +1 -1
- package/dist/{DataTable-C000E74h.d.mts → DataTable-BXHmi-SW.d.mts} +7 -6
- package/dist/{DataTable-DEJHWrsy.mjs → DataTable-CAfZNJmb.mjs} +8 -7
- package/dist/DataTable-CAfZNJmb.mjs.map +1 -0
- package/dist/DataTable.d.mts +1 -1
- package/dist/DatePicker-D-_ibUd1.mjs.map +1 -1
- package/dist/DropdownButton-BiFRlSVD.mjs.map +1 -1
- package/dist/DropdownButton.d.mts +1 -1
- package/dist/{DropdownMenu-CQbS7ML5.d.mts → DropdownMenu-CAYVX9Q3.d.mts} +2 -2
- package/dist/DropdownMenu-Q8S-9rXm.mjs.map +1 -1
- package/dist/DropdownMenu.d.mts +1 -1
- package/dist/FormControl-BztNXLn6.mjs.map +1 -1
- package/dist/{FormField-g1zQFM9T.mjs → FormField-BStxmlZT.mjs} +2 -2
- package/dist/FormField-BStxmlZT.mjs.map +1 -0
- package/dist/{FormField-PBo1ctY8.d.mts → FormField-D10LW9-a.d.mts} +2 -2
- package/dist/FormField.d.mts +1 -1
- package/dist/HoverCopyableField-CW7Jxmni.mjs.map +1 -1
- package/dist/{I18nContext-EPmbUprm.d.mts → I18nContext-BBVKF9ui.d.mts} +2 -2
- package/dist/I18nContext.d.mts +1 -1
- package/dist/IconButton-DftINsp7.mjs.map +1 -1
- package/dist/IndexTableLayout.d.mts +3 -3
- package/dist/InlineCombobox.d.mts +1 -1
- package/dist/InlineInput.d.mts +1 -1
- package/dist/Input-DtO3qMnE.mjs.map +1 -1
- package/dist/Link-DKYmdL9t.mjs.map +1 -1
- package/dist/ListBox-CDG0EAPg.mjs.map +1 -1
- package/dist/{ListBox-D9SYTzOd.d.mts → ListBox-CvnFiHK5.d.mts} +2 -2
- package/dist/ListBox.d.mts +1 -1
- package/dist/{ListBoxField-CtPDd_Aw.d.mts → ListBoxField-DuUwx9Cv.d.mts} +4 -4
- package/dist/ListBoxField.d.mts +1 -1
- package/dist/LoadingShimmer-oPIv2ESr.mjs.map +1 -1
- package/dist/{LogicRow-BWIZ7262.d.mts → LogicRow-COvZNiUd.d.mts} +2 -2
- package/dist/LogicRow.d.mts +1 -1
- package/dist/{Menu-DizjcMbO.d.mts → Menu-ByYFNvgS.d.mts} +2 -2
- package/dist/Menu-EIT_MwK6.mjs.map +1 -1
- package/dist/Menu.d.mts +1 -1
- package/dist/{Modal-92O_uW8H.mjs → Modal-ziuzDCPN.mjs} +2 -2
- package/dist/Modal-ziuzDCPN.mjs.map +1 -0
- package/dist/PageHeader-BzvA_NNt.mjs.map +1 -1
- package/dist/PageLayout-DCe3F76N.mjs.map +1 -1
- package/dist/{PageSelector-QaKYtk6y.d.mts → PageSelector-BOe4EzbS.d.mts} +8 -2
- package/dist/PageSelector.d.mts +1 -1
- package/dist/{Pagination-dTsHLVAk.mjs → Pagination-Dpc6TadZ.mjs} +15 -11
- package/dist/Pagination-Dpc6TadZ.mjs.map +1 -0
- package/dist/{Pagination-DeXorbSK.d.mts → Pagination-Dy-OSH0Y.d.mts} +10 -2
- package/dist/Pagination.d.mts +1 -1
- package/dist/Popover-DordjYNM.mjs.map +1 -1
- package/dist/ProgressIndicator-ISARECzW.mjs.map +1 -1
- package/dist/Radio-BlEtetrr.mjs.map +1 -1
- package/dist/RadioGroup-CMrXmmn4.mjs.map +1 -1
- package/dist/SegmentedControl-D_DA-MU1.mjs.map +1 -1
- package/dist/{Select-Chk5WB1F.d.mts → Select-BLqHxJUz.d.mts} +2 -2
- package/dist/Select-DkUMz4LG.mjs.map +1 -1
- package/dist/Select.d.mts +1 -1
- package/dist/SmartTextInputField.d.mts +2 -2
- package/dist/Spacer-C4d9Aho6.mjs.map +1 -1
- package/dist/Spinner-CXb-KUs1.mjs.map +1 -1
- package/dist/StatusIndicator-pWl1-FLb.mjs.map +1 -1
- package/dist/Sticker-Bi_fezCO.mjs.map +1 -1
- package/dist/TabBar-DpXYsWgS.mjs.map +1 -1
- package/dist/Table-DPi4Dt5H.mjs.map +1 -1
- package/dist/TableBox-BfSF36Gy.mjs.map +1 -1
- package/dist/TableBox.d.mts +1 -1
- package/dist/{TableBoxCell-CwroLAWy.d.mts → TableBoxCell-DPXrw63v.d.mts} +4 -4
- package/dist/TableBoxCell.d.mts +1 -1
- package/dist/{TableBoxField-B7bHv7uV.d.mts → TableBoxField-C7MGSie9.d.mts} +5 -5
- package/dist/TableBoxField.d.mts +1 -1
- package/dist/{TableBoxRow-Dke8B99J.d.mts → TableBoxRow-uToXVWvl.d.mts} +2 -2
- package/dist/TableBoxRow.d.mts +1 -1
- package/dist/{TableBoxRowActions-CkUDVERC.d.mts → TableBoxRowActions-Do646IVE.d.mts} +2 -2
- package/dist/TableBoxRowActions.d.mts +1 -1
- package/dist/{TableControls-DAjx1TYG.d.mts → TableControls-BHv-tXA-.d.mts} +4 -3
- package/dist/{TableControls-BDXOQMr7.mjs → TableControls-C-0Dw8vM.mjs} +7 -5
- package/dist/TableControls-C-0Dw8vM.mjs.map +1 -0
- package/dist/TableControls.d.mts +1 -1
- package/dist/{TableControlsContext-BEIvE9qN.d.mts → TableControlsContext-D6rifk-v.d.mts} +2 -2
- package/dist/TableControlsContext.d.mts +1 -1
- package/dist/{TableViewConfigurationDropdown-vYnU0d4k.d.mts → TableViewConfigurationDropdown-C5bjxTGX.d.mts} +2 -2
- package/dist/TableViewConfigurationDropdown.d.mts +1 -1
- package/dist/TechnicalSticker-B_JlBkXZ.mjs.map +1 -1
- package/dist/Text-D0vEReED.mjs.map +1 -1
- package/dist/TextArea-Dro-HH8O.mjs.map +1 -1
- package/dist/Toggle-D9MzTIZs.mjs.map +1 -1
- package/dist/Tooltip-YViXzMdm.mjs.map +1 -1
- package/dist/{clientFilterUtils-DYKgw2Yq.d.mts → clientFilterUtils-DDDG1g7e.d.mts} +2 -2
- package/dist/clientFilterUtils.d.mts +1 -1
- package/dist/components/Accordion/index.mjs.map +1 -1
- package/dist/components/Attribute/index.mjs.map +1 -1
- package/dist/components/Banner/index.mjs.map +1 -1
- package/dist/components/BottomPanel/index.mjs.map +1 -1
- package/dist/components/ButtonGroup/index.mjs.map +1 -1
- package/dist/components/CodeHighlight/index.mjs.map +1 -1
- package/dist/components/Combobox/index.d.mts +2 -2
- package/dist/components/DataTable/TableControls/index.d.mts +6 -6
- package/dist/components/DataTable/TableControls/index.mjs +1 -1
- package/dist/components/DataTable/index.d.mts +5 -5
- package/dist/components/DataTable/index.mjs +1 -1
- package/dist/components/DataTable/types.d.mts +1 -1
- package/dist/components/DropdownMenu/index.d.mts +1 -1
- package/dist/components/FloatingPanel/index.mjs.map +1 -1
- package/dist/components/FormField/index.d.mts +5 -5
- package/dist/components/FormField/index.mjs +1 -1
- package/dist/components/ImageTile/index.mjs.map +1 -1
- package/dist/components/ListBox/index.d.mts +3 -3
- package/dist/components/MaskedInput/index.mjs.map +1 -1
- package/dist/components/MatchHighlight/index.mjs.map +1 -1
- package/dist/components/Menu/index.d.mts +1 -1
- package/dist/components/Modal/index.mjs +1 -1
- package/dist/components/Pagination/index.d.mts +2 -2
- package/dist/components/Pagination/index.mjs +1 -1
- package/dist/components/ProgressBar/index.mjs.map +1 -1
- package/dist/components/RichTextEditor/index.mjs +1 -1
- package/dist/components/RichTextEditor/index.mjs.map +1 -1
- package/dist/components/RightPanel/index.mjs.map +1 -1
- package/dist/components/Select/index.d.mts +1 -1
- package/dist/components/SelectionCard/index.mjs.map +1 -1
- package/dist/components/Slider/index.mjs.map +1 -1
- package/dist/components/SmartTextInput/index.mjs +1 -1
- package/dist/components/SmartTextInput/index.mjs.map +1 -1
- package/dist/components/SwatchPicker/index.mjs.map +1 -1
- package/dist/components/TableBox/index.d.mts +1 -1
- package/dist/components/Tile/index.mjs.map +1 -1
- package/dist/components/Toast/index.mjs.map +1 -1
- package/dist/components/VersionHistory/index.mjs +1 -1
- package/dist/components/VersionHistory/index.mjs.map +1 -1
- package/dist/display.d.mts +1 -1
- package/dist/fieldPickerOptions.d.mts +1 -1
- package/dist/{filters-DjXkx8GJ.d.mts → filters-CkAFU8LV.d.mts} +2 -2
- package/dist/filters.d.mts +1 -1
- package/dist/{helpers-CdxEL7ri.d.mts → helpers-Dvvcz-hL.d.mts} +3 -3
- package/dist/helpers.d.mts +1 -1
- package/dist/{i18n-BLyCaSdJ.mjs → i18n-CKRi992F.mjs} +2 -1
- package/dist/i18n-CKRi992F.mjs.map +1 -0
- package/dist/{index-DX5Zu9JU.d.mts → index-B3A74_ew.d.mts} +3 -3
- package/dist/index6.d.mts +1 -1
- package/dist/{inputFields-CYttsz5M.d.mts → inputFields-Dfpxi68z.d.mts} +5 -5
- package/dist/inputFields.d.mts +1 -1
- package/dist/lib/PDSProvider.d.mts +1 -1
- package/dist/lib/PDSProvider.mjs +1 -1
- package/dist/lib/PDSProvider.mjs.map +1 -1
- package/dist/lib/TruncatedText.mjs.map +1 -1
- package/dist/lib/TruncatedTextWithTooltip.mjs.map +1 -1
- package/dist/lib/color.mjs.map +1 -1
- package/dist/lib/colorMode.mjs.map +1 -1
- package/dist/lib/i18n/index.d.mts +2 -2
- package/dist/lib/i18n/index.mjs +1 -1
- package/dist/lib/pseudoClass.mjs.map +1 -1
- package/dist/lib/semanticColor.mjs.map +1 -1
- package/dist/lib/useEmbeddedSurface.mjs.map +1 -1
- package/dist/mixins/focus.mjs.map +1 -1
- package/dist/mixins/hoverable.mjs.map +1 -1
- package/dist/mixins/input.mjs.map +1 -1
- package/dist/mixins/menuItem.mjs.map +1 -1
- package/dist/mixins/print/index.mjs.map +1 -1
- package/dist/mixins/scrollbar.mjs.map +1 -1
- package/dist/{operators-gCG7uZ6y.d.mts → operators-BrrJKENE.d.mts} +2 -2
- package/dist/operators.d.mts +1 -1
- package/dist/patterns/CardGrouping/index.mjs.map +1 -1
- package/dist/patterns/IndexTableLayout/index.mjs +1 -1
- package/dist/patterns/IndexTableLayout/index.mjs.map +1 -1
- package/dist/patterns/LayoutLoadingShimmer/index.mjs.map +1 -1
- package/dist/patterns/LayoutLoadingSpinner/index.mjs.map +1 -1
- package/dist/patterns/WizardModal/index.mjs +1 -1
- package/dist/patterns/WizardModal/index.mjs.map +1 -1
- package/dist/{strings-CK9n6b65.d.mts → strings-BGXKl_m6.d.mts} +6 -1
- package/dist/strings.d.mts +1 -1
- package/dist/theme.mjs.map +1 -1
- package/dist/{types-DJobO07d.d.mts → types-DoJubhWu.d.mts} +2 -2
- package/dist/{types-CayYd8EX.d.mts → types-sUEmxsGM.d.mts} +2 -2
- package/dist/types5.d.mts +1 -1
- package/dist/useChain-D1aNsdvn.mjs.map +1 -1
- package/dist/useColumnConfiguration.d.mts +2 -2
- package/dist/useComboboxFooterAction.d.mts +1 -1
- package/dist/useFormField-pOVkb5BK.mjs.map +1 -1
- package/dist/{useTableColumns-BK-KYY0L.d.mts → useTableColumns-nPrbDfF_.d.mts} +2 -2
- package/dist/useTableColumns.d.mts +1 -1
- package/dist/useTruncation.d.mts +1 -1
- package/dist/utils/storybook.mjs.map +1 -1
- package/dist/variables/effect.mjs.map +1 -1
- package/package.json +16 -3
- package/dist/DataTable-DEJHWrsy.mjs.map +0 -1
- package/dist/FormField-g1zQFM9T.mjs.map +0 -1
- package/dist/Modal-92O_uW8H.mjs.map +0 -1
- package/dist/Pagination-dTsHLVAk.mjs.map +0 -1
- package/dist/TableControls-BDXOQMr7.mjs.map +0 -1
- package/dist/i18n-BLyCaSdJ.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/BottomPanel/ResizeHandle.tsx","../../../src/components/BottomPanel/ResizableVerticalPanel.tsx","../../../src/components/BottomPanel/BottomPanel.tsx"],"sourcesContent":["import { type FC, type RefObject, useEffect, useRef } from 'react';\nimport styled from 'styled-components';\n\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { Spacing } from '@persona/design-tokens';\n\nconst DRAGGING_CLASSNAME = 'dragging';\n\ninterface ResizeHandleProps {\n ariaLabel: string;\n /** Fires on double-click or Enter/Space so the host can toggle/reset the size. */\n onDoubleClick?: () => void;\n /** Called on each pointer move with the new top edge position (clientY) in px. */\n onMoveTo: (position: number) => void;\n /** Called once when the drag ends (pointerup, cancel, or lost capture). */\n onRelease?: () => void;\n /** The panel being resized; its edge seeds the grab offset so the handle doesn't jump. */\n panelRef: RefObject<HTMLDivElement>;\n}\n\n// The visible line is 2px tall on the panel's top border; the hitbox is Spacing[2] tall and\n// straddles that border so it is easy to grab without covering the header row's controls.\nconst ResizeHandleContainer = styled.div`\n cursor: row-resize;\n position: absolute;\n height: ${Spacing[2]};\n top: -${Spacing[1]};\n left: 0;\n right: 0;\n z-index: ${Z_INDICES.dropdown};\n touch-action: none;\n\n &::after {\n content: '';\n position: absolute;\n top: ${Spacing[1]};\n left: 0;\n right: 0;\n height: 2px;\n background-color: transparent;\n transition: background-color 0.15s ease-in;\n transition-delay: 0.025s;\n }\n\n &:hover::after,\n &.${DRAGGING_CLASSNAME}::after {\n background-color: ${({ theme }) => theme.color.border.active};\n }\n`;\n\n/** Vertical resize handle pinned to the top edge of a bottom-anchored panel. */\nexport const ResizeHandle: FC<ResizeHandleProps> = ({\n ariaLabel,\n onDoubleClick,\n onMoveTo,\n onRelease,\n panelRef,\n}) => {\n const resizeHandleRef = useRef<HTMLDivElement>(null);\n const panelOffsetRef = useRef(0);\n const activePointerIdRef = useRef<number | null>(null);\n const documentListenersRef = useRef<{\n handleEnd: (event: PointerEvent) => void;\n handleMove: (event: PointerEvent) => void;\n } | null>(null);\n // Document listeners are registered once per drag; reading the callbacks through\n // refs keeps them on the latest props without re-registering mid-drag.\n const onMoveToRef = useRef(onMoveTo);\n const onReleaseRef = useRef(onRelease);\n onMoveToRef.current = onMoveTo;\n onReleaseRef.current = onRelease;\n\n const removeDocumentListeners = () => {\n const listeners = documentListenersRef.current;\n if (!listeners) {\n return;\n }\n\n document.removeEventListener('pointermove', listeners.handleMove);\n document.removeEventListener('pointerup', listeners.handleEnd);\n document.removeEventListener('pointercancel', listeners.handleEnd);\n documentListenersRef.current = null;\n };\n\n // Pointer capture routes events through the handle (including over iframes), but\n // some surfaces still drop pointerup. Document-level listeners during an active\n // drag are the release safety net. Only the pointer that started the drag may\n // move or end it.\n const endDrag = (pointerId: number) => {\n if (activePointerIdRef.current !== pointerId) {\n return;\n }\n\n activePointerIdRef.current = null;\n removeDocumentListeners();\n try {\n resizeHandleRef.current?.releasePointerCapture(pointerId);\n } catch {\n // No active capture (or unsupported, e.g. jsdom) — nothing to release.\n }\n\n resizeHandleRef.current?.classList.remove(DRAGGING_CLASSNAME);\n panelOffsetRef.current = 0;\n onReleaseRef.current?.();\n };\n\n const handleDocumentPointerMove = (event: PointerEvent) => {\n if (activePointerIdRef.current !== event.pointerId) {\n return;\n }\n\n onMoveToRef.current(event.clientY + panelOffsetRef.current);\n };\n\n const addDocumentListeners = () => {\n removeDocumentListeners();\n\n const listeners = {\n handleEnd: (event: PointerEvent) => endDrag(event.pointerId),\n handleMove: handleDocumentPointerMove,\n };\n documentListenersRef.current = listeners;\n document.addEventListener('pointermove', listeners.handleMove);\n document.addEventListener('pointerup', listeners.handleEnd);\n document.addEventListener('pointercancel', listeners.handleEnd);\n };\n\n const endDragRef = useRef(endDrag);\n endDragRef.current = endDrag;\n useEffect(() => {\n return () => {\n const activePointerId = activePointerIdRef.current;\n if (activePointerId != null) {\n endDragRef.current(activePointerId);\n }\n };\n }, []);\n\n return (\n <ResizeHandleContainer\n aria-label={ariaLabel}\n onDoubleClick={onDoubleClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n onDoubleClick?.();\n e.preventDefault();\n }\n }}\n onLostPointerCapture={(e) => endDrag(e.pointerId)}\n onPointerCancel={(e) => endDrag(e.pointerId)}\n onPointerDown={(e) => {\n // Primary button / touch / pen only; ignore secondary and middle clicks,\n // and a second pointer while a drag is already active.\n if (e.button !== 0 || activePointerIdRef.current != null) {\n return;\n }\n const panelRect = panelRef.current?.getBoundingClientRect();\n panelOffsetRef.current = panelRect ? panelRect.top - e.clientY : 0;\n activePointerIdRef.current = e.pointerId;\n resizeHandleRef.current?.classList.add(DRAGGING_CLASSNAME);\n addDocumentListeners();\n try {\n resizeHandleRef.current?.setPointerCapture(e.pointerId);\n } catch {\n // Pointer capture unsupported (e.g. jsdom) — document listeners still\n // route move/up events for the duration of the drag.\n }\n e.preventDefault();\n e.stopPropagation();\n }}\n onPointerUp={(e) => endDrag(e.pointerId)}\n ref={resizeHandleRef}\n role='button'\n tabIndex={0}\n />\n );\n};\n","import { type FC, type ReactNode, useRef } from 'react';\nimport styled from 'styled-components';\n\nimport { IconButton } from '@persona/design-system/components/Button';\nimport { PanelState, type ResizablePanelState } from '@persona/design-system/lib/useResizablePanel';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon, XIcon } from '@persona/icons';\nimport { semanticScrollbar } from 'design-system/mixins/scrollbar';\n\nimport { ResizeHandle } from './ResizeHandle';\n\ninterface ResizableVerticalPanelProps {\n /** Panel body, rendered in the scrollable content area below the header. */\n children: ReactNode;\n /** Content for the header row, left of the maximize/minimize/close buttons. */\n headerContent?: ReactNode;\n /** State and drag/resize handlers from `useResizablePanel`. */\n hookState: ResizablePanelState;\n /** Minimum panel height in px. */\n minHeight: number;\n}\n\nconst TriStatePanel = styled.div.attrs<{\n customHeight: number | null;\n minHeight: number;\n panelState: PanelState;\n}>(({ customHeight, minHeight, panelState }) => ({\n style: {\n height: panelState === PanelState.Maximized ? '100%' : `${customHeight ?? minHeight}px`,\n },\n}))<{\n customHeight: number | null;\n minHeight: number;\n panelState: PanelState;\n}>`\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n background-color: ${({ theme }) => theme.color.background.primary};\n position: relative;\n min-height: ${({ minHeight }) => minHeight}px;\n width: 100%;\n border-top: 1px solid ${Color.BorderDivider};\n z-index: ${Z_INDICES.topNav};\n`;\n\nconst TopRowContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n box-shadow: inset 0px -1px 0px 0px ${Color.BorderDivider};\n`;\n\nconst TopRightIconsContainer = styled.div`\n display: flex;\n align-items: center;\n padding: 0 ${Spacing[2]};\n gap: ${Spacing[2]};\n flex-direction: row;\n`;\n\nconst ContentContainer = styled.div`\n /* offset by the top row container height */\n height: calc(100% - ${Spacing[6]});\n overflow: auto;\n ${semanticScrollbar}\n display: flex;\n flex-direction: column;\n min-height: 0;\n`;\n\n/**\n * Bottom-anchored panel with a drag-to-resize top edge, a header row, and\n * maximize/minimize/close controls.\n */\nexport const ResizableVerticalPanel: FC<ResizableVerticalPanelProps> = ({\n children,\n headerContent,\n hookState,\n minHeight,\n}) => {\n const {\n collapse,\n handleDragMove: handlePanelDragMove,\n handleDragRelease,\n maximize,\n panelState,\n restore,\n size,\n toggleMaximized,\n } = hookState;\n const panelRef = useRef<HTMLDivElement>(null);\n // Controls only make sense once the drawer is taller than its collapsed header.\n const showControls = (size != null && size > minHeight) || panelState === PanelState.Maximized;\n // Converts the dragged top edge (clientY) into a panel height bounded by the\n // panel's container.\n const handleDragMove = (clientY: number) => {\n const panel = panelRef.current;\n const container = panel?.parentElement;\n if (!panel || !container) {\n return;\n }\n const panelBottom = panel.getBoundingClientRect().bottom;\n const containerTop = container.getBoundingClientRect().top;\n handlePanelDragMove(panelBottom - clientY, panelBottom - containerTop);\n };\n\n return (\n <TriStatePanel\n aria-label='Bottom panel'\n customHeight={size}\n minHeight={minHeight}\n panelState={panelState}\n ref={panelRef}\n role='region'\n >\n <ResizeHandle\n ariaLabel='Drag to resize bottom panel'\n onDoubleClick={toggleMaximized}\n onMoveTo={handleDragMove}\n onRelease={handleDragRelease}\n panelRef={panelRef}\n />\n\n <TopRowContainer>\n {headerContent}\n\n {showControls && (\n <TopRightIconsContainer>\n {panelState === PanelState.Maximized ? (\n <IconButton aria-label='Restore the bottom panel' onClick={restore} size='sm'>\n <ArrowCollapseIcon />\n </IconButton>\n ) : (\n <IconButton aria-label='Maximize the bottom panel' onClick={maximize} size='sm'>\n <ArrowExpandIcon />\n </IconButton>\n )}\n <IconButton aria-label='Close bottom panel' onClick={collapse} size='sm'>\n <XIcon />\n </IconButton>\n </TopRightIconsContainer>\n )}\n </TopRowContainer>\n\n <ContentContainer>{children}</ContentContainer>\n </TriStatePanel>\n );\n};\n","import {\n forwardRef,\n type ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react';\nimport { useId } from 'react-aria';\nimport styled, { css } from 'styled-components';\n\nimport Badge from '@persona/design-system/components/Badge';\nimport TabBar, { Tab } from '@persona/design-system/components/TabBar';\nimport { PanelState, useResizablePanel } from '@persona/design-system/lib/useResizablePanel';\nimport { Spacing } from '@persona/design-tokens';\n\nimport { ResizableVerticalPanel } from './ResizableVerticalPanel';\n\n// One-pixel panel top border plus the 32px header row sets the collapsed drawer height.\nconst PANEL_MIN_HEIGHT = 33;\n// Where the drawer opens to when a collapsed tab is selected; the user can drag from there.\nconst OPEN_HEIGHT = 200;\n\nexport interface BottomPanelItemProps {\n /** Tab text; also the key `openPanel(label)` looks up. Unique per BottomPanel. */\n label: string;\n /**\n * Tab body. Every panel stays mounted while another tab is selected, so local\n * state (scroll, expanded rows) survives a switch.\n */\n content: ReactNode;\n /** Count shown as a badge on the tab. `0`/`undefined` hides it. */\n badge?: number;\n}\n\nexport interface BottomPanelHandle {\n /** Select the tab and expand the drawer if collapsed. No-op for an unknown label. */\n openPanel: (label: string) => void;\n}\n\nexport interface BottomPanelProps {\n /** Tabs to show, in order. */\n panels: BottomPanelItemProps[];\n}\n\nconst Header = styled.div`\n display: flex;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n padding-left: ${Spacing[4]};\n`;\n\n// The header row draws the divider edge to edge; the tab bar must not add its own.\nconst HeaderTabBar = styled(TabBar)`\n border-bottom: none;\n`;\n\nconst PanelContent = styled.div<{ $hidden: boolean }>`\n ${({ $hidden }) =>\n $hidden\n ? css`\n position: absolute;\n inset: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n `\n : css`\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 0;\n `}\n`;\n\n/**\n * Resizable drawer anchored to the bottom of its container with one tab per\n * panel. Owns the tab bar, expand/collapse/resize, and always-mounted content;\n * the caller owns what each panel shows.\n */\nconst BottomPanel = forwardRef<BottomPanelHandle, BottomPanelProps>(function BottomPanel(\n { panels },\n ref,\n) {\n const baseId = useId();\n const [selected, setSelected] = useState<string | undefined>(panels[0]?.label);\n // Falls back to the first panel when the selected label has left `panels`, and\n // commits the fallback so the old label does not regain selection if it returns.\n const hasSelected = panels.some((panel) => panel.label === selected);\n const selectedLabel = hasSelected ? selected : panels[0]?.label;\n useEffect(() => {\n if (!hasSelected) {\n setSelected(selectedLabel);\n }\n }, [hasSelected, selectedLabel]);\n\n const resizablePanelState = useResizablePanel({\n initialSize: PANEL_MIN_HEIGHT,\n minSize: PANEL_MIN_HEIGHT,\n });\n const { expandTo, panelState, size } = resizablePanelState;\n\n // Selecting a tab opens a collapsed drawer but leaves a maximized one as is.\n const openPanel = useCallback(\n (label: string) => {\n if (panelState === PanelState.Drawer && (size == null || size <= PANEL_MIN_HEIGHT)) {\n expandTo(OPEN_HEIGHT);\n }\n setSelected(label);\n },\n [expandTo, panelState, size],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n openPanel: (label: string) => {\n if (panels.some((panel) => panel.label === label)) {\n openPanel(label);\n }\n },\n }),\n [openPanel, panels],\n );\n\n return (\n <ResizableVerticalPanel\n headerContent={\n <Header>\n <HeaderTabBar>\n {panels.map((panel, index) => (\n <Tab\n aria-controls={`${baseId}-panel-${index}`}\n badge={panel.badge ? <Badge>{panel.badge}</Badge> : undefined}\n id={`${baseId}-tab-${index}`}\n key={panel.label}\n onClick={() => openPanel(panel.label)}\n selected={selectedLabel === panel.label}\n >\n {panel.label}\n </Tab>\n ))}\n </HeaderTabBar>\n </Header>\n }\n hookState={resizablePanelState}\n minHeight={PANEL_MIN_HEIGHT}\n >\n {panels.map((panel, index) => {\n const isSelected = selectedLabel === panel.label;\n return (\n <PanelContent\n $hidden={!isSelected}\n aria-hidden={!isSelected}\n aria-labelledby={`${baseId}-tab-${index}`}\n id={`${baseId}-panel-${index}`}\n key={panel.label}\n role='tabpanel'\n >\n {panel.content}\n </PanelContent>\n );\n })}\n </ResizableVerticalPanel>\n );\n});\n\nexport default BottomPanel;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/BottomPanel/ResizeHandle.tsx","../../../src/components/BottomPanel/ResizableVerticalPanel.tsx","../../../src/components/BottomPanel/BottomPanel.tsx"],"sourcesContent":["import { type FC, type RefObject, useEffect, useRef } from 'react';\nimport styled from 'styled-components';\n\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { Spacing } from '@persona/design-tokens';\n\nconst DRAGGING_CLASSNAME = 'dragging';\n\ninterface ResizeHandleProps {\n ariaLabel: string;\n /** Fires on double-click or Enter/Space so the host can toggle/reset the size. */\n onDoubleClick?: () => void;\n /** Called on each pointer move with the new top edge position (clientY) in px. */\n onMoveTo: (position: number) => void;\n /** Called once when the drag ends (pointerup, cancel, or lost capture). */\n onRelease?: () => void;\n /** The panel being resized; its edge seeds the grab offset so the handle doesn't jump. */\n panelRef: RefObject<HTMLDivElement>;\n}\n\n// The visible line is 2px tall on the panel's top border; the hitbox is Spacing[2] tall and\n// straddles that border so it is easy to grab without covering the header row's controls.\nconst ResizeHandleContainer = styled.div`\n cursor: row-resize;\n position: absolute;\n height: ${Spacing[2]};\n top: -${Spacing[1]};\n left: 0;\n right: 0;\n z-index: ${Z_INDICES.dropdown};\n touch-action: none;\n\n &::after {\n content: '';\n position: absolute;\n top: ${Spacing[1]};\n left: 0;\n right: 0;\n height: 2px;\n background-color: transparent;\n transition: background-color 0.15s ease-in;\n transition-delay: 0.025s;\n }\n\n &:hover::after,\n &.${DRAGGING_CLASSNAME}::after {\n background-color: ${({ theme }) => theme.color.border.active};\n }\n`;\n\n/** Vertical resize handle pinned to the top edge of a bottom-anchored panel. */\nexport const ResizeHandle: FC<ResizeHandleProps> = ({\n ariaLabel,\n onDoubleClick,\n onMoveTo,\n onRelease,\n panelRef,\n}) => {\n const resizeHandleRef = useRef<HTMLDivElement>(null);\n const panelOffsetRef = useRef(0);\n const activePointerIdRef = useRef<number | null>(null);\n const documentListenersRef = useRef<{\n handleEnd: (event: PointerEvent) => void;\n handleMove: (event: PointerEvent) => void;\n } | null>(null);\n // Document listeners are registered once per drag; reading the callbacks through\n // refs keeps them on the latest props without re-registering mid-drag.\n const onMoveToRef = useRef(onMoveTo);\n const onReleaseRef = useRef(onRelease);\n onMoveToRef.current = onMoveTo;\n onReleaseRef.current = onRelease;\n\n const removeDocumentListeners = () => {\n const listeners = documentListenersRef.current;\n if (!listeners) {\n return;\n }\n\n document.removeEventListener('pointermove', listeners.handleMove);\n document.removeEventListener('pointerup', listeners.handleEnd);\n document.removeEventListener('pointercancel', listeners.handleEnd);\n documentListenersRef.current = null;\n };\n\n // Pointer capture routes events through the handle (including over iframes), but\n // some surfaces still drop pointerup. Document-level listeners during an active\n // drag are the release safety net. Only the pointer that started the drag may\n // move or end it.\n const endDrag = (pointerId: number) => {\n if (activePointerIdRef.current !== pointerId) {\n return;\n }\n\n activePointerIdRef.current = null;\n removeDocumentListeners();\n try {\n resizeHandleRef.current?.releasePointerCapture(pointerId);\n } catch {\n // No active capture (or unsupported, e.g. jsdom) — nothing to release.\n }\n\n resizeHandleRef.current?.classList.remove(DRAGGING_CLASSNAME);\n panelOffsetRef.current = 0;\n onReleaseRef.current?.();\n };\n\n const handleDocumentPointerMove = (event: PointerEvent) => {\n if (activePointerIdRef.current !== event.pointerId) {\n return;\n }\n\n onMoveToRef.current(event.clientY + panelOffsetRef.current);\n };\n\n const addDocumentListeners = () => {\n removeDocumentListeners();\n\n const listeners = {\n handleEnd: (event: PointerEvent) => endDrag(event.pointerId),\n handleMove: handleDocumentPointerMove,\n };\n documentListenersRef.current = listeners;\n document.addEventListener('pointermove', listeners.handleMove);\n document.addEventListener('pointerup', listeners.handleEnd);\n document.addEventListener('pointercancel', listeners.handleEnd);\n };\n\n const endDragRef = useRef(endDrag);\n endDragRef.current = endDrag;\n useEffect(() => {\n return () => {\n const activePointerId = activePointerIdRef.current;\n if (activePointerId != null) {\n endDragRef.current(activePointerId);\n }\n };\n }, []);\n\n return (\n <ResizeHandleContainer\n aria-label={ariaLabel}\n onDoubleClick={onDoubleClick}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n onDoubleClick?.();\n e.preventDefault();\n }\n }}\n onLostPointerCapture={(e) => endDrag(e.pointerId)}\n onPointerCancel={(e) => endDrag(e.pointerId)}\n onPointerDown={(e) => {\n // Primary button / touch / pen only; ignore secondary and middle clicks,\n // and a second pointer while a drag is already active.\n if (e.button !== 0 || activePointerIdRef.current != null) {\n return;\n }\n const panelRect = panelRef.current?.getBoundingClientRect();\n panelOffsetRef.current = panelRect ? panelRect.top - e.clientY : 0;\n activePointerIdRef.current = e.pointerId;\n resizeHandleRef.current?.classList.add(DRAGGING_CLASSNAME);\n addDocumentListeners();\n try {\n resizeHandleRef.current?.setPointerCapture(e.pointerId);\n } catch {\n // Pointer capture unsupported (e.g. jsdom) — document listeners still\n // route move/up events for the duration of the drag.\n }\n e.preventDefault();\n e.stopPropagation();\n }}\n onPointerUp={(e) => endDrag(e.pointerId)}\n ref={resizeHandleRef}\n role='button'\n tabIndex={0}\n />\n );\n};\n","import { type FC, type ReactNode, useRef } from 'react';\nimport styled from 'styled-components';\n\nimport { IconButton } from '@persona/design-system/components/Button';\nimport { PanelState, type ResizablePanelState } from '@persona/design-system/lib/useResizablePanel';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon, XIcon } from '@persona/icons';\n\nimport { semanticScrollbar } from '#src/mixins/scrollbar';\n\nimport { ResizeHandle } from './ResizeHandle';\n\ninterface ResizableVerticalPanelProps {\n /** Panel body, rendered in the scrollable content area below the header. */\n children: ReactNode;\n /** Content for the header row, left of the maximize/minimize/close buttons. */\n headerContent?: ReactNode;\n /** State and drag/resize handlers from `useResizablePanel`. */\n hookState: ResizablePanelState;\n /** Minimum panel height in px. */\n minHeight: number;\n}\n\nconst TriStatePanel = styled.div.attrs<{\n customHeight: number | null;\n minHeight: number;\n panelState: PanelState;\n}>(({ customHeight, minHeight, panelState }) => ({\n style: {\n height: panelState === PanelState.Maximized ? '100%' : `${customHeight ?? minHeight}px`,\n },\n}))<{\n customHeight: number | null;\n minHeight: number;\n panelState: PanelState;\n}>`\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n background-color: ${({ theme }) => theme.color.background.primary};\n position: relative;\n min-height: ${({ minHeight }) => minHeight}px;\n width: 100%;\n border-top: 1px solid ${Color.BorderDivider};\n z-index: ${Z_INDICES.topNav};\n`;\n\nconst TopRowContainer = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n box-shadow: inset 0px -1px 0px 0px ${Color.BorderDivider};\n`;\n\nconst TopRightIconsContainer = styled.div`\n display: flex;\n align-items: center;\n padding: 0 ${Spacing[2]};\n gap: ${Spacing[2]};\n flex-direction: row;\n`;\n\nconst ContentContainer = styled.div`\n /* offset by the top row container height */\n height: calc(100% - ${Spacing[6]});\n overflow: auto;\n ${semanticScrollbar}\n display: flex;\n flex-direction: column;\n min-height: 0;\n`;\n\n/**\n * Bottom-anchored panel with a drag-to-resize top edge, a header row, and\n * maximize/minimize/close controls.\n */\nexport const ResizableVerticalPanel: FC<ResizableVerticalPanelProps> = ({\n children,\n headerContent,\n hookState,\n minHeight,\n}) => {\n const {\n collapse,\n handleDragMove: handlePanelDragMove,\n handleDragRelease,\n maximize,\n panelState,\n restore,\n size,\n toggleMaximized,\n } = hookState;\n const panelRef = useRef<HTMLDivElement>(null);\n // Controls only make sense once the drawer is taller than its collapsed header.\n const showControls = (size != null && size > minHeight) || panelState === PanelState.Maximized;\n // Converts the dragged top edge (clientY) into a panel height bounded by the\n // panel's container.\n const handleDragMove = (clientY: number) => {\n const panel = panelRef.current;\n const container = panel?.parentElement;\n if (!panel || !container) {\n return;\n }\n const panelBottom = panel.getBoundingClientRect().bottom;\n const containerTop = container.getBoundingClientRect().top;\n handlePanelDragMove(panelBottom - clientY, panelBottom - containerTop);\n };\n\n return (\n <TriStatePanel\n aria-label='Bottom panel'\n customHeight={size}\n minHeight={minHeight}\n panelState={panelState}\n ref={panelRef}\n role='region'\n >\n <ResizeHandle\n ariaLabel='Drag to resize bottom panel'\n onDoubleClick={toggleMaximized}\n onMoveTo={handleDragMove}\n onRelease={handleDragRelease}\n panelRef={panelRef}\n />\n\n <TopRowContainer>\n {headerContent}\n\n {showControls && (\n <TopRightIconsContainer>\n {panelState === PanelState.Maximized ? (\n <IconButton aria-label='Restore the bottom panel' onClick={restore} size='sm'>\n <ArrowCollapseIcon />\n </IconButton>\n ) : (\n <IconButton aria-label='Maximize the bottom panel' onClick={maximize} size='sm'>\n <ArrowExpandIcon />\n </IconButton>\n )}\n <IconButton aria-label='Close bottom panel' onClick={collapse} size='sm'>\n <XIcon />\n </IconButton>\n </TopRightIconsContainer>\n )}\n </TopRowContainer>\n\n <ContentContainer>{children}</ContentContainer>\n </TriStatePanel>\n );\n};\n","import {\n forwardRef,\n type ReactNode,\n useCallback,\n useEffect,\n useImperativeHandle,\n useState,\n} from 'react';\nimport { useId } from 'react-aria';\nimport styled, { css } from 'styled-components';\n\nimport Badge from '@persona/design-system/components/Badge';\nimport TabBar, { Tab } from '@persona/design-system/components/TabBar';\nimport { PanelState, useResizablePanel } from '@persona/design-system/lib/useResizablePanel';\nimport { Spacing } from '@persona/design-tokens';\n\nimport { ResizableVerticalPanel } from './ResizableVerticalPanel';\n\n// One-pixel panel top border plus the 32px header row sets the collapsed drawer height.\nconst PANEL_MIN_HEIGHT = 33;\n// Where the drawer opens to when a collapsed tab is selected; the user can drag from there.\nconst OPEN_HEIGHT = 200;\n\nexport interface BottomPanelItemProps {\n /** Tab text; also the key `openPanel(label)` looks up. Unique per BottomPanel. */\n label: string;\n /**\n * Tab body. Every panel stays mounted while another tab is selected, so local\n * state (scroll, expanded rows) survives a switch.\n */\n content: ReactNode;\n /** Count shown as a badge on the tab. `0`/`undefined` hides it. */\n badge?: number;\n}\n\nexport interface BottomPanelHandle {\n /** Select the tab and expand the drawer if collapsed. No-op for an unknown label. */\n openPanel: (label: string) => void;\n}\n\nexport interface BottomPanelProps {\n /** Tabs to show, in order. */\n panels: BottomPanelItemProps[];\n}\n\nconst Header = styled.div`\n display: flex;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n padding-left: ${Spacing[4]};\n`;\n\n// The header row draws the divider edge to edge; the tab bar must not add its own.\nconst HeaderTabBar = styled(TabBar)`\n border-bottom: none;\n`;\n\nconst PanelContent = styled.div<{ $hidden: boolean }>`\n ${({ $hidden }) =>\n $hidden\n ? css`\n position: absolute;\n inset: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n `\n : css`\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 0;\n `}\n`;\n\n/**\n * Resizable drawer anchored to the bottom of its container with one tab per\n * panel. Owns the tab bar, expand/collapse/resize, and always-mounted content;\n * the caller owns what each panel shows.\n */\nconst BottomPanel = forwardRef<BottomPanelHandle, BottomPanelProps>(function BottomPanel(\n { panels },\n ref,\n) {\n const baseId = useId();\n const [selected, setSelected] = useState<string | undefined>(panels[0]?.label);\n // Falls back to the first panel when the selected label has left `panels`, and\n // commits the fallback so the old label does not regain selection if it returns.\n const hasSelected = panels.some((panel) => panel.label === selected);\n const selectedLabel = hasSelected ? selected : panels[0]?.label;\n useEffect(() => {\n if (!hasSelected) {\n setSelected(selectedLabel);\n }\n }, [hasSelected, selectedLabel]);\n\n const resizablePanelState = useResizablePanel({\n initialSize: PANEL_MIN_HEIGHT,\n minSize: PANEL_MIN_HEIGHT,\n });\n const { expandTo, panelState, size } = resizablePanelState;\n\n // Selecting a tab opens a collapsed drawer but leaves a maximized one as is.\n const openPanel = useCallback(\n (label: string) => {\n if (panelState === PanelState.Drawer && (size == null || size <= PANEL_MIN_HEIGHT)) {\n expandTo(OPEN_HEIGHT);\n }\n setSelected(label);\n },\n [expandTo, panelState, size],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n openPanel: (label: string) => {\n if (panels.some((panel) => panel.label === label)) {\n openPanel(label);\n }\n },\n }),\n [openPanel, panels],\n );\n\n return (\n <ResizableVerticalPanel\n headerContent={\n <Header>\n <HeaderTabBar>\n {panels.map((panel, index) => (\n <Tab\n aria-controls={`${baseId}-panel-${index}`}\n badge={panel.badge ? <Badge>{panel.badge}</Badge> : undefined}\n id={`${baseId}-tab-${index}`}\n key={panel.label}\n onClick={() => openPanel(panel.label)}\n selected={selectedLabel === panel.label}\n >\n {panel.label}\n </Tab>\n ))}\n </HeaderTabBar>\n </Header>\n }\n hookState={resizablePanelState}\n minHeight={PANEL_MIN_HEIGHT}\n >\n {panels.map((panel, index) => {\n const isSelected = selectedLabel === panel.label;\n return (\n <PanelContent\n $hidden={!isSelected}\n aria-hidden={!isSelected}\n aria-labelledby={`${baseId}-tab-${index}`}\n id={`${baseId}-panel-${index}`}\n key={panel.label}\n role='tabpanel'\n >\n {panel.content}\n </PanelContent>\n );\n })}\n </ResizableVerticalPanel>\n );\n});\n\nexport default BottomPanel;\n"],"mappings":";;;;;;;;;;;;;AAMA,MAAM,qBAAqB;AAgB3B,MAAM,wBAAwB,OAAO,GAAG;;;YAG5B,QAAQ,GAAG;UACb,QAAQ,GAAG;;;aAGR,UAAU,SAAS;;;;;;WAMrB,QAAQ,GAAG;;;;;;;;;;MAUhB,mBAAmB;yBACA,EAAE,YAAY,MAAM,MAAM,OAAO,OAAO;;;;AAKjE,MAAa,gBAAuC,EAClD,WACA,eACA,UACA,WACA,eACI;CACJ,MAAM,kBAAkB,OAAuB,KAAK;CACpD,MAAM,iBAAiB,OAAO,EAAE;CAChC,MAAM,qBAAqB,OAAsB,KAAK;CACtD,MAAM,uBAAuB,OAGnB,KAAK;CAGf,MAAM,cAAc,OAAO,SAAS;CACpC,MAAM,eAAe,OAAO,UAAU;AACtC,aAAY,UAAU;AACtB,cAAa,UAAU;CAEvB,MAAM,gCAAgC;EACpC,MAAM,YAAY,qBAAqB;AACvC,MAAI,CAAC,UACH;AAGF,WAAS,oBAAoB,eAAe,UAAU,WAAW;AACjE,WAAS,oBAAoB,aAAa,UAAU,UAAU;AAC9D,WAAS,oBAAoB,iBAAiB,UAAU,UAAU;AAClE,uBAAqB,UAAU;;CAOjC,MAAM,WAAW,cAAsB;AACrC,MAAI,mBAAmB,YAAY,UACjC;AAGF,qBAAmB,UAAU;AAC7B,2BAAyB;AACzB,MAAI;AACF,mBAAgB,SAAS,sBAAsB,UAAU;UACnD;AAIR,kBAAgB,SAAS,UAAU,OAAO,mBAAmB;AAC7D,iBAAe,UAAU;AACzB,eAAa,WAAW;;CAG1B,MAAM,6BAA6B,UAAwB;AACzD,MAAI,mBAAmB,YAAY,MAAM,UACvC;AAGF,cAAY,QAAQ,MAAM,UAAU,eAAe,QAAQ;;CAG7D,MAAM,6BAA6B;AACjC,2BAAyB;EAEzB,MAAM,YAAY;GAChB,YAAY,UAAwB,QAAQ,MAAM,UAAU;GAC5D,YAAY;GACb;AACD,uBAAqB,UAAU;AAC/B,WAAS,iBAAiB,eAAe,UAAU,WAAW;AAC9D,WAAS,iBAAiB,aAAa,UAAU,UAAU;AAC3D,WAAS,iBAAiB,iBAAiB,UAAU,UAAU;;CAGjE,MAAM,aAAa,OAAO,QAAQ;AAClC,YAAW,UAAU;AACrB,iBAAgB;AACd,eAAa;GACX,MAAM,kBAAkB,mBAAmB;AAC3C,OAAI,mBAAmB,KACrB,YAAW,QAAQ,gBAAgB;;IAGtC,EAAE,CAAC;AAEN,QACE,oBAAC,uBAAD;EACE,cAAY;EACG;EACf,YAAY,MAAM;AAChB,OAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,qBAAiB;AACjB,MAAE,gBAAgB;;;EAGtB,uBAAuB,MAAM,QAAQ,EAAE,UAAU;EACjD,kBAAkB,MAAM,QAAQ,EAAE,UAAU;EAC5C,gBAAgB,MAAM;AAGpB,OAAI,EAAE,WAAW,KAAK,mBAAmB,WAAW,KAClD;GAEF,MAAM,YAAY,SAAS,SAAS,uBAAuB;AAC3D,kBAAe,UAAU,YAAY,UAAU,MAAM,EAAE,UAAU;AACjE,sBAAmB,UAAU,EAAE;AAC/B,mBAAgB,SAAS,UAAU,IAAI,mBAAmB;AAC1D,yBAAsB;AACtB,OAAI;AACF,oBAAgB,SAAS,kBAAkB,EAAE,UAAU;WACjD;AAIR,KAAE,gBAAgB;AAClB,KAAE,iBAAiB;;EAErB,cAAc,MAAM,QAAQ,EAAE,UAAU;EACxC,KAAK;EACL,MAAK;EACL,UAAU;EACV,CAAA;;;;ACtJN,MAAM,gBAAgB,OAAO,IAAI,OAI7B,EAAE,cAAc,WAAW,kBAAkB,EAC/C,OAAO,EACL,QAAQ,eAAA,cAAsC,SAAS,GAAG,gBAAgB,UAAU,KACrF,EACF,EAAE;;;;;uBASoB,EAAE,YAAY,MAAM,MAAM,WAAW,QAAQ;;iBAEnD,EAAE,gBAAgB,UAAU;;0BAEnB,MAAM,cAAc;aACjC,UAAU,OAAO;;AAG9B,MAAM,kBAAkB,OAAO,GAAG;;;;uCAIK,MAAM,cAAc;;AAG3D,MAAM,yBAAyB,OAAO,GAAG;;;eAG1B,QAAQ,GAAG;SACjB,QAAQ,GAAG;;;AAIpB,MAAM,mBAAmB,OAAO,GAAG;;wBAEX,QAAQ,GAAG;;IAE/B,kBAAkB;;;;;;;;;AAUtB,MAAa,0BAA2D,EACtE,UACA,eACA,WACA,gBACI;CACJ,MAAM,EACJ,UACA,gBAAgB,qBAChB,mBACA,UACA,YACA,SACA,MACA,oBACE;CACJ,MAAM,WAAW,OAAuB,KAAK;CAE7C,MAAM,eAAgB,QAAQ,QAAQ,OAAO,aAAc,eAAA;CAG3D,MAAM,kBAAkB,YAAoB;EAC1C,MAAM,QAAQ,SAAS;EACvB,MAAM,YAAY,OAAO;AACzB,MAAI,CAAC,SAAS,CAAC,UACb;EAEF,MAAM,cAAc,MAAM,uBAAuB,CAAC;EAClD,MAAM,eAAe,UAAU,uBAAuB,CAAC;AACvD,sBAAoB,cAAc,SAAS,cAAc,aAAa;;AAGxE,QACE,qBAAC,eAAD;EACE,cAAW;EACX,cAAc;EACH;EACC;EACZ,KAAK;EACL,MAAK;YANP;GAQE,oBAAC,cAAD;IACE,WAAU;IACV,eAAe;IACf,UAAU;IACV,WAAW;IACD;IACV,CAAA;GAEF,qBAAC,iBAAD,EAAA,UAAA,CACG,eAEA,gBACC,qBAAC,wBAAD,EAAA,UAAA,CACG,eAAA,cACC,oBAAC,YAAD;IAAY,cAAW;IAA2B,SAAS;IAAS,MAAK;cACvE,oBAAC,mBAAD,EAAqB,CAAA;IACV,CAAA,GAEb,oBAAC,YAAD;IAAY,cAAW;IAA4B,SAAS;IAAU,MAAK;cACzE,oBAAC,iBAAD,EAAmB,CAAA;IACR,CAAA,EAEf,oBAAC,YAAD;IAAY,cAAW;IAAqB,SAAS;IAAU,MAAK;cAClE,oBAAC,OAAD,EAAS,CAAA;IACE,CAAA,CACU,EAAA,CAAA,CAEX,EAAA,CAAA;GAElB,oBAAC,kBAAD,EAAmB,UAA4B,CAAA;GACjC;;;;;AClIpB,MAAM,mBAAmB;AAEzB,MAAM,cAAc;AAwBpB,MAAM,SAAS,OAAO,GAAG;;;;;kBAKP,QAAQ,GAAG;;AAI7B,MAAM,eAAe,OAAO,OAAO;;;AAInC,MAAM,eAAe,OAAO,GAAyB;KAChD,EAAE,cACH,UACI,GAAG;;;;;;YAOH,GAAG;;;;;UAKD;;;;;;;AAQV,MAAM,cAAc,WAAgD,SAAS,YAC3E,EAAE,UACF,KACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,CAAC,UAAU,eAAe,SAA6B,OAAO,IAAI,MAAM;CAG9E,MAAM,cAAc,OAAO,MAAM,UAAU,MAAM,UAAU,SAAS;CACpE,MAAM,gBAAgB,cAAc,WAAW,OAAO,IAAI;AAC1D,iBAAgB;AACd,MAAI,CAAC,YACH,aAAY,cAAc;IAE3B,CAAC,aAAa,cAAc,CAAC;CAEhC,MAAM,sBAAsB,kBAAkB;EAC5C,aAAa;EACb,SAAS;EACV,CAAC;CACF,MAAM,EAAE,UAAU,YAAY,SAAS;CAGvC,MAAM,YAAY,aACf,UAAkB;AACjB,MAAI,eAAA,aAAqC,QAAQ,QAAQ,QAAQ,kBAC/D,UAAS,YAAY;AAEvB,cAAY,MAAM;IAEpB;EAAC;EAAU;EAAY;EAAK,CAC7B;AAED,qBACE,YACO,EACL,YAAY,UAAkB;AAC5B,MAAI,OAAO,MAAM,UAAU,MAAM,UAAU,MAAM,CAC/C,WAAU,MAAM;IAGrB,GACD,CAAC,WAAW,OAAO,CACpB;AAED,QACE,oBAAC,wBAAD;EACE,eACE,oBAAC,QAAD,EAAA,UACE,oBAAC,cAAD,EAAA,UACG,OAAO,KAAK,OAAO,UAClB,oBAAC,KAAD;GACE,iBAAe,GAAG,OAAO,SAAS;GAClC,OAAO,MAAM,QAAQ,oBAAC,OAAD,EAAA,UAAQ,MAAM,OAAc,CAAA,GAAG,KAAA;GACpD,IAAI,GAAG,OAAO,OAAO;GAErB,eAAe,UAAU,MAAM,MAAM;GACrC,UAAU,kBAAkB,MAAM;aAEjC,MAAM;GACH,EALC,MAAM,MAKP,CACN,EACW,CAAA,EACR,CAAA;EAEX,WAAW;EACX,WAAW;YAEV,OAAO,KAAK,OAAO,UAAU;GAC5B,MAAM,aAAa,kBAAkB,MAAM;AAC3C,UACE,oBAAC,cAAD;IACE,SAAS,CAAC;IACV,eAAa,CAAC;IACd,mBAAiB,GAAG,OAAO,OAAO;IAClC,IAAI,GAAG,OAAO,SAAS;IAEvB,MAAK;cAEJ,MAAM;IACM,EAJR,MAAM,MAIE;IAEjB;EACqB,CAAA;EAE3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/ButtonGroup/ButtonGroup.tsx"],"sourcesContent":["import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';\nimport type {\n ToggleGroupMultipleProps,\n ToggleGroupSingleProps,\n} from '@radix-ui/react-toggle-group';\nimport { forwardRef } from 'react';\nimport styled, { css } from 'styled-components';\n\nimport { BorderRadius } from '@persona/design-tokens';\nimport IconButton from '
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/components/ButtonGroup/ButtonGroup.tsx"],"sourcesContent":["import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';\nimport type {\n ToggleGroupMultipleProps,\n ToggleGroupSingleProps,\n} from '@radix-ui/react-toggle-group';\nimport { forwardRef } from 'react';\nimport styled, { css } from 'styled-components';\n\nimport { BorderRadius } from '@persona/design-tokens';\n\nimport IconButton from '#src/components/Button/IconButton';\nimport { buttonPalette } from '#src/components/Button/palette';\nimport useFormField from '#src/components/FormControl/useFormField';\nimport { withAlpha } from '#src/lib/color';\nimport { semanticOnly } from '#src/lib/semanticColor';\n\nexport interface ButtonGroupProps {\n id?: string;\n className?: string;\n fullWidth?: boolean;\n}\n\nconst OptionItem = styled(IconButton)`\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n flex: 1;\n border-radius: ${BorderRadius.Md};\n width: 32px;\n height: 32px;\n background-color: ${({ theme }) => buttonPalette(theme, 'basic').default};\n white-space: nowrap;\n\n // radix-toggle-group adds a wrapping div to the options, so this is to\n // make sure the content is always center-aligned\n & > div {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n &[data-state='on'] {\n background-color: ${({ theme }) => buttonPalette(theme, 'basic').active};\n }\n\n ${semanticOnly(\n (tokens) => css`\n &:disabled {\n background-color: ${withAlpha(tokens.ActionNeutral, tokens.Opacity65)};\n }\n `,\n )}\n\n &:first-child {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n\n &:last-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n\n &[tabindex='0'] {\n z-index: 1;\n }\n`;\n\nconst ButtonGroupContainer = styled.div<{ fullWidth?: boolean }>`\n display: inline-flex;\n justify-content: space-between;\n border-radius: 4px;\n width: ${({ fullWidth }) => (fullWidth ? `100%` : `max-content`)};\n gap: 1px;\n\n > * {\n ${({ fullWidth }) =>\n fullWidth &&\n css`\n flex: 1;\n `}\n }\n`;\n\nexport const ButtonGroup = ({\n children,\n fullWidth,\n ...props\n}: (ToggleGroupSingleProps | ToggleGroupMultipleProps) & ButtonGroupProps) => {\n const { disabled } = props;\n const field = useFormField({ inputId: props.id, disabled });\n\n return (\n <ToggleGroupPrimitive.Root\n {...props}\n disabled={field.disabled}\n aria-describedby={field.helperTextId}\n aria-errormessage={field.hasError ? field.helperTextId : undefined}\n aria-invalid={field.hasError}\n >\n <ButtonGroupContainer fullWidth={fullWidth} {...props}>\n {children}\n </ButtonGroupContainer>\n </ToggleGroupPrimitive.Root>\n );\n};\n\nexport default ButtonGroup;\n\nconst ButtonItem = forwardRef<HTMLButtonElement, ToggleGroupPrimitive.ToggleGroupItemProps>(\n function ButtonItem(props: ToggleGroupPrimitive.ToggleGroupItemProps, forwardedRef) {\n return <OptionItem ref={forwardedRef} {...props} />;\n },\n);\n\nexport const ButtonGroupItem = forwardRef<\n HTMLButtonElement,\n ToggleGroupPrimitive.ToggleGroupItemProps\n>(function ButtonGroupItem({ children, ...props }, forwardedRef) {\n return (\n <ToggleGroupPrimitive.Item {...props} ref={forwardedRef} asChild>\n <ButtonItem {...props}>{children}</ButtonItem>\n </ToggleGroupPrimitive.Item>\n );\n});\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,aAAa,OAAO,WAAW;;;;;;mBAMlB,aAAa,GAAG;;;uBAGZ,EAAE,YAAY,cAAc,OAAO,QAAQ,CAAC,QAAQ;;;;;;;;;;;;yBAYlD,EAAE,YAAY,cAAc,OAAO,QAAQ,CAAC,OAAO;;;IAGxE,cACC,WAAW,GAAG;;4BAES,UAAU,OAAO,eAAe,OAAO,UAAU,CAAC;;MAG3E,CAAC;;;;;;;;;;;;;;;;;;;;AAqBJ,MAAM,uBAAuB,OAAO,GAA4B;;;;YAIpD,EAAE,gBAAiB,YAAY,SAAS,cAAe;;;;OAI5D,EAAE,gBACH,aACA,GAAG;;QAED;;;AAIR,MAAa,eAAe,EAC1B,UACA,WACA,GAAG,YACyE;CAC5E,MAAM,EAAE,aAAa;CACrB,MAAM,QAAQ,aAAa;EAAE,SAAS,MAAM;EAAI;EAAU,CAAC;AAE3D,QACE,oBAAC,qBAAqB,MAAtB;EACE,GAAI;EACJ,UAAU,MAAM;EAChB,oBAAkB,MAAM;EACxB,qBAAmB,MAAM,WAAW,MAAM,eAAe,KAAA;EACzD,gBAAc,MAAM;YAEpB,oBAAC,sBAAD;GAAiC;GAAW,GAAI;GAC7C;GACoB,CAAA;EACG,CAAA;;AAMhC,MAAM,aAAa,WACjB,SAAS,WAAW,OAAkD,cAAc;AAClF,QAAO,oBAAC,YAAD;EAAY,KAAK;EAAc,GAAI;EAAS,CAAA;EAEtD;AAED,MAAa,kBAAkB,WAG7B,SAAS,gBAAgB,EAAE,UAAU,GAAG,SAAS,cAAc;AAC/D,QACE,oBAAC,qBAAqB,MAAtB;EAA2B,GAAI;EAAO,KAAK;EAAc,SAAA;YACvD,oBAAC,YAAD;GAAY,GAAI;GAAQ;GAAsB,CAAA;EACpB,CAAA;EAE9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["Prism","ChevronRightIcon","ChevronDownIcon"],"sources":["../../../src/components/CodeHighlight/CodeHighlight.tsx","../../../src/components/CodeHighlight/index.ts"],"sourcesContent":["import { Highlight, type Language, type PrismTheme, themes } from 'prism-react-renderer';\nimport { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport styled from 'styled-components';\n\nimport Button from '@persona/design-system/components/Button';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { focusOutline } from '@persona/design-system/mixins/focus';\nimport { Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon } from '@persona/icons';\nimport { ChevronDownIcon, ChevronRightIcon } from '@persona/icons/12px';\nimport useToggle from 'design-system/lib/useToggle';\nimport { semanticScrollbar } from 'design-system/mixins/scrollbar';\n\nimport Prism from './PrismWithLanguages';\n\nconst LINE_HEIGHT = 1.5;\n\nexport const Wrapper = styled.div`\n font-family: ${({ theme }) => theme.text.fontFamily.mono};\n font-size: ${({ theme }) => theme.text.paragraph.sm.fontSize};\n line-height: ${LINE_HEIGHT};\n text-align: center;\n position: relative;\n`;\n\nexport const ExpandButtonContainer = styled.div`\n position: absolute;\n top: ${Spacing[2]};\n right: ${Spacing[4]};\n display: flex;\n gap: ${Spacing[1]};\n z-index: ${Z_INDICES.withShadow};\n`;\n\nexport const CollapseTriangle = styled.button<{ $isCollapsed: boolean }>`\n cursor: pointer;\n user-select: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n margin-right: ${Spacing[1]};\n color: ${Color.TextSecondary};\n background: none;\n border: none;\n padding: 0;\n\n &:hover {\n color: ${Color.TextActive};\n }\n\n ${focusOutline}\n`;\n\nexport const Pre = styled.pre<{ expanded: boolean; rowsToShow?: number }>`\n max-height: ${({ theme, expanded, rowsToShow }) => {\n if (expanded || rowsToShow == null) {\n return 'unset';\n }\n\n const charHeight = parseFloat(theme.text.paragraph.sm.fontSize);\n const rowHeight = charHeight * LINE_HEIGHT;\n const marginHeight = charHeight * 2; // margin is 1rem\n // Row height + top/bottom padding\n return `${rowsToShow * rowHeight + marginHeight}px`;\n }};\n\n border-radius: ${({ theme }) => theme.element.borderRadius};\n font-family: inherit;\n text-align: left;\n padding: 1rem; // Custom padding to match typical code block formatting\n overflow: auto;\n ${semanticScrollbar}\n\n a {\n /* overwrite dashboard global styles */\n font-size: inherit;\n line-height: inherit;\n text-decoration: underline;\n }\n`;\n\nexport const Line = styled.div`\n display: table-row;\n`;\n\nexport const LineNo = styled.span`\n display: table-cell;\n text-align: right;\n padding-right: 1rem; // Custom padding for line number gutter spacing\n user-select: none;\n opacity: 0.5;\n`;\n\nexport const LineContent = styled.span`\n display: table-cell;\n`;\n\nexport const IndentSpacer = styled.span`\n display: inline-block;\n width: 16px; // Match collapse triangle icon (12px) + margin (4px) for alignment\n`;\n\nexport const CollapsedItemCount = styled.span`\n color: ${Color.TextSecondary};\n`;\n\n// mirrored from lib -- not exported\ntype Token = {\n types: string[];\n content: string;\n empty?: boolean;\n};\n\ntype CollapsibleRegion = {\n startLine: number;\n endLine: number;\n type: 'object' | 'array';\n itemCount: number;\n};\n\n// Analyzes JSON structure from Prism tokens to find collapsible regions\n// This correctly handles brackets/braces inside strings by using tokenization\nconst analyzeJsonStructure = (\n tokens: Token[][],\n jsonString: string,\n): Map<number, CollapsibleRegion> => {\n const collapsibleRegions = new Map<number, CollapsibleRegion>();\n\n try {\n // Validate JSON is parseable\n const parsed = JSON.parse(jsonString);\n\n // Use a stack to track opening brackets/braces with their line numbers\n const stack: Array<{ line: number; char: '{' | '['; depth: number }> = [];\n let depth = 0;\n\n tokens.forEach((line, lineNum) => {\n line.forEach((token) => {\n // Only process punctuation tokens (not strings)\n if (token.types.includes('punctuation')) {\n if (token.content === '{' || token.content === '[') {\n stack.push({ line: lineNum, char: token.content, depth });\n depth++;\n } else if (token.content === '}' || token.content === ']') {\n depth--;\n const opening = stack.pop();\n\n if (opening && opening.line < lineNum) {\n // This is a multi-line object/array\n const startLine = opening.line;\n const endLine = lineNum;\n\n // Skip root-level (depth 0) regions\n if (opening.depth === 0) {\n return;\n }\n\n // Count items in this region\n const itemCount = countItemsInRegion(\n parsed,\n tokens,\n startLine,\n endLine,\n opening.char,\n );\n\n // Only add regions with items (skip empty objects/arrays)\n if (itemCount > 0) {\n collapsibleRegions.set(startLine, {\n startLine,\n endLine,\n type: opening.char === '{' ? 'object' : 'array',\n itemCount,\n });\n }\n }\n }\n }\n });\n });\n } catch {\n // If JSON is invalid, return empty map\n return new Map();\n }\n\n return collapsibleRegions;\n};\n\n// Count items in a collapsible region by counting commas at the same depth\nconst countItemsInRegion = (\n _parsed: unknown,\n tokens: Token[][],\n startLine: number,\n endLine: number,\n openChar: '{' | '[',\n): number => {\n let itemCount = 0;\n let depth = 0;\n\n // Iterate through lines in the region\n for (let i = startLine; i <= endLine; i++) {\n tokens[i]?.forEach((token) => {\n if (!token.types.includes('punctuation')) {\n return;\n }\n\n // Track depth\n if (token.content === openChar) {\n depth++;\n } else if (token.content === (openChar === '{' ? '}' : ']')) {\n depth--;\n }\n\n // Count commas at depth 1 (immediate children)\n if (token.content === ',' && depth === 1) {\n itemCount++;\n }\n });\n }\n\n // Items = commas + 1 (if any content exists)\n return itemCount > 0 ? itemCount + 1 : 0;\n};\n\ninterface CodeHighlightProps {\n id?: string;\n children: string;\n language?: Language;\n rowsToShow?: number;\n light?: boolean;\n className?: string;\n resolveEntityLink?: (token: string) => string | undefined;\n}\n\nconst CodeHighlight = ({\n id,\n children = '',\n language = 'markup',\n rowsToShow,\n light = false,\n className,\n resolveEntityLink,\n}: CodeHighlightProps) => {\n const [expanded, { toggle: toggleExpanded }] = useToggle();\n const rowCount = useMemo(() => children.match(/\\n/g)?.length ?? 0, [children]);\n\n // JSON folding state\n const [collapsedLines, setCollapsedLines] = useState<Set<number>>(new Set());\n const [hasCollapsibleRegions, setHasCollapsibleRegions] = useState(false);\n const collapsibleRegionsRef = useRef<Map<number, CollapsibleRegion>>(new Map());\n\n // Sync hasCollapsibleRegions state from ref after render (avoids state update during render)\n useLayoutEffect(() => {\n if (language !== 'json') {\n if (hasCollapsibleRegions) {\n setHasCollapsibleRegions(false);\n }\n return;\n }\n\n const hasRegions = collapsibleRegionsRef.current.size > 0;\n if (hasRegions !== hasCollapsibleRegions) {\n setHasCollapsibleRegions(hasRegions);\n }\n });\n\n const toggleLineCollapse = useCallback(\n (lineNumber: number, event?: React.KeyboardEvent | React.MouseEvent) => {\n // Prevent default if it's a keyboard event to avoid page scrolling\n if (event && 'key' in event) {\n event.preventDefault();\n }\n\n setCollapsedLines((prev) => {\n const next = new Set(prev);\n if (next.has(lineNumber)) {\n next.delete(lineNumber);\n } else {\n next.add(lineNumber);\n }\n return next;\n });\n },\n [],\n );\n\n const collapseAll = useCallback(() => {\n setCollapsedLines(new Set(collapsibleRegionsRef.current.keys()));\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsedLines(new Set());\n }, []);\n\n const allowExpanding = rowsToShow != null && rowsToShow < rowCount;\n\n return (\n <Wrapper className={className}>\n {(allowExpanding || hasCollapsibleRegions) && (\n <ExpandButtonContainer>\n {hasCollapsibleRegions && (\n <>\n <Button\n id={`code-highlight__${id}__collapse-all`}\n size='sm'\n variant='inverse'\n onClick={collapseAll}\n aria-label='Collapse all JSON regions'\n data-test='code-highlight__collapse-all'\n >\n Collapse All\n </Button>\n <Button\n id={`code-highlight__${id}__expand-all`}\n size='sm'\n variant='inverse'\n onClick={expandAll}\n aria-label='Expand all JSON regions'\n data-test='code-highlight__expand-all'\n >\n Expand All\n </Button>\n </>\n )}\n {allowExpanding && (\n <Button\n id={`code-highlight__${id}__expand-button`}\n size='sm'\n width='icon'\n onClick={toggleExpanded}\n variant='inverse'\n data-test='code-highlight__expand'\n >\n {expanded ? <ArrowCollapseIcon /> : <ArrowExpandIcon />}\n </Button>\n )}\n </ExpandButtonContainer>\n )}\n <Highlight\n data-test='code-highlight'\n theme={light ? themes.nightOwlLight : THEME}\n code={children}\n prism={Prism}\n language={language}\n >\n {({ className, style, tokens, getLineProps, getTokenProps }) => {\n // Compute collapsible regions from tokens (only for JSON)\n const collapsibleRegions =\n language === 'json' ? analyzeJsonStructure(tokens, children) : new Map();\n\n // Update ref (state will be synced in useLayoutEffect)\n collapsibleRegionsRef.current = collapsibleRegions;\n\n const isJsonFoldingEnabled = collapsibleRegions.size > 0;\n\n // Determine which lines should be hidden based on collapsed state\n const hiddenLines = new Set<number>();\n collapsedLines.forEach((collapsedLine) => {\n const region = collapsibleRegions.get(collapsedLine);\n if (region) {\n // Hide all lines between start and end (exclusive)\n for (let i = region.startLine + 1; i <= region.endLine; i++) {\n hiddenLines.add(i);\n }\n }\n });\n\n return (\n <Pre\n className={className}\n style={style}\n data-test={id}\n expanded={expanded}\n rowsToShow={rowsToShow}\n >\n {tokens.map((line, i) => {\n // Skip hidden lines\n if (hiddenLines.has(i)) {\n return null;\n }\n\n const region = collapsibleRegions.get(i);\n const isCollapsed = collapsedLines.has(i);\n const isCollapsible = region != null;\n\n return (\n <Line key={i} {...getLineProps({ line, key: i })}>\n <LineNo>{i + 1}</LineNo>\n <LineContent>\n {isCollapsible && (\n <CollapseTriangle\n $isCollapsed={isCollapsed}\n onClick={(e) => toggleLineCollapse(i, e)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n toggleLineCollapse(i, e);\n }\n }}\n aria-expanded={!isCollapsed}\n aria-label={`${isCollapsed ? 'Expand' : 'Collapse'} JSON ${region?.type} with ${region?.itemCount} items`}\n type='button'\n tabIndex={0}\n data-test={`code-highlight__collapse-toggle__${i}`}\n >\n {isCollapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}\n </CollapseTriangle>\n )}\n {!isCollapsible && isJsonFoldingEnabled && <IndentSpacer />}\n {isCollapsed && region ? (\n // Render collapsed representation\n <>\n {line.map((token, key) => {\n const tokenProps = getTokenProps({ token, key });\n // Only render up to the opening bracket\n if (token.content === '{' || token.content === '[') {\n return (\n <span key={key}>\n <span {...tokenProps} />\n <CollapsedItemCount>\n {` ${region.itemCount} ${region.itemCount === 1 ? 'item' : 'items'} `}\n </CollapsedItemCount>\n <span {...tokenProps}>\n {region.type === 'object' ? '}' : ']'}\n </span>\n </span>\n );\n }\n // Render tokens before the bracket\n return <span key={key} {...tokenProps} />;\n })}\n </>\n ) : (\n // Render normal line\n <>\n {line.map((token, key) => {\n const tokenProps = getTokenProps({ token, key });\n const tokenLink =\n resolveEntityLink != null && token.types[0] === 'string'\n ? resolveEntityLink(\n token.content.slice(1, token.content.length - 1),\n )\n : undefined;\n\n return tokenLink != null ? (\n <span {...tokenProps}>\n "\n <Link to={tokenLink} {...tokenProps}>\n {tokenProps.children.slice(1, tokenProps.children.length - 1)}\n </Link>\n "\n </span>\n ) : (\n <span key={key} {...tokenProps} />\n );\n })}\n </>\n )}\n </LineContent>\n </Line>\n );\n })}\n </Pre>\n );\n }}\n </Highlight>\n </Wrapper>\n );\n};\n\nexport default CodeHighlight;\n\n// Based off of https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/themes/duotoneDark.js\n// NOTE: This theme uses hardcoded hex colors instead of design tokens because it's a specialized\n// syntax highlighting theme for the prism-react-renderer library. The colors are carefully chosen\n// for code readability and are not semantic UI colors from our design system.\nconst THEME: PrismTheme = {\n plain: {\n backgroundColor: '#161320', // edited\n color: '#9a86fd',\n },\n styles: [\n {\n types: ['comment', 'prolog', 'doctype', 'cdata', 'punctuation'],\n style: {\n color: '#6c6783',\n },\n },\n {\n types: ['namespace'],\n style: {\n opacity: 0.7,\n },\n },\n {\n types: ['tag', 'operator', 'number', 'keyword'],\n style: {\n color: '#e09142',\n fontWeight: 'bold', // added for more contrast\n },\n },\n {\n types: ['property', 'function'],\n style: {\n color: '#9a86fd',\n },\n },\n {\n types: ['tag-id', 'selector', 'atrule-id'],\n style: {\n color: '#eeebff',\n },\n },\n {\n types: ['attr-name'],\n style: {\n color: '#c4b9fe',\n },\n },\n {\n types: [\n 'boolean',\n 'string',\n 'entity',\n 'url',\n 'attr-value',\n 'control',\n 'directive',\n 'unit',\n 'statement',\n 'regex',\n 'at-rule',\n 'placeholder',\n 'variable',\n ],\n style: {\n color: '#ffcc99',\n },\n },\n {\n types: ['deleted'],\n style: {\n textDecorationLine: 'line-through',\n },\n },\n {\n types: ['inserted'],\n style: {\n textDecorationLine: 'underline',\n },\n },\n {\n types: ['italic'],\n style: {\n fontStyle: 'italic',\n },\n },\n {\n types: ['important', 'bold'],\n style: {\n fontWeight: 'bold',\n },\n },\n {\n types: ['important'],\n style: {\n color: '#c4b9fe',\n },\n },\n ],\n};\n","import CodeHighlight from './CodeHighlight';\n\nexport default CodeHighlight;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["Prism","ChevronRightIcon","ChevronDownIcon"],"sources":["../../../src/components/CodeHighlight/CodeHighlight.tsx","../../../src/components/CodeHighlight/index.ts"],"sourcesContent":["import { Highlight, type Language, type PrismTheme, themes } from 'prism-react-renderer';\nimport { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport styled from 'styled-components';\n\nimport Button from '@persona/design-system/components/Button';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { focusOutline } from '@persona/design-system/mixins/focus';\nimport { Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon } from '@persona/icons';\nimport { ChevronDownIcon, ChevronRightIcon } from '@persona/icons/12px';\n\nimport useToggle from '#src/lib/useToggle';\nimport { semanticScrollbar } from '#src/mixins/scrollbar';\n\nimport Prism from './PrismWithLanguages';\n\nconst LINE_HEIGHT = 1.5;\n\nexport const Wrapper = styled.div`\n font-family: ${({ theme }) => theme.text.fontFamily.mono};\n font-size: ${({ theme }) => theme.text.paragraph.sm.fontSize};\n line-height: ${LINE_HEIGHT};\n text-align: center;\n position: relative;\n`;\n\nexport const ExpandButtonContainer = styled.div`\n position: absolute;\n top: ${Spacing[2]};\n right: ${Spacing[4]};\n display: flex;\n gap: ${Spacing[1]};\n z-index: ${Z_INDICES.withShadow};\n`;\n\nexport const CollapseTriangle = styled.button<{ $isCollapsed: boolean }>`\n cursor: pointer;\n user-select: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n margin-right: ${Spacing[1]};\n color: ${Color.TextSecondary};\n background: none;\n border: none;\n padding: 0;\n\n &:hover {\n color: ${Color.TextActive};\n }\n\n ${focusOutline}\n`;\n\nexport const Pre = styled.pre<{ expanded: boolean; rowsToShow?: number }>`\n max-height: ${({ theme, expanded, rowsToShow }) => {\n if (expanded || rowsToShow == null) {\n return 'unset';\n }\n\n const charHeight = parseFloat(theme.text.paragraph.sm.fontSize);\n const rowHeight = charHeight * LINE_HEIGHT;\n const marginHeight = charHeight * 2; // margin is 1rem\n // Row height + top/bottom padding\n return `${rowsToShow * rowHeight + marginHeight}px`;\n }};\n\n border-radius: ${({ theme }) => theme.element.borderRadius};\n font-family: inherit;\n text-align: left;\n padding: 1rem; // Custom padding to match typical code block formatting\n overflow: auto;\n ${semanticScrollbar}\n\n a {\n /* overwrite dashboard global styles */\n font-size: inherit;\n line-height: inherit;\n text-decoration: underline;\n }\n`;\n\nexport const Line = styled.div`\n display: table-row;\n`;\n\nexport const LineNo = styled.span`\n display: table-cell;\n text-align: right;\n padding-right: 1rem; // Custom padding for line number gutter spacing\n user-select: none;\n opacity: 0.5;\n`;\n\nexport const LineContent = styled.span`\n display: table-cell;\n`;\n\nexport const IndentSpacer = styled.span`\n display: inline-block;\n width: 16px; // Match collapse triangle icon (12px) + margin (4px) for alignment\n`;\n\nexport const CollapsedItemCount = styled.span`\n color: ${Color.TextSecondary};\n`;\n\n// mirrored from lib -- not exported\ntype Token = {\n types: string[];\n content: string;\n empty?: boolean;\n};\n\ntype CollapsibleRegion = {\n startLine: number;\n endLine: number;\n type: 'object' | 'array';\n itemCount: number;\n};\n\n// Analyzes JSON structure from Prism tokens to find collapsible regions\n// This correctly handles brackets/braces inside strings by using tokenization\nconst analyzeJsonStructure = (\n tokens: Token[][],\n jsonString: string,\n): Map<number, CollapsibleRegion> => {\n const collapsibleRegions = new Map<number, CollapsibleRegion>();\n\n try {\n // Validate JSON is parseable\n const parsed = JSON.parse(jsonString);\n\n // Use a stack to track opening brackets/braces with their line numbers\n const stack: Array<{ line: number; char: '{' | '['; depth: number }> = [];\n let depth = 0;\n\n tokens.forEach((line, lineNum) => {\n line.forEach((token) => {\n // Only process punctuation tokens (not strings)\n if (token.types.includes('punctuation')) {\n if (token.content === '{' || token.content === '[') {\n stack.push({ line: lineNum, char: token.content, depth });\n depth++;\n } else if (token.content === '}' || token.content === ']') {\n depth--;\n const opening = stack.pop();\n\n if (opening && opening.line < lineNum) {\n // This is a multi-line object/array\n const startLine = opening.line;\n const endLine = lineNum;\n\n // Skip root-level (depth 0) regions\n if (opening.depth === 0) {\n return;\n }\n\n // Count items in this region\n const itemCount = countItemsInRegion(\n parsed,\n tokens,\n startLine,\n endLine,\n opening.char,\n );\n\n // Only add regions with items (skip empty objects/arrays)\n if (itemCount > 0) {\n collapsibleRegions.set(startLine, {\n startLine,\n endLine,\n type: opening.char === '{' ? 'object' : 'array',\n itemCount,\n });\n }\n }\n }\n }\n });\n });\n } catch {\n // If JSON is invalid, return empty map\n return new Map();\n }\n\n return collapsibleRegions;\n};\n\n// Count items in a collapsible region by counting commas at the same depth\nconst countItemsInRegion = (\n _parsed: unknown,\n tokens: Token[][],\n startLine: number,\n endLine: number,\n openChar: '{' | '[',\n): number => {\n let itemCount = 0;\n let depth = 0;\n\n // Iterate through lines in the region\n for (let i = startLine; i <= endLine; i++) {\n tokens[i]?.forEach((token) => {\n if (!token.types.includes('punctuation')) {\n return;\n }\n\n // Track depth\n if (token.content === openChar) {\n depth++;\n } else if (token.content === (openChar === '{' ? '}' : ']')) {\n depth--;\n }\n\n // Count commas at depth 1 (immediate children)\n if (token.content === ',' && depth === 1) {\n itemCount++;\n }\n });\n }\n\n // Items = commas + 1 (if any content exists)\n return itemCount > 0 ? itemCount + 1 : 0;\n};\n\ninterface CodeHighlightProps {\n id?: string;\n children: string;\n language?: Language;\n rowsToShow?: number;\n light?: boolean;\n className?: string;\n resolveEntityLink?: (token: string) => string | undefined;\n}\n\nconst CodeHighlight = ({\n id,\n children = '',\n language = 'markup',\n rowsToShow,\n light = false,\n className,\n resolveEntityLink,\n}: CodeHighlightProps) => {\n const [expanded, { toggle: toggleExpanded }] = useToggle();\n const rowCount = useMemo(() => children.match(/\\n/g)?.length ?? 0, [children]);\n\n // JSON folding state\n const [collapsedLines, setCollapsedLines] = useState<Set<number>>(new Set());\n const [hasCollapsibleRegions, setHasCollapsibleRegions] = useState(false);\n const collapsibleRegionsRef = useRef<Map<number, CollapsibleRegion>>(new Map());\n\n // Sync hasCollapsibleRegions state from ref after render (avoids state update during render)\n useLayoutEffect(() => {\n if (language !== 'json') {\n if (hasCollapsibleRegions) {\n setHasCollapsibleRegions(false);\n }\n return;\n }\n\n const hasRegions = collapsibleRegionsRef.current.size > 0;\n if (hasRegions !== hasCollapsibleRegions) {\n setHasCollapsibleRegions(hasRegions);\n }\n });\n\n const toggleLineCollapse = useCallback(\n (lineNumber: number, event?: React.KeyboardEvent | React.MouseEvent) => {\n // Prevent default if it's a keyboard event to avoid page scrolling\n if (event && 'key' in event) {\n event.preventDefault();\n }\n\n setCollapsedLines((prev) => {\n const next = new Set(prev);\n if (next.has(lineNumber)) {\n next.delete(lineNumber);\n } else {\n next.add(lineNumber);\n }\n return next;\n });\n },\n [],\n );\n\n const collapseAll = useCallback(() => {\n setCollapsedLines(new Set(collapsibleRegionsRef.current.keys()));\n }, []);\n\n const expandAll = useCallback(() => {\n setCollapsedLines(new Set());\n }, []);\n\n const allowExpanding = rowsToShow != null && rowsToShow < rowCount;\n\n return (\n <Wrapper className={className}>\n {(allowExpanding || hasCollapsibleRegions) && (\n <ExpandButtonContainer>\n {hasCollapsibleRegions && (\n <>\n <Button\n id={`code-highlight__${id}__collapse-all`}\n size='sm'\n variant='inverse'\n onClick={collapseAll}\n aria-label='Collapse all JSON regions'\n data-test='code-highlight__collapse-all'\n >\n Collapse All\n </Button>\n <Button\n id={`code-highlight__${id}__expand-all`}\n size='sm'\n variant='inverse'\n onClick={expandAll}\n aria-label='Expand all JSON regions'\n data-test='code-highlight__expand-all'\n >\n Expand All\n </Button>\n </>\n )}\n {allowExpanding && (\n <Button\n id={`code-highlight__${id}__expand-button`}\n size='sm'\n width='icon'\n onClick={toggleExpanded}\n variant='inverse'\n data-test='code-highlight__expand'\n >\n {expanded ? <ArrowCollapseIcon /> : <ArrowExpandIcon />}\n </Button>\n )}\n </ExpandButtonContainer>\n )}\n <Highlight\n data-test='code-highlight'\n theme={light ? themes.nightOwlLight : THEME}\n code={children}\n prism={Prism}\n language={language}\n >\n {({ className, style, tokens, getLineProps, getTokenProps }) => {\n // Compute collapsible regions from tokens (only for JSON)\n const collapsibleRegions =\n language === 'json' ? analyzeJsonStructure(tokens, children) : new Map();\n\n // Update ref (state will be synced in useLayoutEffect)\n collapsibleRegionsRef.current = collapsibleRegions;\n\n const isJsonFoldingEnabled = collapsibleRegions.size > 0;\n\n // Determine which lines should be hidden based on collapsed state\n const hiddenLines = new Set<number>();\n collapsedLines.forEach((collapsedLine) => {\n const region = collapsibleRegions.get(collapsedLine);\n if (region) {\n // Hide all lines between start and end (exclusive)\n for (let i = region.startLine + 1; i <= region.endLine; i++) {\n hiddenLines.add(i);\n }\n }\n });\n\n return (\n <Pre\n className={className}\n style={style}\n data-test={id}\n expanded={expanded}\n rowsToShow={rowsToShow}\n >\n {tokens.map((line, i) => {\n // Skip hidden lines\n if (hiddenLines.has(i)) {\n return null;\n }\n\n const region = collapsibleRegions.get(i);\n const isCollapsed = collapsedLines.has(i);\n const isCollapsible = region != null;\n\n return (\n <Line key={i} {...getLineProps({ line, key: i })}>\n <LineNo>{i + 1}</LineNo>\n <LineContent>\n {isCollapsible && (\n <CollapseTriangle\n $isCollapsed={isCollapsed}\n onClick={(e) => toggleLineCollapse(i, e)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n toggleLineCollapse(i, e);\n }\n }}\n aria-expanded={!isCollapsed}\n aria-label={`${isCollapsed ? 'Expand' : 'Collapse'} JSON ${region?.type} with ${region?.itemCount} items`}\n type='button'\n tabIndex={0}\n data-test={`code-highlight__collapse-toggle__${i}`}\n >\n {isCollapsed ? <ChevronRightIcon /> : <ChevronDownIcon />}\n </CollapseTriangle>\n )}\n {!isCollapsible && isJsonFoldingEnabled && <IndentSpacer />}\n {isCollapsed && region ? (\n // Render collapsed representation\n <>\n {line.map((token, key) => {\n const tokenProps = getTokenProps({ token, key });\n // Only render up to the opening bracket\n if (token.content === '{' || token.content === '[') {\n return (\n <span key={key}>\n <span {...tokenProps} />\n <CollapsedItemCount>\n {` ${region.itemCount} ${region.itemCount === 1 ? 'item' : 'items'} `}\n </CollapsedItemCount>\n <span {...tokenProps}>\n {region.type === 'object' ? '}' : ']'}\n </span>\n </span>\n );\n }\n // Render tokens before the bracket\n return <span key={key} {...tokenProps} />;\n })}\n </>\n ) : (\n // Render normal line\n <>\n {line.map((token, key) => {\n const tokenProps = getTokenProps({ token, key });\n const tokenLink =\n resolveEntityLink != null && token.types[0] === 'string'\n ? resolveEntityLink(\n token.content.slice(1, token.content.length - 1),\n )\n : undefined;\n\n return tokenLink != null ? (\n <span {...tokenProps}>\n "\n <Link to={tokenLink} {...tokenProps}>\n {tokenProps.children.slice(1, tokenProps.children.length - 1)}\n </Link>\n "\n </span>\n ) : (\n <span key={key} {...tokenProps} />\n );\n })}\n </>\n )}\n </LineContent>\n </Line>\n );\n })}\n </Pre>\n );\n }}\n </Highlight>\n </Wrapper>\n );\n};\n\nexport default CodeHighlight;\n\n// Based off of https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/themes/duotoneDark.js\n// NOTE: This theme uses hardcoded hex colors instead of design tokens because it's a specialized\n// syntax highlighting theme for the prism-react-renderer library. The colors are carefully chosen\n// for code readability and are not semantic UI colors from our design system.\nconst THEME: PrismTheme = {\n plain: {\n backgroundColor: '#161320', // edited\n color: '#9a86fd',\n },\n styles: [\n {\n types: ['comment', 'prolog', 'doctype', 'cdata', 'punctuation'],\n style: {\n color: '#6c6783',\n },\n },\n {\n types: ['namespace'],\n style: {\n opacity: 0.7,\n },\n },\n {\n types: ['tag', 'operator', 'number', 'keyword'],\n style: {\n color: '#e09142',\n fontWeight: 'bold', // added for more contrast\n },\n },\n {\n types: ['property', 'function'],\n style: {\n color: '#9a86fd',\n },\n },\n {\n types: ['tag-id', 'selector', 'atrule-id'],\n style: {\n color: '#eeebff',\n },\n },\n {\n types: ['attr-name'],\n style: {\n color: '#c4b9fe',\n },\n },\n {\n types: [\n 'boolean',\n 'string',\n 'entity',\n 'url',\n 'attr-value',\n 'control',\n 'directive',\n 'unit',\n 'statement',\n 'regex',\n 'at-rule',\n 'placeholder',\n 'variable',\n ],\n style: {\n color: '#ffcc99',\n },\n },\n {\n types: ['deleted'],\n style: {\n textDecorationLine: 'line-through',\n },\n },\n {\n types: ['inserted'],\n style: {\n textDecorationLine: 'underline',\n },\n },\n {\n types: ['italic'],\n style: {\n fontStyle: 'italic',\n },\n },\n {\n types: ['important', 'bold'],\n style: {\n fontWeight: 'bold',\n },\n },\n {\n types: ['important'],\n style: {\n color: '#c4b9fe',\n },\n },\n ],\n};\n","import CodeHighlight from './CodeHighlight';\n\nexport default CodeHighlight;\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { D as flattenOptions, a as ComboboxOptionGroup, i as ComboboxOption, o as ComboboxOptionsOrGroups, t as CaretButton } from "../../ComboboxBase-
|
|
2
|
-
import { n as ComboboxProps, t as Combobox } from "../../Combobox-
|
|
1
|
+
import { D as flattenOptions, a as ComboboxOptionGroup, i as ComboboxOption, o as ComboboxOptionsOrGroups, t as CaretButton } from "../../ComboboxBase-5aSDuY-E.mjs";
|
|
2
|
+
import { n as ComboboxProps, t as Combobox } from "../../Combobox-O6LbofT2.mjs";
|
|
3
3
|
export { CaretButton, Combobox, Combobox as default, ComboboxOption, ComboboxOptionGroup, ComboboxOptionsOrGroups, ComboboxProps, flattenOptions };
|
|
@@ -3,18 +3,18 @@ import { a as FilterConditionOperator, c as FilterFieldType, d as FilterRuleValu
|
|
|
3
3
|
import { n as RawFieldInfo, r as buildFieldRegistry, t as FieldRegistry } from "../../../FieldRegistry-a44G08fS.mjs";
|
|
4
4
|
import { n as ValueControlResolver, r as resolveValueControl, t as ResolveValueControlOptions } from "../../../value-control-resolver-CMyFwEY7.mjs";
|
|
5
5
|
import { t as FilterBar } from "../../../FilterBar-BpMguIXl.mjs";
|
|
6
|
-
import { a as ComboboxFilterConfig, c as FilterRenderOptions, d as InputFilterConfig, f as MultiSelectFilterConfig, i as BaseFilterConfig, l as FilterTypeDefinition, o as DateRangeFilterConfig, p as SelectFilterConfig, r as BaseActiveFilter, s as FilterConfig, t as ActiveFilter, u as FilterTypeResolver } from "../../../types-
|
|
7
|
-
import { i as TableViewConfigurationProps, n as TableViewConfigurationDropdown, r as TableViewConfigurationDropdownProps, t as TableViewConfiguration } from "../../../TableViewConfigurationDropdown-
|
|
8
|
-
import { n as TableControlsFiltersV2Props, r as TableControlsProps, t as TableControls } from "../../../TableControls-
|
|
6
|
+
import { a as ComboboxFilterConfig, c as FilterRenderOptions, d as InputFilterConfig, f as MultiSelectFilterConfig, i as BaseFilterConfig, l as FilterTypeDefinition, o as DateRangeFilterConfig, p as SelectFilterConfig, r as BaseActiveFilter, s as FilterConfig, t as ActiveFilter, u as FilterTypeResolver } from "../../../types-sUEmxsGM.mjs";
|
|
7
|
+
import { i as TableViewConfigurationProps, n as TableViewConfigurationDropdown, r as TableViewConfigurationDropdownProps, t as TableViewConfiguration } from "../../../TableViewConfigurationDropdown-C5bjxTGX.mjs";
|
|
8
|
+
import { n as TableControlsFiltersV2Props, r as TableControlsProps, t as TableControls } from "../../../TableControls-BHv-tXA-.mjs";
|
|
9
9
|
import { n as DataTableCompactBar } from "../../../CompactBar-zYfXjFmn.mjs";
|
|
10
|
-
import { i as useTableControls, n as TableControlsContextProps, r as TableControlsProvider, t as TableControlsContext } from "../../../TableControlsContext-
|
|
11
|
-
import { a as resolveFilterTypeDefinition, i as isFilterActive, n as FiltersContainer, r as getActiveFilters } from "../../../filters-
|
|
10
|
+
import { i as useTableControls, n as TableControlsContextProps, r as TableControlsProvider, t as TableControlsContext } from "../../../TableControlsContext-D6rifk-v.mjs";
|
|
11
|
+
import { a as resolveFilterTypeDefinition, i as isFilterActive, n as FiltersContainer, r as getActiveFilters } from "../../../filters-CkAFU8LV.mjs";
|
|
12
12
|
import { t as dateRuleIntent } from "../../../date-rule-intent-C1aptAoX.mjs";
|
|
13
13
|
import { t as resolveDateRangeRuleValue } from "../../../date-range-rule-value-CrVBpQcf.mjs";
|
|
14
14
|
import { t as FilterBarProps } from "../../../index-FgIOTuJ4.mjs";
|
|
15
15
|
import { a as useFilterBarSize, i as FilterSizeTokens, t as FILTER_SIZE_TOKENS } from "../../../filter-size-context-CbT4pi3S.mjs";
|
|
16
16
|
import { n as PillShellProps, t as PillShell } from "../../../PillShell-B35z66jZ.mjs";
|
|
17
|
-
import { _ as isNumericComparisonOperator, a as emptyValueForRule, b as reconcileValueForOperator, c as getDefaultOperatorForType, d as getOperatorsForType, n as NumericComparisonOperator, p as isCompleteDateRange, t as NUMERIC_COMPARISON_OPERATORS, u as getOperatorsForField, v as isRangeOperator, y as isValuelessOperator } from "../../../operators-
|
|
17
|
+
import { _ as isNumericComparisonOperator, a as emptyValueForRule, b as reconcileValueForOperator, c as getDefaultOperatorForType, d as getOperatorsForType, n as NumericComparisonOperator, p as isCompleteDateRange, t as NUMERIC_COMPARISON_OPERATORS, u as getOperatorsForField, v as isRangeOperator, y as isValuelessOperator } from "../../../operators-BrrJKENE.mjs";
|
|
18
18
|
import { a as decodeFilterStateFromUrl, i as decodeFilterStateFromString, n as UrlStateCodecResult, o as encodeFilterStateToUrlParam, r as applyFilterStateToSearchParams, t as FILTER_STATE_URL_PARAM } from "../../../url-state-CmgyDnG7.mjs";
|
|
19
19
|
import { n as UseFilterStateV2Result, r as useFilterStateV2, t as UseFilterStateV2Options } from "../../../useFilterStateV2-CPBt0qwc.mjs";
|
|
20
20
|
import { n as isFilterStateV2, r as pruneToRegistry, t as hasCompleteValue } from "../../../validation-BaqPVG1C.mjs";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as isNumericComparisonOperator, B as useTableControls, C as useFilterBarSize, D as getOperatorsForField, E as getDefaultOperatorForType, F as getActiveFilters, H as DataTableCompactBar, I as isFilterActive, L as resolveFilterTypeDefinition, M as isValuelessOperator, N as reconcileValueForOperator, O as getOperatorsForType, P as FiltersContainer, R as TableControlsContext, S as FILTER_SIZE_TOKENS, T as emptyValueForRule, V as ControlBar, _ as EMPTY_FILTER_STATE, a as encodeFilterStateToUrlParam, b as resolveValueControl, c as FilterBar_default, d as TableViewConfiguration, f as TableViewConfigurationDropdown, g as pruneToRegistry, h as isFilterStateV2, i as decodeFilterStateFromUrl, j as isRangeOperator, k as isCompleteDateRange, l as resolveDateRangeRuleValue, m as hasCompleteValue, n as applyFilterStateToSearchParams, o as FieldRegistry, p as useFilterStateV2, r as decodeFilterStateFromString, s as buildFieldRegistry, t as FILTER_STATE_URL_PARAM, u as TableControls, v as isEmptyState, w as NUMERIC_COMPARISON_OPERATORS, x as dateRuleIntent, y as PillShell, z as TableControlsProvider } from "../../../TableControls-
|
|
1
|
+
import { A as isNumericComparisonOperator, B as useTableControls, C as useFilterBarSize, D as getOperatorsForField, E as getDefaultOperatorForType, F as getActiveFilters, H as DataTableCompactBar, I as isFilterActive, L as resolveFilterTypeDefinition, M as isValuelessOperator, N as reconcileValueForOperator, O as getOperatorsForType, P as FiltersContainer, R as TableControlsContext, S as FILTER_SIZE_TOKENS, T as emptyValueForRule, V as ControlBar, _ as EMPTY_FILTER_STATE, a as encodeFilterStateToUrlParam, b as resolveValueControl, c as FilterBar_default, d as TableViewConfiguration, f as TableViewConfigurationDropdown, g as pruneToRegistry, h as isFilterStateV2, i as decodeFilterStateFromUrl, j as isRangeOperator, k as isCompleteDateRange, l as resolveDateRangeRuleValue, m as hasCompleteValue, n as applyFilterStateToSearchParams, o as FieldRegistry, p as useFilterStateV2, r as decodeFilterStateFromString, s as buildFieldRegistry, t as FILTER_STATE_URL_PARAM, u as TableControls, v as isEmptyState, w as NUMERIC_COMPARISON_OPERATORS, x as dateRuleIntent, y as PillShell, z as TableControlsProvider } from "../../../TableControls-C-0Dw8vM.mjs";
|
|
2
2
|
export { ControlBar, DataTableCompactBar, EMPTY_FILTER_STATE, FILTER_SIZE_TOKENS, FILTER_STATE_URL_PARAM, FieldRegistry, FilterBar_default as FilterBar, FiltersContainer, NUMERIC_COMPARISON_OPERATORS, PillShell, TableControlsContext, TableControlsProvider, TableViewConfiguration, TableViewConfigurationDropdown, applyFilterStateToSearchParams, buildFieldRegistry, dateRuleIntent, decodeFilterStateFromString, decodeFilterStateFromUrl, TableControls as default, emptyValueForRule, encodeFilterStateToUrlParam, getActiveFilters, getDefaultOperatorForType, getOperatorsForField, getOperatorsForType, hasCompleteValue, isCompleteDateRange, isEmptyState, isFilterActive, isFilterStateV2, isNumericComparisonOperator, isRangeOperator, isValuelessOperator, pruneToRegistry, reconcileValueForOperator, resolveDateRangeRuleValue, resolveFilterTypeDefinition, resolveValueControl, useFilterBarSize, useFilterStateV2, useTableControls };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { C as RowAction, D as RowDataWithTourTarget, E as RowDataWithSubrowsToAlwaysShowIds, O as SortProps, S as RenderValueStickerFormatConfig, T as RowDataWithSubrows, _ as DataTableColumns, a as DataTableColumnBaseFormat, b as DatetimeConfig, c as DataTableColumnDatetimeFormat, d as DataTableColumnImageFormat, f as DataTableColumnNumberFormat, g as DataTableColumnURLFormat, h as DataTableColumnStringFormat, i as ColumnConfig, k as StickerMapping, l as DataTableColumnFormat, m as DataTableColumnStickerFormat, n as ClientFilterConfig, o as DataTableColumnCheckboxFormat, p as DataTableColumnPiiFormat, r as ClientFilterType, s as DataTableColumnDateFormat, t as BulkAction, u as DataTableColumnIDFormat, v as DataTableVariables, w as RowDataWithDetails, x as HeadlessFilterConfig, y as DateConfig } from "../../types-
|
|
2
|
-
import { r as useTableColumns, t as RenderFormatFn } from "../../useTableColumns-
|
|
3
|
-
import { a as FloatingActionBarContainer, i as DataTableProps, n as DataTableContainer, r as DataTableControls, t as DataTable } from "../../DataTable-
|
|
1
|
+
import { C as RowAction, D as RowDataWithTourTarget, E as RowDataWithSubrowsToAlwaysShowIds, O as SortProps, S as RenderValueStickerFormatConfig, T as RowDataWithSubrows, _ as DataTableColumns, a as DataTableColumnBaseFormat, b as DatetimeConfig, c as DataTableColumnDatetimeFormat, d as DataTableColumnImageFormat, f as DataTableColumnNumberFormat, g as DataTableColumnURLFormat, h as DataTableColumnStringFormat, i as ColumnConfig, k as StickerMapping, l as DataTableColumnFormat, m as DataTableColumnStickerFormat, n as ClientFilterConfig, o as DataTableColumnCheckboxFormat, p as DataTableColumnPiiFormat, r as ClientFilterType, s as DataTableColumnDateFormat, t as BulkAction, u as DataTableColumnIDFormat, v as DataTableVariables, w as RowDataWithDetails, x as HeadlessFilterConfig, y as DateConfig } from "../../types-DoJubhWu.mjs";
|
|
2
|
+
import { r as useTableColumns, t as RenderFormatFn } from "../../useTableColumns-nPrbDfF_.mjs";
|
|
3
|
+
import { a as FloatingActionBarContainer, i as DataTableProps, n as DataTableContainer, r as DataTableControls, t as DataTable } from "../../DataTable-BXHmi-SW.mjs";
|
|
4
4
|
import { t as FloatingActionBar } from "../../FloatingActionBar-DPA9v_yH.mjs";
|
|
5
5
|
import { t as Inserter } from "../../Inserter-BnQVEqHV.mjs";
|
|
6
|
-
import { n as getFilterFnName, t as generateClientFilters } from "../../clientFilterUtils-
|
|
6
|
+
import { n as getFilterFnName, t as generateClientFilters } from "../../clientFilterUtils-DDDG1g7e.mjs";
|
|
7
7
|
import { t as getColumnWidths } from "../../constants-D1hoZ5LO.mjs";
|
|
8
|
-
import { a as renderAsDate, c as renderAsNumber, d as renderAsSticker, f as renderAsString, i as renderAsCopyableString, l as renderAsPDSFormat, n as renderAsCheckbox, o as renderAsDatetime, p as renderAsURL, r as renderAsCheckboxHeader, s as renderAsLightweightImage, t as PDSFormatOptions, u as renderAsPii } from "../../helpers-
|
|
8
|
+
import { a as renderAsDate, c as renderAsNumber, d as renderAsSticker, f as renderAsString, i as renderAsCopyableString, l as renderAsPDSFormat, n as renderAsCheckbox, o as renderAsDatetime, p as renderAsURL, r as renderAsCheckboxHeader, s as renderAsLightweightImage, t as PDSFormatOptions, u as renderAsPii } from "../../helpers-Dvvcz-hL.mjs";
|
|
9
9
|
export { BulkAction, ClientFilterConfig, ClientFilterType, ColumnConfig, DataTable, DataTable as default, DataTableColumnBaseFormat, DataTableColumnCheckboxFormat, DataTableColumnDateFormat, DataTableColumnDatetimeFormat, DataTableColumnFormat, DataTableColumnIDFormat, DataTableColumnImageFormat, DataTableColumnNumberFormat, DataTableColumnPiiFormat, DataTableColumnStickerFormat, DataTableColumnStringFormat, DataTableColumnURLFormat, DataTableColumns, DataTableContainer, DataTableControls, DataTableProps, DataTableVariables, DateConfig, DatetimeConfig, FloatingActionBar, FloatingActionBarContainer, HeadlessFilterConfig, Inserter, PDSFormatOptions, RenderFormatFn, RenderValueStickerFormatConfig, RowAction, RowDataWithDetails, RowDataWithSubrows, RowDataWithSubrowsToAlwaysShowIds, RowDataWithTourTarget, SortProps, StickerMapping, generateClientFilters, getColumnWidths, getFilterFnName, renderAsCheckbox, renderAsCheckboxHeader, renderAsCopyableString, renderAsDate, renderAsDatetime, renderAsLightweightImage, renderAsNumber, renderAsPDSFormat, renderAsPii, renderAsSticker, renderAsString, renderAsURL, useTableColumns };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as getFilterFnName, _ as renderAsString, a as useTableColumns, b as getColumnWidths, c as renderAsCheckboxHeader, d as renderAsDatetime, f as renderAsLightweightImage, g as renderAsSticker, h as renderAsPii, i as FloatingActionBarContainer, l as renderAsCopyableString, m as renderAsPDSFormat, n as DataTableContainer, o as Inserter, p as renderAsNumber, r as DataTableControls, s as renderAsCheckbox, t as DataTable, u as renderAsDate, v as renderAsURL, x as generateClientFilters, y as FloatingActionBar } from "../../DataTable-
|
|
1
|
+
import { S as getFilterFnName, _ as renderAsString, a as useTableColumns, b as getColumnWidths, c as renderAsCheckboxHeader, d as renderAsDatetime, f as renderAsLightweightImage, g as renderAsSticker, h as renderAsPii, i as FloatingActionBarContainer, l as renderAsCopyableString, m as renderAsPDSFormat, n as DataTableContainer, o as Inserter, p as renderAsNumber, r as DataTableControls, s as renderAsCheckbox, t as DataTable, u as renderAsDate, v as renderAsURL, x as generateClientFilters, y as FloatingActionBar } from "../../DataTable-CAfZNJmb.mjs";
|
|
2
2
|
export { DataTable, DataTable as default, DataTableContainer, DataTableControls, FloatingActionBar, FloatingActionBarContainer, Inserter, generateClientFilters, getColumnWidths, getFilterFnName, renderAsCheckbox, renderAsCheckboxHeader, renderAsCopyableString, renderAsDate, renderAsDatetime, renderAsLightweightImage, renderAsNumber, renderAsPDSFormat, renderAsPii, renderAsSticker, renderAsString, renderAsURL, useTableColumns };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as RowAction, D as RowDataWithTourTarget, E as RowDataWithSubrowsToAlwaysShowIds, O as SortProps, S as RenderValueStickerFormatConfig, T as RowDataWithSubrows, _ as DataTableColumns, a as DataTableColumnBaseFormat, b as DatetimeConfig, c as DataTableColumnDatetimeFormat, d as DataTableColumnImageFormat, f as DataTableColumnNumberFormat, g as DataTableColumnURLFormat, h as DataTableColumnStringFormat, i as ColumnConfig, k as StickerMapping, l as DataTableColumnFormat, m as DataTableColumnStickerFormat, n as ClientFilterConfig, o as DataTableColumnCheckboxFormat, p as DataTableColumnPiiFormat, r as ClientFilterType, s as DataTableColumnDateFormat, t as BulkAction, u as DataTableColumnIDFormat, v as DataTableVariables, w as RowDataWithDetails, x as HeadlessFilterConfig, y as DateConfig } from "../../types-
|
|
1
|
+
import { C as RowAction, D as RowDataWithTourTarget, E as RowDataWithSubrowsToAlwaysShowIds, O as SortProps, S as RenderValueStickerFormatConfig, T as RowDataWithSubrows, _ as DataTableColumns, a as DataTableColumnBaseFormat, b as DatetimeConfig, c as DataTableColumnDatetimeFormat, d as DataTableColumnImageFormat, f as DataTableColumnNumberFormat, g as DataTableColumnURLFormat, h as DataTableColumnStringFormat, i as ColumnConfig, k as StickerMapping, l as DataTableColumnFormat, m as DataTableColumnStickerFormat, n as ClientFilterConfig, o as DataTableColumnCheckboxFormat, p as DataTableColumnPiiFormat, r as ClientFilterType, s as DataTableColumnDateFormat, t as BulkAction, u as DataTableColumnIDFormat, v as DataTableVariables, w as RowDataWithDetails, x as HeadlessFilterConfig, y as DateConfig } from "../../types-DoJubhWu.mjs";
|
|
2
2
|
export { BulkAction, ClientFilterConfig, ClientFilterType, ColumnConfig, DataTableColumnBaseFormat, DataTableColumnCheckboxFormat, DataTableColumnDateFormat, DataTableColumnDatetimeFormat, DataTableColumnFormat, DataTableColumnIDFormat, DataTableColumnImageFormat, DataTableColumnNumberFormat, DataTableColumnPiiFormat, DataTableColumnStickerFormat, DataTableColumnStringFormat, DataTableColumnURLFormat, DataTableColumns, DataTableVariables, DateConfig, DatetimeConfig, HeadlessFilterConfig, RenderValueStickerFormatConfig, RowAction, RowDataWithDetails, RowDataWithSubrows, RowDataWithSubrowsToAlwaysShowIds, RowDataWithTourTarget, SortProps, StickerMapping };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as DropdownMenuProps, r as _default, t as DropdownMenu } from "../../DropdownMenu-
|
|
1
|
+
import { n as DropdownMenuProps, r as _default, t as DropdownMenu } from "../../DropdownMenu-CAYVX9Q3.mjs";
|
|
2
2
|
export { DropdownMenu, DropdownMenuProps, _default as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["uuid"],"sources":["../../../src/components/FloatingPanel/utils.ts","../../../src/components/FloatingPanel/FloatingPanel.tsx","../../../src/components/FloatingPanel/FloatingPanelContext.tsx","../../../src/components/FloatingPanel/FloatingPanelRenderer.tsx"],"sourcesContent":["export const PADDING = 8;\nexport const EDGE_PADDING = PADDING * 6;\n\n// Cap a content-fitting panel's height to the room below its top edge so it\n// can't overflow the viewport bottom when anchored partway down the screen.\nexport function autoFitMaxHeight(viewportHeight: number, topOffset: number, minHeight: number) {\n return Math.max(minHeight, viewportHeight - Math.max(EDGE_PADDING, topOffset) - EDGE_PADDING);\n}\n","import { flip, offset, type Placement, shift, useFloating } from '@floating-ui/react';\nimport { motion, useDragControls, useMotionValue, useReducedMotion } from 'framer-motion';\nimport {\n isValidElement,\n type ReactNode,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal, flushSync } from 'react-dom';\nimport styled, { css } from 'styled-components';\n\nimport { IconButton } from '@persona/design-system/components/Button';\nimport Stack from '@persona/design-system/components/Stack';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { paragraphMixins } from '@persona/design-system/mixins/text';\nimport { Elevation } from '@persona/design-system/variables/effect';\nimport { BorderRadius, Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon, XIcon } from '@persona/icons';\nimport ConfigContext from 'design-system/lib/ConfigContext';\nimport { usePathname } from 'design-system/lib/router';\nimport { semanticColor } from 'design-system/lib/semanticColor';\nimport { semanticScrollbar } from 'design-system/mixins/scrollbar';\n\nimport { autoFitMaxHeight, PADDING } from './utils';\n\nexport const FLOATING_PANEL_ID_PREFIX = 'floating-panel__' as const;\n\nenum ResizeDirection {\n North = 'n',\n South = 's',\n East = 'e',\n West = 'w',\n NorthEast = 'ne',\n NorthWest = 'nw',\n SouthEast = 'se',\n SouthWest = 'sw',\n}\n\nexport interface FloatingPanelProps {\n /** The title text displayed in the panel header */\n title: ReactNode;\n /** Callback function called when the close button is clicked */\n onClose?: () => void;\n /** Content to render inside the main panel area */\n children?: ReactNode;\n /** Optional React component rendered to the left of the expand button in the header */\n headerActions?: ReactNode;\n\n /** Whether the panel displays the fullsize button */\n canFullsize?: boolean;\n\n /** When true, the panel opens already in full-size (maximized) mode. */\n defaultFullSize?: boolean;\n\n /** Initial width of the panel in pixels */\n initialWidth?: number;\n /** Initial height of the panel in pixels */\n initialHeight?: number;\n /** Minimum width the panel can be resized to in pixels */\n minWidth?: number;\n /** Minimum height the panel can be resized to in pixels */\n minHeight?: number;\n\n footerButtons?: ReactNode;\n\n footerAdditionalAction?: ReactNode;\n\n portal?: boolean;\n\n /** Reference to the element that triggered this panel, used for automatic positioning */\n triggerRef?: RefObject<HTMLElement>;\n\n /** Which placement of the trigger element to position the panel on */\n placement?: Placement;\n\n /** Additional main axis offset in pixels from the calculated position. Main axis is defined as the axis in position to where its being defined\n * i.e. right, top, left ,bottom */\n mainAxisOffset?: number;\n\n /** Additional cross offset in pixels from the calculated position. Cross is defined as the axis that runs along the alignment\n * of the floating element. */\n crossAxisOffset?: number;\n\n /** remove padding from the panel content */\n noPadding?: boolean;\n\n /** When true, automatically calls `onClose` if the route changes after the\n * panel mounts. Mirrors the auto-dismiss-on-navigation behavior provided by\n * `PanelProvider` / `usePersistentFloatingPanel` for panels that don't opt\n * into the persistent panel context. Defaults to `false` so existing\n * consumers (e.g. dirty-check confirmation flows) are not broken. */\n dismissOnNavigate?: boolean;\n\n /** When true, the panel's height auto-fits its content via CSS (`max-content`)\n * up to the viewport, instead of using `initialHeight`. Once the user manually\n * resizes, the panel switches to pixel mode and stays there. `initialHeight`\n * is ignored while auto-fitting. */\n fitContent?: boolean;\n}\n\nconst FloatingPanelContainer = styled(motion.div)<{\n $fitHeight?: boolean;\n $maxHeight?: number;\n $minHeight?: number;\n}>`\n position: absolute;\n z-index: ${Z_INDICES.modal};\n background: ${({ theme }) =>\n semanticColor(theme, 'SurfaceElevated', theme.color.background.primary)};\n border: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n border-radius: ${BorderRadius.Lg};\n box-shadow: ${Elevation.Low};\n display: flex;\n flex-direction: column;\n cursor: auto;\n ${({ $fitHeight, $maxHeight, $minHeight }) =>\n $fitHeight &&\n css`\n height: auto;\n max-height: ${$maxHeight ?? 0}px;\n min-height: ${$minHeight ?? 0}px;\n `}\n`;\n\nconst DragHandle = styled(motion.div)<{ isFullSize: boolean }>`\n cursor: ${({ isFullSize }) => (isFullSize ? 'default' : 'grab')};\n user-select: none;\n\n &:active {\n cursor: ${({ isFullSize }) => (isFullSize ? 'default' : 'grabbing')};\n }\n display: flex;\n flex-direction: column;\n justify-content: center;\n min-height: 48px;\n height: 48px;\n overflow: hidden;\n padding: ${Spacing[1]} ${Spacing[1]} ${Spacing[1]} ${Spacing[3]};\n border-bottom: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n`;\n\nconst Footer = styled.div`\n padding: ${Spacing[1]} ${Spacing[1]} ${Spacing[1]} ${Spacing[3]};\n border-top: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n overflow-x: hidden;\n background-color: ${({ theme }) =>\n semanticColor(theme, 'SurfaceElevated', theme.color.background.primary)};\n width: 100%;\n border-radius: 0 0 ${BorderRadius.Lg} ${BorderRadius.Lg};\n`;\n\nconst ResizeHandleBase = styled.div`\n position: absolute;\n user-select: none;\n`;\n\n// Sets the width and height for base corner to 20px\nconst ResizeHandleBaseCorner = styled(ResizeHandleBase)`\n width: 1.25rem;\n height: 1.25rem;\n`;\n\nconst ResizeHandleBottomRight = styled(ResizeHandleBaseCorner)`\n bottom: -0.75rem;\n right: -0.75rem;\n cursor: nwse-resize;\n`;\n\nconst ResizeHandleBottomLeft = styled(ResizeHandleBaseCorner)`\n bottom: -0.75rem;\n left: -0.75rem;\n cursor: nesw-resize;\n`;\n\nconst ResizeHandleTopLeft = styled(ResizeHandleBaseCorner)`\n top: -0.75rem;\n left: -0.75rem;\n cursor: nwse-resize;\n`;\n\nconst ResizeHandleTopRight = styled(ResizeHandleBaseCorner)`\n top: -0.75rem;\n right: -0.75rem;\n cursor: nesw-resize;\n`;\n\n// These are all the Resize handles for the four cardinal direction,\n// To calculate the width, we subtract by the padding of 1rem on both sides\n// which are corners of the panel\nconst ResizeHandleBottom = styled(ResizeHandleBase)`\n bottom: -0.75rem;\n left: 0.5rem;\n width: calc(100% - 1rem);\n height: 1rem;\n cursor: ns-resize;\n user-select: none;\n`;\n\nconst ResizeHandleTop = styled(ResizeHandleBase)`\n top: -0.75rem;\n left: 0.5rem;\n width: calc(100% - 1rem);\n height: 1rem;\n cursor: ns-resize;\n`;\n\nconst ResizeHandleRight = styled(ResizeHandleBase)`\n right: -0.75rem;\n top: 0.5rem;\n width: 1rem;\n height: calc(100% - 1rem);\n cursor: ew-resize;\n`;\n\nconst ResizeHandleLeft = styled(ResizeHandleBase)`\n left: -0.75rem;\n top: 0.5rem;\n width: 1rem;\n height: calc(100% - 1rem);\n cursor: ew-resize;\n`;\n\nconst PanelContent = styled.div<{ $noPadding?: boolean; $fitHeight?: boolean }>`\n overflow-y: auto;\n ${semanticScrollbar}\n overscroll-behavior: contain;\n min-height: 0;\n /* While the panel height is derived from its content, the content must size\n itself (a percentage flex-basis against an indefinite height collapses in\n WebKit); it still shrinks when the panel hits its max-height. */\n flex: ${({ $fitHeight }) => ($fitHeight ? '0 1 auto' : '1 1 0%')};\n padding: ${({ $noPadding }) => ($noPadding ? 0 : Spacing[3])};\n`;\n\n// Sets a min width so that the text will display, but overflows if needed\nconst PanelText = styled.p`\n ${paragraphMixins.sm}\n white-space: nowrap;\n min-width: 3rem;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n font-weight: 500;\n`;\n\nconst StyledIconButton = styled(IconButton)`\n width: 1.5rem;\n height: 1.5rem;\n border-radius: ${BorderRadius.Md};\n`;\n\n// Only rendered when dismissOnNavigate is true, keeping the router lookup out of the\n// main component body so FloatingPanel works without a Router when not needed.\nfunction DismissOnNavigate({ onClose }: { onClose: () => void }) {\n const pathname = usePathname();\n const initialPathname = useRef(pathname);\n useEffect(() => {\n if (pathname !== initialPathname.current) {\n onClose();\n }\n }, [pathname, onClose]);\n return null;\n}\n\nexport default function FloatingPanel({\n title = 'Panel title',\n children,\n portal = true,\n triggerRef,\n initialWidth = 400,\n initialHeight = 600,\n minWidth = 100,\n minHeight = 150,\n mainAxisOffset = 0,\n crossAxisOffset = 0,\n footerButtons,\n footerAdditionalAction,\n placement = 'right',\n canFullsize = true,\n defaultFullSize = false,\n noPadding,\n headerActions,\n dismissOnNavigate = false,\n fitContent = false,\n onClose = () => {},\n ...restProps\n}: FloatingPanelProps) {\n const { floatingPanel } = useContext(ConfigContext);\n const fullscreenRightInset = floatingPanel?.fullscreenRightInset ?? PADDING;\n const hasFooter = footerButtons || footerAdditionalAction;\n const isAdditionalActionButton =\n isValidElement(footerAdditionalAction) && footerAdditionalAction.type === 'button';\n\n const [panelSize, setPanelSize] = useState({ width: initialWidth, height: initialHeight });\n const panelSizeRef = useRef({ width: initialWidth, height: initialHeight });\n const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 });\n const [isPositionReady, setIsPositionReady] = useState(!triggerRef); // Ready immediately if no triggerRef\n\n const [fullSize, setFullSize] = useState(defaultFullSize);\n const resizeBottomRef = useRef<number | null>(null);\n const resizeRightRef = useRef<number | null>(null);\n\n const [wasFullSizeToggled, setWasFullSizeToggled] = useState(false);\n const resizeOffsetRef = useRef({ x: 0, y: 0 });\n\n const resizeDirectionRef = useRef<ResizeDirection | null>(null);\n const resizeStartDimensionsRef = useRef({\n width: initialWidth,\n height: initialHeight,\n x: 0,\n y: 0,\n });\n\n // Track if the user has manually resized the panel\n const [hasManuallyResized, setHasManuallyResized] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n\n // Track reduced motion preference\n const prefersReducedMotion = useReducedMotion();\n\n const dragControls = useDragControls();\n\n const x = useMotionValue(0);\n const y = useMotionValue(0);\n\n const {\n x: floatingX,\n y: floatingY,\n refs,\n } = useFloating({\n placement: placement,\n elements: {\n reference: triggerRef?.current || undefined,\n },\n middleware: [\n offset({\n mainAxis: mainAxisOffset,\n crossAxis: crossAxisOffset,\n }),\n flip(),\n // flip() only swaps sides, so a large panel can still open clipped off an\n // edge. shift() slides it back into view on both axes (crossAxis covers the\n // side axis flip leaves unhandled).\n shift({ crossAxis: true, padding: PADDING }),\n ],\n });\n\n useEffect(() => {\n // Only update position when floating values are not at the default 0,0\n // or when we don't have a triggerRef (meaning we should use initial position)\n if (!triggerRef || floatingX !== 0 || floatingY !== 0) {\n setPanelPosition({\n x: floatingX,\n y: floatingY,\n });\n setIsPositionReady(true);\n }\n }, [floatingX, floatingY, triggerRef]);\n\n // Window dimensions and drag constraints\n const [windowDimensions, setWindowDimensions] = useState({\n width: typeof window !== 'undefined' ? window.innerWidth : 1200,\n height: typeof window !== 'undefined' ? window.innerHeight : 800,\n });\n\n // Update window dimensions on resize\n useEffect(() => {\n const handleResize = () => {\n setWindowDimensions({\n width: window.innerWidth,\n height: window.innerHeight,\n });\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n const dragConstraints = fullSize\n ? undefined\n : {\n left: PADDING,\n right: Math.max(PADDING, windowDimensions.width - panelSize.width - PADDING),\n top: PADDING,\n bottom: Math.max(PADDING, windowDimensions.height - panelSize.height - PADDING),\n };\n\n // Clamp initial position and any position updates to be within bounds\n const clampPositionToBounds = useCallback(\n (position: { x: number; y: number }) => {\n if (fullSize) {\n return position;\n }\n\n return {\n x: Math.max(\n PADDING,\n Math.min(\n position.x,\n Math.max(PADDING, windowDimensions.width - panelSize.width - PADDING),\n ),\n ),\n y: Math.max(\n PADDING,\n Math.min(\n position.y,\n Math.max(PADDING, windowDimensions.height - panelSize.height - PADDING),\n ),\n ),\n };\n },\n [windowDimensions, panelSize, fullSize],\n );\n\n // Clamp position on window resize\n useEffect(() => {\n if (!fullSize) {\n const clampedPosition = clampPositionToBounds(panelPosition);\n if (clampedPosition.x !== panelPosition.x || clampedPosition.y !== panelPosition.y) {\n setPanelPosition(clampedPosition);\n }\n }\n }, [windowDimensions, panelPosition, clampPositionToBounds, fullSize]);\n\n useEffect(() => {\n if (wasFullSizeToggled) {\n const timer = setTimeout(() => setWasFullSizeToggled(false), 400); // match duration\n return () => clearTimeout(timer);\n }\n }, [wasFullSizeToggled]);\n\n // We need this useEffect here to sync a ref to the panel size, which is needed for resizing\n useEffect(() => {\n panelSizeRef.current = panelSize;\n }, [panelSize]);\n\n // True while the panel is letting CSS auto-fit its height to content\n // (`fitContent` opt-in, no manual resize yet, not in fullsize). In this mode\n // we omit `height` from the framer-motion animate prop so the styled\n // container's `height: max-content` is in effect.\n const isAutoHeight = fitContent && !hasManuallyResized && !fullSize;\n\n // Unified resize handler for all directions\n function handleResizeMouseDown(\n event: React.MouseEvent<HTMLDivElement>,\n direction: ResizeDirection,\n ) {\n event.preventDefault();\n event.stopPropagation();\n\n let currentWidth: number;\n let currentHeight: number;\n let currentX: number;\n let currentY: number;\n\n if (fullSize) {\n // Exit fullscreen but preserve the current rendered dimensions so the panel\n // appears to stay in place while the user resizes from the edges.\n // Measure from the DOM so we get the real pixel width/height regardless of\n // what `calc(100% - 16px)` resolves to (differs for portaled vs. in-place\n // panels because `100%` is relative to the containing block, not the viewport).\n const container = contentRef.current?.parentElement;\n currentWidth = container?.offsetWidth ?? windowDimensions.width - 16;\n currentHeight = container?.offsetHeight ?? windowDimensions.height - 16;\n currentX = 8;\n currentY = 8;\n // Sync motion values now so x.get()/y.get() return the correct position for\n // computing fixed-edge anchors below.\n x.set(8);\n y.set(8);\n setFullSize(false);\n setPanelSize({ width: currentWidth, height: currentHeight });\n setPanelPosition({ x: currentX, y: currentY });\n } else if (isAutoHeight) {\n // If we're leaving CSS auto-fit, capture the current rendered height so the\n // panel doesn't jump from its content-fit size back to `initialHeight` when\n // pixel mode takes over.\n const container = contentRef.current?.parentElement;\n currentHeight = container?.offsetHeight ?? panelSize.height;\n currentWidth = panelSize.width;\n currentX = panelPosition.x;\n currentY = panelPosition.y;\n setPanelSize({ width: currentWidth, height: currentHeight });\n } else {\n currentWidth = panelSize.width;\n currentHeight = panelSize.height;\n currentX = panelPosition.x;\n currentY = panelPosition.y;\n }\n\n panelSizeRef.current = { width: currentWidth, height: currentHeight };\n // Capture start dimensions in a ref so handleResizeMouseMove (stale closure)\n // can read the correct initial values for unchanged axes without depending on\n // panelSize/panelPosition state captured at listener-registration time.\n resizeStartDimensionsRef.current = {\n width: currentWidth,\n height: currentHeight,\n x: currentX,\n y: currentY,\n };\n\n // Mark that user has manually resized - disable auto-resize from now on\n setHasManuallyResized(true);\n\n resizeDirectionRef.current = direction;\n\n // Calculate initial offsets and fixed points based on direction\n if (direction === ResizeDirection.SouthEast) {\n // Bottom-right: resize from bottom-right corner\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: event.clientY - currentHeight,\n };\n } else if (direction === ResizeDirection.SouthWest) {\n // Bottom-left: resize from bottom-left corner\n resizeRightRef.current = x.get() + currentWidth;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: event.clientY - currentHeight,\n };\n } else if (direction === ResizeDirection.NorthWest) {\n // Top-left: resize from top-left corner\n resizeRightRef.current = x.get() + currentWidth;\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.NorthEast) {\n // Top-right: resize from top-right corner\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.West) {\n // Left edge\n resizeRightRef.current = x.get() + currentWidth;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: 0,\n };\n } else if (direction === ResizeDirection.East) {\n // Right edge\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: 0,\n };\n } else if (direction === ResizeDirection.North) {\n // Top edge\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: 0,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.South) {\n // Bottom edge\n resizeOffsetRef.current = {\n x: 0,\n y: event.clientY - currentHeight,\n };\n }\n\n document.addEventListener('mousemove', handleResizeMouseMove);\n document.addEventListener('mouseup', handleResizeMouseUp);\n }\n\n // ResizeMouseMove to calculate the new size and position of the panel\n function handleResizeMouseMove(event: MouseEvent) {\n const direction = resizeDirectionRef.current;\n // Use resizeStartDimensionsRef (a ref, always current) rather than panelSize/panelPosition\n // (stale closure values). For unchanged axes, these provide the correct starting dimensions\n // set at drag start — including the case where the drag began in fullscreen mode.\n let newWidth = resizeStartDimensionsRef.current.width;\n let newHeight = resizeStartDimensionsRef.current.height;\n let clampedX = resizeStartDimensionsRef.current.x;\n let clampedY = resizeStartDimensionsRef.current.y;\n\n if (direction === ResizeDirection.SouthEast) {\n // Bottom-right corner\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n } else if (direction === ResizeDirection.SouthWest) {\n // Bottom-left corner\n const right = resizeRightRef.current!;\n const proposedX = event.clientX;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n clampedX = Math.round(right - newWidth);\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n } else if (direction === ResizeDirection.NorthWest) {\n // Top-left corner\n const right = resizeRightRef.current!;\n const bottom = resizeBottomRef.current!;\n const proposedX = event.clientX;\n const proposedY = event.clientY;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedX = Math.round(right - newWidth);\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.NorthEast) {\n // Top-right corner\n const bottom = resizeBottomRef.current!;\n const proposedY = event.clientY;\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.West) {\n // Left edge\n const right = resizeRightRef.current!;\n const proposedX = event.clientX;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n clampedX = Math.round(right - newWidth);\n } else if (direction === ResizeDirection.East) {\n // Right edge\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n } else if (direction === ResizeDirection.North) {\n // Top edge\n const bottom = resizeBottomRef.current!;\n const proposedY = event.clientY;\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.South) {\n // Bottom edge\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n }\n\n // We need to flush sync here because it would create jitter while the panel resizes from other directions\n // this is because the browser will animate serially, but we want to update the position and size together\n // so that the panel doesn't jump around\n flushSync(() => {\n setPanelPosition({ x: clampedX, y: clampedY });\n setPanelSize({ width: newWidth, height: newHeight });\n });\n }\n\n function handleResizeMouseUp() {\n document.removeEventListener('mousemove', handleResizeMouseMove);\n document.removeEventListener('mouseup', handleResizeMouseUp);\n }\n\n const panelContent = (\n <FloatingPanelContainer\n // Need to keep the values of x and y for positioning\n ref={refs.setFloating}\n $fitHeight={isAutoHeight}\n $maxHeight={autoFitMaxHeight(windowDimensions.height, panelPosition.y, minHeight)}\n $minHeight={minHeight}\n style={{\n x,\n y,\n }}\n initial={{\n top: 0,\n left: 0,\n opacity: 0,\n }}\n animate={{\n x: fullSize ? PADDING : panelPosition.x,\n y: fullSize ? PADDING : panelPosition.y,\n\n // When fullscreen, leave space for any reserved right-side content.\n width: fullSize ? `calc(100% - ${PADDING + fullscreenRightInset}px)` : panelSize.width,\n // Omit height when CSS auto-fit is active so `height: max-content`\n // on the styled container takes effect.\n ...(isAutoHeight ? {} : { height: fullSize ? 'calc(100% - 16px)' : panelSize.height }),\n opacity: isPositionReady ? 1 : 0,\n }}\n transition={\n wasFullSizeToggled\n ? {\n type: 'tween',\n // Easing curve for a smooth transition\n ease: [0.83, 0.0, 0.17, 1.0],\n duration: prefersReducedMotion ? 1.2 : 0.4,\n }\n : { opacity: { duration: 0.15, ease: 'easeOut' }, duration: 0 }\n }\n onDragEnd={() => {\n if (!fullSize) {\n const newPosition = { x: x.get(), y: y.get() };\n const clampedPosition = clampPositionToBounds(newPosition);\n setPanelPosition(clampedPosition);\n }\n }}\n drag={!fullSize}\n dragControls={dragControls}\n dragListener={false}\n dragMomentum={false}\n dragConstraints={dragConstraints}\n // The frame portals to the body, so panels that dismiss on an outside click\n // need this id to recognize a click in here as one of their own overlays.\n id={`${FLOATING_PANEL_ID_PREFIX}container`}\n {...restProps}\n >\n <DragHandle isFullSize={fullSize} onPointerDown={(e) => dragControls.start(e)}>\n <Stack align='center' direction='horizontal' justify='space-between'>\n <PanelText>{title}</PanelText>\n <Stack direction='horizontal' align='center' spacing={Spacing[1]}>\n {headerActions}\n {canFullsize && (\n <StyledIconButton\n size='sm'\n aria-label={fullSize ? 'collapse' : 'expand'}\n id='floating-panel__toggle-fullsize'\n onClick={() => {\n setWasFullSizeToggled(true);\n setFullSize(!fullSize);\n }}\n >\n {fullSize ? <ArrowCollapseIcon /> : <ArrowExpandIcon />}\n </StyledIconButton>\n )}\n\n <StyledIconButton\n size='sm'\n id='floating-panel__close-panel'\n onClick={() => onClose?.()}\n aria-label='close'\n >\n <XIcon />\n </StyledIconButton>\n </Stack>\n </Stack>\n </DragHandle>\n <PanelContent ref={contentRef} $noPadding={noPadding} $fitHeight={isAutoHeight}>\n {children}\n </PanelContent>\n {hasFooter && (\n <Footer style={{ paddingLeft: isAdditionalActionButton ? Spacing[1] : Spacing[3] }}>\n <Stack\n align='center'\n direction='horizontal'\n justify={footerAdditionalAction ? 'space-between' : 'flex-end'}\n >\n {footerAdditionalAction &&\n (isAdditionalActionButton ? (\n footerAdditionalAction\n ) : (\n <PanelText>{footerAdditionalAction}</PanelText>\n ))}\n\n {footerButtons && <div>{footerButtons}</div>}\n </Stack>\n </Footer>\n )}\n <ResizeHandleBottomRight\n data-test='resize-handle-se'\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.SouthEast)}\n />\n <ResizeHandleBottom\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.South)}\n />\n <ResizeHandleBottomLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.SouthWest)}\n />\n <ResizeHandleLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.West)}\n />\n <ResizeHandleTopLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.NorthWest)}\n />\n <ResizeHandleTop\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.North)}\n />\n <ResizeHandleTopRight\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.NorthEast)}\n />\n <ResizeHandleRight\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.East)}\n />\n </FloatingPanelContainer>\n );\n\n const content = (\n <>\n {dismissOnNavigate && <DismissOnNavigate onClose={onClose} />}\n {panelContent}\n </>\n );\n\n return portal ? createPortal(content, document.body) : content;\n}\n","import {\n createContext,\n type ReactElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport { v4 as uuid } from 'uuid';\n\nimport { usePathname } from 'design-system/lib/router';\n\nexport type Panel = {\n key: string;\n panelElement: ReactElement;\n persistUntilPathRoot?: string;\n};\n\ninterface PanelContextType {\n openPanel: (panel: Panel) => void;\n closePanel: (key: string) => void;\n togglePanel: (panel: Panel) => void;\n closeAllPanels: () => void;\n isPanelOpen: (key: string) => boolean;\n panels: Panel[];\n}\n\nconst PanelContext = createContext<PanelContextType | null>(null);\n\nexport const PanelProvider = ({ children }: { children: ReactNode }) => {\n const [panels, setPanels] = useState<Panel[]>([]);\n const pathname = usePathname();\n\n function shouldPanelPersist(currentUrl: string, persistUntilPathRoot?: string): boolean {\n if (!persistUntilPathRoot) {\n return false;\n }\n return currentUrl.includes(persistUntilPathRoot);\n }\n\n const openPanel = useCallback(\n (panel: Panel) => {\n const { key, panelElement, persistUntilPathRoot } = panel;\n const pathRoot = persistUntilPathRoot || pathname;\n setPanels((prev) => [\n ...prev.filter((p) => p.key !== key), // Remove existing panel with same key\n { key, panelElement, persistUntilPathRoot: pathRoot },\n ]);\n },\n [pathname],\n );\n\n const closePanel = useCallback((key: string) => {\n setPanels((prev) => prev.filter((panel) => panel.key !== key));\n }, []);\n\n const isPanelOpen = useCallback(\n (key: string) => {\n return panels.some((panel) => panel.key === key);\n },\n [panels],\n );\n\n const togglePanel = useCallback(\n (panel: Panel) => {\n const { key } = panel;\n if (isPanelOpen(key)) {\n closePanel(key);\n } else {\n openPanel(panel);\n }\n },\n [isPanelOpen, closePanel, openPanel],\n );\n\n const closeAllPanels = useCallback(() => {\n setPanels([]);\n }, []);\n\n useEffect(() => {\n const nextLocation = pathname;\n\n setPanels((prevPanels) =>\n prevPanels.filter((panel) => shouldPanelPersist(nextLocation, panel.persistUntilPathRoot)),\n );\n }, [pathname]);\n\n return (\n <PanelContext.Provider\n value={{ openPanel, closePanel, togglePanel, closeAllPanels, panels, isPanelOpen }}\n >\n {children}\n </PanelContext.Provider>\n );\n};\n\nexport const usePersistentFloatingPanels = () => {\n const ctx = useContext(PanelContext);\n if (!ctx) {\n throw new Error('usePersistentFloatingPanels must be used within a PanelProvider');\n }\n return ctx;\n};\n\n// This hook is used to open a panel that persists across multiple pages\n// For single page panels, use the useToggle hook instead to manage individual panel state.\nexport const usePersistentFloatingPanel = (panelId?: string) => {\n const ctx = useContext(PanelContext);\n if (!ctx) {\n throw new Error('usePersistentFloatingPanels must be used within a PanelProvider');\n }\n\n // If the panel doesn't need to persist across multiple pages, we generate an id that can be passed back\n const currentPanelId = panelId || `panel-${uuid()}`;\n\n return {\n id: currentPanelId,\n openPanel: useCallback(\n (panel: Panel) => {\n ctx.openPanel(panel);\n },\n [ctx],\n ),\n closePanel: useCallback(() => {\n ctx.closePanel(currentPanelId);\n }, [currentPanelId, ctx]),\n togglePanel: useCallback(\n (panel: Panel) => {\n ctx.togglePanel(panel);\n },\n [ctx],\n ),\n isPanelOpen: ctx.isPanelOpen(currentPanelId),\n };\n};\n","import { cloneElement } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { usePersistentFloatingPanels } from './FloatingPanelContext';\n\nexport default function FloatingPanelRenderer() {\n const { panels, closePanel } = usePersistentFloatingPanels();\n\n if (panels.length === 0) {\n return null;\n }\n\n return createPortal(\n panels.map(({ key, panelElement: panel }) => {\n return cloneElement(panel, { onClose: () => closePanel(key), key: key });\n }),\n document.body,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["uuid"],"sources":["../../../src/components/FloatingPanel/utils.ts","../../../src/components/FloatingPanel/FloatingPanel.tsx","../../../src/components/FloatingPanel/FloatingPanelContext.tsx","../../../src/components/FloatingPanel/FloatingPanelRenderer.tsx"],"sourcesContent":["export const PADDING = 8;\nexport const EDGE_PADDING = PADDING * 6;\n\n// Cap a content-fitting panel's height to the room below its top edge so it\n// can't overflow the viewport bottom when anchored partway down the screen.\nexport function autoFitMaxHeight(viewportHeight: number, topOffset: number, minHeight: number) {\n return Math.max(minHeight, viewportHeight - Math.max(EDGE_PADDING, topOffset) - EDGE_PADDING);\n}\n","import { flip, offset, type Placement, shift, useFloating } from '@floating-ui/react';\nimport { motion, useDragControls, useMotionValue, useReducedMotion } from 'framer-motion';\nimport {\n isValidElement,\n type ReactNode,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { createPortal, flushSync } from 'react-dom';\nimport styled, { css } from 'styled-components';\n\nimport { IconButton } from '@persona/design-system/components/Button';\nimport Stack from '@persona/design-system/components/Stack';\nimport { Z_INDICES } from '@persona/design-system/lib/zindex';\nimport { paragraphMixins } from '@persona/design-system/mixins/text';\nimport { Elevation } from '@persona/design-system/variables/effect';\nimport { BorderRadius, Color, Spacing } from '@persona/design-tokens';\nimport { ArrowCollapseIcon, ArrowExpandIcon, XIcon } from '@persona/icons';\n\nimport ConfigContext from '#src/lib/ConfigContext';\nimport { usePathname } from '#src/lib/router';\nimport { semanticColor } from '#src/lib/semanticColor';\nimport { semanticScrollbar } from '#src/mixins/scrollbar';\n\nimport { autoFitMaxHeight, PADDING } from './utils';\n\nexport const FLOATING_PANEL_ID_PREFIX = 'floating-panel__' as const;\n\nenum ResizeDirection {\n North = 'n',\n South = 's',\n East = 'e',\n West = 'w',\n NorthEast = 'ne',\n NorthWest = 'nw',\n SouthEast = 'se',\n SouthWest = 'sw',\n}\n\nexport interface FloatingPanelProps {\n /** The title text displayed in the panel header */\n title: ReactNode;\n /** Callback function called when the close button is clicked */\n onClose?: () => void;\n /** Content to render inside the main panel area */\n children?: ReactNode;\n /** Optional React component rendered to the left of the expand button in the header */\n headerActions?: ReactNode;\n\n /** Whether the panel displays the fullsize button */\n canFullsize?: boolean;\n\n /** When true, the panel opens already in full-size (maximized) mode. */\n defaultFullSize?: boolean;\n\n /** Initial width of the panel in pixels */\n initialWidth?: number;\n /** Initial height of the panel in pixels */\n initialHeight?: number;\n /** Minimum width the panel can be resized to in pixels */\n minWidth?: number;\n /** Minimum height the panel can be resized to in pixels */\n minHeight?: number;\n\n footerButtons?: ReactNode;\n\n footerAdditionalAction?: ReactNode;\n\n portal?: boolean;\n\n /** Reference to the element that triggered this panel, used for automatic positioning */\n triggerRef?: RefObject<HTMLElement>;\n\n /** Which placement of the trigger element to position the panel on */\n placement?: Placement;\n\n /** Additional main axis offset in pixels from the calculated position. Main axis is defined as the axis in position to where its being defined\n * i.e. right, top, left ,bottom */\n mainAxisOffset?: number;\n\n /** Additional cross offset in pixels from the calculated position. Cross is defined as the axis that runs along the alignment\n * of the floating element. */\n crossAxisOffset?: number;\n\n /** remove padding from the panel content */\n noPadding?: boolean;\n\n /** When true, automatically calls `onClose` if the route changes after the\n * panel mounts. Mirrors the auto-dismiss-on-navigation behavior provided by\n * `PanelProvider` / `usePersistentFloatingPanel` for panels that don't opt\n * into the persistent panel context. Defaults to `false` so existing\n * consumers (e.g. dirty-check confirmation flows) are not broken. */\n dismissOnNavigate?: boolean;\n\n /** When true, the panel's height auto-fits its content via CSS (`max-content`)\n * up to the viewport, instead of using `initialHeight`. Once the user manually\n * resizes, the panel switches to pixel mode and stays there. `initialHeight`\n * is ignored while auto-fitting. */\n fitContent?: boolean;\n}\n\nconst FloatingPanelContainer = styled(motion.div)<{\n $fitHeight?: boolean;\n $maxHeight?: number;\n $minHeight?: number;\n}>`\n position: absolute;\n z-index: ${Z_INDICES.modal};\n background: ${({ theme }) =>\n semanticColor(theme, 'SurfaceElevated', theme.color.background.primary)};\n border: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n border-radius: ${BorderRadius.Lg};\n box-shadow: ${Elevation.Low};\n display: flex;\n flex-direction: column;\n cursor: auto;\n ${({ $fitHeight, $maxHeight, $minHeight }) =>\n $fitHeight &&\n css`\n height: auto;\n max-height: ${$maxHeight ?? 0}px;\n min-height: ${$minHeight ?? 0}px;\n `}\n`;\n\nconst DragHandle = styled(motion.div)<{ isFullSize: boolean }>`\n cursor: ${({ isFullSize }) => (isFullSize ? 'default' : 'grab')};\n user-select: none;\n\n &:active {\n cursor: ${({ isFullSize }) => (isFullSize ? 'default' : 'grabbing')};\n }\n display: flex;\n flex-direction: column;\n justify-content: center;\n min-height: 48px;\n height: 48px;\n overflow: hidden;\n padding: ${Spacing[1]} ${Spacing[1]} ${Spacing[1]} ${Spacing[3]};\n border-bottom: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n`;\n\nconst Footer = styled.div`\n padding: ${Spacing[1]} ${Spacing[1]} ${Spacing[1]} ${Spacing[3]};\n border-top: 1px solid ${({ theme }) => semanticColor(theme, 'BorderSubtle', Color.BorderDivider)};\n overflow-x: hidden;\n background-color: ${({ theme }) =>\n semanticColor(theme, 'SurfaceElevated', theme.color.background.primary)};\n width: 100%;\n border-radius: 0 0 ${BorderRadius.Lg} ${BorderRadius.Lg};\n`;\n\nconst ResizeHandleBase = styled.div`\n position: absolute;\n user-select: none;\n`;\n\n// Sets the width and height for base corner to 20px\nconst ResizeHandleBaseCorner = styled(ResizeHandleBase)`\n width: 1.25rem;\n height: 1.25rem;\n`;\n\nconst ResizeHandleBottomRight = styled(ResizeHandleBaseCorner)`\n bottom: -0.75rem;\n right: -0.75rem;\n cursor: nwse-resize;\n`;\n\nconst ResizeHandleBottomLeft = styled(ResizeHandleBaseCorner)`\n bottom: -0.75rem;\n left: -0.75rem;\n cursor: nesw-resize;\n`;\n\nconst ResizeHandleTopLeft = styled(ResizeHandleBaseCorner)`\n top: -0.75rem;\n left: -0.75rem;\n cursor: nwse-resize;\n`;\n\nconst ResizeHandleTopRight = styled(ResizeHandleBaseCorner)`\n top: -0.75rem;\n right: -0.75rem;\n cursor: nesw-resize;\n`;\n\n// These are all the Resize handles for the four cardinal direction,\n// To calculate the width, we subtract by the padding of 1rem on both sides\n// which are corners of the panel\nconst ResizeHandleBottom = styled(ResizeHandleBase)`\n bottom: -0.75rem;\n left: 0.5rem;\n width: calc(100% - 1rem);\n height: 1rem;\n cursor: ns-resize;\n user-select: none;\n`;\n\nconst ResizeHandleTop = styled(ResizeHandleBase)`\n top: -0.75rem;\n left: 0.5rem;\n width: calc(100% - 1rem);\n height: 1rem;\n cursor: ns-resize;\n`;\n\nconst ResizeHandleRight = styled(ResizeHandleBase)`\n right: -0.75rem;\n top: 0.5rem;\n width: 1rem;\n height: calc(100% - 1rem);\n cursor: ew-resize;\n`;\n\nconst ResizeHandleLeft = styled(ResizeHandleBase)`\n left: -0.75rem;\n top: 0.5rem;\n width: 1rem;\n height: calc(100% - 1rem);\n cursor: ew-resize;\n`;\n\nconst PanelContent = styled.div<{ $noPadding?: boolean; $fitHeight?: boolean }>`\n overflow-y: auto;\n ${semanticScrollbar}\n overscroll-behavior: contain;\n min-height: 0;\n /* While the panel height is derived from its content, the content must size\n itself (a percentage flex-basis against an indefinite height collapses in\n WebKit); it still shrinks when the panel hits its max-height. */\n flex: ${({ $fitHeight }) => ($fitHeight ? '0 1 auto' : '1 1 0%')};\n padding: ${({ $noPadding }) => ($noPadding ? 0 : Spacing[3])};\n`;\n\n// Sets a min width so that the text will display, but overflows if needed\nconst PanelText = styled.p`\n ${paragraphMixins.sm}\n white-space: nowrap;\n min-width: 3rem;\n overflow: hidden;\n text-overflow: ellipsis;\n display: flex;\n align-items: center;\n font-weight: 500;\n`;\n\nconst StyledIconButton = styled(IconButton)`\n width: 1.5rem;\n height: 1.5rem;\n border-radius: ${BorderRadius.Md};\n`;\n\n// Only rendered when dismissOnNavigate is true, keeping the router lookup out of the\n// main component body so FloatingPanel works without a Router when not needed.\nfunction DismissOnNavigate({ onClose }: { onClose: () => void }) {\n const pathname = usePathname();\n const initialPathname = useRef(pathname);\n useEffect(() => {\n if (pathname !== initialPathname.current) {\n onClose();\n }\n }, [pathname, onClose]);\n return null;\n}\n\nexport default function FloatingPanel({\n title = 'Panel title',\n children,\n portal = true,\n triggerRef,\n initialWidth = 400,\n initialHeight = 600,\n minWidth = 100,\n minHeight = 150,\n mainAxisOffset = 0,\n crossAxisOffset = 0,\n footerButtons,\n footerAdditionalAction,\n placement = 'right',\n canFullsize = true,\n defaultFullSize = false,\n noPadding,\n headerActions,\n dismissOnNavigate = false,\n fitContent = false,\n onClose = () => {},\n ...restProps\n}: FloatingPanelProps) {\n const { floatingPanel } = useContext(ConfigContext);\n const fullscreenRightInset = floatingPanel?.fullscreenRightInset ?? PADDING;\n const hasFooter = footerButtons || footerAdditionalAction;\n const isAdditionalActionButton =\n isValidElement(footerAdditionalAction) && footerAdditionalAction.type === 'button';\n\n const [panelSize, setPanelSize] = useState({ width: initialWidth, height: initialHeight });\n const panelSizeRef = useRef({ width: initialWidth, height: initialHeight });\n const [panelPosition, setPanelPosition] = useState({ x: 0, y: 0 });\n const [isPositionReady, setIsPositionReady] = useState(!triggerRef); // Ready immediately if no triggerRef\n\n const [fullSize, setFullSize] = useState(defaultFullSize);\n const resizeBottomRef = useRef<number | null>(null);\n const resizeRightRef = useRef<number | null>(null);\n\n const [wasFullSizeToggled, setWasFullSizeToggled] = useState(false);\n const resizeOffsetRef = useRef({ x: 0, y: 0 });\n\n const resizeDirectionRef = useRef<ResizeDirection | null>(null);\n const resizeStartDimensionsRef = useRef({\n width: initialWidth,\n height: initialHeight,\n x: 0,\n y: 0,\n });\n\n // Track if the user has manually resized the panel\n const [hasManuallyResized, setHasManuallyResized] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n\n // Track reduced motion preference\n const prefersReducedMotion = useReducedMotion();\n\n const dragControls = useDragControls();\n\n const x = useMotionValue(0);\n const y = useMotionValue(0);\n\n const {\n x: floatingX,\n y: floatingY,\n refs,\n } = useFloating({\n placement: placement,\n elements: {\n reference: triggerRef?.current || undefined,\n },\n middleware: [\n offset({\n mainAxis: mainAxisOffset,\n crossAxis: crossAxisOffset,\n }),\n flip(),\n // flip() only swaps sides, so a large panel can still open clipped off an\n // edge. shift() slides it back into view on both axes (crossAxis covers the\n // side axis flip leaves unhandled).\n shift({ crossAxis: true, padding: PADDING }),\n ],\n });\n\n useEffect(() => {\n // Only update position when floating values are not at the default 0,0\n // or when we don't have a triggerRef (meaning we should use initial position)\n if (!triggerRef || floatingX !== 0 || floatingY !== 0) {\n setPanelPosition({\n x: floatingX,\n y: floatingY,\n });\n setIsPositionReady(true);\n }\n }, [floatingX, floatingY, triggerRef]);\n\n // Window dimensions and drag constraints\n const [windowDimensions, setWindowDimensions] = useState({\n width: typeof window !== 'undefined' ? window.innerWidth : 1200,\n height: typeof window !== 'undefined' ? window.innerHeight : 800,\n });\n\n // Update window dimensions on resize\n useEffect(() => {\n const handleResize = () => {\n setWindowDimensions({\n width: window.innerWidth,\n height: window.innerHeight,\n });\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n const dragConstraints = fullSize\n ? undefined\n : {\n left: PADDING,\n right: Math.max(PADDING, windowDimensions.width - panelSize.width - PADDING),\n top: PADDING,\n bottom: Math.max(PADDING, windowDimensions.height - panelSize.height - PADDING),\n };\n\n // Clamp initial position and any position updates to be within bounds\n const clampPositionToBounds = useCallback(\n (position: { x: number; y: number }) => {\n if (fullSize) {\n return position;\n }\n\n return {\n x: Math.max(\n PADDING,\n Math.min(\n position.x,\n Math.max(PADDING, windowDimensions.width - panelSize.width - PADDING),\n ),\n ),\n y: Math.max(\n PADDING,\n Math.min(\n position.y,\n Math.max(PADDING, windowDimensions.height - panelSize.height - PADDING),\n ),\n ),\n };\n },\n [windowDimensions, panelSize, fullSize],\n );\n\n // Clamp position on window resize\n useEffect(() => {\n if (!fullSize) {\n const clampedPosition = clampPositionToBounds(panelPosition);\n if (clampedPosition.x !== panelPosition.x || clampedPosition.y !== panelPosition.y) {\n setPanelPosition(clampedPosition);\n }\n }\n }, [windowDimensions, panelPosition, clampPositionToBounds, fullSize]);\n\n useEffect(() => {\n if (wasFullSizeToggled) {\n const timer = setTimeout(() => setWasFullSizeToggled(false), 400); // match duration\n return () => clearTimeout(timer);\n }\n }, [wasFullSizeToggled]);\n\n // We need this useEffect here to sync a ref to the panel size, which is needed for resizing\n useEffect(() => {\n panelSizeRef.current = panelSize;\n }, [panelSize]);\n\n // True while the panel is letting CSS auto-fit its height to content\n // (`fitContent` opt-in, no manual resize yet, not in fullsize). In this mode\n // we omit `height` from the framer-motion animate prop so the styled\n // container's `height: max-content` is in effect.\n const isAutoHeight = fitContent && !hasManuallyResized && !fullSize;\n\n // Unified resize handler for all directions\n function handleResizeMouseDown(\n event: React.MouseEvent<HTMLDivElement>,\n direction: ResizeDirection,\n ) {\n event.preventDefault();\n event.stopPropagation();\n\n let currentWidth: number;\n let currentHeight: number;\n let currentX: number;\n let currentY: number;\n\n if (fullSize) {\n // Exit fullscreen but preserve the current rendered dimensions so the panel\n // appears to stay in place while the user resizes from the edges.\n // Measure from the DOM so we get the real pixel width/height regardless of\n // what `calc(100% - 16px)` resolves to (differs for portaled vs. in-place\n // panels because `100%` is relative to the containing block, not the viewport).\n const container = contentRef.current?.parentElement;\n currentWidth = container?.offsetWidth ?? windowDimensions.width - 16;\n currentHeight = container?.offsetHeight ?? windowDimensions.height - 16;\n currentX = 8;\n currentY = 8;\n // Sync motion values now so x.get()/y.get() return the correct position for\n // computing fixed-edge anchors below.\n x.set(8);\n y.set(8);\n setFullSize(false);\n setPanelSize({ width: currentWidth, height: currentHeight });\n setPanelPosition({ x: currentX, y: currentY });\n } else if (isAutoHeight) {\n // If we're leaving CSS auto-fit, capture the current rendered height so the\n // panel doesn't jump from its content-fit size back to `initialHeight` when\n // pixel mode takes over.\n const container = contentRef.current?.parentElement;\n currentHeight = container?.offsetHeight ?? panelSize.height;\n currentWidth = panelSize.width;\n currentX = panelPosition.x;\n currentY = panelPosition.y;\n setPanelSize({ width: currentWidth, height: currentHeight });\n } else {\n currentWidth = panelSize.width;\n currentHeight = panelSize.height;\n currentX = panelPosition.x;\n currentY = panelPosition.y;\n }\n\n panelSizeRef.current = { width: currentWidth, height: currentHeight };\n // Capture start dimensions in a ref so handleResizeMouseMove (stale closure)\n // can read the correct initial values for unchanged axes without depending on\n // panelSize/panelPosition state captured at listener-registration time.\n resizeStartDimensionsRef.current = {\n width: currentWidth,\n height: currentHeight,\n x: currentX,\n y: currentY,\n };\n\n // Mark that user has manually resized - disable auto-resize from now on\n setHasManuallyResized(true);\n\n resizeDirectionRef.current = direction;\n\n // Calculate initial offsets and fixed points based on direction\n if (direction === ResizeDirection.SouthEast) {\n // Bottom-right: resize from bottom-right corner\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: event.clientY - currentHeight,\n };\n } else if (direction === ResizeDirection.SouthWest) {\n // Bottom-left: resize from bottom-left corner\n resizeRightRef.current = x.get() + currentWidth;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: event.clientY - currentHeight,\n };\n } else if (direction === ResizeDirection.NorthWest) {\n // Top-left: resize from top-left corner\n resizeRightRef.current = x.get() + currentWidth;\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.NorthEast) {\n // Top-right: resize from top-right corner\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.West) {\n // Left edge\n resizeRightRef.current = x.get() + currentWidth;\n resizeOffsetRef.current = {\n x: event.clientX,\n y: 0,\n };\n } else if (direction === ResizeDirection.East) {\n // Right edge\n resizeOffsetRef.current = {\n x: event.clientX - currentWidth,\n y: 0,\n };\n } else if (direction === ResizeDirection.North) {\n // Top edge\n resizeBottomRef.current = y.get() + currentHeight;\n resizeOffsetRef.current = {\n x: 0,\n y: event.clientY,\n };\n } else if (direction === ResizeDirection.South) {\n // Bottom edge\n resizeOffsetRef.current = {\n x: 0,\n y: event.clientY - currentHeight,\n };\n }\n\n document.addEventListener('mousemove', handleResizeMouseMove);\n document.addEventListener('mouseup', handleResizeMouseUp);\n }\n\n // ResizeMouseMove to calculate the new size and position of the panel\n function handleResizeMouseMove(event: MouseEvent) {\n const direction = resizeDirectionRef.current;\n // Use resizeStartDimensionsRef (a ref, always current) rather than panelSize/panelPosition\n // (stale closure values). For unchanged axes, these provide the correct starting dimensions\n // set at drag start — including the case where the drag began in fullscreen mode.\n let newWidth = resizeStartDimensionsRef.current.width;\n let newHeight = resizeStartDimensionsRef.current.height;\n let clampedX = resizeStartDimensionsRef.current.x;\n let clampedY = resizeStartDimensionsRef.current.y;\n\n if (direction === ResizeDirection.SouthEast) {\n // Bottom-right corner\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n } else if (direction === ResizeDirection.SouthWest) {\n // Bottom-left corner\n const right = resizeRightRef.current!;\n const proposedX = event.clientX;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n clampedX = Math.round(right - newWidth);\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n } else if (direction === ResizeDirection.NorthWest) {\n // Top-left corner\n const right = resizeRightRef.current!;\n const bottom = resizeBottomRef.current!;\n const proposedX = event.clientX;\n const proposedY = event.clientY;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedX = Math.round(right - newWidth);\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.NorthEast) {\n // Top-right corner\n const bottom = resizeBottomRef.current!;\n const proposedY = event.clientY;\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.West) {\n // Left edge\n const right = resizeRightRef.current!;\n const proposedX = event.clientX;\n newWidth = Math.round(Math.max(minWidth, right - proposedX));\n clampedX = Math.round(right - newWidth);\n } else if (direction === ResizeDirection.East) {\n // Right edge\n newWidth = Math.round(Math.max(minWidth, event.clientX - resizeOffsetRef.current.x));\n } else if (direction === ResizeDirection.North) {\n // Top edge\n const bottom = resizeBottomRef.current!;\n const proposedY = event.clientY;\n newHeight = Math.round(Math.max(minHeight, bottom - proposedY));\n clampedY = Math.round(bottom - newHeight);\n } else if (direction === ResizeDirection.South) {\n // Bottom edge\n newHeight = Math.round(Math.max(minHeight, event.clientY - resizeOffsetRef.current.y));\n }\n\n // We need to flush sync here because it would create jitter while the panel resizes from other directions\n // this is because the browser will animate serially, but we want to update the position and size together\n // so that the panel doesn't jump around\n flushSync(() => {\n setPanelPosition({ x: clampedX, y: clampedY });\n setPanelSize({ width: newWidth, height: newHeight });\n });\n }\n\n function handleResizeMouseUp() {\n document.removeEventListener('mousemove', handleResizeMouseMove);\n document.removeEventListener('mouseup', handleResizeMouseUp);\n }\n\n const panelContent = (\n <FloatingPanelContainer\n // Need to keep the values of x and y for positioning\n ref={refs.setFloating}\n $fitHeight={isAutoHeight}\n $maxHeight={autoFitMaxHeight(windowDimensions.height, panelPosition.y, minHeight)}\n $minHeight={minHeight}\n style={{\n x,\n y,\n }}\n initial={{\n top: 0,\n left: 0,\n opacity: 0,\n }}\n animate={{\n x: fullSize ? PADDING : panelPosition.x,\n y: fullSize ? PADDING : panelPosition.y,\n\n // When fullscreen, leave space for any reserved right-side content.\n width: fullSize ? `calc(100% - ${PADDING + fullscreenRightInset}px)` : panelSize.width,\n // Omit height when CSS auto-fit is active so `height: max-content`\n // on the styled container takes effect.\n ...(isAutoHeight ? {} : { height: fullSize ? 'calc(100% - 16px)' : panelSize.height }),\n opacity: isPositionReady ? 1 : 0,\n }}\n transition={\n wasFullSizeToggled\n ? {\n type: 'tween',\n // Easing curve for a smooth transition\n ease: [0.83, 0.0, 0.17, 1.0],\n duration: prefersReducedMotion ? 1.2 : 0.4,\n }\n : { opacity: { duration: 0.15, ease: 'easeOut' }, duration: 0 }\n }\n onDragEnd={() => {\n if (!fullSize) {\n const newPosition = { x: x.get(), y: y.get() };\n const clampedPosition = clampPositionToBounds(newPosition);\n setPanelPosition(clampedPosition);\n }\n }}\n drag={!fullSize}\n dragControls={dragControls}\n dragListener={false}\n dragMomentum={false}\n dragConstraints={dragConstraints}\n // The frame portals to the body, so panels that dismiss on an outside click\n // need this id to recognize a click in here as one of their own overlays.\n id={`${FLOATING_PANEL_ID_PREFIX}container`}\n {...restProps}\n >\n <DragHandle isFullSize={fullSize} onPointerDown={(e) => dragControls.start(e)}>\n <Stack align='center' direction='horizontal' justify='space-between'>\n <PanelText>{title}</PanelText>\n <Stack direction='horizontal' align='center' spacing={Spacing[1]}>\n {headerActions}\n {canFullsize && (\n <StyledIconButton\n size='sm'\n aria-label={fullSize ? 'collapse' : 'expand'}\n id='floating-panel__toggle-fullsize'\n onClick={() => {\n setWasFullSizeToggled(true);\n setFullSize(!fullSize);\n }}\n >\n {fullSize ? <ArrowCollapseIcon /> : <ArrowExpandIcon />}\n </StyledIconButton>\n )}\n\n <StyledIconButton\n size='sm'\n id='floating-panel__close-panel'\n onClick={() => onClose?.()}\n aria-label='close'\n >\n <XIcon />\n </StyledIconButton>\n </Stack>\n </Stack>\n </DragHandle>\n <PanelContent ref={contentRef} $noPadding={noPadding} $fitHeight={isAutoHeight}>\n {children}\n </PanelContent>\n {hasFooter && (\n <Footer style={{ paddingLeft: isAdditionalActionButton ? Spacing[1] : Spacing[3] }}>\n <Stack\n align='center'\n direction='horizontal'\n justify={footerAdditionalAction ? 'space-between' : 'flex-end'}\n >\n {footerAdditionalAction &&\n (isAdditionalActionButton ? (\n footerAdditionalAction\n ) : (\n <PanelText>{footerAdditionalAction}</PanelText>\n ))}\n\n {footerButtons && <div>{footerButtons}</div>}\n </Stack>\n </Footer>\n )}\n <ResizeHandleBottomRight\n data-test='resize-handle-se'\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.SouthEast)}\n />\n <ResizeHandleBottom\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.South)}\n />\n <ResizeHandleBottomLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.SouthWest)}\n />\n <ResizeHandleLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.West)}\n />\n <ResizeHandleTopLeft\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.NorthWest)}\n />\n <ResizeHandleTop\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.North)}\n />\n <ResizeHandleTopRight\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.NorthEast)}\n />\n <ResizeHandleRight\n onMouseDown={(event) => handleResizeMouseDown(event, ResizeDirection.East)}\n />\n </FloatingPanelContainer>\n );\n\n const content = (\n <>\n {dismissOnNavigate && <DismissOnNavigate onClose={onClose} />}\n {panelContent}\n </>\n );\n\n return portal ? createPortal(content, document.body) : content;\n}\n","import {\n createContext,\n type ReactElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport { v4 as uuid } from 'uuid';\n\nimport { usePathname } from '#src/lib/router';\n\nexport type Panel = {\n key: string;\n panelElement: ReactElement;\n persistUntilPathRoot?: string;\n};\n\ninterface PanelContextType {\n openPanel: (panel: Panel) => void;\n closePanel: (key: string) => void;\n togglePanel: (panel: Panel) => void;\n closeAllPanels: () => void;\n isPanelOpen: (key: string) => boolean;\n panels: Panel[];\n}\n\nconst PanelContext = createContext<PanelContextType | null>(null);\n\nexport const PanelProvider = ({ children }: { children: ReactNode }) => {\n const [panels, setPanels] = useState<Panel[]>([]);\n const pathname = usePathname();\n\n function shouldPanelPersist(currentUrl: string, persistUntilPathRoot?: string): boolean {\n if (!persistUntilPathRoot) {\n return false;\n }\n return currentUrl.includes(persistUntilPathRoot);\n }\n\n const openPanel = useCallback(\n (panel: Panel) => {\n const { key, panelElement, persistUntilPathRoot } = panel;\n const pathRoot = persistUntilPathRoot || pathname;\n setPanels((prev) => [\n ...prev.filter((p) => p.key !== key), // Remove existing panel with same key\n { key, panelElement, persistUntilPathRoot: pathRoot },\n ]);\n },\n [pathname],\n );\n\n const closePanel = useCallback((key: string) => {\n setPanels((prev) => prev.filter((panel) => panel.key !== key));\n }, []);\n\n const isPanelOpen = useCallback(\n (key: string) => {\n return panels.some((panel) => panel.key === key);\n },\n [panels],\n );\n\n const togglePanel = useCallback(\n (panel: Panel) => {\n const { key } = panel;\n if (isPanelOpen(key)) {\n closePanel(key);\n } else {\n openPanel(panel);\n }\n },\n [isPanelOpen, closePanel, openPanel],\n );\n\n const closeAllPanels = useCallback(() => {\n setPanels([]);\n }, []);\n\n useEffect(() => {\n const nextLocation = pathname;\n\n setPanels((prevPanels) =>\n prevPanels.filter((panel) => shouldPanelPersist(nextLocation, panel.persistUntilPathRoot)),\n );\n }, [pathname]);\n\n return (\n <PanelContext.Provider\n value={{ openPanel, closePanel, togglePanel, closeAllPanels, panels, isPanelOpen }}\n >\n {children}\n </PanelContext.Provider>\n );\n};\n\nexport const usePersistentFloatingPanels = () => {\n const ctx = useContext(PanelContext);\n if (!ctx) {\n throw new Error('usePersistentFloatingPanels must be used within a PanelProvider');\n }\n return ctx;\n};\n\n// This hook is used to open a panel that persists across multiple pages\n// For single page panels, use the useToggle hook instead to manage individual panel state.\nexport const usePersistentFloatingPanel = (panelId?: string) => {\n const ctx = useContext(PanelContext);\n if (!ctx) {\n throw new Error('usePersistentFloatingPanels must be used within a PanelProvider');\n }\n\n // If the panel doesn't need to persist across multiple pages, we generate an id that can be passed back\n const currentPanelId = panelId || `panel-${uuid()}`;\n\n return {\n id: currentPanelId,\n openPanel: useCallback(\n (panel: Panel) => {\n ctx.openPanel(panel);\n },\n [ctx],\n ),\n closePanel: useCallback(() => {\n ctx.closePanel(currentPanelId);\n }, [currentPanelId, ctx]),\n togglePanel: useCallback(\n (panel: Panel) => {\n ctx.togglePanel(panel);\n },\n [ctx],\n ),\n isPanelOpen: ctx.isPanelOpen(currentPanelId),\n };\n};\n","import { cloneElement } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { usePersistentFloatingPanels } from './FloatingPanelContext';\n\nexport default function FloatingPanelRenderer() {\n const { panels, closePanel } = usePersistentFloatingPanels();\n\n if (panels.length === 0) {\n return null;\n }\n\n return createPortal(\n panels.map(({ key, panelElement: panel }) => {\n return cloneElement(panel, { onClose: () => closePanel(key), key: key });\n }),\n document.body,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,MAAa,UAAU;AAKvB,SAAgB,iBAAiB,gBAAwB,WAAmB,WAAmB;AAC7F,QAAO,KAAK,IAAI,WAAW,iBAAiB,KAAK,IAAA,IAAkB,UAAU,GAAA,GAAgB;;;;ACwB/F,MAAa,2BAA2B;AA2ExC,MAAM,yBAAyB,OAAO,OAAO,IAAI;;aAMpC,UAAU,MAAM;iBACZ,EAAE,YACf,cAAc,OAAO,mBAAmB,MAAM,MAAM,WAAW,QAAQ,CAAC;uBACrD,EAAE,YAAY,cAAc,OAAO,gBAAgB,MAAM,cAAc,CAAC;mBAC5E,aAAa,GAAG;kIACL;;;;KAIzB,EAAE,YAAY,YAAY,iBAC3B,cACA,GAAG;;oBAEa,cAAc,EAAE;oBAChB,cAAc,EAAE;MAC9B;;AAGN,MAAM,aAAa,OAAO,OAAO,IAAI;aACxB,EAAE,iBAAkB,aAAa,YAAY,OAAQ;;;;eAInD,EAAE,iBAAkB,aAAa,YAAY,WAAY;;;;;;;;aAQ3D,QAAQ,GAAG,GAAG,QAAQ,GAAG,GAAG,QAAQ,GAAG,GAAG,QAAQ,GAAG;8BACpC,EAAE,YAAY,cAAc,OAAO,gBAAgB,MAAM,cAAc,CAAC;;AAGtG,MAAM,SAAS,OAAO,GAAG;aACZ,QAAQ,GAAG,GAAG,QAAQ,GAAG,GAAG,QAAQ,GAAG,GAAG,QAAQ,GAAG;2BACvC,EAAE,YAAY,cAAc,OAAO,gBAAgB,MAAM,cAAc,CAAC;;uBAE5E,EAAE,YACrB,cAAc,OAAO,mBAAmB,MAAM,MAAM,WAAW,QAAQ,CAAC;;uBAErD,aAAa,GAAG,GAAG,aAAa,GAAG;;AAG1D,MAAM,mBAAmB,OAAO,GAAG;;;;AAMnC,MAAM,yBAAyB,OAAO,iBAAiB;;;;AAKvD,MAAM,0BAA0B,OAAO,uBAAuB;;;;;AAM9D,MAAM,yBAAyB,OAAO,uBAAuB;;;;;AAM7D,MAAM,sBAAsB,OAAO,uBAAuB;;;;;AAM1D,MAAM,uBAAuB,OAAO,uBAAuB;;;;;AAS3D,MAAM,qBAAqB,OAAO,iBAAiB;;;;;;;;AASnD,MAAM,kBAAkB,OAAO,iBAAiB;;;;;;;AAQhD,MAAM,oBAAoB,OAAO,iBAAiB;;;;;;;AAQlD,MAAM,mBAAmB,OAAO,iBAAiB;;;;;;;AAQjD,MAAM,eAAe,OAAO,GAAmD;;IAE3E,kBAAkB;;;;;;WAMX,EAAE,iBAAkB,aAAa,aAAa,SAAU;cACrD,EAAE,iBAAkB,aAAa,IAAI,QAAQ,GAAI;;AAI/D,MAAM,YAAY,OAAO,CAAC;IACtB,gBAAgB,GAAG;;;;;;;;;AAUvB,MAAM,mBAAmB,OAAO,WAAW;;;mBAGxB,aAAa,GAAG;;AAKnC,SAAS,kBAAkB,EAAE,WAAoC;CAC/D,MAAM,WAAW,aAAa;CAC9B,MAAM,kBAAkB,OAAO,SAAS;AACxC,iBAAgB;AACd,MAAI,aAAa,gBAAgB,QAC/B,UAAS;IAEV,CAAC,UAAU,QAAQ,CAAC;AACvB,QAAO;;AAGT,SAAwB,cAAc,EACpC,QAAQ,eACR,UACA,SAAS,MACT,YACA,eAAe,KACf,gBAAgB,KAChB,WAAW,KACX,YAAY,KACZ,iBAAiB,GACjB,kBAAkB,GAClB,eACA,wBACA,YAAY,SACZ,cAAc,MACd,kBAAkB,OAClB,WACA,eACA,oBAAoB,OACpB,aAAa,OACb,gBAAgB,IAChB,GAAG,aACkB;CACrB,MAAM,EAAE,kBAAkB,WAAW,cAAc;CACnD,MAAM,uBAAuB,eAAe,wBAAA;CAC5C,MAAM,YAAY,iBAAiB;CACnC,MAAM,2BACJ,eAAe,uBAAuB,IAAI,uBAAuB,SAAS;CAE5E,MAAM,CAAC,WAAW,gBAAgB,SAAS;EAAE,OAAO;EAAc,QAAQ;EAAe,CAAC;CAC1F,MAAM,eAAe,OAAO;EAAE,OAAO;EAAc,QAAQ;EAAe,CAAC;CAC3E,MAAM,CAAC,eAAe,oBAAoB,SAAS;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;CAClE,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,CAAC,WAAW;CAEnE,MAAM,CAAC,UAAU,eAAe,SAAS,gBAAgB;CACzD,MAAM,kBAAkB,OAAsB,KAAK;CACnD,MAAM,iBAAiB,OAAsB,KAAK;CAElD,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,MAAM;CACnE,MAAM,kBAAkB,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;CAE9C,MAAM,qBAAqB,OAA+B,KAAK;CAC/D,MAAM,2BAA2B,OAAO;EACtC,OAAO;EACP,QAAQ;EACR,GAAG;EACH,GAAG;EACJ,CAAC;CAGF,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,MAAM;CACnE,MAAM,aAAa,OAAuB,KAAK;CAG/C,MAAM,uBAAuB,kBAAkB;CAE/C,MAAM,eAAe,iBAAiB;CAEtC,MAAM,IAAI,eAAe,EAAE;CAC3B,MAAM,IAAI,eAAe,EAAE;CAE3B,MAAM,EACJ,GAAG,WACH,GAAG,WACH,SACE,YAAY;EACH;EACX,UAAU,EACR,WAAW,YAAY,WAAW,KAAA,GACnC;EACD,YAAY;GACV,OAAO;IACL,UAAU;IACV,WAAW;IACZ,CAAC;GACF,MAAM;GAIN,MAAM;IAAE,WAAW;IAAM,SAAA;IAAkB,CAAC;GAC7C;EACF,CAAC;AAEF,iBAAgB;AAGd,MAAI,CAAC,cAAc,cAAc,KAAK,cAAc,GAAG;AACrD,oBAAiB;IACf,GAAG;IACH,GAAG;IACJ,CAAC;AACF,sBAAmB,KAAK;;IAEzB;EAAC;EAAW;EAAW;EAAW,CAAC;CAGtC,MAAM,CAAC,kBAAkB,uBAAuB,SAAS;EACvD,OAAO,OAAO,WAAW,cAAc,OAAO,aAAa;EAC3D,QAAQ,OAAO,WAAW,cAAc,OAAO,cAAc;EAC9D,CAAC;AAGF,iBAAgB;EACd,MAAM,qBAAqB;AACzB,uBAAoB;IAClB,OAAO,OAAO;IACd,QAAQ,OAAO;IAChB,CAAC;;AAGJ,SAAO,iBAAiB,UAAU,aAAa;AAC/C,eAAa,OAAO,oBAAoB,UAAU,aAAa;IAC9D,EAAE,CAAC;CAEN,MAAM,kBAAkB,WACpB,KAAA,IACA;EACE,MAAA;EACA,OAAO,KAAK,IAAA,GAAa,iBAAiB,QAAQ,UAAU,QAAA,EAAgB;EAC5E,KAAA;EACA,QAAQ,KAAK,IAAA,GAAa,iBAAiB,SAAS,UAAU,SAAA,EAAiB;EAChF;CAGL,MAAM,wBAAwB,aAC3B,aAAuC;AACtC,MAAI,SACF,QAAO;AAGT,SAAO;GACL,GAAG,KAAK,IAAA,GAEN,KAAK,IACH,SAAS,GACT,KAAK,IAAA,GAAa,iBAAiB,QAAQ,UAAU,QAAA,EAAgB,CACtE,CACF;GACD,GAAG,KAAK,IAAA,GAEN,KAAK,IACH,SAAS,GACT,KAAK,IAAA,GAAa,iBAAiB,SAAS,UAAU,SAAA,EAAiB,CACxE,CACF;GACF;IAEH;EAAC;EAAkB;EAAW;EAAS,CACxC;AAGD,iBAAgB;AACd,MAAI,CAAC,UAAU;GACb,MAAM,kBAAkB,sBAAsB,cAAc;AAC5D,OAAI,gBAAgB,MAAM,cAAc,KAAK,gBAAgB,MAAM,cAAc,EAC/E,kBAAiB,gBAAgB;;IAGpC;EAAC;EAAkB;EAAe;EAAuB;EAAS,CAAC;AAEtE,iBAAgB;AACd,MAAI,oBAAoB;GACtB,MAAM,QAAQ,iBAAiB,sBAAsB,MAAM,EAAE,IAAI;AACjE,gBAAa,aAAa,MAAM;;IAEjC,CAAC,mBAAmB,CAAC;AAGxB,iBAAgB;AACd,eAAa,UAAU;IACtB,CAAC,UAAU,CAAC;CAMf,MAAM,eAAe,cAAc,CAAC,sBAAsB,CAAC;CAG3D,SAAS,sBACP,OACA,WACA;AACA,QAAM,gBAAgB;AACtB,QAAM,iBAAiB;EAEvB,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,UAAU;GAMZ,MAAM,YAAY,WAAW,SAAS;AACtC,kBAAe,WAAW,eAAe,iBAAiB,QAAQ;AAClE,mBAAgB,WAAW,gBAAgB,iBAAiB,SAAS;AACrE,cAAW;AACX,cAAW;AAGX,KAAE,IAAI,EAAE;AACR,KAAE,IAAI,EAAE;AACR,eAAY,MAAM;AAClB,gBAAa;IAAE,OAAO;IAAc,QAAQ;IAAe,CAAC;AAC5D,oBAAiB;IAAE,GAAG;IAAU,GAAG;IAAU,CAAC;aACrC,cAAc;AAKvB,oBADkB,WAAW,SAAS,gBACX,gBAAgB,UAAU;AACrD,kBAAe,UAAU;AACzB,cAAW,cAAc;AACzB,cAAW,cAAc;AACzB,gBAAa;IAAE,OAAO;IAAc,QAAQ;IAAe,CAAC;SACvD;AACL,kBAAe,UAAU;AACzB,mBAAgB,UAAU;AAC1B,cAAW,cAAc;AACzB,cAAW,cAAc;;AAG3B,eAAa,UAAU;GAAE,OAAO;GAAc,QAAQ;GAAe;AAIrE,2BAAyB,UAAU;GACjC,OAAO;GACP,QAAQ;GACR,GAAG;GACH,GAAG;GACJ;AAGD,wBAAsB,KAAK;AAE3B,qBAAmB,UAAU;AAG7B,MAAI,cAAA,KAEF,iBAAgB,UAAU;GACxB,GAAG,MAAM,UAAU;GACnB,GAAG,MAAM,UAAU;GACpB;WACQ,cAAA,MAAyC;AAElD,kBAAe,UAAU,EAAE,KAAK,GAAG;AACnC,mBAAgB,UAAU;IACxB,GAAG,MAAM;IACT,GAAG,MAAM,UAAU;IACpB;aACQ,cAAA,MAAyC;AAElD,kBAAe,UAAU,EAAE,KAAK,GAAG;AACnC,mBAAgB,UAAU,EAAE,KAAK,GAAG;AACpC,mBAAgB,UAAU;IACxB,GAAG,MAAM;IACT,GAAG,MAAM;IACV;aACQ,cAAA,MAAyC;AAElD,mBAAgB,UAAU,EAAE,KAAK,GAAG;AACpC,mBAAgB,UAAU;IACxB,GAAG,MAAM,UAAU;IACnB,GAAG,MAAM;IACV;aACQ,cAAA,KAAoC;AAE7C,kBAAe,UAAU,EAAE,KAAK,GAAG;AACnC,mBAAgB,UAAU;IACxB,GAAG,MAAM;IACT,GAAG;IACJ;aACQ,cAAA,IAET,iBAAgB,UAAU;GACxB,GAAG,MAAM,UAAU;GACnB,GAAG;GACJ;WACQ,cAAA,KAAqC;AAE9C,mBAAgB,UAAU,EAAE,KAAK,GAAG;AACpC,mBAAgB,UAAU;IACxB,GAAG;IACH,GAAG,MAAM;IACV;aACQ,cAAA,IAET,iBAAgB,UAAU;GACxB,GAAG;GACH,GAAG,MAAM,UAAU;GACpB;AAGH,WAAS,iBAAiB,aAAa,sBAAsB;AAC7D,WAAS,iBAAiB,WAAW,oBAAoB;;CAI3D,SAAS,sBAAsB,OAAmB;EAChD,MAAM,YAAY,mBAAmB;EAIrC,IAAI,WAAW,yBAAyB,QAAQ;EAChD,IAAI,YAAY,yBAAyB,QAAQ;EACjD,IAAI,WAAW,yBAAyB,QAAQ;EAChD,IAAI,WAAW,yBAAyB,QAAQ;AAEhD,MAAI,cAAA,MAAyC;AAE3C,cAAW,KAAK,MAAM,KAAK,IAAI,UAAU,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;AACpF,eAAY,KAAK,MAAM,KAAK,IAAI,WAAW,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;aAC7E,cAAA,MAAyC;GAElD,MAAM,QAAQ,eAAe;GAC7B,MAAM,YAAY,MAAM;AACxB,cAAW,KAAK,MAAM,KAAK,IAAI,UAAU,QAAQ,UAAU,CAAC;AAC5D,cAAW,KAAK,MAAM,QAAQ,SAAS;AACvC,eAAY,KAAK,MAAM,KAAK,IAAI,WAAW,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;aAC7E,cAAA,MAAyC;GAElD,MAAM,QAAQ,eAAe;GAC7B,MAAM,SAAS,gBAAgB;GAC/B,MAAM,YAAY,MAAM;GACxB,MAAM,YAAY,MAAM;AACxB,cAAW,KAAK,MAAM,KAAK,IAAI,UAAU,QAAQ,UAAU,CAAC;AAC5D,eAAY,KAAK,MAAM,KAAK,IAAI,WAAW,SAAS,UAAU,CAAC;AAC/D,cAAW,KAAK,MAAM,QAAQ,SAAS;AACvC,cAAW,KAAK,MAAM,SAAS,UAAU;aAChC,cAAA,MAAyC;GAElD,MAAM,SAAS,gBAAgB;GAC/B,MAAM,YAAY,MAAM;AACxB,cAAW,KAAK,MAAM,KAAK,IAAI,UAAU,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;AACpF,eAAY,KAAK,MAAM,KAAK,IAAI,WAAW,SAAS,UAAU,CAAC;AAC/D,cAAW,KAAK,MAAM,SAAS,UAAU;aAChC,cAAA,KAAoC;GAE7C,MAAM,QAAQ,eAAe;GAC7B,MAAM,YAAY,MAAM;AACxB,cAAW,KAAK,MAAM,KAAK,IAAI,UAAU,QAAQ,UAAU,CAAC;AAC5D,cAAW,KAAK,MAAM,QAAQ,SAAS;aAC9B,cAAA,IAET,YAAW,KAAK,MAAM,KAAK,IAAI,UAAU,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;WAC3E,cAAA,KAAqC;GAE9C,MAAM,SAAS,gBAAgB;GAC/B,MAAM,YAAY,MAAM;AACxB,eAAY,KAAK,MAAM,KAAK,IAAI,WAAW,SAAS,UAAU,CAAC;AAC/D,cAAW,KAAK,MAAM,SAAS,UAAU;aAChC,cAAA,IAET,aAAY,KAAK,MAAM,KAAK,IAAI,WAAW,MAAM,UAAU,gBAAgB,QAAQ,EAAE,CAAC;AAMxF,kBAAgB;AACd,oBAAiB;IAAE,GAAG;IAAU,GAAG;IAAU,CAAC;AAC9C,gBAAa;IAAE,OAAO;IAAU,QAAQ;IAAW,CAAC;IACpD;;CAGJ,SAAS,sBAAsB;AAC7B,WAAS,oBAAoB,aAAa,sBAAsB;AAChE,WAAS,oBAAoB,WAAW,oBAAoB;;CAG9D,MAAM,eACJ,qBAAC,wBAAD;EAEE,KAAK,KAAK;EACV,YAAY;EACZ,YAAY,iBAAiB,iBAAiB,QAAQ,cAAc,GAAG,UAAU;EACjF,YAAY;EACZ,OAAO;GACL;GACA;GACD;EACD,SAAS;GACP,KAAK;GACL,MAAM;GACN,SAAS;GACV;EACD,SAAS;GACP,GAAG,WAAA,IAAqB,cAAc;GACtC,GAAG,WAAA,IAAqB,cAAc;GAGtC,OAAO,WAAW,eAAA,IAAyB,qBAAqB,OAAO,UAAU;GAGjF,GAAI,eAAe,EAAE,GAAG,EAAE,QAAQ,WAAW,sBAAsB,UAAU,QAAQ;GACrF,SAAS,kBAAkB,IAAI;GAChC;EACD,YACE,qBACI;GACE,MAAM;GAEN,MAAM;IAAC;IAAM;IAAK;IAAM;IAAI;GAC5B,UAAU,uBAAuB,MAAM;GACxC,GACD;GAAE,SAAS;IAAE,UAAU;IAAM,MAAM;IAAW;GAAE,UAAU;GAAG;EAEnE,iBAAiB;AACf,OAAI,CAAC,SAGH,kBADwB,sBAAsB;IADxB,GAAG,EAAE,KAAK;IAAE,GAAG,EAAE,KAAK;IACa,CACzB,CAAC;;EAGrC,MAAM,CAAC;EACO;EACd,cAAc;EACd,cAAc;EACG;EAGjB,IAAI,GAAG,yBAAyB;EAChC,GAAI;YAnDN;GAqDE,oBAAC,YAAD;IAAY,YAAY;IAAU,gBAAgB,MAAM,aAAa,MAAM,EAAE;cAC3E,qBAAC,OAAD;KAAO,OAAM;KAAS,WAAU;KAAa,SAAQ;eAArD,CACE,oBAAC,WAAD,EAAA,UAAY,OAAkB,CAAA,EAC9B,qBAAC,OAAD;MAAO,WAAU;MAAa,OAAM;MAAS,SAAS,QAAQ;gBAA9D;OACG;OACA,eACC,oBAAC,kBAAD;QACE,MAAK;QACL,cAAY,WAAW,aAAa;QACpC,IAAG;QACH,eAAe;AACb,+BAAsB,KAAK;AAC3B,qBAAY,CAAC,SAAS;;kBAGvB,WAAW,oBAAC,mBAAD,EAAqB,CAAA,GAAG,oBAAC,iBAAD,EAAmB,CAAA;QACtC,CAAA;OAGrB,oBAAC,kBAAD;QACE,MAAK;QACL,IAAG;QACH,eAAe,WAAW;QAC1B,cAAW;kBAEX,oBAAC,OAAD,EAAS,CAAA;QACQ,CAAA;OACb;QACF;;IACG,CAAA;GACb,oBAAC,cAAD;IAAc,KAAK;IAAY,YAAY;IAAW,YAAY;IAC/D;IACY,CAAA;GACd,aACC,oBAAC,QAAD;IAAQ,OAAO,EAAE,aAAa,2BAA2B,QAAQ,KAAK,QAAQ,IAAI;cAChF,qBAAC,OAAD;KACE,OAAM;KACN,WAAU;KACV,SAAS,yBAAyB,kBAAkB;eAHtD,CAKG,2BACE,2BACC,yBAEA,oBAAC,WAAD,EAAA,UAAY,wBAAmC,CAAA,GAGlD,iBAAiB,oBAAC,OAAD,EAAA,UAAM,eAAoB,CAAA,CACtC;;IACD,CAAA;GAEX,oBAAC,yBAAD;IACE,aAAU;IACV,cAAc,UAAU,sBAAsB,OAAA,KAAiC;IAC/E,CAAA;GACF,oBAAC,oBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,IAA6B,EAC3E,CAAA;GACF,oBAAC,wBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,KAAiC,EAC/E,CAAA;GACF,oBAAC,kBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,IAA4B,EAC1E,CAAA;GACF,oBAAC,qBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,KAAiC,EAC/E,CAAA;GACF,oBAAC,iBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,IAA6B,EAC3E,CAAA;GACF,oBAAC,sBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,KAAiC,EAC/E,CAAA;GACF,oBAAC,mBAAD,EACE,cAAc,UAAU,sBAAsB,OAAA,IAA4B,EAC1E,CAAA;GACqB;;CAG3B,MAAM,UACJ,qBAAA,YAAA,EAAA,UAAA,CACG,qBAAqB,oBAAC,mBAAD,EAA4B,SAAW,CAAA,EAC5D,aACA,EAAA,CAAA;AAGL,QAAO,SAAS,aAAa,SAAS,SAAS,KAAK,GAAG;;;;ACtvBzD,MAAM,eAAe,cAAuC,KAAK;AAEjE,MAAa,iBAAiB,EAAE,eAAwC;CACtE,MAAM,CAAC,QAAQ,aAAa,SAAkB,EAAE,CAAC;CACjD,MAAM,WAAW,aAAa;CAE9B,SAAS,mBAAmB,YAAoB,sBAAwC;AACtF,MAAI,CAAC,qBACH,QAAO;AAET,SAAO,WAAW,SAAS,qBAAqB;;CAGlD,MAAM,YAAY,aACf,UAAiB;EAChB,MAAM,EAAE,KAAK,cAAc,yBAAyB;EACpD,MAAM,WAAW,wBAAwB;AACzC,aAAW,SAAS,CAClB,GAAG,KAAK,QAAQ,MAAM,EAAE,QAAQ,IAAI,EACpC;GAAE;GAAK;GAAc,sBAAsB;GAAU,CACtD,CAAC;IAEJ,CAAC,SAAS,CACX;CAED,MAAM,aAAa,aAAa,QAAgB;AAC9C,aAAW,SAAS,KAAK,QAAQ,UAAU,MAAM,QAAQ,IAAI,CAAC;IAC7D,EAAE,CAAC;CAEN,MAAM,cAAc,aACjB,QAAgB;AACf,SAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,IAAI;IAElD,CAAC,OAAO,CACT;CAED,MAAM,cAAc,aACjB,UAAiB;EAChB,MAAM,EAAE,QAAQ;AAChB,MAAI,YAAY,IAAI,CAClB,YAAW,IAAI;MAEf,WAAU,MAAM;IAGpB;EAAC;EAAa;EAAY;EAAU,CACrC;CAED,MAAM,iBAAiB,kBAAkB;AACvC,YAAU,EAAE,CAAC;IACZ,EAAE,CAAC;AAEN,iBAAgB;EACd,MAAM,eAAe;AAErB,aAAW,eACT,WAAW,QAAQ,UAAU,mBAAmB,cAAc,MAAM,qBAAqB,CAAC,CAC3F;IACA,CAAC,SAAS,CAAC;AAEd,QACE,oBAAC,aAAa,UAAd;EACE,OAAO;GAAE;GAAW;GAAY;GAAa;GAAgB;GAAQ;GAAa;EAEjF;EACqB,CAAA;;AAI5B,MAAa,oCAAoC;CAC/C,MAAM,MAAM,WAAW,aAAa;AACpC,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,kEAAkE;AAEpF,QAAO;;AAKT,MAAa,8BAA8B,YAAqB;CAC9D,MAAM,MAAM,WAAW,aAAa;AACpC,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,kEAAkE;CAIpF,MAAM,iBAAiB,WAAW,SAASA,IAAM;AAEjD,QAAO;EACL,IAAI;EACJ,WAAW,aACR,UAAiB;AAChB,OAAI,UAAU,MAAM;KAEtB,CAAC,IAAI,CACN;EACD,YAAY,kBAAkB;AAC5B,OAAI,WAAW,eAAe;KAC7B,CAAC,gBAAgB,IAAI,CAAC;EACzB,aAAa,aACV,UAAiB;AAChB,OAAI,YAAY,MAAM;KAExB,CAAC,IAAI,CACN;EACD,aAAa,IAAI,YAAY,eAAe;EAC7C;;;;ACjIH,SAAwB,wBAAwB;CAC9C,MAAM,EAAE,QAAQ,eAAe,6BAA6B;AAE5D,KAAI,OAAO,WAAW,EACpB,QAAO;AAGT,QAAO,aACL,OAAO,KAAK,EAAE,KAAK,cAAc,YAAY;AAC3C,SAAO,aAAa,OAAO;GAAE,eAAe,WAAW,IAAI;GAAO;GAAK,CAAC;GACxE,EACF,SAAS,KACV"}
|