diff --git a/packages/kanban/src/components/KanbanRow.svelte b/packages/kanban/src/components/KanbanRow.svelte index b6bf7bd5ff..efcaf7bb0c 100644 --- a/packages/kanban/src/components/KanbanRow.svelte +++ b/packages/kanban/src/components/KanbanRow.svelte @@ -14,7 +14,7 @@ --> + +
{ + if (val) { + visible = true + dispatch('visible') + } + }} +> + {#if visible} + + {:else} + + {#if $$slots.loading} + + {:else} + ​ + {/if} + {/if} +
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 000b5e8879..efe37787f1 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -197,6 +197,7 @@ export { default as IconWithEmoji } from './components/IconWithEmoji.svelte' export { default as ModeSelector } from './components/ModeSelector.svelte' export { default as SimpleTimePopup } from './components/calendar/SimpleTimePopup.svelte' export { default as NumberInput } from './components/NumberInput.svelte' +export { default as Lazy } from './components/Lazy.svelte' export * from './types' export * from './location' @@ -208,6 +209,7 @@ export * from './components/calendar/internal/DateUtils' export * from './colors' export * from './focus' export * from './resize' +export * from './lazy' export function createApp (target: HTMLElement): SvelteComponent { return new Root({ target }) diff --git a/packages/ui/src/lazy.ts b/packages/ui/src/lazy.ts new file mode 100644 index 0000000000..49f43d310a --- /dev/null +++ b/packages/ui/src/lazy.ts @@ -0,0 +1,64 @@ +const observers = new Map() +const entryMap = new WeakMap void }>() + +function makeObserver (rootMargin: string): IntersectionObserver { + return new IntersectionObserver( + (entries, observer) => { + for (const entry of entries) { + const entryData = entryMap.get(entry.target) + if (entryData == null) { + observer.unobserve(entry.target) + continue + } + + entryData.callback(entry) + if (entry.isIntersecting) { + entryMap.delete(entry.target) + observer.unobserve(entry.target) + } + } + }, + { rootMargin } + ) +} + +function listen ( + rootMargin: string, + element: Element, + callback: (entry: IntersectionObserverEntry) => void +): () => void { + let observer = observers.get(rootMargin) + if (observer == null) { + observer = makeObserver(rootMargin) + observers.set(rootMargin, observer) + } + + entryMap.set(element, { callback }) + observer.observe(element) + return () => { + observer?.unobserve(element) + entryMap.delete(element) + } +} + +export function lazyObserver (node: Element, onVisible: (value: boolean) => void): any { + let visible = false + const lazyEnabled = (localStorage.getItem('#platform.lazy.loading') ?? 'true') === 'true' + if (!lazyEnabled) { + visible = true + onVisible(visible) + } + if (visible) { + onVisible(visible) + return {} + } + + const destroy = listen('20%', node, ({ isIntersecting }) => { + visible = isIntersecting + onVisible(visible) + }) + + return { + destroy + } +} diff --git a/plugins/activity-resources/src/components/Activity.svelte b/plugins/activity-resources/src/components/Activity.svelte index 5ba2b32c63..f91a06d112 100644 --- a/plugins/activity-resources/src/components/Activity.svelte +++ b/plugins/activity-resources/src/components/Activity.svelte @@ -19,7 +19,7 @@ import notification, { DocUpdateTx, DocUpdates, Writable } from '@hcengineering/notification' import { getResource } from '@hcengineering/platform' import { createQuery, getClient } from '@hcengineering/presentation' - import { Component, Grid, Label, Spinner } from '@hcengineering/ui' + import { Component, Grid, Label, Lazy, Spinner } from '@hcengineering/ui' import { ActivityKey, activityKey, newActivity } from '../activity' import { filterCollectionTxes } from '../utils' import ActivityFilter from './ActivityFilter.svelte' @@ -149,13 +149,15 @@ {#if filtered} {#each filtered as tx, i} - + + + {/each} {/if} diff --git a/plugins/chunter-resources/src/components/CommentPopup.svelte b/plugins/chunter-resources/src/components/CommentPopup.svelte index 12ce9e292a..9b8b419e15 100644 --- a/plugins/chunter-resources/src/components/CommentPopup.svelte +++ b/plugins/chunter-resources/src/components/CommentPopup.svelte @@ -18,7 +18,7 @@ import chunter, { Comment } from '@hcengineering/chunter' import { createQuery } from '@hcengineering/presentation' - import { Label, resizeObserver, Spinner, closeTooltip } from '@hcengineering/ui' + import { Label, resizeObserver, Spinner, closeTooltip, Lazy } from '@hcengineering/ui' import { DocNavLink, ObjectPresenter } from '@hcengineering/view-resources' import { createEventDispatcher } from 'svelte' import CommentInput from './CommentInput.svelte' @@ -79,7 +79,9 @@ {:else} {#each comments as comment}
- + + +
{/each} {/if} diff --git a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte index 11264b34f9..0864372ba8 100644 --- a/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/EditIssue.svelte @@ -200,7 +200,10 @@ - + {#if saved}