From b1c71358842e3dbbf608c82f597a5466191a988f Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 5 Dec 2023 13:01:13 -0600 Subject: [PATCH] chore: init --- packages/vuetify/src/labs/VFab/VFab.sass | 59 +++++++++ packages/vuetify/src/labs/VFab/VFab.tsx | 118 ++++++++++++++++++ packages/vuetify/src/labs/VFab/_mixins.scss | 20 +++ .../vuetify/src/labs/VFab/_variables.scss | 20 +++ packages/vuetify/src/labs/VFab/index.ts | 1 + packages/vuetify/src/labs/components.ts | 1 + 6 files changed, 219 insertions(+) create mode 100644 packages/vuetify/src/labs/VFab/VFab.sass create mode 100644 packages/vuetify/src/labs/VFab/VFab.tsx create mode 100644 packages/vuetify/src/labs/VFab/_mixins.scss create mode 100644 packages/vuetify/src/labs/VFab/_variables.scss create mode 100644 packages/vuetify/src/labs/VFab/index.ts diff --git a/packages/vuetify/src/labs/VFab/VFab.sass b/packages/vuetify/src/labs/VFab/VFab.sass new file mode 100644 index 00000000000..02f68825a03 --- /dev/null +++ b/packages/vuetify/src/labs/VFab/VFab.sass @@ -0,0 +1,59 @@ +@use '../../styles/tools' +@use '../../styles/settings' +@use 'sass:math' +@use 'sass:map' +@use './variables' as * +@use './mixins' as * + +.v-fab + display: inline-flex + transition-duration: $fab-transition-duration + transition-timing-function: $fab-transition-timing-function + + .v-btn + @include tools.elevation(3) + + &--app + display: flex + + .v-btn + margin: 4px + + &--left, + &--right, + &--start, + &--end + flex-direction: column + + .v-btn--fab-center + margin-top: auto + margin-bottom: auto + + .v-btn--fab-start + margin-bottom: auto + + .v-btn--fab-end + margin-top: auto + + &--bottom, + &--top + flex-direction: row + + .v-btn--fab-center + margin-inline-start: auto + margin-inline-end: auto + + .v-btn--fab-start + margin-inline-end: auto + + .v-btn--fab-end + margin-inline-start: auto + + &--extended + .v-btn + // min-height: 56px + // min-width: 80px + border-radius: 9999px !important + + @at-root + @include fab-sizes() diff --git a/packages/vuetify/src/labs/VFab/VFab.tsx b/packages/vuetify/src/labs/VFab/VFab.tsx new file mode 100644 index 00000000000..bcee565b056 --- /dev/null +++ b/packages/vuetify/src/labs/VFab/VFab.tsx @@ -0,0 +1,118 @@ +// Styles +import './VFab.sass' + +// Components +import { makeVBtnProps, VBtn } from '@/components/VBtn/VBtn' + +// Composables +import { makeLayoutItemProps, useLayoutItem } from '@/composables/layout' +import { makeLocationProps, useLocation } from '@/composables/location' +import { useProxiedModel } from '@/composables/proxiedModel' +import { useResizeObserver } from '@/composables/resizeObserver' + +// Utilities +import { computed, onMounted, ref, shallowRef, toRef, toRefs, watch, watchEffect } from 'vue' +import { useRtl } from '../entry-bundler' +import { convertToUnit, genericComponent, propsFactory, toPhysical, useRender } from '@/util' + +// Types +import type { PropType } from 'vue' + +const locations = ['start', 'end', 'left', 'right', 'top', 'bottom'] as const + +export const makeVFabProps = propsFactory({ + app: { + type: String as PropType, + validator: (value: any) => locations.includes(value), + }, + extended: Boolean, + modelValue: { + type: Boolean, + default: true, + }, + + ...makeVBtnProps(), + ...makeLayoutItemProps(), + + location: { + type: String as PropType, + default: 'bottom', + validator: (value: any) => locations.includes(value), + }, +}, 'VFab') + +export const VFab = genericComponent()({ + name: 'VFab', + + props: makeVFabProps(), + + emits: { + 'update:modelValue': (value: boolean) => true, + }, + + setup (props, { slots }) { + const isActive = useProxiedModel(props, 'modelValue') + const { isRtl } = useRtl() + const height = shallowRef(56) + const { resizeRef } = useResizeObserver(entries => { + if (!entries.length) return + height.value = entries[0].target.clientHeight + }) + const position = computed(() => { + return toPhysical(props.app, isRtl.value) as 'top' | 'right' | 'bottom' | 'left' + }) + const { layoutItemStyles } = useLayoutItem({ + id: props.name, + order: computed(() => parseInt(props.order, 10)), + position, + layoutSize: height, + elementSize: computed(() => height.value + 8), + active: computed(() => !!props.app && isActive.value), + absolute: toRef(props, 'absolute'), + }) + + const vFabRef = ref() + + useRender(() => { + const btnProps = VBtn.filterProps(props) + + return ( +
+ +
+ ) + }) + + return {} + }, +}) diff --git a/packages/vuetify/src/labs/VFab/_mixins.scss b/packages/vuetify/src/labs/VFab/_mixins.scss new file mode 100644 index 00000000000..45f14739642 --- /dev/null +++ b/packages/vuetify/src/labs/VFab/_mixins.scss @@ -0,0 +1,20 @@ +@use 'sass:math'; +@use 'sass:map'; +@use 'sass:meta'; +@use '../../styles/settings'; +@use '../../styles/tools'; +@use './variables' as *; + +@mixin fab-sizes ($immediate: false) { + @each $sizeName, $multiplier in $fab-size-scales { + $size: $fab-font-size + math.div(2 * $multiplier, 16); + $height: $fab-height + (settings.$size-scale * $multiplier); + + .v-fab .v-btn--size-#{$sizeName} { + --v-btn-size: #{$size}; + --v-btn-height: #{$height}; + + border-radius: math.round($fab-border-radius + ($fab-border-radius-multiplier * $multiplier)); + } + } +} diff --git a/packages/vuetify/src/labs/VFab/_variables.scss b/packages/vuetify/src/labs/VFab/_variables.scss new file mode 100644 index 00000000000..aaf70c1083a --- /dev/null +++ b/packages/vuetify/src/labs/VFab/_variables.scss @@ -0,0 +1,20 @@ +@use 'sass:math'; +@use 'sass:map'; +@use '../../styles/settings'; +@use '../../styles/tools'; + +$fab-border-radius: map.get(settings.$rounded, 'circle') !default; +$fab-border-radius-multiplier: 0 !default; // 2.4 for MD3 +$fab-height: 44px !default; +$fab-font-size: tools.map-deep-get(settings.$typography, 'button', 'size') !default; +$fab-font-weight: tools.map-deep-get(settings.$typography, 'button', 'weight') !default; +$fab-transition-duration: 0.2s !default; +$fab-transition-timing-function: settings.$standard-easing !default; + +$fab-size-scales: ( + 'x-small': -2, + 'small': -1, + 'default': 0, + 'large': 2, + 'x-large': 5 +) !default; diff --git a/packages/vuetify/src/labs/VFab/index.ts b/packages/vuetify/src/labs/VFab/index.ts new file mode 100644 index 00000000000..a2c3347dfea --- /dev/null +++ b/packages/vuetify/src/labs/VFab/index.ts @@ -0,0 +1 @@ +export { VFab } from './VFab' diff --git a/packages/vuetify/src/labs/components.ts b/packages/vuetify/src/labs/components.ts index 7ac16f64688..7a646cf9ba4 100644 --- a/packages/vuetify/src/labs/components.ts +++ b/packages/vuetify/src/labs/components.ts @@ -1,3 +1,4 @@ export * from './VConfirmEdit' export * from './VCalendar' +export * from './VFab' export * from './VPicker'