From aac4be56091800d9812ceda77c8a49ff75540815 Mon Sep 17 00:00:00 2001 From: heswell Date: Wed, 13 Nov 2024 09:09:02 +0000 Subject: [PATCH] reenebale minimize on flexbox --- vuu-ui/packages/vuu-icons/index.css | 8 ++ .../vuu-layout/src/flexbox/Flexbox.css | 1 + .../vuu-layout/src/flexbox/Flexbox.tsx | 3 +- .../vuu-layout/src/flexbox/flexboxTypes.ts | 4 +- .../src/flexbox/useSplitterResizing.ts | 33 +++-- .../vuu-layout/src/layout-header/Header.tsx | 126 ++++++---------- .../vuu-layout/src/layout-header/useHeader.ts | 100 +++++++++++++ .../src/layout-reducer/layout-reducer.ts | 47 +++--- .../src/layout-reducer/layoutTypes.ts | 19 ++- .../layout-reducer/replace-layout-element.ts | 87 ++++++------ .../useViewActionDispatcher.ts | 21 ++- .../vuu-layout/src/layout-view/View.css | 15 +- .../vuu-layout/src/layout-view/View.tsx | 3 + .../vuu-layout/src/layout-view/viewTypes.ts | 14 +- .../packages/vuu-table/src/useTableModel.ts | 2 - .../ClientSourcedTableColumn.examples.tsx | 134 ++++++++++++++---- .../src/examples/Layout/Flexbox.examples.tsx | 57 ++++++++ 17 files changed, 464 insertions(+), 210 deletions(-) create mode 100644 vuu-ui/packages/vuu-layout/src/layout-header/useHeader.ts diff --git a/vuu-ui/packages/vuu-icons/index.css b/vuu-ui/packages/vuu-icons/index.css index 788144b9e..f515fc3a3 100644 --- a/vuu-ui/packages/vuu-icons/index.css +++ b/vuu-ui/packages/vuu-icons/index.css @@ -148,6 +148,12 @@ span[data-icon] { [data-icon="chevron-down"] { --vuu-icon-svg: var(--vuu-svg-chevron-down); + transition: transform .2s linear; +} +[data-icon="chevron-open"] { + --vuu-icon-svg: var(--vuu-svg-chevron-down); + transform: rotate(-90deg); + transition: transform .2s linear; } [data-icon="chevron-left"] { @@ -158,6 +164,8 @@ span[data-icon] { --vuu-icon-svg: var(--vuu-svg-chevron-right); } + + [data-icon="close"] { --vuu-icon-svg: var(--vuu-close-icon-svg, var(--svg-close)); } diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.css b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.css index 880ddcc9f..02fe26b08 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.css +++ b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.css @@ -42,3 +42,4 @@ .vuuView.flex-fill { border-color: red; } + diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx index 5e9d69e6b..6eba91ba1 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx +++ b/vuu-ui/packages/vuu-layout/src/flexbox/Flexbox.tsx @@ -12,7 +12,7 @@ const classBase = "hwFlexbox"; const Flexbox = forwardRef(function Flexbox( props: FlexboxProps, - ref: ForwardedRef + ref: ForwardedRef, ) { const { breakPoints, @@ -42,7 +42,6 @@ const Flexbox = forwardRef(function Flexbox( const { content, rootRef } = useSplitterResizing({ children, - // cols: colsProp, onSplitterMoved, style, }); diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/flexboxTypes.ts b/vuu-ui/packages/vuu-layout/src/flexbox/flexboxTypes.ts index e976f2373..24f780f90 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/flexboxTypes.ts +++ b/vuu-ui/packages/vuu-layout/src/flexbox/flexboxTypes.ts @@ -11,6 +11,8 @@ export interface LayoutContainerProps { resizeable?: boolean; } +export type SplitterMoveHandler = (content: ContentMeta[]) => void; + export interface FlexboxProps extends LayoutContainerProps, HTMLAttributes { @@ -21,7 +23,7 @@ export interface FlexboxProps fullPage?: number; flexFill?: boolean; gap?: number; - onSplitterMoved?: (content: ContentMeta[]) => void; + onSplitterMoved?: SplitterMoveHandler; row?: true; spacing?: number; splitterSize?: number; diff --git a/vuu-ui/packages/vuu-layout/src/flexbox/useSplitterResizing.ts b/vuu-ui/packages/vuu-layout/src/flexbox/useSplitterResizing.ts index 4f4624eab..0074de01f 100644 --- a/vuu-ui/packages/vuu-layout/src/flexbox/useSplitterResizing.ts +++ b/vuu-ui/packages/vuu-layout/src/flexbox/useSplitterResizing.ts @@ -50,9 +50,9 @@ export const useSplitterResizing = ({ Array.isArray(childrenProp) ? childrenProp : React.isValidElement(childrenProp) - ? [childrenProp] - : [], - [childrenProp] + ? [childrenProp] + : [], + [childrenProp], ); const handleDragStart = useCallback( @@ -61,7 +61,7 @@ export const useSplitterResizing = ({ if (contentMeta) { const [participants, bystanders] = identifyResizeParties( contentMeta, - index + index, ); if (participants) { participants.forEach((index) => { @@ -81,10 +81,14 @@ export const useSplitterResizing = ({ } }); } + + if (rootRef.current) { + rootRef.current.classList.add("vuuSplitterResizing"); + } } } }, - [dimension] + [dimension], ); const handleDrag = useCallback( @@ -95,18 +99,21 @@ export const useSplitterResizing = ({ contentRef.current, metaRef.current, distance, - dimension - ) + dimension, + ), ); } }, - [dimension] + [dimension], ); const handleDragEnd = useCallback(() => { const contentMeta = metaRef.current; if (contentMeta) { onSplitterMoved?.(contentMeta.filter(originalContentOnly)); + if (rootRef.current) { + rootRef.current.classList.remove("vuuSplitterResizing"); + } } contentMeta?.forEach((meta) => { meta.currentSize = undefined; @@ -126,7 +133,7 @@ export const useSplitterResizing = ({ onDragStart: handleDragStart, }); }, - [handleDrag, handleDragEnd, handleDragStart, isColumn] + [handleDrag, handleDragEnd, handleDragStart, isColumn], ); useMemo(() => { @@ -134,7 +141,7 @@ export const useSplitterResizing = ({ children, dimension, createSplitter, - assignedKeys.current + assignedKeys.current, ); metaRef.current = meta; contentRef.current = content; @@ -150,7 +157,7 @@ function buildContent( children: ReactElement[], dimension: "width" | "height", createSplitter: SplitterFactory, - keys: any[] + keys: any[], ): [any[], ContentMeta[]] { const childMeta = gatherChildMeta(children, dimension); const splitterAndPlaceholderPositions = @@ -186,7 +193,7 @@ function resizeContent( content: ReactElement[], contentMeta: ContentMeta[], distance: number, - dimension: "width" | "height" + dimension: "width" | "height", ) { const metaUpdated = updateMeta(contentMeta, distance); if (!metaUpdated) { @@ -260,7 +267,7 @@ function createPlaceholder(index: number) { function measureElement( el: HTMLElement, - dimension: "width" | "height" + dimension: "width" | "height", ): FlexSize { const { [dimension]: size } = el.getBoundingClientRect(); const style = getComputedStyle(el); diff --git a/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx b/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx index 41ef39fae..ce4d8a31b 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx +++ b/vuu-ui/packages/vuu-layout/src/layout-header/Header.tsx @@ -2,18 +2,9 @@ import { EditableLabel, IconButton } from "@finos/vuu-ui-controls"; import { useComponentCssInjection } from "@salt-ds/styles"; import { useWindow } from "@salt-ds/window"; import cx from "clsx"; -import { - HTMLAttributes, - KeyboardEvent, - MouseEvent, - ReactElement, - cloneElement, - useCallback, - useRef, - useState, -} from "react"; +import { HTMLAttributes, MouseEvent, ReactElement, cloneElement } from "react"; import { Contribution } from "../layout-view"; -import { useViewDispatch } from "../layout-view-actions/ViewContext"; +import { useHeader } from "./useHeader"; import headerCss from "./Header.css"; @@ -23,7 +14,7 @@ export interface HeaderProps extends HTMLAttributes { contributions?: Contribution[]; expanded?: boolean; closeable?: boolean; - onEditTitle: (value: string) => void; + onEditTitle?: (value: string) => void; orientation?: "horizontal" | "vertical"; tearOut?: boolean; } @@ -48,22 +39,25 @@ export const Header = ({ window: targetWindow, }); - const labelFieldRef = useRef(null); - const [value, setValue] = useState(title); - const [editing, setEditing] = useState(false); - - const viewDispatch = useViewDispatch(); - const handleClose = (evt: MouseEvent) => - viewDispatch?.({ type: "remove" }, evt); - - const focusTitle = useCallback(() => { - labelFieldRef.current?.focus(); - }, []); + const { + editing, + focusTitle, + labelFieldRef, + onClickEdit, + onClose, + onExitEditMode, + onMouseDown, + onTitleKeyDown, + onToggleCollapse, + onToggleExpand, + setValue, + value, + } = useHeader({ + onEditTitle, + title, + }); - const handleClickEdit = useCallback(() => { - focusTitle(); - setEditing((isEditing) => !isEditing); - }, [focusTitle]); + console.log(`Header ${title}`); const handleButtonMouseDown = (evt: MouseEvent) => { // do not allow drag to be initiated @@ -74,37 +68,11 @@ export const Header = ({ const className = cx(classBase, classNameProp, `${classBase}-${orientation}`); - const handleTitleKeyDown = (evt: KeyboardEvent) => { - if (evt.key === "Enter") { - setEditing(true); - } - }; - - const handleExitEditMode = ( - originalValue = "", - finalValue = "", - allowDeactivation = true, - editCancelled = false, - ) => { - setEditing(false); - if (editCancelled) { - setValue(originalValue); - } else if (finalValue !== originalValue) { - setValue(finalValue); - onEditTitle?.(finalValue); - } - if (allowDeactivation === false) { - labelFieldRef.current?.focus(); - } - }; - - const handleMouseDown = (e: MouseEvent) => { - viewDispatch?.({ type: "mousedown" }, e); - }; - const toolbarItems: ReactElement[] = []; const postTitleContributedItems: ReactElement[] = []; const actionButtons: ReactElement[] = []; + const allowCollapse = + typeof collapsed === "boolean" || typeof collapsed === "string"; contributions?.forEach((contribution, i) => { switch (contribution.location) { @@ -118,6 +86,23 @@ export const Header = ({ } }); + allowCollapse && + toolbarItems.push( + , + ); + title && toolbarItems.push( , ); @@ -140,7 +125,7 @@ export const Header = ({ data-embedded icon="edit" key="edit-button" - onClick={handleClickEdit} + onClick={onClickEdit} onMouseDown={handleButtonMouseDown} tabIndex={0} variant="secondary" @@ -150,12 +135,13 @@ export const Header = ({ closeable && actionButtons.push( , ); @@ -177,28 +163,10 @@ export const Header = ({
{toolbarItems} {/* - {collapsed === false ? ( - - ) : null} - {collapsed ? ( - - ) : null} {expanded === false ? ( { + debugString?: string; + title: string; +} + +export const useHeader = ({ onEditTitle, title }: HeaderHookProps) => { + const [editing, setEditing] = useState(false); + const [value, setValue] = useState(title); + const labelFieldRef = useRef(null); + + const viewDispatch = useViewDispatch(); + const handleClose = useCallback( + (evt) => viewDispatch?.({ type: "remove" }, evt), + [viewDispatch], + ); + + const focusTitle = useCallback(() => { + labelFieldRef.current?.focus(); + }, []); + + const handleClickEdit = useCallback(() => { + focusTitle(); + setEditing((isEditing) => !isEditing); + }, [focusTitle]); + + const handleTitleKeyDown = (evt: KeyboardEvent) => { + if (evt.key === "Enter") { + setEditing(true); + } + }; + + const handleMouseDown = useCallback( + (e) => { + const button = queryClosest(e.target, ".saltButton"); + if (button === null) { + // This is for drag start detection. + viewDispatch?.({ type: "mousedown" }, e); + } + }, + [viewDispatch], + ); + + const handleExitEditMode = ( + originalValue = "", + finalValue = "", + allowDeactivation = true, + editCancelled = false, + ) => { + setEditing(false); + if (editCancelled) { + setValue(originalValue); + } else if (finalValue !== originalValue) { + setValue(finalValue); + onEditTitle?.(finalValue); + } + if (allowDeactivation === false) { + labelFieldRef.current?.focus(); + } + }; + + const handleToggleCollapse = useCallback( + (e) => { + viewDispatch?.({ type: "collapse" }, e); + }, + [viewDispatch], + ); + + const handleToggleExpand = useCallback( + (e) => { + viewDispatch?.({ type: "expand" }, e); + }, + [viewDispatch], + ); + + return { + editing, + focusTitle, + labelFieldRef, + onClickEdit: handleClickEdit, + onClose: handleClose, + onExitEditMode: handleExitEditMode, + onMouseDown: handleMouseDown, + onToggleCollapse: handleToggleCollapse, + onToggleExpand: handleToggleExpand, + onTitleKeyDown: handleTitleKeyDown, + setValue, + value, + }; +}; diff --git a/vuu-ui/packages/vuu-layout/src/layout-reducer/layout-reducer.ts b/vuu-ui/packages/vuu-layout/src/layout-reducer/layout-reducer.ts index a877bc266..ccd5229a7 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-reducer/layout-reducer.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-reducer/layout-reducer.ts @@ -19,10 +19,11 @@ import { import { moveChild } from "./move-layout-element"; import { AddAction, + CollapseAction, DragDropAction, + ExpandAction, LayoutActionType, LayoutReducerAction, - MaximizeAction, SetPropAction, SetPropsAction, SwitchTabAction, @@ -39,14 +40,15 @@ import { wrap } from "./wrap-layout-element"; export const layoutReducer = ( state: ReactElement, - action: LayoutReducerAction + action: LayoutReducerAction, ): ReactElement => { switch (action.type) { case LayoutActionType.ADD: return addChild(state, action); case LayoutActionType.DRAG_DROP: return dragDrop(state, action); - case LayoutActionType.MAXIMIZE: + case "collapse": + case "expand": return setChildProps(state, action); case LayoutActionType.REMOVE: return removeChild(state, action); @@ -87,7 +89,7 @@ const switchTab = (state: ReactElement, { path, nextIdx }: SwitchTabAction) => { const setProp = ( state: ReactElement, - { path, propName, propValue }: SetPropAction + { path, propName, propValue }: SetPropAction, ) => { const target = followPath(state, path, true); const replacement = React.cloneElement(target, { @@ -102,7 +104,10 @@ const setProps = (state: ReactElement, { path, props }: SetPropsAction) => { return swapChild(state, target, replacement); }; -const setChildProps = (state: ReactElement, { path, type }: MaximizeAction) => { +const setChildProps = ( + state: ReactElement, + { path, type }: CollapseAction | ExpandAction, +) => { if (path) { const target = followPath(state, path, true); return swapChild(state, target, target, type); @@ -113,7 +118,7 @@ const setChildProps = (state: ReactElement, { path, type }: MaximizeAction) => { const dragDrop = ( layoutRoot: ReactElement, - action: DragDropAction + action: DragDropAction, ): ReactElement => { const { draggedReactElement: newComponent, @@ -131,33 +136,33 @@ const dragDrop = ( const [targetTab, insertionPosition] = getInsertTabBeforeAfter( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion existingComponent!, - pos + pos, ); if (targetTab === undefined) { newLayoutRoot = insertIntoContainer( layoutRoot, existingComponent, - newComponent + newComponent, ); } else { newLayoutRoot = insertBesideChild( layoutRoot, targetTab, newComponent, - insertionPosition + insertionPosition, ); } } else if (!intrinsicSize && pos?.position?.Centre) { newLayoutRoot = _replaceChild( layoutRoot, existingComponent as ReactElement, - newComponent + newComponent, ); } else { newLayoutRoot = dropLayoutIntoContainer( layoutRoot, dropTarget as DropTarget, - newComponent + newComponent, ); } @@ -167,7 +172,7 @@ const dragDrop = ( const finalTarget = findTarget( newLayoutRoot, - (props: LayoutProps) => props.id === id && props.version === version + (props: LayoutProps) => props.id === id && props.version === version, ) as ReactElement; const finalPath = getProp(finalTarget, "path"); return removeChild(newLayoutRoot, { path: finalPath, type: "remove" }); @@ -175,19 +180,19 @@ const dragDrop = ( const addChild = ( layoutRoot: ReactElement, - { path: containerPath, component }: AddAction + { path: containerPath, component }: AddAction, ) => { return insertIntoContainer( layoutRoot, followPath(layoutRoot, containerPath) as ReactElement, - component + component, ); }; const dropLayoutIntoContainer = ( layoutRoot: ReactElement, dropTarget: DropTarget, - newComponent: ReactElement + newComponent: ReactElement, ): ReactElement => { const { component, pos, clientRect, dropRect } = dropTarget; const existingComponent = component as ReactElement; @@ -199,13 +204,13 @@ const dropLayoutIntoContainer = ( layoutRoot, existingComponent as ReactElement, newComponent, - pos + pos, ); } const targetContainer = followPathToParent( layoutRoot, - existingComponentPath + existingComponentPath, ) as ReactElement; if (withTheGrain(pos, targetContainer)) { @@ -217,7 +222,7 @@ const dropLayoutIntoContainer = ( insertionPosition, pos, clientRect, - dropRect + dropRect, ); } @@ -228,7 +233,7 @@ const dropLayoutIntoContainer = ( newComponent, pos, clientRect, - dropRect + dropRect, ); } @@ -247,8 +252,8 @@ const withTheGrain = (pos: DropPos, container: ReactElement) => { return pos.position.NorthOrSouth ? isTower(container) : pos.position.EastOrWest - ? isTerrace(container) - : false; + ? isTerrace(container) + : false; }; const isTower = (container: ReactElement) => { diff --git a/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts b/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts index ed16b773e..4795f2188 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-reducer/layoutTypes.ts @@ -45,9 +45,14 @@ export type MaximizeAction = { type: typeof LayoutActionType.MAXIMIZE; }; -export type MinimizeAction = { +export type CollapseAction = { path?: string; - type: typeof LayoutActionType.MINIMIZE; + type: "collapse"; +}; + +export type ExpandAction = { + path?: string; + type: "expand"; }; export type MoveChildAction = { @@ -126,8 +131,8 @@ export type LayoutReducerAction = | AddAction | DragDropAction | LayoutResizeAction - | MaximizeAction - | MinimizeAction + | CollapseAction + | ExpandAction | MoveChildAction | RemoveAction | ReplaceAction @@ -176,11 +181,11 @@ export type LayoutChangeReason = LayoutLevelChange | ApplicationLevelChange; export type LayoutChangeHandler = ( layout: LayoutJSON, - layoutChangeReason: LayoutChangeReason + layoutChangeReason: LayoutChangeReason, ) => void; export const isApplicationLevelChange = ( - layoutChangeReason: LayoutChangeReason + layoutChangeReason: LayoutChangeReason, ): layoutChangeReason is ApplicationLevelChange => [ "switch-active-layout", @@ -190,7 +195,7 @@ export const isApplicationLevelChange = ( ].includes(layoutChangeReason); export const isLayoutLevelChange = ( - layoutChangeReason: LayoutChangeReason + layoutChangeReason: LayoutChangeReason, ): layoutChangeReason is LayoutLevelChange => [ "switch-active-tab", diff --git a/vuu-ui/packages/vuu-layout/src/layout-reducer/replace-layout-element.ts b/vuu-ui/packages/vuu-layout/src/layout-reducer/replace-layout-element.ts index 0c04360e9..bcacf9a7e 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-reducer/replace-layout-element.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-reducer/replace-layout-element.ts @@ -1,32 +1,33 @@ -import React, { ReactElement } from 'react'; -import { Action } from '../layout-action'; -import { getProp, getProps, nextStep } from '../utils'; -import { ReplaceAction } from './layoutTypes'; -import { applyLayoutProps, LayoutProps } from './layoutUtils'; +import React, { ReactElement } from "react"; +import { getProp, getProps, nextStep } from "../utils"; +import { ReplaceAction } from "./layoutTypes"; +import { applyLayoutProps, LayoutProps } from "./layoutUtils"; -export function replaceChild(model: ReactElement, { target, replacement }: ReplaceAction) { +export function replaceChild( + model: ReactElement, + { target, replacement }: ReplaceAction, +) { return _replaceChild(model, target, replacement); } export function _replaceChild( model: ReactElement, child: ReactElement, - replacement: ReactElement + replacement: ReactElement, ) { - const path = getProp(child, 'path'); - const resizeable = getProp(child, 'resizeable'); + const path = getProp(child, "path"); + const resizeable = getProp(child, "resizeable"); const { style } = getProps(child); - const newChild = - applyLayoutProps( - React.cloneElement(replacement, { - resizeable, - style: { - ...style, - ...replacement.props.style - } - }), - path - ); + const newChild = applyLayoutProps( + React.cloneElement(replacement, { + resizeable, + style: { + ...style, + ...replacement.props.style, + }, + }), + path, + ); return swapChild(model, child, newChild); } @@ -35,22 +36,25 @@ export function swapChild( model: ReactElement, child: ReactElement, replacement: ReactElement, - op?: 'maximize' | 'minimize' | 'restore' + op?: "collapse" | "expand", ): ReactElement { if (model === child) { return replacement; } - - const { idx, finalStep } = nextStep(getProp(model, 'path'), getProp(child, 'path')); + + const { idx, finalStep } = nextStep( + getProp(model, "path"), + getProp(child, "path"), + ); const children = model.props.children.slice(); - + if (finalStep) { if (!op) { children[idx] = replacement; - } else if (op === Action.MINIMIZE) { - children[idx] = minimize(model, children[idx]); - } else if (op === Action.RESTORE) { - children[idx] = restore(children[idx]); + } else if (op === "collapse") { + children[idx] = collapse(model, children[idx]); + } else if (op === "expand") { + children[idx] = expand(children[idx]); } } else { children[idx] = swapChild(children[idx], child, replacement, op); @@ -58,56 +62,57 @@ export function swapChild( return React.cloneElement(model, undefined, children); } -function minimize(parent: ReactElement, child: ReactElement) { +function collapse(parent: ReactElement, child: ReactElement) { const { style: parentStyle } = getProps(parent); const { style: childStyle } = getProps(child); - const { width, height, flexBasis, flexShrink, flexGrow, ...rest } = childStyle; + const { width, height, flexBasis, flexShrink, flexGrow, ...rest } = + childStyle; const restoreStyle = { width, height, flexBasis, flexShrink, - flexGrow + flexGrow, }; const style = { ...rest, flexBasis: 0, flexGrow: 0, - flexShrink: 0 + flexShrink: 0, }; const collapsed = - parentStyle.flexDirection === 'row' - ? 'vertical' - : parentStyle.flexDirection === 'column' - ? 'horizontal' - : false; + parentStyle.flexDirection === "row" + ? "vertical" + : parentStyle.flexDirection === "column" + ? "horizontal" + : false; if (collapsed) { return React.cloneElement(child, { collapsed, restoreStyle, - style + style, }); } return child; } -function restore(child: ReactElement) { +function expand(child: ReactElement) { const { style: childStyle, restoreStyle } = getProps(child); const { flexBasis, flexShrink, flexGrow, ...rest } = childStyle; const style = { ...rest, - ...restoreStyle + ...restoreStyle, }; return React.cloneElement(child, { collapsed: false, style, - restoreStyle: undefined + restoreStyle: undefined, }); } diff --git a/vuu-ui/packages/vuu-layout/src/layout-view-actions/useViewActionDispatcher.ts b/vuu-ui/packages/vuu-layout/src/layout-view-actions/useViewActionDispatcher.ts index c75ad3e48..5c46d243b 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view-actions/useViewActionDispatcher.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-view-actions/useViewActionDispatcher.ts @@ -22,13 +22,13 @@ export const useViewActionDispatcher = ( id: string, rootRef: RefObject, viewPath?: string, - dropTargets?: string[] + dropTargets?: string[], ): [ViewDispatch, Contribution[] | undefined] => { const { loadSessionState, purgeSessionState, purgeState, saveSessionState } = usePersistentState(); const [contributions, setContributions] = useState( - loadSessionState(id, "contributions") ?? [] + loadSessionState(id, "contributions") ?? [], ); const dispatchLayoutAction = useLayoutProviderDispatch(); const updateContributions = useCallback( @@ -39,7 +39,7 @@ export const useViewActionDispatcher = ( saveSessionState(id, "contributions", updatedContributions); setContributions(updatedContributions); }, - [contributions, id, saveSessionState] + [contributions, id, saveSessionState], ); const clearContributions = useCallback(() => { @@ -80,7 +80,7 @@ export const useViewActionDispatcher = ( } as DragStartAction); }); }, - [rootRef, dispatchLayoutAction, viewPath, dropTargets] + [rootRef, dispatchLayoutAction, viewPath, dropTargets], ); const handleMessageReceived = useCallback( @@ -99,25 +99,24 @@ export const useViewActionDispatcher = ( console.log(`received ${message.type} message`); } }, - [rootRef, unsubscribeAndClearState] + [rootRef, unsubscribeAndClearState], ); const sendMessage = useViewBroadcastChannel( id, viewPath, - handleMessageReceived + handleMessageReceived, ); const dispatchAction = useCallback( async ( action: A, - evt?: SyntheticEvent + evt?: SyntheticEvent, ): Promise => { const { type } = action; switch (type) { - case "maximize": - case "minimize": - case "restore": + case "collapse": + case "expand": return dispatchLayoutAction({ type, path: action.path ?? viewPath }); case "remove": return handleRemove(); @@ -150,7 +149,7 @@ export const useViewActionDispatcher = ( updateContributions, clearContributions, sendMessage, - ] + ], ); return [dispatchAction, contributions]; diff --git a/vuu-ui/packages/vuu-layout/src/layout-view/View.css b/vuu-ui/packages/vuu-layout/src/layout-view/View.css index f7cc08619..fb31a38d2 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view/View.css +++ b/vuu-ui/packages/vuu-layout/src/layout-view/View.css @@ -1,4 +1,5 @@ .vuuView { + --vuuToolbarProxy-height: var(--salt-size-base); border-color: var(--vuuView-borderColor, transparent); border-width: var(--vuuView-borderWidth, 1px); border-style: var(--vuuView-borderStyle, solid); @@ -11,6 +12,7 @@ outline: none; overflow: hidden; position: relative; + transition: flex-basis .3s ease-in-out; &.vuuHighlighted { --vuuView-borderStyle: dashed; @@ -18,6 +20,15 @@ } } +.vuuSplitterResizing .vuuView { + transition: none; + +} + +.vuuView:has(> .vuuHeader){ + min-height: var(--vuuToolbarProxy-height); +} + .vuuView.focus-visible:after { content: ""; position: absolute; @@ -50,9 +61,9 @@ flex-shrink: var(--vuuView-flex-shrink, 1); } -.vuuView-collapsed .vuuView-main { +/* .vuuView-collapsed .vuuView-main { display: none; -} +} */ .vuuView-collapsed + .Splitter { display: none; diff --git a/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx b/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx index 239138f73..9f2533268 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx +++ b/vuu-ui/packages/vuu-layout/src/layout-view/View.tsx @@ -59,12 +59,15 @@ const View = forwardRef(function View( path = dataPath, resize = "responsive", resizeable = dataResizeable, + restoreStyle, tearOut, style = {}, title: titleProp, ...restProps } = props; + console.log({ collapsed, restoreStyle }); + const targetWindow = useWindow(); useComponentCssInjection({ testId: "vuu-view", diff --git a/vuu-ui/packages/vuu-layout/src/layout-view/viewTypes.ts b/vuu-ui/packages/vuu-layout/src/layout-view/viewTypes.ts index bbf48d6df..07c021338 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-view/viewTypes.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-view/viewTypes.ts @@ -1,8 +1,14 @@ -import { FunctionComponent, HTMLAttributes, ReactElement } from "react"; +import { + CSSProperties, + FunctionComponent, + HTMLAttributes, + ReactElement, +} from "react"; import { HeaderProps } from "../layout-header"; import { MaximizeAction, - MinimizeAction, + CollapseAction, + ExpandAction, MousedownViewAction, QueryAction, RemoveAction, @@ -42,7 +48,8 @@ export type BroadcastMessageViewAction = { export type ViewAction = | BroadcastMessageViewAction | MaximizeAction - | MinimizeAction + | CollapseAction + | ExpandAction | MousedownViewAction | QueryAction | RemoveAction @@ -68,5 +75,6 @@ export interface ViewProps extends HTMLAttributes { path?: string; resize?: ResizeStrategy; resizeable?: boolean; + restoreStyle?: CSSProperties; tearOut?: boolean; } diff --git a/vuu-ui/packages/vuu-table/src/useTableModel.ts b/vuu-ui/packages/vuu-table/src/useTableModel.ts index 10c94614f..b1bebf779 100644 --- a/vuu-ui/packages/vuu-table/src/useTableModel.ts +++ b/vuu-ui/packages/vuu-table/src/useTableModel.ts @@ -309,8 +309,6 @@ function init( tableSchema, ); - console.log(`useTableModel availableWidth ${availableWidth}`); - const runtimeColumns: RuntimeColumnDescriptor[] = []; let colIndex = 1; for (const column of columns.filter( diff --git a/vuu-ui/showcase/src/examples/AppPatterns/ClientSourcedTableColumn/ClientSourcedTableColumn.examples.tsx b/vuu-ui/showcase/src/examples/AppPatterns/ClientSourcedTableColumn/ClientSourcedTableColumn.examples.tsx index 7148a3d46..14996b24e 100644 --- a/vuu-ui/showcase/src/examples/AppPatterns/ClientSourcedTableColumn/ClientSourcedTableColumn.examples.tsx +++ b/vuu-ui/showcase/src/examples/AppPatterns/ClientSourcedTableColumn/ClientSourcedTableColumn.examples.tsx @@ -18,7 +18,13 @@ import { useClientTableColumn, } from "./ClientTableColumnProvider/ClientTableColumnProvider"; import { TableSearch } from "@finos/vuu-ui-controls"; -import { Flexbox, View } from "@finos/vuu-layout"; +import { + FlexboxLayout, + Header, + LayoutContainer, + LayoutProvider, + View, +} from "@finos/vuu-layout"; registerComponent("pin-button", PinButtonCell, "cell-renderer", { userCanAssign: false, @@ -177,7 +183,10 @@ export const SearchWithPin = () => { }; SearchWithPin.displaySequence = displaySequence++; -const EmptyDisplay = () => { +const EmptyRecent = () => { + return
No recently viewed items
; +}; +const EmptyPinned = () => { return (
No Instruments have been pinned. Use the pin icon in the search list below @@ -194,7 +203,7 @@ const RecentlyUsedItemsTable = ({ schema }: { schema: TableSchema }) => { return ( { return ( { return ( - - - - - - - - + - - - + + + + + + + + + + + ); }; SearchAndPinned.displaySequence = displaySequence++; + +export const SearchAndPinnedWithAdditionalContent = () => { + const schema = getSchema("instruments"); + + return ( + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + + ); +}; +SearchAndPinnedWithAdditionalContent.displaySequence = displaySequence++; diff --git a/vuu-ui/showcase/src/examples/Layout/Flexbox.examples.tsx b/vuu-ui/showcase/src/examples/Layout/Flexbox.examples.tsx index a921c9cf1..a2bdec306 100644 --- a/vuu-ui/showcase/src/examples/Layout/Flexbox.examples.tsx +++ b/vuu-ui/showcase/src/examples/Layout/Flexbox.examples.tsx @@ -3,10 +3,13 @@ import { // ConfigWrapper, Flexbox, FlexboxLayout, + LayoutProvider, Stack, View, } from "@finos/vuu-layout"; import { Brown } from "./components"; +import { SplitterMoveHandler } from "@finos/vuu-layout/src/flexbox/flexboxTypes"; +import { useCallback } from "react"; let displaySequence = 1; @@ -98,6 +101,60 @@ export const SimpleTower = () => { SimpleTower.displaySequence = displaySequence++; +export const TowerWithCollapsibleViews = () => { + const handleSplitterMoved = useCallback( + (contentMeta) => { + console.log(`splitter moved ${JSON.stringify(contentMeta)}`); + }, + [], + ); + + return ( + + + + + + + + + + + + + + ); +}; + +TowerWithCollapsibleViews.displaySequence = displaySequence++; + export const ThreeChildTower = () => { const handleSplitterMoved = (sizes: any) => { console.log(`splitter moved ${JSON.stringify(sizes)}`);