@fiscozen/checkbox 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiscozen/checkbox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Design System Checkbox and Checkbox Group component",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"tailwindcss": "^3.4.1",
|
|
15
15
|
"vue": "^3.4.13",
|
|
16
|
-
"@fiscozen/icons": "^0.1.
|
|
16
|
+
"@fiscozen/icons": "^0.1.4"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@rushstack/eslint-patch": "^1.3.3",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"@awesome.me/kit-8137893ad3": "^1.0.65",
|
|
35
35
|
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
|
36
36
|
"@fortawesome/vue-fontawesome": "^3.0.6",
|
|
37
|
-
"@fiscozen/eslint-config": "^0.1.0",
|
|
38
|
-
"@fiscozen/prettier-config": "^0.1.0",
|
|
39
37
|
"@fiscozen/tsconfig": "^0.1.0",
|
|
40
|
-
"@fiscozen/
|
|
38
|
+
"@fiscozen/eslint-config": "^0.1.0",
|
|
39
|
+
"@fiscozen/icons": "^0.1.4",
|
|
40
|
+
"@fiscozen/prettier-config": "^0.1.0"
|
|
41
41
|
},
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"scripts": {
|
package/src/FzCheckbox.vue
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="flex justify-center flex-col w-fit">
|
|
3
3
|
<input
|
|
4
4
|
type="checkbox"
|
|
5
|
-
:id="
|
|
5
|
+
:id="id"
|
|
6
6
|
:disabled="disabled"
|
|
7
7
|
:checked="checked"
|
|
8
8
|
:class="staticInputClass"
|
|
@@ -13,10 +13,7 @@
|
|
|
13
13
|
:indeterminate="indeterminate"
|
|
14
14
|
ref="refCheckbox"
|
|
15
15
|
/>
|
|
16
|
-
<label
|
|
17
|
-
:for="value.replace(/ /g, '-').toLowerCase()"
|
|
18
|
-
:class="[staticLabelClass, computedLabelClass]"
|
|
19
|
-
>
|
|
16
|
+
<label :for="id" :class="[staticLabelClass, computedLabelClass]">
|
|
20
17
|
<FzIcon
|
|
21
18
|
:name="computedName"
|
|
22
19
|
:size="size"
|
|
@@ -44,9 +41,13 @@ const props = withDefaults(defineProps<FzCheckboxProps>(), {
|
|
|
44
41
|
indeterminate: false,
|
|
45
42
|
});
|
|
46
43
|
|
|
47
|
-
const
|
|
44
|
+
const currentValue = computed(() => props.value ?? props.label);
|
|
48
45
|
|
|
49
|
-
const
|
|
46
|
+
const id = computed(
|
|
47
|
+
() => `fz-checkbox-${Math.random().toString(36).slice(2, 9)}`,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const model = defineModel<boolean | (string | number | boolean)[]>({
|
|
50
51
|
required: true,
|
|
51
52
|
});
|
|
52
53
|
|
|
@@ -96,7 +97,7 @@ const checkValueIsInModel = () => {
|
|
|
96
97
|
if (typeof model.value === "boolean") {
|
|
97
98
|
return model.value;
|
|
98
99
|
} else {
|
|
99
|
-
return model.value.includes(value);
|
|
100
|
+
return model.value.includes(currentValue.value);
|
|
100
101
|
}
|
|
101
102
|
};
|
|
102
103
|
|
|
@@ -130,9 +131,9 @@ onMounted(() => {
|
|
|
130
131
|
if (model.value) refCheckbox.value?.dispatchEvent(new Event("change"));
|
|
131
132
|
else if (props.checked !== undefined) model.value = props.checked;
|
|
132
133
|
} else {
|
|
133
|
-
if (model.value.includes(value))
|
|
134
|
+
if (model.value.includes(currentValue.value))
|
|
134
135
|
refCheckbox.value?.dispatchEvent(new Event("change"));
|
|
135
|
-
else if (props.checked) model.value.push(value);
|
|
136
|
+
else if (props.checked) model.value.push(currentValue.value);
|
|
136
137
|
}
|
|
137
138
|
});
|
|
138
139
|
</script>
|
package/src/FzCheckboxGroup.vue
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
<div :class="[staticSlotContainerClass, computedSlotContainerClass]">
|
|
10
10
|
<FzCheckboxGroupOption
|
|
11
11
|
v-for="option in options"
|
|
12
|
-
:key="option.value"
|
|
12
|
+
:key="option.value ? option.value.toString() : option.label"
|
|
13
13
|
v-model="model"
|
|
14
|
-
v-bind="option"
|
|
15
14
|
:disabled="disabled"
|
|
15
|
+
v-bind="option"
|
|
16
16
|
:emphasis="emphasis"
|
|
17
17
|
:error="error"
|
|
18
18
|
:size="size"
|
|
@@ -26,11 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
<script setup lang="ts">
|
|
28
28
|
import { computed } from "vue";
|
|
29
|
-
import { FzCheckboxGroupProps
|
|
29
|
+
import { FzCheckboxGroupProps } from "./types";
|
|
30
30
|
import FzCheckboxErrorText from "./components/FzCheckboxErrorText.vue";
|
|
31
31
|
import { mapSizeToClasses } from "./common";
|
|
32
32
|
import FzCheckboxGroupOption from "./components/FzCheckboxGroupOption.vue";
|
|
33
33
|
|
|
34
|
+
FzCheckboxGroupOption.compatConfig = {
|
|
35
|
+
MODE: 3,
|
|
36
|
+
};
|
|
37
|
+
|
|
34
38
|
const props = defineProps<FzCheckboxGroupProps>();
|
|
35
39
|
const id = `fz-checkbox-group-${generateRandomId()}`;
|
|
36
40
|
|
|
@@ -3,6 +3,8 @@ import { mount } from "@vue/test-utils";
|
|
|
3
3
|
import { describe, it, expect } from "vitest";
|
|
4
4
|
import FzCheckbox from "../FzCheckbox.vue";
|
|
5
5
|
|
|
6
|
+
const MAX_CHECKBOX = 200;
|
|
7
|
+
|
|
6
8
|
describe("FzCheckbox", () => {
|
|
7
9
|
it("renders correctly", async () => {
|
|
8
10
|
const wrapper = mount(FzCheckbox, {
|
|
@@ -16,7 +18,6 @@ describe("FzCheckbox", () => {
|
|
|
16
18
|
|
|
17
19
|
await wrapper.vm.$nextTick();
|
|
18
20
|
expect(wrapper.html()).toContain("Test Checkbox");
|
|
19
|
-
expect(wrapper.html()).toMatchSnapshot();
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
it("emits an update event when clicked", async () => {
|
|
@@ -85,4 +86,23 @@ describe("FzCheckbox", () => {
|
|
|
85
86
|
await wrapper.vm.$nextTick();
|
|
86
87
|
expect(wrapper.find("input").element.disabled).toBe(true);
|
|
87
88
|
});
|
|
89
|
+
|
|
90
|
+
it(`should render ${MAX_CHECKBOX} checkbox all with different ids`, async () => {
|
|
91
|
+
const checkboxes = Array.from({ length: MAX_CHECKBOX }).map((_) => {
|
|
92
|
+
return mount(FzCheckbox, {
|
|
93
|
+
props: {
|
|
94
|
+
label: "Test Checkbox",
|
|
95
|
+
value: "test",
|
|
96
|
+
size: "md",
|
|
97
|
+
modelValue: false,
|
|
98
|
+
disabled: true,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
await Promise.all(checkboxes.map((c) => c.vm.$nextTick()));
|
|
103
|
+
const ids = checkboxes.map((c) => c.find("input").attributes("id"));
|
|
104
|
+
const labelFor = checkboxes.map((c) => c.find("label").attributes("for"));
|
|
105
|
+
expect(new Set(ids).size).toBe(MAX_CHECKBOX);
|
|
106
|
+
expect(new Set(labelFor).size).toBe(MAX_CHECKBOX);
|
|
107
|
+
});
|
|
88
108
|
});
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
<div :class="[staticChildContainerClass, computedChildContainerClasses]">
|
|
15
15
|
<FzCheckbox
|
|
16
16
|
v-for="child in children"
|
|
17
|
-
:key="child.value"
|
|
17
|
+
:key="child.value ? child.value.toString() : child.label"
|
|
18
18
|
v-model="model"
|
|
19
|
-
v-bind="child"
|
|
20
19
|
:disabled="disabled"
|
|
20
|
+
v-bind="child"
|
|
21
21
|
:emphasis="emphasis"
|
|
22
22
|
:error="error"
|
|
23
23
|
:size="size"
|
|
@@ -32,9 +32,13 @@ import { computed } from "vue";
|
|
|
32
32
|
import FzCheckbox from "../FzCheckbox.vue";
|
|
33
33
|
import { ParentCheckbox } from "../types";
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
FzCheckbox.compatConfig = {
|
|
36
|
+
MODE: 3,
|
|
37
|
+
};
|
|
36
38
|
|
|
37
|
-
const
|
|
39
|
+
const props = defineProps<ParentCheckbox & { size: "sm" | "md" }>();
|
|
40
|
+
const currentValue = computed(() => props.value ?? props.label);
|
|
41
|
+
const model = defineModel<(string | number | boolean)[]>({
|
|
38
42
|
required: true,
|
|
39
43
|
default: [],
|
|
40
44
|
});
|
|
@@ -50,7 +54,7 @@ const isIndeterminate = computed(() => {
|
|
|
50
54
|
if (!props.children) return false;
|
|
51
55
|
|
|
52
56
|
const numChecked = props.children.filter((child) =>
|
|
53
|
-
model.value.includes(child.value
|
|
57
|
+
model.value.includes(child.value ?? child.label),
|
|
54
58
|
).length;
|
|
55
59
|
return numChecked > 0 && numChecked < props.children.length;
|
|
56
60
|
});
|
|
@@ -58,28 +62,26 @@ const isIndeterminate = computed(() => {
|
|
|
58
62
|
function handleCheckboxParentChange() {
|
|
59
63
|
if (!props.children) return;
|
|
60
64
|
const numChecked = props.children.filter((child) =>
|
|
61
|
-
model.value.includes(child.value
|
|
65
|
+
model.value.includes(child.value ?? child.label),
|
|
62
66
|
).length;
|
|
63
67
|
|
|
64
68
|
if (numChecked === props.children.length) {
|
|
65
69
|
// push parent value to model (using concat to force reactivity, push seems to not work)
|
|
66
|
-
model.value = model.value.concat(
|
|
70
|
+
model.value = model.value.concat(currentValue.value);
|
|
67
71
|
} else {
|
|
68
72
|
// remove parent value from model if it exists
|
|
69
|
-
if (model.value.includes(
|
|
70
|
-
model.value = model.value.filter(
|
|
71
|
-
(value) => value !== (props.value || props.label),
|
|
72
|
-
);
|
|
73
|
+
if (model.value.includes(currentValue.value))
|
|
74
|
+
model.value = model.value.filter((value) => value !== currentValue.value);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
function onCheckboxParentChange() {
|
|
77
79
|
if (!props.children) return;
|
|
78
|
-
if (model.value.includes(
|
|
80
|
+
if (model.value.includes(currentValue.value)) {
|
|
79
81
|
// push all children values to model that are not already in model
|
|
80
82
|
model.value = model.value.concat(
|
|
81
83
|
props.children
|
|
82
|
-
?.map((child) => child.value
|
|
84
|
+
?.map((child) => child.value ?? child.label)
|
|
83
85
|
.filter((value) => !model.value.includes(value)),
|
|
84
86
|
);
|
|
85
87
|
} else {
|
|
@@ -87,7 +89,7 @@ function onCheckboxParentChange() {
|
|
|
87
89
|
model.value = model.value.filter(
|
|
88
90
|
(value) =>
|
|
89
91
|
!props.children
|
|
90
|
-
?.map((child) => child.value
|
|
92
|
+
?.map((child) => child.value ?? child.label)
|
|
91
93
|
.includes(value),
|
|
92
94
|
);
|
|
93
95
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`FzCheckbox > renders correctly 1`] = `
|
|
4
|
-
"<div class="flex justify-center flex-col w-fit"><input type="checkbox" id="test" class="w-0 h-0 peer" value="test"><label for="test" class="flex items-start gap-4 hover:cursor-pointer
|
|
5
|
-
peer-focus:[&_div]:after:border-1
|
|
6
|
-
peer-focus:[&_div]:after:border-solid
|
|
7
|
-
peer-focus:[&_div]:after:rounded-[3px]
|
|
8
|
-
peer-focus:[&_div]:after:border-blue-500
|
|
9
|
-
peer-focus:[&_div]:after:content-['']
|
|
10
|
-
peer-focus:[&_div]:after:top-0
|
|
11
|
-
peer-focus:[&_div]:after:left-0
|
|
12
|
-
peer-focus:[&_div]:after:right-0
|
|
13
|
-
peer-focus:[&_div]:after:bottom-0
|
|
14
|
-
peer-focus:[&_div]:after:absolute text-md text-grey-500">
|
|
15
|
-
<div class="flex items-center justify-center w-[20px] h-[20px] relative mt-2 text-grey-500"><svg class="svg-inline--fa fa-square h-[16px]" aria-hidden="true" focusable="false" data-prefix="far" data-icon="square" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
|
16
|
-
<path class="" fill="currentColor" d="M384 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H384zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"></path>
|
|
17
|
-
</svg></div><span class="w-fit">Test Checkbox</span>
|
|
18
|
-
</label>
|
|
19
|
-
<!--v-if-->
|
|
20
|
-
</div>"
|
|
21
|
-
`;
|