Skip to content

Commit

Permalink
feat: add checkbox buttons and radio buttons components
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgrozav committed Jun 24, 2023
1 parent 2a3b8c9 commit a7e065c
Show file tree
Hide file tree
Showing 61 changed files with 2,129 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .storybook/preview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
@import '../src/components/ITabs/css/preview';
@import '../src/components/IToast/css/preview';
@import '../src/components/ITooltip/css/preview';
@import '../src/components/utils/ICheckableButtonGroup/css/preview';
@import '../src/css/preview';

#storybook-root {
Expand Down Expand Up @@ -52,6 +53,7 @@
@extend %button-preview;
@extend %button-group-preview;
@extend %card-preview;
@extend %checkable-button-group-preview;
@extend %collapsible-preview;
@extend %dropdown-preview;
@extend %hamburger-menu-preview;
Expand Down
25 changes: 14 additions & 11 deletions src/components/IButton/css/_component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,22 @@
&:focus,
&.-hovered,
&.-focused {
--button--background: var(--button--hover--background);
--button--border-color: var(--button--hover--border-color);

background: var(--button--hover--background, var(--button--background));
border-color: var(
--button--hover--border-color,
var(--button--hover--border-top-color, var(--button--border-top-color))
var(--button--hover--border-right-color, var(--button--border-right-color))
var(--button--hover--border-bottom-color, var(--button--border-bottom-color))
var(--button--hover--border-left-color, var(--button--border-left-color))
);
text-decoration: none;
color: var(--button--color);
outline: 0;
}

&:active,
&.-active {
--button--background: var(--button--active--background);
background: var(--button--active--background, var(--button--background));
}
}

Expand Down Expand Up @@ -148,7 +153,7 @@
background: transparent;
color: var(--button--background);
border-color: var(--button--background);
--button--box-shadow: none;
box-shadow: none;

&:not(:disabled, .-disabled) {
&:hover,
Expand All @@ -157,8 +162,7 @@
&.-hovered,
&.-focused,
&.-active {
--button--border-color: var(--button--hover--border-color);

border-color: var(--button--background);
background: var(--button--background);
color: var(--button--color);
}
Expand All @@ -167,8 +171,7 @@

// Circle button
&.-circle {
--button--border-radius: 100%;

border-radius: 50%;
width: var(--button--circle--size);
height: var(--button--circle--size);
padding: 0;
Expand All @@ -195,11 +198,11 @@
//

.button-group:not(.-vertical) > &:not(:first-of-type) {
--button--border-left-color: var(--button--hover--background);
border-left-color: var(--button--border-left-color);
}

.button-group.-vertical > &:not(:first-of-type) {
--button--border-top-color: var(--button--hover--background);
border-top-color: var(--button--border-top-color);
}
}

Expand Down
250 changes: 250 additions & 0 deletions src/components/ICheckboxButtons/ICheckboxButtons.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
<script lang="ts">
import { computed, defineComponent, inject, PropType, toRef } from 'vue';
import {
useComponentColor,
useComponentSize,
useValidation,
useFormValidationError
} from '@inkline/inkline/composables';
import { FormKey } from '@inkline/inkline/components/IForm/mixin';
import { FormGroupKey } from '@inkline/inkline/components/IFormGroup/mixin';
import { IButton } from '@inkline/inkline/components/IButton';
import { uid } from '@grozav/utils';
import {
IRenderResolver,
ICheckableButtonGroup,
CheckableButtonGroupOption,
CheckableButtonGroupVariant
} from '@inkline/inkline/components/utils';
const componentName = 'ICheckboxButtons';
export default defineComponent({
name: componentName,
components: {
IRenderResolver,
IButton,
ICheckableButtonGroup
},
inheritAttrs: false,
props: {
/**
* The color variant of the checkbox buttons
* @type light | dark
* @default
* @name color
*/
color: {
type: String,
default: undefined
},
/**
* The disabled state of the checkbox buttons
* @type Boolean
* @default false
* @name disabled
*/
disabled: {
type: Boolean,
default: false
},
/**
* The error state of the checkbox, computed based on schema by default.
* @type Boolean | Array
* @default ['touched', 'dirty', 'invalid']
* @TODO use propDefaultValue to set default value
* @name error
*/
error: {
type: [Array, Boolean] as PropType<boolean | string[]>,
default: () => ['touched', 'dirty', 'invalid']
},
/**
* Used to set the checkbox buttons value
* @default []
* @name modelValue
*/
modelValue: {
type: Array,
default: () => []
},
/**
* The unique identifier of the checkbox buttons
* @type String
* @default uid()
* @name name
*/
name: {
type: String,
default() {
return uid('checkbox-buttons');
}
},
/**
* The options to be rendered as checkbox buttons
*/
options: {
type: Array as PropType<CheckableButtonGroupOption[]>,
default: () => []
},
/**
* The readonly state of the checkbox buttons
* @type Boolean
* @default false
* @name readonly
*/
readonly: {
type: Boolean,
default: false
},
/**
* The size variant of the checkbox buttons
* @type sm | md | lg
* @default
* @name size
*/
size: {
type: String,
default: undefined
},
/**
* Enable checkbox buttons validation using schema
* @type Boolean
* @default true
* @name validate
*/
validate: {
type: Boolean,
default: true
},
/**
* The style variant of the checkbox buttons
* @type default | button-group
* @default default
* @name variant
*/
variant: {
type: String as PropType<CheckableButtonGroupVariant>,
default: 'default'
}
},
emits: [
/**
* Event emitted for setting the modelValue
* @event update:modelValue
*/
'update:modelValue'
],
setup(props, { emit }) {
const form = inject(FormKey, null);
const formGroup = inject(FormGroupKey, null);
const currentColor = computed(
() => props.color || formGroup?.color.value || form?.color.value
);
const currentSize = computed(() => props.size || formGroup?.size.value || form?.size.value);
const { color } = useComponentColor({ componentName, currentColor });
const { size } = useComponentSize({ componentName, currentSize });
const disabled = computed(
() => !!(props.disabled || formGroup?.disabled.value || form?.disabled.value)
);
const readonly = computed(
() => !!(props.readonly || formGroup?.readonly.value || form?.readonly.value)
);
const name = toRef(props, 'name');
const validate = toRef(props, 'validate');
const {
schema,
onInput: schemaOnInput,
onBlur: schemaOnBlur
} = useValidation({
name,
validate
});
const { hasError } = useFormValidationError({
schema,
error: props.error
});
const classes = computed(() => ({
[`-${color.value}`]: true,
[`-${size.value}`]: true,
'-disabled': disabled.value,
'-readonly': readonly.value,
'-error': hasError.value
}));
const value = computed(() => {
if (schema.value && validate.value) {
return schema.value.value;
}
return props.modelValue;
});
function onChange(value: string) {
let modelValue: any[] = [];
if (schema.value) {
modelValue = [...schema.value.value];
} else if (props.modelValue) {
modelValue = [...props.modelValue];
}
const valueIndex = modelValue.findIndex((v) => v === value);
if (valueIndex !== -1) {
modelValue.splice(valueIndex, 1);
} else {
modelValue.push(value);
}
schemaOnInput(props.name, modelValue);
emit('update:modelValue', modelValue);
}
function onBlur(event: FocusEvent) {
schemaOnBlur(props.name, event);
}
return {
classes,
value,
onChange,
onBlur
};
}
});
</script>

<template>
<ICheckableButtonGroup
v-bind="$attrs"
:class="classes"
:name="name"
:variant="variant"
class="checkbox-buttons"
type="checkbox"
role="checkboxgroup"
>
<IButton
v-for="option in options"
:key="`${name}/${option.id}`"
:disabled="option.disabled || option.readonly || readonly || disabled"
:active="value.includes(option.value)"
:color="color"
:size="size"
role="checkbox"
v-bind="option.buttonProps"
@click="onChange(option.value)"
@blur="onBlur"
>
<!-- @slot default Slot for rendering checkbox buttons options -->
<slot :option="option">
<IRenderResolver :data="option.label" />
</slot>
</IButton>
</ICheckableButtonGroup>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Components > ICheckboxButtons > should render correctly 1`] = `
"<div class=\\"checkable-button-group -light -md -checkbox -default -light -md checkbox-buttons\\" name=\\"checkbox-buttons\\" role=\\"checkboxgroup\\">
<!-- @slot default Slot for default content --><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 1</div>
</button><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 2</div>
</button><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 3</div>
</button>
</div>"
`;
exports[`Components > ICheckboxButtons > should render group variant correctly 1`] = `
"<div class=\\"checkable-button-group -light -md -checkbox -group -light -md checkbox-buttons button-group -md -light\\" name=\\"checkbox-buttons\\" role=\\"group\\">
<!-- @slot default Slot for default button group content --><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 1</div>
</button><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 2</div>
</button><button type=\\"button\\" tabindex=\\"0\\" aria-live=\\"polite\\" tag=\\"button\\" class=\\"button -light -md\\">
<!-- @slot loading Slot for button loading state -->
<!--v-if-->
<!-- @slot default Slot for default button content -->
<!-- @slot default Slot for rendering checkbox buttons options -->
<div>Option 3</div>
</button>
</div>"
`;
Loading

0 comments on commit a7e065c

Please sign in to comment.