diff options
author | bobzel <zzzman@gmail.com> | 2025-01-28 12:02:37 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2025-01-28 12:02:37 -0500 |
commit | 519a28c4ef5b5a70d29377c9baed50b455459ebd (patch) | |
tree | d637caf13fa0dc9b167b9ec45715915202a92bf5 /packages/components/src | |
parent | a78901127cd8af401146df47595442c4d8a696f2 (diff) |
card view cleanup. moved 'pile' into shiftclick on Perspective dropdown. fixed tags sorting.
Diffstat (limited to 'packages/components/src')
3 files changed, 280 insertions, 378 deletions
diff --git a/packages/components/src/components/Dropdown/Dropdown.tsx b/packages/components/src/components/Dropdown/Dropdown.tsx index d9fec5e9d..0953f412c 100644 --- a/packages/components/src/components/Dropdown/Dropdown.tsx +++ b/packages/components/src/components/Dropdown/Dropdown.tsx @@ -1,31 +1,32 @@ -import React, { useEffect, useState } from 'react' -import { FaCaretDown, FaCaretLeft, FaCaretRight, FaCaretUp } from 'react-icons/fa' -import { Popup, PopupTrigger } from '..' -import { Colors, IGlobalProps, Placement, Type, getFontSize, getHeight, isDark , getFormLabelSize } from '../../global' -import { IconButton } from '../IconButton' -import { ListBox } from '../ListBox' -import { IListItemProps, ListItem } from '../ListItem' -import './Dropdown.scss' -import { Tooltip } from '@mui/material' +import React, { useState } from 'react'; +import { FaCaretDown, FaCaretLeft, FaCaretRight, FaCaretUp } from 'react-icons/fa'; +import { Popup, PopupTrigger } from '..'; +import { Colors, IGlobalProps, Placement, Type, getFontSize, getHeight, isDark, getFormLabelSize } from '../../global'; +import { IconButton } from '../IconButton'; +import { ListBox } from '../ListBox'; +import { IListItemProps, ListItem } from '../ListItem'; +import './Dropdown.scss'; +import { Tooltip } from '@mui/material'; export enum DropdownType { - SELECT = "select", - CLICK = "click" + SELECT = 'select', + CLICK = 'click', } export interface IDropdownProps extends IGlobalProps { - items: IListItemProps[] - placement?: Placement - dropdownType: DropdownType - title?: string - closeOnSelect?: boolean; - iconProvider?: (active:boolean, placement?:Placement) => JSX.Element, - selectedVal?: string, - setSelectedVal?: (val: string | number) => unknown, - maxItems?: number, - uppercase?: boolean, - activeChanged?: (isOpen:boolean) => void, - onItemDown?: (e:React.PointerEvent, val:number | string) => boolean, // returns whether to select item + items: IListItemProps[]; + placement?: Placement; + dropdownType: DropdownType; + title?: string; + toolTip?: string; + closeOnSelect?: boolean; + iconProvider?: (active: boolean, placement?: Placement) => JSX.Element; + selectedVal?: string; + setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown; + maxItems?: number; + uppercase?: boolean; + activeChanged?: (isOpen: boolean) => void; + onItemDown?: (e: React.PointerEvent, val: number | string) => boolean; // returns whether to select item } /** @@ -37,189 +38,159 @@ export interface IDropdownProps extends IGlobalProps { * Look at: import Select from "react-select"; */ export const Dropdown = (props: IDropdownProps) => { - const { - size, - height, - maxItems, - items, - dropdownType, - selectedVal, - setSelectedVal, - iconProvider, - placement = 'bottom-start', - tooltip, - tooltipPlacement = 'top', - inactive, - color = Colors.MEDIUM_BLUE, - background, - closeOnSelect, - title = "Dropdown", - type, - width, - formLabel, - formLabelPlacement, - fillWidth = true, - onItemDown, - uppercase - } = props + const { + size, + height, + maxItems, + items, + dropdownType, + selectedVal, + toolTip, + setSelectedVal, + iconProvider, + placement = 'bottom-start', + tooltip, + tooltipPlacement = 'top', + inactive, + color = Colors.MEDIUM_BLUE, + background, + closeOnSelect, + title = 'Dropdown', + type, + width, + formLabel, + formLabelPlacement, + fillWidth = true, + onItemDown, + uppercase, + } = props; - const [active, setActive] = useState<boolean>(false) - const itemsMap = new Map(); - items.forEach((item) => { - itemsMap.set(item.val, item) - }) + const [active, setActive] = useState<boolean>(false); + const itemsMap = new Map(); + items.forEach(item => { + itemsMap.set(item.val, item); + }); - const getBorderColor = (): Colors | string | undefined => { - switch(type){ - case Type.PRIM: - return undefined; - case Type.SEC: - return color; - case Type.TERT: - if (active) return color; - else return color; - } - } + const getBorderColor = (): Colors | string | undefined => { + switch (type) { + case Type.PRIM: + return undefined; + case Type.SEC: + return color; + case Type.TERT: + if (active) return color; + else return color; + } + }; - const defaultProperties: React.CSSProperties = { - height: getHeight(height, size), - width: fillWidth ? '100%' : width, - fontWeight: 500, - fontSize: getFontSize(size), - fontFamily: 'sans-serif', - textTransform: uppercase ? 'uppercase' : undefined, - borderColor: getBorderColor(), - background, - color: color && background? color : type == (Type.TERT) ? isDark(color) ? Colors.WHITE : Colors.BLACK : color - } + const defaultProperties: React.CSSProperties = { + height: getHeight(height, size), + width: fillWidth ? '100%' : width, + fontWeight: 500, + fontSize: getFontSize(size), + fontFamily: 'sans-serif', + textTransform: uppercase ? 'uppercase' : undefined, + borderColor: getBorderColor(), + background, + color: color && background ? color : type == Type.TERT ? (isDark(color) ? Colors.WHITE : Colors.BLACK) : color, + }; - const backgroundProperties: React.CSSProperties = { - background: background ?? color - } + const backgroundProperties: React.CSSProperties = { + background: background ?? color, + }; - const getCaretDirection = (active: boolean, placement:Placement = 'left'): JSX.Element => { - if (iconProvider) return iconProvider(active, placement); - switch (placement) { - case 'bottom': - if (active) return <FaCaretUp/> - return <FaCaretDown/> - case 'right': - if (active) return <FaCaretLeft/> - return <FaCaretRight/> - case 'top': - if (active) return <FaCaretDown/> - return <FaCaretUp/> - default: - if (active) return <FaCaretUp/> - return <FaCaretDown/> - } - } + const getCaretDirection = (active: boolean, placement: Placement = 'left'): JSX.Element => { + if (iconProvider) return iconProvider(active, placement); + switch (placement) { + case 'bottom': + if (active) return <FaCaretUp />; + return <FaCaretDown />; + case 'right': + if (active) return <FaCaretLeft />; + return <FaCaretRight />; + case 'top': + if (active) return <FaCaretDown />; + return <FaCaretUp />; + default: + if (active) return <FaCaretUp />; + return <FaCaretDown />; + } + }; - const getToggle = () => { - switch (dropdownType) { - case DropdownType.SELECT: - return ( - <div - className={`dropdown-toggle${!selectedVal?"-mini":""} ${type} ${inactive && 'inactive'}`} - style={{...defaultProperties, height: getHeight(height, size), width: width }} - > - {selectedVal && ( - <ListItem - size={size} - {...itemsMap.get(selectedVal)} - style={{ color: defaultProperties.color, background: defaultProperties.background}} - inactive - /> - )} - <div className="toggle-caret"> - <IconButton + const getToggle = () => { + switch (dropdownType) { + case DropdownType.SELECT: + return ( + <div className={`dropdown-toggle${!selectedVal ? '-mini' : ''} ${type} ${inactive && 'inactive'}`} style={{ ...defaultProperties, height: getHeight(height, size), width: width }}> + {selectedVal && <ListItem size={size} {...itemsMap.get(selectedVal)} style={{ color: defaultProperties.color, background: defaultProperties.background }} inactive />} + <div className="toggle-caret"> + <IconButton size={size} icon={getCaretDirection(active, placement)} color={defaultProperties.color} inactive /> + </div> + <div className={`background ${active && 'active'}`} style={{ ...backgroundProperties }} /> + </div> + ); + case DropdownType.CLICK: + default: + return ( + <div className={`dropdown-toggle${!selectedVal ? '-mini' : ''} ${type} ${inactive && 'inactive'}`} style={{ ...defaultProperties, height: getHeight(height, size), width: width }}> + <ListItem val="title" text={title} size={size} style={{ color: defaultProperties.color, background: defaultProperties.backdropFilter }} inactive /> + <div className="toggle-caret"> + <IconButton size={size} icon={getCaretDirection(active, placement)} color={defaultProperties.color} inactive /> + </div> + <div className={`background ${active && 'active'}`} style={{ ...backgroundProperties }} /> + </div> + ); + } + }; + + const setActiveChanged = (active: boolean) => { + setActive(active); + props.activeChanged?.(active); + }; + + const dropdown: JSX.Element = ( + <div className="dropdown-container"> + <Popup + toggle={ + <Tooltip disableInteractive={true} arrow={true} placement={tooltipPlacement} title={toolTip || (itemsMap.get(selectedVal)?.text ?? title)}> + {getToggle()} + </Tooltip> + } + placement={placement} + tooltip={tooltip} + tooltipPlacement={tooltipPlacement} + trigger={PopupTrigger.CLICK} + isOpen={active} + setOpen={setActiveChanged} size={size} - icon={getCaretDirection(active,placement)} - color={defaultProperties.color} - inactive - /> - </div> - <div className={`background ${active && 'active'}`} style={{...backgroundProperties}}/> - </div> - ) - case DropdownType.CLICK: - default: - return ( - <div - className={`dropdown-toggle${!selectedVal?"-mini":""} ${type} ${inactive && 'inactive'}`} - style={{...defaultProperties, height: getHeight(height, size), width: width }} - > - <ListItem val='title' - text={title} - size={size} - style={{ color: defaultProperties.color, background: defaultProperties.backdropFilter}} - inactive + fillWidth={true} + color={color} + popup={ + <ListBox + maxItems={maxItems} + items={items} + color={color} + onItemDown={onItemDown} + selectedVal={selectedVal} + setSelectedVal={(val, e) => { + setSelectedVal?.(val, e); + closeOnSelect && setActive(false); + }} + size={size} + /> + } /> - <div className="toggle-caret"> - <IconButton - size={size} - icon={getCaretDirection(active,placement)} - color={defaultProperties.color} - inactive - /> - </div> - <div className={`background ${active && 'active'}`} style={{...backgroundProperties}}/> - </div> - ) - } - } - - const setActiveChanged = (active:boolean) => { - setActive(active); - props.activeChanged?.(active); - } - - const dropdown: JSX.Element = - ( - <div - className="dropdown-container" - > - <Popup - toggle={ - <Tooltip disableInteractive={true} arrow={true} placement={tooltipPlacement} title={itemsMap.get(selectedVal) ? itemsMap.get(selectedVal).text : title}> - {getToggle()} - </Tooltip> - } - placement={placement} - tooltip={tooltip} - tooltipPlacement={tooltipPlacement} - trigger={PopupTrigger.CLICK} - isOpen={active} - setOpen={setActiveChanged} - size={size} - fillWidth={true} - color={color} - popup={ - <ListBox - maxItems={maxItems} - items={items} - color={color} - onItemDown={onItemDown} - selectedVal={selectedVal} - setSelectedVal={val => { - setSelectedVal?.(val); - closeOnSelect && setActive(false); - }} - size={size} - /> - } - /> - </div> - ) + </div> + ); - return ( - formLabel ? - <div className={`form-wrapper ${formLabelPlacement}`} -style={{ width: fillWidth ? '100%' : undefined}}> - <div className={'formLabel'} style={{fontSize: getFormLabelSize(size)}}>{formLabel}</div> - {dropdown} - </div> - : - dropdown - ) -} + return formLabel ? ( + <div className={`form-wrapper ${formLabelPlacement}`} style={{ width: fillWidth ? '100%' : undefined }}> + <div className={'formLabel'} style={{ fontSize: getFormLabelSize(size) }}> + {formLabel} + </div> + {dropdown} + </div> + ) : ( + dropdown + ); +}; diff --git a/packages/components/src/components/ListBox/ListBox.tsx b/packages/components/src/components/ListBox/ListBox.tsx index abdfd38f3..aa5eb6b44 100644 --- a/packages/components/src/components/ListBox/ListBox.tsx +++ b/packages/components/src/components/ListBox/ListBox.tsx @@ -1,15 +1,15 @@ -import React, { ReactText } from 'react' -import { IListItemProps, ListItem } from '../ListItem' -import './ListBox.scss' -import { Colors, IGlobalProps, isDark , getFormLabelSize } from '../../global' +import React from 'react'; +import { IListItemProps, ListItem } from '../ListItem'; +import './ListBox.scss'; +import { Colors, IGlobalProps } from '../../global'; export interface IListBoxProps extends IGlobalProps { - items: IListItemProps[] - filter?: string - selectedVal?: string | number - setSelectedVal?: (val: string | number) => unknown - maxItems?: number - onItemDown?: (e:React.PointerEvent, val:number|string) => void + items: IListItemProps[]; + filter?: string; + selectedVal?: string | number; + setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown; + maxItems?: number; + onItemDown?: (e: React.PointerEvent, val: number | string) => void; } /** @@ -21,56 +21,24 @@ export interface IListBoxProps extends IGlobalProps { * Look at: import Select from "react-select"; */ export const ListBox = (props: IListBoxProps) => { - const { - items, - selectedVal, - setSelectedVal, - filter, - onItemDown, - color = Colors.MEDIUM_BLUE - } = props + const { items, selectedVal, setSelectedVal, filter, onItemDown, color = Colors.MEDIUM_BLUE } = props; - const getListItem = ( - item: IListItemProps, - ind: number, - selected: boolean - ): JSX.Element => { + const getListItem = (item: IListItemProps, ind: number, selected: boolean): JSX.Element => { + return <ListItem key={ind} ind={ind} onItemDown={onItemDown} selected={selected} color={color} setSelectedVal={setSelectedVal} onClick={item.onClick} {...item} />; + }; + const itemElements: JSX.Element[] = []; + items.forEach((item, ind) => { + if (filter) { + if (filter.toLowerCase() === item.text?.substring(0, filter.length).toLowerCase()) { + itemElements.push(getListItem(item, ind, item.val === selectedVal)); + } + } else { + itemElements.push(getListItem(item, ind, item.val === selectedVal)); + } + }); return ( - <ListItem - key={ind} - ind={ind} - onItemDown={onItemDown} - selected={selected} - color={color} - setSelectedVal={setSelectedVal} - onClick={item.onClick} - {...item} - /> - ) - } - let itemElements: JSX.Element[] = [] - items.forEach((item, ind) => { - if (filter) { - if ( - filter.toLowerCase() === - item.text?.substring(0, filter.length).toLowerCase() - ) { - itemElements.push( - getListItem(item, ind, item.val === selectedVal) - ) - } - } else { - itemElements.push( - getListItem(item, ind, item.val === selectedVal) - ) - } - }) - return ( - <div - className="listBox-container" - style={{ color: color }} - > - {itemElements} - </div> - ) -} + <div className="listBox-container" style={{ color: color }}> + {itemElements} + </div> + ); +}; diff --git a/packages/components/src/components/ListItem/ListItem.tsx b/packages/components/src/components/ListItem/ListItem.tsx index d76c84b3e..e04c6fbee 100644 --- a/packages/components/src/components/ListItem/ListItem.tsx +++ b/packages/components/src/components/ListItem/ListItem.tsx @@ -1,25 +1,25 @@ -import React, { useState } from 'react' -import * as fa from 'react-icons/fa' -import { getFontSize, IGlobalProps, Type , getFormLabelSize, getHeight } from '../../global' -import { Size } from '../../global/globalEnums' -import { IconButton } from '../IconButton' -import { ListBox } from '../ListBox' -import { Popup, PopupTrigger } from '../Popup' -import './ListItem.scss' +import React, { useState } from 'react'; +import * as fa from 'react-icons/fa'; +import { getFontSize, IGlobalProps, Type, getHeight } from '../../global'; +import { Size } from '../../global/globalEnums'; +import { IconButton } from '../IconButton'; +import { ListBox } from '../ListBox'; +import { Popup, PopupTrigger } from '../Popup'; +import './ListItem.scss'; export interface IListItemProps extends IGlobalProps { - ind?: number - text?: string - val: string | number - icon?: JSX.Element - description?: string - shortcut?: string - items?: IListItemProps[] - selected?: boolean - setSelectedVal?: (val: string | number) => unknown - onClick?: () => void - onItemDown?: (e:React.PointerEvent, val:string| number) => void - uppercase?: boolean + ind?: number; + text?: string; + val: string | number; + icon?: JSX.Element; + description?: string; + shortcut?: string; + items?: IListItemProps[]; + selected?: boolean; + setSelectedVal?: (val: string | number, e?: React.MouseEvent) => unknown; + onClick?: () => void; + onItemDown?: (e: React.PointerEvent, val: string | number) => void; + uppercase?: boolean; } /** @@ -31,104 +31,67 @@ export interface IListItemProps extends IGlobalProps { * Look at: import Select from "react-select"; */ export const ListItem = (props: IListItemProps) => { - const { - ind, - val, - description, - text, - shortcut, - items, - icon, - selected, - setSelectedVal, - onClick, - onItemDown, - inactive, - size = Size.SMALL, - style, - color, - background, - uppercase - } = props + const { val, description, text, shortcut, items, icon, selected, setSelectedVal, onClick, onItemDown, inactive, size = Size.SMALL, style, color, background, uppercase } = props; - const [isHovered, setIsHovered] = useState<boolean>(false); + const [isHovered, setIsHovered] = useState<boolean>(false); - let listItem:JSX.Element = ( - <div - tabIndex={-1} - className="listItem-container" - onPointerDown={(e) => onItemDown?.(e, val) && setSelectedVal?.(val)} - onClick={(e: React.MouseEvent) => { - if (!items) { - !inactive && onClick?.() - !inactive && onClick && e.stopPropagation() - setSelectedVal?.(val) - } - }} - style={{ - minHeight: getHeight(undefined, size), - userSelect: 'none', - ...style - }} - onPointerEnter={() => { - setIsHovered(true) - }} - onPointerLeave={() => { - setIsHovered(false) - }} - > - <div className="listItem-top"> - <div className="content" - style={{ - fontSize: getFontSize(size), - color: style?.color ? style.color : color - }}> - {icon} - <div className="text" style={{ - textTransform: uppercase ? 'uppercase' : undefined - }}>{text}</div> + const listItem: JSX.Element = ( + <div + tabIndex={-1} + className="listItem-container" + onPointerDown={e => onItemDown?.(e, val) && setSelectedVal?.(val, e)} + onClick={(e: React.MouseEvent) => { + if (!items) { + !inactive && onClick?.(); + !inactive && onClick && e.stopPropagation(); + setSelectedVal?.(val, e); + } + }} + style={{ + minHeight: getHeight(undefined, size), + userSelect: 'none', + ...style, + }} + onPointerEnter={() => { + setIsHovered(true); + }} + onPointerLeave={() => { + setIsHovered(false); + }}> + <div className="listItem-top"> + <div + className="content" + style={{ + fontSize: getFontSize(size), + color: style?.color ? style.color : color, + }}> + {icon} + <div + className="text" + style={{ + textTransform: uppercase ? 'uppercase' : undefined, + }}> + {text} + </div> + </div> + {shortcut && !inactive && ( + <div className="shortcut" color={style?.color ? style.color : color}> + {shortcut} + </div> + )} + {items && !inactive && <IconButton type={Type.PRIM} size={Size.SMALL} icon={<fa.FaCaretRight />} color={style?.color ? style.color : color} background={background} inactive />} + </div> + {description && !inactive && <div className="listItem-description">{description}</div>} + <div + className="listItem-background" + style={{ + background: background ? background : style?.color ? style.color : color, + filter: selected ? 'opacity(0.3)' : isHovered && !inactive ? 'opacity(0.2)' : 'opacity(0)', + }} + /> </div> - {shortcut && !inactive && ( - <div - className="shortcut" - color={style?.color ? style.color : color} - > - {shortcut} - </div> - )} - {items && !inactive && ( - <IconButton - type={Type.PRIM} - size={Size.SMALL} - icon={<fa.FaCaretRight/>} - color={style?.color ? style.color : color} - background={background} - inactive - /> - )} - </div> - {description && !inactive && ( - <div className="listItem-description">{description}</div> - )} - <div className="listItem-background" - style={{ - background: background ? background : style?.color ? style.color : color, - filter: selected ? 'opacity(0.3)' : isHovered && !inactive ? 'opacity(0.2)' : 'opacity(0)' - }} - /> - </div> -) + ); - if (items && !inactive) return <Popup - placement={'right'} - toggle={listItem} - color={color} - background={background} - trigger={PopupTrigger.CLICK} - popup={ - <ListBox color={color} background={background} items={items}/> - } - fillWidth={true} - /> - else return <>{listItem}</> -} + if (items && !inactive) return <Popup placement={'right'} toggle={listItem} color={color} background={background} trigger={PopupTrigger.CLICK} popup={<ListBox color={color} background={background} items={items} />} fillWidth={true} />; + else return <>{listItem}</>; +}; |