feat: Refactor DataSourceSelector to use structured options and implement RegularDropDownID for improved dropdown functionality
This commit is contained in:
@@ -359,7 +359,13 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
||||
<div className="design-section">
|
||||
<DataSourceSelector
|
||||
label={"Chart Type"}
|
||||
options={["Line Chart", "Bar Chart", "Pie Chart", "Area Chart", "Radar Chart"]}
|
||||
options={[
|
||||
{ id: "line", label: "Line Chart" },
|
||||
{ id: "bar", label: "Bar Chart" },
|
||||
{ id: "pie", label: "Pie Chart" },
|
||||
{ id: "area", label: "Area Chart" },
|
||||
{ id: "radar", label: "Radar Chart" },
|
||||
]}
|
||||
onSelect={(newValue) => {
|
||||
if (newValue === "Line Chart") {
|
||||
updateGraphType(selectedBlock, selectedElement, "line");
|
||||
@@ -568,7 +574,7 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
||||
<div className="data-details">
|
||||
{element?.type === "label-value" && (
|
||||
<div className="data-wrapper">
|
||||
<InputWithDropDown label="Title" value={`title`} placeholder={"Label 1"} min={0.1} step={0.1} max={2} onChange={() => {}} />
|
||||
<InputWithDropDown label="Title" value={`title`} placeholder={"Label 1"} min={0.1} step={0.1} max={2} onChange={() => { }} />
|
||||
<div className="data">
|
||||
<DataDetailedDropdown
|
||||
title="Data Source"
|
||||
@@ -628,7 +634,14 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
||||
{selectDataMapping === "singleMachine" && (
|
||||
<div className="fields-wrapper">
|
||||
{singleFields.map((field) => (
|
||||
<DataSourceSelector key={field.id} label={field.label} options={["1h", "2h", "12h"]} onSelect={() => {}} showEyeDropper={!!field.showEyeDropper} />
|
||||
<DataSourceSelector
|
||||
key={field.id}
|
||||
label={field.label}
|
||||
options={[
|
||||
{ id: "global", label: "Global" }
|
||||
]}
|
||||
onSelect={() => { }} showEyeDropper={!!field.showEyeDropper}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div className="add-field" onClick={addField}>
|
||||
@@ -645,7 +658,14 @@ const ElementEditor: React.FC<ElementEditorProps> = ({
|
||||
{multipleFields.map((field) => (
|
||||
<div className="datas" key={field.id}>
|
||||
<div className="datas__class">
|
||||
<DataSourceSelector label={field.label} options={["1h", "2h", "12h"]} onSelect={() => {}} showEyeDropper={field.label !== "Common Value"} />
|
||||
<DataSourceSelector
|
||||
label={field.label}
|
||||
options={[
|
||||
{ id: "global", label: "Global" }
|
||||
]}
|
||||
onSelect={() => { }}
|
||||
showEyeDropper={field.label !== "Common Value"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -188,7 +188,7 @@ function MainScene() {
|
||||
{!selectedUser && (
|
||||
<>
|
||||
<KeyPressListener />
|
||||
{!createNewWindow && loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||
{/* {!createNewWindow && loadingProgress > 0 && <LoadingPage progress={loadingProgress} />} */}
|
||||
{!isPlaying && (
|
||||
<>
|
||||
{!toggleView && !isComparing && <ModuleToggle />}
|
||||
@@ -254,7 +254,7 @@ function MainScene() {
|
||||
}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
>
|
||||
<Scene layout="Main Layout" />
|
||||
{/* <Scene layout="Main Layout" /> */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import React, { useState } from "react";
|
||||
import RegularDropDown from "./RegularDropDown";
|
||||
import { EyeDroperIcon } from "../../icons/ExportCommonIcons";
|
||||
import RegularDropDownID from "./RegularDropDownID";
|
||||
|
||||
type DataSourceSelectorProps = {
|
||||
label?: string;
|
||||
options: string[];
|
||||
options: {
|
||||
id: string;
|
||||
label: string;
|
||||
}[];
|
||||
selected?: string;
|
||||
onSelect: (value: string) => void;
|
||||
eyeDropperActive?: boolean; // initial state
|
||||
@@ -26,7 +30,7 @@ const DataSourceSelector: React.FC<DataSourceSelectorProps> = ({
|
||||
<div className="datas__label">{label}</div>
|
||||
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
<RegularDropDownID
|
||||
header={selected || "Select value"}
|
||||
options={options}
|
||||
onSelect={onSelect}
|
||||
|
||||
106
app/src/components/ui/inputs/RegularDropDownID.tsx
Normal file
106
app/src/components/ui/inputs/RegularDropDownID.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
interface DropdownOption {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface DropdownProps {
|
||||
header: string;
|
||||
options: DropdownOption[];
|
||||
onSelect: (optionId: string) => void;
|
||||
search?: boolean;
|
||||
onClick?: () => void;
|
||||
onChange?: () => void;
|
||||
}
|
||||
|
||||
const RegularDropDownID: React.FC<DropdownProps> = ({
|
||||
header,
|
||||
options,
|
||||
onSelect,
|
||||
search = true,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [filteredOptions, setFilteredOptions] = useState<DropdownOption[]>(options);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const [position, setPosition] = useState<{ top: number; left: number; width: number }>({ top: 0, left: 0, width: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm("");
|
||||
setFilteredOptions(options);
|
||||
}
|
||||
}, [isOpen, options]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedOption(null);
|
||||
setSearchTerm("");
|
||||
setFilteredOptions(options);
|
||||
}, [header, options]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
document.addEventListener("click", handleClickOutside);
|
||||
return () => document.removeEventListener("click", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && dropdownRef.current) {
|
||||
const rect = dropdownRef.current.getBoundingClientRect();
|
||||
setPosition({ top: rect.bottom + window.scrollY, left: rect.left + window.scrollX, width: rect.width });
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const toggleDropdown = () => setIsOpen((p) => !p);
|
||||
|
||||
const handleOptionClick = (opt: DropdownOption) => {
|
||||
setSelectedOption(opt.label);
|
||||
onSelect(opt.id);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const term = e.target.value;
|
||||
setSearchTerm(term);
|
||||
setFilteredOptions(options.filter(o => o.label.toLowerCase().includes(term.toLowerCase())));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="regularDropdown-container" ref={dropdownRef} onPointerLeave={() => setIsOpen(false)}>
|
||||
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
||||
<div className="key">{selectedOption || header}</div>
|
||||
<div className="icon">▾</div>
|
||||
</div>
|
||||
|
||||
{isOpen && createPortal(
|
||||
<div className="dropdown-options" style={{ position: "absolute", top: position.top, left: position.left, width: position.width, zIndex: 9999 }}>
|
||||
{search && (
|
||||
<div className="dropdown-search">
|
||||
<input type="text" placeholder="Search..." value={searchTerm} onChange={handleSearchChange} />
|
||||
</div>
|
||||
)}
|
||||
{filteredOptions.length > 0 ? (
|
||||
filteredOptions.map((opt) => (
|
||||
<div className="option" key={opt.id} onClick={() => handleOptionClick(opt)} title={opt.label}>
|
||||
{opt.label}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="no-options">No options found</div>
|
||||
)}
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RegularDropDownID
|
||||
Reference in New Issue
Block a user