Skip to content

Commit

Permalink
feat: add ability to remove selected icon on button (#1274)
Browse files Browse the repository at this point in the history
  • Loading branch information
brunozoric authored Oct 5, 2020
1 parent 18d41d1 commit bfb0d46
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
71 changes: 64 additions & 7 deletions packages/app-page-builder/src/editor/components/IconPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { DelayedOnChange } from "@webiny/app-page-builder/editor/components/Dela
import { Menu } from "@webiny/ui/Menu";
import { Input } from "@webiny/ui/Input";
import { PbIcon, PbIconsPlugin } from "@webiny/app-page-builder/types";
import classNames from "classnames";

const COLUMN_COUNT = 6;

const gridItem = css({
position: "relative",
display: "flex",
flexDirection: "column",
justifyContent: "flex-start",
Expand Down Expand Up @@ -49,6 +51,21 @@ const gridItem = css({
}
});

const gridItemSelected = css({
backgroundColor: "var(--mdc-theme-text-secondary-on-background)",
color: "#FFFFFF",
">svg": {
fill: "#FFFFFF"
},
"> .remove": {
position: "absolute",
width: "auto",
marginBottom: "0",
top: "2px",
right: "5px"
}
});

const grid = css({
padding: 20
});
Expand All @@ -70,7 +87,7 @@ const searchInput = css({

const { useState, useCallback, useMemo, Fragment } = React;

const IconPicker = ({ value, onChange }) => {
const IconPicker = ({ value, onChange, removable = true }) => {
const [filter, setFilter] = useState("");

const onFilterChange = useCallback(
Expand All @@ -81,16 +98,47 @@ const IconPicker = ({ value, onChange }) => {
[filter]
);

const { prefix: selectedIconPrefix, name: selectedIconName } = useMemo(() => {
if (!value || Array.isArray(value) === false || !removable) {
return {
prefix: undefined,
name: undefined
};
}
return {
prefix: value[0],
name: value[1]
};
}, [value]);

const allIcons: PbIcon[] = useMemo(() => {
const plugins = getPlugins<PbIconsPlugin>("pb-icons");
return plugins.reduce((icons: Array<PbIcon>, pl) => {
return icons.concat(pl.getIcons());
let selectedIconItem = null;
const allIconItems = plugins.reduce((icons: Array<PbIcon>, pl) => {
const pluginIcons = pl.getIcons().filter(({ id }) => {
const [prefix, name] = id;
if (!selectedIconPrefix || !selectedIconName || prefix !== selectedIconPrefix) {
return true;
}
return name !== selectedIconName;
});
const selectedIcon = pl.getIcons().find(({ name }) => {
return name === selectedIconName;
});
if (selectedIcon) {
selectedIconItem = selectedIcon;
}
return icons.concat(pluginIcons);
}, []);
}, []);
if (selectedIconItem) {
allIconItems.unshift(selectedIconItem);
}
return allIconItems;
}, [selectedIconPrefix, selectedIconName]);

const icons = useMemo(() => {
return filter ? allIcons.filter(ic => ic.name.includes(filter)) : allIcons;
}, [filter]);
}, [filter, selectedIconPrefix, selectedIconName]);

const renderCell = useCallback(
({ closeMenu }) => {
Expand All @@ -99,17 +147,26 @@ const IconPicker = ({ value, onChange }) => {
if (!item) {
return null;
}

const isSelectedIcon =
item.id[0] === selectedIconPrefix && item.id[1] === selectedIconName;
const gridItemClassName = classNames(gridItem, {
[gridItemSelected]: isSelectedIcon
});
return (
<div
key={key}
style={style}
className={gridItem}
className={gridItemClassName}
onClick={() => {
onChange(item);
closeMenu();
}}
>
{isSelectedIcon && (
<span className="remove">
<FontAwesomeIcon icon={["fas", "times"]} />
</span>
)}
<FontAwesomeIcon icon={item.id} size={"2x"} />
<Typography use={"body2"}>{item.name}</Typography>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Props = {
label: string;
value: string;
updateValue: (value: any) => void;
removable?: boolean;
};

class IconPicker extends React.Component<Props> {
Expand All @@ -16,14 +17,18 @@ class IconPicker extends React.Component<Props> {
}

render() {
const { label, value, updateValue } = this.props;
const { label, value, updateValue, removable } = this.props;
return (
<Grid>
<Cell span={4}>
<Typography use={"overline"}>{label}</Typography>
</Cell>
<Cell span={8}>
<IconPickerComponent value={value} onChange={updateValue} />
<IconPickerComponent
value={value}
onChange={updateValue}
removable={removable}
/>
</Cell>
</Grid>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ const excludePlugins = [
const ButtonContainer = props => {
const { getAllClasses, elementStyle, elementAttributes, element } = props;
const { type = "default", icon = {} } = element.data || {};
const svg = icon.svg || null;
const { alignItems } = elementStyle;

const { position = "left" } = icon;
const { svg = null, position = "left" } = icon || {};

const onChange = useHandler(props, ({ element, updateElement }) => (value: string) => {
updateElement({ element: set(element, "data.text", value) });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,36 @@ const ButtonSettings = ({ element, updateElement }) => {
return (name, value, history = true) => {
const attrKey = `data.${name}`;

let newElement = set(element, attrKey, value);
if (name.startsWith("icon")) {
const { id, width, color } = get(newElement, "data.icon");
newElement = set(newElement, "data.icon.svg", getSvg(id, { width, color }));
const newElement = set(element, attrKey, value);
const isIcon = name.startsWith("icon");
if (isIcon) {
const { id, width, color } = newElement.data?.icon || {};

const isSelectedIcon =
icon.id && id ? icon.id[0] === id[0] && icon.id[1] === id[1] : false;

const updatedIcon = isSelectedIcon ? {} : newElement.data.icon || {};

newElement.data.icon = {
...updatedIcon,
svg: id && !isSelectedIcon ? getSvg(id, { width, color }) : undefined
};
}

if (!history) {
updateElement({ element: newElement, history });
return;
}

if (historyUpdated[name] !== value) {
if (historyUpdated[name] !== value || (value === undefined && isIcon)) {
historyUpdated[name] = value;
updateElement({ element: newElement });
}
};
}, [element, updateElement]);

const updateType = useCallback(value => setData("type", value), [setData]);
const updateIcon = useCallback(value => setData("icon.id", value.id), [setData]);
const updateIcon = useCallback(value => setData("icon.id", value?.id), [setData]);
const updateIconColor = useCallback((value: string) => setData("icon.color", value), [setData]);
const updateIconColorPreview = useCallback(
(value: string) => setData("icon.color", value, false),
Expand Down Expand Up @@ -77,11 +87,15 @@ const ButtonSettings = ({ element, updateElement }) => {
</Grid>
</Tab>
<Tab label={"Icon"}>
<IconPicker label={"Icon"} value={icon.id} updateValue={updateIcon} />
<Input label={"Width"} value={icon.width || 50} updateValue={updateIconWidth} />
<IconPicker label={"Icon"} value={icon?.id} updateValue={updateIcon} />
<Input
label={"Width"}
value={icon?.width || 50}
updateValue={updateIconWidth}
/>
<ColorPicker
label={"Color"}
value={icon.color}
value={icon?.color}
updateValue={updateIconColor}
updatePreview={updateIconColorPreview}
/>
Expand All @@ -90,7 +104,7 @@ const ButtonSettings = ({ element, updateElement }) => {
<Typography use={"overline"}>Position</Typography>
</Cell>
<Cell span={6}>
<Select value={icon.position || "left"} onChange={updateIconPosition}>
<Select value={icon?.position || "left"} onChange={updateIconPosition}>
<option value={"left"}>Left</option>
<option value={"right"}>Right</option>
<option value={"top"}>Top</option>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ const IconSettings = ({ element, updateElement }) => {
<React.Fragment>
<Tabs>
<Tab label={"Icon"}>
<IconPicker label={"Icon"} value={icon.id} updateValue={updateIcon} />
<IconPicker
label={"Icon"}
value={icon.id}
updateValue={updateIcon}
removable={false}
/>
<Input
label={"Width"}
value={icon.width}
Expand Down

0 comments on commit bfb0d46

Please sign in to comment.