@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
148 lines • 6.46 kB
JavaScript
import { Shade, createComponent } from '@furystack/shades';
import { cssVariableTheme } from '../../services/css-variable-theme.js';
import { Tabs } from '../tabs.js';
import { MarkdownDisplay } from './markdown-display.js';
import { MarkdownInput } from './markdown-input.js';
import { resolveValidationState } from './markdown-validation.js';
/**
* Combined Markdown editor with an input pane and a live preview pane.
* Supports three layouts: side-by-side, tabs (Edit/Preview), or above-below.
*/
export const MarkdownEditor = Shade({
customElementName: 'shade-markdown-editor',
css: {
display: 'flex',
fontFamily: cssVariableTheme.typography.fontFamily,
flexDirection: 'column',
minHeight: '0',
'& .md-editor-label': {
fontSize: cssVariableTheme.typography.fontSize.xs,
color: cssVariableTheme.text.secondary,
padding: `0 0 ${cssVariableTheme.spacing.sm} 0`,
transition: `color ${cssVariableTheme.transitions.duration.slow} ${cssVariableTheme.transitions.easing.default}`,
},
'&[data-invalid] .md-editor-label': {
color: cssVariableTheme.palette.error.main,
},
'& .md-editor-frame': {
display: 'flex',
flexDirection: 'column',
border: `1px solid ${cssVariableTheme.action.subtleBorder}`,
borderRadius: cssVariableTheme.shape.borderRadius.md,
overflow: 'hidden',
flex: '1',
minHeight: '0',
},
'&[data-invalid] .md-editor-frame': {
borderColor: cssVariableTheme.palette.error.main,
},
'& .md-editor-helperText': {
fontSize: cssVariableTheme.typography.fontSize.xs,
padding: `${cssVariableTheme.spacing.sm} 0 0 0`,
opacity: '0.85',
lineHeight: '1.4',
},
'& .md-editor-split': {
display: 'flex',
flex: '1',
minHeight: '0',
},
'& .md-editor-split[data-layout="side-by-side"]': {
flexDirection: 'row',
},
'& .md-editor-split[data-layout="above-below"]': {
flexDirection: 'column',
minHeight: 'auto',
},
'& .md-editor-pane': {
flex: '1',
minWidth: '0',
minHeight: '0',
overflow: 'auto',
display: 'flex',
flexDirection: 'column',
},
'& .md-editor-pane-input': {
borderRight: 'none',
},
'& .md-editor-split[data-layout="side-by-side"] .md-editor-pane-input': {
borderRight: `1px solid ${cssVariableTheme.action.subtleBorder}`,
},
'& .md-editor-split[data-layout="above-below"] .md-editor-pane-input': {
borderBottom: `1px solid ${cssVariableTheme.action.subtleBorder}`,
},
'& .md-editor-split[data-layout="above-below"] .md-editor-pane': {
flex: 'none',
overflow: 'visible',
minHeight: 'auto',
},
'& .md-editor-split[data-layout="above-below"] shade-markdown-input textarea': {
overflow: 'hidden',
fieldSizing: 'content',
},
'& .md-editor-pane-preview': {
padding: cssVariableTheme.spacing.md,
},
'& shade-markdown-input': {
marginBottom: '0',
flex: '1',
display: 'flex',
flexDirection: 'column',
},
'& shade-markdown-input label': {
border: 'none',
borderRadius: '0',
flex: '1',
display: 'flex',
flexDirection: 'column',
},
'& shade-markdown-input textarea': {
flex: '1',
resize: 'none',
},
'& shade-tabs': {
flex: '1',
minHeight: '0',
},
'& .md-editor-tab-content': {
padding: cssVariableTheme.spacing.md,
overflow: 'auto',
},
},
render: ({ props, useState, useHostProps }) => {
const layout = props.layout ?? 'side-by-side';
const { isInvalid, helperNode } = resolveValidationState(props);
useHostProps({
...(props.style ? { style: props.style } : {}),
'data-invalid': isInvalid ? '' : undefined,
});
const [activeTab, setActiveTab] = useState('activeTab', 'edit');
const inputPane = (createComponent(MarkdownInput, { value: props.value, onValueChange: props.onValueChange, maxImageSizeBytes: props.maxImageSizeBytes, readOnly: props.readOnly, name: props.name, required: props.required, disabled: props.disabled, placeholder: props.placeholder, rows: props.rows, getValidationResult: props.getValidationResult, hideChrome: true }));
const previewPane = createComponent(MarkdownDisplay, { content: props.value, readOnly: false, onChange: props.onValueChange });
let content;
if (layout === 'tabs') {
content = (createComponent(Tabs, { activeKey: activeTab, onTabChange: (key) => setActiveTab(key), tabs: [
{
header: createComponent(createComponent, null, "Edit"),
hash: 'edit',
component: createComponent("div", { className: "md-editor-tab-content" }, inputPane),
},
{
header: createComponent(createComponent, null, "Preview"),
hash: 'preview',
component: createComponent("div", { className: "md-editor-tab-content" }, previewPane),
},
] }));
}
else {
content = (createComponent("div", { className: "md-editor-split", "data-layout": layout },
createComponent("div", { className: "md-editor-pane md-editor-pane-input" }, inputPane),
createComponent("div", { className: "md-editor-pane md-editor-pane-preview" }, previewPane)));
}
return (createComponent(createComponent, null,
props.labelTitle ? createComponent("span", { className: "md-editor-label" }, props.labelTitle) : null,
createComponent("div", { className: "md-editor-frame" }, content),
helperNode ? createComponent("span", { className: "md-editor-helperText" }, helperNode) : null));
},
});
//# sourceMappingURL=markdown-editor.js.map