Support for YAML content
This commit is contained in:
parent
bbbf3c5621
commit
fcd0ce718a
@ -1,14 +1,14 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import Widgets from './Widgets';
|
import {resolveWidget} from './Widgets';
|
||||||
|
|
||||||
export default class ControlPane extends React.Component {
|
export default class ControlPane extends React.Component {
|
||||||
controlFor(field) {
|
controlFor(field) {
|
||||||
const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||||
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
const widget = resolveWidget(field.get('widget'));
|
||||||
return <div className="cms-control">
|
return <div className="cms-control">
|
||||||
<label>{ field.get('label') }</label>
|
<label>{ field.get('label') }</label>
|
||||||
{React.createElement(widget.Control, {
|
{React.createElement(widget.control, {
|
||||||
field: field,
|
field: field,
|
||||||
value: entry.getIn(['data', field.get('name')]),
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
onChange: (value) => onChange(entry.setIn(['data', field.get('name')], value)),
|
onChange: (value) => onChange(entry.setIn(['data', field.get('name')], value)),
|
||||||
|
10
src/components/EntryEditor.css
Normal file
10
src/components/EntryEditor.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.container {
|
||||||
|
display: flex
|
||||||
|
}
|
||||||
|
.controlPane {
|
||||||
|
width: 50%;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
.previewPane {
|
||||||
|
width: 50%;
|
||||||
|
}
|
@ -2,13 +2,14 @@ import React, { PropTypes } from 'react';
|
|||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ControlPane from './ControlPane';
|
import ControlPane from './ControlPane';
|
||||||
import PreviewPane from './PreviewPane';
|
import PreviewPane from './PreviewPane';
|
||||||
|
import styles from './EntryEditor.css';
|
||||||
|
|
||||||
export default function EntryEditor({ collection, entry, getMedia, onChange, onAddMedia, onRemoveMedia, onPersist }) {
|
export default function EntryEditor({ collection, entry, getMedia, onChange, onAddMedia, onRemoveMedia, onPersist }) {
|
||||||
return <div>
|
return <div>
|
||||||
<h1>Entry in {collection.get('label')}</h1>
|
<h1>Entry in {collection.get('label')}</h1>
|
||||||
<h2>{entry && entry.get('title')}</h2>
|
<h2>{entry && entry.get('title')}</h2>
|
||||||
<div className="cms-container" style={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className="cms-control-pane" style={styles.controlPane}>
|
<div className={styles.controlPane}>
|
||||||
<ControlPane
|
<ControlPane
|
||||||
collection={collection}
|
collection={collection}
|
||||||
entry={entry}
|
entry={entry}
|
||||||
@ -18,7 +19,7 @@ export default function EntryEditor({ collection, entry, getMedia, onChange, onA
|
|||||||
onRemoveMedia={onRemoveMedia}
|
onRemoveMedia={onRemoveMedia}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="cms-preview-pane" style={styles.pane}>
|
<div className={styles.previewPane}>
|
||||||
<PreviewPane collection={collection} entry={entry} getMedia={getMedia} />
|
<PreviewPane collection={collection} entry={entry} getMedia={getMedia} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -26,20 +27,6 @@ export default function EntryEditor({ collection, entry, getMedia, onChange, onA
|
|||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = {
|
|
||||||
container: {
|
|
||||||
display: 'flex'
|
|
||||||
},
|
|
||||||
controlPane: {
|
|
||||||
width: '50%',
|
|
||||||
paddingLeft: '10px',
|
|
||||||
paddingRight: '10px'
|
|
||||||
},
|
|
||||||
pane: {
|
|
||||||
width: '50%'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EntryEditor.propTypes = {
|
EntryEditor.propTypes = {
|
||||||
collection: ImmutablePropTypes.map.isRequired,
|
collection: ImmutablePropTypes.map.isRequired,
|
||||||
entry: ImmutablePropTypes.map.isRequired,
|
entry: ImmutablePropTypes.map.isRequired,
|
||||||
|
@ -60,7 +60,8 @@ export default class EntryListing extends React.Component {
|
|||||||
|
|
||||||
cardFor(collection, entry, link) {
|
cardFor(collection, entry, link) {
|
||||||
//const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
//const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||||
const card = Cards[collection.getIn(['card', 'type'])] || Cards._unknown;
|
const cartType = collection.getIn(['card', 'type']) || 'alltype';
|
||||||
|
const card = Cards[cartType] || Cards._unknown;
|
||||||
return React.createElement(card, {
|
return React.createElement(card, {
|
||||||
key: entry.get('slug'),
|
key: entry.get('slug'),
|
||||||
collection: collection,
|
collection: collection,
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { getPreviewTemplate, getPreviewStyles } from '../lib/registry';
|
import registry from '../lib/registry';
|
||||||
import Widgets from './Widgets';
|
import { resolveWidget } from './Widgets';
|
||||||
import styles from './PreviewPane.css';
|
import styles from './PreviewPane.css';
|
||||||
|
|
||||||
class Preview extends React.Component {
|
class Preview extends React.Component {
|
||||||
previewFor(field) {
|
previewFor(field) {
|
||||||
const { entry, getMedia } = this.props;
|
const { entry, getMedia } = this.props;
|
||||||
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
const widget = resolveWidget(field.get('widget'));
|
||||||
return React.createElement(widget.Preview, {
|
return React.createElement(widget.preview, {
|
||||||
field: field,
|
field: field,
|
||||||
value: entry.getIn(['data', field.get('name')]),
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
getMedia: getMedia,
|
getMedia: getMedia,
|
||||||
@ -46,8 +46,8 @@ export default class PreviewPane extends React.Component {
|
|||||||
widgetFor(name) {
|
widgetFor(name) {
|
||||||
const { collection, entry, getMedia } = this.props;
|
const { collection, entry, getMedia } = this.props;
|
||||||
const field = collection.get('fields').find((field) => field.get('name') === name);
|
const field = collection.get('fields').find((field) => field.get('name') === name);
|
||||||
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
const widget = resolveWidget(field.get('widget'));
|
||||||
return React.createElement(widget.Preview, {
|
return React.createElement(widget.preview, {
|
||||||
field: field,
|
field: field,
|
||||||
value: entry.getIn(['data', field.get('name')]),
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
getMedia: getMedia,
|
getMedia: getMedia,
|
||||||
@ -56,14 +56,14 @@ export default class PreviewPane extends React.Component {
|
|||||||
|
|
||||||
renderPreview() {
|
renderPreview() {
|
||||||
const props = Object.assign({}, this.props, {widgetFor: this.widgetFor});
|
const props = Object.assign({}, this.props, {widgetFor: this.widgetFor});
|
||||||
const component = getPreviewTemplate(props.collection.get('name')) || Preview;
|
const component = registry.getPreviewTemplate(props.collection.get('name')) || Preview;
|
||||||
|
|
||||||
render(React.createElement(component, props), this.previewEl);
|
render(React.createElement(component, props), this.previewEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIframeRef(ref) {
|
handleIframeRef(ref) {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
getPreviewStyles().forEach((style) => {
|
registry.getPreviewStyles().forEach((style) => {
|
||||||
const linkEl = document.createElement('link');
|
const linkEl = document.createElement('link');
|
||||||
linkEl.setAttribute('rel', 'stylesheet');
|
linkEl.setAttribute('rel', 'stylesheet');
|
||||||
linkEl.setAttribute('href', style);
|
linkEl.setAttribute('href', style);
|
||||||
@ -79,7 +79,7 @@ export default class PreviewPane extends React.Component {
|
|||||||
const { collection } = this.props;
|
const { collection } = this.props;
|
||||||
if (!collection) { return null; }
|
if (!collection) { return null; }
|
||||||
|
|
||||||
return <iframe className={styles.frame} ref={this.handleIframeRef}></iframe>
|
return <iframe className={styles.frame} ref={this.handleIframeRef}></iframe>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import registry from '../lib/registry';
|
||||||
import UnknownControl from './Widgets/UnknownControl';
|
import UnknownControl from './Widgets/UnknownControl';
|
||||||
import UnknownPreview from './Widgets/UnknownPreview';
|
import UnknownPreview from './Widgets/UnknownPreview';
|
||||||
import StringControl from './Widgets/StringControl';
|
import StringControl from './Widgets/StringControl';
|
||||||
@ -6,25 +7,15 @@ import MarkdownControl from './Widgets/MarkdownControl';
|
|||||||
import MarkdownPreview from './Widgets/MarkdownPreview';
|
import MarkdownPreview from './Widgets/MarkdownPreview';
|
||||||
import ImageControl from './Widgets/ImageControl';
|
import ImageControl from './Widgets/ImageControl';
|
||||||
import ImagePreview from './Widgets/ImagePreview';
|
import ImagePreview from './Widgets/ImagePreview';
|
||||||
|
import DateTimeControl from './Widgets/DateTimeControl';
|
||||||
|
import DateTimePreview from './Widgets/DateTimePreview';
|
||||||
|
|
||||||
|
registry.registerWidget('string', StringControl, StringPreview);
|
||||||
|
registry.registerWidget('markdown', MarkdownControl, MarkdownPreview);
|
||||||
|
registry.registerWidget('image', ImageControl, ImagePreview);
|
||||||
|
registry.registerWidget('datetime', DateTimeControl, DateTimePreview);
|
||||||
|
registry.registerWidget('_unknown', UnknownControl, UnknownPreview);
|
||||||
|
|
||||||
const Widgets = {
|
export function resolveWidget(name) {
|
||||||
_unknown: {
|
return registry.getWidget(name) || registry.getWidget('_unknown');
|
||||||
Control: UnknownControl,
|
}
|
||||||
Preview: UnknownPreview
|
|
||||||
},
|
|
||||||
string: {
|
|
||||||
Control: StringControl,
|
|
||||||
Preview: StringPreview
|
|
||||||
},
|
|
||||||
markdown: {
|
|
||||||
Control: MarkdownControl,
|
|
||||||
Preview: MarkdownPreview
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
Control: ImageControl,
|
|
||||||
Preview: ImagePreview
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Widgets;
|
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
|
import YAML from './yaml';
|
||||||
import YAMLFrontmatter from './yaml-frontmatter';
|
import YAMLFrontmatter from './yaml-frontmatter';
|
||||||
|
|
||||||
|
const yamlFormatter = new YAML();
|
||||||
|
const YamlFrontmatterFormatter = new YAMLFrontmatter();
|
||||||
|
|
||||||
export function resolveFormat(collection, entry) {
|
export function resolveFormat(collection, entry) {
|
||||||
return new YAMLFrontmatter();
|
const extension = entry.path.split('.').pop();
|
||||||
|
switch (extension) {
|
||||||
|
case 'yml':
|
||||||
|
return yamlFormatter;
|
||||||
|
default:
|
||||||
|
return YamlFrontmatterFormatter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
212
src/index.css
212
src/index.css
@ -60,3 +60,215 @@ button{
|
|||||||
background-color:#fff;
|
background-color:#fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:global {
|
||||||
|
& .rdt {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
& .rdtPicker {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
width: 250px;
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: 1px;
|
||||||
|
z-index: 99999 !important;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,.1);
|
||||||
|
border: 1px solid #f9f9f9;
|
||||||
|
}
|
||||||
|
& .rdtOpen .rdtPicker {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
& .rdtStatic .rdtPicker {
|
||||||
|
box-shadow: none;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker .rdtTimeToggle {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker table {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
& .rdtPicker td,
|
||||||
|
& .rdtPicker th {
|
||||||
|
text-align: center;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
& .rdtPicker td {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtDay:hover,
|
||||||
|
& .rdtPicker td.rdtHour:hover,
|
||||||
|
& .rdtPicker td.rdtMinute:hover,
|
||||||
|
& .rdtPicker td.rdtSecond:hover,
|
||||||
|
& .rdtPicker .rdtTimeToggle:hover {
|
||||||
|
background: #eeeeee;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtOld,
|
||||||
|
& .rdtPicker td.rdtNew {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtToday {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtToday:before {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
border-left: 7px solid transparent;
|
||||||
|
border-bottom: 7px solid #428bca;
|
||||||
|
border-top-color: rgba(0, 0, 0, 0.2);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 4px;
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtActive,
|
||||||
|
& .rdtPicker td.rdtActive:hover {
|
||||||
|
background-color: #428bca;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtActive.rdtToday:before {
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
}
|
||||||
|
& .rdtPicker td.rdtDisabled,
|
||||||
|
& .rdtPicker td.rdtDisabled:hover {
|
||||||
|
background: none;
|
||||||
|
color: #999999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker td span.rdtOld {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
& .rdtPicker td span.rdtDisabled,
|
||||||
|
& .rdtPicker td span.rdtDisabled:hover {
|
||||||
|
background: none;
|
||||||
|
color: #999999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
& .rdtPicker th {
|
||||||
|
border-bottom: 1px solid #f9f9f9;
|
||||||
|
}
|
||||||
|
& .rdtPicker .dow {
|
||||||
|
width: 14.2857%;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
& .rdtPicker th.rdtSwitch {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
& .rdtPicker th.rdtNext,
|
||||||
|
& .rdtPicker th.rdtPrev {
|
||||||
|
font-size: 21px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPrev span,
|
||||||
|
& .rdtNext span {
|
||||||
|
display: block;
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||||
|
-khtml-user-select: none; /* Konqueror */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker th.rdtDisabled,
|
||||||
|
& .rdtPicker th.rdtDisabled:hover {
|
||||||
|
background: none;
|
||||||
|
color: #999999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
& .rdtPicker thead tr:first-child th {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
& .rdtPicker thead tr:first-child th:hover {
|
||||||
|
background: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker tfoot {
|
||||||
|
border-top: 1px solid #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker button {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
& .rdtPicker button:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtPicker thead button {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
& td.rdtMonth,
|
||||||
|
& td.rdtYear {
|
||||||
|
height: 50px;
|
||||||
|
width: 25%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
& td.rdtMonth:hover,
|
||||||
|
& td.rdtYear:hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounters {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounters > div {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounter {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounter {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounterSeparator {
|
||||||
|
line-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtCounter .rdtBtn {
|
||||||
|
height: 40%;
|
||||||
|
line-height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||||
|
-khtml-user-select: none; /* Konqueror */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
& .rdtCounter .rdtBtn:hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
& .rdtCounter .rdtCount {
|
||||||
|
height: 20%;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtMilli {
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-left: 8px;
|
||||||
|
width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .rdtMilli input {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-top: 37px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
src/index.js
11
src/index.js
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { Router } from 'react-router';
|
import { Router } from 'react-router';
|
||||||
import { registerPreviewStyle,registerPreviewTemplate } from './lib/registry';
|
import registry from './lib/registry';
|
||||||
import configureStore from './store/configureStore';
|
import configureStore from './store/configureStore';
|
||||||
import routes from './routing/routes';
|
import routes from './routing/routes';
|
||||||
import history, { syncHistory } from './routing/history';
|
import history, { syncHistory } from './routing/history';
|
||||||
@ -31,7 +31,8 @@ render((
|
|||||||
</Provider>
|
</Provider>
|
||||||
), el);
|
), el);
|
||||||
|
|
||||||
window.CMS = {
|
window.CMS = {};
|
||||||
registerPreviewStyle: registerPreviewStyle,
|
console.log('reg: ', registry);
|
||||||
registerPreviewTemplate: registerPreviewTemplate
|
for (const method in registry) {
|
||||||
};
|
window.CMS[method] = registry[method];
|
||||||
|
}
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
const registry = {
|
const _registry = {
|
||||||
templates: {},
|
templates: {},
|
||||||
previewStyles: []
|
previewStyles: [],
|
||||||
|
widgets: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function registerPreviewStyle(style) {
|
export default {
|
||||||
registry.previewStyles.push(style);
|
registerPreviewStyle(style) {
|
||||||
}
|
_registry.previewStyles.push(style);
|
||||||
|
},
|
||||||
export function registerPreviewTemplate(name, component) {
|
registerPreviewTemplate(name, component) {
|
||||||
registry.templates[name] = component;
|
_registry.templates[name] = component;
|
||||||
}
|
},
|
||||||
|
getPreviewTemplate(name) {
|
||||||
export function getPreviewTemplate(name) {
|
return _registry.templates[name];
|
||||||
return registry.templates[name];
|
},
|
||||||
}
|
getPreviewStyles() {
|
||||||
|
return _registry.previewStyles;
|
||||||
export function getPreviewStyles() {
|
},
|
||||||
return registry.previewStyles;
|
registerWidget(name, control, preview) {
|
||||||
}
|
_registry.widgets[name] = { control, preview };
|
||||||
|
},
|
||||||
|
getWidget(name) {
|
||||||
|
return _registry.widgets[name];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user