From 13087e1b7e35bded1de5b9b58ff5bd2a6d010aca Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Wed, 2 Oct 2024 09:33:32 +0200 Subject: [PATCH 1/5] feat: useLazyData --- lib/basic/lazy-data.spec.ts | 52 +++++++++++++++++++++++++++++++++++++ lib/basic/lazy-data.ts | 46 ++++++++++++++++++++++++++++++++ package.json | 1 - vite.config.ts | 2 +- 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 lib/basic/lazy-data.spec.ts create mode 100644 lib/basic/lazy-data.ts diff --git a/lib/basic/lazy-data.spec.ts b/lib/basic/lazy-data.spec.ts new file mode 100644 index 0000000..ac952fc --- /dev/null +++ b/lib/basic/lazy-data.spec.ts @@ -0,0 +1,52 @@ +import { describe, expect, it } from 'vitest' +import { createArray } from 'zeed' +import { useLazyData } from './lazy-data' + +describe('useLazyData', () => { + async function onFetch(from: number, to: number) { + return createArray(to - from).map((_, i) => from + i) + } + + it('should generate fake data', async () => { + const result = await onFetch(5, 10) + expect(result).toMatchInlineSnapshot(` + [ + 5, + 6, + 7, + 8, + 9, + ] + `) + }) + + it('should initialize with size 0', () => { + const { getSize } = useLazyData({ onFetch }) + expect(getSize()).toBe(0) + }) + + it('should set size correctly', () => { + const { setSize, getSize, data } = useLazyData({ onFetch }) + setSize(5) + expect(getSize()).toBe(5) + expect(data.length).toBe(5) + expect(data).toMatchInlineSnapshot(` + [ + undefined, + undefined, + undefined, + undefined, + undefined, + ] + `) + }) + + it('should reload data correctly', () => { + const { setSize, reload, data } = useLazyData({ onFetch }) + setSize(3) + reload() + // Assuming the data is reactive and we can access it directly for testing purposes + expect(data.length).toBe(3) + expect(data.every(item => item == null)).toBe(true) + }) +}) diff --git a/lib/basic/lazy-data.ts b/lib/basic/lazy-data.ts new file mode 100644 index 0000000..4946d90 --- /dev/null +++ b/lib/basic/lazy-data.ts @@ -0,0 +1,46 @@ +import { reactive } from 'vue' +import { arrayEmptyInPlace, createArray } from 'zeed' + +interface Config { + onFetch: (from: number, to: number) => Promise + chunkSize?: number + margin?: number +} + +enum ChunkStatus { + Loading = 1, + Loaded, + Error, +} + +export function useLazyData(opt: Config) { + const { chunkSize = 10, margin = 5, onFetch } = opt + + let dataSize = 0 + const data = reactive<(T | null)[]>([]) + const chunks: Record = {} + + function reload() { + arrayEmptyInPlace(data) + const newData = createArray(dataSize) as (T | null)[] + data.push(...newData as any) + } + + function setSize(size: number) { + dataSize = size + reload() + } + + function setVisible(fromPos: number, toPos: number) { + const fromChunk = Math.floor(fromPos / chunkSize) + const toChunk = Math.floor(toPos / chunkSize) + } + + return { + setSize, + getSize: () => dataSize, + setVisible, + reload, + data, + } +} diff --git a/package.json b/package.json index cc6cbe8..5dbec98 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,6 @@ "@vitejs/plugin-vue": "^5.1.4", "@vitest/browser": "^2.1.1", "eslint": "^9", - "lightningcss": "^1.27.0", "stylus": "^0.63.0", "tsup": "^8.3.0", "typescript": "^5.6", diff --git a/vite.config.ts b/vite.config.ts index 93f3032..cea08fb 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -70,7 +70,7 @@ if (!process.env.BUILD_DEMO) { // https://vitejs.dev/guide/build.html#library-mode config.build = { // sourcemap: false, - cssMinify: 'lightningcss', + // cssMinify: 'lightningcss', // cssTarget: 'es2015', lib: { From f2a66f406d76192047c5167433e8cf2e53f8a97f Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Sat, 5 Oct 2024 18:27:51 +0200 Subject: [PATCH 2/5] fix: fallback for utopia clamp --- stylus/preset/utopia.styl | 84 +++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/stylus/preset/utopia.styl b/stylus/preset/utopia.styl index 5478d49..e7c1510 100644 --- a/stylus/preset/utopia.styl +++ b/stylus/preset/utopia.styl @@ -1,35 +1,67 @@ // utopia.fyi/type/calculator?c=320,16,1.2,1240,20,1.25,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 *//* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,20,1.25,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 *//* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,20,1.333,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ :root { - --step--2: unquote("clamp(0.6944rem, 0.6913rem + 0.0157vw, 0.7035rem)"); - --step--1: unquote("clamp(0.8333rem, 0.797rem + 0.1816vw, 0.9377rem)"); - --step-0: unquote("clamp(1rem, 0.913rem + 0.4348vw, 1.25rem)"); - --step-1: unquote("clamp(1.2rem, 1.0378rem + 0.8109vw, 1.6663rem)"); - --step-2: unquote("clamp(1.44rem, 1.1683rem + 1.3585vw, 2.2211rem)"); - --step-3: unquote("clamp(1.728rem, 1.2992rem + 2.1439vw, 2.9607rem)"); - --step-4: unquote("clamp(2.0736rem, 1.4221rem + 3.2575vw, 3.9467rem)"); - --step-5: unquote("clamp(2.4883rem, 1.5239rem + 4.8219vw, 5.2609rem)"); + --step--2-flex: unquote("clamp(0.6944rem, 0.6913rem + 0.0157vw, 0.7035rem)"); + --step--1-flex: unquote("clamp(0.8333rem, 0.797rem + 0.1816vw, 0.9377rem)"); + --step-0-flex: unquote("clamp(1rem, 0.913rem + 0.4348vw, 1.25rem)"); + --step-1-flex: unquote("clamp(1.2rem, 1.0378rem + 0.8109vw, 1.6663rem)"); + --step-2-flex: unquote("clamp(1.44rem, 1.1683rem + 1.3585vw, 2.2211rem)"); + --step-3-flex: unquote("clamp(1.728rem, 1.2992rem + 2.1439vw, 2.9607rem)"); + --step-4-flex: unquote("clamp(2.0736rem, 1.4221rem + 3.2575vw, 3.9467rem)"); + --step-5-flex: unquote("clamp(2.4883rem, 1.5239rem + 4.8219vw, 5.2609rem)"); +} + +:root { + --step--2: var(--step--2-flex, 0.6944rem); + --step--1: var(--step--1-flex, 0.8333rem); + --step-0: var(--step-0-flex, 1rem); + --step-1: var(--step-1-flex, 1.2rem); + --step-2: var(--step-2-flex, 1.44rem); + --step-3: var(--step-3-flex, 1.728rem); + --step-4: var(--step-4-flex, 2.0736rem); + --step-5: var(--step-5-flex, 2.4883rem); } /* @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,20,1.333,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ :root { - --space-3xs: unquote("clamp(0.25rem, 0.2283rem + 0.1087vi, 0.3125rem)"); - --space-2xs: unquote("clamp(0.5rem, 0.4565rem + 0.2174vi, 0.625rem)"); - --space-xs: unquote("clamp(0.75rem, 0.6848rem + 0.3261vi, 0.9375rem)"); - --space-s: unquote("clamp(1rem, 0.913rem + 0.4348vi, 1.25rem)"); - --space-m: unquote("clamp(1.5rem, 1.3696rem + 0.6522vi, 1.875rem)"); - --space-l: unquote("clamp(2rem, 1.8261rem + 0.8696vi, 2.5rem)"); - --space-xl: unquote("clamp(3rem, 2.7391rem + 1.3043vi, 3.75rem)"); - --space-2xl: unquote("clamp(4rem, 3.6522rem + 1.7391vi, 5rem)"); - --space-3xl: unquote("clamp(6rem, 5.4783rem + 2.6087vi, 7.5rem)"); - --space-3xs-2xs: unquote("clamp(0.25rem, 0.1196rem + 0.6522vi, 0.625rem)"); - --space-2xs-xs: unquote("clamp(0.5rem, 0.3478rem + 0.7609vi, 0.9375rem)"); - --space-xs-s: unquote("clamp(0.75rem, 0.5761rem + 0.8696vi, 1.25rem)"); - --space-s-m: unquote("clamp(1rem, 0.6957rem + 1.5217vi, 1.875rem)"); - --space-m-l: unquote("clamp(1.5rem, 1.1522rem + 1.7391vi, 2.5rem)"); - --space-l-xl: unquote("clamp(2rem, 1.3913rem + 3.0435vi, 3.75rem)"); - --space-xl-2xl: unquote("clamp(3rem, 2.3043rem + 3.4783vi, 5rem)"); - --space-2xl-3xl: unquote("clamp(4rem, 2.7826rem + 6.087vi, 7.5rem)"); - --space-s-l: unquote("clamp(1rem, 0.4783rem + 2.6087vi, 2.5rem)"); + --space-3xs-flex: unquote("clamp(0.25rem, 0.2283rem + 0.1087vi, 0.3125rem)"); + --space-2xs-flex: unquote("clamp(0.5rem, 0.4565rem + 0.2174vi, 0.625rem)"); + --space-xs-flex: unquote("clamp(0.75rem, 0.6848rem + 0.3261vi, 0.9375rem)"); + --space-s-flex: unquote("clamp(1rem, 0.913rem + 0.4348vi, 1.25rem)"); + --space-m-flex: unquote("clamp(1.5rem, 1.3696rem + 0.6522vi, 1.875rem)"); + --space-l-flex: unquote("clamp(2rem, 1.8261rem + 0.8696vi, 2.5rem)"); + --space-xl-flex: unquote("clamp(3rem, 2.7391rem + 1.3043vi, 3.75rem)"); + --space-2xl-flex: unquote("clamp(4rem, 3.6522rem + 1.7391vi, 5rem)"); + --space-3xl-flex: unquote("clamp(6rem, 5.4783rem + 2.6087vi, 7.5rem)"); + --space-3xs-2xs-flex: unquote("clamp(0.25rem, 0.1196rem + 0.6522vi, 0.625rem)"); + --space-2xs-xs-flex: unquote("clamp(0.5rem, 0.3478rem + 0.7609vi, 0.9375rem)"); + --space-xs-s-flex: unquote("clamp(0.75rem, 0.5761rem + 0.8696vi, 1.25rem)"); + --space-s-m-flex: unquote("clamp(1rem, 0.6957rem + 1.5217vi, 1.875rem)"); + --space-m-l-flex: unquote("clamp(1.5rem, 1.1522rem + 1.7391vi, 2.5rem)"); + --space-l-xl-flex: unquote("clamp(2rem, 1.3913rem + 3.0435vi, 3.75rem)"); + --space-xl-2xl-flex: unquote("clamp(3rem, 2.3043rem + 3.4783vi, 5rem)"); + --space-2xl-3xl-flex: unquote("clamp(4rem, 2.7826rem + 6.087vi, 7.5rem)"); + --space-s-l-flex: unquote("clamp(1rem, 0.4783rem + 2.6087vi, 2.5rem)"); +} + +:root { + --space-3xs: var(--space-3xs-flex, 0.25rem); + --space-2xs: var(--space-2xs-flex, 0.5rem); + --space-xs: var(--space-xs-flex, 0.75rem); + --space-s: var(--space-s-flex, 1rem); + --space-m: var(--space-m-flex, 1.5rem); + --space-l: var(--space-l-flex, 2rem); + --space-xl: var(--space-xl-flex, 3rem); + --space-2xl: var(--space-2xl-flex, 4rem); + --space-3xl: var(--space-3xl-flex, 6rem); + --space-3xs-2xs: var(--space-3xs-2xs-flex, 0.25rem); + --space-2xs-xs: var(--space-2xs-xs-flex, 0.5rem); + --space-xs-s: var(--space-xs-s-flex, 0.75rem); + --space-s-m: var(--space-s-m-flex, 1rem); + --space-m-l: var(--space-m-l-flex, 1.5rem); + --space-l-xl: var(--space-l-xl-flex, 2rem); + --space-xl-2xl: var(--space-xl-2xl-flex, 3rem); + --space-2xl-3xl: var(--space-2xl-3xl-flex, 4rem); + --space-s-l: var(--space-s-l-flex, 1rem); } oui-utopia() { From 4015aba468a38eecdceabc021594fe3cb55a754c Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Sat, 5 Oct 2024 18:37:36 +0200 Subject: [PATCH 3/5] fix: css vi compat --- stylus/preset/utopia.styl | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/stylus/preset/utopia.styl b/stylus/preset/utopia.styl index e7c1510..1d502c9 100644 --- a/stylus/preset/utopia.styl +++ b/stylus/preset/utopia.styl @@ -23,24 +23,24 @@ /* @link https://utopia.fyi/space/calculator?c=320,16,1.2,1240,20,1.333,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ :root { - --space-3xs-flex: unquote("clamp(0.25rem, 0.2283rem + 0.1087vi, 0.3125rem)"); - --space-2xs-flex: unquote("clamp(0.5rem, 0.4565rem + 0.2174vi, 0.625rem)"); - --space-xs-flex: unquote("clamp(0.75rem, 0.6848rem + 0.3261vi, 0.9375rem)"); - --space-s-flex: unquote("clamp(1rem, 0.913rem + 0.4348vi, 1.25rem)"); - --space-m-flex: unquote("clamp(1.5rem, 1.3696rem + 0.6522vi, 1.875rem)"); - --space-l-flex: unquote("clamp(2rem, 1.8261rem + 0.8696vi, 2.5rem)"); - --space-xl-flex: unquote("clamp(3rem, 2.7391rem + 1.3043vi, 3.75rem)"); - --space-2xl-flex: unquote("clamp(4rem, 3.6522rem + 1.7391vi, 5rem)"); - --space-3xl-flex: unquote("clamp(6rem, 5.4783rem + 2.6087vi, 7.5rem)"); - --space-3xs-2xs-flex: unquote("clamp(0.25rem, 0.1196rem + 0.6522vi, 0.625rem)"); - --space-2xs-xs-flex: unquote("clamp(0.5rem, 0.3478rem + 0.7609vi, 0.9375rem)"); - --space-xs-s-flex: unquote("clamp(0.75rem, 0.5761rem + 0.8696vi, 1.25rem)"); - --space-s-m-flex: unquote("clamp(1rem, 0.6957rem + 1.5217vi, 1.875rem)"); - --space-m-l-flex: unquote("clamp(1.5rem, 1.1522rem + 1.7391vi, 2.5rem)"); - --space-l-xl-flex: unquote("clamp(2rem, 1.3913rem + 3.0435vi, 3.75rem)"); - --space-xl-2xl-flex: unquote("clamp(3rem, 2.3043rem + 3.4783vi, 5rem)"); - --space-2xl-3xl-flex: unquote("clamp(4rem, 2.7826rem + 6.087vi, 7.5rem)"); - --space-s-l-flex: unquote("clamp(1rem, 0.4783rem + 2.6087vi, 2.5rem)"); + --space-3xs-flex: unquote("clamp(0.25rem, 0.2283rem + 0.1087vw, 0.3125rem)"); + --space-2xs-flex: unquote("clamp(0.5rem, 0.4565rem + 0.2174vw, 0.625rem)"); + --space-xs-flex: unquote("clamp(0.75rem, 0.6848rem + 0.3261vw, 0.9375rem)"); + --space-s-flex: unquote("clamp(1rem, 0.913rem + 0.4348vw, 1.25rem)"); + --space-m-flex: unquote("clamp(1.5rem, 1.3696rem + 0.6522vw, 1.875rem)"); + --space-l-flex: unquote("clamp(2rem, 1.8261rem + 0.8696vw, 2.5rem)"); + --space-xl-flex: unquote("clamp(3rem, 2.7391rem + 1.3043vw, 3.75rem)"); + --space-2xl-flex: unquote("clamp(4rem, 3.6522rem + 1.7391vw, 5rem)"); + --space-3xl-flex: unquote("clamp(6rem, 5.4783rem + 2.6087vw, 7.5rem)"); + --space-3xs-2xs-flex: unquote("clamp(0.25rem, 0.1196rem + 0.6522vw, 0.625rem)"); + --space-2xs-xs-flex: unquote("clamp(0.5rem, 0.3478rem + 0.7609vw, 0.9375rem)"); + --space-xs-s-flex: unquote("clamp(0.75rem, 0.5761rem + 0.8696vw, 1.25rem)"); + --space-s-m-flex: unquote("clamp(1rem, 0.6957rem + 1.5217vw, 1.875rem)"); + --space-m-l-flex: unquote("clamp(1.5rem, 1.1522rem + 1.7391vw, 2.5rem)"); + --space-l-xl-flex: unquote("clamp(2rem, 1.3913rem + 3.0435vw, 3.75rem)"); + --space-xl-2xl-flex: unquote("clamp(3rem, 2.3043rem + 3.4783vw, 5rem)"); + --space-2xl-3xl-flex: unquote("clamp(4rem, 2.7826rem + 6.087vw, 7.5rem)"); + --space-s-l-flex: unquote("clamp(1rem, 0.4783rem + 2.6087vw, 2.5rem)"); } :root { From 5fb39a6f625281960625e6f5ce68f4739fb8dc73 Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Sat, 5 Oct 2024 18:45:14 +0200 Subject: [PATCH 4/5] feat: debounce visible update for virtual table --- lib/basic/lazy-data.spec.ts | 6 +++--- lib/basic/lazy-data.ts | 29 ++++++++++++++++++++++++----- lib/basic/oui-tableview.demo.vue | 8 +++++++- lib/basic/oui-tableview.vue | 2 ++ lib/basic/oui-virtual-list.vue | 10 +++++++++- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/basic/lazy-data.spec.ts b/lib/basic/lazy-data.spec.ts index ac952fc..2648e42 100644 --- a/lib/basic/lazy-data.spec.ts +++ b/lib/basic/lazy-data.spec.ts @@ -3,12 +3,12 @@ import { createArray } from 'zeed' import { useLazyData } from './lazy-data' describe('useLazyData', () => { - async function onFetch(from: number, to: number) { - return createArray(to - from).map((_, i) => from + i) + async function onFetch(offset: number, length: number) { + return createArray(length).map((_, i) => offset + i) } it('should generate fake data', async () => { - const result = await onFetch(5, 10) + const result = await onFetch(5, 5) expect(result).toMatchInlineSnapshot(` [ 5, diff --git a/lib/basic/lazy-data.ts b/lib/basic/lazy-data.ts index 4946d90..c0740ac 100644 --- a/lib/basic/lazy-data.ts +++ b/lib/basic/lazy-data.ts @@ -1,10 +1,14 @@ +import type { LoggerInterface } from 'zeed' import { reactive } from 'vue' -import { arrayEmptyInPlace, createArray } from 'zeed' +import { arrayEmptyInPlace, createArray, Logger } from 'zeed' + +const log: LoggerInterface = Logger('lazy-data') interface Config { - onFetch: (from: number, to: number) => Promise + onFetch: (from: number, length: number) => Promise chunkSize?: number margin?: number + size?: number } enum ChunkStatus { @@ -14,13 +18,15 @@ enum ChunkStatus { } export function useLazyData(opt: Config) { - const { chunkSize = 10, margin = 5, onFetch } = opt + const { chunkSize = 10, margin = 5, onFetch, size = 0 } = opt + let iteration = 0 let dataSize = 0 const data = reactive<(T | null)[]>([]) const chunks: Record = {} function reload() { + iteration++ arrayEmptyInPlace(data) const newData = createArray(dataSize) as (T | null)[] data.push(...newData as any) @@ -31,9 +37,22 @@ export function useLazyData(opt: Config) { reload() } + if (size > 0) + setSize(size) + function setVisible(fromPos: number, toPos: number) { - const fromChunk = Math.floor(fromPos / chunkSize) - const toChunk = Math.floor(toPos / chunkSize) + log.assert(fromPos <= toPos, 'fromPos must be less than or equal to toPos') + const fromChunk = Math.floor(Math.max(0, fromPos - margin) / chunkSize) + const toChunk = Math.floor((toPos + margin) / chunkSize) * chunkSize + const iterationNow = iteration + onFetch(fromChunk * chunkSize, ((toChunk - fromChunk) * chunkSize) + chunkSize).then((result) => { + if (iterationNow !== iteration) + return + for (let i = fromChunk; i <= toChunk; i++) + chunks[i] = ChunkStatus.Loaded + + // arraySetArrayInPlace(data, result, fromChunk * chunkSize) + }) } return { diff --git a/lib/basic/oui-tableview.demo.vue b/lib/basic/oui-tableview.demo.vue index dc5a024..c4b4bc5 100644 --- a/lib/basic/oui-tableview.demo.vue +++ b/lib/basic/oui-tableview.demo.vue @@ -13,6 +13,8 @@ const state = reactive({ fillLast: true, scrollToEnd: false, showSepHandle: false, + first: 0, + last: 0, }) const columns: OuiTableColumn[] = [ @@ -42,7 +44,10 @@ const menu = useMenu((row: any) => [ }, ]) -const x = ref(0) +function onVisible(offset: number, limit: number) { + state.first = offset + state.last = offset + limit +}