From 926dfa128664f0c3c3732292d4f484f398731c64 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Mon, 4 Aug 2025 18:22:32 -0400 Subject: [PATCH 01/88] refactor: refactored layout to be a plugin --- .../0/src/composables/useLayout/index.test.ts | 10 ++-- packages/0/src/composables/useLayout/index.ts | 53 ++++++++++++++++--- playground/src/composables.d.ts | 4 +- playground/src/plugins/index.ts | 3 ++ 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.test.ts b/packages/0/src/composables/useLayout/index.test.ts index 13f000a7..3d78cfa9 100644 --- a/packages/0/src/composables/useLayout/index.test.ts +++ b/packages/0/src/composables/useLayout/index.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' -import { useLayout } from './index.ts' +import { createLayout } from './index.ts' import { mount } from '@vue/test-utils' import { defineComponent } from 'vue' @@ -25,7 +25,7 @@ describe('useLayout inside component', () => { it('registers height and width in browser', () => { const testComponent = defineComponent({ setup () { - const context = useLayout() + const context = createLayout() return { context } }, template: '
', @@ -42,7 +42,7 @@ describe('useLayout inside component', () => { it('correctly calculates main', () => { const testComponent = defineComponent({ setup () { - const context = useLayout() + const context = createLayout() return { context } }, template: '
', @@ -62,7 +62,7 @@ describe('useLayout inside component', () => { describe('useLayout outside component', () => { it('registers components', () => { - const context = useLayout() + const context = createLayout() context.register({ id: 'Component1', position: 'top', value: 32 }) context.register({ id: 'Component2', position: 'bottom', value: 64 }) expect(context.collection.has('Component1')).toEqual(true) @@ -70,7 +70,7 @@ describe('useLayout outside component', () => { }) it('calculates bound', () => { - const context = useLayout() + const context = createLayout() context.register({ id: 'Component1', position: 'top', value: 32 }) context.register({ id: 'Component2', position: 'bottom', value: 128 }) context.register({ id: 'Component3', position: 'left', value: 64 }) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index 00ed1e31..c4b7f4d3 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -1,3 +1,7 @@ +// Factories +import { createPlugin } from '#v0/factories/createPlugin' +import { createContext } from '#v0/factories/createContext' + // Composables import { useGroup } from '#v0/composables/useGroup' @@ -8,7 +12,7 @@ import { computed, shallowReactive, shallowRef, onUnmounted, onMounted, getCurre import { IN_BROWSER } from '#v0/constants/globals.ts' // Types -import type { ComputedRef, ShallowReactive, ShallowRef } from 'vue' +import type { ComputedRef, ShallowReactive, ShallowRef, App } from 'vue' import type { GroupContext, GroupOptions, GroupTicket } from '#v0/composables/useGroup' import type { ID } from '#v0/types' @@ -36,11 +40,16 @@ export interface LayoutContext extends GroupContext { sizes: ShallowReactive> height: ShallowRef width: ShallowRef + resize: () => void } export interface LayoutOptions extends GroupOptions {} -export function useLayout< +export interface LayoutPlugin { + install: (app: App, ...options: any[]) => any +} + +export function createLayout< Z extends LayoutTicket = LayoutTicket, E extends LayoutContext = LayoutContext, > (_options: LayoutOptions = {}): E { @@ -94,12 +103,12 @@ export function useLayout< return ticket } - if (IN_BROWSER && getCurrentInstance()) { - function resize () { - height.value = window.innerHeight - width.value = window.innerWidth - } + function resize () { + height.value = window.innerHeight + width.value = window.innerWidth + } + if (IN_BROWSER && getCurrentInstance()) { onMounted(() => { resize() window.addEventListener('resize', resize) @@ -122,5 +131,35 @@ export function useLayout< sizes, height, width, + resize, } as E } + +/** + * Creates a Vue plugin for managing responsive layout with automatic updates. + * This plugin sets up layout tracking and updates the context when the window + * is resized, providing reactive layout state throughout the application. + * + * @param options Optional configuration for toggling layout items on automatically and + * allowing events to be called. + * @returns A Vue plugin object with install method. + */ + +export const [useLayout, provideLayout] = createContext('v0:layout') + +export function createLayoutPlugin (options: LayoutOptions = {}): LayoutPlugin { + const layout = createLayout(options) + + return createPlugin({ namespace: 'v0:layout', + provide: (app: App) => { + provideLayout(layout, app) + }, + setup: (app: App) => { + app.mixin({ + mounted () { + layout.resize() + }, + }) + }, + }) +} diff --git a/playground/src/composables.d.ts b/playground/src/composables.d.ts index dfe59dd0..3c1d6fb4 100644 --- a/playground/src/composables.d.ts +++ b/playground/src/composables.d.ts @@ -37,6 +37,7 @@ declare global { const createGroupContext: typeof import('../../packages/0/src/composables/useGroup/index')['createGroupContext'] const createHydration: typeof import('../../packages/0/src/composables/useHydration/index')['createHydration'] const createHydrationPlugin: typeof import('../../packages/0/src/composables/useHydration/index')['createHydrationPlugin'] + const createLayoutPlugin: typeof import('../../packages/0/src/composables/useLayout/index')['createLayoutPlugin'] const createLocale: typeof import('../../packages/0/src/composables/useLocale/index')['createLocale'] const createLocalePlugin: typeof import('../../packages/0/src/composables/useLocale/index')['createLocalePlugin'] const createLogger: typeof import('../../packages/0/src/composables/useLogger/index')['createLogger'] @@ -217,7 +218,7 @@ declare global { export type { KeyHandler } from '../../packages/0/src/composables/useKeydown/index' import('../../packages/0/src/composables/useKeydown/index') // @ts-ignore - export type { LayoutLocation, LayoutTicket, LayoutContext } from '../../packages/0/src/composables/useLayout/index' + export type { LayoutLocation, LayoutTicket, LayoutContext, LayoutOptions, LayoutPlugin } from '../../packages/0/src/composables/useLayout/index' import('../../packages/0/src/composables/useLayout/index') // @ts-ignore export type { LocaleTicket, LocaleContext, LocaleOptions, LocalePluginOptions, LocalePlugin } from '../../packages/0/src/composables/useLocale/index' @@ -282,6 +283,7 @@ declare module 'vue' { readonly createElevation: UnwrapRef readonly createHydration: UnwrapRef readonly createHydrationPlugin: UnwrapRef + readonly createLayoutPlugin: UnwrapRef readonly createLocale: UnwrapRef readonly createLocalePlugin: UnwrapRef readonly createLogger: UnwrapRef diff --git a/playground/src/plugins/index.ts b/playground/src/plugins/index.ts index 617b2b54..033431f8 100644 --- a/playground/src/plugins/index.ts +++ b/playground/src/plugins/index.ts @@ -1,5 +1,6 @@ import type { App } from 'vue' import { materialPalette, tailwindPalette } from './palettes' +import { createLayoutPlugin } from '@vuetify/v0' export function registerPlugins (app: App) { app.use(createHydrationPlugin()) @@ -12,6 +13,8 @@ export function registerPlugins (app: App) { }), ) + app.use(createLayoutPlugin({ enroll: true })) + app.use( createLocalePlugin({ default: 'en', From 86e4df7845243d9c3dedbc12d52b6f42246f4053 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Mon, 4 Aug 2025 19:26:41 -0400 Subject: [PATCH 02/88] type: typing changes --- packages/0/src/composables/useLayout/index.ts | 37 +++++++++++++------ playground/src/composables.d.ts | 6 ++- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index c4b7f4d3..dbcdf19d 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -16,14 +16,24 @@ import type { ComputedRef, ShallowReactive, ShallowRef, App } from 'vue' import type { GroupContext, GroupOptions, GroupTicket } from '#v0/composables/useGroup' import type { ID } from '#v0/types' +export interface BaseLayoutTicket extends GroupTicket { + order: number +} + export type LayoutLocation = 'top' | 'bottom' | 'left' | 'right' -export interface LayoutTicket extends GroupTicket { - order: number - position: LayoutLocation - value: number +export interface HorizontalTicket extends BaseLayoutTicket { + position: 'left' | 'right' + width: number +} + +export interface VerticalTicket extends BaseLayoutTicket { + position: 'top' | 'bottom' + height: number } +export type LayoutTicket = VerticalTicket | HorizontalTicket + export interface LayoutContext extends GroupContext { bounds: { top: ComputedRef @@ -79,26 +89,31 @@ export function createLayout< height: computed(() => height.value - bounds.top.value - bounds.bottom.value), } + function isHorizontal (ticket: LayoutTicket): ticket is HorizontalTicket { + return ticket.position === 'left' || ticket.position === 'right' + } + function sum (position: LayoutLocation): number { let total = 0 for (const item of registry.collection.values()) { if (item.position === position && item.isActive.value) { - total += sizes.get(item.id) ?? item.value ?? 0 + const value = isHorizontal(item) ? item.width : item.height + total += sizes.get(item.id) ?? value ?? 0 } } return total } - function register (registrant: Partial): Z { - const item: Partial = { - position: registrant.position, - order: registrant.order ?? 0, + function register (registrant: LayoutTicket): Z { + const item: LayoutTicket = { ...registrant, + order: registrant.order ?? 0, } - const ticket = registry.register(item) + const ticket = registry.register(item as Z) - sizes.set(ticket.id, ticket.value) + const value = isHorizontal(ticket) ? ticket.width : ticket.height + sizes.set(ticket.id, value) return ticket } diff --git a/playground/src/composables.d.ts b/playground/src/composables.d.ts index 3c1d6fb4..7da16ce0 100644 --- a/playground/src/composables.d.ts +++ b/playground/src/composables.d.ts @@ -37,6 +37,7 @@ declare global { const createGroupContext: typeof import('../../packages/0/src/composables/useGroup/index')['createGroupContext'] const createHydration: typeof import('../../packages/0/src/composables/useHydration/index')['createHydration'] const createHydrationPlugin: typeof import('../../packages/0/src/composables/useHydration/index')['createHydrationPlugin'] + const createLayout: typeof import('../../packages/0/src/composables/useLayout/index')['createLayout'] const createLayoutPlugin: typeof import('../../packages/0/src/composables/useLayout/index')['createLayoutPlugin'] const createLocale: typeof import('../../packages/0/src/composables/useLocale/index')['createLocale'] const createLocalePlugin: typeof import('../../packages/0/src/composables/useLocale/index')['createLocalePlugin'] @@ -105,6 +106,7 @@ declare global { const provide: typeof import('vue')['provide'] const provideBreakpointsContext: typeof import('../../packages/0/src/composables/useBreakpoints/index')['provideBreakpointsContext'] const provideHydrationContext: typeof import('../../packages/0/src/composables/useHydration/index')['provideHydrationContext'] + const provideLayout: typeof import('../../packages/0/src/composables/useLayout/index')['provideLayout'] const provideLoggerContext: typeof import('../../packages/0/src/composables/useLogger/index')['provideLoggerContext'] const provideMarkdownContext: typeof import('../../packages/0/src/composables/useMarkdown/index')['provideMarkdownContext'] const provideStorageContext: typeof import('../../packages/0/src/composables/useStorage/index')['provideStorageContext'] @@ -218,7 +220,7 @@ declare global { export type { KeyHandler } from '../../packages/0/src/composables/useKeydown/index' import('../../packages/0/src/composables/useKeydown/index') // @ts-ignore - export type { LayoutLocation, LayoutTicket, LayoutContext, LayoutOptions, LayoutPlugin } from '../../packages/0/src/composables/useLayout/index' + export type { BaseLayoutTicket, LayoutLocation, HorizontalTicket, VerticalTicket, LayoutTicket, LayoutContext, LayoutOptions, LayoutPlugin } from '../../packages/0/src/composables/useLayout/index' import('../../packages/0/src/composables/useLayout/index') // @ts-ignore export type { LocaleTicket, LocaleContext, LocaleOptions, LocalePluginOptions, LocalePlugin } from '../../packages/0/src/composables/useLocale/index' @@ -283,6 +285,7 @@ declare module 'vue' { readonly createElevation: UnwrapRef readonly createHydration: UnwrapRef readonly createHydrationPlugin: UnwrapRef + readonly createLayout: UnwrapRef readonly createLayoutPlugin: UnwrapRef readonly createLocale: UnwrapRef readonly createLocalePlugin: UnwrapRef @@ -340,6 +343,7 @@ declare module 'vue' { readonly provide: UnwrapRef readonly provideBreakpointsContext: UnwrapRef readonly provideHydrationContext: UnwrapRef + readonly provideLayout: UnwrapRef readonly provideStorageContext: UnwrapRef readonly reactive: UnwrapRef readonly readonly: UnwrapRef From 8b3a65b2b1f93ea74598140b34548dd1034b65a5 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Tue, 5 Aug 2025 08:45:36 -0400 Subject: [PATCH 03/88] type: exclusive or type and typing context --- packages/0/src/composables/useLayout/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index dbcdf19d..368f82db 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -25,11 +25,13 @@ export type LayoutLocation = 'top' | 'bottom' | 'left' | 'right' export interface HorizontalTicket extends BaseLayoutTicket { position: 'left' | 'right' width: number + height: never } export interface VerticalTicket extends BaseLayoutTicket { position: 'top' | 'bottom' height: number + width?: never } export type LayoutTicket = VerticalTicket | HorizontalTicket @@ -160,7 +162,7 @@ export function createLayout< * @returns A Vue plugin object with install method. */ -export const [useLayout, provideLayout] = createContext('v0:layout') +export const [useLayout, provideLayout] = createContext>('v0:layout') export function createLayoutPlugin (options: LayoutOptions = {}): LayoutPlugin { const layout = createLayout(options) From 051723d01b46a6e59fe3864a8a0fdcb14eb4d02b Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Wed, 6 Aug 2025 13:31:50 -0400 Subject: [PATCH 04/88] refactor: pass component ref and calculate sizes based on window or component --- packages/0/src/composables/useLayout/index.ts | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index 368f82db..43c1f130 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -12,7 +12,7 @@ import { computed, shallowReactive, shallowRef, onUnmounted, onMounted, getCurre import { IN_BROWSER } from '#v0/constants/globals.ts' // Types -import type { ComputedRef, ShallowReactive, ShallowRef, App } from 'vue' +import type { Ref, ComputedRef, ShallowReactive, ShallowRef, App } from 'vue' import type { GroupContext, GroupOptions, GroupTicket } from '#v0/composables/useGroup' import type { ID } from '#v0/types' @@ -55,7 +55,9 @@ export interface LayoutContext extends GroupContext { resize: () => void } -export interface LayoutOptions extends GroupOptions {} +export interface LayoutOptions extends GroupOptions { + el?: Ref +} export interface LayoutPlugin { install: (app: App, ...options: any[]) => any @@ -68,6 +70,7 @@ export function createLayout< const { enroll = true, events = true, + el = null, ...options } = _options @@ -121,18 +124,36 @@ export function createLayout< } function resize () { - height.value = window.innerHeight + if (el?.value) { + const rect = el.value.getBoundingClientRect() + width.value = rect.width + height.value = rect.height + return + } width.value = window.innerWidth + height.value = window.innerHeight } + let observer: ResizeObserver | null = null + if (IN_BROWSER && getCurrentInstance()) { onMounted(() => { + if (el?.value) { + observer = new ResizeObserver(resize) + observer.observe(el.value) + } else { + window.addEventListener('resize', resize) + } resize() - window.addEventListener('resize', resize) }) onUnmounted(() => { - window.removeEventListener('resize', resize) + if (observer && el?.value) { + observer.unobserve(el.value) + observer.disconnect() + } else { + window.removeEventListener('resize', resize) + } }) } From 237f84a616c5b568ec63652e81a4cb1dfdffe7ee Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Wed, 6 Aug 2025 13:32:04 -0400 Subject: [PATCH 05/88] test: updated test to use width and height instead of value --- .../0/src/composables/useLayout/index.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.test.ts b/packages/0/src/composables/useLayout/index.test.ts index 3d78cfa9..e68b80c0 100644 --- a/packages/0/src/composables/useLayout/index.test.ts +++ b/packages/0/src/composables/useLayout/index.test.ts @@ -32,8 +32,8 @@ describe('useLayout inside component', () => { }) const mountedComponent = mount(testComponent) - mountedComponent.vm.context.register({ id: 'Component1', position: 'top', value: 32 }) - mountedComponent.vm.context.register({ id: 'Component2', position: 'left', value: 128 }) + mountedComponent.vm.context.register({ id: 'Component1', position: 'top', height: 32 }) + mountedComponent.vm.context.register({ id: 'Component2', position: 'left', width: 128 }) expect(mountedComponent.vm.context.width.value).toEqual(1024) expect(mountedComponent.vm.context.height.value).toEqual(768) @@ -50,8 +50,8 @@ describe('useLayout inside component', () => { const mountedComponent = mount(testComponent) - mountedComponent.vm.context.register({ id: 'Component1', position: 'top', value: 32 }) - mountedComponent.vm.context.register({ id: 'Component2', position: 'left', value: 128 }) + mountedComponent.vm.context.register({ id: 'Component1', position: 'top', height: 32 }) + mountedComponent.vm.context.register({ id: 'Component2', position: 'left', width: 128 }) expect(mountedComponent.vm.context.main.x.value).toEqual(128) expect(mountedComponent.vm.context.main.y.value).toEqual(32) @@ -63,17 +63,17 @@ describe('useLayout inside component', () => { describe('useLayout outside component', () => { it('registers components', () => { const context = createLayout() - context.register({ id: 'Component1', position: 'top', value: 32 }) - context.register({ id: 'Component2', position: 'bottom', value: 64 }) + context.register({ id: 'Component1', position: 'top', height: 32 }) + context.register({ id: 'Component2', position: 'bottom', height: 64 }) expect(context.collection.has('Component1')).toEqual(true) expect(context.collection.has('Component2')).toEqual(true) }) it('calculates bound', () => { const context = createLayout() - context.register({ id: 'Component1', position: 'top', value: 32 }) - context.register({ id: 'Component2', position: 'bottom', value: 128 }) - context.register({ id: 'Component3', position: 'left', value: 64 }) + context.register({ id: 'Component1', position: 'top', height: 32 }) + context.register({ id: 'Component2', position: 'bottom', height: 128 }) + context.register({ id: 'Component3', position: 'left', width: 64 }) expect(context.bounds.top.value).toEqual(32) expect(context.bounds.bottom.value).toEqual(128) From cc602d2fe0ea9613de0e7879e830ea769a493af7 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Thu, 7 Aug 2025 13:49:46 -0400 Subject: [PATCH 06/88] refactor: use value --- .../0/src/composables/useLayout/index.test.ts | 18 +++++------ packages/0/src/composables/useLayout/index.ts | 30 ++++--------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.test.ts b/packages/0/src/composables/useLayout/index.test.ts index e68b80c0..3d78cfa9 100644 --- a/packages/0/src/composables/useLayout/index.test.ts +++ b/packages/0/src/composables/useLayout/index.test.ts @@ -32,8 +32,8 @@ describe('useLayout inside component', () => { }) const mountedComponent = mount(testComponent) - mountedComponent.vm.context.register({ id: 'Component1', position: 'top', height: 32 }) - mountedComponent.vm.context.register({ id: 'Component2', position: 'left', width: 128 }) + mountedComponent.vm.context.register({ id: 'Component1', position: 'top', value: 32 }) + mountedComponent.vm.context.register({ id: 'Component2', position: 'left', value: 128 }) expect(mountedComponent.vm.context.width.value).toEqual(1024) expect(mountedComponent.vm.context.height.value).toEqual(768) @@ -50,8 +50,8 @@ describe('useLayout inside component', () => { const mountedComponent = mount(testComponent) - mountedComponent.vm.context.register({ id: 'Component1', position: 'top', height: 32 }) - mountedComponent.vm.context.register({ id: 'Component2', position: 'left', width: 128 }) + mountedComponent.vm.context.register({ id: 'Component1', position: 'top', value: 32 }) + mountedComponent.vm.context.register({ id: 'Component2', position: 'left', value: 128 }) expect(mountedComponent.vm.context.main.x.value).toEqual(128) expect(mountedComponent.vm.context.main.y.value).toEqual(32) @@ -63,17 +63,17 @@ describe('useLayout inside component', () => { describe('useLayout outside component', () => { it('registers components', () => { const context = createLayout() - context.register({ id: 'Component1', position: 'top', height: 32 }) - context.register({ id: 'Component2', position: 'bottom', height: 64 }) + context.register({ id: 'Component1', position: 'top', value: 32 }) + context.register({ id: 'Component2', position: 'bottom', value: 64 }) expect(context.collection.has('Component1')).toEqual(true) expect(context.collection.has('Component2')).toEqual(true) }) it('calculates bound', () => { const context = createLayout() - context.register({ id: 'Component1', position: 'top', height: 32 }) - context.register({ id: 'Component2', position: 'bottom', height: 128 }) - context.register({ id: 'Component3', position: 'left', width: 64 }) + context.register({ id: 'Component1', position: 'top', value: 32 }) + context.register({ id: 'Component2', position: 'bottom', value: 128 }) + context.register({ id: 'Component3', position: 'left', value: 64 }) expect(context.bounds.top.value).toEqual(32) expect(context.bounds.bottom.value).toEqual(128) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index f4c3fdf6..68a4851c 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -16,26 +16,14 @@ import type { Ref, ComputedRef, ShallowReactive, ShallowRef, App } from 'vue' import type { GroupContext, GroupOptions, GroupTicket } from '#v0/composables/useGroup' import type { ID } from '#v0/types' -export interface BaseLayoutTicket extends GroupTicket { - order: number -} - export type LayoutLocation = 'top' | 'bottom' | 'left' | 'right' -export interface HorizontalTicket extends BaseLayoutTicket { - position: 'left' | 'right' - width: number - height: never -} - -export interface VerticalTicket extends BaseLayoutTicket { - position: 'top' | 'bottom' - height: number - width?: never +export interface LayoutTicket extends GroupTicket { + order: number + position: LayoutLocation + value: number } -export type LayoutTicket = VerticalTicket | HorizontalTicket - export interface LayoutContext extends GroupContext { bounds: { top: ComputedRef @@ -94,16 +82,11 @@ export function createLayout< height: computed(() => height.value - bounds.top.value - bounds.bottom.value), } - function isHorizontal (ticket: LayoutTicket): ticket is HorizontalTicket { - return ticket.position === 'left' || ticket.position === 'right' - } - function sum (position: LayoutLocation): number { let total = 0 for (const item of registry.values()) { if (item.position === position && item.isActive.value) { - const value = isHorizontal(item) ? item.width : item.height - total += sizes.get(item.id) ?? value ?? 0 + total += sizes.get(item.id) ?? item.value ?? 0 } } return total @@ -117,8 +100,7 @@ export function createLayout< const ticket = registry.register(item as Z) - const value = isHorizontal(ticket) ? ticket.width : ticket.height - sizes.set(ticket.id, value) + sizes.set(ticket.id, ticket.value) return ticket } From bfe2f1189212ded06030d963e38330a50f39e021 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Thu, 7 Aug 2025 18:07:25 -0400 Subject: [PATCH 07/88] feat: fix typing --- packages/0/src/composables/useLayout/index.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index 68a4851c..4bff04ad 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -41,6 +41,7 @@ export interface LayoutContext extends GroupContext { height: ShallowRef width: ShallowRef resize: () => void + register: (item?: Partial) => Z } export interface LayoutOptions extends GroupOptions { @@ -51,6 +52,12 @@ export interface LayoutPlugin { install: (app: App, ...options: any[]) => any } +export const [useLayoutContext, provideLayout] = createContext>('v0:layout') + +export function useLayout (): LayoutContext { + return useLayoutContext() +} + export function createLayout< Z extends LayoutTicket = LayoutTicket, E extends LayoutContext = LayoutContext, @@ -92,13 +99,14 @@ export function createLayout< return total } - function register (registrant: LayoutTicket): Z { - const item: LayoutTicket = { + function register (registrant: Partial): Z { + const item: Partial = { ...registrant, order: registrant.order ?? 0, + value: registrant.value, } - const ticket = registry.register(item as Z) + const ticket = registry.register(item) sizes.set(ticket.id, ticket.value) @@ -165,8 +173,6 @@ export function createLayout< * @returns A Vue plugin object with install method. */ -export const [useLayout, provideLayout] = createContext>('v0:layout') - export function createLayoutPlugin (options: LayoutOptions = {}): LayoutPlugin { const layout = createLayout(options) From ed2111ba9e6b03e8c0b216f23285230e253e493e Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Thu, 7 Aug 2025 18:07:33 -0400 Subject: [PATCH 08/88] feat: add plugin to docs --- apps/docs/src/plugins/zero.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/docs/src/plugins/zero.ts b/apps/docs/src/plugins/zero.ts index e40212ec..44d7a4a7 100644 --- a/apps/docs/src/plugins/zero.ts +++ b/apps/docs/src/plugins/zero.ts @@ -1,5 +1,5 @@ // Vuetify0 -import { createBreakpointsPlugin, createHydrationPlugin, createLoggerPlugin, createThemePlugin } from '@vuetify/v0' +import { createBreakpointsPlugin, createHydrationPlugin, createLoggerPlugin, createThemePlugin, createLayoutPlugin } from '@vuetify/v0' // Plugins import { createIconPlugin } from './icons' @@ -12,6 +12,7 @@ export default function zero (app: App) { app.use(createLoggerPlugin()) app.use(createHydrationPlugin()) app.use(createBreakpointsPlugin()) + app.use(createLayoutPlugin()) app.use( createThemePlugin({ default: 'slate', From fa7b88275ed001378a8ab8eef8368b5ec317d3f6 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Thu, 7 Aug 2025 21:58:17 -0400 Subject: [PATCH 09/88] feat: register element value --- packages/0/src/composables/useLayout/index.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/0/src/composables/useLayout/index.ts b/packages/0/src/composables/useLayout/index.ts index 4bff04ad..01f595c1 100644 --- a/packages/0/src/composables/useLayout/index.ts +++ b/packages/0/src/composables/useLayout/index.ts @@ -18,10 +18,15 @@ import type { ID } from '#v0/types' export type LayoutLocation = 'top' | 'bottom' | 'left' | 'right' +export type ExposedElement = { + element: HTMLElement | null +} + export interface LayoutTicket extends GroupTicket { order: number position: LayoutLocation value: number + element?: Ref } export interface LayoutContext extends GroupContext { @@ -90,6 +95,7 @@ export function createLayout< } function sum (position: LayoutLocation): number { + debugger let total = 0 for (const item of registry.values()) { if (item.position === position && item.isActive.value) { @@ -100,14 +106,14 @@ export function createLayout< } function register (registrant: Partial): Z { + const value = registrant.value ?? registrant.element?.value?.element?.offsetHeight ?? 0 const item: Partial = { ...registrant, order: registrant.order ?? 0, - value: registrant.value, + value, } const ticket = registry.register(item) - sizes.set(ticket.id, ticket.value) return ticket From 1f9303699a08b51e2b9f94849e48407ed20c5917 Mon Sep 17 00:00:00 2001 From: Henry Aviles Date: Thu, 7 Aug 2025 21:58:29 -0400 Subject: [PATCH 10/88] feat: utilize in docs components --- apps/docs/src/components/app/AppBanner.vue | 17 ++++++++++++----- apps/docs/src/components/app/AppBar.vue | 10 +++++++++- apps/docs/src/components/app/AppMain.vue | 13 ++++++++++--- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/docs/src/components/app/AppBanner.vue b/apps/docs/src/components/app/AppBanner.vue index 652608d5..168e200b 100644 --- a/apps/docs/src/components/app/AppBanner.vue +++ b/apps/docs/src/components/app/AppBanner.vue @@ -1,25 +1,32 @@ diff --git a/apps/docs/src/components/app/AppBar.vue b/apps/docs/src/components/app/AppBar.vue index 7b8e2b03..2e005c18 100644 --- a/apps/docs/src/components/app/AppBar.vue +++ b/apps/docs/src/components/app/AppBar.vue @@ -1,6 +1,7 @@