@zohodesk/docs-builder
Version:
docs-builder is used to build your own docs
369 lines (350 loc) • 12 kB
JavaScript
import React, { useState, useEffect, useRef, useMemo } from "react";
import { Route, Switch, useRouteMatch, useHistory } from "react-router-dom";
import PropTypes from "../PropTypes/PropTypes";
import DocsCode from "../DocsCode/DocsCode";
import { ComponentPlayground } from "@zohodesk-private/component-playground";
import styles from "./Preview.module.css";
import { useResizer } from "./useResizer";
function IFrame(props) {
return /*#__PURE__*/React.createElement("iframe", { ...props,
ref: props.eref
});
} // Custom NavLink component to avoid default Link styling and handle active state
const TabLink = _ref => {
let {
to,
isActive,
disabled,
className,
onClick,
children
} = _ref;
const history = useHistory();
const handleClick = e => {
if (disabled) {
e.preventDefault();
return;
}
if (onClick) {
onClick(e);
}
history.push(to);
};
return /*#__PURE__*/React.createElement("button", {
onClick: handleClick,
className: `${className} ${isActive ? styles.activeTab : ""} ${disabled ? styles.disabledTab : ""}`,
disabled: disabled
}, children);
};
export default function Preview(_ref2) {
let {
componentName,
components,
handleFullScreen,
isFullScreen
} = _ref2;
const iframeRef = useRef(null);
const sliderRef = useRef(null);
const match = useRouteMatch();
const history = useHistory();
const resizerRef = useRef(null);
const iframeContainerRef = useRef(null);
const [device, setDevice] = useState("DEFAULT");
const [loading, setLoading] = useState(true);
const [frameWidth, setFrameWidth] = useState("100%");
const [isRTL, setIsRTL] = useState(false);
const [isContentEditable, setIsContentEditable] = useState(false);
const [windowSize, setWindowSize] = useState({
height: 0,
width: 0
});
const [isResizingStarted, setIsResizingStarted] = useState(false);
const {
isResizing
} = useResizer({
resizerHandleRef: resizerRef,
resizableElementRef: iframeContainerRef,
orientation: 'vertical',
enabled: true,
onWidthChange: width => {
setFrameWidth(width);
},
onResizeStart: started => {
setIsResizingStarted(started);
}
});
const handleIframeLoad = () => {
setLoading(false);
};
useEffect(() => {
// Initial setup
if (sliderRef.current) {
sliderRef.current.value = "11";
iframeSize();
}
}, []);
useEffect(() => {
const iframeDocument = iframeRef.current?.contentDocument || iframeRef.current?.contentWindow?.document;
if (iframeDocument) {
iframeDocument.body.style.direction = isRTL ? "rtl" : "ltr";
iframeDocument.body.setAttribute("contentEditable", isContentEditable ? "true" : "false");
}
}, [isRTL, isContentEditable]);
const handleContentEditable = () => {
setIsContentEditable(prevState => !prevState);
};
const handleReload = () => {
setLoading(true);
iframeRef.current.contentWindow.location.reload(true);
};
const handleRTL = () => {
setIsRTL(prevState => !prevState);
};
const handleReset = () => {
if (sliderRef.current) {
sliderRef.current.value = "11";
iframeSize();
}
};
function iframeSize() {
let value = sliderRef.current.value;
let sizes = {
"1": {
device: "MOBILE_XS",
frameWidth: 320
},
"2": {
device: "MOBILE_S",
frameWidth: 360
},
"3": {
device: "MOBILE_M",
frameWidth: 375.04
},
"4": {
device: "MOBILE",
frameWidth: 480
},
"5": {
device: "TABLET_S",
frameWidth: 640
},
"6": {
device: "TABLET_M",
frameWidth: 720
},
"7": {
device: "TABLET",
frameWidth: 768
},
"8": {
device: "LAPTOP_S",
frameWidth: 1024
},
"9": {
device: "LAPTOP_M",
frameWidth: 1280
},
"10": {
device: "LAPTOP",
frameWidth: 1440
},
"11": {
device: "DEFAULT",
frameWidth: `100%`
},
"12": {
device: "MONITOR_M",
frameWidth: 1600
},
"13": {
device: "MONITOR",
frameWidth: 1920
}
};
setIsResizingStarted(false);
setDevice(sizes[value].device);
setFrameWidth(sizes[value].frameWidth);
getWindow();
}
function getWindow() {
if (iframeRef.current) {
setWindowSize({
height: iframeRef.current.offsetHeight,
width: iframeRef.current.offsetWidth
});
}
}
const playGroundData = useMemo(() => components[componentName]?.docs?.playgroundProps, [components, componentName]);
const displayName = componentName.split("__")[1] || componentName;
const baseUrl = `/all/${componentName}`; // Determine active tab based on current path
const currentPath = history.location.pathname;
const isComponentActive = currentPath === baseUrl;
const isPropTypesActive = currentPath === `${baseUrl}/proptypes`;
const isCodeActive = currentPath === `${baseUrl}/code`;
const isPlaygroundActive = currentPath === `${baseUrl}/playground`;
return /*#__PURE__*/React.createElement("div", {
className: styles.previewContainer
}, /*#__PURE__*/React.createElement("header", {
className: styles.header
}, /*#__PURE__*/React.createElement("div", {
className: styles.headerContent
}, /*#__PURE__*/React.createElement("div", {
className: styles.titleArea
}, /*#__PURE__*/React.createElement("h1", {
className: styles.componentTitle
}, displayName)), /*#__PURE__*/React.createElement("nav", {
className: styles.tabsContainer
}, /*#__PURE__*/React.createElement("div", {
className: styles.tabs
}, /*#__PURE__*/React.createElement(TabLink, {
to: baseUrl,
className: styles.tab,
isActive: isComponentActive
}, /*#__PURE__*/React.createElement("span", {
className: styles.tabIcon
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-cube"
})), "Component"), /*#__PURE__*/React.createElement(TabLink, {
to: `${baseUrl}/proptypes`,
className: styles.tab,
isActive: isPropTypesActive
}, /*#__PURE__*/React.createElement("span", {
className: styles.tabIcon
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-list-check"
})), "PropTypes"), /*#__PURE__*/React.createElement(TabLink, {
to: `${baseUrl}/code`,
className: styles.tab,
isActive: isCodeActive
}, /*#__PURE__*/React.createElement("span", {
className: styles.tabIcon
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-code"
})), "Code"), /*#__PURE__*/React.createElement(TabLink, {
to: `${baseUrl}/playground`,
className: styles.tab,
isActive: isPlaygroundActive,
disabled: !playGroundData
}, /*#__PURE__*/React.createElement("span", {
className: styles.tabIcon
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-puzzle-piece"
})), "Playground"))))), /*#__PURE__*/React.createElement("div", {
className: styles.contentArea
}, /*#__PURE__*/React.createElement(Switch, null, /*#__PURE__*/React.createElement(Route, {
exact: true,
path: baseUrl
}, /*#__PURE__*/React.createElement("div", {
className: styles.componentView
}, /*#__PURE__*/React.createElement("div", {
className: styles.iframeContainer,
style: {
width: `${frameWidth == "100%" ? frameWidth : `${frameWidth}px`}`
},
ref: iframeContainerRef
}, loading && /*#__PURE__*/React.createElement("div", {
className: styles.loadingOverlay,
id: "loadingText"
}, /*#__PURE__*/React.createElement("div", {
className: styles.loadingSpinner
}, /*#__PURE__*/React.createElement("div", null), /*#__PURE__*/React.createElement("div", null))), isResizing && /*#__PURE__*/React.createElement("div", {
className: styles.resizeOverlay
}), /*#__PURE__*/React.createElement(IFrame, {
id: "componentIframe",
className: styles.iframe,
src: `#/preview/${componentName}`,
eref: iframeRef,
onLoad: handleIframeLoad
}), /*#__PURE__*/React.createElement("div", {
ref: resizerRef,
className: styles.resizeHandle
}, /*#__PURE__*/React.createElement("div", {
className: styles.resizeHandleBar
})))), /*#__PURE__*/React.createElement("div", {
className: styles.toolbar
}, /*#__PURE__*/React.createElement("div", {
className: styles.toolbarActions
}, /*#__PURE__*/React.createElement("button", {
onClick: handleReload,
className: styles.toolbarButton,
title: "Reload"
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-arrow-rotate-left"
})), /*#__PURE__*/React.createElement("a", {
className: styles.toolbarButton,
href: `#/preview/${componentName}`,
target: "_blank",
rel: "noopener noreferrer",
title: "Open in new tab"
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-up-right-from-square"
})), /*#__PURE__*/React.createElement("button", {
className: `${styles.toolbarButton} ${isRTL ? styles.active : ""}`,
onClick: handleRTL,
title: "Toggle RTL"
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-paragraph"
})), /*#__PURE__*/React.createElement("button", {
className: `${styles.toolbarButton} ${isContentEditable ? styles.active : ""}`,
onClick: handleContentEditable,
title: "Toggle content editable"
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-pen-to-square"
})), /*#__PURE__*/React.createElement("button", {
className: `${styles.toolbarButton} ${isFullScreen ? styles.active : ""}`,
onClick: handleFullScreen,
title: "Toggle fullscreen"
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-expand"
}))), /*#__PURE__*/React.createElement("div", {
className: styles.resizeControls
}, /*#__PURE__*/React.createElement("button", {
onClick: handleReset,
className: `${styles.resetButton}`,
title: "Reset to default width",
disabled: frameWidth === "100%"
}, "Reset"), /*#__PURE__*/React.createElement("input", {
min: "1",
max: "13",
type: "range",
defaultValue: "11",
step: "1",
id: "myRange",
className: styles.rangeSlider,
ref: sliderRef,
onChange: iframeSize,
disabled: isResizing
}), /*#__PURE__*/React.createElement("div", {
className: styles.deviceInfo
}, /*#__PURE__*/React.createElement("span", {
className: styles.deviceType
}, isResizingStarted ? "CUSTOM" : device), windowSize && windowSize.width > 0 && /*#__PURE__*/React.createElement("span", {
className: styles.dimensions
}, frameWidth, " \xD7 ", windowSize.height))))), /*#__PURE__*/React.createElement(Route, {
path: `${baseUrl}/proptypes`
}, /*#__PURE__*/React.createElement("div", {
className: styles.propTypesView
}, /*#__PURE__*/React.createElement(PropTypes, {
Components: components,
propComName: componentName
}))), /*#__PURE__*/React.createElement(Route, {
path: `${baseUrl}/code`
}, /*#__PURE__*/React.createElement("div", {
className: styles.codeView
}, /*#__PURE__*/React.createElement(DocsCode, {
components: components,
propComName: componentName
}))), /*#__PURE__*/React.createElement(Route, {
path: `${baseUrl}/playground`
}, /*#__PURE__*/React.createElement("div", {
className: styles.playgroundView
}, playGroundData ? /*#__PURE__*/React.createElement(ComponentPlayground, { ...playGroundData
}) : /*#__PURE__*/React.createElement("div", {
className: styles.noPlayground
}, /*#__PURE__*/React.createElement("div", {
className: styles.emptyState
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-puzzle-piece"
}), /*#__PURE__*/React.createElement("h2", null, "No Playground Available"), /*#__PURE__*/React.createElement("p", null, "This component doesn't have a playground configured."))))))));
}