Skip to content

Commit

Permalink
feat: Better floating of editing widget (#18780)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Nov 22, 2023
1 parent e35c8e5 commit 9033d08
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 33 deletions.
2 changes: 1 addition & 1 deletion frontend/src/scenes/notebooks/Nodes/NodeWrapper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
}

&--selected {
--border-color: var(--primary-3000);
--border-color: var(--border-bold);
}

&--auto-hide-metadata {
Expand Down
15 changes: 12 additions & 3 deletions frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,17 @@ function NodeWrapper<T extends CustomNotebookNodeAttributes>(props: NodeWrapperP
// nodeId can start null, but should then immediately be generated
const nodeLogic = useMountedLogic(notebookNodeLogic(logicProps))
const { resizeable, expanded, actions, nodeId } = useValues(nodeLogic)
const { setExpanded, deleteNode, toggleEditing, insertOrSelectNextLine } = useActions(nodeLogic)
const { setRef, setExpanded, deleteNode, toggleEditing, insertOrSelectNextLine } = useActions(nodeLogic)

const { ref: inViewRef, inView } = useInView({ triggerOnce: true })

const setRefs = useCallback(
(node) => {
setRef(node)
inViewRef(node)
},
[inViewRef]
)

useEffect(() => {
// TRICKY: child nodes mount the parent logic so we need to control the mounting / unmounting directly in this component
Expand All @@ -92,7 +102,6 @@ function NodeWrapper<T extends CustomNotebookNodeAttributes>(props: NodeWrapperP
mountedNotebookLogic,
})

const [ref, inView] = useInView({ triggerOnce: true })
const contentRef = useRef<HTMLDivElement | null>(null)

// If resizeable is true then the node attr "height" is required
Expand Down Expand Up @@ -136,7 +145,7 @@ function NodeWrapper<T extends CustomNotebookNodeAttributes>(props: NodeWrapperP
<BindLogic logic={notebookNodeLogic} props={logicProps}>
<NodeViewWrapper as="div">
<div
ref={ref}
ref={setRefs}
className={clsx(nodeType, 'NotebookNode', {
'NotebookNode--auto-hide-metadata': autoHideMetadata,
'NotebookNode--editable': getPos && isEditable,
Expand Down
12 changes: 11 additions & 1 deletion frontend/src/scenes/notebooks/Nodes/notebookNodeLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const notebookNodeLogic = kea<notebookNodeLogicType>([
initializeNode: true,
setMessageListeners: (listeners: NotebookNodeMessagesListeners) => ({ listeners }),
setTitlePlaceholder: (titlePlaceholder: string) => ({ titlePlaceholder }),
setRef: (ref: HTMLElement | null) => ({ ref }),
}),

connect((props: NotebookNodeLogicProps) => ({
Expand All @@ -71,6 +72,13 @@ export const notebookNodeLogic = kea<notebookNodeLogicType>([
})),

reducers(({ props }) => ({
ref: [
null as HTMLElement | null,
{
setRef: (_, { ref }) => ref,
unregisterNodeLogic: () => null,
},
],
expanded: [
props.startExpanded ?? true,
{
Expand Down Expand Up @@ -246,7 +254,9 @@ export const notebookNodeLogic = kea<notebookNodeLogicType>([
props.updateAttributes(attributes)
},
toggleEditing: ({ visible }) => {
const shouldShowThis = typeof visible === 'boolean' ? visible : !values.notebookLogic.values.editingNodeId
const shouldShowThis =
typeof visible === 'boolean' ? visible : values.notebookLogic.values.editingNodeId !== values.nodeId

props.notebookLogic.actions.setEditingNodeId(shouldShowThis ? values.nodeId : null)
},
initializeNode: () => {
Expand Down
39 changes: 22 additions & 17 deletions frontend/src/scenes/notebooks/Notebook/Notebook.scss
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,6 @@
}
}

&--editable {
.NotebookEditor .ProseMirror {
// Add some padding to help clicking below the last element
padding-bottom: 10rem;
flex: 1;
}
}

.NotebookColumn {
position: relative;
width: 0;
Expand Down Expand Up @@ -191,6 +183,11 @@
.NotebookColumn__content {
width: var(--notebook-column-left-width);
transform: translateX(-100%);

> .LemonWidget .LemonWidget__content {
max-height: var(--notebook-sidebar-height);
overflow: auto;
}
}
}

Expand Down Expand Up @@ -218,12 +215,27 @@
}
}

&--editable {
.NotebookEditor .ProseMirror {
// Add some padding to help clicking below the last element
padding-bottom: 10rem;
flex: 1;
}

.NotebookColumn--left.NotebookColumn--showing {
& + .NotebookEditor {
.ProseMirror {
// Add a lot of padding to allow the entire column to always be on screen
padding-bottom: 100vh;
}
}
}
}

.NotebookHistory {
flex: 1;
display: flex;
flex-direction: column;
height: var(--notebook-sidebar-height);
overflow: hidden;
}

.NotebookInlineMenu {
Expand All @@ -236,13 +248,6 @@
}
}

.NotebookColumnLeft__widget {
> .LemonWidget__content {
max-height: calc(100vh - 220px);
overflow: auto;
}
}

.LemonTable__content > table > thead {
position: sticky;
top: 0;
Expand Down
52 changes: 46 additions & 6 deletions frontend/src/scenes/notebooks/Notebook/NotebookColumnLeft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import clsx from 'clsx'
import { notebookLogic } from './notebookLogic'
import { notebookNodeLogicType } from '../Nodes/notebookNodeLogicType'
import { LemonButton } from '@posthog/lemon-ui'
import { IconEyeVisible } from 'lib/lemon-ui/icons'
import { NotebookHistory } from './NotebookHistory'
import { useEffect, useRef, useState } from 'react'

export const NotebookColumnLeft = (): JSX.Element | null => {
const { editingNodeLogic, isShowingLeftColumn, showHistory } = useValues(notebookLogic)
Expand All @@ -16,7 +16,7 @@ export const NotebookColumnLeft = (): JSX.Element | null => {
'NotebookColumn--showing': isShowingLeftColumn,
})}
>
<div className="NotebookColumn__padding" />
{editingNodeLogic ? <NotebookNodeSettingsOffset logic={editingNodeLogic} /> : null}
<div className="NotebookColumn__content">
{isShowingLeftColumn ? (
editingNodeLogic ? (
Expand All @@ -30,6 +30,41 @@ export const NotebookColumnLeft = (): JSX.Element | null => {
)
}

export const NotebookNodeSettingsOffset = ({ logic }: { logic: BuiltLogic<notebookNodeLogicType> }): JSX.Element => {
const { ref } = useValues(logic)
const offsetRef = useRef<HTMLDivElement>(null)
const [height, setHeight] = useState(0)

useEffect(() => {
// Interval to check the relative positions of the node and the offset div
// updating the height so that it always is inline
const updateHeight = (): void => {
if (ref && offsetRef.current) {
const newHeight = ref.getBoundingClientRect().top - offsetRef.current.getBoundingClientRect().top

if (height !== newHeight) {
setHeight(newHeight)
}
}
}

const interval = setInterval(updateHeight, 100)
updateHeight()

return () => clearInterval(interval)
}, [ref, offsetRef.current, height])

return (
<div
ref={offsetRef}
// eslint-disable-next-line react/forbid-dom-props
style={{
height,
}}
/>
)
}

export const NotebookNodeSettingsWidget = ({ logic }: { logic: BuiltLogic<notebookNodeLogicType> }): JSX.Element => {
const { setEditingNodeId } = useActions(notebookLogic)
const { Settings, nodeAttributes, title } = useValues(logic)
Expand All @@ -41,16 +76,21 @@ export const NotebookNodeSettingsWidget = ({ logic }: { logic: BuiltLogic<notebo
className="NotebookColumn__widget"
actions={
<>
<LemonButton icon={<IconEyeVisible />} size="small" status="primary" onClick={() => selectNode()} />
<LemonButton size="small" status="primary" onClick={() => setEditingNodeId(null)}>
Done
</LemonButton>
</>
}
>
{Settings ? (
<Settings key={nodeAttributes.nodeId} attributes={nodeAttributes} updateAttributes={updateAttributes} />
) : null}
<div onClick={() => selectNode()}>
{Settings ? (
<Settings
key={nodeAttributes.nodeId}
attributes={nodeAttributes}
updateAttributes={updateAttributes}
/>
) : null}
</div>
</LemonWidget>
)
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
"react-dom": "^18.2.0",
"react-draggable": "^4.2.0",
"react-grid-layout": "^1.3.0",
"react-intersection-observer": "^9.4.3",
"react-intersection-observer": "^9.5.3",
"react-markdown": "^5.0.3",
"react-modal": "^3.15.1",
"react-resizable": "^3.0.5",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9033d08

Please sign in to comment.