Skip to content

Commit

Permalink
feat(ui): introduce WdsCheckbox - WF-138
Browse files Browse the repository at this point in the history
  • Loading branch information
madeindjs committed Feb 19, 2025
1 parent 9b726d8 commit 028e3db
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 33 deletions.
106 changes: 106 additions & 0 deletions src/ui/src/wds/WdsCheckbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script lang="tsx" setup>
import { computed, defineProps, useId } from "vue";
const props = defineProps({
label: { type: String, required: false, default: undefined },
detail: { type: String, required: false, default: undefined },
disabled: { type: Boolean, required: false },
});
const id = useId();
const checked = defineModel({ type: Boolean, default: false });
const classes = computed(() =>
[
props.disabled ? "WdsCheckbox--disabled" : undefined,
checked.value ? "WdsCheckbox--checked" : undefined,
].filter(Boolean),
);
function onChange(event: InputEvent) {
checked.value = (event.target as HTMLInputElement).checked;
}
</script>

<template>
<label
:for="id"
class="WdsCheckbox"
:class="classes"
@mousedown.prevent
@click.prevent="checked = !checked"
>
<div class="WdsCheckbox__checkbox">
<i class="WdsCheckbox__checkbox__check material-symbols-outlined"
>check</i
>
</div>
<span v-if="label" class="WdsCheckbox__label">{{ label }}</span>
<span v-if="detail" class="WdsCheckbox__detail">{{ detail }}</span>
<input
:id="id"
type="checkbox"
:checked="checked"
:disabled="disabled"
@change.stop="onChange"
/>
</label>
</template>

<style lang="css" scoped>
.WdsCheckbox {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto;
align-items: center;
column-gap: 12px;
row-gap: 2px;
cursor: pointer;
}
.WdsCheckbox__checkbox {
border: 1px solid var(--wdsColorGray4);
width: 18px;
height: 18px;
border-radius: 4px;
grid-row-start: 1;
grid-row-end: -1;
}
.WdsCheckbox--checked .WdsCheckbox__checkbox {
background-color: var(--wdsColorBlue5);
font-weight: bold;
}
.WdsCheckbox__checkbox__check {
display: none;
}
.WdsCheckbox:hover:not(.WdsCheckbox--checked) .WdsCheckbox__checkbox__check {
display: block;
color: var(--wdsColorGray4);
}
.WdsCheckbox--checked .WdsCheckbox__checkbox__check {
display: block;
color: var(--wdsColorWhite);
}
.WdsCheckbox__detail,
.WdsCheckbox__label {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-align: left;
}
.WdsCheckbox:has(.WdsCheckbox__detail) {
grid-template-rows: auto auto;
}
.WdsCheckbox__detail {
color: var(--wdsColorGray4);
}
.WdsCheckbox input {
display: none;
}
</style>
6 changes: 3 additions & 3 deletions src/ui/src/wds/WdsDropdownMenu.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { shallowMount } from "@vue/test-utils";
import { mount, shallowMount } from "@vue/test-utils";
import { describe, expect, it } from "vitest";

import WdsDropdownMenu from "./WdsDropdownMenu.vue";
Expand Down Expand Up @@ -31,7 +31,7 @@ describe("WdsDropdownMenu", () => {

describe("multiple mode", () => {
it("should support multiple mode", async () => {
const wrapper = shallowMount(WdsDropdownMenu, {
const wrapper = mount(WdsDropdownMenu, {
props: {
selected: ["???"],
enableMultiSelection: true,
Expand All @@ -40,7 +40,7 @@ describe("WdsDropdownMenu", () => {
});

await wrapper
.get(`.WdsDropdownMenu__item[data-automation-key="b"]`)
.get(`.WdsDropdownMenu__checkbox[data-automation-key="b"]`)
.trigger("click");

expect(wrapper.emitted("select").at(0)).toStrictEqual([["b"]]);
Expand Down
62 changes: 32 additions & 30 deletions src/ui/src/wds/WdsDropdownMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,43 @@
:key="index"
class="WdsDropdownMenu__item"
>
<div
<WdsSkeletonLoader
v-if="enableMultiSelection || !hideIcons"
class="WdsDropdownMenu__item__checkbox"
>
<WdsSkeletonLoader style="width: 20px" />
</div>
style="width: 20px"
/>
<div class="WdsDropdownMenu__item__label">
<WdsSkeletonLoader />
</div>
</button>
</template>

<template v-else-if="enableMultiSelection">
<WdsCheckbox
v-for="option in optionsFiltered"
:key="option.value"
class="WdsDropdownMenu__checkbox"
:checked="isSelected(option.value)"
:label="option.label"
:detail="option.detail"
:data-automation-key="option.value"
:model-value="isSelected(option.value)"
@update:model-value="onSelect(option.value)"
/>
</template>

<template v-else>
<button
v-for="option in optionsFiltered"
:key="option.value"
class="WdsDropdownMenu__item"
:class="{
'WdsDropdownMenu__item--selected': isSelected(option.value),
'WdsDropdownMenu__item--selected':
!enableMultiSelection && isSelected(option.value),
}"
:data-automation-key="option.value"
@click="onSelect(option.value)"
>
<div
v-if="enableMultiSelection"
class="WdsDropdownMenu__item__checkbox"
>
<input
type="checkbox"
:checked="isSelected(option.value)"
/>
</div>
<i v-else-if="!hideIcons" class="material-symbols-outlined">{{
<i v-if="!hideIcons" class="material-symbols-outlined">{{
getOptionIcon(option)
}}</i>
<div
Expand Down Expand Up @@ -98,6 +102,7 @@ export type WdsDropdownMenuOption = {
// from https://www.figma.com/design/jgLDtwVwg3hReC1t4Vw20D/.WDS-Writer-Design-System?node-id=128-396&t=9Gy9MYDycjVV8C2Y-1
import { computed, PropType, ref, watch } from "vue";
import WdsSkeletonLoader from "./WdsSkeletonLoader.vue";
import WdsCheckbox from "./WdsCheckbox.vue";
const props = defineProps({
options: {
Expand Down Expand Up @@ -184,6 +189,16 @@ watch(searchTerm, () => emits("search", searchTerm.value));
padding-top: 0px;
}
.WdsDropdownMenu__checkbox,
.WdsDropdownMenu__item {
min-height: 36px;
}
.WdsDropdownMenu__checkbox {
margin-top: 8px;
margin-bottom: 8px;
}
.WdsDropdownMenu__item {
background-color: transparent;
border: none;
Expand All @@ -195,8 +210,6 @@ watch(searchTerm, () => emits("search", searchTerm.value));
column-gap: 8px;
align-items: center;
min-height: 36px;
border-radius: 4px;
padding: 8px;
Expand All @@ -207,8 +220,7 @@ watch(searchTerm, () => emits("search", searchTerm.value));
transition: all 0.2s;
pointer-events: all;
}
.WdsDropdownMenu__item:has(.material-symbols-outlined),
.WdsDropdownMenu__item:has(.WdsDropdownMenu__item__checkbox) {
.WdsDropdownMenu__item:has(.material-symbols-outlined) {
grid-template-columns: auto 1fr auto;
}
Expand All @@ -221,16 +233,6 @@ watch(searchTerm, () => emits("search", searchTerm.value));
background-color: var(--wdsColorBlue2);
}
.WdsDropdownMenu__item__checkbox {
grid-row-start: 1;
grid-row-end: -1;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.WdsDropdownMenu__item__detail,
.WdsDropdownMenu__item__label {
text-overflow: ellipsis;
Expand Down

0 comments on commit 028e3db

Please sign in to comment.