Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Toggle): add size prop #950

Merged
merged 2 commits into from Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/content/3.forms/7.toggle.md
Expand Up @@ -26,6 +26,17 @@ props:
---
::

### Size

Use the `size` prop to change the size of the Toggle.

::component-card
---
props:
size: 'md'
---
::

### Icon

Use any icon from [Iconify](https://icones.js.org) by setting the `on-icon` and `off-icon` props by using this pattern: `i-{collection_name}-{icon_name}` or change it globally in `ui.toggle.default.onIcon` and `ui.toggle.default.offIcon`.
Expand Down
21 changes: 20 additions & 1 deletion src/runtime/components/forms/Toggle.vue
Expand Up @@ -7,7 +7,7 @@
:class="switchClass"
v-bind="attrs"
>
<span :class="[active ? ui.container.active : ui.container.inactive, ui.container.base]">
<span :class="containerClass">
<span v-if="onIcon" :class="[active ? ui.icon.active : ui.icon.inactive, ui.icon.base]" aria-hidden="true">
<UIcon :name="onIcon" :class="onIconClass" />
</span>
Expand Down Expand Up @@ -77,6 +77,13 @@ export default defineComponent({
type: [String, Object, Array] as PropType<any>,
default: undefined
},
size: {
type: String as PropType<keyof typeof config.size>,
default: config.default.size,
validator (value: string) {
return Object.keys(config.size).includes(value)
}
},
ui: {
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
default: undefined
Expand All @@ -101,20 +108,31 @@ export default defineComponent({
const switchClass = computed(() => {
return twMerge(twJoin(
ui.value.base,
ui.value.size[props.size],
ui.value.rounded,
ui.value.ring.replaceAll('{color}', color.value),
(active.value ? ui.value.active : ui.value.inactive).replaceAll('{color}', color.value)
), props.class)
})

const containerClass = computed(() => {
return twJoin(
ui.value.container.base,
ui.value.container.size[props.size],
(active.value ? ui.value.container.active[props.size] : ui.value.container.inactive)
)
})

const onIconClass = computed(() => {
return twJoin(
ui.value.icon.size[props.size],
ui.value.icon.on.replaceAll('{color}', color.value)
)
})

const offIconClass = computed(() => {
return twJoin(
ui.value.icon.size[props.size],
ui.value.icon.off.replaceAll('{color}', color.value)
)
})
Expand All @@ -128,6 +146,7 @@ export default defineComponent({
inputId,
active,
switchClass,
containerClass,
onIconClass,
offIconClass
}
Expand Down
50 changes: 43 additions & 7 deletions src/runtime/ui.config.ts
Expand Up @@ -802,27 +802,63 @@ export const checkbox = {
}

export const toggle = {
base: 'relative inline-flex h-5 w-9 flex-shrink-0 border-2 border-transparent disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none',
base: 'relative inline-flex flex-shrink-0 border-2 border-transparent disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none',
rounded: 'rounded-full',
ring: 'focus-visible:ring-2 focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-900',
active: 'bg-{color}-500 dark:bg-{color}-400',
inactive: 'bg-gray-200 dark:bg-gray-700',
size: {
'2xs': 'h-3 w-5',
xs: 'h-3.5 w-6',
sm: 'h-4 w-7',
md: 'h-5 w-9',
lg: 'h-6 w-11',
xl: 'h-7 w-[3.25rem]',
'2xl': 'h-8 w-[3.75rem]'
},
container: {
base: 'pointer-events-none relative inline-block h-4 w-4 rounded-full bg-white dark:bg-gray-900 shadow transform ring-0 transition ease-in-out duration-200',
active: 'translate-x-4 rtl:-translate-x-4',
inactive: 'translate-x-0 rtl:-translate-x-0'
base: 'pointer-events-none relative inline-block rounded-full bg-white dark:bg-gray-900 shadow transform ring-0 transition ease-in-out duration-200',
active: {
'2xs': 'translate-x-2 rtl:-translate-x-2',
xs: 'translate-x-2.5 rtl:-translate-x-2.5',
sm: 'translate-x-3 rtl:-translate-x-3',
md: 'translate-x-4 rtl:-translate-x-4',
lg: 'translate-x-5 rtl:-translate-x-5',
xl: 'translate-x-6 rtl:-translate-x-6',
'2xl': 'translate-x-7 rtl:-translate-x-7'
},
inactive: 'translate-x-0 rtl:-translate-x-0',
size: {
'2xs': 'h-2 w-2',
xs: 'h-2.5 w-2.5',
sm: 'h-3 w-3',
md: 'h-4 w-4',
lg: 'h-5 w-5',
xl: 'h-6 w-6',
'2xl': 'h-7 w-7'
}
},
icon: {
base: 'absolute inset-0 h-full w-full flex items-center justify-center transition-opacity',
active: 'opacity-100 ease-in duration-200',
inactive: 'opacity-0 ease-out duration-100',
on: 'h-3 w-3 text-{color}-500 dark:text-{color}-400',
off: 'h-3 w-3 text-gray-400 dark:text-gray-500'
size: {
'2xs': 'h-2 w-2',
xs: 'h-2 w-2',
sm: 'h-2 w-2',
md: 'h-3 w-3',
lg: 'h-4 w-4',
xl: 'h-5 w-5',
'2xl': 'h-6 w-6'
},
on: 'text-{color}-500 dark:text-{color}-400',
off: 'text-gray-400 dark:text-gray-500'
},
default: {
onIcon: null,
offIcon: null,
color: 'primary'
color: 'primary',
size: 'md'
}
}

Expand Down