aboutsummaryrefslogtreecommitdiff
path: root/packages/components/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-01-28 12:02:37 -0500
committerbobzel <zzzman@gmail.com>2025-01-28 12:02:37 -0500
commit519a28c4ef5b5a70d29377c9baed50b455459ebd (patch)
treed637caf13fa0dc9b167b9ec45715915202a92bf5 /packages/components/src
parenta78901127cd8af401146df47595442c4d8a696f2 (diff)
card view cleanup. moved 'pile' into shiftclick on Perspective dropdown. fixed tags sorting.
Diffstat (limited to 'packages/components/src')
-rw-r--r--packages/components/src/components/Dropdown/Dropdown.tsx371
-rw-r--r--packages/components/src/components/ListBox/ListBox.tsx90
-rw-r--r--packages/components/src/components/ListItem/ListItem.tsx197
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}</>;
+};