@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
191 lines (190 loc) • 11 kB
JavaScript
import * as React from 'react';
import { useState, useRef } from 'react';
import { Flex, Box, Text } from 'rebass';
import Dialog from '../../components/Dialog';
import SimpleButton from '../../components/SimpleButton';
import useProperty from '../../components/utils/useProperty';
import { isMacLike } from '../../Utilities/isMacLike';
import { KeyHint } from '../KeyHint';
import { Icon } from '../../components/icons';
import { useResizeObserver } from '../../components/ResizeObserver';
import { NamedQueryContext, } from '../../components/ExpressionEditor/NamedQueryContext';
import { useKeyboardNavigation } from './useKeyboardNavigation';
export const SummaryTag = (props) => (React.createElement(Text, { ...props }));
export const SummaryText = (props) => (React.createElement(Text, { fontSize: 2, mb: 3, ...props }));
export const FormDescriptionText = (props) => React.createElement(Text, { fontSize: 2, mt: 1, ...props });
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;
if (props.defaultCurrentSectionName) {
const candidate = visibleSections.findIndex((section) => section !== '-' && section?.title === props.defaultCurrentSectionName);
if (candidate >= 0) {
defaultCurrentIndex = candidate;
}
}
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 React.createElement(React.Fragment, { key: index });
}
return (React.createElement(Flex, { flexDirection: "column", key: index, "data-name": `section-${index}`, style: { minHeight: '100%' }, mr: 2 },
React.createElement(Box, { py: 3, paddingLeft: 2, fontSize: 4, className: "ab-OnePageWizard__details" }, section.details),
React.createElement(Box, { flex: 1, className: "ab-OnePageWizard__section" }, section.render(props.data, index))));
};
const selectedNodeRef = useRef(null);
const selectedFeedback = (React.createElement("div", { ref: selectedNodeRef, className: "ab-OnePageWizard__selected-title-overlay", style: {
position: 'absolute',
background: 'var(--ab-cmp-one-page-wizard-selected-title__background)',
pointerEvents: 'none',
borderRadius: 'var(--ab__border-radius)',
transition: 'top 0.2s',
} }));
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`;
}, [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; //!active && canFinish !== true;
if (valid !== true) {
invalidCount++;
if (firstErrorMessage == null) {
firstErrorMessage = valid;
}
}
acc.set(index, valid);
return acc;
}, new Map());
useKeyboardNavigation(setCurrentSection, visibleSections);
const canFinish = !invalidCount;
return (React.createElement(NamedQueryContext.Provider, { value: { namedQuery, setNamedQuery } },
React.createElement(OnePageWizardContext.Provider, { value: contextValue },
React.createElement(Dialog, { modal: true, isOpen: true, showCloseButton: false, focusOnBrowserVisible: true, style: {
borderRadius: 'var(--ab__border-radius)',
overflow: 'hidden',
height: '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();
});
}
}
}
} },
React.createElement(Flex, { className: "ab-OnePageWizard", flexDirection: "column", "data-name": props.name, style: {
height: '100%',
width: '90vw',
maxWidth: 1200,
...props.style,
} },
React.createElement(Flex, { flexDirection: "row", alignItems: "stretch", flex: 1, style: { overflow: 'auto' } },
React.createElement(Flex, { flexDirection: "column", padding: 3, className: "ab-OnePageWizard__section-title-container", ref: sizeOwnerRef, style: {
overflow: 'auto',
position: 'relative',
flex: 'none',
...props.titleContainerStyle,
} },
visibleSections.map((section, index) => {
if (section === '-') {
return (React.createElement(Box, { as: "hr", mt: 2, className: "ab-OnePageWizard__section-separator", key: `${index}-`, style: {
width: '100%',
border: 'none',
borderTop: `1px solid var(--ab-color-inputborder)`,
} }));
}
navIndex++;
navIndexMap.set(navIndex, index);
const active = index === currentSection;
const disabled = false; //!active && !currentSectionValid;
return (React.createElement(Flex, { className: "ab-OnePageWizard__section-title", "data-name": section.title, flexDirection: "row", style: {
cursor: disabled ? 'auto' : 'pointer',
zIndex: 10,
transition: 'color 0.2s',
opacity: disabled ? 0.5 : 1,
}, key: section.title, color: active ? 'var(--ab-cmp-one-page-wizard-section-title__color)' : '', px: 2, py: 1, mt: index ? 2 : 0, onClick: () => {
if (disabled) {
return;
}
setCurrentSection(index);
} },
React.createElement(KeyHint, { mr: 2, style: { display: 'inline-block' } }, navIndex),
React.createElement("div", { style: { flex: 1 } }, section.title),
React.createElement(Icon, { name: "error", style: {
marginLeft: 'var(--ab-space-2)',
visibility: validSectionsMap.get(index) !== true ? 'visible' : 'hidden',
} })));
}),
selectedFeedback,
React.createElement(Box, { flex: 1 }),
React.createElement(KeyHint, { style: { lineHeight: 1.5 }, className: "ab-OnePageWizard__key-hint" },
isMacLike() ? 'Cmd' : 'Ctrl',
" + #",
React.createElement("br", null),
"to navigate")),
React.createElement(Flex, { flex: 1, flexDirection: "column", className: "ab-OnePageWizard__section-container" }, renderSection(currentSection))),
React.createElement(Flex, { flexDirection: "row", padding: 2, alignItems: "center", className: "ab-WizardDialog__footer ab-OnePageWizard__footer" },
React.createElement(SimpleButton, { tone: "neutral", variant: "text", "data-name": "close", onClick: () => props.onHide?.(), tooltip: props.closeTooltip ?? 'Close wizard', accessLevel: 'Full' }, props.closeText ?? 'CLOSE'),
React.createElement(KeyHint, { ml: 2 }, "Esc"),
React.createElement(Text, { fontSize: 2, mr: 3, className: "ab-OnePageWizard__error", style: {
flex: 1,
color: 'var(--ab-color-error)',
textAlign: 'end',
} }, firstErrorMessage),
React.createElement(SimpleButton, { tone: "accent", "data-name": "finish", variant: "raised", disabled: canFinish !== true, onClick: () => handleClickFinish(), icon: 'check', accessLevel: 'Full' }, props.finishText ?? 'Finish')))))));
};