@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
189 lines (188 loc) • 13.7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import * as React from 'react';
import { useState, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { cn } from '../../lib/utils';
import Dialog from '../../components/Dialog';
import SimpleButton from '../../components/SimpleButton';
import useProperty from '../../components/utils/useProperty';
import { isMacLike } from '../../Utilities/isMacLike';
import { ACCESS_LEVEL_FULL } from '../../Utilities/Constants/GeneralConstants';
import { KeyHint } from '../KeyHint';
import { Icon } from '../../components/icons';
import { useResizeObserver } from '../../components/ResizeObserver';
import { NamedQueryContext, } from '../../components/ExpressionEditor/NamedQueryContext';
import { useKeyboardNavigation } from './useKeyboardNavigation';
import { Box, Flex } from '../../components/Flex';
import { twMerge } from '../../twMerge';
import { targetOwn } from '../../components/twUtils';
import { useAdaptable } from '../AdaptableContext';
import { getMiddlePosition, getWizardSize } from '../Components/Popups/Utilities';
import { SettingsPanelSet } from '../../Redux/ActionsReducers/InternalRedux';
const ONE_PAGE_WIZARD_SECTION_GRID = 'twa:grid twa:grid-cols-[minmax(160px,14rem)_minmax(0,1fr)]';
export const SummaryTag = (props) => (_jsx(Box, { ...props }));
export const SummaryText = (props) => (_jsx(Box, { ...props, className: twMerge('twa:text-2 twa:mb-3', props.className) }));
export const FormDescriptionText = (props) => _jsx(Box, { ...props, className: twMerge('twa:text-2 twa:mt-1', props.className) });
export const OnePageWizardContext = React.createContext({
data: null,
sections: [],
setCurrentSection: (index) => { },
});
export function useOnePageWizardContext() {
return React.useContext(OnePageWizardContext);
}
export const OnePageWizard = (props) => {
let defaultCurrentIndex = 0;
const [currentSection, setCurrentSection] = useProperty(props, 'currentIndex', defaultCurrentIndex, {
onChange: (index) => {
props.onSectionChange?.(index);
},
});
const contextValue = {
data: props.data,
sections: props.sections,
setCurrentSection,
};
const visibleSections = React.useMemo(() => {
return props.sections
.filter(Boolean)
.filter((section) => section === '-' ||
section.isVisible == undefined ||
section.isVisible(props.data, contextValue));
}, [props.sections]);
contextValue.sections = visibleSections;
const lastAppliedDefaultSectionName = React.useRef(undefined);
React.useEffect(() => {
if (!props.defaultCurrentSectionName) {
return;
}
if (lastAppliedDefaultSectionName.current === props.defaultCurrentSectionName) {
return;
}
const candidate = visibleSections.findIndex((section) => section !== '-' && section?.title === props.defaultCurrentSectionName);
if (candidate >= 0) {
setCurrentSection(candidate);
lastAppliedDefaultSectionName.current = props.defaultCurrentSectionName;
}
}, [props.defaultCurrentSectionName, visibleSections]);
const [namedQuery, setNamedQuery] = useState(false);
const [navIndexMap] = useState(() => new Map());
const handleClickFinish = () => {
props.onFinish?.(props.data);
};
const renderSection = (index) => {
const section = visibleSections[index];
if (section === '-') {
return _jsx(React.Fragment, {}, index);
}
return (_jsx(Flex, { flexDirection: "column", "data-name": `section-${index}`, className: "twa:flex-1 twa:overflow-hidden", children: _jsx(Box, { className: "ab-OnePageWizard__section twa:flex-1 twa:rounded-standard twa:overflow-auto twa:bg-background", children: section.render(props.data, index) }) }, index));
};
const handleNavigation = useKeyboardNavigation(setCurrentSection, visibleSections);
const selectedNodeRef = useRef(null);
const selectedFeedback = (_jsx("div", { ref: selectedNodeRef, onKeyDown: (event) => handleNavigation(event), tabIndex: 0, className: cn('ab-OnePageWizard__selected-title-overlay', 'twa:absolute twa:rounded-standard twa:select-none twa:bg-accent twa:transition-top twa:duration-200', targetOwn.focusOutline) }));
const sizeOwnerRef = useRef(null);
const [width, setWidth] = useState(0);
useResizeObserver(sizeOwnerRef, ({ width }) => {
setWidth(width);
});
React.useEffect(() => {
const node = selectedNodeRef.current;
const parent = node.parentNode;
const activeElement = parent.children[currentSection];
node.style.top = `${activeElement.offsetTop}px`;
node.style.left = `${activeElement.offsetLeft}px`;
node.style.height = `${activeElement.offsetHeight}px`;
node.style.width = `${activeElement.offsetWidth}px`;
node.focus();
}, [currentSection, width]);
let navIndex = 0;
const dialogRef = useRef(null);
let invalidCount = 0;
let firstErrorMessage = null;
const validSectionsMap = visibleSections.reduce((acc, section, index) => {
if (section === '-') {
acc.set(index, true);
return acc;
}
const valid = section.isValid ? section.isValid(props.data, contextValue) : true;
if (valid !== true) {
invalidCount++;
if (firstErrorMessage == null) {
firstErrorMessage = valid;
}
}
acc.set(index, valid);
return acc;
}, new Map());
const canFinish = !invalidCount;
const activeSection = visibleSections[currentSection];
const activeSectionDetails = activeSection !== '-' ? activeSection?.details : undefined;
const adaptable = useAdaptable();
const wizardOptions = adaptable.adaptableOptions.wizardOptions;
const isWindowMode = wizardOptions?.popupType === 'window' && props.modal !== false;
const wizardSettingsKey = `wizard-${props.name || 'unnamed'}`;
const dispatch = useDispatch();
const persistedWizardSettings = useSelector((state) => state?.Internal?.SettingsPanel?.[wizardSettingsKey]);
let windowModalProps;
if (isWindowMode) {
const size = persistedWizardSettings?.size ?? wizardOptions?.size ?? getWizardSize();
const position = persistedWizardSettings?.position ?? wizardOptions?.position ?? getMiddlePosition(size);
windowModalProps = {
handleSelector: '.ab-OnePageWizard__header',
minHeight: 460,
minWidth: 400,
size,
position,
onChange: (settings) => {
dispatch(SettingsPanelSet(wizardSettingsKey, settings));
},
};
}
return (_jsx(NamedQueryContext.Provider, { value: { namedQuery, setNamedQuery }, children: _jsx(OnePageWizardContext.Provider, { value: contextValue, children: _jsx(Dialog, { modal: isWindowMode ? false : props.modal ?? true, windowModal: isWindowMode, windowModalProps: windowModalProps, fixed: !isWindowMode, isOpen: true, showCloseButton: false, focusOnBrowserVisible: true, className: cn('twa:rounded-standard twa:overflow-hidden', isWindowMode ? 'twa:h-full' : 'twa:h-[90vh]'), ref: dialogRef, onDismiss: () => props.onHide?.(), onKeyDown: (event) => {
if (event.metaKey || event.ctrlKey) {
const { key } = event;
if (!isNaN(Number(key))) {
const num = Number(key);
if (navIndexMap.has(num)) {
const index = navIndexMap.get(num);
setCurrentSection(index);
event.preventDefault();
event.stopPropagation();
requestAnimationFrame(() => {
dialogRef?.current?.bringToFront();
});
}
}
}
}, children: _jsxs(Box, { className: cn('ab-OnePageWizard twa:flex twa:flex-col twa:h-full', isWindowMode ? 'twa:w-full' : 'twa:w-[90vw] twa:max-w-[1200px]', 'twa:bg-primarylight twa:text-primary-foreground'), "data-name": props.name, style: props.style, children: [(props.moduleName || activeSectionDetails) && (_jsxs(Box, { className: cn('ab-OnePageWizard__header', ONE_PAGE_WIZARD_SECTION_GRID, 'twa:items-start twa:my-3 twa:px-2'), children: [_jsx(Box, { className: "ab-OnePageWizard__module-name twa:min-w-0 twa:pl-3 twa:font-bold", children: props.moduleName }), _jsx(Box, { className: "ab-OnePageWizard__details twa:min-w-0 twa:pr-2 twa:text-4", children: activeSectionDetails })] })), _jsx(Box, { as: "hr", className: "ab-OnePageWizard__module-separator twa:w-full twa:border-0 twa:border-t twa:border-t-input-border twa:mb-2" }), _jsxs(Box, { className: cn(ONE_PAGE_WIZARD_SECTION_GRID, 'twa:flex-1 twa:min-h-0 twa:overflow-auto twa:items-stretch'), children: [_jsxs(Flex, { flexDirection: "column", className: "ab-OnePageWizard__section-title-container twa:min-h-0 twa:min-w-0 twa:overflow-auto twa:p-3 twa:relative", ref: sizeOwnerRef, style: props.titleContainerStyle, children: [visibleSections.map((section, index) => {
if (section === '-') {
return (_jsx(Box, { as: "hr", className: "ab-OnePageWizard__section-separator twa:mt-2 twa:w-full twa:border-t twa:border-t-input-border" }, `${index}-`));
}
navIndex++;
navIndexMap.set(navIndex, index);
const active = index === currentSection;
const disabled = false;
return (_jsxs(Flex, { className: cn('ab-OnePageWizard__section-title twa:p-2', {
'twa:cursor-auto': disabled,
'twa:cursor-pointer': !disabled,
'twa:z-10': true,
'twa:opacity-50': disabled,
'twa:opacity-100': !disabled,
'twa:mt-2': index > 0,
'twa:mt-0': index === 0,
'twa:text-accent-foreground twa:pointer-events-none': active,
}), "data-name": section.title, flexDirection: "row", style: {
transition: 'color 0.2s',
}, onClick: () => {
if (disabled) {
return;
}
if (active) {
return;
}
setCurrentSection(index);
}, children: [_jsx(KeyHint, { className: cn('twa:mr-2 twa:inline-block', {
'twa:text-accent-foreground': active,
}), children: navIndex }), _jsx("div", { className: "twa:flex-1", children: section.title }), _jsx(Icon, { name: "error", className: cn('twa:ml-2', validSectionsMap.get(index) !== true ? 'twa:visible' : 'twa:invisible') })] }, section.title));
}), selectedFeedback, _jsx(Box, { className: "twa:flex-1" }), _jsxs(KeyHint, { className: "ab-OnePageWizard__key-hint twa:leading-normal", children: [isMacLike() ? 'Cmd' : 'Ctrl', " + #", _jsx("br", {}), "or arrow keys", _jsx("br", {}), "to navigate"] })] }), _jsxs(Flex, { flexDirection: "column", className: "ab-OnePageWizard__section-container twa:overflow-hidden twa:min-w-0 twa:flex-1 twa:gap-2 twa:mr-2", children: [props.headerPreview ? (_jsxs(_Fragment, { children: [_jsx(Box, { className: "ab-OnePageWizard__header-preview", children: props.headerPreview }), _jsx(Box, { as: "hr", className: "ab-OnePageWizard__header-preview-separator twa:w-full twa:border-0 twa:border-t twa:my-0 twa:border-t-input-border" })] })) : null, renderSection(currentSection)] })] }), _jsxs(Flex, { flexDirection: "row", alignItems: "center", className: "ab-WizardDialog__footer ab-OnePageWizard__footer twa:p-2", children: [_jsx(SimpleButton, { tone: "neutral", variant: "text", "data-name": "close", onClick: () => props.onHide?.(), tooltip: props.closeTooltip ?? 'Close wizard', accessLevel: ACCESS_LEVEL_FULL, children: props.closeText ?? 'CLOSE' }), _jsx(KeyHint, { className: "twa:ml-2", children: "Esc" }), _jsx(Box, { className: "ab-OnePageWizard__error twa:text-2 twa:mr-3 twa:flex-1 twa:text-destructive twa:text-end", children: firstErrorMessage }), _jsx(SimpleButton, { tone: "accent", "data-name": "finish", variant: "raised", disabled: canFinish !== true, onClick: () => handleClickFinish(), icon: 'check', accessLevel: ACCESS_LEVEL_FULL, children: props.finishText ?? 'Finish' })] })] }) }) }) }));
};