Repository: wiredjs/designer
Branch: master
Commit: 9e8d3381a869
Files: 31
Total size: 104.8 KB
Directory structure:
gitextract_kz5tdmj3/
├── .gitignore
├── LICENSE
├── README.md
├── bower.json
├── deploy-to-pages.sh
├── elements.json
├── index.html
├── manifest.json
├── polymer.json
├── src/
│ ├── action-history.html
│ ├── app-controls.html
│ ├── app-icons.html
│ ├── app.js
│ ├── canvas/
│ │ ├── canvas-controls.html
│ │ └── canvas-view.html
│ ├── components/
│ │ ├── designer-tab.html
│ │ ├── designer-tabs.html
│ │ ├── icon-picker.html
│ │ └── tree-view.html
│ ├── element-view/
│ │ ├── element-properties.html
│ │ ├── element-property.html
│ │ ├── element-stuff-base.html
│ │ ├── element-stuff-flex.html
│ │ ├── element-stuff-shared-styles.html
│ │ ├── element-stuff-styles.html
│ │ └── element-view.html
│ ├── palette/
│ │ ├── palette-list.html
│ │ ├── palette-shared-styles.html
│ │ └── palette-view.html
│ └── the-app.html
└── test/
└── the-app/
└── the-app_test.html
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
bower_components
designer
================================================
FILE: LICENSE
================================================
BSD 3-Clause License
Copyright (c) 2017, Preet Shihn
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: README.md
================================================
# Wired Designer
This is a very simple wysiwyg style designer for createing mockups and wireframes.
[Launch designer](https://wiredjs.github.io/designer)
The sketchy, hand-drawn looking components used by the designer are stand alone functional webcomponents, and can be used by anyone in their web app.<br>
[Wired elements on webcomponents.org](https://www.webcomponents.org/collection/wiredjs/wired-elements)
The designer app is adapted from [Polymer's wizzywid](https://github.com/PolymerLabs/wizzywid)
Built with webcomponents and Polymer.
License: [BSD-3-Clause](https://github.com/wiredjs/designer/blob/master/LICENSE)<br>
Author: [Preet Shihn](https://twitter.com/preetster)

================================================
FILE: bower.json
================================================
{
"name": "wired-designer",
"description": "Mockups and wireframing tool built using web components, and is open source.",
"main": "index.html",
"authors": [
"Preet Shihn <preetshihn@gmail.com>"
],
"dependencies": {
"polymer": "Polymer/polymer#^2.0.0",
"iron-flex-layout": "PolymerElements/iron-flex-layout#^2.0.0",
"iron-pages": "PolymerElements/iron-pages#^2.0.0",
"iron-ajax": "^2.0.5",
"wired-elements": "^0.2.3",
"paper-toggle-button": "PolymerElements/paper-toggle-button#^2.0.0",
"iron-icons": "^2.0.1"
},
"license": "BSD-3",
"private": true
}
================================================
FILE: deploy-to-pages.sh
================================================
#!/bin/bash -e
# Based on https://github.com/Polymer/tools/blob/master/bin/gp.sh
# This script pushes a demo-friendly version of your element and its
# dependencies to gh-pages.
# Run in a clean directory passing in a GitHub org and repo name
org="wiredjs"
repo="designer"
#branch="master" # default to master when branch isn't specified
# make folder (same as input, no checking!)
rm -rf $repo
mkdir $repo
git clone https://github.com/$org/$repo.git --single-branch
# switch to gh-pages branch
pushd $repo >/dev/null
git checkout --orphan gh-pages
# remove the .gitignore since we're going to be pushing deps
git rm -rf ./.gitignore
git rm -rf ./bower_components
# use bower to install runtime deployment
bower cache clean # ensure we're getting the latest from the desired branch.
# install the bower deps
bower install
# send it all to github
git add -A .
git commit -am 'seed gh-pages'
git push -u origin gh-pages --force
popd >/dev/null
================================================
FILE: elements.json
================================================
{
"elements": [
{
"name": "wired-card",
"label": "Card (Container)",
"styles": [
{
"name": "width",
"value": "150px"
},
{
"name": "height",
"value": "150px"
}
]
},
{
"name": "wired-item",
"label": "Combo/List item",
"disableSizing": true,
"properties": [
{
"name": "text",
"value": "item"
},
{
"name": "value",
"value": "item"
}
]
},
{
"name": "wired-button",
"label": "Button",
"properties": [
{
"name": "text",
"value": "Button"
}
]
},
{
"name": "wired-checkbox",
"label": "Checkbox",
"disableSizing": true,
"properties": [
{
"name": "text",
"value": "Checkbox text"
}
]
},
{
"name": "wired-combo",
"label": "Combo box",
"disableSizing": true
},
{
"name": "wired-input",
"label": "Text input",
"properties": [
{
"name": "placeholder",
"value": "Placeholder"
}
]
},
{
"name": "wired-listbox",
"label": "List box",
"styles": [
{
"name": "width",
"value": "80px"
},
{
"name": "height",
"value": "100px"
}
]
},
{
"name": "wired-progress",
"label": "Progress bar"
},
{
"name": "wired-radio",
"label": "Radio",
"disableSizing": true,
"properties": [
{
"name": "text",
"value": "Radio_text"
}
]
},
{
"name": "wired-radio-group",
"label": "Radio group",
"styles": [
{
"name": "width",
"value": "80px"
},
{
"name": "height",
"value": "100px"
}
]
},
{
"name": "wired-textarea",
"label": "Multiline text input",
"properties": [
{
"name": "placeholder",
"value": "Placeholder"
}
]
},
{
"name": "wired-toggle",
"label": "Toggle switch",
"disableSizing": true
},
{
"name": "wired-icon-button",
"label": "Icon button"
},
{
"name": "wired-slider",
"label": "Slider"
},
{
"name": "wired-spinner",
"label": "Spinner"
},
{
"name": "a",
"native": true,
"label": "Link",
"textContent": "Link text"
},
{
"name": "p",
"native": true,
"label": "Text",
"textContent": "Lorem ipsum dolor sit amet..."
},
{
"name": "img",
"native": true,
"noCloseTag": true,
"label": "Image",
"styles": [
{
"name": "minWidth",
"value": "20px"
},
{
"name": "minHeight",
"value": "20px"
}
]
},
{
"name": "h1",
"native": true,
"label": "Title",
"textContent": "Title"
},
{
"name": "h2",
"native": true,
"label": "Title 2",
"textContent": "Smaller title"
}
]
}
================================================
FILE: index.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
<title>Wired Designer</title>
<meta name="description" content="Mockups and wireframing tool built using web components, and is open source.">
<link rel="manifest" href="manifest.json">
<link rel="icon" href="images/fav2.png" type="image/png">
<meta property="og:title" content="Wired Designer">
<meta property="og:description" content="Mockups and wireframing tool built using web components, and is open source.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://wiredjs.github.io/designer/">
<meta property="og:image" content="https://wiredjs.github.io/designer/images/logo512.png">
<meta property="og:image:width" content="512">
<meta property="og:image:height" content="512">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@preetster">
<meta name="twitter:title" content="Wired Designer">
<meta name="twitter:description" content="Mockups and wireframing tool built using web components, and is open source.">
<meta name="twitter:image" content="https://wiredjs.github.io/designer/images/logo512.png">
<meta name="twitter:image:width" content="512">
<meta name="twitter:image:height" content="512">
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<script src="src/app.js"></script>
<link rel="import" href="src/the-app.html">
<link href="https://fonts.googleapis.com/css?family=Gloria+Hallelujah" rel="stylesheet">
<style>
body {
margin: 0;
font-family: 'Roboto', 'Noto', sans-serif;
line-height: 1.5;
background-color: white;
-webkit-font-smoothing: antialiased;
}
</style>
</head>
<body>
<the-app></the-app>
</body>
</html>
================================================
FILE: manifest.json
================================================
{
"name": "wywiwyg",
"short_name": "wywiwyg",
"description": "What you wire is what you get",
"start_url": "/",
"display": "standalone"
}
================================================
FILE: polymer.json
================================================
{
"lint": {
"rules": [
"polymer-2"
]
}
}
================================================
FILE: src/action-history.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<dom-module id="action-history">
<template>
<style>
:host {
display: none;
}
</style>
</template>
<script>
/*
* Manages a stack of available undo/redo actions
*/
class ActionHistory extends Polymer.Element {
static get is() { return 'action-history'; }
constructor() {
super();
this.undoHistory = [];
this.redoHistory = [];
}
add(action, node, detail) {
const item = {
action: action,
node: node,
detail: detail
};
// Don't save no-ops: this action may have the new state the same as
// the old state (like when you start dragging but don't get anywhere)
if (detail && detail.new && detail.old &&
this._itemsMatch(action, detail.new, detail.old)) {
return;
}
const topItem = this.undoHistory[this.undoHistory.length - 1];
// Don't save dupes: this action may be a duplicate of the previous one.
if (topItem &&
item.action === topItem.action &&
topItem.node === item.node &&
item.detail && topItem.detail &&
this._itemsMatch(item.action, item.detail, topItem.detail)) {
return;
}
this.undoHistory.push(item);
// A new item in the undo stack means you have nothing to redo.
this.redoHistory = [];
this.updateButtons();
}
undo() {
// Take the top action off the undo stack and move it to the redo stack.
const item = this.undoHistory.pop();
this.redoHistory.push(item);
this.updateButtons();
const detail = item.detail;
item.node.click();
switch (item.action) {
case 'update':
Polymer.Base.fire('element-updated',
{ type: detail.type, name: detail.name, value: detail.old.value, skipHistory: true },
{ node: this });
break;
case 'new':
Polymer.Base.fire('remove-from-canvas',
{ target: item.node, parent: item.detail.parent },
{ node: this });
break;
case 'delete':
if (item.node.id === 'viewContainer') {
item.node.setInnerHTML(detail.innerHTML);
} else {
detail.parent.appendChild(item.node);
}
break;
case 'move':
this._updatePosition(item.node, detail.old);
break;
case 'resize':
this._updateSize(item.node, detail.old);
break;
case 'reparent':
case 'move-up':
case 'move-down':
this._reparent(item.node, detail.new.parent, detail.old.parent);
this._updatePosition(item.node, detail.old);
break;
case 'fit':
this._updatePosition(item.node, detail.old);
this._updateSize(item.node, detail.old);
break;
case 'move-back':
Polymer.Base.fire('move', { type: 'forward', skipHistory: true }, { node: this });
break;
case 'move-forward':
Polymer.Base.fire('move', { type: 'back', skipHistory: true }, { node: this });
break;
}
item.node.click();
}
redo() {
// Take the top action off the redo stack and move it to the undo stack.
let item = this.redoHistory.pop();
let detail = item.detail;
this.undoHistory.push(item);
this.updateButtons();
item.node.click();
switch (item.action) {
case 'update':
Polymer.Base.fire('element-updated',
{ type: detail.type, name: detail.name, value: detail.new.value, skipHistory: true },
{ node: this });
break;
case 'new':
Polymer.Base.fire('add-to-canvas',
{ target: item.node, parent: item.detail.parent },
{ node: this });
break;
case 'delete':
// If the node is the viewContainer, clear its inner HTML.
if (item.node.id === 'viewContainer') {
item.node.setInnerHTML('');
} else {
item.node.parentElement.click();
item.node.parentElement.removeChild(item.node);
}
break;
case 'move':
this._updatePosition(item.node, detail.new);
break;
case 'resize':
this._updateSize(item.node, detail.new);
break;
case 'reparent':
case 'move-up':
case 'move-down':
this._reparent(item.node, detail.old.parent, detail.new.parent);
this._updatePosition(item.node, detail.new);
break;
case 'fit':
this._updateSize(item.node, detail.new);
this._updatePosition(item.node, detail.new);
break;
case 'move-back':
Polymer.Base.fire('move', { type: 'forward', skipHistory: true }, { node: this });
break;
case 'move-forward':
Polymer.Base.fire('move', { type: 'back', skipHistory: true }, { node: this });
break;
}
item.node.click();
}
updateButtons() {
Polymer.Base.fire('update-action-buttons',
{ undos: this.undoHistory.length, redos: this.redoHistory.length }, { node: this });
}
_itemsMatch(action, first, second) {
// These kinds of actions have element refs in the details,
// and you can't json those anyway.
if (action === 'reparent' || action === 'move-up' || action === 'move-down') {
return false;
}
return JSON.stringify(first) === JSON.stringify(second);
}
_updatePosition(node, detail) {
node.style.left = detail.left;
node.style.top = detail.top;
node.style.position = detail.position;
}
_updateSize(node, detail) {
node.style.width = detail.width;
node.style.height = detail.height;
rewire(node);
}
_reparent(node, oldParent, newParent) {
oldParent.removeChild(node);
newParent.appendChild(node);
rewire(oldParent);
rewire(newParent);
}
}
customElements.define(ActionHistory.is, ActionHistory);
</script>
</dom-module>
================================================
FILE: src/app-controls.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="app-icons.html">
<dom-module id="app-controls">
<template strip-whitespace>
<style>
:host {
display: flex;
}
button {
background: transparent;
color: white;
border: none;
cursor: pointer;
transition: all .05s ease-in;
}
button[disabled] {
opacity: 0.3;
pointer-events: none;
}
button:hover {
transform: scale(1.1);
}
.separator {
border-left: var(--light-grey) solid 1px;
opacity: .8;
height: 24px;
margin: 8px;
}
</style>
<button on-click="undo" id="undoBtn" disabled title="Undo">
<iron-icon icon="designer:undo"></iron-icon>
<div>Undo</div>
</button>
<button on-click="redo" id="redoBtn" disabled title="Redo">
<iron-icon icon="designer:redo"></iron-icon>
<div>Redo</div>
</button>
<!-- <div class="separator"></div>
<button on-click="jsFiddleIt" title="Create a JSFiddle">
<iron-icon icon="designer:cloud"></iron-icon>
<div>JSFiddle</div>
</button> -->
<form id="jsFiddleForm" hidden method='post' action='https://jsfiddle.net/api/post/library/pure/' target='check'>
<input type='submit' />
<textarea name='html'></textarea>
<input name='title' />
<input name='description'>
</form>
</template>
<script>
class AppControls extends Polymer.Element {
static get is() { return 'app-controls'; }
static get properties() {
return {
actionHistory: Object
}
}
update(undos, redos) {
this.$.undoBtn.disabled = (undos === 0);
this.$.redoBtn.disabled = (redos === 0);
}
undo() {
this.actionHistory.undo();
}
redo() {
this.actionHistory.redo();
}
}
customElements.define(AppControls.is, AppControls);
</script>
</dom-module>
================================================
FILE: src/app-icons.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/iron-iconset-svg/iron-iconset-svg.html">
<iron-iconset-svg size="24" name="designer">
<svg>
<defs>
<g id="undo">
<path d="M12.5 8c-2.65 0-5.05.99-6.9 2.6L2 7v9h9l-3.62-3.62c1.39-1.16 3.16-1.88 5.12-1.88 3.54 0 6.55 2.31 7.6 5.5l2.37-.78C21.08 11.03 17.15 8 12.5 8z"></path>
</g>
<g id="redo">
<path d="M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7l-3.6 3.6z"></path>
</g>
<g id="delete">
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path>
</g>
<g id="copy">
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"></path>
</g>
<g id="fit">
<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path>
</g>
<g id="back">
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path>
</g>
<g id="forward">
<path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"></path>
</g>
<g id="up">
<path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"></path>
</g>
<g id="down">
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"></path>
</g>
<g id="cloud">
<path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"></path>
</g>
<g id="clear">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
</g>
<g id="unfold-more">
<path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"
/>
</g>
</defs>
</svg>
</iron-iconset-svg>
================================================
FILE: src/app.js
================================================
/*
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
// window.addEventListener('WebComponentsReady', function () {
// document.addEventListener('update-code', function (event) {
// codeView.dump(event.detail.target);
// }, true);
// });
function getProtoProperties(target) {
// If this is a custom element, you need to go up the prototype
// chain until you get proper HTMLElement, since everything under it
// is generated prototypes and will have propeties that are dupes (like:
// every observedAttribute is also mirrored as a property)
const isCustomElement = target.tagName.indexOf('-') !== -1;
let proto = target.__proto__;
if (isCustomElement) {
while (proto.constructor !== window.HTMLElement.prototype.constructor) {
proto = proto.__proto__;
}
}
let protoProps = {};
// We literally want nothing other than 'href' and 'target' from HTMLAnchorElement.
if (proto.constructor.name === 'HTMLAnchorElement') {
protoProps['href'] = Object.getOwnPropertyDescriptors(proto).href;
protoProps['target'] = Object.getOwnPropertyDescriptors(proto).target;
proto = proto.__proto__;
}
while (proto.constructor.name !== 'Element') {
Object.assign(protoProps, Object.getOwnPropertyDescriptors(proto));
proto = proto.__proto__;
}
let propNames = Object.keys(protoProps).sort();
// Skip some very specific Polymer/element properties.
let blacklist = [
// Polymer specific
'isAttached',
'constructor', 'created', 'ready', 'attached', 'detached',
'attributeChanged', 'is', 'listeners', 'observers', 'properties',
// Native elements ones we don't care about
'validity', 'useMap', 'innerText', 'outerText', 'style', 'accessKey',
'draggable', 'lang', 'spellcheck', 'tabIndex', 'translate', 'align', 'dir',
'isMap', 'useMap', 'hspace', 'vspace', 'referrerPolicy', 'crossOrigin',
'lowsrc', 'longDesc', "contentEditable", "hidden", "title",
// Specific elements stuff
'receivedFocusFromKeyboard', 'pointerDown', 'valueAsNumber',
'selectionDirection', 'selectionStart', 'selectionEnd'
];
let i = 0;
while (i < propNames.length) {
let name = propNames[i];
// Skip everything that starts with a _ which is a Polymer private/protected
// and you probably don't care about it.
// Also anything in the blacklist. Or that starts with webkit.
if (name.charAt(0) === '_' ||
name === 'keyEventTarget' ||
blacklist.indexOf(name) !== -1 ||
name.indexOf('webkit') === 0 ||
name.indexOf('on') === 0) {
propNames.splice(i, 1);
continue;
}
// Skip everything that doesn't have a setter.
if (!protoProps[name].set) {
propNames.splice(i, 1);
continue;
}
i++;
}
return propNames || [];
}
function getAttributesIfCustomElement(target) {
if (target.tagName.indexOf('-') !== -1) {
return target.constructor.observedAttributes;
} else {
return [];
}
}
function getCustomProperties(target) {
let list = [];
if (target.tagName.indexOf('-') !== -1) {
let attrs = target.constructor.observedAttributes || [];
if (attrs.length) {
var props = target.constructor.properties;
if (props) {
var keys = Object.keys(props);
for (var i = 0; i < keys.length; i++) {
var pname = keys[i];
var p = props[pname];
var typeFn = null;
if (typeof p === 'function') {
typeFn = p;
} else {
typeFn = p.type;
}
list.push({
name: pname,
type: typeFn ? (typeFn.name || "String") : "String",
value: target[pname]
});
}
}
}
}
return list;
}
function rewire(el) {
setTimeout(() => {
if (el._relayout) {
try { el._relayout(); } catch (ex) { console.error(ex); }
} else if (el.relayout) {
try { el.relayout(); } catch (ex) { console.error(ex); }
} else if (el._refresh) {
try { el._refresh(); } catch (ex) { console.error(ex); }
}
}, 1);
}
================================================
FILE: src/canvas/canvas-controls.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../app-icons.html">
<link rel="import" href="../components/designer-tab.html">
<dom-module id="canvas-controls">
<template strip-whitespace>
<style>
:host {
display: block;
}
designer-tab {
color: white;
background: var(--dark-grey);
width: 100%;
height: 41px;
margin: 0;
padding: 0;
border: none;
display: flex;
padding: 0 0 1em;
font-size: 10px;
line-height: 1em;
justify-content: space-around;
}
button {
padding: 0;
cursor: pointer;
font-size: 8px;
border: 2px solid transparent;
border-width: 2px 0;
position: relative;
margin: 0;
transition: all .05s ease-in;
}
button[disabled] {
pointer-events: none;
opacity: 0.3;
}
button::before,
button::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
border: 2px solid transparent;
border-width: 0 2px 0;
box-sizing: border-box;
}
button::after {
top: auto;
bottom: 0;
}
button:hover,
button:hover::before,
button:hover::after {
border-color: var(--light-grey);
}
button:active,
button:active::before,
button:active::after {
border-color: var(--highlight-pink);
}
</style>
<designer-tab>
<button on-click="delete" title="Delete element">
<iron-icon icon="designer:delete"></iron-icon>
</button>
<button on-click="clone" id="cloneBtn" title="Clone element">
<iron-icon icon="designer:copy"></iron-icon>
</button>
<button on-click="fit" id="fitBtn" title="Fit to parent">
<iron-icon icon="designer:fit"></iron-icon>
</button>
<button on-click="moveUp" title="Move to parent. Also Shift+UpArrow" id="moveUpBtn">
<iron-icon icon="designer:up"></iron-icon>
</button>
<button on-click="moveDown" title="Move to first child. Also Shift+DownArrow" id="moveDownBtn">
<iron-icon icon="designer:down"></iron-icon>
</button>
<button on-click="moveBack" title="Move back. Also Shift+LeftArrow" id="moveBackBtn">
<iron-icon icon="designer:back"></iron-icon>
</button>
<button on-click="moveForward" title="Move forward. Also Shift+RightArrow" id="moveForwardBtn">
<iron-icon icon="designer:forward"></iron-icon>
</button>
</designer-tab>
</template>
<script>
class CanvasControls extends Polymer.Element {
static get is() { return 'canvas-controls'; }
static get properties() {
return {
selectedElement: {
type: Object,
observer: '_selectedElementChanged'
},
canvasElement: Object,
actionHistory: Object
}
}
connectedCallback() {
super.connectedCallback();
window.addEventListener("delete-request", () => {
this.delete();
});
}
/**
* Disable a bunch of UI if the selected element is the canvas element.
*/
update(disableUI) {
this.$.cloneBtn.disabled = disableUI;
this.$.fitBtn.disabled = disableUI;
this.$.moveUpBtn.disabled = disableUI;
this.$.moveDownBtn.disabled = disableUI;
this.$.moveBackBtn.disabled = disableUI;
this.$.moveForwardBtn.disabled = disableUI;
}
/**
* Deletes the active element.
*/
delete() {
if (!this.selectedElement) {
console.log('🔥 how did i get here?');
return;
}
const el = this.selectedElement;
// Deleting the top level app should remove its children.
if (this._isCanvasElement(el)) {
this.actionHistory.add('delete', el, { innerHTML: el.getInnerHTML() });
el.setInnerHTML('');
} else {
const parent = el.parentElement;
if (parent) {
parent.removeChild(el);
this.selectedElement = parent;
this.actionHistory.add('delete', el, { parent: parent });
}
}
this._refreshView();
}
/**
* Creates a sibling copy of the active element.
*/
clone() {
const el = this.selectedElement;
if (this._isCanvasElement(el)) {
return;
}
let clone = el.cloneNode(true);
el.parentNode.appendChild(clone);
let attrs = el.constructor.observedAttributes || [];
if (attrs.length) {
var props = el.constructor.properties;
if (props) {
var keys = Object.keys(props);
for (var i = 0; i < keys.length; i++) {
var pname = keys[i];
clone[pname] = el[pname];
}
}
}
Polymer.Base.fire('finish-clone', { target: clone }, { node: this });
// P.S: Since we did a clone, we already have the initial state of the <tag>.
this.actionHistory.add('new', clone, { parent: el.parentNode });
this._refreshView();
}
/**
* Fit an element to its target
*/
fit() {
const el = this.selectedElement;
if (this._isCanvasElement(el)) {
return;
}
this.actionHistory.add('fit', el,
{
new: {
position: 'absolute',
left: '0', top: '0',
width: '100%', height: '100%'
},
old: {
position: el.style.position,
left: el.style.left, top: el.style.top,
width: el.style.width, height: el.style.height,
}
});
el.style.position = 'absolute';
el.style.left = el.style.top = '0px';
el.style.height = el.style.width = '100%';
rewire(el);
}
/**
* Moving elements in the DOM
*/
move(type, skipHistory) {
switch (type) {
case 'forward':
this.moveForward(skipHistory);
break;
case 'back':
this.moveBack(skipHistory);
break;
case 'up':
this.moveUp(skipHistory);
break;
case 'down':
this.moveDown(skipHistory);
break;
}
}
moveBack(skipHistory) {
const el = this.selectedElement;
if (this._isCanvasElement(el)) {
return;
}
let parent = el.parentElement;
let previous = el.previousElementSibling;
if (previous) {
parent.insertBefore(el, previous);
} else {
parent.appendChild(el);
}
this._refreshView();
if (skipHistory === true) {
return;
}
this.actionHistory.add('move-back', el);
}
moveForward(skipHistory) {
const el = this.selectedElement;
if (this._isCanvasElement(el)) {
return;
}
let parent = el.parentElement;
// Since you can't insertAfter your next sibling, you need to
// insert before two siblings over.
let next = el.nextElementSibling;
if (next) {
next = next.nextElementSibling;
if (next) {
parent.insertBefore(el, next);
} else {
parent.appendChild(el);
}
} else {
parent.insertBefore(el, parent.firstChild);
}
this._refreshView();
if (skipHistory === true) {
return;
}
this.actionHistory.add('move-forward', el);
}
moveUp(skipHistory) {
const el = this.selectedElement;
let parent = el.parentElement;
// If the parent isn't already the viewContainer, move it one up.
if (this._isCanvasElement(el) || (parent && parent.id === 'canvas')) {
return;
}
parent.removeChild(el);
parent.parentElement.appendChild(el);
this._refreshView();
if (skipHistory === true) {
return;
}
this.actionHistory.add('move-up', el,
{ old: { parent: parent }, new: { parent: parent.parentElement } });
}
moveDown(skipHistory) {
const el = this.selectedElement;
let sibling = el.nextElementSibling;
if (this._isCanvasElement(el) || !sibling) {
return;
}
// Not everything accepts children, as we've learnt from canvas-view
// (where I copied this code from like a lazy bum)
let slots = sibling.root ? sibling.root.querySelectorAll('slot') : [];
let canDrop =
(sibling.localName.indexOf('-') === -1 && sibling.localName !== 'input') ||
sibling.localName === 'dom-repeat' || slots.length !== 0;
if (!canDrop) {
return;
}
// If you can, add it there.
const oldParent = el.parentElement;
sibling.appendChild(el);
const oldPosition = el.style.position;
el.style.position = 'relative';
this._refreshView();
if (skipHistory === true) {
return;
}
this.actionHistory.add('move-down', el,
{
old: { parent: oldParent, position: oldPosition },
new: { parent: sibling, position: 'relative' }
});
}
_refreshView() {
Polymer.Base.fire('refresh-view', {}, { node: this });
}
_selectedElementChanged() {
Polymer.Base.fire('selected-element-changed', { target: this.selectedElement }, { node: this });
}
_isCanvasElement(el) {
return (el === this.canvasElement);
}
}
customElements.define(CanvasControls.is, CanvasControls);
</script>
</dom-module>
================================================
FILE: src/canvas/canvas-view.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/polymer/lib/mixins/gesture-event-listeners.html">
<dom-module id="canvas-view">
<template>
<style>
:host {
display: block;
box-sizing: border-box;
width: 100%;
position: relative;
background-color: var(--canvas-background);
transform: translateZ(0);
font-family: 'Gloria Hallelujah', sans-serif;
}
#canvas {
box-sizing: border-box;
width: 100%;
height: 100%;
}
#canvas>dom-repeat {
height: 20px;
width: 20px;
display: inline-block;
}
#canvas * {
cursor: pointer;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
#canvas *:not(.active):hover {
outline: solid 2px #90CAF9 !important;
outline-offset: 2px;
}
.active,
:host(.active) {
outline: solid 3px var(--highlight-blue) !important;
outline-offset: 2px;
transform: translateZ(0);
}
:host(.active) {
outline-offset: -3px;
}
/* Show a resize cursor in the corner */
.active-resizable:after {
position: absolute;
bottom: -3px;
right: -3px;
height: 14px;
width: 14px;
content: '↘';
cursor: se-resize;
font-size: 10px;
font-weight: bold;
text-align: center;
background: var(--highlight-blue);
color: white;
}
.dragging,
.resizing {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.dragging {
/*opacity: 0.6;*/
z-index: 1000;
cursor: move;
}
.resizing {
cursor: se-resize;
}
.over {
outline: dashed 3px var(--highlight-blue) !important;
outline-offset: 2px;
}
</style>
<div id="canvas"></div>
</template>
<script>
class CanvasView extends Polymer.Element {
static get is() { return 'canvas-view'; }
static get properties() {
return {
grid: {
type: Boolean,
value: true,
observer: '_onGridChange'
}
}
}
connectedCallback() {
super.connectedCallback();
this._onGridChange();
Polymer.Gestures.addListener(this.$.canvas, 'track', this.trackElement.bind(this));
this.addEventListener('click', event => {
this.updateActiveElement(this);
});
this.$.canvas.addEventListener('click', event => {
// If this element is a link, it will actually do a navigation, so, don't.
event.preventDefault();
event.stopImmediatePropagation();
if (event.target.id === 'canvas' && !this._justFinishedDraggingOrDropping) {
this.updateActiveElement(this);
} else {
this.updateActiveElement(event.target);
}
});
window.addEventListener('keydown', this.onKeyDown.bind(this), true);
}
_onGridChange() {
if (this.grid) {
this.classList.add("grid");
} else {
this.classList.remove("grid");
}
}
add(el) {
this.$.canvas.appendChild(el);
}
remove(el) {
this.$.canvas.removeChild(el);
}
has(query) {
return this.$.canvas.querySelector(query);
}
setInnerHTML(thing) {
this.$.canvas.innerHTML = thing;
}
getInnerHTML() {
return this.$.canvas.innerHTML;
}
get children() {
return this.$.canvas.children;
}
updateActiveElement(el) {
this.selectedElement = el;
Polymer.Base.fire('selected-element-changed', { target: el }, { node: this });
Polymer.Base.fire('refresh-view', {}, { node: this });
}
trackElement(event) {
let el = event.target;
this._justFinishedDraggingOrDropping = false;
if (el === this || el === this.$.canvas) {
return;
}
// If we're already resizing, continue.
if (this._resizing) {
this.resizeElement(event, el);
return;
}
let rekt = el.getBoundingClientRect();
let shouldResize = this.dragShouldSize(event, rekt);
if (this._dragging || el.getAttribute("data-noresize") === "true") {
shouldResize = false;
}
if (shouldResize) {
this._resizing = true;
this._initialWidth = rekt.width;
this._initialHeight = rekt.height;
el.classList.add('resizing');
el.classList.add('active');
el.classList.add('active-resizable');
}
if (this._resizing) {
this.resizeElement(event, el);
} else {
this.dragElement(event, el, rekt);
}
// TODO: I don't know how to do this better, but I should fix this one day.
// The problem is that sometimes when you drag, the end drag is outside
// the dragging target (like, if it resizes because CSS), and will
// register as a click on the canvas and it's annoying. This gets
// around that but in a gross way.
if (event.detail.state === 'end') {
this._justFinishedDraggingOrDropping = true;
}
}
dragElement(event, el, rekt) {
switch (event.detail.state) {
case 'start':
this._resizing = false;
this._dragging = true;
el.style.position = 'absolute';
el.classList.add('dragging');
el.classList.add('active');
if (el.getAttribute("data-noresize") != "true") {
el.classList.add('active-resizable');
}
break;
case 'track':
// Grid is 10.
this._trackx = Math.round(event.detail.dx / 10) * 10;
this._tracky = Math.round(event.detail.dy / 10) * 10;
el.style.transform = el.style.webkitTransform =
'translate(' + this._trackx + 'px, ' + this._tracky + 'px)';
// See if it's over anything.
this._dropTarget = null;
let targets = this.$.canvas.querySelectorAll('*');
for (let i = 0; i < targets.length; i++) {
let t = targets[i];
t.classList.remove('over');
// Only some native elements and things with slots can be
// drop targets.
let slots = t.root ? t.root.querySelectorAll('slot') : [];
// input is the only native in this app that doesn't have a slot
let canDrop =
(t.localName.indexOf('-') === -1 && t.localName !== 'input') ||
t.localName === 'dom-repeat' || slots.length !== 0;
if (!canDrop) {
continue;
}
// Do we actually intersect this child?
let b = t.getBoundingClientRect();
if (rekt.left > b.left && rekt.left < b.left + b.width &&
rekt.top > b.top && rekt.top < b.top + b.height) {
// New target! Remove the other target indicators.
var previousTargets = this.root.querySelectorAll('.over');
for (var j = 0; j < previousTargets.length; j++) {
previousTargets[j].classList.remove('over');
}
t.classList.add('over');
this._dropTarget = t;
}
}
break;
case 'end':
this._resizing = false;
this._dragging = false;
let reparented = false;
let oldParent = el.parentElement;
let newParent;
// Does this need to be added to a new parent?
if (this._dropTarget) {
reparented = true;
oldParent.removeChild(el);
// If there was a textContent nuke it, or else you'll
// never be able to again.
if (this._dropTarget.children.length === 0) {
this._dropTarget.textContent = '';
}
this._dropTarget.appendChild(el);
newParent = this._dropTarget;
this._dropTarget = null;
} else if (el.parentElement && (el.parentElement !== this.$.canvas)) {
reparented = true;
// If there's no drop target and the el used to be in a different
// parent, move it to the main view.
newParent = this.$.canvas;
el.parentElement.removeChild(el);
this.add(el);
}
let parent = el.parentElement.getBoundingClientRect();
let oldLeft = el.style.left;
let oldTop = el.style.top;
let oldPosition = el.style.position;
if (reparented) {
el.style.position = 'relative';
el.style.left = el.style.top = '0px';
this.actionHistory.add('reparent', el,
{
new: {
parent: newParent,
left: el.style.left, top: el.style.top, position: el.style.position
},
old: {
parent: oldParent,
left: oldLeft, top: oldTop, position: oldPosition
}
});
} else {
el.style.position = 'absolute';
el.style.left = rekt.left - parent.left + 'px';
el.style.top = rekt.top - parent.top + 'px';
this.actionHistory.add('move', el,
{
new: { left: el.style.left, top: el.style.top, position: el.style.position },
old: { left: oldLeft, top: oldTop, position: oldPosition }
});
}
if (newParent)
newParent.classList.remove('over');
if (oldParent)
oldParent.classList.remove('over');
el.classList.remove('dragging');
el.classList.remove('resizing');
el.style.transform = el.style.webkitTransform = 'none';
break;
}
this.updateActiveElement(el);
Polymer.Base.fire('refresh-view', { whileTracking: true }, { node: this });
}
resizeElement(event, el) {
switch (event.detail.state) {
case 'track':
// Grid is 10.
let trackX = Math.round(event.detail.dx / 10) * 10;
let trackY = Math.round(event.detail.dy / 10) * 10;
el.style.width = this._initialWidth + trackX + 'px';
el.style.height = this._initialHeight + trackY + 'px';
rewire(el);
break;
case 'end':
this._resizing = false;
this.actionHistory.add('resize', el,
{
new: { width: el.style.width, height: el.style.height },
old: { width: this._initialWidth + 'px', height: this._initialHeight + 'px' }
});
el.classList.remove('resizing');
el.classList.remove('dragging');
rewire(el);
// Ensure that this element is still selected after we're done.
// i.e.: Sometimes the end of a resize can end up outside of the element,
// and register as a click on the main canvas, deselecting the thing
// you were dragging.
setTimeout(function () {
el.click();
}, 50)
break;
}
this.updateActiveElement(el);
}
dragShouldSize(event, rect) {
const right = Math.abs(rect.right - event.detail.x);
const bottom = Math.abs(rect.bottom - event.detail.y);
return (right < 13 && bottom < 13);
}
deepTargetFind(x, y, notThis) {
let node = document.elementFromPoint(x, y);
let next = node;
// this code path is only taken when native ShadowDOM is used
// if there is a shadowroot, it may have a node at x/y
// if there is not a shadowroot, exit the loop
while (next !== notThis && next && next.shadowRoot && !window.ShadyDOM) {
// if there is a node at x/y in the shadowroot, look deeper
let oldNext = next;
next = next.shadowRoot.elementFromPoint(x, y);
// on Safari, elementFromPoint may return the shadowRoot host
if (oldNext === next) {
break;
}
if (next) {
node = next;
}
}
return node;
}
onKeyDown(event) {
let el = this.selectedElement;
if (!el) {
return;
}
// This is a global window handler, so clicks can come from anywhere
// We only care about keys that come after you've clicked on an element,
// or keys after you've selected something from the tree view.
// TODO: can this be less bad since it's p horrid?
let isOk =
(event.composedPath()[0].localName === 'button' && (event.composedPath()[2].localName == 'tree-view' || event.composedPath()[2].localName == 'palettes-list')) ||
(event.composedPath()[0].localName == 'body') ||
event.composedPath()[0].classList.contains('active');
if (!isOk) {
return;
}
let oldLeft = parseInt(el.style.left);
let oldTop = parseInt(el.style.top);
let oldPosition = el.style.position;
switch (event.keyCode) {
case 38: // up arrow
if (event.shiftKey) {
event.preventDefault();
Polymer.Base.fire('move', { type: 'up' }, { node: this });
} else {
el.style.top = oldTop - 10 + 'px';
}
break;
case 40: // down arrow
if (event.shiftKey) {
event.preventDefault();
Polymer.Base.fire('move', { type: 'down' }, { node: this });
} else {
el.style.top = oldTop + 10 + 'px';
}
break;
case 37: // left arrow
if (event.shiftKey) {
event.preventDefault();
Polymer.Base.fire('move', { type: 'back' }, { node: this });
} else {
el.style.left = oldLeft - 10 + 'px';
}
break;
case 39: // right arrow
if (event.shiftKey) {
event.preventDefault();
Polymer.Base.fire('move', { type: 'forward' }, { node: this });
} else {
el.style.left = oldLeft + 10 + 'px';
}
break;
case 8:
case 46:
const removeEvent = new CustomEvent('delete-request', { bubbles: true, composed: true, detail: {} });
window.dispatchEvent(removeEvent);
break;
}
this.actionHistory.add('move', el,
{
new: { left: el.style.left, top: el.style.top, position: el.style.position },
old: { left: oldLeft, top: oldTop, position: oldPosition }
});
}
}
customElements.define(CanvasView.is, CanvasView);
</script>
</dom-module>
================================================
FILE: src/components/designer-tab.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<dom-module id="designer-tab">
<template strip-whitespace>
<style>
:host {
display: inline-block;
position: relative;
border-top: 3px solid transparent;
color: white;
transition: border .1s ease-in;
}
:host([disabled]) {
opacity: 0.3;
pointer-events: none;
}
:host(:hover) {
border-color: var(--light-grey);
}
:host(.iron-selected) {
background: var(--medium-grey);
border-color: var(--highlight-pink);
}
:host ::slotted(*) {
display: inline-block;
background: transparent;
border: none;
padding: 10px 5px;
font-size: 12px;
letter-spacing: 1px;
font-weight: 500;
text-decoration: none;
text-transform: uppercase;
line-height: 1.5;
color: inherit;
margin: 0 8px;
outline: none;
cursor: pointer;
}
</style>
<slot></slot>
</template>
<script>
class DesignerTab extends Polymer.Element {
static get is() { return 'designer-tab'; }
}
customElements.define(DesignerTab.is, DesignerTab);
</script>
</dom-module>
================================================
FILE: src/components/designer-tabs.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-selector/iron-selectable.html">
<dom-module id="designer-tabs">
<template strip-whitespace>
<style>
:host {
display: block;
background-color: var(--dark-grey);
text-transform: uppercase;
width: 100%;
}
#container {
position: relative;
width: 100%;
}
</style>
<div id="container">
<slot></slot>
</div>
</template>
<script>
class DesignerTabs extends Polymer.mixinBehaviors(
[Polymer.IronSelectableBehavior], Polymer.Element) {
static get is() { return 'designer-tabs'; }
}
customElements.define(DesignerTabs.is, DesignerTabs);
</script>
</dom-module>
================================================
FILE: src/components/icon-picker.html
================================================
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-icon/iron-icon.html">
<dom-module id="icon-picker">
<template>
<style include="element-stuff-shared-styles iron-flex iron-flex-alignment">
:host {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
background: var(--canvas-background);
transform: translateY(-100px);
transition: transform 0.3s ease;
color: var(--almost-black);
}
.container {
display: inline-block;
width: 10em;
padding: 1em 0.5em;
text-align: center;
cursor: pointer;
border-radius: 10px;
}
.container>div {
margin-top: 0.5em;
color: black;
font-size: 10px;
}
.container:hover {
background: rgba(33, 150, 243, 0.15);
}
h1 {
font-weight: 300;
margin: 0;
padding: 15px 10px 20px;
font-size: 30px;
}
#btnClose {
position: fixed;
top: 15px;
right: 30px;
background: var(--highlight-pink);
color: white;
padding: 12px;
border-radius: 100%;
cursor: pointer;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.12), 0 3px 3px rgba(0, 0, 0, 0.24), 0 0 6px rgba(0, 0, 0, 0.12), 0 6px 6px rgba(0, 0, 0, 0.24);
}
</style>
<h1 class="flex">Select an icon</h1>
<iron-icon id="btnClose" on-click="hide" icon="designer:clear"></iron-icon>
<div>
<template is="dom-repeat" items="[[icons]]">
<span class="container" on-click="_onSelected">
<iron-icon icon="{{item}}"></iron-icon>
<div>{{item}}</div>
</span>
</template>
</div>
</template>
<script>
class IconPicker extends Polymer.Element {
static get is() { return "icon-picker" }
static get properties() {
return {
icons: Array
}
}
connectedCallback() {
super.connectedCallback();
const list = new Polymer.IronMeta({ type: 'iconset' }).list;
var match;
for (var i = 0; i < list.length; i++) {
if (list[i].name === "icons") {
match = list[i];
break;
}
}
this.icons = match.getIconNames();
}
_onSelected(event) {
var icon = event.model.item;
const e = new CustomEvent('select', { bubbles: true, composed: true, detail: { icon: icon } });
this.dispatchEvent(e);
this.hide();
}
show() {
this.style.display = "block";
setTimeout(() => {
this.style.transform = "none";
}, 10);
}
hide() {
this.style.transform = "translateY(100%)";
setTimeout(() => {
this.style.display = "none";
}, 300);
}
}
customElements.define(IconPicker.is, IconPicker);
</script>
</dom-module>
================================================
FILE: src/components/tree-view.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<dom-module id="tree-view">
<template strip-whitespace>
<style>
:host {
display: inline-block;
position: relative;
width: 100%;
height: 100%;
background: var(--dark-grey);
}
button {
border: none;
font-size: 13px;
display: block;
padding: 4px 0;
cursor: pointer;
width: 100%;
text-align: left;
display: inline-block;
margin: 0;
background: var(--dark-grey);
position: relative;
top: 0.5em;
color: white;
}
button:hover,
button:focus {
background: var(--light-grey);
}
span {
margin: 4px;
}
.id {
font-style: italic;
color: var(--highlight-pink);
}
.selected {
background: var(--light-grey);
outline: none;
}
#tree ul:first-child {
padding-left: 0px;
}
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}
ul {
padding-left: 14px;
}
li {
padding-left: 10px;
border: 1px solid silver;
border-width: 0 0 1px 1px;
}
li.has-children {
border-bottom: 0px;
}
li ul {
margin-left: -10px;
padding-left: 20px;
}
</style>
<div id="tree"></div>
</template>
<script>
class TreeView extends Polymer.Element {
static get is() { return 'tree-view'; }
ready() {
super.ready();
this.$.tree.addEventListener('click', this.findElement.bind(this))
}
recomputeTree(parent, active) {
this.$.tree.innerHTML = '';
// Since we can't add a pojo to each button, generate a new index for
// each button in the this.items array of useful data.
this._index = 0;
this.items = this.getChildren(parent, this.$.tree);
this.highlight(active);
this.$.tree
return this.items;
}
_makeButton(tag, id, index) {
let aButton = document.createElement('button');
aButton.dataset.index = index;
let aTag = document.createElement('span');
aTag.className = 'tag';
aTag.textContent = tag;
let aId = document.createElement('span');
aId.className = 'id';
aId.textContent = id;
aButton.appendChild(aTag);
aButton.appendChild(aId);
return aButton;
}
getChildren(parent, div) {
// At every new parent, we create a new <ul>
let ul = document.createElement('ul');
div.appendChild(ul);
let isViewContainer = parent.id === 'viewContainer';
let data = {
tag: isViewContainer ? 'main-app' : parent.tagName.toLowerCase(),
id: isViewContainer ? '' : (parent.id ? '#' + parent.id : ''),
text: isViewContainer ? '' : '"' + parent.textContent + '"',
ref: parent,
index: this._index
};
// Create this node's content;
let li = document.createElement('li');
let button = this._makeButton(data.tag, data.id, data.index);
li.appendChild(button);
ul.appendChild(li);
this._index++;
let nodes = [data];
// If this node has children...
for (let i = 0; i < parent.children.length; i++) {
let child = parent.children[i];
// Skip <style> nodes;
if (child.localName === 'style') {
continue;
}
li.className = 'has-children';
nodes = nodes.concat(this.getChildren(child, li));
}
return nodes;
}
findElement(event) {
// If the target is a <span>, you clicked on the span inside the button
// so you need to use currentTarget.
let item = event.target;
if (item.tagName === 'SPAN') {
item = item.parentElement;
}
this.selectTreeElement(item);
// Find the actual element it points to.
let index = item.dataset.index;
let el = this.items[index].ref;
el.click();
}
selectTreeElement(item) {
if (this._previouslySelected) {
this._previouslySelected.classList.remove('selected');
}
this._previouslySelected = item;
item.classList.add('selected');
}
highlight(element) {
// Find it in the tree.
let buttons = this.root.querySelectorAll('button');
if (buttons.length !== this.items.length) {
return;
}
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].ref === element) {
this.selectTreeElement(buttons[i]);
return;
}
}
}
}
customElements.define(TreeView.is, TreeView);
</script>
</dom-module>
================================================
FILE: src/element-view/element-properties.html
================================================
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-repeat.html">
<link rel="import" href="element-stuff-shared-styles.html">
<link rel="import" href="element-property.html">
<link rel="import" href="../components/icon-picker.html">
<dom-module id="element-properties">
<template>
<style include="element-stuff-shared-styles"></style>
<div class="content-wrapper">
<dom-repeat items="[[props]]">
<template>
<element-property on-icon-picker="_onIconPicker" on-change="_onChange" prop="[[item]]"></element-property>
</template>
</dom-repeat>
</div>
<icon-picker id="iconPicker" on-select="_onIconSelect"></icon-picker>
</template>
<script>
class ElementProperties extends Polymer.Element {
static get is() { return 'element-properties' }
static get properties() {
return {
props: Array
}
}
display(target, info) {
if (target.id === 'viewContainer') {
this.set("props", []);
return;
}
let list = this._getCustomProperties(target, info);
if (info && info.native) {
let propNames = window.getProtoProperties(target);
if (propNames && propNames.length) {
for (var i = 0; i < propNames.length; i++) {
list.push({
name: propNames[i],
type: String,
value: target[propNames[i]] || ""
});
}
}
}
list.sort((a, b) => {
let na = a.name.toUpperCase();
let nb = b.name.toUpperCase();
if (na < nb) return -1;
if (na > nb) return 1;
return 0;
});
this.set("props", list);
}
_getCustomProperties(target, info) {
let list = [];
if (target.tagName.indexOf('-') !== -1) {
let attrs = target.constructor.observedAttributes || [];
if (attrs.length) {
var props = target.constructor.properties;
if (props) {
var keys = Object.keys(props);
for (var i = 0; i < keys.length; i++) {
var pname = keys[i];
var p = props[pname];
var typeFn = null;
if (typeof p === 'function') {
typeFn = p;
} else {
typeFn = p.type;
}
let listItem = {
name: pname,
type: typeFn ? (typeFn.name || "String") : "String",
value: target[pname]
};
if ((listItem.type !== "Boolean") && (!listItem.value)) {
listItem.value = "";
}
list.push(listItem);
}
}
}
}
if (info && info.textContent) {
list.push({
name: "textContent",
type: "String",
value: target.textContent
});
}
return list;
}
_onChange(event) {
Polymer.Base.fire('element-updated',
{
type: 'property',
name: event.detail.name,
value: event.detail.value,
isAttribute: false
}, { node: this });
}
_onIconPicker(event) {
this._pickerTarget = event.target;
this.$.iconPicker.show();
}
_onIconSelect(event) {
let icon = event.detail.icon;
if (this._pickerTarget) {
this._pickerTarget.value = icon;
this._pickerTarget = null;
}
}
}
window.customElements.define(ElementProperties.is, ElementProperties);
</script>
</dom-module>
================================================
FILE: src/element-view/element-property.html
================================================
<link rel="import" href="../../bower_components/paper-toggle-button/paper-toggle-button.html">
<dom-module id="element-property">
<template>
<style include="element-stuff-shared-styles iron-flex iron-flex-alignment">
:host {
display: block;
}
.container {
box-sizing: border-box;
overflow: hidden;
}
#moreIcon {
cursor: pointer;
}
</style>
<div class="container horizontal layout center">
<label class="flex">{{prop.name}}</label>
<iron-icon on-click="_onMore" id="moreIcon" icon="designer:unfold-more" style="display: none;"></iron-icon>
<input id="input" on-change="_onChange">
<paper-toggle-button id="btn" on-change="_onChange"></paper-toggle-button>
</div>
</template>
<script>
class ElementProperty extends Polymer.Element {
static get is() { return "element-property"; }
static get properties() {
return {
prop: {
type: Object,
observer: '_onProp'
}
};
}
_onProp() {
if (this.prop.name === "icon") {
this.$.moreIcon.style.display = "";
} else {
this.$.moreIcon.style.display = "none";
}
switch (this.prop.type) {
case "Boolean":
this.$.input.style.display = "none";
this.$.btn.style.display = "";
this.$.btn.checked = this.prop.value;
break;
case "Number":
this.$.input.style.display = "";
this.$.btn.style.display = "none";
this.$.input.type = "number";
this.$.input.value = this.prop.value;
break;
default:
this.$.input.style.display = "";
this.$.btn.style.display = "none";
this.$.input.type = "text";
this.$.input.value = this.prop.value;
break;
}
}
_onChange(event) {
if (event) {
event.stopPropagation();
}
var detail = {
name: this.prop.name,
value: (this.prop.type === "Boolean") ? this.$.btn.checked : this.$.input.value
}
const e = new CustomEvent('change', { bubbles: true, composed: true, detail: detail });
this.dispatchEvent(e);
}
_onMore() {
const e = new CustomEvent('icon-picker', { bubbles: true, composed: true, detail: {} });
this.dispatchEvent(e);
}
set value(v) {
this.$.input.value = v;
this._onChange();
}
}
customElements.define(ElementProperty.is, ElementProperty);
</script>
</dom-module>
================================================
FILE: src/element-view/element-stuff-base.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<script>
(function () {
window.ElementStuffBase = function (base) {
return class extends base {
ready() {
super.ready();
this._recomputeStuff();
this.root.addEventListener('change', this._do.bind(this));
}
_recomputeStuff() {
this._stuff = [];
let els = this.root.querySelectorAll('[name]');
for (let i = 0; i < els.length; i++) {
this._stuff.push(els[i].name);
}
}
_do(event) {
let target = event.target;
// Is it a custom thing?
if (target.classList.contains('style-label')) {
// Set the name on the next input
target.nextElementSibling.name = target.value;
this._recomputeStuff();
return;
}
Polymer.Base.fire('element-updated',
{
type: this.stuffType,
name: target.name,
value: target.value,
isAttribute: target.classList.contains('attribute')
}, { node: this });
}
}
}
})();
</script>
================================================
FILE: src/element-view/element-stuff-flex.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="element-stuff-base.html">
<link rel="import" href="element-stuff-shared-styles.html">
<dom-module id="element-stuff-flex">
<template>
<style include="element-stuff-shared-styles"></style>
<div class="content-wrapper">
<label>position</label>
<select name="position">
<option>static</option>
<option>absolute</option>
<option>relative</option>
</select>
<label>display</label>
<select name="display">
<option>block</option>
<option>inline-block</option>
<option>flex</option>
<option>contents</option>
<option>grid</option>
<option>inherit</option>
<option>initial</option>
<option>none</option>
</select>
<label>flex-direction</label>
<select name="flexDirection">
<option>row</option>
<option>row-reverse</option>
<option selected>column</option>
<option>column-reverse</option>
</select>
<label>flex-wrap</label>
<select name="flexWrap">
<option selected>nowrap</option>
<option>wrap</option>
<option>wrap-reverse</option>
</select>
<label>justify-content</label>
<select name="justifyContent">
<option selected>flex-start</option>
<option>flex-end</option>
<option>center</option>
<option>space-between</option>
<option>space-around</option>
</select>
<label>align-items</label>
<select name="alignItems">
<option selected>flex-start</option>
<option>flex-end</option>
<option>center</option>
<option>baseline</option>
<option>stretch</option>
</select>
<label>align-content</label>
<select name="alignContent">
<option selected>flex-start</option>
<option>flex-end</option>
<option>center</option>
<option>space-between</option>
<option>space-around</option>
<option>stretch</option>
</select>
<label>align-self</label>
<select name="alignSelf">
<option selected>auto</option>
<option>flex-start</option>
<option>flex-end</option>
<option>center</option>
<option>baseline</option>
<option>stretch</option>
</select>
<label>flex</label><input name="flex">
</div>
</template>
<script>
class ElementFlex extends ElementStuffBase(Polymer.Element) {
static get is() { return 'element-stuff-flex'; }
constructor() {
super();
this.stuffType = 'style';
}
display(elementStyles) {
for (let i = 0; i < this._stuff.length; i++) {
let name = this._stuff[i];
let el = this.root.querySelector(`[name=${name}]`);
el.value = elementStyles[name];
}
}
}
customElements.define(ElementFlex.is, ElementFlex);
</script>
</dom-module>
================================================
FILE: src/element-view/element-stuff-shared-styles.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<dom-module id="element-stuff-shared-styles">
<template>
<style>
:host {
display: block;
height: 100%;
overflow: auto;
box-sizing: border-box;
}
.content-wrapper {
padding: .5em;
}
label,
input,
select {
display: inline-block;
color: white;
background: transparent;
height: 24px;
margin: 2px 0;
padding: 0 2px 0 4px;
width: 110px;
}
label,
.style-label {
box-sizing: border-box;
display: inline-block;
margin-right: 20px;
font-size: 13px;
width: 90px;
}
input,
select {
border: 1px solid var(--input-border-color);
border-radius: 5px;
box-sizing: border-box;
font-size: 11px;
}
input {
margin-left: 4px;
}
input[disabled] {
color: #BDBDBD;
}
select {
background: transparent;
}
select:focus option {
color: black;
}
paper-toggle-button {
--paper-toggle-button-checked-bar-color: #4caf50;
--paper-toggle-button-checked-button-color: #4caf50;
--paper-toggle-button-checked-ink-color: #4caf50;
}
</style>
</template>
</dom-module>
================================================
FILE: src/element-view/element-stuff-styles.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="element-stuff-base.html">
<link rel="import" href="element-stuff-shared-styles.html">
<dom-module id="element-stuff-styles">
<template strip-whitespace>
<style include="element-stuff-shared-styles">
button.add {
display: inline-block;
background: transparent;
border: none;
padding: 4px 10px;
font-size: 12px;
letter-spacing: 1px;
font-weight: 500;
text-decoration: none;
text-transform: uppercase;
line-height: 1.5;
color: white;
background: #232733;
margin-top: 4px;
}
</style>
<div class="content-wrapper">
<label>color</label><input name="color" type="color"><br>
<label>background</label><input name="backgroundColor" type="color">
<label>font family</label><input name="fontFamily">
<label>font size</label><input name="fontSize">
<label>opacity</label><input name="opacity" type="text" min="0" max="1" step="0.1" value="1">
<label>padding</label><input name="padding">
<label>margin</label><input name="margin">
<label>position</label>
<select name="position">
<option>static</option>
<option>absolute</option>
<option>relative</option>
</select>
<label>left</label><input name="left">
<label>top</label><input name="top">
<label>width</label><input name="width">
<label>height</label><input name="height">
<div id="bonus"></div>
<button class="add" on-click="addStyle">+ Add style</button>
</div>
</template>
<script>
class ElementStyles extends ElementStuffBase(Polymer.Element) {
static get is() { return 'element-stuff-styles'; }
constructor() {
super();
this.stuffType = 'style';
}
display(elementStyles, selectedElement) {
for (let i = 0; i < this._stuff.length; i++) {
let name = this._stuff[i];
if (!elementStyles[name])
continue;
let el = this.root.querySelector(`[name=${name}]`);
if (name === 'backgroundColor' || name === 'color') {
el.value = this._rgb2hex(elementStyles[name]);
} else if (name === 'width' || name === 'height') {
// For width or height, the computedStyle gives us exact pixels
// rather than % positioning.
el.value = selectedElement.style[name];
} else {
el.value = elementStyles[name];
}
}
}
addStyle(event) {
let label = document.createElement('input');
label.className = 'style-label';
let input = document.createElement('input');
input.className = 'style-value';
this.$.bonus.appendChild(label);
this.$.bonus.appendChild(input);
}
_rgb2hex(rgb) {
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? "#" +
("0" + parseInt(rgb[1], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2], 10).toString(16)).slice(-2) +
("0" + parseInt(rgb[3], 10).toString(16)).slice(-2) : '';
}
}
customElements.define(ElementStyles.is, ElementStyles);
</script>
</dom-module>
================================================
FILE: src/element-view/element-view.html
================================================
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../components/designer-tabs.html">
<link rel="import" href="../components/designer-tab.html">
<link rel="import" href="element-stuff-styles.html">
<link rel="import" href="element-properties.html">
<dom-module id="element-view">
<template>
<style>
:host {
display: block;
}
iron-pages {
overflow: hidden;
height: 300px;
background: var(--medium-grey);
color: white;
}
</style>
<designer-tabs attr-for-selected="name" selected="{{selected}}">
<designer-tab name="properties">
<button>Properties</button>
</designer-tab>
<designer-tab name="styles">
<button>styles</button>
</designer-tab>
</designer-tabs>
<iron-pages attr-for-selected="name" selected-attribute="visible" selected="[[selected]]">
<element-properties name="properties" id="propertiesContainer"></element-properties>
<element-stuff-styles name="styles" id="stylesContainer"></element-stuff-styles>
</iron-pages>
</template>
<script>
class ElementView extends Polymer.Element {
static get is() { return 'element-view'; }
static get properties() {
return {
selected: {
type: String,
value: 'properties'
}
}
}
/**
* Updates the views.
*/
display(el, info) {
let computedStyle = window.getComputedStyle(el);
this.$.propertiesContainer.display(el, info);
this.$.stylesContainer.display(computedStyle, el);
}
displayPosition(top, left) {
this.$.stylesContainer.display({ top: top + 'px', left: left + 'px' });
}
}
customElements.define(ElementView.is, ElementView);
</script>
</dom-module>
================================================
FILE: src/palette/palette-list.html
================================================
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-repeat.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="palette-shared-styles.html">
<dom-module id="palette-list">
<template strip-whitespace>
<style include="palette-shared-styles iron-flex iron-flex-alignment">
.buttonTag {
font-style: italic;
color: var(--highlight-blue);
font-size: 95%;
}
</style>
<dom-repeat items="[[elements]]">
<template>
<button on-click="_doClick">[[item.label]] <span class="buttonTag"><[[item.name]]></span></button>
</template>
</dom-repeat>
<iron-ajax auto url="[[src]]" handle-as="json" on-response="_elementsReady"></iron-ajax>
</template>
<script>
class PaletteList extends Polymer.Element {
static get is() { return 'palette-list' }
static get properties() {
return {
src: String,
elements: { type: Array }
}
}
constructor() {
super();
this._elementMap = {};
}
getElementInfo(tag) {
return this._elementMap[tag];
}
_elementsReady(event) {
let list = event.detail.response.elements;
list.sort((a, b) => {
let na = a.label.toUpperCase();
let nb = b.label.toUpperCase();
if (na < nb) return -1;
if (na > nb) return 1;
return 0;
});
this._elementMap = {};
for (var i = 0; i < list.length; i++) {
this._elementMap[list[i].name] = list[i];
}
this.elements = list;
}
_doClick(event) {
let item = event.model.item;
let target = event.currentTarget;
if (item.native) {
setTimeout(() => {
if (target && target.blur) {
target.blur();
}
setTimeout(() => {
const event = new CustomEvent('new-element', { bubbles: true, composed: true, detail: item });
this.dispatchEvent(event);
})
});
} else {
let kind = item.name;
let matches = kind.match(/(.*)\/(.*)/);
let packageName = kind;
if (matches && matches.length === 3) {
packageName = matches[1];
kind = matches[2];
}
let url = this.resolveUrl('../../bower_components/' + packageName + "/" + kind + ".html");
Polymer.importHref(url, () => {
setTimeout(() => {
if (target && target.blur) {
target.blur();
}
setTimeout(() => {
const event = new CustomEvent('new-element', { bubbles: true, composed: true, detail: item });
this.dispatchEvent(event);
})
});
});
}
}
}
window.customElements.define(PaletteList.is, PaletteList);
</script>
</dom-module>
================================================
FILE: src/palette/palette-shared-styles.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<dom-module id="palette-shared-styles">
<template>
<style>
:host {
display: block;
box-sizing: border-box;
height: 100%;
overflow: auto;
}
button {
background: transparent;
color: white;
border: none;
font-size: 13px;
display: block;
cursor: pointer;
width: 100%;
text-align: left;
padding: 8px 14px;
}
button:hover {
background: var(--light-grey);
}
div {
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
padding: 4px 14px;
}
input {
display: block;
background: none;
border: none;
color: white;
font-size: 16px;
margin: 10px;
border-bottom: 1px solid white;
width: 90%;
}
::-webkit-input-placeholder {
color: white;
font-weight: 100;
font-size: 14px;
}
::-moz-placeholder {
color: white;
font-weight: 100;
font-size: 14px;
}
:-ms-input-placeholder {
color: white;
font-weight: 100;
font-size: 14px;
}
:-moz-placeholder {
color: white;
font-weight: 100;
font-size: 14px;
}
</style>
</template>
</dom-module>
================================================
FILE: src/palette/palette-view.html
================================================
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../components/designer-tabs.html">
<link rel="import" href="../components/designer-tab.html">
<link rel="import" href="palette-list.html">
<dom-module id="palette-view">
<template>
<style>
:host {
display: flex;
flex-direction: column;
flex: 1;
}
iron-pages {
flex: 1;
overflow: hidden;
padding-bottom: 20px;
background: var(--medium-grey);
color: white;
}
</style>
<designer-tabs attr-for-selected="name" selected="{{selected}}">
<designer-tab name="wired">
<button>Elements</button>
</designer-tab>
<!-- <designer-tab name="native">
<button>Native</button>
</designer-tab> -->
</designer-tabs>
<iron-pages selected="[[selected]]" attr-for-selected="name" selected-attribute="visible">
<palette-list id="wired" name="wired" src="elements.json"></palette-list>
</iron-pages>
</template>
<script>
class PaletteView extends Polymer.Element {
static get is() { return 'palette-view'; }
static get properties() {
return {
selected: {
type: String,
value: 'wired'
}
}
}
getElementInfo(el) {
let tag = el.tagName.toLowerCase();
return this.$.wired.getElementInfo(tag);
}
}
customElements.define(PaletteView.is, PaletteView);
</script>
</dom-module>
================================================
FILE: src/the-app.html
================================================
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="components/designer-tab.html">
<link rel="import" href="components/designer-tabs.html">
<link rel="import" href="components/tree-view.html">
<link rel="import" href="element-view/element-view.html">
<link rel="import" href="palette/palette-view.html">
<link rel="import" href="canvas/canvas-view.html">
<link rel="import" href="canvas/canvas-controls.html">
<link rel="import" href="action-history.html">
<link rel="import" href="app-controls.html">
<dom-module id="the-app">
<template>
<style is="custom-style" include="iron-flex iron-flex-alignment">
:host {
display: block;
box-sizing: border-box;
position: relative;
--canvas-background: white;
--almost-black: #141720;
--dark-grey: #232733;
--medium-grey: #2f3545;
--light-grey: #383f52;
--highlight-pink: #e91e63;
--highlight-blue: #2196f3;
--input-border-color: #596c7a;
}
#shell {
height: 100vh;
overflow: hidden;
}
#toolbar {
padding: 0 16px;
background-color: var(--almost-black);
color: white;
height: 60px;
font-size: 20px;
}
.heavy {
font-weight: 900;
letter-spacing: 2px;
}
.lite {
font-weight: 100;
opacity: 0.5;
letter-spacing: normal;
}
button {
background: transparent;
color: white;
border: none;
cursor: pointer;
}
button[disabled] {
pointer-events: none;
opacity: 0.3;
}
.drawer {
min-width: 270px;
width: 270px;
height: 100%;
overflow: hidden;
background: var(--medium-grey);
color: white;
display: flex;
flex-direction: column;
}
.grid {
background-color: var(--canvas-background);
/* 10px grid, using http://www.patternify.com/ */
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAIElEQVQoU2NkYGBIY2BgmMVAADASUgCTH1WIN6SIDh4AnhABC01te2MAAAAASUVORK5CYII=);
background-position: 0px 0px;
}
.gridPanel {
background: var(--dark-grey);
white-space: nowrap;
padding: 0;
color: white;
}
.gridPanel label {
font-size: 12px;
letter-spacing: 1px;
font-weight: 500;
text-decoration: none;
text-transform: uppercase;
line-height: 1.5;
margin-right: 5px;
}
paper-toggle-button {
--paper-toggle-button-checked-bar-color: #4caf50;
--paper-toggle-button-checked-button-color: #4caf50;
--paper-toggle-button-checked-ink-color: #4caf50;
--paper-toggle-button-unchecked-bar-color: #c73e65;
--paper-toggle-button-unchecked-button-color: #c73e65;
--paper-toggle-button-unchecked-ink-color: #c73e65;
}
designer-tab.single {
color: white;
background: var(--dark-grey);
width: 100%;
height: 41px;
margin: 0;
padding: 0;
border: none;
}
iron-pages {
height: 100%;
overflow: auto;
position: relative;
}
tree-view {
overflow: auto;
}
.logo {
display: block;
height: 44px;
width: auto;
border-radius: 100%;
margin-right: 10px;
margin-left: -5px;
}
a,
a:visited,
a:hover {
outline: none;
text-decoration: none;
cursor: pointer;
color: inherit !important;
}
#mobilePanel {
display: none;
background: var(--medium-grey);
color: white;
padding: 20px;
}
#mobilePanel h2 {
font-weight: 400;
}
#mobilePanel a {
background: var(--highlight-pink);
color: white !important;
display: inline-block;
padding: 5px 6px;
border-radius: 3px;
}
@media (max-width: 800px) {
#mainPanel {
display: none;
}
#appControls {
display: none;
}
#mobilePanel {
display: initial;
}
}
</style>
<action-history id="actionHistory"></action-history>
<div id="shell" class="vertical layout">
<div id="toolbar" class="horizontal layout center">
<a href="https://github.com/wiredjs/designer" target="_blank"><img class="logo" src$="[[importPath]]../images/logo100.png"></a>
<span class="heavy flex">
<a href="https://github.com/wiredjs/designer" target="_blank">wired designer<span class="lite"> // beta</span></a>
</span>
<app-controls id="appControls"></app-controls>
</div>
<div id="mainPanel" class="flex horizontal layout">
<div id="ldrawer" class="drawer">
<designer-tab class="single"><button>Components</button></designer-tab>
<canvas-controls id="canvasControls"></canvas-controls>
<tree-view name="tree" id="treeView"></tree-view>
</div>
<div id="mainView" class="flex vertical layout">
<div class="horizontal layout" style="box-sizing: border-box;">
<designer-tabs attr-for-selected="name" selected="{{mainPage}}" class="flex" style="width: auto;">
<designer-tab name="designer">
<button>Designer</button>
</designer-tab>
</designer-tabs>
<div class="gridPanel horizontal layout center">
<label>Show grid</label>
<paper-toggle-button id="gridToggle" on-change="_onGridToggle"></paper-toggle-button>
</div>
</div>
<iron-pages class="flex" selected="[[mainPage]]" attr-for-selected="name" selected-attribute="visible">
<canvas-view name="designer" id="viewContainer" style="height:100%"></canvas-view>
</iron-pages>
</div>
<div class="drawer">
<element-view id="elementView"></element-view>
<palette-view id="paletteView"></palette-view>
</div>
</div>
<div id="mobilePanel" class="flex">
<h2>Wired designer is a desktop only app. Sorry :(</h2>
<p>
It's a mockups and wireframing tool built using web components, and is open source.
</p>
<p>
<a href="https://github.com/wiredjs/designer">View on github</a>
</p>
</div>
</div>
</template>
<script>
class TheApp extends Polymer.Element {
static get is() { return 'the-app'; }
static get properties() {
return {
activeElement: {
type: Object
},
mainPage: {
type: String,
value: 'designer'
}
};
}
connectedCallback() {
super.connectedCallback();
this.setActiveElement(this.$.viewContainer);
this._loadGridState()
this.refreshView();
this.$.canvasControls.actionHistory = this.$.actionHistory;
this.$.canvasControls.canvasElement = this.$.viewContainer;
this.$.appControls.actionHistory = this.$.actionHistory;
this.$.viewContainer.actionHistory = this.$.actionHistory;
this.addEventListener('new-element', event => this.createElement(event));
this.addEventListener('element-updated', event => this.updateElement(event));
this.addEventListener('refresh-view', event => this.refreshView(event));
this.addEventListener('selected-element-changed', event => {
this.setActiveElement(event.detail.target);
});
this.addEventListener('finish-clone', event => {
this._finishCloneElement(event.detail.target);
});
this.addEventListener('update-action-buttons', event => {
this.$.appControls.update(event.detail.undos, event.detail.redos);
});
this.addEventListener('remove-from-canvas', event => {
const parent = event.detail.parent;
const node = event.detail.target;
if (parent === this.$.viewContainer) {
this.$.viewContainer.remove(node);
} else {
parent.removeChild(node);
}
parent.click();
});
this.addEventListener('add-to-canvas', event => {
const parent = event.detail.parent;
const node = event.detail.target;
if (parent === this.$.viewContainer) {
this.$.viewContainer.add(node);
} else {
parent.appendChild(node);
}
node.click();
});
this.addEventListener('move', event => {
this.$.canvasControls.move(event.detail.type, event.detail.skipHistory);
});
}
setActiveElement(el) {
if (el === this) {
el = this.$.viewContainer;
}
if (this.activeElement) {
this.activeElement.classList.remove('active');
this.activeElement.classList.remove('active-resizable');
}
el.classList.add('active');
if (el.getAttribute("data-noresize") != "true") {
el.classList.add('active-resizable');
}
// Tell everyone who cares about this.
this.$.canvasControls.selectedElement =
this.$.viewContainer.selectedElement = this.activeElement = el;
this.$.canvasControls.selectedElement = this.activeElement;
this.$.canvasControls.update(this.activeElement === this.$.viewContainer);
}
createElement(event) {
let tag = event.detail.name.toLowerCase();
let el = document.createElement(tag);
this.$.viewContainer.add(el);
// If we haven't before, save this initial state of a <tag> element,
// so that we can diff it to produce the actual state of the world
// codeView.save(tag, event.detail.package, el);
this.$.actionHistory.add('new', el, { parent: el.parentNode });
this._finishNewElement2(el, event.detail);
// You need the item to render first.
requestAnimationFrame(function () {
el.click();
});
}
refreshView(event) {
if (event && event.detail.whileTracking) {
let size = this.activeElement.getBoundingClientRect();
this.$.elementView.displayPosition(size.top, size.left);
return;
}
let el = this.activeElement ? this.activeElement : this.$.viewContainer;
// Display its properties in the side view.
this.$.elementView.display(el, this.$.paletteView.getElementInfo(el));
// Highlight it in the tree.
this.$.treeView.recomputeTree(this.$.viewContainer, el);
}
updateElement(event) {
let detail = event.detail;
let oldValue = this.updateActiveElementValues(detail.type, detail.name, detail.value, detail.isAttribute);
if (this.activeElement) {
rewire(this.activeElement);
}
if (detail.skipHistory) {
return;
}
this.$.actionHistory.add('update', this.activeElement,
{
type: detail.type, name: detail.name,
new: { value: detail.value },
old: { value: oldValue }
});
}
updateActiveElementValues(type, name, value, isAttribute) {
let previousValue;
if (type === 'style') {
// If we switch to flexbox, automatically reposition the children
if (name === 'display' && value === 'flex') {
let children = this.activeElement.children;
for (let i = 0; i < children.length; i++) {
children[i].style.position = 'relative';
children[i].style.top = children[i].style.left = 'auto';
}
}
previousValue = this.activeElement.style[name];
this.activeElement.style[name] = value;
} else {
previousValue = this.activeElement[name];
// If this is a dom-repeat, don't set the items attribute, set a fake
// items instead (so that it doesn't stamp).
if (this.activeElement.localName === 'dom-repeat' && name === 'items') {
this.activeElement.dataset['fakeItemsAttr'] = value;
} else if (value === 'true') {
this._setPropertyOrValue(name, true, isAttribute);
} else if (value === 'false') {
if (this.activeElement.hasAttribute(name)) {
this.activeElement.removeAttribute(name);
} else {
this._setPropertyOrValue(name, false, isAttribute);
}
} else {
this._setPropertyOrValue(name, value, isAttribute);
}
}
this.$.treeView.recomputeTree(this.$.viewContainer, this.activeElement);
return previousValue;
}
_setPropertyOrValue(name, value, isAttribute) {
if (isAttribute) {
this.activeElement.setAttribute(name, value);
} else {
this.activeElement[name] = value;
}
}
_finishNewElement2(el, item) {
if (item.properties && item.properties.length) {
for (var i = 0; i < item.properties.length; i++) {
el[item.properties[i].name] = item.properties[i].value
}
}
el.style.boxSizing = 'border-box';
el.style.position = 'absolute';
el.style.left = el.style.top = '20px';
if (item.styles && item.styles.length) {
for (var i = 0; i < item.styles.length; i++) {
el.style[item.styles[i].name] = item.styles[i].value
}
}
if (item.textContent) {
el.textContent = item.textContent;
}
if (item.disableSizing) {
el.setAttribute("data-noresize", "true")
}
}
_finishCloneElement(el) {
el.style.boxSizing = 'border-box';
el.style.position = 'absolute';
el.style.left = el.style.top = '20px';
}
_makeUniqueId(node, id, suffix) {
id = id.replace('-', '_');
let uId = id + (suffix || '');
return this.$.viewContainer.has('#' + uId) ?
this._makeUniqueId(node, id, suffix ? ++suffix : 1) : uId;
}
_loadGridState() {
var showGrid = true;
if (localStorage) {
if (localStorage.getItem("hideGrid") === "true") {
showGrid = false;
}
}
this.$.gridToggle.checked = showGrid;
this.$.viewContainer.grid = showGrid;
}
_onGridToggle() {
this.$.viewContainer.grid = this.$.gridToggle.checked;
if (localStorage) {
localStorage.setItem('hideGrid', this.$.gridToggle.checked ? "false" : "true");
}
}
}
window.customElements.define(TheApp.is, TheApp);
</script>
</dom-module>
================================================
FILE: test/the-app/the-app_test.html
================================================
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
<title>the-app test</title>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../src/the-app/the-app.html">
</head>
<body>
<test-fixture id="BasicTestFixture">
<template>
<the-app></the-app>
</template>
</test-fixture>
<test-fixture id="ChangedPropertyTestFixture">
<template>
<the-app prop1="new-prop1"></the-app>
</template>
</test-fixture>
<script>
suite('the-app', function () {
test('instantiating the element with default properties works', function () {
var element = fixture('BasicTestFixture');
assert.equal(element.prop1, 'the-app');
var elementShadowRoot = element.shadowRoot;
var elementHeader = elementShadowRoot.querySelector('h2');
assert.equal(elementHeader.innerHTML, 'Hello the-app!');
});
test('setting a property on the element works', function () {
// Create a test fixture
var element = fixture('ChangedPropertyTestFixture');
assert.equal(element.prop1, 'new-prop1');
var elementShadowRoot = element.shadowRoot;
var elementHeader = elementShadowRoot.querySelector('h2');
assert.equal(elementHeader.innerHTML, 'Hello new-prop1!');
});
});
</script>
</body>
</html>
gitextract_kz5tdmj3/
├── .gitignore
├── LICENSE
├── README.md
├── bower.json
├── deploy-to-pages.sh
├── elements.json
├── index.html
├── manifest.json
├── polymer.json
├── src/
│ ├── action-history.html
│ ├── app-controls.html
│ ├── app-icons.html
│ ├── app.js
│ ├── canvas/
│ │ ├── canvas-controls.html
│ │ └── canvas-view.html
│ ├── components/
│ │ ├── designer-tab.html
│ │ ├── designer-tabs.html
│ │ ├── icon-picker.html
│ │ └── tree-view.html
│ ├── element-view/
│ │ ├── element-properties.html
│ │ ├── element-property.html
│ │ ├── element-stuff-base.html
│ │ ├── element-stuff-flex.html
│ │ ├── element-stuff-shared-styles.html
│ │ ├── element-stuff-styles.html
│ │ └── element-view.html
│ ├── palette/
│ │ ├── palette-list.html
│ │ ├── palette-shared-styles.html
│ │ └── palette-view.html
│ └── the-app.html
└── test/
└── the-app/
└── the-app_test.html
SYMBOL INDEX (4 symbols across 1 files)
FILE: src/app.js
function getProtoProperties (line 17) | function getProtoProperties(target) {
function getAttributesIfCustomElement (line 86) | function getAttributesIfCustomElement(target) {
function getCustomProperties (line 94) | function getCustomProperties(target) {
function rewire (line 123) | function rewire(el) {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (114K chars).
[
{
"path": ".gitignore",
"chars": 26,
"preview": "bower_components\ndesigner\n"
},
{
"path": "LICENSE",
"chars": 1511,
"preview": "BSD 3-Clause License\n\nCopyright (c) 2017, Preet Shihn\nAll rights reserved.\n\nRedistribution and use in source and binary "
},
{
"path": "README.md",
"chars": 761,
"preview": "# Wired Designer \n\nThis is a very simple wysiwyg style designer for createing mockups and wireframes.\n\n[Launch designer]"
},
{
"path": "bower.json",
"chars": 601,
"preview": "{\n \"name\": \"wired-designer\",\n \"description\": \"Mockups and wireframing tool built using web components, and is open sou"
},
{
"path": "deploy-to-pages.sh",
"chars": 950,
"preview": "#!/bin/bash -e\n\n# Based on https://github.com/Polymer/tools/blob/master/bin/gp.sh\n\n# This script pushes a demo-friendly "
},
{
"path": "elements.json",
"chars": 3268,
"preview": "{\n \"elements\": [\n {\n \"name\": \"wired-card\",\n \"label\": \"Card (Container)\",\n \"styles\": [\n {\n "
},
{
"path": "index.html",
"chars": 1898,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, m"
},
{
"path": "manifest.json",
"chars": 148,
"preview": "{\n \"name\": \"wywiwyg\",\n \"short_name\": \"wywiwyg\",\n \"description\": \"What you wire is what you get\",\n \"start_url\": \"/\",\n"
},
{
"path": "polymer.json",
"chars": 59,
"preview": "{\n \"lint\": {\n \"rules\": [\n \"polymer-2\"\n ]\n }\n}\n"
},
{
"path": "src/action-history.html",
"chars": 6994,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/app-controls.html",
"chars": 2608,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/app-icons.html",
"chars": 2615,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/app.js",
"chars": 4510,
"preview": "/*\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BS"
},
{
"path": "src/canvas/canvas-controls.html",
"chars": 10569,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/canvas/canvas-view.html",
"chars": 15950,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/components/designer-tab.html",
"chars": 1797,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/components/designer-tabs.html",
"chars": 1324,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/components/icon-picker.html",
"chars": 3118,
"preview": "<link rel=\"import\" href=\"../../bower_components/polymer/polymer-element.html\">\n<link rel=\"import\" href=\"../../bower_comp"
},
{
"path": "src/components/tree-view.html",
"chars": 5454,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/element-view/element-properties.html",
"chars": 3806,
"preview": "<link rel=\"import\" href=\"../../bower_components/polymer/polymer-element.html\">\n<link rel=\"import\" href=\"../../bower_comp"
},
{
"path": "src/element-view/element-property.html",
"chars": 2652,
"preview": "<link rel=\"import\" href=\"../../bower_components/paper-toggle-button/paper-toggle-button.html\">\n\n<dom-module id=\"element-"
},
{
"path": "src/element-view/element-stuff-base.html",
"chars": 1638,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/element-view/element-stuff-flex.html",
"chars": 3529,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/element-view/element-stuff-shared-styles.html",
"chars": 1831,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/element-view/element-stuff-styles.html",
"chars": 3882,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/element-view/element-view.html",
"chars": 1948,
"preview": "<link rel=\"import\" href=\"../../bower_components/polymer/polymer-element.html\">\n<link rel=\"import\" href=\"../../bower_comp"
},
{
"path": "src/palette/palette-list.html",
"chars": 3061,
"preview": "<link rel=\"import\" href=\"../../bower_components/polymer/polymer-element.html\">\n<link rel=\"import\" href=\"../../bower_comp"
},
{
"path": "src/palette/palette-shared-styles.html",
"chars": 1873,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/palette/palette-view.html",
"chars": 2125,
"preview": "<!--\n@license\nCopyright (c) 2017 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the "
},
{
"path": "src/the-app.html",
"chars": 15211,
"preview": "<link rel=\"import\" href=\"../bower_components/polymer/polymer-element.html\">\n<link rel=\"import\" href=\"../bower_components"
},
{
"path": "test/the-app/the-app_test.html",
"chars": 1553,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, m"
}
]
About this extraction
This page contains the full source code of the wiredjs/designer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (104.8 KB), approximately 26.7k tokens, and a symbol index with 4 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.