UNPKG

colonel-kurtz

Version:
1,386 lines (1,101 loc) 37.2 kB
'use strict'; function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = _interopDefault(require('react')); var reactTransitionGroup = require('react-transition-group'); var Ink = _interopDefault(require('react-ink')); var FocusTrap = _interopDefault(require('react-focus-trap')); var DOM = _interopDefault(require('react-dom')); var groupBy = _interopDefault(require('group-by')); var classNames = _interopDefault(require('classnames')); var Microcosm = _interopDefault(require('microcosm')); var DefaultBlockType = /*@__PURE__*/(function (superclass) { function DefaultBlockType () { superclass.apply(this, arguments); } if ( superclass ) DefaultBlockType.__proto__ = superclass; DefaultBlockType.prototype = Object.create( superclass && superclass.prototype ); DefaultBlockType.prototype.constructor = DefaultBlockType; DefaultBlockType.prototype.render = function render () { return React.createElement( 'div', null, this.props.children ) }; return DefaultBlockType; }(React.Component)); var KEY_DELIMETER = '.'; function isBlank(value) { return value === '' || value === null || value === undefined } function isObject(target) { return !(!target || typeof target !== 'object') } function copyOver(next, obj) { for (var key in obj) { next[key] = obj[key]; } return next } function castPath(value) { if (Array.isArray(value)) { return value } else if (isBlank(value)) { return [] } return typeof value === 'string' ? value.trim().split(KEY_DELIMETER) : [value] } function assign(subject) { var values = [], len = arguments.length - 1; while ( len-- > 0 ) values[ len ] = arguments[ len + 1 ]; return values.reduce(copyOver, subject) } /** * Shallow copy an object */ function clone(target) { if (Array.isArray(target)) { return target.slice(0) } else if (isObject(target) === false) { return {} } var copy = {}; for (var key in target) { copy[key] = target[key]; } return copy } /** * Retrieve a value from an object. If no key is provided, just return * the object. */ function get(object, keyPath, fallback) { var path = castPath(keyPath); var value = object; for (var i = 0, len = path.length; i < len; i++) { if (value == null) { break } value = value[path[i]]; } if (value === undefined || value === null) { return arguments.length <= 2 ? value : fallback } return value } /** * Non-destructively assign a value to a provided object at a given key. If the * value is the same, don't do anything. Otherwise return a new object. */ function set(object, key, value) { // Ensure we're working with a key path, like: ['a', 'b', 'c'] var path = castPath(key); var len = path.length; if (len <= 0) { return value } if (get(object, path) === value) { return object } var root = clone(object); var node = root; // For each key in the path... for (var i = 0; i < len; i++) { var key$1 = path[i]; var next = value; // Are we at the end? if (i < len - 1) { // No: Check to see if the key is already assigned, if (key$1 in node) { // If yes, clone that value next = clone(node[key$1]); } else { // Otherwise assign an object so that we can keep drilling down next = {}; } } // Assign the value, then continue on to the next iteration of the loop // using the next step down node[key$1] = next; node = node[key$1]; } return root } var defaults = { component: DefaultBlockType, group: null, maxChildren: Infinity, root: true, types: [] }; var BlockType = function BlockType(config) { assign(this, defaults, config); }; BlockType.prototype.valueOf = function valueOf () { return this.id }; /** * Block Type Store * * A Block Type describes the editing experience for a Block. Whenever * an action associated with block type the system, this module tells * Colonel Kurtz how that action manipulates block type data. */ var BlockTypes = { getInitialState: function getInitialState() { return [] }, deserialize: function deserialize(blockTypes) { if ( blockTypes === void 0 ) blockTypes = []; return blockTypes.map(function (options) { return new BlockType(options); }) }, serialize: function serialize() { return undefined } } var Actions = { create: function create(type, position, parent) { return { type: type, position: position, parent: parent } }, destroy: function destroy(id) { return id }, update: function update(id, content) { // valueOf() allows blocks to be passed, it will return // the id return { id: id.valueOf(), content: content } }, set: function set(id, path, value) { return { id: id.valueOf(), path: path, value: value } }, move: function move(block, distance) { return { block: block, distance: distance } } } var uidCounter = 0; function uid() { uidCounter += 1; return ("c" + uidCounter) } var Block = function Block(params) { this.id = uid(); this.content = params.content || {}; this.parent = params.parent; this.type = params.type; this.clientOnly = params.clientOnly || false; }; Block.prototype.valueOf = function valueOf () { return this.id }; /** * InsertAfter * Given a list and an item, non-destructively return a new list * including the item after a given position */ var inRange = function (value, min, max) { return Math.max(min, Math.min(max, value)); }; function insertAt(list, item, position) { if ( position === void 0 ) position = list.length; var corrected = inRange(position, 0, list.length); var head = list.slice(0, corrected); var tail = list.slice(corrected); return head.concat(item, tail) } /** * siblingsOf * Get the siblings of a provided block */ function siblingsOf(list, block) { if (block.parent) { return list.filter(function (i) { return i.parent === block.parent; }) } else { return list.filter(function (i) { return !i.parent; }) } } /** * Given a list of blocks, determine if a provided block * is the first child of its parent */ function siblingAt(list, block, delta) { var siblings = siblingsOf(list, block); var index = siblings.indexOf(block); return index !== -1 ? siblings[index + delta] : null } function blocksToJson(items) { // If items are null or undefined, assume an empty list items = items || []; var root = items.filter(function (i) { return !i.parent; }); function jsonify(block) { var children = items.filter(function (i) { return i.parent === block; }); return { content: block.content, type: block.type, blocks: children.map(jsonify) } } return root.map(jsonify) } function jsonToBlocks(blocks, parent) { // If blocks are null or undefined, assume an empty list blocks = blocks || []; return blocks.reduce(function(memo, params) { var block = new Block(assign({}, params, { parent: parent })); var children = jsonToBlocks(params.blocks, block); return memo.concat(block, children) }, []) } /** * Block Store * * The Block Store is responsible for defining how blocks are stored * within Colonel Kurtz. Whenever an action associated with block * records is pushed into the system, this module tells Colonel Kurtz * how that action manipulates block data. */ var Blocks = { register: function register() { var obj; return ( obj = {}, obj[Actions.create] = this.create, obj[Actions.destroy] = this.destroy, obj[Actions.update] = this.update, obj[Actions.set] = this.set, obj[Actions.move] = this.move, obj) }, getInitialState: function getInitialState() { return [] }, find: function find(state, id) { return state.filter(function (block) { return block.valueOf() === id; })[0] }, getChildren: function getChildren(state, parent) { return state.filter(function (i) { return i.parent === parent; }) }, getDepth: function getDepth(state, block, maxDepth) { var currentBlock = block; var depth = 0; while (currentBlock && depth <= maxDepth + 1) { depth += 1; currentBlock = state.filter(function (i) { return i === currentBlock.parent; })[0]; } return depth }, filterChildren: function filterChildren(state) { return state.filter(function (i) { return !i.parent; }) }, /** * `blocksToJson` takes a list of blocks and transforms them into * the nested structure shown in the front end */ serialize: function serialize(state) { return blocksToJson(state) }, /** * jsonToBlocks takes this nested structure and flattens * into a list for this store. */ deserialize: function deserialize(state) { return jsonToBlocks(state) }, create: function create(state, ref) { var type = ref.type; var parent = ref.parent; var position = ref.position; var record = new Block({ clientOnly: true, parent: parent, type: type }); // If the provided position is a Block, place the new block right // after it. if (position instanceof Block) { position = state.indexOf(position) + 1; } return insertAt(state, record, position || 0) }, update: function update(state, ref) { var id = ref.id; var content = ref.content; var block = Blocks.find(state, id); block.content = assign({}, block.content, content); return state }, set: function set$1(state, ref) { var id = ref.id; var path = ref.path; var value = ref.value; var block = Blocks.find(state, id); block.content = set(block.content, path, value); return state }, destroy: function destroy(state, id) { return state.filter(function(block) { for (var b = block; b; b = b.parent) { if (b.id == id) { return false } } return true }) }, move: function move(state, ref) { var block = ref.block; var distance = ref.distance; var without = state.filter(function (i) { return i !== block; }); var before = siblingAt(state, block, distance); return insertAt(without, block, state.indexOf(before)) } }; /** * Bootstrap * This plugin is responsible for injecting data into the system */ var parseElement = function(element) { var data = []; try { data = JSON.parse(element.value); } catch (x) { // Do nothing } return data }; var bootstrap = { filter: function filter(blockTypes, acceptable) { if (!acceptable) { return blockTypes } return blockTypes.filter(function (type) { return acceptable.indexOf(type.id) > -1; }) }, register: function register( app, ref, next ) { var allow = ref.allow; var maxChildren = ref.maxChildren; if ( maxChildren === void 0 ) maxChildren = Infinity; var blocks = ref.blocks; var blockTypes = ref.blockTypes; var maxDepth = ref.maxDepth; if ( maxDepth === void 0 ) maxDepth = Infinity; if (blocks instanceof HTMLElement) { blocks = parseElement(blocks); } app.replace( { maxChildren: maxChildren, maxDepth: maxDepth, blocks: blocks, blockTypes: this.filter(blockTypes, allow) }, next ); } } /** * Animator * In order to make block animations easy to edit in one place, this * component maintains all of this logic. */ var defaultProps = { component: 'div', transitionName: 'col-editor-block', transitionEnterTimeout: 280, transitionLeaveTimeout: 280 }; var Animator = /*@__PURE__*/(function (superclass) { function Animator () { superclass.apply(this, arguments); } if ( superclass ) Animator.__proto__ = superclass; Animator.prototype = Object.create( superclass && superclass.prototype ); Animator.prototype.constructor = Animator; Animator.prototype.render = function render () { return React.createElement(reactTransitionGroup.CSSTransitionGroup, this.props) }; return Animator; }(React.Component)); Animator.defaultProps = defaultProps; function objectWithoutProperties (obj, exclude) { var target = {}; for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) target[k] = obj[k]; return target; } var defaultProps$1 = { className: 'col-btn', tagName: 'button', type: 'button' }; var Button = /*@__PURE__*/(function (superclass) { function Button () { superclass.apply(this, arguments); } if ( superclass ) Button.__proto__ = superclass; Button.prototype = Object.create( superclass && superclass.prototype ); Button.prototype.constructor = Button; Button.prototype.render = function render () { var ref = this.props; var tagName = ref.tagName; var children = ref.children; var rest = objectWithoutProperties( ref, ["tagName", "children"] ); var attrs = rest; return React.createElement(tagName, attrs, [ React.createElement( Ink, { key: "__ink__" }) ].concat( children )) }; return Button; }(React.Component)); Button.defaultProps = defaultProps$1; function objectWithoutProperties$1 (obj, exclude) { var target = {}; for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) target[k] = obj[k]; return target; } var defaultProps$2 = { className: 'col-menu-handle', label: 'Open the menu for this block', type: 'button' }; var MenuHandle = /*@__PURE__*/(function (superclass) { function MenuHandle () { superclass.apply(this, arguments); } if ( superclass ) MenuHandle.__proto__ = superclass; MenuHandle.prototype = Object.create( superclass && superclass.prototype ); MenuHandle.prototype.constructor = MenuHandle; MenuHandle.prototype.render = function render () { var ref = this.props; var label = ref.label; var rest = objectWithoutProperties$1( ref, ["label"] ); var safe = rest; return ( React.createElement( Button, safe, React.createElement( 'span', { className: "col-hidden" }, label), React.createElement( 'svg', { width: "24", height: "24", viewBox: "0 0 24 24", 'aria-hidden': "true" }, React.createElement( 'path', { d: "M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" }) ) ) ) }; return MenuHandle; }(React.Component)); MenuHandle.defaultProps = defaultProps$2; function objectWithoutProperties$2 (obj, exclude) { var target = {}; for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) target[k] = obj[k]; return target; } var defaultProps$3 = { className: 'col-menu-item', type: 'button', onClick: function onClick() {}, isDisabled: function isDisabled() {} }; var MenuItem = /*@__PURE__*/(function (superclass) { function MenuItem () { superclass.apply(this, arguments); } if ( superclass ) MenuItem.__proto__ = superclass; MenuItem.prototype = Object.create( superclass && superclass.prototype ); MenuItem.prototype.constructor = MenuItem; MenuItem.prototype.isDisabled = function isDisabled () { var ref = this.props; var app = ref.app; var block = ref.block; var isDisabled = ref.isDisabled; return isDisabled(app, block) }; MenuItem.prototype.render = function render () { var ref = this.props; var label = ref.label; var app = ref.app; var block = ref.block; var onOpen = ref.onOpen; var onExit = ref.onExit; var active = ref.active; var isDisabled = ref.isDisabled; var items = ref.items; var rest = objectWithoutProperties$2( ref, ["label", "app", "block", "onOpen", "onExit", "active", "isDisabled", "items"] ); var safe = rest; return ( React.createElement( Button, Object.assign({}, safe, { onClick: this._onClick.bind(this), disabled: this.isDisabled() }), this._formatLabel(label) ) ) }; MenuItem.prototype._formatLabel = function _formatLabel (label) { var ref = this.props; var app = ref.app; var block = ref.block; if (typeof label === 'function') { return label(app, block, this) } else { return label } }; MenuItem.prototype._onClick = function _onClick () { var ref = this.props; var app = ref.app; var block = ref.block; var onClick = ref.onClick; onClick(app, block, this); }; return MenuItem; }(React.Component)); MenuItem.defaultProps = defaultProps$3; var destroy = Actions.destroy; var move = Actions.move; var menuItems = [ { id: 'moveBefore', label: 'Move Up', onClick: function onClick(app, block) { app.push(move, [block, -1]); }, isDisabled: function isDisabled(app, block) { return siblingsOf(app.state.blocks, block)[0] === block } }, { id: 'moveAfter', label: 'Move Down', onClick: function onClick(app, block) { app.push(move, [block, 1]); }, isDisabled: function isDisabled(app, block) { return siblingsOf(app.state.blocks, block).pop() === block } }, { id: 'destroy', label: 'Remove', onClick: function onClick(app, block) { app.push(destroy, block.id); } } ] var defaultProps$4 = { items: [] }; var BlockMenu = /*@__PURE__*/(function (superclass) { function BlockMenu () { superclass.apply(this, arguments); } if ( superclass ) BlockMenu.__proto__ = superclass; BlockMenu.prototype = Object.create( superclass && superclass.prototype ); BlockMenu.prototype.constructor = BlockMenu; BlockMenu.prototype.getMenuItem = function getMenuItem (item) { var this$1 = this; var id = item.id; return ( React.createElement( MenuItem, Object.assign({}, { key: id, ref: function (el) { return (this$1[id] = el); } }, item, this.props)) ) }; BlockMenu.prototype.getMenuItems = function getMenuItems () { var ref = this.props; var items = ref.items; return items.concat(menuItems).map(this.getMenuItem, this) }; BlockMenu.prototype.getMenu = function getMenu () { if (!this.props.active) { return null } return React.createElement( FocusTrap, { active: true, key: 'menu', className: 'col-menu', element: 'nav', onExit: this.props.onExit, role: 'navigation' }, this.getMenuItems() ) }; BlockMenu.prototype.render = function render () { var this$1 = this; return ( React.createElement( Animator, { className: "col-menu-wrapper", transitionName: "col-menu", transitionEnterTimeout: 300, transitionLeaveTimeout: 200 }, React.createElement( MenuHandle, { key: "handle", ref: function (el) { return (this$1.handle = el); }, onClick: this.props.onOpen }), this.getMenu() ) ) }; return BlockMenu; }(React.Component)); BlockMenu.Item = MenuItem; BlockMenu.defaultProps = defaultProps$4; /** * A fallback block type */ var FallbackBlockType = /*@__PURE__*/(function (BlockType$$1) { function FallbackBlockType(ref) { var block = ref.block; BlockType$$1.call(this, { type: 'unsupported', component: /*@__PURE__*/(function (superclass) { function FallbackBlock () { superclass.apply(this, arguments); } if ( superclass ) FallbackBlock.__proto__ = superclass; FallbackBlock.prototype = Object.create( superclass && superclass.prototype ); FallbackBlock.prototype.constructor = FallbackBlock; FallbackBlock.prototype.render = function render () { return ( React.createElement( 'section', { className: "col-unsupported" }, React.createElement( 'header', { className: "col-unsupported-header" }, React.createElement( 'p', { className: "col-unsupported-subtitle" }, "Error"), React.createElement( 'p', { className: "col-unsupported-title" }, "Unrecognized block “", block.type, "”") ), React.createElement( 'div', { className: "col-unsupported-content" }, React.createElement( 'p', null, "This typically happens when a block type is removed, or the identifier changes." ), React.createElement( 'p', null, React.createElement( 'b', { className: "col-strong" }, "Your content has not been lost!"), ' ', "Feel free to ignore this message, or build a new block with the information below:" ) ), React.createElement( 'pre', { className: "col-unsupported-data" }, JSON.stringify(block.content, null, 4) ) ) ) }; return FallbackBlock; }(React.Component)) }); } if ( BlockType$$1 ) FallbackBlockType.__proto__ = BlockType$$1; FallbackBlockType.prototype = Object.create( BlockType$$1 && BlockType$$1.prototype ); FallbackBlockType.prototype.constructor = FallbackBlockType; return FallbackBlockType; }(BlockType)); var defaultProps$5 = { label: 'Add block', className: 'col-btn-fab', symbol: '+' }; var ActionButton = /*@__PURE__*/(function (superclass) { function ActionButton () { superclass.apply(this, arguments); } if ( superclass ) ActionButton.__proto__ = superclass; ActionButton.prototype = Object.create( superclass && superclass.prototype ); ActionButton.prototype.constructor = ActionButton; ActionButton.prototype.focus = function focus () { DOM.findDOMNode(this).focus(); }; ActionButton.prototype.render = function render () { var ref = this.props; var className = ref.className; var disabled = ref.disabled; var label = ref.label; var onClick = ref.onClick; var symbol = ref.symbol; return ( React.createElement( Button, { className: className, onClick: onClick, disabled: disabled }, React.createElement( 'span', { className: "col-hidden" }, label), React.createElement( 'span', { 'aria-hidden': "true" }, symbol) ) ) }; return ActionButton; }(React.Component)); ActionButton.defaultProps = defaultProps$5; var defaultProps$6 = { items: [] }; var BlockTypeGroup = /*@__PURE__*/(function (superclass) { function BlockTypeGroup() { superclass.apply(this, arguments); this.state = { open: false }; } if ( superclass ) BlockTypeGroup.__proto__ = superclass; BlockTypeGroup.prototype = Object.create( superclass && superclass.prototype ); BlockTypeGroup.prototype.constructor = BlockTypeGroup; BlockTypeGroup.prototype.open = function open () { this.setState({ open: true }); }; BlockTypeGroup.prototype.close = function close () { this.setState({ open: false }); }; BlockTypeGroup.prototype.getButton = function getButton (type) { var id = type.id; var label = type.label; var ref = this.props; var onAdd = ref.onAdd; return ( React.createElement( Button, { key: id, className: "col-menu-item", onClick: function () { return onAdd(type); } }, label ) ) }; BlockTypeGroup.prototype.getMenu = function getMenu () { return this.state.open ? ( React.createElement( FocusTrap, { key: "menu", className: "col-menu", element: "nav", active: true, onExit: this.close.bind(this), role: "navigation" }, this.props.items.map(this.getButton, this) ) ) : null }; BlockTypeGroup.prototype.render = function render () { return ( React.createElement( Animator, { role: "button", transitionName: "col-menu", className: "col-switch-dropdown", transitionEnterTimeout: 300, transitionLeaveTimeout: 200, onKeyUp: this._onKeyUp.bind(this) }, React.createElement( Button, { key: "label", className: "col-switch-btn col-menu-label", onClick: this.open.bind(this) }, this.props.label ), this.getMenu() ) ) }; BlockTypeGroup.prototype._onKeyUp = function _onKeyUp (event) { // Do not allow escape presses to bubble up to parent switch if (event.key === 'Escape' && this.state.open) { event.stopPropagation(); } }; return BlockTypeGroup; }(React.Component)); BlockTypeGroup.defaultProps = defaultProps$6; var SwitchNav = /*@__PURE__*/(function (superclass) { function SwitchNav () { superclass.apply(this, arguments); } if ( superclass ) SwitchNav.__proto__ = superclass; SwitchNav.prototype = Object.create( superclass && superclass.prototype ); SwitchNav.prototype.constructor = SwitchNav; SwitchNav.prototype.componentDidMount = function componentDidMount () { DOM.findDOMNode(this).focus(); }; SwitchNav.prototype.getButton = function getButton (type) { var id = type.id; var label = type.label; var ref = this.props; var onAdd = ref.onAdd; return { name: label, type: type, component: ( React.createElement( Button, { key: id, className: "col-switch-btn", onClick: function () { return onAdd(type); } }, label ) ) } }; SwitchNav.prototype.getGroups = function getGroups (blocks) { var groups = groupBy(blocks.filter(function (b) { return b.group; }), function (type) { return type.group; }); var items = []; for (var name in groups) { items.push({ name: name, type: groups[name][0], component: ( React.createElement( BlockTypeGroup, { key: name, items: groups[name], label: name, onAdd: this.props.onAdd }) ) }); } return items }; SwitchNav.prototype.render = function render () { var ref = this.props; var blockTypes = ref.blockTypes; var ungrouped = blockTypes.filter(function (b) { return !b.group; }).map(this.getButton, this); var grouped = this.getGroups(blockTypes); var sorted = grouped.concat(ungrouped).sort(function(a, b) { return blockTypes.indexOf(a.type) - blockTypes.indexOf(b.type) }); return ( React.createElement( 'nav', { className: "col-switch-nav", role: "navigation" }, sorted.map(function (s) { return s.component; }) ) ) }; return SwitchNav; }(React.Component)); /** * typesForBlock * Extracted logic to get the types of children a block may have */ function typesForBlock(blockTypes, block) { if (block) { var types = blockTypes.filter(function (i) { return i.id === block.type; })[0].types; return blockTypes.filter(function (i) { return types.indexOf(i.id) > -1; }) } else { return blockTypes.filter(function (type) { return type.root; }) } } var Switch = /*@__PURE__*/(function (superclass) { function Switch() { superclass.apply(this, arguments); this.state = { open: false }; } if ( superclass ) Switch.__proto__ = superclass; Switch.prototype = Object.create( superclass && superclass.prototype ); Switch.prototype.constructor = Switch; Switch.prototype.open = function open () { this.setState({ open: true }); }; Switch.prototype.close = function close () { var this$1 = this; this.setState({ open: false }, function () { this$1.toggle.focus(); }); }; Switch.prototype.getToggle = function getToggle () { var this$1 = this; if (this.state.open) { return null } return ( React.createElement( ActionButton, { ref: function (el) { return (this$1.toggle = el); }, disabled: this.hasMaxChildren(), label: "Open the block menu and create a block", onClick: this._onToggle.bind(this) }) ) }; Switch.prototype.getNav = function getNav (blockTypes) { var this$1 = this; if (!this.state.open) { return null } return ( React.createElement( SwitchNav, { ref: function (el) { return (this$1.nav = el); }, blockTypes: blockTypes, onAdd: this._onAdd.bind(this), onExit: this.close.bind(this) }) ) }; Switch.prototype.hasMaxChildren = function hasMaxChildren () { var ref = this.props; var app = ref.app; var parent = ref.parent; if (!parent) { return ( Blocks.filterChildren(app.state.blocks).length >= app.state.maxChildren ) } var children = Blocks.getChildren(app.state.blocks, parent); var type = app.state.blockTypes.filter(function (t) { return t.id === parent.type; })[0]; return children.length >= type.maxChildren }; Switch.prototype.depth = function depth () { var ref = this.props; var app = ref.app; var parent = ref.parent; return Blocks.getDepth(app.state.blocks, parent, app.state.maxDepth) + 1 }; Switch.prototype.hasHitMaxDepth = function hasHitMaxDepth () { var ref = this.props; var app = ref.app; if (!app.state.maxDepth) { return false } return this.depth() >= app.state.maxDepth }; Switch.prototype.render = function render () { var ref = this.props; var app = ref.app; var parent = ref.parent; var types = typesForBlock(app.state.blockTypes, parent); var className = classNames('col-switch', { 'col-switch-disabled': this.hasMaxChildren() || this.hasHitMaxDepth() }); return types.length ? ( React.createElement( 'div', { className: className, onKeyUp: this._onKeyUp.bind(this) }, this.getToggle(), this.getNav(types) ) ) : null }; Switch.prototype._onAdd = function _onAdd (type) { var ref = this.props; var app = ref.app; var position = ref.position; var parent = ref.parent; app.push(Actions.create, [type.id, position, parent]); this.setState({ open: false }); }; Switch.prototype._onToggle = function _onToggle () { var ref = this.props; var app = ref.app; var position = ref.position; var parent = ref.parent; var types = typesForBlock(app.state.blockTypes, parent); // If only one type exists, instead of opening the nav, just // create that element if (types.length === 1) { app.push(Actions.create, [types[0].id, position, parent]); } else { this.open(); } }; Switch.prototype._onKeyUp = function _onKeyUp (e) { if (e.key === 'Escape') { this.close(); } }; return Switch; }(React.Component)); /** * respondsTo * Can an object respond to a method name? */ function responesTo(obj, key) { return !!(obj && typeof obj[key] === 'function') } var Block$1 = /*@__PURE__*/(function (superclass) { function Block() { superclass.apply(this, arguments); this.state = { extraMenuItems: [], menuOpen: false }; } if ( superclass ) Block.__proto__ = superclass; Block.prototype = Object.create( superclass && superclass.prototype ); Block.prototype.constructor = Block; Block.prototype.getBlockType = function getBlockType () { var ref = this.props; var app = ref.app; var block = ref.block; var blockType = app.state.blockTypes.filter(function (i) { return i.id === block.type; })[0]; return blockType ? blockType : new FallbackBlockType({ block: block }) }; Block.prototype.getMenuItems = function getMenuItems () { return this.state.extraMenuItems }; Block.prototype.setMenuItems = function setMenuItems (component) { if (responesTo(component, 'getMenuItems')) { this.setState({ extraMenuItems: component.getMenuItems() }); } }; Block.prototype.openMenu = function openMenu () { this.setState({ menuOpen: true }); }; Block.prototype.closeMenu = function closeMenu () { this.setState({ menuOpen: false }); }; Block.prototype.componentDidMount = function componentDidMount () { this.setMenuItems(this.block); // Trigger an initial change to ensure default content // is assigned immediately this._onChange(this.getContent(this.props.block)); }; Block.prototype.getContent = function getContent (block) { var ref = this.getBlockType(); var component = ref.component; var defaults = component.defaultProps || {}; return assign({}, defaults.content, block.content) }; Block.prototype.render = function render () { var this$1 = this; var ref = this.props; var app = ref.app; var block = ref.block; var children = ref.children; var ref$1 = this.getBlockType(); var Component = ref$1.component; var ref$2 = this.state; var menuOpen = ref$2.menuOpen; var extraMenuItems = ref$2.extraMenuItems; // Determine content by taking the default content and extend it with // the current block content var content = this.getContent(block); return ( React.createElement( 'div', { className: "col-editor-block" }, React.createElement( 'div', { className: ("col-block col-block-" + (block.type)) }, React.createElement( Component, Object.assign({}, { ref: function (el) { return (this$1.block = el); } }, block, { content: content, onChange: this._onChange.bind(this) }), React.createElement( Switch, { app: app, parent: block }), React.createElement( Animator, { className: "col-block-children" }, children) ), React.createElement( BlockMenu, { ref: function (el) { return (this$1.menu = el); }, app: app, block: block, items: extraMenuItems, active: menuOpen, onOpen: this.openMenu.bind(this), onExit: this.closeMenu.bind(this) }) ), React.createElement( Switch, { app: app, position: block, parent: block.parent }) ) ) }; Block.prototype._onChange = function _onChange (keypath, value) { var ref = this.props; var app = ref.app; var block = ref.block; if (typeof keypath === 'object') { // onChange({ field: 'value' }) app.push(Actions.update, [block, keypath]); } else { // onChange('field', 'value') // onChange('deep.field', 'value') app.push(Actions.set, [block, keypath, value]); } }; return Block; }(React.PureComponent)); var EditorBlock = /*@__PURE__*/(function (superclass) { function EditorBlock () { superclass.apply(this, arguments); } if ( superclass ) EditorBlock.__proto__ = superclass; EditorBlock.prototype = Object.create( superclass && superclass.prototype ); EditorBlock.prototype.constructor = EditorBlock; EditorBlock.prototype.getBlock = function getBlock (block) { return React.createElement( EditorBlock, { key: block, app: this.props.app, block: block }) }; EditorBlock.prototype.render = function render () { var ref = this.props; var app = ref.app; var block = ref.block; return ( React.createElement( Block$1, { app: app, block: block }, Blocks.getChildren(app.state.blocks, block).map(this.getBlock, this) ) ) }; return EditorBlock; }(React.Component)); /** * This is the root component that contains sections for * toggling between viewing modes and viewing managed content */ var App = /*@__PURE__*/(function (superclass) { function App () { superclass.apply(this, arguments); } if ( superclass ) App.__proto__ = superclass; App.prototype = Object.create( superclass && superclass.prototype ); App.prototype.constructor = App; App.prototype.getBlock = function getBlock (block, i) { return React.createElement( EditorBlock, { key: block, app: this.props.app, block: block }) }; App.prototype.render = function render () { var ref = this.props; var app = ref.app; var parents = Blocks.filterChildren(app.state.blocks); return ( React.createElement( 'div', { className: "colonel" }, React.createElement( Switch, { app: app }), React.createElement( Animator, { className: "col-block-children" }, parents.map(this.getBlock, this) ) ) ) }; return App; }(React.Component)); /** * Render * Handles updating the browser UI */ var render = { render: function render(app, el) { DOM.render(React.createElement( App, { app: app }), el); }, register: function register(app, ref) { var this$1 = this; var el = ref.el; this.render(app, el); app.listen(function (i) { return this$1.render(app, el); }); } } /** * Colonel Kurts * A custom block editor */ var ColonelKurtz = /*@__PURE__*/(function (Microcosm$$1) { function ColonelKurtz(options) { Microcosm$$1.call(this); /** * A block is an individual chunk of content. It can have children */ this.addStore('blocks', Blocks); /** * A block type defines the editing experience for a specific type * content */ this.addStore('blockTypes', BlockTypes); /** * The bootstrap plugin takes seed data and prepares the * application's state beyond initializing */ this.addPlugin(bootstrap, options); /** * The render plugin handles updating the browser ui */ this.addPlugin(render, options); } if ( Microcosm$$1 ) ColonelKurtz.__proto__ = Microcosm$$1; ColonelKurtz.prototype = Object.create( Microcosm$$1 && Microcosm$$1.prototype ); ColonelKurtz.prototype.constructor = ColonelKurtz; ColonelKurtz.prototype.toJSON = function toJSON () { return this.serialize().blocks }; return ColonelKurtz; }(Microcosm)); module.exports = ColonelKurtz; //# sourceMappingURL=colonel.js.map