diff --git a/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx b/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx new file mode 100644 index 0000000000..16e87944e5 --- /dev/null +++ b/libs/renderer/src/components/block-defaults/chip-block/ChipBlock.tsx @@ -0,0 +1,121 @@ +//React and Third Party Libraries +import React from "react"; +import { observer } from "mobx-react-lite"; +import { CSSProperties } from "react"; +import { Face } from "@mui/icons-material"; +import { Chip, styled } from "@mui/material"; + +//Internal Semoss libs +import { Avatar } from "@semoss/ui"; + +//Modules internal to current package +import { useBlock } from "../../../hooks"; +import { BlockDef, BlockComponent } from "../../../store"; + +export interface ChipBlockDef extends BlockDef<"chip"> { + widget: "chip"; + data: { + type: string; + label: string; + style: CSSProperties; + variant: "filled" | "outlined"; + disabled?: boolean; + avatar?: React.ReactElement; + size: "small" | "medium"; + color: + | "default" + | "primary" + | "secondary" + | "success" + | "warning" + | "error"; + clickable?: boolean; + multiSelect?: boolean; + link?: string; + icon?: React.JSX.Element; + src: string; + title: string; + show: string; + }; + listeners: { + // onClick: true; + }; + slots: never; +} + +const StyledAvatar = styled(Avatar, { + shouldForwardProp: (prop) => prop !== "chipColor", +})<{ chipColor: string }>(({ chipColor, theme }) => { + const palette = theme.palette; + + return { + "&&": { + backgroundColor: palette[chipColor]?.main || palette.grey[500], + color: palette[chipColor]?.contrastText, + }, + }; +}); + +export const ChipBlock: BlockComponent = observer(({ id }) => { + const { attrs, data /*listeners*/ } = useBlock(id); + + const displayChip = (key): React.ReactNode => { + const avatar = data?.avatar; + const link = data?.link || null; + + const chipProps = { + label: data.label ?? data.type ?? "Chip", + color: data.color, + size: data.size, + variant: data.variant, + clickable: data.clickable, + }; + + switch (key) { + case "Chip": + return ; + case "Avatar": + return ( + + {avatar} + + } + /> + ); + case "Icon": + return } />; + case "Link": + return ( + + e.preventDefault()} + /> + + ); + default: + return ; + } + }; + + return ( +
{ + // listeners.onClick(); + // }} + > + {displayChip(data.type)} +
+ ); +}); diff --git a/libs/renderer/src/components/block-defaults/chip-block/config.tsx b/libs/renderer/src/components/block-defaults/chip-block/config.tsx new file mode 100644 index 0000000000..66cf0a5b82 --- /dev/null +++ b/libs/renderer/src/components/block-defaults/chip-block/config.tsx @@ -0,0 +1,183 @@ +//React and Third Party Modules +import { CSSProperties } from "react"; +import { LabelRounded } from "@mui/icons-material"; + +//Internal Semoss libs +import { Avatar } from "@semoss/ui"; + +//Modules internal to current package +import { BlockConfig } from "../../../store"; +import { InputSettings, SelectInputSettings } from "../../block-settings"; +import { SwitchSettings } from "../../block-settings/shared/SwitchSettings"; +import { ChipSettings } from "../../block-settings/custom/ChipSettings"; +import { buildListener, buildShowField } from "../block-defaults.shared"; +import { BLOCK_TYPE_DISPLAY } from "../block-defaults.constants"; +import { ChipBlockDef, ChipBlock } from "./ChipBlock"; + +export const DefaultStyles: CSSProperties = {}; + +export const config: BlockConfig = { + widget: "chip", + type: BLOCK_TYPE_DISPLAY, + data: { + style: DefaultStyles, + color: "default", + size: "small", + avatar: A, + type: "Chip", + variant: "filled", + label: "", + src: "", + title: "", + show: "true", + }, + listeners: { + //onClick: [], + }, + slots: {}, + render: ChipBlock, + icon: LabelRounded, + + contentMenu: [ + { + name: "General", + children: [...buildShowField()], + }, + { + name: "Select Chip", + children: [ + { + description: " Chip Type", + render: ({ id }) => ( + + ), + }, + { + description: "Label", + render: ({ id }) => ( + + ), + }, + { + description: "clickable", + render: ({ id }) => ( + + ), + }, + ], + }, + { + name: "on Click", + children: [...buildListener("onClick")], + }, + ], + styleMenu: [ + { + name: "", + children: [ + { + description: "Variant", + render: ({ id }) => ( + + ), + }, + { + description: "Color", + render: ({ id }) => ( + + ), + }, + { + description: "Size", + render: ({ id }) => ( + + ), + }, + ], + }, + ], +}; diff --git a/libs/renderer/src/components/block-defaults/chip-block/index.ts b/libs/renderer/src/components/block-defaults/chip-block/index.ts new file mode 100644 index 0000000000..7807e82085 --- /dev/null +++ b/libs/renderer/src/components/block-defaults/chip-block/index.ts @@ -0,0 +1,2 @@ +export * from "./config"; +export * from "./ChipBlock"; diff --git a/libs/renderer/src/components/block-defaults/index.ts b/libs/renderer/src/components/block-defaults/index.ts index 7b6f851d59..849ada5f1e 100644 --- a/libs/renderer/src/components/block-defaults/index.ts +++ b/libs/renderer/src/components/block-defaults/index.ts @@ -5,8 +5,6 @@ import { AccordionBlockDef, } from "./accordion-block"; -import { config as PopoverBlockConfig, PopoverBlockDef } from "./popover-block"; - import { config as AudioBlockConfig, AudioBlockDef } from "./audio-block"; import { config as AudioInputBlockConfig, @@ -19,6 +17,7 @@ import { config as CheckboxBlockConfig, CheckboxBlockDef, } from "./checkbox-block"; +import { config as ChipBlockConfig, ChipBlockDef } from "./chip-block"; import { config as ContainerBlockConfig, ContainerBlockDef, @@ -59,6 +58,7 @@ import { config as PDFViewerBlockConfig, PDFViewerBlockDef, } from "./pdfViewer-block"; +import { config as PopoverBlockConfig, PopoverBlockDef } from "./popover-block"; import { config as ProgressBlockConfig, ProgressBlockDef, @@ -104,6 +104,7 @@ export type DefaultBlockDefinitions = | AudioInputBlockDef | ButtonBlockDef | CheckboxBlockDef + | ChipBlockDef | ContainerBlockDef | DividerBlockDef | EchartVisualizationBlockDef @@ -152,6 +153,7 @@ export const DefaultBlocks: Registry = { [AudioInputBlockConfig.widget]: AudioInputBlockConfig, [ButtonBlockConfig.widget]: ButtonBlockConfig, [CheckboxBlockConfig.widget]: CheckboxBlockConfig, + [ChipBlockConfig.widget]: ChipBlockConfig, [ContainerBlockConfig.widget]: ContainerBlockConfig, [DividerBlockConfig.widget]: DividerBlockConfig, [EchartVisualizationBlockConfig.widget]: EchartVisualizationBlockConfig, @@ -193,6 +195,7 @@ export { AudioInputBlockConfig, ButtonBlockConfig, CheckboxBlockConfig, + ChipBlockConfig, ContainerBlockConfig, DividerBlockConfig, GridBlockConfig, diff --git a/libs/renderer/src/components/block-settings/custom/ChipSettings.tsx b/libs/renderer/src/components/block-settings/custom/ChipSettings.tsx new file mode 100644 index 0000000000..3da48dede7 --- /dev/null +++ b/libs/renderer/src/components/block-settings/custom/ChipSettings.tsx @@ -0,0 +1,198 @@ +//React and Third Party Libraries +import { useEffect, useMemo, useRef, useState } from "react"; +import { computed } from "mobx"; +import { observer } from "mobx-react-lite"; +import { Autocomplete, Chip, Stack, TextField } from "@mui/material"; +import { Face } from "@mui/icons-material"; + +//Internal Semoss libs +import { Avatar } from "@semoss/ui"; + +//Modules internal to current package +import { Paths, PathValue } from "../../../types"; +import { useBlocks, useBlockSettings } from "../../../hooks"; +import { ActionMessages, Block, BlockDef } from "../../../store"; +import { getValueByPath } from "../../../utility"; +import { BaseSettingSection } from "../BaseSettingSection"; + +interface ChipSettingsProps { + id: string; + path: Paths["data"], 4>; + label: string; + options?: Array<{ value: string; display: string }>; + resizeOnSet?: boolean; +} + +export const ChipSettings = observer( + ({ + id, + path, + label, + options, + resizeOnSet = false, + }: ChipSettingsProps) => { + const { data, setData } = useBlockSettings(id); + const { state } = useBlocks(); + + const [autocompleteOptions, setAutocompleteOptions] = useState< + Array + >([]); + + useEffect(() => { + setAutocompleteOptions(options.map((option) => option.value)); + }, [options]); + + // track the value + const [value, setValue] = useState(""); + + // track the ref to debounce the input + const timeoutRef = useRef>(null); + + // get the value of the input (wrapped in usememo because of path prop) + const computedValue = useMemo(() => { + return computed(() => { + if (!data) { + return ""; + } + + const v = getValueByPath(data, path); + if (typeof v === "undefined") { + return ""; + } else if (typeof v === "string") { + return v; + } + + return JSON.stringify(v); + }); + }, [data, path]).get(); + + // update the value whenever the computed one changes + useEffect(() => { + setValue(computedValue); + }, [computedValue]); + + /** + * Sync the data on change + */ + const onChange = (value: string) => { + // set the value + setValue(value); + + // clear out he old timeout + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + + timeoutRef.current = setTimeout(() => { + try { + // set the value + setData(path, value as PathValue); + if (resizeOnSet) { + // emit event to resize the block on the screen + state.dispatch({ + message: ActionMessages.DISPATCH_EVENT, + payload: { + name: "blockResized", + }, + }); + } + } catch (e) { + console.log(e); + } + }, 300); + }; + + const [ChipValue, setChipValue] = useState(""); + const [selectedChipType, setSelectedChipType] = useState(""); + + const handleChipChange = (chip, e) => { + setChipValue(e.target.value); + setData(chip.toLowerCase(), e.target.value); + }; + + return ( + + + + { + onChange(newValue); + setSelectedChipType(newValue); + }} + options={options.map((option) => option.value)} + renderOption={(props, option) => ( +
  • + + {(() => { + switch (option) { + case "Chip": + return ( + + ); + case "Icon": + return ( + } + /> + ); + case "Avatar": + return ( + + A + + } + /> + ); + case "Link": + return ( + + ); + default: + return ( + + ); + } + })()} + +
  • + )} + renderInput={(params) => } + disablePortal + disableClearable + /> + {selectedChipType && + (selectedChipType === "Avatar" || + selectedChipType === "Link") && ( + + handleChipChange(selectedChipType, e) + } + size="small" + variant="outlined" + autoComplete="off" + placeholder={`${selectedChipType} value`} + sx={{ mt: 1 }} + /> + )} +
    +
    +
    + ); + }, +); diff --git a/libs/renderer/src/components/block-settings/custom/QueryInputSettings.tsx b/libs/renderer/src/components/block-settings/custom/QueryInputSettings.tsx index faad137355..26265b158f 100644 --- a/libs/renderer/src/components/block-settings/custom/QueryInputSettings.tsx +++ b/libs/renderer/src/components/block-settings/custom/QueryInputSettings.tsx @@ -663,9 +663,10 @@ export const QueryInputSettings = observer( > {label} - + {/* Neel pointed this out 3/31 */} + {/* Open text view - + */} setOpen(true)} diff --git a/libs/renderer/src/components/block-settings/custom/index.ts b/libs/renderer/src/components/block-settings/custom/index.ts index db938043ff..53690ebb8d 100644 --- a/libs/renderer/src/components/block-settings/custom/index.ts +++ b/libs/renderer/src/components/block-settings/custom/index.ts @@ -12,3 +12,4 @@ export { GridSettings } from "./grid"; export { IconSelectSettings } from "./IconSelectSettings"; export { QueryInputSettings } from "./QueryInputSettings"; export { OptionsSettings } from "./OptionsSettings"; +export { ChipSettings } from "./ChipSettings"; diff --git a/libs/renderer/src/components/blocks/RendererEngine.tsx b/libs/renderer/src/components/blocks/RendererEngine.tsx index 2676074e63..43131d7416 100644 --- a/libs/renderer/src/components/blocks/RendererEngine.tsx +++ b/libs/renderer/src/components/blocks/RendererEngine.tsx @@ -105,12 +105,14 @@ export const RendererEngine = observer( ); } + if (showBlock(block, state)) { return createElement(b.render, { key: id, id: id, }); } + return createElement("div", { key: id, id: id, diff --git a/packages/client/src/assets/blocks/Chip_Active.png b/packages/client/src/assets/blocks/Chip_Active.png new file mode 100644 index 0000000000..a7ad5a7f4b Binary files /dev/null and b/packages/client/src/assets/blocks/Chip_Active.png differ diff --git a/packages/client/src/assets/blocks/Chip_Hover.png b/packages/client/src/assets/blocks/Chip_Hover.png new file mode 100644 index 0000000000..67310f3741 Binary files /dev/null and b/packages/client/src/assets/blocks/Chip_Hover.png differ diff --git a/packages/client/src/assets/blocks/index.ts b/packages/client/src/assets/blocks/index.ts index 66d0bd213b..63b584113e 100644 --- a/packages/client/src/assets/blocks/index.ts +++ b/packages/client/src/assets/blocks/index.ts @@ -10,6 +10,8 @@ export { default as BUTTON_ACTIVE } from './Button_Active.png'; export { default as BUTTON_HOVER } from './Button_Hover.png'; export { default as CHECKBOX_ACTIVE } from './Checkbox_Active.png'; export { default as CHECKBOX_HOVER } from './Checkbox_Hover.png'; +export { default as CHIP_ACTIVE } from './Chip_Active.png'; +export { default as CHIP_HOVER } from './Chip_Hover.png'; export { default as COMPARE_LLMS_ACTIVE } from './Compare_LLMS_Active.png'; export { default as COMPARE_LLMS_HOVER } from './Compare_LLMS_Hover.png'; export { default as CONTAINER_ACTIVE } from './Container_Active.png'; diff --git a/packages/client/src/components/blocks-workspace/menus/default-menu.ts b/packages/client/src/components/blocks-workspace/menus/default-menu.ts index f3b9d6b755..86e4a08ca9 100644 --- a/packages/client/src/components/blocks-workspace/menus/default-menu.ts +++ b/packages/client/src/components/blocks-workspace/menus/default-menu.ts @@ -1318,7 +1318,7 @@ export const DEFAULT_MENU: DesignerMenuItem[] = [ }, }, { - section: SECTION_PROGRESS, + section: SECTION_ELEMENT, name: 'Progress', helperText: 'Display progress tracking or status', activeImage: BLOCK_IMAGES['PROGRESS_ACTIVE'], @@ -1448,6 +1448,29 @@ export const DEFAULT_MENU: DesignerMenuItem[] = [ slots: {} as BlockJSON['slots'], }, }, + { + section: SECTION_ELEMENT, + activeImage: BLOCK_IMAGES['CHIP_ACTIVE'], + hoverImage: BLOCK_IMAGES['CHIP_HOVER'], + name: 'Chip', + json: { + widget: 'chip', + data: { + style: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + height: '200px', + }, + src: '', + title: '', + show: 'true', + }, + listeners: {}, + slots: {} as BlockJSON['slots'], + }, + }, { section: SECTION_INPUT, name: 'Toggle Button',