Skip to content

Commit

Permalink
Fix update logic for tag select and add autocomplete with tags in use
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamindehli committed May 1, 2024
1 parent 8d9d545 commit 687fb0f
Showing 1 changed file with 207 additions and 73 deletions.
280 changes: 207 additions & 73 deletions src/components/Template/DefaultTagsField.jsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,234 @@
// Dependencies
import { useEffect, useRef, useState } from "react";
import { useContext, useEffect, useRef, useState } from "react";

// Material UI
import { Help } from "@mui/icons-material";
import {
Chip,
Collapse,
FormControl,
FormHelperText,
IconButton,
InputAdornment,
InputLabel,
OutlinedInput,
Stack
} from "@mui/material";
import { Autocomplete, Chip, FormControl, FormHelperText, TextField } from "@mui/material";

// Functions
import { capitalizeFirstLetter } from "@/functions/helpers";

export default function DefaultTagsField({
id,
name,
label,
type = "text",
defaultValue,
helperText,
inputProps,
autoFocus,
onChange
}) {
const [tags, SetTags] = useState(!!defaultValue?.length ? defaultValue.split(",") : []);
const tagRef = useRef();

const handleDelete = (value) => {
const newtags = tags.filter((val) => val !== value);
SetTags(newtags);
};
function handleOnChange(event) {
if (event.target.value.includes(",")) {
SetTags([...tags, event.target.value.split(",")[0]]);
tagRef.current.value = "";
}
}
// Store
import DecentSamplerContext from "@/store/DecentSamplerContext";

export default function DefaultTagsField({ id, name, label, getDefaultValue, helperText, autoFocus, onChange }) {
const decentSamplerContext = useContext(DecentSamplerContext);

function getTagsInUse() {
const getTagsInUse = [];
const decentSampler = decentSamplerContext.decentSampler;
const groupsItem = decentSampler.getFirstGroupsItem();
const tabItem = decentSampler.getFirstUiItem()?.getFirstTabItem();
const midiItem = decentSampler.getFirstMidiItem();
const modulatorsItem = decentSampler.getFirstModulatorsItem();
const tagsItem = decentSampler.getFirstTagsItem();

// Get group tags
const groupItems = groupsItem?.getGroupItems();
groupItems?.length && // Group items
groupItems.forEach((group) => {
group.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
// Get group sample tags
const sampleItems = group.getSampleItems();
sampleItems?.length && // Sample items inside group item
sampleItems.forEach((sample) => {
sample.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

// Get sample tags
const sampleItems = groupsItem?.getGroupItems();
sampleItems?.length && // Sample items
sampleItems.forEach((sample) => {
sample.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});

useEffect(() => {
onChange(tags.join(","));
}, [onChange, tags]);
// Get button state binding tags
const buttonItems = tabItem?.getButtonItems();
buttonItems?.length && // Button items
buttonItems.forEach((button) => {
const stateItems = button.getStateItems();
stateItems?.length && // State items inside button item
stateItems.forEach((state) => {
const bindingItems = state.getBindingItems();
bindingItems?.length && // Binding items inside state item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});
});

const [showHelperText, setShowHelperText] = useState(false);
// Get control binding tags
const controlItems = tabItem?.getControlItems();
controlItems?.length && // Control items
controlItems.forEach((control) => {
const bindingItems = control.getBindingItems();
bindingItems?.length && // Binding items inside control item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

const handleClickShowHelperText = () => setShowHelperText((showHelperText) => !showHelperText);
// Get labeled knob binding tags
const labeledKnobItems = tabItem?.getLabeledKnobItems();
labeledKnobItems?.length && // Labeled knob items
labeledKnobItems.forEach((labeledKnob) => {
const bindingItems = labeledKnob.getBindingItems();
bindingItems?.length && // Binding items inside labeled knob item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

const handleMouseDownShowHelperText = (event) => {
event.preventDefault();
};
// Get menu option tags
const menuItems = tabItem?.getMenuItems();
menuItems?.length && // Menu items
menuItems.forEach((menu) => {
const optionItems = menu.getOptionItems();
optionItems?.length && // Option items inside menu item
optionItems.forEach((option) => {
const bindingItems = option.getBindingItems();
bindingItems?.length && // Binding items inside option item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});
});

// Get CC binding tags
const ccItems = midiItem?.getCcItems();
ccItems?.length && // CC items
ccItems.forEach((cc) => {
const bindingItems = cc.getBindingItems();
bindingItems?.length && // Binding items inside CC item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

// Get note binding tags
const noteItems = midiItem?.getNoteItems();
noteItems?.length && // Note items
noteItems.forEach((note) => {
const bindingItems = note.getBindingItems();
bindingItems?.length && // Binding items inside note item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

// Get LFO binding tags
const lfoItems = modulatorsItem?.getLfoItems();
lfoItems?.length && // LFO items
lfoItems.forEach((lfo) => {
const bindingItems = lfo.getBindingItems();
bindingItems?.length && // Binding items inside LFO item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

// Get envelope binding tags
const envelopeItems = modulatorsItem?.getEnvelopeItems();
envelopeItems?.length && // Envelope items
envelopeItems.forEach((envelope) => {
const bindingItems = envelope.getBindingItems();
bindingItems?.length && // Binding items inside envelope item
bindingItems.forEach((binding) => {
binding.getTags()?.forEach((tag) => {
if (!getTagsInUse.includes(tag)) {
getTagsInUse.push(tag);
}
});
});
});

// Get tags
const tagItems = tagsItem?.getTagItems();
tagItems?.length && // Tag items
tagItems.forEach((tag) => {
if (tag?.name?.length && !getTagsInUse.includes(tag.name)) {
getTagsInUse.push(tag.name);
}
});

return getTagsInUse.sort();
}

function handleOnChange(event, newValue) {
let newTags = [];
newValue.forEach((tag) => {
newTags = [...newTags, ...tag.split(",").filter((tag) => tag.trim().length)];
});
onChange(newTags.join(","));
}

const labelWithFallback = label || capitalizeFirstLetter(name);
const idWithFallback = id || name;
const helperTextId = `${idWithFallback}-helper-text`;

const defaultValue = !!getDefaultValue?.(name)?.length ? getDefaultValue(name).split(",") : [];

return (
<FormControl margin="dense" fullWidth variant="outlined">
<InputLabel htmlFor={id || name}>{labelWithFallback}</InputLabel>
<OutlinedInput
<Autocomplete
freeSolo
multiple
autoSelect
id={idWithFallback}
type={type}
name={name}
inputProps={{ ...inputProps, "aria-label": labelWithFallback }}
aria-describedby={helperTextId}
defaultValue={defaultValue}
autoFocus={autoFocus}
label={labelWithFallback}
inputRef={tagRef}
aria-describedby={helperTextId}
options={getTagsInUse()}
onChange={handleOnChange}
startAdornment={
<Stack direction="row" spacing={1} sx={{ mr: 1 }}>
{tags.map((tag, index) => {
return <Chip label={tag} key={index} onDelete={() => handleDelete(tag)} />;
})}
</Stack>
}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowHelperText}
onMouseDown={handleMouseDownShowHelperText}
edge="end"
>
<Help color={showHelperText ? "primary" : "inherit"} />
</IconButton>
</InputAdornment>
renderTags={(value, getTagProps) =>
value.map((tag, index) => (
<Chip {...getTagProps({ index })} key={index} variant="outlined" label={tag} />
))
}
renderInput={(params) => <TextField {...params} label={labelWithFallback} />}
/>
<Collapse in={showHelperText}>
<FormHelperText id={helperTextId}>{helperText}</FormHelperText>
</Collapse>
<FormHelperText id={helperTextId}>{helperText}</FormHelperText>
</FormControl>
);
}

0 comments on commit 687fb0f

Please sign in to comment.