UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

148 lines 6.46 kB
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