UNPKG

@finos/legend-application-marketplace

Version:
189 lines 9.24 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { NAVIGATION_ZONE_SEPARATOR } from '@finos/legend-application'; import { action, computed, makeObservable, observable } from 'mobx'; import {} from './DataProductViewerState.js'; import { at, guaranteeNonNullable, isNonNullable } from '@finos/legend-shared'; import { DATA_PRODUCT_VIEWER_ACTIVITY_MODE, extractActivityFromAnchor, generateAnchorForActivity, } from './DataProductViewerNavigation.js'; export const DATA_PRODUCT_WIKI_PAGE_SECTIONS = [ DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DESCRIPTION, DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER, DATA_PRODUCT_VIEWER_ACTIVITY_MODE.MODELS_DOCUMENTATION, DATA_PRODUCT_VIEWER_ACTIVITY_MODE.QUICK_START, DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DATA_ACCESS, ]; const DATA_SPACE_WIKI_PAGE_ANCHORS = DATA_PRODUCT_WIKI_PAGE_SECTIONS.map((activity) => generateAnchorForActivity(activity)); export class DataProductLayoutState { dataProductViewerState; currentNavigationZone = ''; isExpandedModeEnabled = false; frame; header; isTopScrollerVisible = false; wikiPageAnchorIndex = new Map(); wikiPageNavigationCommand; wikiPageVisibleAnchors = []; wikiPageScrollIntersectionObserver; constructor(dataProductViewerState) { makeObservable(this, { currentNavigationZone: observable, isExpandedModeEnabled: observable, isTopScrollerVisible: observable, wikiPageAnchorIndex: observable, wikiPageVisibleAnchors: observable, frame: observable.ref, wikiPageNavigationCommand: observable.ref, isWikiPageFullyRendered: computed, registerWikiPageScrollObserver: action, setCurrentNavigationZone: action, enableExpandedMode: action, setFrame: action, setTopScrollerVisible: action, setWikiPageAnchor: action, unsetWikiPageAnchor: action, setWikiPageAnchorToNavigate: action, updatePageVisibleAnchors: action, }); this.dataProductViewerState = dataProductViewerState; } setCurrentNavigationZone(val) { this.currentNavigationZone = val; } get isWikiPageFullyRendered() { return (Boolean(this.frame) && DATA_PRODUCT_WIKI_PAGE_SECTIONS.includes(this.dataProductViewerState.currentActivity) && DATA_SPACE_WIKI_PAGE_ANCHORS.every((anchor) => this.wikiPageAnchorIndex.has(anchor)) && Array.from(this.wikiPageAnchorIndex.values()).every(isNonNullable)); } registerWikiPageScrollObserver() { if (this.frame && this.isWikiPageFullyRendered) { const wikiPageIntersectionObserver = new IntersectionObserver((entries, observer) => { const anchorsWithVisibilityChanged = entries .map((entry) => { for (const [key, element] of this.wikiPageAnchorIndex.entries()) { if (element === entry.target) { return { key, isIntersecting: entry.isIntersecting }; } } return undefined; }) .filter(isNonNullable); anchorsWithVisibilityChanged.forEach((entry) => { this.updatePageVisibleAnchors(entry.key, entry.isIntersecting); }); // NOTE: sync scroll with menu/address is quite a delicate piece of work // as it interferes with programatic scroll operations we do elsewhere. // This is particularly bad when we do a programatic `smooth` scroll, which // mimic user scrolling behavior and would tangle up with this observer // Since currently, there's no good mechanism to detect scroll end event, and as such, // there is no good way to temporarily disable this logic while doing the programmatic // smooth scroll as such, we avoid supporting programatic smooth scrolling for now // See https://github.com/w3c/csswg-drafts/issues/3744 // See https://developer.mozilla.org/en-US/docs/Web/API/Document/scrollend_event if ( // if current navigation zone is not set, do not update zone this.currentNavigationZone === '' || // if there is no visible anchors, do not update zone !this.wikiPageVisibleAnchors.length || // if some of the current visible anchors match or is parent section of the current // navigation zone, do not update zone this.wikiPageVisibleAnchors.some((visibleAnchor) => this.currentNavigationZone === visibleAnchor || this.currentNavigationZone.startsWith(`${visibleAnchor}${NAVIGATION_ZONE_SEPARATOR}`))) { return; } const anchor = at(this.wikiPageVisibleAnchors, 0); // this.dataProductViewerState.syncZoneWithNavigation(anchor); const anchorChunks = anchor.split(NAVIGATION_ZONE_SEPARATOR); const activity = anchorChunks[0]; if (activity) { this.dataProductViewerState.setCurrentActivity(extractActivityFromAnchor(activity)); } }, { root: this.frame, threshold: 0.5, }); Array.from(this.wikiPageAnchorIndex.values()).forEach((el) => wikiPageIntersectionObserver.observe(el)); this.wikiPageScrollIntersectionObserver = wikiPageIntersectionObserver; } } unregisterWikiPageScrollObserver() { this.wikiPageScrollIntersectionObserver?.disconnect(); this.wikiPageScrollIntersectionObserver = undefined; this.wikiPageVisibleAnchors = []; } updatePageVisibleAnchors(changedAnchor, isIntersecting) { if (isIntersecting) { const anchors = this.wikiPageVisibleAnchors.filter((anchor) => changedAnchor !== anchor); // NOTE: the newly visible anchors should be the furthest one in // the direction of scroll anchors.push(changedAnchor); this.wikiPageVisibleAnchors = anchors; } else { this.wikiPageVisibleAnchors = this.wikiPageVisibleAnchors.filter((anchor) => changedAnchor !== anchor); } } enableExpandedMode(val) { this.isExpandedModeEnabled = val; } setFrame(val) { this.frame = val; } setTopScrollerVisible(val) { this.isTopScrollerVisible = val; } setWikiPageAnchor(anchorKey, element) { // do not allow overriding existing anchor if (!this.wikiPageAnchorIndex.has(anchorKey)) { this.wikiPageAnchorIndex.set(anchorKey, element); } } unsetWikiPageAnchor(anchorKey) { this.wikiPageAnchorIndex.delete(anchorKey); } setWikiPageAnchorToNavigate(val) { this.wikiPageNavigationCommand = val; } navigateWikiPageAnchor() { if (this.frame && this.wikiPageNavigationCommand && this.isWikiPageFullyRendered) { const anchor = this.wikiPageNavigationCommand.anchor; const matchingWikiPageSection = this.wikiPageAnchorIndex.get(anchor); const anchorChunks = anchor.split(NAVIGATION_ZONE_SEPARATOR); if (matchingWikiPageSection) { this.frame.scrollTop = matchingWikiPageSection.offsetTop - (this.header?.getBoundingClientRect().height ?? 0); } else if (generateAnchorForActivity(DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER) === anchorChunks[0]) { this.frame.scrollTop = guaranteeNonNullable(this.wikiPageAnchorIndex.get(generateAnchorForActivity(DATA_PRODUCT_VIEWER_ACTIVITY_MODE.DIAGRAM_VIEWER))).offsetTop - (this.header?.getBoundingClientRect().height ?? 0); // const matchingDiagram = // this.dataProductViewerState.dataSpaceAnalysisResult.diagrams.find( // (diagram) => generateAnchorForDiagram(diagram) === anchor, // ); // if (matchingDiagram) { // this.dataProductViewerState.diagramViewerState.setCurrentDiagram( // matchingDiagram, // ); // } } this.setWikiPageAnchorToNavigate(undefined); } } } //# sourceMappingURL=DataProductLayoutState.js.map