Skip to content

Commit

Permalink
feat(input): add disabled prop to checkboxes and radios (#333) (#334)
Browse files Browse the repository at this point in the history
close #333
  • Loading branch information
brc-dd committed Aug 29, 2023
1 parent daa8905 commit 332cc10
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 20 deletions.
14 changes: 14 additions & 0 deletions docs/components/input-checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ interface Props {
/>
```

### `:disabled`

Mark input as disabled. When this prop is set, users may not be able to focus the element not trigger any events.

```ts
interface Props {
disabled?: boolean
}
```

```vue-html
<SInputCheckbox disabled v-model="..." />
```

### `:value`

Sets the input value. When `model-value` prop is set (e.g. via `v-model` directive), this prop gets ignored.
Expand Down
19 changes: 19 additions & 0 deletions docs/components/input-checkboxes.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ interface Props {
export interface Option {
label: string
value: string | number | boolean
disabled?: boolean
}
```

Expand Down Expand Up @@ -222,6 +223,24 @@ interface Props {
/>
```

### `:disabled`

Mark input as disabled. When this prop is set, users may not be able to focus the element not trigger any events.

```ts
interface Props {
disabled?: boolean
}
```

```vue-html
<SInputCheckboxes
:options="[...]"
disabled
v-model="..."
/>
```

### `:value`

Sets the input value. When `model-value` prop is set (e.g. via `v-model` directive), this prop gets ignored.
Expand Down
19 changes: 19 additions & 0 deletions docs/components/input-radios.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ interface Props {
export interface Option {
label: string
value: string | number | boolean
disabled?: boolean
}
```

Expand Down Expand Up @@ -223,6 +224,24 @@ interface Props {
/>
```

### `:disabled`

Mark input as disabled. When this prop is set, users may not be able to focus the element not trigger any events.

```ts
interface Props {
disabled?: boolean
}
```

```vue-html
<SInputRadios
:options="[...]"
disabled
v-model="..."
/>
```

### `:value`

Sets the input value. When `model-value` prop is set (e.g. via `v-model` directive), this prop gets ignored.
Expand Down
34 changes: 30 additions & 4 deletions lib/components/SInputCheckbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const props = withDefaults(defineProps<{
checkText?: string
checkColor?: Color
text?: string
disabled?: boolean
value?: boolean
modelValue?: boolean
validation?: Validatable
Expand All @@ -33,22 +34,29 @@ const emit = defineEmits<{
(e: 'change', value: boolean): void
}>()
const classes = computed(() => [
props.size ?? 'small',
{ disabled: props.disabled }
])
const _value = computed(() => {
return props.modelValue !== undefined
? props.modelValue
: props.value !== undefined ? props.value : false
})
function onClick() {
emit('update:model-value', !_value.value)
emit('change', !_value.value)
if (!props.disabled) {
emit('update:model-value', !_value.value)
emit('change', !_value.value)
}
}
</script>

<template>
<SInputBase
class="SInputCheckbox"
:class="[size ?? 'small']"
:class="classes"
:label="label"
:note="note"
:info="info"
Expand All @@ -59,7 +67,13 @@ function onClick() {
:validation="validation"
>
<div class="container">
<div class="input" :class="{ on: _value }" role="button" @click="onClick">
<div
class="input"
:class="{ on: _value }"
role="button"
@click="onClick"
:aria-disabled="disabled"
>
<div class="box">
<div class="check">
<SIcon :icon="IconCheck" class="check-icon" />
Expand Down Expand Up @@ -139,4 +153,16 @@ function onClick() {
font-size: 14px;
font-weight: 400;
}
.SInputCheckbox.disabled {
.box {
border-color: var(--input-disabled-border-color);
background-color: var(--input-disabled-bg-color);
&:hover { border-color: var(--input-disabled-border-color); }
&:focus:not(:focus-visible) { border-color: var(--input-disabled-border-color); }
}
.input { cursor: not-allowed; }
}
</style>
3 changes: 3 additions & 0 deletions lib/components/SInputCheckboxes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Value = string | number | boolean
export interface Option {
label: string
value: Value
disabled?: boolean
}
const props = withDefaults(defineProps<{
Expand All @@ -27,6 +28,7 @@ const props = withDefaults(defineProps<{
checkColor?: Color
options: Option[]
nullable?: boolean
disabled?: boolean
value?: Value[]
modelValue?: Value[]
validation?: Validatable
Expand Down Expand Up @@ -82,6 +84,7 @@ function handleChange(value: Value): void {
<div v-for="option in options" :key="String(option.value)" class="col">
<SInputCheckbox
:text="option.label"
:disabled="option.disabled ?? disabled"
:model-value="isChecked(option.value)"
@update:model-value="handleChange(option.value)"
/>
Expand Down
36 changes: 31 additions & 5 deletions lib/components/SInputRadio.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { type IconifyIcon } from '@iconify/vue/dist/offline'
import { type DefineComponent } from 'vue'
import { type DefineComponent, computed } from 'vue'
import { type Validatable } from '../composables/Validation'
import SInputBase from './SInputBase.vue'
Expand All @@ -18,6 +18,7 @@ const props = defineProps<{
checkText?: string
checkColor?: Color
text: string
disabled?: boolean
modelValue: boolean
validation?: Validatable
hideError?: boolean
Expand All @@ -28,16 +29,23 @@ const emit = defineEmits<{
(e: 'change', value: boolean): void
}>()
const classes = computed(() => [
props.size ?? 'small',
{ disabled: props.disabled }
])
function onClick() {
emit('update:model-value', !props.modelValue)
emit('change', !props.modelValue)
if (!props.disabled) {
emit('update:model-value', !props.modelValue)
emit('change', !props.modelValue)
}
}
</script>

<template>
<SInputBase
class="SInputRadio"
:class="[size ?? 'small']"
:class="classes"
:label="label"
:note="note"
:info="info"
Expand All @@ -49,7 +57,13 @@ function onClick() {
:hide-error="hideError"
>
<div class="container">
<div class="input" :class="{ on: props.modelValue }" role="button" @click="onClick">
<div
class="input"
:class="{ on: props.modelValue }"
role="button"
@click="onClick"
:aria-disabled="disabled"
>
<div class="box">
<div class="check" />
</div>
Expand Down Expand Up @@ -125,4 +139,16 @@ function onClick() {
font-size: 14px;
font-weight: 400;
}
.SInputRadio.disabled {
.box {
border-color: var(--input-disabled-border-color);
background-color: var(--input-disabled-bg-color);
&:hover { border-color: var(--input-disabled-border-color); }
&:focus:not(:focus-visible) { border-color: var(--input-disabled-border-color); }
}
.input { cursor: not-allowed; }
}
</style>
3 changes: 3 additions & 0 deletions lib/components/SInputRadios.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'dange
export interface Option {
label: string
value: string | number | boolean
disabled?: boolean
}
const props = withDefaults(defineProps<{
Expand All @@ -26,6 +27,7 @@ const props = withDefaults(defineProps<{
checkColor?: Color
options: Option[]
nullable?: boolean
disabled?: boolean
value?: string | number | boolean | null
modelValue?: string | number | boolean | null
validation?: Validatable
Expand Down Expand Up @@ -92,6 +94,7 @@ function onChange(value: string | number | boolean) {
<div v-for="(option, index) in options" :key="index" class="col">
<SInputRadio
:text="option.label"
:disabled="option.disabled ?? disabled"
:model-value="isChecked(option.value)"
@update:model-value="onUpdate(option.value)"
@change="onChange(option.value)"
Expand Down
6 changes: 6 additions & 0 deletions stories/components/SInputCheckbox.01_Playground.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function state() {
note: 'Note text',
help: 'This is a help text.',
text: 'Text for the checkbox',
disabled: false,
error: false
}
}
Expand Down Expand Up @@ -52,6 +53,10 @@ function state() {
title="text"
v-model="state.text"
/>
<HstCheckbox
title="disabled"
v-model="state.disabled"
/>
<HstCheckbox
title="error"
v-model="state.error"
Expand All @@ -68,6 +73,7 @@ function state() {
:note="state.note"
:help="state.help"
:text="state.text"
:disabled="state.disabled"
v-model="value"
/>
</Board>
Expand Down
6 changes: 6 additions & 0 deletions stories/components/SInputCheckboxes.01_Playground.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function state() {
help: 'This is a help text.',
text: 'Text for the checkbox',
nullable: true,
disabled: false,
error: false
}
}
Expand Down Expand Up @@ -63,6 +64,10 @@ function state() {
title="nullable"
v-model="state.nullable"
/>
<HstCheckbox
title="disabled"
v-model="state.disabled"
/>
<HstCheckbox
title="error"
v-model="state.error"
Expand All @@ -80,6 +85,7 @@ function state() {
:help="state.help"
:options="options"
:nullable="state.nullable"
:disabled="state.disabled"
v-model="input"
/>
</Board>
Expand Down
5 changes: 5 additions & 0 deletions stories/components/SInputRadios.01_Playground.story.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ function state() {
title="help"
v-model="state.help"
/>
<HstCheckbox
title="disabled"
v-model="state.disabled"
/>
<HstCheckbox
title="nullable"
v-model="state.nullable"
Expand All @@ -75,6 +79,7 @@ function state() {
:note="state.note"
:help="state.help"
:nullable="state.nullable"
:disabled="state.disabled"
:options="options"
v-model="value"
/>
Expand Down
16 changes: 15 additions & 1 deletion tests/components/SInputCheckbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils'
import SInputCheckbox from 'sefirot/components/SInputCheckbox.vue'
import { assertEmitted } from 'tests/Utils'
import { assertEmitted, assertNotEmitted } from 'tests/Utils'

describe('components/SInputCheckbox', () => {
test('accepts `:value`', async () => {
Expand Down Expand Up @@ -41,4 +41,18 @@ describe('components/SInputCheckbox', () => {
assertEmitted(wrapper, 'update:model-value', 1, true)
assertEmitted(wrapper, 'change', 1, true)
})

test('does not emit on click when `:disabled`', async () => {
const wrapper = mount(SInputCheckbox, {
props: {
value: false,
disabled: true
}
})

await wrapper.find('.SInputCheckbox .input').trigger('click')

assertNotEmitted(wrapper, 'update:model-value')
assertNotEmitted(wrapper, 'change')
})
})

0 comments on commit 332cc10

Please sign in to comment.