Skip to content

Commit

Permalink
treeview checkbox
Browse files Browse the repository at this point in the history
  • Loading branch information
FredericHeem committed Dec 15, 2023
1 parent 6763364 commit 8c491fc
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 79 deletions.
7 changes: 6 additions & 1 deletion bau-ui/checkbox/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ export default function (context, options = {}) {
&:hover.solid {
filter: brightness(var(--brightness-hover-always));
}
&:indeterminate::after {
content: "\u2796";
opacity: 1;
}
&:disabled {
border: 2px dashed var(--color-gray-500);
}
&:checked::after {
content: "\u2716";
opacity: 1;
}
&::after {
content: "\u2716";
content: "";
position: absolute;
top: 50%;
left: 50%;
Expand Down
5 changes: 2 additions & 3 deletions bau-ui/collapsible/collapsible.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,12 @@ export default function (context, options = {}) {
color = options.color ?? "neutral",
Header,
Content,
close = true,
expanded = false,
...props
},
] = toPropsAndChildren(args);

const closeState = bau.state(close);

const closeState = bau.state(!expanded);
return div(
{
...props,
Expand Down
2 changes: 1 addition & 1 deletion bau-ui/collapsible/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ declare module "@grucloud/bau-ui/collapsible" {
type DefaultDesignProps = import("../constants").DefaultDesignProps;
type ComponentOption = import("../bau-ui").ComponentOption;

export type CollapsibleProps = {} & DefaultDesignProps;
export type CollapsibleProps = { expanded?: boolean } & DefaultDesignProps;

type Component = import("../bau-ui").Component<CollapsibleProps>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,54 @@
import checkbox from "@grucloud/bau-ui/checkbox";
import { Context } from "@grucloud/bau-ui/context";
import checkbox from "@grucloud/bau-ui/checkbox";
import button from "@grucloud/bau-ui/button";

export default (context: Context) => {
const { bau, css } = context;
const { section, label } = bau.tags;
const { form, article, footer, label } = bau.tags;

const Checkbox = checkbox(context);
const Checkbox = checkbox(context, { color: "neutral", variant: "outline" });
const Button = button(context, {
variant: "outline",
color: "primary",
});

const checkboxState = bau.state(false);

const onChange = (event: any) => {
checkboxState.val = event.target.checked ? true : false;
};

const onsubmit = (event: any) => {
event.preventDefault();
const payload = Object.fromEntries(
new FormData(event.target.closest("form"))
);
alert(JSON.stringify(payload));
};

return () =>
section(
label(
{
class: css`
display: inline-flex;
font-size: smaller;
align-items: center;
justify-content: space-between;
color: var(--color-content-secondary);
gap: 1rem;
`,
},
"My Checkbox",
Checkbox({
color: "neutral",
variant: "outline",
id: "my-checkbox",
name: "myCheckbox",
checked: checkboxState,
onchange: onChange,
})
)
form(
{ onsubmit },
article(
label(
{
class: css`
display: inline-flex;
font-size: smaller;
align-items: center;
justify-content: space-between;
color: var(--color-content-secondary);
gap: 1rem;
`,
},
"My Checkbox",
Checkbox({
name: "myCheckbox",
checked: checkboxState,
onchange: onChange,
})
)
),
footer(Button({ type: "submit" }, "Submit"))
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import checkbox from "@grucloud/bau-ui/checkbox";
import { Context } from "@grucloud/bau-ui/context";
import button from "@grucloud/bau-ui/button";

export default (context: Context) => {
const { bau, css } = context;
const { label, footer, article, form } = bau.tags;

const Checkbox = checkbox(context, { color: "neutral", variant: "outline" });

const Button = button(context, {
variant: "outline",
color: "primary",
});

const ButtonSubmit = button(context, {
variant: "solid",
color: "primary",
});

const onsubmit = (event: any) => {
event.preventDefault();
const payload = Object.fromEntries(
new FormData(event.target.closest("form"))
);
alert(JSON.stringify(payload));
};
const onclickIndeterminate = (_event: any) => {
const checkboxEl = window.document.getElementById("my-checkbox");
if (checkboxEl) {
// @ts-ignore
checkboxEl.indeterminate = !checkboxEl.indeterminate;
}
};
return () =>
form(
{
onsubmit,
class: css`
display: inline-flex;
flex-direction: column;
gap: 1rem;
& label {
display: inline-flex;
flex-direction: row;
font-size: smaller;
align-items: center;
gap: 1rem;
}
`,
},
article(
label(
"My Checkbox",
Checkbox({
id: "my-checkbox",
name: "my-checkbox",
})
),
Button({ onclick: onclickIndeterminate }, "Toggle Indeterminate")
),
footer(ButtonSubmit({ type: "submit" }, "Submit"))
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import button from "@grucloud/bau-ui/button";

export default (context: Context) => {
const { bau, css } = context;
const { label, form } = bau.tags;
const { label, footer, article, form } = bau.tags;

const Checkbox = checkbox(context, { color: "neutral", variant: "outline" });
const Button = button(context);
const Button = button(context, {
variant: "outline",
color: "primary",
});

const onsubmit = (event: any) => {
event.preventDefault();
Expand All @@ -34,13 +37,14 @@ export default (context: Context) => {
}
`,
},
label(
"My Checkbox",
Checkbox({
id: "my-checkbox-uncontrolled",
name: "my-checkbox-uncontrolled",
})
article(
label(
"My Checkbox",
Checkbox({
name: "my-checkbox-uncontrolled",
})
)
),
Button({ type: "submit" }, "Submit")
footer(Button({ type: "submit" }, "Submit"))
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import checkboxUncontrolled from "./checkbox-uncontrolled.ts";
// @ts-ignore
import codeExampleUncontrolled from "./checkbox-uncontrolled.ts?raw";

import checkboxIndeterminate from "./checkbox-indeterminate.ts";
// @ts-ignore
import codeIndeterminate from "./checkbox-indeterminate.ts?raw";

export const checkboxSpec = {
title: "Checkbox",
package: "checkbox",
Expand All @@ -32,6 +36,12 @@ export const checkboxSpec = {
code: codeExampleUncontrolled,
createComponent: checkboxUncontrolled,
},
{
title: "Indeterminate checkbox",
description: "An indeterminate checkbox.",
code: codeIndeterminate,
createComponent: checkboxIndeterminate,
},
],
gridItem: checkboxGridItem,
};
Expand Down
133 changes: 133 additions & 0 deletions bau-ui/examples/bau-storybook/src/pages/treeView/treeView-check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { Context } from "@grucloud/bau-ui/context";
import treeView, { type Tree } from "@grucloud/bau-ui/treeView";
import checkbox from "@grucloud/bau-ui/checkbox";
import button from "@grucloud/bau-ui/button";

export default (context: Context) => {
const { bau, css, window } = context;
const { form, label, article, footer } = bau.tags;

const Checkbox = checkbox(context, { color: "neutral", variant: "outline" });
const Button = button(context, {
variant: "solid",
color: "danger",
});

const selectedCount = bau.state(0);

const onsubmit = (event: any) => {
event.preventDefault();
const formEl = event.target.closest("form");
const payload = Object.fromEntries(new FormData(formEl));
alert(JSON.stringify(payload));
};

const tree: Tree = {
data: { name: "Resources" },
expanded: true,
children: [
{
data: { name: "EC2" },
expanded: true,
children: [
{ data: { name: "Vpc", id: "EC2::Vpc" } },
{ data: { name: "Subnet", id: "EC2::Subnet" } },
],
},
{
data: { name: "IAM" },
children: [{ data: { name: "Role", id: "IAM:Role" } }],
},
],
};

const getCheckboxId = ({ id, name }: any) => id ?? name;
const getCheckboxEl = (data: any): HTMLInputElement =>
window.document.getElementById(getCheckboxId(data)) as HTMLInputElement;

const walkTree =
({ onNode }: any) =>
(item: any) => {
onNode(item);
const { children = [] } = item;
children.map(walkTree({ onNode }));
};

const isParentIndeterminate = ({ parent }: any) => {
if (parent) {
const { children } = parent;
const parentCheckboxEl = getCheckboxEl(parent.data);
if (parentCheckboxEl) {
const allUnchecked = children.every((child: any) => {
const { checked, indeterminate } = getCheckboxEl(child.data);
return !checked && !indeterminate;
});
parentCheckboxEl.indeterminate =
!allUnchecked &&
children.some((child: any) => !getCheckboxEl(child.data).checked);
parentCheckboxEl.checked = children.every(
(child: any) => getCheckboxEl(child.data).checked
);
}
isParentIndeterminate({ parent: parent.parent });
}
};

const onclickCheckbox =
({ item, parent }: any) =>
(event: any) => {
isParentIndeterminate({ parent });
walkTree({
onNode: (node: any) => {
const checkboxEl = getCheckboxEl(node.data);
if (checkboxEl) {
checkboxEl.checked = event.target.checked;
checkboxEl.indeterminate = false;
}
},
})(item);

const formEl = event.target.closest("form");
const checkboxesChecked = formEl.querySelectorAll(
'input[type="checkbox"][data-type="resources"]:checked'
);
selectedCount.val = checkboxesChecked.length;
event.stopPropagation();
};

const renderMenuItem = ({ item, parent }: any) => {
const { name, id } = item.data;
const checkboxId = getCheckboxId(item.data);
return label(
{
class: css`
display: flex;
align-items: center;
padding-right: 1rem;
`,
onclick: (event: any) => event.stopPropagation(),
},
Checkbox({
onclick: onclickCheckbox({ item, parent }),
name: checkboxId,
id: checkboxId,
"data-type": id ? "resources" : "group",
}),
name
);
};

const TreeView = treeView(context, { renderMenuItem });

return () =>
form(
{ onsubmit },
article(TreeView({ tree })),
footer(
Button(
{ type: "submit" },
() => `Delete ${selectedCount.val} Resource(s)`
)
)
);
};
Loading

0 comments on commit 8c491fc

Please sign in to comment.