Skip to content

Commit

Permalink
fix(VsCheckboxNode): replace checkbox node icon with clip-path (#289)
Browse files Browse the repository at this point in the history
  • Loading branch information
smithoo authored Nov 20, 2024
1 parent c34452c commit dd444b0
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 179 deletions.
10 changes: 6 additions & 4 deletions packages/vlossom/playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
<vs-layout>
<vs-header
class="header"
position="fixed"
fixed
primary
height="60px"
height="72px"
:style-set="{ backgroundColor: 'black', fontColor: 'white' }"
:style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }"
>
<div class="logo">
<vs-image src="/assets/vlossom-logo.png" :style-set="{ height: '40px', width: '40px' }" />
Expand All @@ -21,8 +22,9 @@
<vs-footer
class="footer"
:style-set="{ backgroundColor: 'black', fontColor: '#dfdfdf' }"
height="30px"
position="fixed"
height="40px"
fixed
:style="{ display: 'flex', justifyContent: 'center', alignItems: 'center' }"
>
<span>&copy; {{ currentYear }} Vlossom</span>
</vs-footer>
Expand Down
1 change: 1 addition & 0 deletions packages/vlossom/src/components/vs-table/VsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
:id="utils.string.createID()"
type="checkbox"
:color-scheme="computedColorScheme"
:indeterminate="!isSelectedAll && selectedItems.length > 0"
:checked="isSelectedAll"
aria-label="select-all"
@toggle="onToggleCheck"
Expand Down
15 changes: 0 additions & 15 deletions packages/vlossom/src/icons/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,6 @@ export const iconSvgs = {
<path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/>
</svg>
`,
// check_box (fill)
checkboxChecked: `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
<path d="m424-312 282-282-56-56-226 226-114-114-56 56 170 170ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"/>
</svg>`,
// indeterminate_check_box (fill)
checkboxIndeterminate: `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
<path d="M280-440h400v-80H280v80Zm-80 320q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"/>
</svg>`,
// check_box_outline_blank
checkboxUnchecked: `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
<path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Z"/>
</svg>`,
close: `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
<path
Expand Down
107 changes: 71 additions & 36 deletions packages/vlossom/src/nodes/vs-checkbox-node/VsCheckboxNode.scss
Original file line number Diff line number Diff line change
@@ -1,75 +1,110 @@
@use '@/styles/mixin' as *;

$checkbox-size: var(--vs-checkbox-node-checkboxSize, 2.4rem);
$checkbox-size: var(--vs-checkbox-node-checkboxSize, 2rem);

.vs-checkbox-node {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: nowrap;
user-select: none;
height: var(--vs-checkbox-node-height, var(--vs-input-comp-height));
min-height: var(--vs-checkbox-node-height, var(--vs-input-comp-height));

.vs-checkbox-wrap {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
color: var(--vs-checkbox-node-checkboxColor, var(--vs-primary-comp-bg));
border-radius: var(--vs-checkbox-node-borderRadius, calc(var(--vs-radius-ratio) * var(--vs-radius-sm)));
overflow: hidden;
flex-wrap: nowrap;
user-select: none;

.vs-check-icon {
.vs-checkbox-input {
display: flex;
align-items: center;
justify-content: center;
appearance: none;
margin: 0;
width: $checkbox-size;
height: $checkbox-size;
border: 0.1rem solid var(--vs-checkbox-node-checkboxColor, var(--vs-primary-comp-bg));
border-radius: var(--vs-checkbox-node-borderRadius, calc(var(--vs-radius-ratio) * var(--vs-radius-sm)));
cursor: pointer;
background-color: transparent;

&.vs-state-box {
@include state-box;
}

&:focus-within {
@include focus-outline;
}

&:before {
content: '';
display: block;
width: calc($checkbox-size * 0.6);
height: calc($checkbox-size * 0.6);
transform: scale(0);
transform-origin: center center;
transition: 120ms all linear;
}
}

.vs-checkbox-input {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 100%;
height: 100%;
.vs-checkbox-label {
user-select: none;
padding-left: 0.5rem;
cursor: pointer;
white-space: nowrap;
color: var(--vs-checkbox-node-labelFontColor, var(--vs-font-color));
font-size: var(--vs-checkbox-node-labelFontSize, var(--vs-font-size));
}
}

&.vs-state-box {
@include state-box;
outline-offset: 0;
}
&.vs-indeterminate {
.vs-checkbox-wrap {
.vs-checkbox-input {
background-color: var(--vs-checkbox-node-checkboxColor, var(--vs-primary-comp-bg));

&:focus-within {
@include focus-outline;
outline-offset: 0;
&:before {
clip-path: polygon(0% 38%, 100% 38%, 100% 62%, 0% 62%);
background-color: var(--vs-primary-comp-font);
transform: scale(1);
}
}
}
}

.vs-checkbox-label {
user-select: none;
padding-left: 0.5rem;
cursor: pointer;
white-space: nowrap;
color: var(--vs-checkbox-node-labelFontColor, var(--vs-font-color));
font-size: var(--vs-checkbox-node-labelFontSize, var(--vs-font-size));
&.vs-checked {
.vs-checkbox-wrap {
.vs-checkbox-input {
background-color: var(--vs-checkbox-node-checkboxColor, var(--vs-primary-comp-bg));

&:before {
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
background-color: var(--vs-primary-comp-font);
transform: scale(1) rotate(10deg) translateX(-3%);
}
}
.vs-checkbox-label {
color: var(--vs-checkbox-node-selectedLabelFontColor, var(--vs-primary-comp-bg));
}
}
}

&.vs-dense {
height: var(--vs-checkbox-node-height, var(--vs-input-comp-height-dense));
min-height: var(--vs-checkbox-node-height, var(--vs-input-comp-height-dense));

.vs-checkbox-label {
font-size: var(--vs-checkbox-node-labelFontSize, var(--vs-font-size-sm));
.vs-checkbox-input {
width: var(--vs-checkbox-node-checkboxSize, 1.8rem);
height: var(--vs-checkbox-node-checkboxSize, 1.8rem);
}
}

&.vs-checked {
.vs-checkbox-label {
color: var(--vs-checkbox-node-selectedLabelFontColor, var(--vs-primary-comp-bg));
font-size: var(--vs-checkbox-node-labelFontSize, var(--vs-font-size-sm));
}
}

&.vs-disabled {
@include disabled;
cursor: default;
}

&.vs-readonly {
Expand Down
41 changes: 15 additions & 26 deletions packages/vlossom/src/nodes/vs-checkbox-node/VsCheckboxNode.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
<template>
<div :class="['vs-checkbox-node', colorSchemeClass, classObj]" :style="computedStyleSet">
<div :class="['vs-checkbox-wrap', stateClasses]">
<vs-icon class="vs-check-icon" :icon="icon" />
<label class="vs-checkbox-wrap" :for="computedId">
<input
ref="checkboxRef"
type="checkbox"
class="vs-checkbox-input"
:class="['vs-checkbox-input', stateClasses]"
:aria-label="ariaLabel"
:id="id"
:id="computedId"
:disabled="disabled || readonly"
:name="name"
:value="convertToString(value)"
:checked="checked"
:aria-required="required"
@click.prevent.stop="onClick"
@click.prevent.stop="toggle"
@focus.stop="onFocus"
@blur.stop="onBlur"
/>
</div>
<label v-if="label || $slots['label']" :for="id" class="vs-checkbox-label">
<slot name="label">{{ label }}</slot>
<div v-if="label || $slots['label']" class="vs-checkbox-label">
<slot name="label">{{ label }}</slot>
</div>
</label>
</div>
</template>
Expand All @@ -29,21 +28,19 @@ import { computed, defineComponent, nextTick, PropType, Ref, ref, toRefs, watch
import { ColorScheme, UIState, VsNode } from '@/declaration';
import { useColorScheme, useStateClass, useStyleSet } from '@/composables';
import { utils } from '@/utils';
import { VsIcon } from '@/icons';
import { VsCheckboxNodeStyleSet } from './types';
const name = VsNode.VsCheckboxNode;
export default defineComponent({
name,
components: { VsIcon },
props: {
colorScheme: { type: String as PropType<ColorScheme> },
styleSet: { type: [String, Object] as PropType<string | VsCheckboxNodeStyleSet> },
ariaLabel: { type: String, default: '' },
checked: { type: Boolean, default: false },
dense: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
id: { type: String, required: true },
id: { type: String, default: '' },
indeterminate: { type: Boolean, default: false },
label: { type: String, default: '' },
name: { type: String, default: '' },
Expand All @@ -55,7 +52,7 @@ export default defineComponent({
emits: ['change', 'toggle', 'focus', 'blur'],
// expose: ['focus', 'blur'],
setup(props, { emit }) {
const { colorScheme, styleSet, checked, indeterminate, dense, disabled, readonly, state } = toRefs(props);
const { colorScheme, styleSet, checked, id, indeterminate, dense, disabled, readonly, state } = toRefs(props);
const { colorSchemeClass } = useColorScheme(name, colorScheme);
Expand All @@ -70,21 +67,13 @@ export default defineComponent({
'vs-dense': dense.value,
'vs-disabled': disabled.value,
'vs-readonly': readonly.value,
'vs-indeterminate': indeterminate.value,
}));
const icon = computed(() => {
if (checked.value) {
return 'checkboxChecked';
}
const innerId = utils.string.createID();
const computedId = computed(() => id.value || innerId);
if (indeterminate.value) {
return 'checkboxIndeterminate';
}
return 'checkboxUnchecked';
});
function onClick(event: Event) {
function toggle(event: Event) {
emit('change', event);
emit('toggle', !checked.value);
}
Expand Down Expand Up @@ -121,15 +110,15 @@ export default defineComponent({
checkboxRef,
colorSchemeClass,
classObj,
icon,
onClick,
onFocus,
onBlur,
focus,
blur,
convertToString: utils.string.convertToString,
stateClasses,
computedStyleSet,
computedId,
toggle,
};
},
});
Expand Down
Loading

0 comments on commit dd444b0

Please sign in to comment.