chore: format

pull/8414/head^2
Konv Suu 2025-11-14 14:29:23 +08:00
parent 631a2f255b
commit 5951387f11
24 changed files with 159 additions and 174 deletions

View File

@ -1,3 +1,3 @@
import antdv from "@ant-design-vue/eslint-config" import antdv from '@ant-design-vue/eslint-config'
export default antdv() export default antdv()

View File

@ -7,6 +7,7 @@
"build": "vite build", "build": "vite build",
"dev": "vite", "dev": "vite",
"lint": "eslint . --fix", "lint": "eslint . --fix",
"format": "prettier --write .",
"preview": "vite preview", "preview": "vite preview",
"tsc": "vue-tsc --noEmit" "tsc": "vue-tsc --noEmit"
}, },
@ -14,13 +15,6 @@
"@floating-ui/vue": "^1.1.5", "@floating-ui/vue": "^1.1.5",
"@heroicons/vue": "^2.1.5", "@heroicons/vue": "^2.1.5",
"@ant-design-vue/ui": "workspace:*", "@ant-design-vue/ui": "workspace:*",
"@simonwep/pickr": "^1.9.1",
"@trpc/client": "^11.0.0",
"@trpc/server": "^11.0.0",
"@wdns/vue-code-block": "^2.3.3",
"clsx": "^2.1.1",
"cookies": "^0.9.1",
"uuid": "^10.0.0",
"vue": "^3.4.34", "vue": "^3.4.34",
"vue-router": "^4.4.0" "vue-router": "^4.4.0"
}, },
@ -31,7 +25,6 @@
"@ant-design-vue/vite-config": "workspace:*", "@ant-design-vue/vite-config": "workspace:*",
"@ant-design-vue/tailwind-config": "workspace:*", "@ant-design-vue/tailwind-config": "workspace:*",
"@tailwindcss/vite": "^4.1.3", "@tailwindcss/vite": "^4.1.3",
"@types/cookies": "^0.9.0",
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
"@vitejs/plugin-vue": "^5.1.3", "@vitejs/plugin-vue": "^5.1.3",
"prettier-plugin-tailwindcss": "^0.6.11", "prettier-plugin-tailwindcss": "^0.6.11",
@ -39,7 +32,6 @@
"typescript": "^5.8.2", "typescript": "^5.8.2",
"vite": "^5.3.5", "vite": "^5.3.5",
"vite-plugin-dts": "^3.9.1", "vite-plugin-dts": "^3.9.1",
"vite-svg-loader": "^5.1.0",
"vue-tsc": "^3.0.3" "vue-tsc": "^3.0.3"
} }
} }

View File

@ -1,3 +1,3 @@
// @ts-check // @ts-check
export { default } from "@ant-design-vue/prettier-config/tailwind"; export { default } from '@ant-design-vue/prettier-config/tailwind'

View File

@ -2,7 +2,7 @@
<div class="flex flex-wrap gap-8 px-8"> <div class="flex flex-wrap gap-8 px-8">
<RouterLink v-for="item in items" :key="item.path" :to="item.path"> <RouterLink v-for="item in items" :key="item.path" :to="item.path">
<div <div
class="shadow-xs relative flex w-72 flex-col rounded-lg bg-primary capitalize text-primary-content transition-all hover:scale-105 hover:shadow-xl" class="bg-primary text-primary-content relative flex w-72 flex-col rounded-lg capitalize shadow-xs transition-all hover:scale-105 hover:shadow-xl"
> >
<div className="flex-col gap-2 flex flex-auto p-4 text-sm items-center text-center"> <div className="flex-col gap-2 flex flex-auto p-4 text-sm items-center text-center">
<h2 className="font-semibold flex items-center gap-2 text-xl mb-1"> <h2 className="font-semibold flex items-center gap-2 text-xl mb-1">

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="max-w-full select-none overflow-x-auto px-4 py-2 text-sm"> <div class="max-w-full overflow-x-auto px-4 py-2 text-sm select-none">
<ul class="flex min-h-min items-center whitespace-nowrap capitalize"> <ul class="flex min-h-min items-center whitespace-nowrap capitalize">
<template v-for="(item, i) in items" :key="item.path"> <template v-for="(item, i) in items" :key="item.path">
<li class="flex items-center"> <li class="flex items-center">
<template v-if="i > 0"> <template v-if="i > 0">
<span <span
class="ml-2 mr-3 block size-1.5 rotate-45 transform border-r-[1px] border-t-[1px] border-base-content/70 bg-transparent" class="border-base-content/70 mr-3 ml-2 block size-1.5 rotate-45 transform border-t-[1px] border-r-[1px] bg-transparent"
></span> ></span>
</template> </template>
<template v-if="item.path !== route.path"> <template v-if="item.path !== route.path">

View File

@ -1,4 +1,4 @@
import type { InjectionKey, Ref } from 'vue'; import type { InjectionKey, Ref } from 'vue'
import { inject, provide } from 'vue' import { inject, provide } from 'vue'
export interface LayoutOptions { export interface LayoutOptions {

View File

@ -13,7 +13,7 @@
:style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }" :style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"
/> />
</a-flex> </a-flex>
<hr/> <hr />
<label> <label>
Select justify: Select justify:
<select v-model="justify"> <select v-model="justify">
@ -32,7 +32,7 @@
<a-button variant="solid">Primary</a-button> <a-button variant="solid">Primary</a-button>
<a-button variant="solid">Primary</a-button> <a-button variant="solid">Primary</a-button>
</a-flex> </a-flex>
<hr/> <hr />
<a-flex gap="middle" vertical> <a-flex gap="middle" vertical>
<label> <label>
Select gap size: Select gap size:
@ -47,10 +47,8 @@
<a-button variant="link">Link</a-button> <a-button variant="link">Link</a-button>
</a-flex> </a-flex>
</a-flex> </a-flex>
<hr/> <hr />
<label> <label>Auto wrap:</label>
Auto wrap:
</label>
<a-flex wrap="wrap" gap="small"> <a-flex wrap="wrap" gap="small">
<a-button v-for="item in new Array(24)" :key="item" variant="solid">Button</a-button> <a-button v-for="item in new Array(24)" :key="item" variant="solid">Button</a-button>
</a-flex> </a-flex>
@ -58,36 +56,36 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { CSSProperties } from 'vue'; import type { CSSProperties } from 'vue'
import { ref, reactive } from 'vue'; import { ref, reactive } from 'vue'
const baseStyle: CSSProperties = { const baseStyle: CSSProperties = {
width: '25%', width: '25%',
height: '54px', height: '54px',
}; }
const boxStyle: CSSProperties = { const boxStyle: CSSProperties = {
width: '100%', width: '100%',
height: '120px', height: '120px',
borderRadius: '6px', borderRadius: '6px',
border: '1px solid #40a9ff', border: '1px solid #40a9ff',
}; }
const axisOptions = reactive(['horizontal', 'vertical']); const axisOptions = reactive(['horizontal', 'vertical'])
const axis = ref(axisOptions[0]); const axis = ref(axisOptions[0])
const justifyOptions = reactive([ const justifyOptions = reactive([
'flex-start', 'flex-start',
'center', 'center',
'flex-end', 'flex-end',
'space-between', 'space-between',
'space-around', 'space-around',
'space-evenly', 'space-evenly',
]); ])
const justify = ref(justifyOptions[0]); const justify = ref(justifyOptions[0])
const alignOptions = reactive(['flex-start', 'center', 'flex-end']); const alignOptions = reactive(['flex-start', 'center', 'flex-end'])
const align = ref(alignOptions[0]); const align = ref(alignOptions[0])
const gapSizeOptions = reactive(['small', 'middle', 'large']); const gapSizeOptions = reactive(['small', 'middle', 'large'])
const gapSize = ref(gapSizeOptions[0]); const gapSize = ref(gapSizeOptions[0])
</script> </script>

View File

@ -1,4 +1,4 @@
import type { RouteRecordRaw} from 'vue-router'; import type { RouteRecordRaw } from 'vue-router'
import { RouterView } from 'vue-router' import { RouterView } from 'vue-router'
import BasicLayout from './components/BasicLayout.vue' import BasicLayout from './components/BasicLayout.vue'
import { h } from 'vue' import { h } from 'vue'

View File

@ -11,10 +11,10 @@ import {
typescript, typescript,
vue, vue,
} from "./configs" } from "./configs"
import { Config } from './types'; import type { Config } from './types';
import { isPackageExists } from "local-pkg"; import { isPackageExists } from "local-pkg";
import { Linter } from 'eslint'; import type { Linter } from 'eslint';
import { ConfigNames } from './typegen'; import type { ConfigNames } from './typegen';
interface Options { interface Options {
typescript?: boolean, typescript?: boolean,

View File

@ -1,4 +1,4 @@
import { Config } from 'prettier' import type { Config } from 'prettier'
declare const e: Config declare const e: Config

View File

@ -1,3 +1,3 @@
import antdv from "@ant-design-vue/eslint-config" import antdv from '@ant-design-vue/eslint-config'
export default antdv() export default antdv()

View File

@ -21,6 +21,7 @@
"build:dev": "vite build --mode development", "build:dev": "vite build --mode development",
"dev": "vite build --watch --mode development", "dev": "vite build --watch --mode development",
"lint": "eslint . --fix", "lint": "eslint . --fix",
"format": "prettier --write .",
"tsc": "tsc --noEmit", "tsc": "tsc --noEmit",
"tsg": "tsc --declaration --declarationMap --emitDeclarationOnly --noEmit false --outDir dist/types", "tsg": "tsc --declaration --declarationMap --emitDeclarationOnly --noEmit false --outDir dist/types",
"test": "vitest" "test": "vitest"

View File

@ -1,3 +1,3 @@
// @ts-check // @ts-check
export { default } from "@ant-design-vue/prettier-config/tailwind"; export { default } from '@ant-design-vue/prettier-config/tailwind'

View File

@ -1,24 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CSSProperties } from 'vue' import type { CSSProperties } from 'vue'
import { computed, withDefaults } from 'vue' import { computed, withDefaults } from 'vue'
import { type FlexProps, flexDefaultProps } from './meta' import { type FlexProps, flexDefaultProps } from './meta'
import { isPresetSize } from '@/utils/gapSize' import { isPresetSize } from '@/utils/gapSize'
import createFlexClassNames from './utils' import createFlexClassNames from './utils'
defineOptions({ name: 'AFlex' }) defineOptions({ name: 'AFlex' })
const props = withDefaults(defineProps<FlexProps>(), flexDefaultProps) const props = withDefaults(defineProps<FlexProps>(), flexDefaultProps)
const mergedCls = computed(() => [ const mergedCls = computed(() => [
createFlexClassNames(props.prefixCls, props), createFlexClassNames(props.prefixCls, props),
{ {
'ant-flex': true, 'ant-flex': true,
'ant-flex-vertical': props.vertical, 'ant-flex-vertical': props.vertical,
'ant-flex-rtl': false, 'ant-flex-rtl': false,
[`ant-flex-gap-${props.gap}`]: isPresetSize(props.gap), [`ant-flex-gap-${props.gap}`]: isPresetSize(props.gap),
} },
]) ])
const mergedStyle = computed(() => { const mergedStyle = computed(() => {
const style: CSSProperties = {} const style: CSSProperties = {}
if (props.flex) { if (props.flex) {
@ -30,11 +30,16 @@
} }
return style return style
}) })
</script> </script>
<template> <template>
<component :is="componentTag" :class="[$attrs.class, mergedCls]" :style="[$attrs.style, mergedStyle]" v-bind="$attrs"> <component
:is="componentTag"
:class="[$attrs.class, mergedCls]"
:style="[$attrs.style, mergedStyle]"
v-bind="$attrs"
>
<slot /> <slot />
</component> </component>
</template> </template>

View File

@ -8,20 +8,20 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot()
}); })
it('Flex', () => { it('Flex', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
props: { props: {
justify: 'center' justify: 'center',
}, },
slots: { slots: {
default: `<div>test</div>` default: `<div>test</div>`,
}, },
}); })
const wrapper3 = mount(Flex, { const wrapper3 = mount(Flex, {
props: { props: {
@ -30,13 +30,13 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.classes('ant-flex')).toBeTruthy(); expect(wrapper.classes('ant-flex')).toBeTruthy()
expect(wrapper.find('.ant-flex-justify-center')).toBeTruthy(); expect(wrapper.find('.ant-flex-justify-center')).toBeTruthy()
expect(wrapper3.classes('ant-flex')).toBeTruthy(); expect(wrapper3.classes('ant-flex')).toBeTruthy()
expect(wrapper3.element.style.flex).toBe('0 1 auto'); expect(wrapper3.element.style.flex).toBe('0 1 auto')
}); })
describe('Props: gap', () => { describe('Props: gap', () => {
it('support string', () => { it('support string', () => {
@ -47,10 +47,10 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.classes('ant-flex')).toBeTruthy(); expect(wrapper.classes('ant-flex')).toBeTruthy()
expect(wrapper.element.style.gap).toBe('inherit'); expect(wrapper.element.style.gap).toBe('inherit')
}); })
it('support number', () => { it('support number', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
@ -60,10 +60,10 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.classes('ant-flex')).toBeTruthy(); expect(wrapper.classes('ant-flex')).toBeTruthy()
expect(wrapper.element.style.gap).toBe('100px'); expect(wrapper.element.style.gap).toBe('100px')
}); })
it('support preset size', () => { it('support preset size', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
@ -73,42 +73,42 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.classes('ant-flex')).toBeTruthy(); expect(wrapper.classes('ant-flex')).toBeTruthy()
expect(wrapper.classes('ant-flex-gap-small')).toBeTruthy(); expect(wrapper.classes('ant-flex-gap-small')).toBeTruthy()
}); })
}); })
it('Component work', () => { it('Component work', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
slots: { slots: {
default: `<div>test</div>` default: `<div>test</div>`,
}, },
}); })
const wrapper2 = mount(Flex, { const wrapper2 = mount(Flex, {
props: { props: {
componentTag: 'span' componentTag: 'span',
}, },
slots: { slots: {
default: `<div>test</div>` default: `<div>test</div>`,
}, },
}); })
expect(wrapper.find('.ant-flex').element.tagName).toBe('DIV'); expect(wrapper.find('.ant-flex').element.tagName).toBe('DIV')
expect(wrapper2.find('.ant-flex').element.tagName).toBe('SPAN'); expect(wrapper2.find('.ant-flex').element.tagName).toBe('SPAN')
}); })
it('when vertical=true should stretch work', () => { it('when vertical=true should stretch work', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
props: { props: {
vertical: true vertical: true,
}, },
slots: { slots: {
default: `<div>test</div>` default: `<div>test</div>`,
}, },
}); })
const wrapper2 = mount(Flex, { const wrapper2 = mount(Flex, {
props: { props: {
@ -118,11 +118,11 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.find('.ant-flex-align-stretch')).toBeTruthy(); expect(wrapper.find('.ant-flex-align-stretch')).toBeTruthy()
expect(wrapper2.find('.ant-flex-align-center')).toBeTruthy(); expect(wrapper2.find('.ant-flex-align-center')).toBeTruthy()
}); })
it('wrap prop shouled support boolean', () => { it('wrap prop shouled support boolean', () => {
const wrapper = mount(Flex, { const wrapper = mount(Flex, {
@ -132,7 +132,7 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
const wrapper2 = mount(Flex, { const wrapper2 = mount(Flex, {
props: { props: {
@ -141,9 +141,9 @@ describe('Flex', () => {
slots: { slots: {
default: `<div>test</div>`, default: `<div>test</div>`,
}, },
}); })
expect(wrapper.classes('ant-flex-wrap-wrap')).toBeTruthy(); expect(wrapper.classes('ant-flex-wrap-wrap')).toBeTruthy()
expect(wrapper2.classes('ant-flex-wrap-wrap')).toBeTruthy(); expect(wrapper2.classes('ant-flex-wrap-wrap')).toBeTruthy()
}) })
}) })

View File

@ -2,7 +2,6 @@ import type { App, Plugin } from 'vue'
import Flex from './Flex.vue' import Flex from './Flex.vue'
import './style/index.css' import './style/index.css'
export { default as Flex } from './Flex.vue' export { default as Flex } from './Flex.vue'
export * from './meta' export * from './meta'

View File

@ -1,4 +1,4 @@
import type { CSSProperties } from "vue" import type { CSSProperties } from 'vue'
type SizeType = 'small' | 'middle' | 'large' | undefined type SizeType = 'small' | 'middle' | 'large' | undefined

View File

@ -36,7 +36,7 @@ const genClsWrap = (prefixCls: string, props: FlexProps) => {
const wrapCls: Record<PropertyKey, boolean> = {} const wrapCls: Record<PropertyKey, boolean> = {}
flexWrapValues.forEach(cssKey => { flexWrapValues.forEach(cssKey => {
// Handle both boolean attribute (wrap="wrap") and string value (wrap="wrap") // Handle both boolean attribute (wrap="wrap") and string value (wrap="wrap")
const isMatch = props.wrap === true && cssKey === 'wrap' || props.wrap === cssKey const isMatch = (props.wrap === true && cssKey === 'wrap') || props.wrap === cssKey
wrapCls[`${prefixCls}-wrap-${cssKey}`] = isMatch wrapCls[`${prefixCls}-wrap-${cssKey}`] = isMatch
}) })
return wrapCls return wrapCls

View File

@ -1,4 +1,4 @@
import type { InjectionKey} from 'vue'; import type { InjectionKey } from 'vue'
import { inject, provide } from 'vue' import { inject, provide } from 'vue'
import type { ThemeProps } from './meta' import type { ThemeProps } from './meta'

View File

@ -18,15 +18,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import wrapperRaf from '@/utils/raf' import wrapperRaf from '@/utils/raf'
import { import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
computed,
nextTick,
onBeforeUnmount,
onMounted,
ref,
shallowRef,
watch,
} from 'vue'
import { getTargetWaveColor } from './util' import { getTargetWaveColor } from './util'
import isVisible from '@/utils/isVisible' import isVisible from '@/utils/isVisible'

View File

@ -1,10 +1,9 @@
export function isNotGrey(color: string) { export function isNotGrey(color: string) {
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/)
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/);
if (match && match[1] && match[2] && match[3]) { if (match && match[1] && match[2] && match[3]) {
return !(match[1] === match[2] && match[2] === match[3]); return !(match[1] === match[2] && match[2] === match[3])
} }
return true; return true
} }
export function isValidWaveColor(color: string) { export function isValidWaveColor(color: string) {
@ -17,19 +16,19 @@ export function isValidWaveColor(color: string) {
isNotGrey(color) && isNotGrey(color) &&
!/rgba\((?:\d*, ){3}0\)/.test(color) && // any transparent rgba color !/rgba\((?:\d*, ){3}0\)/.test(color) && // any transparent rgba color
color !== 'transparent' color !== 'transparent'
); )
} }
export function getTargetWaveColor(node: HTMLElement) { export function getTargetWaveColor(node: HTMLElement) {
const { borderTopColor, borderColor, backgroundColor } = getComputedStyle(node); const { borderTopColor, borderColor, backgroundColor } = getComputedStyle(node)
if (isValidWaveColor(borderTopColor)) { if (isValidWaveColor(borderTopColor)) {
return borderTopColor; return borderTopColor
} }
if (isValidWaveColor(borderColor)) { if (isValidWaveColor(borderColor)) {
return borderColor; return borderColor
} }
if (isValidWaveColor(backgroundColor)) { if (isValidWaveColor(backgroundColor)) {
return backgroundColor; return backgroundColor
} }
return null; return null
} }

View File

@ -5,4 +5,3 @@ declare module '*.vue' {
const component: DefineComponent<{}, {}, any> const component: DefineComponent<{}, {}, any>
export default component export default component
} }

View File

@ -1,25 +1,25 @@
export default (element: HTMLElement | SVGGraphicsElement): boolean => { export default (element: HTMLElement | SVGGraphicsElement): boolean => {
if (!element) { if (!element) {
return false; return false
} }
if ((element as HTMLElement).offsetParent) { if ((element as HTMLElement).offsetParent) {
return true; return true
} }
if ((element as SVGGraphicsElement).getBBox) { if ((element as SVGGraphicsElement).getBBox) {
const box = (element as SVGGraphicsElement).getBBox(); const box = (element as SVGGraphicsElement).getBBox()
if (box.width || box.height) { if (box.width || box.height) {
return true; return true
} }
} }
if ((element as HTMLElement).getBoundingClientRect) { if ((element as HTMLElement).getBoundingClientRect) {
const box = (element as HTMLElement).getBoundingClientRect(); const box = (element as HTMLElement).getBoundingClientRect()
if (box.width || box.height) { if (box.width || box.height) {
return true; return true
} }
} }
return false; return false
}; }

View File

@ -1,47 +1,47 @@
let raf = (callback: FrameRequestCallback) => setTimeout(callback, 16) as any; let raf = (callback: FrameRequestCallback) => setTimeout(callback, 16) as any
let caf = (num: number) => clearTimeout(num); let caf = (num: number) => clearTimeout(num)
if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) { if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) {
raf = (callback: FrameRequestCallback) => window.requestAnimationFrame(callback); raf = (callback: FrameRequestCallback) => window.requestAnimationFrame(callback)
caf = (handle: number) => window.cancelAnimationFrame(handle); caf = (handle: number) => window.cancelAnimationFrame(handle)
} }
let rafUUID = 0; let rafUUID = 0
const rafIds = new Map<number, number>(); const rafIds = new Map<number, number>()
function cleanup(id: number) { function cleanup(id: number) {
rafIds.delete(id); rafIds.delete(id)
} }
export default function wrapperRaf(callback: () => void, times = 1): number { export default function wrapperRaf(callback: () => void, times = 1): number {
rafUUID += 1; rafUUID += 1
const id = rafUUID; const id = rafUUID
function callRef(leftTimes: number) { function callRef(leftTimes: number) {
if (leftTimes === 0) { if (leftTimes === 0) {
// Clean up // Clean up
cleanup(id); cleanup(id)
// Trigger // Trigger
callback(); callback()
} else { } else {
// Next raf // Next raf
const realId = raf(() => { const realId = raf(() => {
callRef(leftTimes - 1); callRef(leftTimes - 1)
}); })
// Bind real raf id // Bind real raf id
rafIds.set(id, realId); rafIds.set(id, realId)
} }
} }
callRef(times); callRef(times)
return id; return id
} }
wrapperRaf.cancel = (id: number) => { wrapperRaf.cancel = (id: number) => {
const realId = rafIds.get(id); const realId = rafIds.get(id)
cleanup(realId); cleanup(realId)
return caf(realId); return caf(realId)
}; }