├── .gitattributes ├── Demos ├── .DS_Store ├── FAB.framer │ ├── .gitignore │ ├── app.coffee │ ├── framer │ │ ├── .bookmark │ │ ├── coffee-script.js │ │ ├── config.json │ │ ├── design.vekter │ │ ├── framer.generated.js │ │ ├── framer.init.js │ │ ├── framer.js │ │ ├── framer.js.map │ │ ├── framer.modules.js │ │ ├── framer.vekter.js │ │ ├── images │ │ │ ├── cursor-active.png │ │ │ ├── cursor-active@2x.png │ │ │ ├── cursor.png │ │ │ ├── cursor@2x.png │ │ │ ├── icon-120.png │ │ │ ├── icon-152.png │ │ │ ├── icon-180.png │ │ │ ├── icon-192.png │ │ │ └── icon-76.png │ │ ├── style.css │ │ └── version │ ├── images │ │ └── .gitkeep │ ├── index.html │ └── modules │ │ └── MaterialComponents.coffee ├── Form.framer │ ├── .gitignore │ ├── app.coffee │ ├── framer │ │ ├── .bookmark │ │ ├── coffee-script.js │ │ ├── config.json │ │ ├── design.vekter │ │ ├── framer.generated.js │ │ ├── framer.init.js │ │ ├── framer.js │ │ ├── framer.js.map │ │ ├── framer.modules.js │ │ ├── framer.vekter.js │ │ ├── images │ │ │ ├── cursor-active.png │ │ │ ├── cursor-active@2x.png │ │ │ ├── cursor.png │ │ │ ├── cursor@2x.png │ │ │ ├── icon-120.png │ │ │ ├── icon-152.png │ │ │ ├── icon-180.png │ │ │ ├── icon-192.png │ │ │ └── icon-76.png │ │ ├── style.css │ │ └── version │ ├── images │ │ └── .gitkeep │ ├── index.html │ └── modules │ │ └── MaterialComponents.coffee └── Register.framer │ ├── .gitignore │ ├── app.coffee │ ├── framer │ ├── .bookmark │ ├── coffee-script.js │ ├── config.json │ ├── design.vekter │ ├── framer.generated.js │ ├── framer.init.js │ ├── framer.js │ ├── framer.js.map │ ├── framer.modules.js │ ├── framer.vekter.js │ ├── images │ │ ├── cursor-active.png │ │ ├── cursor-active@2x.png │ │ ├── cursor.png │ │ ├── cursor@2x.png │ │ ├── icon-120.png │ │ ├── icon-152.png │ │ ├── icon-180.png │ │ ├── icon-192.png │ │ └── icon-76.png │ ├── style.css │ └── version │ ├── images │ └── .gitkeep │ ├── index.html │ └── modules │ └── MaterialComponents.coffee ├── MaterialComponents.coffee └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /Demos/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/.DS_Store -------------------------------------------------------------------------------- /Demos/FAB.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /Demos/FAB.framer/app.coffee: -------------------------------------------------------------------------------- 1 | MaterialComponents = require 'MaterialComponents' 2 | 3 | bg = new BackgroundLayer 4 | backgroundColor: MaterialComponents.white 5 | 6 | header = new MaterialComponents.AppBar 7 | mobile: true 8 | themeColor: MaterialComponents.purple 9 | menuIconY: Align.center(-5) 10 | statusIconsY: Align.center(-3) 11 | 12 | fab = new MaterialComponents.FAB 13 | themeColor: MaterialComponents.purple 14 | icon: "share" 15 | -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/.bookmark -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 640, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 384, 8 | "fullScreen" : false, 9 | "deviceType" : "google-nexus-4", 10 | "sharedPrototype" : 0, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "5CB87C70-76A7-48D0-AA4D-EF7B002CD5ED", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : false, 18 | "foldedCodeRanges" : [ 19 | 20 | ], 21 | "deviceScale" : "fit" 22 | } -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/design.vekter: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 12, 3 | "root" : { 4 | "id" : "F@zUO{bk", 5 | "__class" : "CanvasNode", 6 | "parentid" : null, 7 | "children" : [ 8 | 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-4","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-4","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"FAB.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Demos/FAB.framer/framer/version: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /Demos/FAB.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/FAB.framer/images/.gitkeep -------------------------------------------------------------------------------- /Demos/FAB.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Demos/Form.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /Demos/Form.framer/app.coffee: -------------------------------------------------------------------------------- 1 | MaterialComponents = require 'MaterialComponents' 2 | 3 | padding = 32 4 | 5 | 6 | 7 | scroll = new ScrollComponent 8 | width: Screen.width 9 | height: Screen.height 10 | backgroundColor: "#fff" 11 | scrollHorizontal: false 12 | 13 | head = new MaterialComponents.AppBar 14 | themeColor: MaterialComponents.indigo 15 | labelText: "Survey" 16 | mobile: true 17 | statusIconsY: Align.center() 18 | menuIconY: Align.center(-1) 19 | 20 | field1 = new MaterialComponents.TextField_Basic 21 | x: padding 22 | y: padding + head.height 23 | width: 300 24 | labelText: "Name" 25 | themeColor: MaterialComponents.indigo 26 | parent: scroll.content 27 | 28 | field2 = new MaterialComponents.RadioButtons 29 | x: padding 30 | y: padding + field1.height + field1.y 31 | width: 300 32 | labelText: "Did you like the event?" 33 | themeColor: MaterialComponents.indigo 34 | type: "password" 35 | choices: ["yes", "it was 'ok'", "no"] 36 | parent: scroll.content 37 | 38 | 39 | field3 = new MaterialComponents.Checkboxes 40 | x: padding 41 | y: padding + field2.height + field2.y 42 | width: 300 43 | labelText: "What did you like" 44 | themeColor: MaterialComponents.indigo 45 | type: "password" 46 | parent: scroll.content 47 | choices: ["the bar", "pony rides", "jumping castles", "music"] 48 | checkY: 4 49 | 50 | field4 = new MaterialComponents.TextArea 51 | x: padding 52 | y: padding + field3.height + field3.y 53 | width: 300 54 | labelText: "Comments" 55 | themeColor: MaterialComponents.indigo 56 | parent: scroll.content 57 | 58 | button = new MaterialComponents.RaisedButton 59 | x: padding 60 | y: padding + field4.height + field4.y 61 | labelText: "Submit" 62 | themeColor: MaterialComponents.indigo 63 | parent: scroll.content -------------------------------------------------------------------------------- /Demos/Form.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/.bookmark -------------------------------------------------------------------------------- /Demos/Form.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 731.4285888671875, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 411.4285583496094, 8 | "fullScreen" : false, 9 | "deviceType" : "google-nexus-6p", 10 | "sharedPrototype" : true, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "77F04927-B690-49DA-AD90-15927740D705", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : 0, 18 | "foldedCodeRanges" : [ 19 | 20 | ], 21 | "deviceScale" : "fit" 22 | } -------------------------------------------------------------------------------- /Demos/Form.framer/framer/design.vekter: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 12, 3 | "root" : { 4 | "id" : "F@zUO{bk", 5 | "__class" : "CanvasNode", 6 | "parentid" : null, 7 | "children" : [ 8 | 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /Demos/Form.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-6p","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-6p","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"Form.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Demos/Form.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Demos/Form.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Demos/Form.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Demos/Form.framer/framer/version: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /Demos/Form.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Form.framer/images/.gitkeep -------------------------------------------------------------------------------- /Demos/Form.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Demos/Register.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /Demos/Register.framer/app.coffee: -------------------------------------------------------------------------------- 1 | MaterialComponents = require 'MaterialComponents' 2 | 3 | padding = 32 4 | 5 | 6 | bg = new BackgroundLayer 7 | backgroundColor : "#fff" 8 | 9 | head = new MaterialComponents.AppBar 10 | themeColor: MaterialComponents.cyan 11 | labelText: "Sign in" 12 | mobile: true 13 | head.menuIcon.y = Align.center(-12) 14 | head.statusBar.children[1].y = Align.center(-8) 15 | 16 | field1 = new MaterialComponents.TextField_Validation 17 | x: padding 18 | y: head.height + padding 19 | labelText: "email" 20 | eyeVisible: false 21 | type: "text" 22 | width: 300 23 | match: ["joe@soap.com", "jane@doe.com", "john@smith.com"] 24 | themeColor: MaterialComponents.cyan 25 | helperText: "email address not recognised" 26 | width: Screen.width - (padding * 2) 27 | 28 | 29 | field2 = new MaterialComponents.TextField_Validation 30 | x: padding 31 | y: field1.height + padding + field1.y 32 | labelText: "password" 33 | eyeVisible: false 34 | type: "text" 35 | width: 300 36 | match: ["password123", "Fido", "alpha"] 37 | themeColor: MaterialComponents.cyan 38 | helperText: "Incorrect password" 39 | width: Screen.width - (padding * 2) 40 | 41 | button = new MaterialComponents.RaisedButton 42 | themeColor: MaterialComponents.cyan 43 | x: padding 44 | y: field2.height + padding + field2.y -------------------------------------------------------------------------------- /Demos/Register.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/.bookmark -------------------------------------------------------------------------------- /Demos/Register.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 568, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 320, 8 | "fullScreen" : false, 9 | "deviceType" : "apple-iphone-5s-space-gray", 10 | "sharedPrototype" : true, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "BF41CB30-D32C-426C-99AF-6442BC39A3C5", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : 0, 18 | "foldedCodeRanges" : [ 19 | 20 | ], 21 | "deviceScale" : "fit" 22 | } -------------------------------------------------------------------------------- /Demos/Register.framer/framer/design.vekter: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 12, 3 | "root" : { 4 | "id" : "F@zUO{bk", 5 | "__class" : "CanvasNode", 6 | "parentid" : null, 7 | "children" : [ 8 | 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /Demos/Register.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-5s-space-gray","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-5s-space-gray","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"Register.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /Demos/Register.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /Demos/Register.framer/framer/framer.vekter.js: -------------------------------------------------------------------------------- 1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window); -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /Demos/Register.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /Demos/Register.framer/framer/version: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /Demos/Register.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TessGadd/MaterialComponents/fdd414a35ce5415a2c372e1a3c29783c34ca0005/Demos/Register.framer/images/.gitkeep -------------------------------------------------------------------------------- /Demos/Register.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /MaterialComponents.coffee: -------------------------------------------------------------------------------- 1 | ######################################################################################################## 2 | # MaterialComponents version 1 3 | # Made by Tess Gadd https://medium.com/@tessgadd 4 | ######################################################################################################## 5 | 6 | # This version contains 7 | # 0. global elements 8 | # 1. Color 9 | # 2. FlatButton 10 | # 3. RaisedButton 11 | # 4. FAB 12 | # 5. Checkboxes 13 | # 6. Radio Buttons 14 | # 7. Switch 15 | # 8. TextField (Text fields frankenstiend from Jordan Robert Dobson's InputField) 16 | # 9. TextField_Validation (Text fields frankenstiend from Jordan Robert Dobson's InputField) 17 | # 10. TextArea (frankenstiend from Jordan Robert Dobson's InputField and Blaine Billingsley's Autogrow) 18 | # 11. TextField_Dropdown 19 | # 12. AppBar 20 | 21 | 22 | 23 | 24 | ################################################# 0. Global Elements ################################################ 25 | #---------colors 26 | label_light = "rgba(0,0,0,0.87)" 27 | label_dark = "rgba(255,255,255,1)" 28 | line_light = "rgba(0,0,0,0.54)" 29 | line_dark = "rgba(255,255,255,0.7)" 30 | input_light = "rgba(0,0,0,0.54)" 31 | input_dark = "rgba(255,255,255,1)" 32 | Inputlabel_light = box_light = "rgba(0,0,0,0.54)" 33 | Inputlabel_dark = box_dark = "rgba(255,255,255,0.7)" 34 | line_light_hover = "rgba(0,0,0,0.87)" 35 | line_dark_hover = "rgba(255,255,255,1)" 36 | 37 | 38 | #---------textlayer---------------------------------------------------------------------------------------------------- 39 | class Label extends TextLayer 40 | constructor: (@options={}) -> 41 | 42 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 43 | 44 | @options.fontFamily ?= "'Roboto', sans serif" 45 | @options.fontSize ?= 16 46 | @options.text ?= 'Label' 47 | @options.color ?= label_light 48 | @options.fontWeight ?= 400 49 | @options.letterSpacing ?= 0 50 | @options.name ?= "label" 51 | 52 | super @options 53 | 54 | 55 | 56 | #---------shadow------------------------------------------------------------------------------------------------------ 57 | class Shadow extends Layer 58 | constructor: (@options={}) -> 59 | 60 | @options.backgroundColor ?= "" 61 | 62 | @umbra = new Layer 63 | width: @options.width 64 | height: @options.height 65 | backgroundColor: @options.themeColor 66 | borderRadius: @options.borderRadius 67 | shadowColor: "rgba(0,0,0,0.14)" 68 | name: "umbra" 69 | 70 | @umbra.states = 71 | _12dp: 72 | shadowY: 12 73 | shadowBlur: 17 74 | shadowSpread: 2 75 | _8dp: 76 | shadowY: 4 77 | shadowBlur: 15 78 | shadowSpread: 0 79 | _6dp: 80 | shadowY: 6 81 | shadowBlur: 10 82 | shadowSpread: 0 83 | _4dp: 84 | shadowY: 2 85 | shadowBlur: 4 86 | shadowSpread: 0 87 | _2dp: 88 | shadowY: 0 89 | shadowBlur: 2 90 | shadowSpread: 0 91 | _1dp: 92 | shadowY: 0 93 | shadowBlur: 2 94 | shadowSpread: 0 95 | _0dp: 96 | shadowY: 0 97 | shadowBlur: 0 98 | shadowSpread: 0 99 | 100 | @penumbra = new Layer 101 | width: @options.width 102 | height: @options.height 103 | backgroundColor: "" 104 | borderRadius: @options.borderRadius 105 | shadowColor: "rgba(0,0,0,0.12)" 106 | name: "penumbra" 107 | 108 | @penumbra.states = 109 | _12dp: 110 | shadowY: 5 111 | shadowBlur: 22 112 | shadowSpread: 4 113 | _8dp: 114 | shadowY: 3 115 | shadowBlur: 14 116 | shadowSpread: 3 117 | _6dp: 118 | shadowY: 1 119 | shadowBlur: 18 120 | shadowSpread: 0 121 | _4dp: 122 | shadowY: 4 123 | shadowBlur: 5 124 | shadowSpread: 0 125 | _2dp: 126 | shadowY: 2 127 | shadowBlur: 2 128 | shadowSpread: 0 129 | _1dp: 130 | shadowY: 2 131 | shadowBlur: 2 132 | shadowSpread: 0 133 | _0dp: 134 | shadowY: 0 135 | shadowBlur: 0 136 | shadowSpread: 0 137 | 138 | @ambient= new Layer 139 | width: @options.width 140 | height: @options.height 141 | backgroundColor: "" 142 | shadowColor: "rgba(0,0,0,0.20)" 143 | name: "ambient" 144 | borderRadius : @options.borderRadius 145 | 146 | @ambient.states = 147 | _12dp: 148 | shadowY: 7 149 | shadowBlur: 8 150 | shadowSpread: 0 151 | _8dp: 152 | shadowY: 8 153 | shadowBlur: 10 154 | shadowSpread: 1 155 | _6dp: 156 | shadowY: 3 157 | shadowBlur: 5 158 | shadowSpread: 0 159 | _4dp: 160 | shadowY: 1 161 | shadowBlur: 10 162 | shadowSpread: 0 163 | _2dp: 164 | shadowY: 1 165 | shadowBlur: 3 166 | shadowSpread: 0 167 | _1dp: 168 | shadowY: 1 169 | shadowBlur: 3 170 | shadowSpread: 0 171 | _0dp: 172 | shadowY: 0 173 | shadowBlur: 0 174 | shadowSpread: 0 175 | 176 | @umbra.animationOptions = time: 0.2 177 | @penumbra.animationOptions = time: 0.2 178 | @ambient.animationOptions = time: 0.2 179 | 180 | @umbra.states.switchInstant "_2dp" 181 | @penumbra.states.switchInstant "_2dp" 182 | @ambient.states.switchInstant "_2dp" 183 | 184 | super @options 185 | 186 | @umbra.parent = @ 187 | @penumbra.parent = @ 188 | @ambient.parent = @ 189 | 190 | @array = [@umbra, @penumbra, @ambient] 191 | 192 | 193 | 194 | #--------Icons------------------------------------------------------------------------------------------------------ 195 | class SystemIcon extends Layer 196 | constructor: (@options={}) -> 197 | 198 | Utils.insertCSS('@import url(https://fonts.googleapis.com/icon?family=Material+Icons); @import url(https://storage.googleapis.com/code.getmdl.io/1.0.6/material.indigo-pink.min.css); .material-icons.tab{}') 199 | 200 | @options.fontSize ?= 24 201 | 202 | 203 | @options.icon ?= "android" 204 | @options.html = "" + @options.icon + "" 205 | @options.color ?= "#009688" 206 | @options.height ?= @options.fontSize 207 | @options.width ?= @options.fontSize 208 | @options.backgroundColor = "" 209 | 210 | super @options 211 | 212 | @define 'fontSize', 213 | get: -> 214 | @options.fontSize 215 | set: (value) -> 216 | @options.fontSize = value 217 | 218 | Utils.insertCSS('@import url(https://fonts.googleapis.com/icon?family=Material+Icons); @import url(https://storage.googleapis.com/code.getmdl.io/1.0.6/material.indigo-pink.min.css); .material-icons.tab{}') 219 | 220 | 221 | 222 | 223 | 224 | 225 | ################################################# 1. Color ######################################################### 226 | class exports.color extends Layer 227 | constructor: (@options={}) -> 228 | @options = _.defaults @options, 229 | super @options 230 | 231 | #reds----------------- 232 | 233 | exports.red = "#F44336" 234 | exports.red50 = "#FFEBEE" 235 | exports.red100 = "#FFCDD2" 236 | exports.red200 = "#EF9A9A" 237 | exports.red300 = "#E57373" 238 | exports.red400 = "#EF5350" 239 | exports.red500 = "#F44336" 240 | exports.red600 = "#E53935" 241 | exports.red700 = "#D32F2F" 242 | exports.red800 = "#C62828" 243 | exports.red900 = "#B71C1C" 244 | exports.redA100 = "#FF8A80" 245 | exports.redA200 = "#FF5252" 246 | exports.redA400 = "#FF1744" 247 | exports.redA700 = "#D50000" 248 | 249 | #pink----------------- 250 | exports.pink = "#E91E63" 251 | exports.pink50 = "#FCE4EC" 252 | exports.pink100 = "#F8BBD0" 253 | exports.pink200 = "#F48FB1" 254 | exports.pink300 = "#F06292" 255 | exports.pink400 = "#EC407A" 256 | exports.pink500 = "#E91E63" 257 | exports.pink600 = "#D81B60" 258 | exports.pink700 = "#C2185B" 259 | exports.pink800 = "#AD1457" 260 | exports.pink900 = "#880E4F" 261 | exports.pinkA100 = "#FF80AB" 262 | exports.pinkA200 = "#FF4081" 263 | exports.pinkA400 = "#F50057" 264 | exports.pinkA700 = "#C51162" 265 | 266 | 267 | #purple----------------- 268 | exports.purple = "#9C27B0" 269 | exports.purple50 = "#F3E5F5" 270 | exports.purple100 = "#E1BEE7" 271 | exports.purple200 = "#CE93D8" 272 | exports.purple300 = "#BA68C8" 273 | exports.purple400 = "#AB47BC" 274 | exports.purple500 = "#9C27B0" 275 | exports.purple600 = "#8E24AA" 276 | exports.purple700 = "#7B1FA2" 277 | exports.purple800 = "#6A1B9A" 278 | exports.purple900 = "#4A148C" 279 | exports.purpleA100 = "#EA80FC" 280 | exports.purpleA200 = "#E040FB" 281 | exports.purpleA400 = "#D500F9" 282 | exports.purpleA700 = "#AA00FF" 283 | 284 | #Deep purple-------------- 285 | exports.deepPurple = "#673AB7" 286 | exports.deepPurple50 = "#EDE7F6" 287 | exports.deepPurple100 = "#D1C4E9" 288 | exports.deepPurple200 = "#B39DDB" 289 | exports.deepPurple300 = "#9575CD" 290 | exports.deepPurple400 = "#7E57C2" 291 | exports.deepPurple500 = "#673AB7" 292 | exports.deepPurple600 = "#5E35B1" 293 | exports.deepPurple700 = "#512DA8" 294 | exports.deepPurple800 = "#4527A0" 295 | exports.deepPurple900 = "#311B92" 296 | exports.deepPurpleA100 = "#B388FF" 297 | exports.deepPurpleA200 = "#7C4DFF" 298 | exports.deepPurpleA400 = "#651FFF" 299 | exports.deepPurpleA700 = "#6200EA" 300 | #indigo-------------- 301 | exports.indigo = "#3F51B5" 302 | exports.indigo50 = "#E8EAF6" 303 | exports.indigo100 = "#C5CAE9" 304 | exports.indigo200 = "#9FA8DA" 305 | exports.indigo300 = "#7986CB" 306 | exports.indigo400 = "#5C6BC0" 307 | exports.indigo500 = "#3F51B5" 308 | exports.indigo600 = "#3949AB" 309 | exports.indigo700 = "#303F9F" 310 | exports.indigo800 = "#283593" 311 | exports.indigo900 = "#1A237E" 312 | exports.indigoA100 = "#8C9EFF" 313 | exports.indigoA200 = "#536DFE" 314 | exports.indigoA400 = "#3D5AFE" 315 | exports.indigoA700 = "#304FFE" 316 | #blue-------------- 317 | exports.blue = "#2196F3" 318 | exports.blue50 = "#E3F2FD" 319 | exports.blue100 = "#BBDEFB" 320 | exports.blue200 = "#90CAF9" 321 | exports.blue300 = "#64B5F6" 322 | exports.blue400 = "#42A5F5" 323 | exports.blue500 = "#2196F3" 324 | exports.blue600 = "#1E88E5" 325 | exports.blue700 = "#1976D2" 326 | exports.blue800 = "#1565C0" 327 | exports.blue900 = "#0D47A1" 328 | exports.blueA100 = "#82B1FF" 329 | exports.blueA200 = "#448AFF" 330 | exports.blueA400 = "#2979FF" 331 | exports.blueA700 = "#2962FF" 332 | #light blue------------ 333 | exports.lightBlue = "#03A9F4" 334 | exports.lightBlue50 = "#E1F5FE" 335 | exports.lightBlue100 = "#B3E5FC" 336 | exports.lightBlue200 = "#81D4FA" 337 | exports.lightBlue300 = "#4FC3F7" 338 | exports.lightBlue400 = "#29B6F6" 339 | exports.lightBlue500 = "#03A9F4" 340 | exports.lightBlue600 = "#039BE5" 341 | exports.lightBlue700 = "#0288D1" 342 | exports.lightBlue800 = "#0277BD" 343 | exports.lightBlue900 = "#01579B" 344 | exports.lightBlueA100 = "#80D8FF" 345 | exports.lightBlueA200 = "#40C4FF" 346 | exports.lightBlueA400 = "#00B0FF" 347 | exports.lightBlueA700 = "#0091EA" 348 | #cyan---------------- 349 | exports.cyan = "#00BCD4" 350 | exports.cyan50 = "#E0F7FA" 351 | exports.cyan100 = "#B2EBF2" 352 | exports.cyan200 = "#80DEEA" 353 | exports.cyan300 = "#4DD0E1" 354 | exports.cyan400 = "#26C6DA" 355 | exports.cyan500 = "#00BCD4" 356 | exports.cyan600 = "#00ACC1" 357 | exports.cyan700 = "#0097A7" 358 | exports.cyan800 = "#00838F" 359 | exports.cyan900 = "#006064" 360 | exports.cyanA100 = "#84FFFF" 361 | exports.cyanA200 = "#18FFFF" 362 | exports.cyanA400 = "#00E5FF" 363 | exports.cyanA700 = "#00B8D4" 364 | #teal------------------- 365 | exports.teal = "#009688" 366 | exports.teal50 = "#E0F2F1" 367 | exports.teal100 = "#B2DFDB" 368 | exports.teal200 = "#80CBC4" 369 | exports.teal300 = "#4DB6AC" 370 | exports.teal400 = "#26A69A" 371 | exports.teal500 = "#009688" 372 | exports.teal600 = "#00897B" 373 | exports.teal700 = "#00796B" 374 | exports.teal800 = "#00695C" 375 | exports.teal900 = "#004D40" 376 | exports.tealA100 = "#A7FFEB" 377 | exports.tealA200 = "#64FFDA" 378 | exports.tealA400 = "#1DE9B6" 379 | exports.tealA700 = "#00BFA5" 380 | #green--------------- 381 | exports.green = "#4CAF50" 382 | exports.green50 = "#E8F5E9" 383 | exports.green100 = "#C8E6C9" 384 | exports.green200 = "#A5D6A7" 385 | exports.green300 = "#81C784" 386 | exports.green400 = "#66BB6A" 387 | exports.green500 = "#4CAF50" 388 | exports.green600 = "#43A047" 389 | exports.green700 = "#388E3C" 390 | exports.green800 = "#2E7D32" 391 | exports.green900 = "#1B5E20" 392 | exports.greenA100 = "#B9F6CA" 393 | exports.greenA200 = "#69F0AE" 394 | exports.greenA400 = "#00E676" 395 | exports.greenA700 = "#00C853" 396 | #light green--------------- 397 | exports.lightGreen = "#8BC34A" 398 | exports.lightGreen50 = "#F1F8E9" 399 | exports.lightGreen100 = "#DCEDC8" 400 | exports.lightGreen200 = "#C5E1A5" 401 | exports.lightGreen300 = "#AED581" 402 | exports.lightGreen400 = "#9CCC65" 403 | exports.lightGreen500 = "#8BC34A" 404 | exports.lightGreen600 = "#7CB342" 405 | exports.lightGreen700 = "#689F38" 406 | exports.lightGreen800 = "#558B2F" 407 | exports.lightGreen900 = "#33691E" 408 | exports.lightGreenA100 = "#CCFF90" 409 | exports.lightGreenA200 = "#B2FF59" 410 | exports.lightGreenA400 = "#76FF03" 411 | exports.lightGreenA700 = "#64DD17" 412 | #lime----------------- 413 | exports.lime = "#CDDC39" 414 | exports.lime50 = "#F9FBE7" 415 | exports.lime100 = "#F0F4C3" 416 | exports.lime200 = "#E6EE9C" 417 | exports.lime300 = "#DCE775" 418 | exports.lime400 = "#D4E157" 419 | exports.lime500 = "#CDDC39" 420 | exports.lime600 = "#C0CA33" 421 | exports.lime700 = "#AFB42B" 422 | exports.lime800 = "#9E9D24" 423 | exports.lime900 = "#827717" 424 | exports.limeA100 = "#F4FF81" 425 | exports.limeA200 = "#EEFF41" 426 | exports.limeA400 = "#C6FF00" 427 | exports.limeA700 = "#AEEA00" 428 | #yellow----------------- 429 | exports.yellow = "#FFEB3B" 430 | exports.yellow50 = "#FFFDE7" 431 | exports.yellow100 = "#FFF9C4" 432 | exports.yellow200 = "#FFF59D" 433 | exports.yellow300 = "#FFF176" 434 | exports.yellow400 = "#FFEE58" 435 | exports.yellow500 = "#FFEB3B" 436 | exports.yellow600 = "#FDD835" 437 | exports.yellow700 = "#FBC02D" 438 | exports.yellow800 = "#F9A825" 439 | exports.yellow900 = "#F57F17" 440 | exports.yellowA100 = "#FFFF8D" 441 | exports.yellowA200 = "#FFFF00" 442 | exports.yellowA400 = "#FFEA00" 443 | exports.yellowA700 = "#FFD600" 444 | #amber------------------ 445 | exports.amber = "#FFC107" 446 | exports.amber50 = "#FFF8E1" 447 | exports.amber100 = "#FFECB3" 448 | exports.amber200 = "#FFE082" 449 | exports.amber300 = "#FFD54F" 450 | exports.amber400 = "#FFCA28" 451 | exports.amber500 = "#FFC107" 452 | exports.amber600 = "#FFB300" 453 | exports.amber700 = "#FFA000" 454 | exports.amber800 = "#FF8F00" 455 | exports.amber900 = "#FF6F00" 456 | exports.amberA100 = "#FFE57F" 457 | exports.amberA200 = "#FFD740" 458 | exports.amberA400 = "#FFC400" 459 | exports.amberA700 = "#FFAB00" 460 | #orange------------------ 461 | exports.orange = "#FF9800" 462 | exports.orange50 = "#FFF3E0" 463 | exports.orange100 = "#FFE0B2" 464 | exports.orange200 = "#FFCC80" 465 | exports.orange300 = "#FFB74D" 466 | exports.orange400 = "#FFA726" 467 | exports.orange500 = "#FF9800" 468 | exports.orange600 = "#FB8C00" 469 | exports.orange700 = "#F57C00" 470 | exports.orange800 = "#EF6C00" 471 | exports.orange900 = "#E65100" 472 | exports.orangeA100 = "#FFD180" 473 | exports.orangeA200 = "#FFAB40" 474 | exports.orangeA400 = "#FF9100" 475 | exports.orangeA700 = "#FF6D00" 476 | #deep orange------------- 477 | exports.deepOrange = "#FF5722" 478 | exports.deepOrange50 = "#FBE9E7" 479 | exports.deepOrange100 = "#FFCCBC" 480 | exports.deepOrange200 = "#FFAB91" 481 | exports.deepOrange300 = "#FF8A65" 482 | exports.deepOrange400 = "#FF7043" 483 | exports.deepOrange500 = "#FF5722" 484 | exports.deepOrange600 = "#F4511E" 485 | exports.deepOrange700 = "#E64A19" 486 | exports.deepOrange800 = "#D84315" 487 | exports.deepOrange900 = "#BF360C" 488 | exports.deepOrangeA100 = "#FF9E80" 489 | exports.deepOrangeA200 = "#FF6E40" 490 | exports.deepOrangeA400 = "#FF3D00" 491 | exports.deepOrangeA700 = "#DD2C00" 492 | #brown------------- 493 | exports.brown = "#795548" 494 | exports.brown50 = "#EFEBE9" 495 | exports.brown100 = "#D7CCC8" 496 | exports.brown200 = "#BCAAA4" 497 | exports.brown300 = "#A1887F" 498 | exports.brown400 = "#8D6E63" 499 | exports.brown500 = "#795548" 500 | exports.brown600 = "#6D4C41" 501 | exports.brown700 = "#5D4037" 502 | exports.brown800 = "#4E342E" 503 | exports.brown900 = "#4E342E" 504 | exports.brownA100 = "" 505 | exports.brownA200 = "" 506 | exports.brownA400 = "" 507 | exports.brownA700 = "" 508 | #grey-------------- 509 | exports.grey = "#9E9E9E" 510 | exports.grey50 = "#FAFAFA" 511 | exports.grey100 = "#F5F5F5" 512 | exports.grey200 = "#EEEEEE" 513 | exports.grey300 = "#E0E0E0" 514 | exports.grey400 = "#BDBDBD" 515 | exports.grey500 = "#9E9E9E" 516 | exports.grey600 = "#757575" 517 | exports.grey700 = "#616161" 518 | exports.grey800 = "#424242" 519 | exports.grey900 = "#212121" 520 | exports.greyA100 = "" 521 | exports.greyA200 = "" 522 | exports.greyA400 = "" 523 | exports.greyA700 = "" 524 | #blue grey------------ 525 | exports.blueGrey = "#607D8B" 526 | exports.blueGrey50 = "#ECEFF1" 527 | exports.blueGrey100 = "#CFD8DC" 528 | exports.blueGrey200 = "#B0BEC5" 529 | exports.blueGrey300 = "#90A4AE" 530 | exports.blueGrey400 = "#78909C" 531 | exports.blueGrey500 = "#607D8B" 532 | exports.blueGrey600 = "#546E7A" 533 | exports.blueGrey700 = "#455A64" 534 | exports.blueGrey800 = "#37474F" 535 | exports.blueGrey900 = "#263238" 536 | 537 | #black and white--------- 538 | exports.black = "#000" 539 | exports.white = "#fff" 540 | 541 | #labels - light -------- 542 | exports.lightPrimary = "rgba(0,0,0,0.87)" 543 | exports.lightSecondary = "rgba(0,0,0,0.54)" 544 | exports.lightDisabled = "rgba(0,0,0,0.38)" 545 | 546 | #labels - Dark -------- 547 | exports.darkPrimary = "rgba(255,255,255,1)" 548 | exports.darkSecondary = "rgba(255,255,255, 0.7)" 549 | exports.darkDisabled = "rgba(255,255,255,0.5)" 550 | 551 | 552 | 553 | 554 | 555 | 556 | ################################################# 2. FlatButton #################################################### 557 | class exports.FlatButton extends Layer 558 | 559 | constructor: (@options={}) -> 560 | 561 | #------ Default properties -------------------------------------------------------------------------------------------- 562 | 563 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 564 | 565 | @options.labelText ?= "Flat Button" 566 | @options.themeColor ?= "#009688" 567 | @options.disabled ?= false 568 | @options.theme ?= "light" 569 | @options.directionRipple ?= false 570 | @options.fontFamily ?= "'Roboto', sans serif" 571 | @options.disableRipple ?= false 572 | @options.letterSpacing ?= 0 573 | @options.fontWeight ?= 600 574 | @options.fontSize ?= 14 575 | 576 | if @options.disabled is true 577 | if @options.theme is "dark" 578 | @disabled_labelColor = "rgba(255,255,255,0.3)" 579 | else 580 | @disabled_labelColor = "rgba(0,0,0,0.26)" 581 | 582 | 583 | _.defaults @options, 584 | backgroundColor : null 585 | height: 48 586 | borderRadius : 2 587 | width: @options.labelText.length * ((@options.fontSize + 3) / 2) + 16 + 16 588 | name: "Flat button" 589 | 590 | 591 | if @options.width < 88 592 | @options.width = 88 593 | 594 | if @options.dense is true 595 | @options.width = @options.labelText.length * ((@options.fontSize + 2) / 2) + 16 + 16 596 | @buttonHeight = 32 597 | else 598 | @buttonHeight = 36 599 | 600 | #------ hover --------------------------------------------------------------------------------------------------------- 601 | 602 | @bttnBG = new Layer 603 | width: @options.width 604 | height: @buttonHeight 605 | backgroundColor: @options.themeColor 606 | clip: true 607 | borderRadius: 2 608 | opacity: 0.12 609 | visible: false 610 | name: "overlay" 611 | 612 | #------- ripple ------------------------------------------------------------------------------------------------------- 613 | 614 | @rippleBG = new Layer 615 | width: @options.width 616 | height: @buttonHeight 617 | backgroundColor: null 618 | name: "ripple parent" 619 | 620 | 621 | @ripple = new Layer 622 | borderRadius: "100%" 623 | size: @options.width 624 | backgroundColor: @options.themeColor 625 | scale: 0.3 626 | opacity: 0 627 | name: "ripple" 628 | 629 | #------- label ----------------------------------------------------------------------------------------------------- 630 | 631 | @label = new TextLayer 632 | text : @options.labelText 633 | fontSize: @options.fontSize 634 | textTransform: "Uppercase" 635 | color: @options.themeColor 636 | fontWeight: @options.fontWeight 637 | fontFamily: @options.fontFamily 638 | letterSpacing: @options.letterSpacing 639 | name: "label" 640 | 641 | #------- super ----------------------------------------------------------------------------------------------------- 642 | 643 | super @options 644 | 645 | @bttnBG.parent = @label.parent = @rippleBG.parent = @ 646 | @bttnBG.y = Align.center 647 | @rippleBG.y = Align.center 648 | 649 | @rippleBG.clip = true 650 | 651 | @ripple.parent = @rippleBG 652 | @ripple.x = Align.center 653 | @ripple.y = Align.center 654 | 655 | @label.x = Align.center 656 | @label.y = Align.center(1) 657 | 658 | if @disableRipple is false 659 | @ripple.destroy() 660 | 661 | #-------- Events ---------------------------------------------------------------------------------------------------- 662 | 663 | @.onClick @clicked 664 | @.onMouseOver @Hover 665 | @.onMouseOut @HoverOff 666 | @.onMouseDown @mouseDown 667 | @.onMouseUp @mouseUp 668 | 669 | #-------- getters & setters ------------------------------------------------------------------------------------------- 670 | 671 | @define 'disabled', 672 | get: -> 673 | @options.disabled 674 | set: (value) -> 675 | @options.disabled = value 676 | 677 | if @options.disabled is true 678 | @label.color = @disabled_labelColor 679 | 680 | if @options.disabled is false 681 | @label.color = @options.themeColor 682 | 683 | 684 | 685 | #--------- Event functions ------------------------------------------------------------------------------------------- 686 | 687 | Hover: => 688 | if @options.disabled is false 689 | @bttnBG.visible = true 690 | 691 | HoverOff: => 692 | @bttnBG.visible = false 693 | 694 | mouseDown: -> 695 | @bttnBG.brightness = 80 696 | mouseUp: -> 697 | @bttnBG.brightness = 100 698 | 699 | clicked: (ev) -> 700 | if @options.disabled is false 701 | if @options.disableRipple is false 702 | 703 | if @options.directionRipple is true 704 | @ripple.midX = ev.offsetX 705 | @ripple.midY = ev.offsetY 706 | @ripple.size = (@options.labelText.length * 8.5 + 16 + 16) * 1.5 707 | 708 | @ripple.visible = true 709 | @ripple.scale = 0.4 710 | @ripple.opacity = 0.3 711 | 712 | rippleA = new Animation 713 | layer: @ripple 714 | properties: 715 | scale: 0.8 716 | time: 0.15 717 | curve: Bezier.linear 718 | 719 | rippleB = new Animation 720 | layer: @ripple 721 | properties: 722 | scale: 1 723 | opacity: 0 724 | time: 0.15 725 | curve: Bezier.linear 726 | 727 | rippleA.start() 728 | 729 | rippleA.onAnimationEnd -> 730 | rippleB.start() 731 | 732 | 733 | 734 | 735 | 736 | ################################################# 3. RaisedButton ################################################## 737 | class exports.RaisedButton extends Layer 738 | 739 | constructor: (@options={}) -> 740 | 741 | #------ Default properties -------------------------------------------------------------------------------------------- 742 | 743 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 744 | 745 | @options.labelText ?= "Raised button" 746 | @options.themeColor ?= "#009688" 747 | @options.disabled ?= false 748 | @options.theme ?= "light" 749 | @options.directionRipple ?= false 750 | @options.fontFamily ?= "'Roboto', sans serif" 751 | @options.height = 48 752 | @options.disableRipple ?= false 753 | @options.letterSpacing ?= 0 754 | @options.fontWeight ?= 600 755 | @options.fontSize ?= 14 756 | 757 | if @options.disabled is true 758 | if @options.theme is "dark" 759 | @disabled_BG = "rgba(255,255,255,0.12)" 760 | @disabled_labelColor = "rgba(255,255,255,0.3)" 761 | else 762 | @disabled_BG = "rgba(0,0,0,0.12)" 763 | @disabled_labelColor = "rgba(0,0,0,0.26)" 764 | 765 | _.defaults @options, 766 | backgroundColor : "" 767 | color: "" 768 | borderRadius : 2 769 | name: "Raised button" 770 | width: @options.labelText.length * ((@options.fontSize + 3) / 2) + 16 + 16 771 | 772 | if @options.width < 88 773 | @options.width = 88 774 | 775 | if @options.dense is true 776 | @buttonHeight = 32 777 | else 778 | @buttonHeight = 36 779 | 780 | #-------Shadows ------------------------------------------------------------------------------------------------------- 781 | 782 | @shadow = new Shadow 783 | width: @options.width 784 | height: @buttonHeight 785 | backgroundColor : @options.themeColor 786 | borderRadius: @options.borderRadius 787 | name: "shadows" 788 | 789 | 790 | 791 | #-------hover -------------------------------------------------------------------------------------------------------- 792 | 793 | @bttnBG = new Layer 794 | width: @options.width 795 | height: @buttonHeight 796 | backgroundColor: "#fff" 797 | clip: true 798 | borderRadius: 2 799 | opacity: 0 800 | name: "overlay" 801 | 802 | #-------ripple --------------------------------------------------------------------------------------------------------- 803 | 804 | @rippleBG = new Layer 805 | width: @options.width 806 | height: @buttonHeight 807 | clip: true 808 | borderRadius: 2 809 | name: "ripple parent" 810 | clip: true 811 | backgroundColor: "" 812 | 813 | 814 | @ripple = new Layer 815 | borderRadius: "100%" 816 | size: @options.width 817 | backgroundColor: "#fff" 818 | scale:0.3 819 | opacity: 0 820 | name: "ripple" 821 | 822 | @rippleColor = @ripple.backgroundColor 823 | 824 | #-------label --------------------------------------------------------------------------------------------------------- 825 | 826 | @label = new TextLayer 827 | text : @options.labelText 828 | fontSize: @options.fontSize 829 | textTransform: "Uppercase" 830 | color: "#fff" 831 | fontWeight: @options.fontWeight 832 | fontFamily: @options.fontFamily 833 | letterSpacing: @options.letterSpacing 834 | name: "label" 835 | 836 | #-------super -------------------------------------------------------------------------------------------------------- 837 | 838 | super @options 839 | 840 | @label.parent = @rippleBG.parent = @shadow.parent = @bttnBG.parent = @ 841 | 842 | @shadow.y = @bttnBG.y = @rippleBG.y = Align.center 843 | 844 | @ripple.parent = @rippleBG 845 | @ripple.x = Align.center 846 | @ripple.y = Align.center 847 | 848 | @label.x = Align.center 849 | @label.y = Align.center(1) 850 | 851 | if @disableRipple is false 852 | @ripple.destroy() 853 | 854 | #---------Events ----------------------------------------------------------------------------------------------------- 855 | 856 | @.onClick @clicked 857 | @.onMouseOver @Hover 858 | @.onMouseOut @HoverOff 859 | @.onMouseDown @mouseDown 860 | @.onMouseUp @mouseUp 861 | 862 | #---------getters & setters ----------------------------------------------------------------------------------------- 863 | 864 | @define 'disabled', 865 | get: -> 866 | @options.disabled 867 | set: (value) -> 868 | @options.disabled = value 869 | 870 | if @options.disabled is true 871 | @label.color = @disabled_labelColor 872 | @shadow.backgroundColor = @disabled_BG 873 | else 874 | @shadow.backgroundColor = @options.themeColor 875 | @label.color = "#fff" 876 | 877 | #---------Event functions ------------------------------------------------------------------------------------------ 878 | 879 | Hover: => 880 | if @options.disabled is false 881 | @bttnBG.opacity = 0.12 882 | for item in @shadow.array 883 | item.states.switch "_8dp" 884 | HoverOff: => 885 | @bttnBG.opacity = 0 886 | for item in @shadow.array 887 | item.states.switch "_2dp" 888 | 889 | mouseDown: -> 890 | if @options.disabled is false 891 | @brightness = 80 892 | @bttnBG.opacity = 0 893 | mouseUp: -> 894 | @brightness = 100 895 | 896 | clicked: (ev) -> 897 | if @options.disabled is false 898 | if @options.disableRipple is false 899 | 900 | if @options.directionRipple is true 901 | @ripple.midX = ev.offsetX 902 | @ripple.midY = ev.offsetY 903 | @ripple.size = (@options.labelText.length * 8.5 + 16 + 16) * 1.5 904 | 905 | @ripple.visible = true 906 | @ripple.scale = 0.4 907 | @ripple.opacity = 0.3 908 | 909 | rippleA = new Animation 910 | layer: @ripple 911 | properties: 912 | scale: 0.8 913 | time: 0.15 914 | curve: Bezier.linear 915 | 916 | rippleB = new Animation 917 | layer: @ripple 918 | properties: 919 | scale: 1 920 | opacity: 0 921 | time: 0.15 922 | curve: Bezier.linear 923 | 924 | rippleA.start() 925 | 926 | rippleA.onAnimationEnd -> 927 | rippleB.start() 928 | 929 | 930 | 931 | 932 | 933 | ################################################# 4. FAB ########################################################### 934 | class exports.FAB extends Layer 935 | constructor: (@options={}) -> 936 | 937 | #------ Default properties -------------------------------------------------------------------------------------------- 938 | 939 | if Utils.isDesktop() 940 | pd = 24 941 | else pd = 16 942 | 943 | @options.mini ?= false 944 | 945 | if @options.mini is true or Screen.width < 460 946 | @options.width ?= 40 947 | @options.height ?= 40 948 | else 949 | @options.width ?= 56 950 | @options.height ?= 56 951 | 952 | @options.x ?= Screen.width - (@options.width + pd) 953 | @options.y ?= Screen.height - (@options.width + pd) 954 | 955 | @options.borderRadius = "100%" 956 | @options.themeColor ?= "#009688" 957 | @options.backgroundColor ?= @options.themeColor 958 | @options.icon ?= "add" 959 | 960 | #------ overlay ----------------------------------------------------------------------------------------------------- 961 | 962 | @overlay = new Layer 963 | width: @options.width 964 | height: @options.height 965 | borderRadius: @options.borderRadius 966 | backgroundColor: "rgba(0,0,0,0.12)" 967 | visible: false 968 | name: "overlay" 969 | 970 | #------ shadow ----------------------------------------------------------------------------------------------------- 971 | 972 | @shadow = new Shadow 973 | width: @options.width 974 | height: @options.height 975 | borderRadius: @options.borderRadius 976 | name: "shadow" 977 | 978 | @shadow.umbra.states.switchInstant "_6dp" 979 | @shadow.penumbra.states.switchInstant "_6dp" 980 | @shadow.ambient.states.switchInstant "_6dp" 981 | 982 | #------ icon ----------------------------------------------------------------------------------------------------- 983 | 984 | @icon = new SystemIcon 985 | width: 24 986 | height: 24 987 | icon: @options.icon 988 | color: "#fff" 989 | name: "icon" 990 | 991 | #------ super ----------------------------------------------------------------------------------------------------- 992 | 993 | super @options 994 | 995 | @icon.parent = @overlay.parent = @shadow.parent = @ 996 | @icon.center() 997 | 998 | #------ events ----------------------------------------------------------------------------------------------------- 999 | 1000 | if Utils.isDesktop() 1001 | @.onMouseOver @Hover 1002 | @.onMouseOut @HoverOff 1003 | @onMouseDown @mouseDown 1004 | @onMouseUp @mouseUp 1005 | else 1006 | @onTapStart @mouseDown 1007 | @onTapEnd @mouseUp 1008 | 1009 | #------ event functions --------------------------------------------------------------------------------------------- 1010 | 1011 | Hover: -> 1012 | @shadow.umbra.states.switch "_12dp" 1013 | @shadow.penumbra.states.switch "_12dp" 1014 | @shadow.ambient.states.switch "_12dp" 1015 | 1016 | HoverOff: -> 1017 | @shadow.umbra.states.switch "_6dp" 1018 | @shadow.penumbra.states.switch "_6dp" 1019 | @shadow.ambient.states.switch "_6dp" 1020 | 1021 | mouseDown: -> 1022 | @overlay.visible = true 1023 | @shadow.umbra.states.switchInstant "_12dp" 1024 | @shadow.penumbra.states.switchInstant "_12dp" 1025 | @shadow.ambient.states.switchInstant "_12dp" 1026 | 1027 | mouseUp: -> 1028 | @overlay.visible = false 1029 | @shadow.umbra.states.switchInstant "_6dp" 1030 | @shadow.penumbra.states.switchInstant "_6dp" 1031 | @shadow.ambient.states.switchInstant "_6dp" 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | ################################################# 5. Checkboxes ##################################################### 1038 | class exports.Checkboxes extends Layer 1039 | 1040 | constructor: (@options={}) -> 1041 | 1042 | #------ default properties -------------------------------- 1043 | 1044 | @options.theme ?= "light" 1045 | theme = @options.theme 1046 | @options.name ?= "checkboxes" 1047 | 1048 | @options.disableRipple ?= false 1049 | 1050 | if @options.theme is "dark" 1051 | @options.screenColor ?= "#212121" 1052 | else 1053 | @options.screenColor ?= "#fff" 1054 | 1055 | #label choices 1056 | @options.choices ?= ["apples", "bananas", "grapes"] 1057 | 1058 | @options.checkY ?= -5 1059 | 1060 | #------ colors 1061 | @themeColor ?= "#009688" 1062 | themeColor = @themeColor 1063 | 1064 | if @options.theme is "dark" 1065 | @labelColor = label_dark 1066 | @boxColor = line_dark 1067 | else 1068 | @labelColor = label_light 1069 | @boxColor = line_light 1070 | boxColor = @boxColor 1071 | 1072 | #text styling 1073 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 1074 | 1075 | @options.labelText ?= "Select fruit" 1076 | 1077 | #Default properties 1078 | _.defaults @options, 1079 | backgroundColor : "" 1080 | height: @options.choices.length * 36 + 32 1081 | width : 150 1082 | 1083 | #------ Question label -------------------------------------------------------------------------------------------- 1084 | 1085 | @label = new Label 1086 | color: @labelColor 1087 | text: @options.labelText 1088 | name: "label" 1089 | 1090 | #------ Super ------------------------------------------------------------------------------------------------------ 1091 | super @options 1092 | 1093 | @label.parent = @ 1094 | 1095 | checkY = @options.checkY 1096 | 1097 | #------ time -------------------------------------------------------------------------------------------------------- 1098 | t1 = 0.2 1099 | t2 = 0.2 1100 | 1101 | #------ loop ------------------------------------------------------------------------------------------------ 1102 | checks = [] 1103 | 1104 | for i in [0...@options.choices.length] 1105 | 1106 | #------ checkbox container 1107 | cont = new Layer 1108 | parent:@ 1109 | height: 40 1110 | y: i * 40 + 24 1111 | backgroundColor: "" 1112 | x: 16 1113 | name: "container" 1114 | 1115 | #------ box settings 1116 | box = new Layer 1117 | backgroundColor : "" 1118 | size : 20 1119 | borderRadius : 2 1120 | borderWidth : 2 1121 | borderColor : @boxColor 1122 | parent: cont 1123 | clip: true 1124 | name: @options.choices[i] 1125 | y: Align.center 1126 | name: @options.choices[i] 1127 | 1128 | box.animationOptions = 1129 | time: t1 1130 | 1131 | box.states = 1132 | selected: 1133 | borderColor: @options.themeColor 1134 | backgroundColor: @options.themeColor 1135 | deselected: 1136 | borderColor: @boxColor 1137 | backgroundColor: @boxColor 1138 | 1139 | box.states.switchInstant "deselected" 1140 | box.backgroundColor = @options.screenColor 1141 | 1142 | #------ box Circle settings 1143 | #------ This create the circle animation within the box 1144 | boxCircle = new Layer 1145 | parent: box 1146 | borderRadius: "100%" 1147 | size: 30 1148 | scale: 0 1149 | backgroundColor: @screenColor 1150 | x: Align.center(2) 1151 | y: Align.center(2) 1152 | name: "overlay" 1153 | 1154 | boxCircle.animationOptions = 1155 | time: t1 1156 | 1157 | boxCircle.states = 1158 | selected: 1159 | scale: 0 1160 | deselected: 1161 | scale: 1 1162 | backgroundColor: @options.screenColor 1163 | 1164 | #------ check mask settings 1165 | #------ This create drawing in effect for the check 1166 | checkMask = new Layer 1167 | width: 0 1168 | height: 20 1169 | backgroundColor: "" 1170 | parent: box 1171 | y: checkY 1172 | x: 3.5 1173 | parent: box 1174 | clip: true 1175 | name: "check mask" 1176 | 1177 | checkMask.states.selected = 1178 | properties: 1179 | width:20 1180 | time: t2 1181 | 1182 | checkMask.states.deselected = 1183 | properties: 1184 | width: 0 1185 | time: 0.01 1186 | 1187 | checkMask.states.switch "deselected" 1188 | 1189 | #------ check settings 1190 | check = new Layer 1191 | html: '' 1192 | width: 20 1193 | height: 20 1194 | backgroundColor: "" 1195 | parent: checkMask 1196 | name: @options.choices[i] 1197 | y: 0 1198 | name: "check" 1199 | 1200 | check.style = 1201 | fontSize: "18px" 1202 | 1203 | #------ Ripple settings 1204 | if @options.disableRipple is false 1205 | 1206 | ripple = new Layer 1207 | size: 50 1208 | borderRadius: "100px" 1209 | parent: cont 1210 | y: Align.center 1211 | x: -15 1212 | opacity: 0.3 1213 | visible: false 1214 | name: "ripple" 1215 | 1216 | ripple.states.selected = 1217 | backgroundColor: @options.themeColor 1218 | 1219 | if @options.theme is "light" 1220 | ripple.states.deselected = 1221 | backgroundColor: "#000" 1222 | 1223 | if @options.theme is "dark" 1224 | ripple.states.deselected = 1225 | backgroundColor: "#fff" 1226 | 1227 | #------ choise lables settings 1228 | choice_label = new Label 1229 | text: @options.choices[i] 1230 | parent: cont 1231 | x: 30 1232 | color: @labelColor 1233 | y: Align.center(-0.5) 1234 | name: "choice ripple" 1235 | 1236 | #------ populating checks array 1237 | checks.push(box) 1238 | 1239 | #------ creating new array to see what checks are selected 1240 | ao = @options 1241 | dp = @options.disableRipple 1242 | ao.activeSelection = [] 1243 | 1244 | #------ event on Click --------------------------------------------------------------------------------------------- 1245 | cont.onClick -> 1246 | 1247 | #------ event setup 1248 | ao.activeSelection = [] #empty array 1249 | 1250 | if dp is false 1251 | pRipple = this.children[1] 1252 | pCheckMask = this.children[0].children[1] 1253 | pBox = this.children[0] 1254 | pBoxCircle = this.children[0].children[0] 1255 | 1256 | #------ box and check animation 1257 | pBox.stateCycle("selected", "deselected") 1258 | pBoxCircle.stateCycle("selected", "deselected") 1259 | 1260 | if pBox.states.current.name is "selected" 1261 | if dp is false 1262 | pRipple.states.switchInstant "selected" 1263 | Utils.delay t1, -> 1264 | pCheckMask.states.switch "selected" 1265 | else 1266 | if dp is false 1267 | pRipple.states.switchInstant "deselected" 1268 | pCheckMask.states.switch "deselected" 1269 | 1270 | # populates array to see selected items 1271 | for box in checks 1272 | if box.states.current.name is "selected" 1273 | ao.activeSelection.push(box.name) 1274 | 1275 | #----- pRipple animation 1276 | if dp is false 1277 | pRipple.visible = true 1278 | pRipple.scale = 0.4 1279 | pRipple.opacity = 0.4 1280 | 1281 | if pRipple.states.current.name is "selected" 1282 | pRipple.opacity = 0.8 1283 | 1284 | pulsaA = new Animation 1285 | layer: pRipple 1286 | properties: 1287 | scale: 0.8 1288 | time: 0.15 1289 | curve: Bezier.linear 1290 | 1291 | pRippleB = new Animation 1292 | layer: pRipple 1293 | properties: 1294 | scale: 1 1295 | opacity: 0 1296 | time: 0.15 1297 | curve: Bezier.linear 1298 | 1299 | pulsaA.start() 1300 | 1301 | pulsaA.onAnimationEnd -> 1302 | pRippleB.start() 1303 | 1304 | #------ event hover 1305 | cont.onMouseOver -> 1306 | this.children[0].borderColor = themeColor 1307 | 1308 | cont.onMouseOut -> 1309 | if this.children[0].states.current.name is "deselected" 1310 | this.children[0].borderColor = boxColor 1311 | 1312 | #------ getters and setters --------------------------------------------------------------------------------------- 1313 | @define 'themeColor', 1314 | get: -> 1315 | @options.themeColor 1316 | set: (value) -> 1317 | @options.themeColor = value 1318 | 1319 | @define 'choices', 1320 | get: -> 1321 | @options.choices 1322 | set: (value) -> 1323 | @options.choices = value 1324 | 1325 | @define 'activeSelection', 1326 | get: -> 1327 | @options.activeSelection 1328 | set: (value) -> 1329 | @options.activeSelection = value 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | ################################################# 6. RadioButtons #################################################### 1336 | class exports.RadioButtons extends Layer 1337 | 1338 | constructor: (@options={}) -> 1339 | 1340 | #------ default properties ----------------------------------------------------------------------------------------- 1341 | @options.theme ?= "light" 1342 | theme = @options.theme 1343 | 1344 | @options.disableRipple ?= false 1345 | 1346 | #label choices 1347 | @options.choices ?= ["apples", "bananas", "grapes"] 1348 | 1349 | #------- colors 1350 | @options.themeColor ?= "#009688" 1351 | themeColor = @options.themeColor 1352 | 1353 | if @options.theme is "dark" 1354 | @labelColor = label_dark 1355 | @boxColor = line_dark 1356 | else 1357 | @labelColor = label_light 1358 | @boxColor = line_light 1359 | boxColor = @boxColor 1360 | 1361 | @options.labelText ?= "Select fruit" 1362 | 1363 | _.defaults @options, 1364 | backgroundColor : "" 1365 | height: @options.choices.length * 36 + 32 1366 | width : 150 1367 | name: "RadioButtons" 1368 | 1369 | #------ Question label --------------------------------------------------------------------------------------------- 1370 | 1371 | @label = new Label 1372 | text: @options.labelText 1373 | color: @labelColor 1374 | name: "label" 1375 | 1376 | #------ Super ------------------------------------------------------------------------------------------------------ 1377 | 1378 | super @options 1379 | 1380 | @label.parent = @ 1381 | 1382 | l = @options.choices 1383 | 1384 | #------ loop and array --------------------------------------------------------------------------------------------- 1385 | 1386 | checks = [] 1387 | circles = [] 1388 | 1389 | for i in [0...@options.choices.length] 1390 | 1391 | cont = new Layer 1392 | height: 40 1393 | y: 40 * i + 24 1394 | backgroundColor: "" 1395 | parent: @ 1396 | name: @options.choices[i] 1397 | x: 16 1398 | 1399 | #------ circle 1400 | 1401 | circle = new Layer 1402 | backgroundColor : "" 1403 | size : 20 1404 | borderRadius : "100%" 1405 | borderWidth : 2 1406 | borderColor: @boxColor 1407 | parent: cont 1408 | y: Align.center 1409 | name: "circle" 1410 | 1411 | circle.animationOptions = 1412 | time: 0.001 1413 | 1414 | circle.states = 1415 | selected: 1416 | borderColor: themeColor 1417 | deselected: 1418 | borderColor: @boxColor 1419 | 1420 | circles.push(circle) 1421 | circle.states.switch "deselected" 1422 | 1423 | if i is @options.activeSelection 1424 | circle.states.switchInstant "selected" 1425 | 1426 | #------ check 1427 | 1428 | check = new Layer 1429 | width: 10 1430 | height: 10 1431 | backgroundColor: @options.themeColor 1432 | borderRadius: circle.borderRadius 1433 | parent: circle 1434 | x: 5 1435 | y: 5 1436 | name: i 1437 | 1438 | check.animationOptions = 1439 | time: 0.17 1440 | 1441 | check.states = 1442 | selected: 1443 | scale: 1 1444 | deselected: 1445 | scale: 0 1446 | 1447 | check.states.switchInstant "deselected" 1448 | 1449 | checks.push(check) 1450 | 1451 | if i is @options.activeSelection 1452 | check.states.switchInstant "selected" 1453 | 1454 | #------ ripple settings 1455 | 1456 | if @options.disableRipple is false 1457 | 1458 | ripple = new Layer 1459 | size: 50 1460 | borderRadius: "100px" 1461 | parent: circle 1462 | y: Align.center(2) 1463 | x: Align.center(2) 1464 | opacity: 0.12 1465 | visible: false 1466 | backgroundColor: @options.themeColor 1467 | name: "ripple" 1468 | 1469 | #------ choice 1470 | 1471 | choice_label = new Label 1472 | text: @options.choices[i] 1473 | parent: cont 1474 | x: 30 1475 | color: @labelColor 1476 | y: -0.5 1477 | y: Align.center 1478 | name: "choice label" 1479 | 1480 | #------ helper 1481 | 1482 | helper = new Layer 1483 | backgroundColor: "" 1484 | height: 5 1485 | parent: cont 1486 | width: i 1487 | name: "helper" 1488 | 1489 | #------ event 1490 | 1491 | @activeSelection = null 1492 | bb = @activeSelection 1493 | dp = @options.disableRipple 1494 | oc = @themeColor 1495 | 1496 | cont.onClick -> 1497 | 1498 | pRipple = this.children[0].children[1] 1499 | pCheck = this.children[0].children[0] 1500 | pCircle = this.children[0] 1501 | 1502 | for check in checks 1503 | if check.name is pCheck.name 1504 | pCheck.states.switch "selected" 1505 | else 1506 | check.states.switch "deselected" 1507 | for circle in circles 1508 | circle.states.switch "deselected" 1509 | 1510 | pCircle.states.switchInstant "selected" 1511 | 1512 | bb = this.name 1513 | 1514 | #------ ripple animation 1515 | 1516 | if dp is false 1517 | pRipple.visible = true 1518 | pRipple.scale = 0.4 1519 | pRipple.opacity = 0.2 1520 | 1521 | if pRipple.states.current.name is "selected" 1522 | pRipple.opacity = 0.3 1523 | 1524 | RippleA = new Animation 1525 | layer: pRipple 1526 | properties: 1527 | scale: 0.8 1528 | time: 0.15 1529 | curve: Bezier.linear 1530 | 1531 | RippleB = new Animation 1532 | layer: pRipple 1533 | properties: 1534 | scale: 1 1535 | opacity: 0 1536 | time: 0.15 1537 | curve: Bezier.linear 1538 | 1539 | RippleA.start() 1540 | 1541 | RippleA.onAnimationEnd -> 1542 | RippleB.start() 1543 | 1544 | #------ event ----------------------------------------------------------------------------------------------------- 1545 | 1546 | cont.onMouseOver -> 1547 | this.children[0].borderColor = themeColor 1548 | 1549 | cont.onMouseOut -> 1550 | if this.children[0].states.current.name is "deselected" 1551 | this.children[0].borderColor = boxColor 1552 | 1553 | @onClick -> 1554 | @options.activeSelection = bb 1555 | 1556 | #------ getter and setter ----------------------------------------------------------------------------------------- 1557 | 1558 | @define 'activeSelection', 1559 | get: -> @options.activeSelection 1560 | set: (value) -> @options.activeSelection = value 1561 | 1562 | @define 'theme', 1563 | get: -> @options.theme 1564 | set: (value) -> @options.theme = value 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | ################################################# 7. Switch ######################################################### 1571 | class exports.Switch extends Layer 1572 | 1573 | constructor: (@options={}) -> 1574 | 1575 | #------ Custome properties ----------------------------------------------------------------------------------------- 1576 | 1577 | @options.disableRipple ?= false 1578 | @options.activeOnStart ?= false 1579 | @options.active ?= false 1580 | 1581 | @options.theme ?= "light" 1582 | theme = @options.theme 1583 | 1584 | #------ colors 1585 | @options.themeColor ?= "#009688" 1586 | themeColor = @options.themeColor 1587 | @thumbColor = @options.themeColor 1588 | @trackColor = @options.themeColor 1589 | @thumb_light_off = "#FAFAFA" 1590 | @thumb_dark_off = "#bdbdbd" 1591 | @track_light_off = "rgba(0,0,0,0.38)" 1592 | @track_dark_off = "rgba(255,255,255,0.3)" 1593 | @ripple_dark_off = "rgba(255,255,255, 1)" 1594 | @ripple_light_off = "rgba(0,0,0, 1)" 1595 | 1596 | if @options.theme is "dark" 1597 | @labelColor = label_dark 1598 | @thumbOff = @thumb_dark_off 1599 | @trackOff = @track_dark_off 1600 | @rippleOff = @ripple_dark_off 1601 | else 1602 | @labelColor = label_light 1603 | @thumbOff = @thumb_light_off 1604 | @trackOff = @track_light_off 1605 | @rippleOff = @ripple_light_off 1606 | 1607 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 1608 | 1609 | _.defaults @options, 1610 | backgroundColor : "" 1611 | height: 48 1612 | width : 150 1613 | 1614 | #------ track --------------------------------------------------------------------------------------------------- 1615 | 1616 | @track = new Layer 1617 | width: 40 1618 | height: 15 1619 | borderRadius: 15 1620 | name: "track" 1621 | @track.animationOptions = 1622 | time: 0.2 1623 | 1624 | @track.states = 1625 | on: 1626 | backgroundColor: @options.themeColor 1627 | opacity: 0.5 1628 | off: 1629 | backgroundColor: @trackOff 1630 | opacity: 0.38 1631 | 1632 | delete @track.states.default 1633 | @track.states.switchInstant "off" 1634 | 1635 | #------ ripple ------------------------------------------------------------------------------------------------- 1636 | 1637 | @ripple = new Layer 1638 | size: 50 1639 | scale: 1 1640 | borderRadius: 50 1641 | opacity: 0.2 1642 | visible: false 1643 | name: "ripple" 1644 | backgroundColor: @options.themeColor 1645 | 1646 | #------ thumb ------------------------------------------------------------------------------------------------- 1647 | 1648 | @thumb = new Layer 1649 | size: 19 1650 | borderRadius: 100 1651 | name: "thumb" 1652 | backgroundColor: @thumbOff 1653 | @thumb.animationOptions = 1654 | time: 0.3 1655 | 1656 | @thumb.states = 1657 | on: 1658 | x: 21 1659 | backgroundColor: @options.themeColor 1660 | off: 1661 | x: 0 1662 | backgroundColor: @thumbOff 1663 | 1664 | delete @thumb.states.default 1665 | @thumb.states.switchInstant "off" 1666 | 1667 | #------ label ------------------------------------------------------------------------------------------------- 1668 | 1669 | @label = new Label 1670 | text: @options.labelText 1671 | color: @labelColor 1672 | name: "label" 1673 | 1674 | #------ Super ------------------------------------------------------------------------------------------------- 1675 | 1676 | super @options 1677 | 1678 | @track.parent = @ 1679 | @track.y = Align.center 1680 | 1681 | @thumb.parent = @ 1682 | @thumb.y = Align.center 1683 | 1684 | @label.parent = @ 1685 | @label.x = 55 1686 | @label.y = Align.center 1687 | 1688 | if @options.disableRipple is false 1689 | @ripple.parent = @thumb 1690 | @ripple.x = - 15 1691 | @ripple.y = - 15 1692 | ripple = @ripple 1693 | 1694 | #------ shadows ------------------------------------------------------------------------------------------------- 1695 | 1696 | shadow = new Shadow 1697 | parent: @thumb 1698 | borderRadius: 100 1699 | width: @thumb.width 1700 | height: @thumb.width 1701 | name: "shadow" 1702 | 1703 | #------ activeOnStart --------------------------------------------------------------------------------------------- 1704 | 1705 | if @options.activeOnStart is true 1706 | @thumb.states.switchInstant "on" 1707 | @track.states.switchInstant "on" 1708 | @active = true 1709 | 1710 | #------ ripple animation ------------------------------------------------------------------------------------------ 1711 | 1712 | rippleAni = -> 1713 | 1714 | ripple.visible = true 1715 | ripple.scale = 0.4 1716 | 1717 | pulsaA = new Animation 1718 | layer: ripple 1719 | properties: 1720 | scale: 0.8 1721 | time: 0.15 1722 | curve: Bezier.linear 1723 | 1724 | rippleB = new Animation 1725 | layer: ripple 1726 | properties: 1727 | scale: 1 1728 | opacity: 0 1729 | time: 0.15 1730 | curve: Bezier.linear 1731 | pulsaA.start() 1732 | 1733 | pulsaA.onAnimationEnd -> 1734 | rippleB.start() 1735 | 1736 | #------ event ------------------------------------------------------------------------------------------------- 1737 | 1738 | state = null 1739 | 1740 | @onClick -> 1741 | 1742 | @track.stateCycle() 1743 | @thumb.stateCycle() 1744 | 1745 | if @options.disableRipple is false 1746 | if @thumb.states.current.name is "on" 1747 | @ripple.backgroundColor = @options.themeColor 1748 | @ripple.opacity = 0.4 1749 | posX = 20 1750 | rippleAni() 1751 | @options.active = true 1752 | else 1753 | posX = 0 1754 | @ripple.backgroundColor = @rippleOff 1755 | @ripple.opacity = 0.2 1756 | rippleAni() 1757 | @options.active = false 1758 | 1759 | 1760 | if @thumb.states.current.name is "on" 1761 | @options.active = true 1762 | else 1763 | @options.active = false 1764 | 1765 | #------ getters and setters -------------------------------------------------------------------------------------- 1766 | 1767 | @define 'active', 1768 | get: -> 1769 | @options.active 1770 | set: (value) -> 1771 | @options.active = value 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | ################################################# 8. TextField ###################################################### 1778 | class TextField extends Layer 1779 | 1780 | INPUT_HIDE_PSUEDO_UI = "{ -webkit-appearance: none; display: none; }" 1781 | INPUT_SELECTOR_NUMBER = "input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button" 1782 | INPUT_SELECTOR_SEARCH = "input[type=search]::-webkit-search-cancel-button" 1783 | 1784 | Events.Input = "InputField.OnInput" 1785 | Events.Focus = "InputField.OnFocus" 1786 | Events.Blur = "InputField.OnBlur" 1787 | Events.Valid = "InputField.OnValid" 1788 | Events.Invalid = "InputField.OnInvalid" 1789 | Events.Match = "InputField.OnMatch" 1790 | 1791 | @define "value", 1792 | get: -> 1793 | @input.value 1794 | 1795 | set: (v) -> 1796 | return unless v 1797 | if @input 1798 | @changeInputValue v 1799 | 1800 | constructor: (@options={}) -> 1801 | 1802 | #------- default properties ----------------------------------------------------------------------------------------- 1803 | 1804 | @isNumber = false 1805 | @isSearch = false 1806 | 1807 | @isEmpty = true 1808 | @isValid = null 1809 | @originalTextColor = null 1810 | 1811 | # Framer Layer Props 1812 | @options.name ?= "Basic text field" 1813 | 1814 | @options.borderRadius = 0 1815 | @options.placeHolderFocus ?= null 1816 | @options.placeHolderColor = "" 1817 | @options.placeHolder ?= "" 1818 | 1819 | @options.theme ?= "light" 1820 | theme = @options.theme 1821 | 1822 | #colors 1823 | @options.themeColor ?= "#009688" 1824 | themeColor = @themeColor 1825 | 1826 | if @options.theme is "dark" 1827 | @labelColor = Inputlabel_dark 1828 | @inputColor = input_dark 1829 | @lineColor = "rgba(255,255,255,0.7)" 1830 | @lineHoverColor = "rgba(255,255,255,1)" 1831 | @labelFocusOpacity = 1 1832 | @options.backgroundColor = "rgba(0,0,0,0.01)" 1833 | else 1834 | @labelColor = Inputlabel_light 1835 | @inputColor = input_light 1836 | @lineColor = "rgba(0,0,0,0.42)" 1837 | @lineHoverColor = "rgba(0,0,0,0.87)" 1838 | @labelFocusOpacity = 0.87 1839 | @options.backgroundColor = "rgba(255,255,255,0.01)" 1840 | boxColor = @boxColor 1841 | 1842 | @options.color = @inputColor 1843 | 1844 | 1845 | #text styling 1846 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 1847 | 1848 | if Utils.isMobile() 1849 | @options.fontSize ?= 16 * 2 1850 | @options.lineHeight ?= 24 * 2 1851 | @options.lineHeight = "#{@options.lineHeight}px" if @options.lineHeight? 1852 | @options.height = 70 1853 | else 1854 | @options.fontSize ?= 16 1855 | @options.lineHeight ?= 24 1856 | @options.lineHeight = "#{@options.lineHeight}px" if @options.lineHeight? 1857 | @options.height = 70 1858 | 1859 | @options.labelSize ?=16 1860 | 1861 | @options.fontFamily ?= "'Roboto', sans serif" 1862 | @options.fontWeight ?= 400 1863 | @options.letterSpacing ?= 0 1864 | 1865 | #text html 1866 | @options.helperText ?= "Helper text" 1867 | @options.labelText ?= "Label" 1868 | @options.helperTextVisble ?= false 1869 | 1870 | #Default properties 1871 | _.defaults @options, 1872 | width : 200 1873 | 1874 | #------- Elements -------------------------------------------------------------------------------------------------- 1875 | 1876 | @line = new Layer 1877 | width: @options.width 1878 | height: 1 1879 | clip: true 1880 | name: "line" 1881 | backgroundColor: @lineColor 1882 | 1883 | @lineRipple = new Layer 1884 | backgroundColor: @options.themeColor 1885 | width: 0 1886 | height: 2 1887 | name: "ripple" 1888 | 1889 | @label = new Label 1890 | text: @options.labelText 1891 | fontSize: @options.labelSize 1892 | color: @labelColor 1893 | name: "label" 1894 | 1895 | @helperText = new Label 1896 | fontSize: 12 1897 | text: @options.helperText 1898 | color: @labelColor 1899 | name: "helper Text" 1900 | visible: @options.helperTextVisble 1901 | 1902 | @inputParent = new Layer 1903 | backgroundColor: @options.backgroundColor 1904 | width: @options.width 1905 | height: 28 1906 | name: "input parent" 1907 | 1908 | super @options 1909 | 1910 | @helperText.parent = @line.parent = @inputParent.parent = @ 1911 | @helperText.y = 50 1912 | @label.parent = @ 1913 | @label.y = 20 1914 | @lineRipple.parent = @line 1915 | @lineRipple.x = Align.center 1916 | @line.y = 44 1917 | @inputParent.y = 10 1918 | 1919 | #------- event -------------------------------------------------------------------------------------------------- 1920 | 1921 | @onClick @clicked 1922 | @onTap @clicked 1923 | 1924 | if Utils.isDesktop() 1925 | @onMouseOver @hoverOn 1926 | @onMouseOut @hoverOff 1927 | 1928 | @.on Events.Blur, (value, layer) -> 1929 | @line.height = 1 1930 | @lineRipple.width = 0 1931 | @lineRipple.x = Align.center 1932 | @helperText.color = @labelColor 1933 | @line.backgroundColor = @lineColor 1934 | @options.color = @inputColor 1935 | @label.color = @labelColor 1936 | 1937 | if @.isEmpty 1938 | @label.animate 1939 | properties: 1940 | fontSize: 16 1941 | y: 20 1942 | color: @labelColor 1943 | time: 0.2 1944 | 1945 | #------ Adjust a few things for various types ----------------------------------------------------------------- 1946 | 1947 | switch @options.type 1948 | when "search" then @isSearch = true 1949 | when "number" then @isNumber = true 1950 | when "numbers-only", "number-only" 1951 | @isNumber = true 1952 | @options.type = if @options.pattern? then "number" else "text" 1953 | @options.pattern = if @options.pattern? then @options.pattern else PATTERN_NUMBER 1954 | 1955 | @html += switch 1956 | when @isNumber then "" 1957 | when @isSearch then "" 1958 | else "" 1959 | 1960 | if @options.placeHolderColor? 1961 | @html += "" 1962 | 1963 | #------ creating & styling the input ------------------------------------------------------------------------------- 1964 | 1965 | @input = document.createElement "input" 1966 | 1967 | @input.type = @options.type 1968 | @input.value = @options.value if @options.value? 1969 | @input.placeholder = @options.placeHolder if @options.placeHolder? 1970 | @input.pattern = @options.pattern if @options.pattern? 1971 | @input.setAttribute("maxLength", @options.maxLength) if @options.maxLength? 1972 | @input.setAttribute("autocapitalize", (if @options.autoCapitalize is true then "on" else "off")) 1973 | @input.setAttribute("autocomplete", (if @options.autoComplete is true then "on" else "off")) 1974 | @input.setAttribute("autocorrect", (if @options.autoCorrect is true then "on" else "off")) 1975 | 1976 | @inputParent._element.appendChild @input 1977 | 1978 | # Setup Values 1979 | @isEmpty = !(@options.value?.length > 0) 1980 | @originalTextColor = @options.color 1981 | 1982 | # Setup Input Style 1983 | inputStyle = 1984 | font: "#{@options.fontWeight} #{@options.fontSize}px/#{@options.lineHeight} #{@options.fontFamily}" 1985 | outline: "none" 1986 | textIndent: "#{@options.indent}px" 1987 | backgroundColor: "transparent" 1988 | height: "22px" 1989 | width: "100%" 1990 | pointerEvents: "none" 1991 | margin: "0" 1992 | padding: "0" 1993 | "-webkit-appearance": "none" 1994 | 1995 | @input.style[key] = val for key, val of inputStyle 1996 | @input.style.color = @options.color if @options.color? 1997 | 1998 | 1999 | @input.onfocus = => 2000 | document.body.scrollTop = 0 2001 | @input.placeholder = @options.placeHolderFocus if @options.placeHolderFocus? 2002 | document.body.scrollTop = 0 2003 | @emit(Events.Focus, @input.value, @) 2004 | 2005 | @input.onblur = => 2006 | document.body.scrollTop = 0 2007 | unless @input.placeholder is @options.placeHolder or !@options.placeHolder? 2008 | @input.placeholder = @options.placeHolder 2009 | @emit(Events.Blur, @input.value, @) 2010 | 2011 | @input.oninput = => 2012 | @isEmpty = !( @input.value?.length > 0) 2013 | @emit(Events.Input, @input.value, @) 2014 | 2015 | @on Events.TouchEnd, -> @input.focus() 2016 | @on "change:color", -> @changeInputTextColor() 2017 | 2018 | @on "keydown", (event) -> 2019 | if event.keyCode is 13 2020 | @line.height = 1 2021 | @lineRipple.width = 0 2022 | @lineRipple.x = Align.center 2023 | @helperText.color = @labelColor 2024 | @line.backgroundColor = @lineColor 2025 | @options.color = @inputColor 2026 | @label.color = @labelColor 2027 | 2028 | if @.isEmpty 2029 | @label.animate 2030 | properties: 2031 | fontSize: 16 2032 | y: 20 2033 | color: @labelColor 2034 | time: 0.2 2035 | 2036 | #------ event functions ------------------------------------------------------------------------------- 2037 | 2038 | clear: -> 2039 | @input.value = "" 2040 | @isValid = null 2041 | @isEmpty = true 2042 | 2043 | changeInputTextColor: -> 2044 | @input.style.color = @color.toHexString() 2045 | 2046 | changeInputValue: (v) -> 2047 | @input.value = v 2048 | @input.oninput() 2049 | 2050 | clicked: -> 2051 | @label.animate 2052 | properties: 2053 | fontSize: 12 2054 | y: 0 2055 | color: @options.themeColor 2056 | opacity: @labelFocusOpacity 2057 | time: 0.2 2058 | 2059 | @line.animate 2060 | properties: 2061 | height: 2 2062 | time: 0.2 2063 | 2064 | @lineRipple.animate 2065 | properties: 2066 | width: @options.width 2067 | x: 0 2068 | time: 0.2 2069 | 2070 | hoverOn: -> 2071 | @line.height = 2 2072 | @line.backgroundColor = @lineHoverColor 2073 | 2074 | hoverOff: -> 2075 | @line.height = 1 2076 | @line.backgroundColor = @lineColor 2077 | 2078 | 2079 | 2080 | 2081 | 2082 | 2083 | 2084 | 2085 | 2086 | 2087 | class exports.TextField_Basic extends TextField 2088 | 2089 | constructor: (@options={}) -> 2090 | 2091 | super @options 2092 | 2093 | 2094 | 2095 | 2096 | 2097 | ################################################# 9. TextField_Validation ############################################ 2098 | class exports.TextField_Validation extends TextField 2099 | 2100 | constructor: (@options={}) -> 2101 | 2102 | #------- default properties ---------------------------------------------------------------------------------------- 2103 | # Make sure we set the Checking Flag 2104 | @shouldCheckValidity = true if @options.pattern? or @options.match? 2105 | 2106 | # Framer Layer Props 2107 | @options.name ?= "password field" 2108 | 2109 | @options.type ?= "password" 2110 | @options.pattern ?= "(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$" 2111 | @options.eyeVisible ?= true 2112 | 2113 | @options.color = @inputColor 2114 | 2115 | if @options.theme is "dark" 2116 | @labelColor = Inputlabel_dark 2117 | else 2118 | @labelColor = Inputlabel_light 2119 | 2120 | @red = "#FF1744" 2121 | 2122 | #text html 2123 | @options.helperText ?= "helperText" 2124 | @options.labelText ?= "Password" 2125 | @options.helperTextVisible ?= false 2126 | 2127 | #Default properties 2128 | _.defaults @options, 2129 | backgroundColor : "" 2130 | width : 200 2131 | 2132 | if @options.pattern is "^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).*$" 2133 | @options.helperText ?= "UpperCase, LowerCase and Number" 2134 | else if @options.pattern is "(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$" 2135 | @options.helperText ?= "Must contain 8 characters, 1 uppercase, 1 lowercase, and 1 number/special character" 2136 | else @options.helperText ?= "helperText" 2137 | 2138 | #------- Elements --------------------------------------------------------------------------------------------------- 2139 | 2140 | @errorText = new Label 2141 | fontSize: 12 2142 | text: @options.helperText 2143 | color: @red 2144 | name: "helper Text" 2145 | visible: false 2146 | 2147 | @eyeContianer = new Layer 2148 | width: 22 2149 | height: 22 2150 | backgroundColor: "" 2151 | visible: @options.eyeVisible 2152 | name: "eyeContianer" 2153 | 2154 | @eyeOn = new Layer 2155 | width: 22 2156 | height: 16 2157 | backgroundColor: "" 2158 | visible: false 2159 | name: "eyeOne" 2160 | html: ' ' 2161 | 2162 | @eyeOff = new Layer 2163 | width: 23 2164 | height: 19 2165 | backgroundColor: "" 2166 | visible: true 2167 | name: "eyeOff" 2168 | html: '' 2169 | 2170 | #------- super --------------------------------------------------------------------------------------------------- 2171 | 2172 | super @options 2173 | 2174 | @eyeContianer.parent = @ 2175 | @eyeOn.parent = @eyeOff.parent = @eyeContianer 2176 | @eyeContianer.x = @.width - 22 2177 | @eyeContianer.y = 13 2178 | @eyeOn.y = 0 2179 | @errorText.parent = @ 2180 | @errorText.y = @helperText.y 2181 | 2182 | #------- event ---------------------------------------------------------------------------------------------------- 2183 | 2184 | @onClick @clicked 2185 | @onTap @clicked 2186 | 2187 | if Utils.isDesktop() 2188 | @onMouseOver @hoverOn 2189 | @onMouseOut @hoverOff 2190 | 2191 | eyeOff = @eyeOff 2192 | eyeOn = @eyeOn 2193 | 2194 | @eyeContianer.onClick -> 2195 | if eyeOff.visible is true 2196 | eyeOff.visible = false 2197 | eyeOn.visible = true 2198 | input.type = "text" 2199 | else 2200 | input.type = "password" 2201 | eyeOff.visible = true 2202 | eyeOn.visible = false 2203 | 2204 | @.on Events.Blur, (value, layer) -> 2205 | @label.color = @labelColor 2206 | @line.height = 1 2207 | @lineRipple.width = 0 2208 | @lineRipple.x = Align.center 2209 | 2210 | if @.isEmpty 2211 | @label.animate 2212 | properties: 2213 | fontSize: @options.labelSize 2214 | y: 20 2215 | color: @labelColor 2216 | time: 0.2 2217 | if @helperTextVisible is true 2218 | @helperText.visible = true 2219 | @errorText.visible = false 2220 | else if @isValid 2221 | @line.backgroundColor = @lineColor 2222 | @label.color = @labelColor 2223 | @helperText.color = @labelColor 2224 | if @helperTextVisible is true 2225 | @helperText.visible = true 2226 | @errorText.visible = false 2227 | else 2228 | @line.backgroundColor = @red 2229 | @label.color = @red 2230 | 2231 | @errorText.visible = true 2232 | errorWobble1 = new Animation 2233 | layer: @label 2234 | properties: 2235 | x: 5 2236 | time: 0.05 2237 | errorWobble2 = new Animation 2238 | layer: @label 2239 | properties: 2240 | x: - 5 2241 | time: 0.05 2242 | errorWobble5 = new Animation 2243 | layer: @label 2244 | properties: 2245 | x: 0 2246 | time: 0.025 2247 | errorWobble1.start() 2248 | errorWobble1.onAnimationEnd -> errorWobble2.start() 2249 | errorWobble2.onAnimationEnd -> errorWobble5.start() 2250 | @helperText.visible = false 2251 | 2252 | #------ Adjust a few things for various types -------------------------------------------------------------------- 2253 | 2254 | @input.oninput = => 2255 | @isEmpty = !( @input.value?.length > 0) 2256 | @emit(Events.Input, @input.value, @) 2257 | @checkValidity() 2258 | 2259 | input = @input 2260 | 2261 | checkValidity: -> 2262 | return unless @shouldCheckValidity 2263 | 2264 | if @options.pattern? 2265 | validity = @input.checkValidity() 2266 | @isEmpty = !( @input.value?.length > 0) 2267 | 2268 | if @isValid isnt validity or @isEmpty 2269 | if @isEmpty or !validity 2270 | @isValid = false 2271 | @emit(Events.Invalid, @input.value, @) 2272 | else 2273 | @isValid = true 2274 | @emit(Events.Valid, @input.value, @) 2275 | 2276 | if @checkMatch() 2277 | @isValid = true 2278 | @emit(Events.Match, @input.value, @) 2279 | 2280 | checkMatch: -> 2281 | return false unless @options.match? 2282 | if Array.isArray(@options.match) 2283 | for match in @options.match 2284 | return true if @input.value.indexOf(match) > -1 2285 | else 2286 | return true if @input.value.indexOf(@options.match) > -1 2287 | return false 2288 | 2289 | #--- event functions ---------------------------------------------------------------------------------------------- 2290 | 2291 | clicked: -> 2292 | @label.animate 2293 | properties: 2294 | fontSize: 12 2295 | y: - 6 2296 | color: @options.themeColor 2297 | time: 0.2 2298 | 2299 | @line.animate 2300 | properties: 2301 | height: 2 2302 | time: 0.2 2303 | 2304 | @lineRipple.animate 2305 | properties: 2306 | width: @options.width 2307 | x: 0 2308 | time: 0.2 2309 | 2310 | @line.backgroundColor = @lineColor 2311 | @label.color = @themeColor 2312 | @helperText.color = @labelColor 2313 | @errorText.visible = false 2314 | if @options.helperTextVisible is true 2315 | @helperText.visible = true 2316 | 2317 | hoverOn: -> 2318 | @line.height = 2 2319 | @line.backgroundColor = @lineHoverColor 2320 | 2321 | hoverOff: -> 2322 | @line.height = 1 2323 | @line.backgroundColor = @lineColor 2324 | 2325 | eyeClick: -> 2326 | @eye.stateCycle("visible", "visibleOff") 2327 | 2328 | 2329 | 2330 | 2331 | 2332 | 2333 | ################################################# 10. TextArea ###################################################### 2334 | class exports.TextArea extends Layer 2335 | 2336 | PATTERN_NUMBER = "[0-9]*" 2337 | 2338 | INPUT_HIDE_PSUEDO_UI = "{ -webkit-appearance: none; display: none; }" 2339 | INPUT_SELECTOR_NUMBER = "input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button" 2340 | INPUT_SELECTOR_SEARCH = "input[type=search]::-webkit-search-cancel-button" 2341 | 2342 | Events.Input = "InputField.OnInput" 2343 | Events.Focus = "InputField.OnFocus" 2344 | Events.Blur = "InputField.OnBlur" 2345 | Events.Valid = "InputField.OnValid" 2346 | Events.Invalid = "InputField.OnInvalid" 2347 | Events.Match = "InputField.OnMatch" 2348 | 2349 | @define "value", 2350 | get: -> 2351 | @textarea.value 2352 | 2353 | set: (v) -> 2354 | return unless v 2355 | if @input 2356 | @changeInputValue v 2357 | 2358 | constructor: (@options={}) -> 2359 | 2360 | #------ default properties ------------------------------------------------------------------------------------------- 2361 | 2362 | @isNumber = false 2363 | @isSearch = false 2364 | 2365 | @isEmpty = true 2366 | @isValid = null 2367 | @originalTextColor = null 2368 | 2369 | # Make sure we set the Checking Flag 2370 | @shouldCheckValidity = true if @options.pattern? or @options.match? 2371 | 2372 | # Framer Layer Props 2373 | @options.name ?= "Text area" 2374 | @options.backgroundColor = "rgba(255,255,255,0.01)" 2375 | @options.height ?= 180 2376 | 2377 | # Custom Layer Props 2378 | @options.type ?= "text" 2379 | @options.fontWeight ?= 400 2380 | @options.fontFamily ?= "'Roboto', sans serif" 2381 | @options.indent ?= 0 2382 | @options.placeHolderFocus ?= null 2383 | @options.placeHolderColor ?= null 2384 | @options.width ?= 300 2385 | @options.themeColor ?= "#009688" 2386 | @options.labelText ?= "Type something..." 2387 | 2388 | @options.theme ?= "light" 2389 | theme = @options.theme 2390 | 2391 | #colors 2392 | @options.themeColor ?= "#009688" 2393 | 2394 | themeColor = @options.themeColor 2395 | @red = "#FF1744" 2396 | 2397 | if @options.theme is "dark" 2398 | @labelColor = Inputlabel_dark 2399 | @inputColor = input_dark 2400 | @lineColor = line_dark 2401 | @lineHoverColor = "rgba(255,255,255,1)" 2402 | @labelFocusOpacity = 1 2403 | @lineColor = line_dark 2404 | @options.color = "#fff" 2405 | else 2406 | @labelColor = Inputlabel_light 2407 | @inputColor = input_light 2408 | @lineColor = line_light 2409 | @lineHoverColor = "rgba(0,0,0,0.87)" 2410 | @labelFocusOpacity = 0.87 2411 | @lineColor = line_light 2412 | @options.color = "rgba(0,0,0,0.87)" 2413 | 2414 | @options.color = @inputColor 2415 | 2416 | if Utils.isMobile() 2417 | @options.fontSize ?= 16 * 2 2418 | @options.lineHeight ?= 24 * 2 2419 | @options.style = 2420 | "padding" : "56px 32px 32px 32px" 2421 | else 2422 | @options.fontSize ?= 16 2423 | @options.lineHeight ?= 24 2424 | @options.style = 2425 | "padding" : "28px 16px 16px 16px" 2426 | 2427 | @options.labelSize ?= 16 2428 | 2429 | #text styling 2430 | Utils.insertCSS('@import url(https://fonts.googleapis.com/css?family=Roboto);') 2431 | 2432 | @options.fontFamily ?= "'Roboto', sans serif" 2433 | @options.fontWeight ?= 400 2434 | @options.letterSpacing ?= 0 2435 | @options.limitOn ?= true 2436 | 2437 | if @options.limitOn is false 2438 | @options.characterLimit = 1000000000000 2439 | else @options.characterLimit ?= 200 2440 | 2441 | #------- Elements -------------------------------------- 2442 | 2443 | @label = new Label 2444 | text: @options.labelText 2445 | fontSize: @options.labelSize 2446 | color: @labelColor 2447 | name: "label" 2448 | name: "label" 2449 | 2450 | @limit = new Layer 2451 | html: "0 / " + @options.characterLimit 2452 | backgroundColor: "" 2453 | width: 100 2454 | height: 12 2455 | visible: @options.limitOn 2456 | name: "limit" 2457 | @limit.style = 2458 | color: @labelColor 2459 | fontFamily: @options.fontFamily 2460 | fontSize: "12px" 2461 | lineHeight: "12px" 2462 | textAlign: "right" 2463 | letterSpacing: @options.letterSpacing 2464 | 2465 | @errorText = new Label 2466 | fontSize: 12 2467 | color: @red 2468 | name: "error text" 2469 | visible: false 2470 | text: "Exeeds text limit." 2471 | 2472 | @border = new Layer 2473 | width: @options.width 2474 | height: @options.height 2475 | backgroundColor: "" 2476 | borderWidth: 1 2477 | borderColor: @lineColor 2478 | borderRadius: 2 2479 | name: "border" 2480 | 2481 | #------ super ----------------------------------------------------------------------------------------------------- 2482 | 2483 | super @options 2484 | 2485 | @label.parent = @border.parent = @ 2486 | @limit.parent = @ 2487 | @errorText.parent = @ 2488 | @label.y = 20 2489 | @label.x = 16 2490 | @limit.x = @width - 100 2491 | @limit.y = @height + 8 2492 | @errorText.y = @height + 8 2493 | 2494 | #------- event ----------------------------------------------------------------------------------------------------- 2495 | 2496 | @onClick @clicked 2497 | 2498 | @.on Events.Blur, (value, layer) -> 2499 | @blurred() 2500 | 2501 | @.on Events.Focus, (value, layer) -> 2502 | @focus() 2503 | 2504 | if Utils.isDesktop() 2505 | @.onMouseOver @hoverOn 2506 | @.onMouseOut @hoverOff 2507 | 2508 | @.on Events.Input, (value, layer) -> 2509 | @limit.html = @value.length + " / " + @options.characterLimit 2510 | if @value.length > @options.characterLimit 2511 | @errorText.visible = true 2512 | @limit.color = @red 2513 | @border.borderColor = @red 2514 | @label.color = @red 2515 | else 2516 | @errorText.visible = false 2517 | @limit.color = @labelColor 2518 | @border.borderColor = @options.themeColor 2519 | @label.color = @options.themeColor 2520 | 2521 | #------- Adjust a few things for various types -------------------------------------------------------------------- 2522 | 2523 | switch @options.type 2524 | when "search" then @isSearch = true 2525 | when "number" then @isNumber = true 2526 | when "numbers-only", "number-only" 2527 | @isNumber = true 2528 | @options.type = if @options.pattern? then "number" else "text" 2529 | @options.pattern = if @options.pattern? then @options.pattern else PATTERN_NUMBER 2530 | 2531 | @html += switch 2532 | when @isNumber then "" 2533 | when @isSearch then "" 2534 | else "" 2535 | 2536 | if @options.placeHolderColor? 2537 | @html += "" 2538 | 2539 | #------- create input ------------------------------------------------------------------------------------------- 2540 | 2541 | @textarea = document.createElement "textarea" 2542 | 2543 | @textarea.value = @options.value if @options.value? 2544 | @input.placeholder = @options.placeHolder if @options.placeHolder? 2545 | @textarea.setAttribute("maxLength", @options.maxLength) if @options.maxLength? 2546 | @textarea.setAttribute("autocapitalize", (if @options.autoCapitalize is true then "on" else "off")) 2547 | @textarea.setAttribute("autocomplete", (if @options.autoComplete is true then "on" else "off")) 2548 | @textarea.setAttribute("autocorrect", (if @options.autoCorrect is true then "on" else "off")) 2549 | 2550 | @_element.appendChild @textarea 2551 | 2552 | # Setup Values 2553 | @isEmpty = !(@options.value?.length > 0) 2554 | @originalTextColor = @options.color 2555 | 2556 | # Setup Input Style 2557 | 2558 | @_textAreaStyle = 2559 | fontSize: "#{@options.fontSize}px" 2560 | lineHeight: "#{@options.lineHeight}px" 2561 | fontWeight: "#{@options.fontWeight}" 2562 | fontFamily: "#{@options.fontFamily}" 2563 | outline: "none" 2564 | textIndent: "#{@options.indent}px" 2565 | backgroundColor: "transparent" 2566 | height: "100%" 2567 | width: "100%" 2568 | pointerEvents: "none" 2569 | margin: "0" 2570 | overflow: "hidden" 2571 | resize: "none" 2572 | "-webkit-appearance": "none" 2573 | 2574 | @textarea.style[key] = val for key, val of @_textAreaStyle 2575 | @textarea.style.color = @options.color if @options.color? 2576 | 2577 | @textarea.onfocus = => 2578 | document.body.scrollTop = 0 2579 | @input.placeholder = @options.placeHolderFocus if @options.placeHolderFocus? 2580 | document.body.scrollTop = 0 2581 | @emit(Events.Focus, @textarea.value, @) 2582 | 2583 | @textarea.onblur = => 2584 | document.body.scrollTop = 0 2585 | unless @textarea.placeholder is @options.placeHolder or !@options.placeHolder? 2586 | @input.placeholder = @options.placeHolder 2587 | @emit(Events.Blur, @textarea.value, @) 2588 | 2589 | @_textAreaStyleonblur = => 2590 | document.body.scrollTop = 0 2591 | unless @input.placeholder is @options.placeHolder or !@options.placeHolder? 2592 | @input.placeholder = @options.placeHolder 2593 | @emit(Events.Blur, @input.value, @) 2594 | 2595 | @textarea.oninput = => 2596 | @isEmpty = !( @textarea.value?.length > 0) 2597 | @emit(Events.Input, @textarea.value, @) 2598 | @checkValidity() 2599 | 2600 | @on Events.TouchEnd, -> @textarea.focus() 2601 | @on "change:color", -> @changeInputTextColor() 2602 | 2603 | #Update the height whenever anything changes. 2604 | @textarea.onkeydown = => @_update() 2605 | @textarea.onkeyup = => @_update() 2606 | @textarea.change = => @_update() 2607 | _resizeParent = (layer, parentMinHeight, bottomPadding) -> 2608 | # Variable for parent 2609 | layerParent = layer.parent 2610 | 2611 | # Array to store all children's maxYs 2612 | allChildrenMaxYs = [] 2613 | 2614 | # Push each maxY to an array 2615 | for max in layerParent.children 2616 | allChildrenMaxYs.push(max.maxY) 2617 | 2618 | # Find the bottom-most maxY value 2619 | tallestChildMaxY = Math.max.apply(null, allChildrenMaxYs) 2620 | 2621 | # Store the distance between the bottom of that and the parent layer 2622 | layerParent.height = Math.max(tallestChildMaxY + bottomPadding, parentMinHeight) 2623 | 2624 | # TODO - Maintain the bottom padding of the parent. 2625 | 2626 | # Reflow all the siblings under the text layer 2627 | _reflowSiblings = (layer, layerMaxY) -> 2628 | layerList = layer.parent.children 2629 | for a in [layerList.indexOf(layer)+1...layerList.length] 2630 | yDiff = layerList[a].y - layerMaxY 2631 | layerList[a].y = layer.maxY + yDiff 2632 | # TODO - redo this without the assumption that all siblings after the layer are below it. 2633 | 2634 | # Update height function 2635 | _update: => 2636 | setTimeout => 2637 | layerMaxY = @.maxY 2638 | # Add back any line breaks that the value method gets ride of 2639 | _trueValue = @textarea.value.replace(//g, ">").replace(/&/g, "&").replace(/\n/g, "
 "); 2640 | 2641 | # If it's empty, make sure there's a letter in there to calculate *something* 2642 | if _trueValue.trim() == "" then _trueValue = "a" 2643 | 2644 | # Calculate the height!!! 2645 | calcHeight = Utils.round(Utils.textSize(_trueValue, @_textAreaStyle, {width: @.width}).height, 0) 2646 | 2647 | # Set the height to either the calculated height, or the minHeight, whichever is greater. 2648 | @.height = Math.max(calcHeight, @options.minHeight) 2649 | if @options.reflowSiblings == true then _reflowSiblings(@, layerMaxY) 2650 | if @options.resizeParent == true then _resizeParent(@, @parentOgHeight, @options.parentBottomPadding) 2651 | 2652 | #------- event functions ------------------------------------------------------------------------------------------- 2653 | 2654 | checkValidity: -> 2655 | return unless @shouldCheckValidity 2656 | 2657 | clear: -> 2658 | @input.value = "" 2659 | @isValid = null 2660 | @isEmpty = true 2661 | 2662 | changeInputTextColor: -> 2663 | @input.style.color = @color.toHexString() 2664 | 2665 | changeInputValue: (v) -> 2666 | @input.value = v 2667 | @input.oninput() 2668 | 2669 | clicked: -> 2670 | @label.animate 2671 | properties: 2672 | fontSize: 12 2673 | y: 8 2674 | color: @options.themeColor 2675 | x: 16 2676 | time: 0.2 2677 | @border.borderColor = @options.themeColor 2678 | @border.borderWidth = 2 2679 | 2680 | error: -> 2681 | @borderColor = @red 2682 | 2683 | focus: -> 2684 | @label.fontSize = 12 2685 | @borderColor = @options.themeColor 2686 | @border.borderWidth = 2 2687 | @label.color = @labelColor 2688 | 2689 | hoverOn: -> 2690 | @border.borderWidth = 2 2691 | @options.borderColor = @lineHoverColor 2692 | 2693 | hoverOff: -> 2694 | @border.borderWidth = 1 2695 | @borderColor = @lineColor 2696 | 2697 | blurred: (value, layer) -> 2698 | @label.color = @labelColor 2699 | @border.borderColor = @lineColor 2700 | 2701 | if @.isEmpty 2702 | @label.animate 2703 | properties: 2704 | fontSize: 16 2705 | y: 20 2706 | x: 16 2707 | color: @labelColor 2708 | time: 0.2 2709 | @border.borderColor = @labelColor 2710 | 2711 | if @value.length > @options.characterLimit 2712 | @errorText.visible = true 2713 | @limit.color = @red 2714 | @border.borderColor = @red 2715 | @label.color = @red 2716 | 2717 | @border.borderWidth = 1 2718 | 2719 | 2720 | 2721 | 2722 | 2723 | 2724 | ################################################# 11. TextField_Dropdown ############################################ 2725 | class exports.TextField_Dropdown extends Layer 2726 | constructor: (@options={}) -> 2727 | 2728 | #------ default properties ------------------------------------------------------------------------------------------ 2729 | if @options.theme is "dark" 2730 | @options.screenColor ?= "#000" 2731 | 2732 | @options.choices ?= ["apple", "banana", "blueberry","cantaloupe", "cherry","coconut", "fig", "grape","grapefruit","guava", "kiwifruit", "lemon","lime", "lychee", "mango", "melon", "orange","papaya", "passionfruit", "peach", "pear","pineapple", "plum","pomegranate", "raspberry", "strawberry", "watermelon"] 2733 | @options.labelText ?= "Select a fruit" 2734 | @options.theme ?= "light" 2735 | @options.visibleItems ?= 4 2736 | @options.activeSelection ?= null 2737 | 2738 | #colors 2739 | @options.themeColor ?= "#009688" 2740 | themeColor = @themeColor 2741 | 2742 | if @options.theme is "dark" 2743 | @labelColor = label_dark 2744 | @lineColor = line_dark 2745 | @lineHoverColor = line_dark_hover 2746 | @inputColor = input_dark 2747 | else 2748 | @labelColor = label_light 2749 | @lineColor = line_light 2750 | @lineHoverColor = line_light_hover 2751 | @inputColor = input_light 2752 | 2753 | _.defaults @options, 2754 | backgroundColor : "" 2755 | height: 50 2756 | color: "#E91E63" 2757 | width : 150 2758 | name: "DropDown" 2759 | 2760 | #------ label ------------------------------------------------------------------------------------------------- 2761 | 2762 | @label = new Label 2763 | text: @options.labelText 2764 | color: @labelColor 2765 | name: "label" 2766 | fontSize: 12 2767 | visible: false 2768 | 2769 | @placeHolder = new Label 2770 | text: @options.labelText 2771 | color: @inputColor 2772 | y: 20 2773 | name: "label" 2774 | 2775 | #------ arrow ----------------------------------------------------------------------------------------------- 2776 | 2777 | @arrow = new Layer 2778 | html: '' 2779 | size: 24 2780 | backgroundColor: "" 2781 | color: "#555" 2782 | width:10 2783 | height: 5 2784 | name:"Arrow" 2785 | 2786 | #------ line --------------------------------------------------------------------------------------------------- 2787 | 2788 | @line = new Layer 2789 | height: 1 2790 | width: @options.width 2791 | y: 49 2792 | backgroundColor: @lineColor 2793 | name: "line" 2794 | 2795 | #------ container ----------------------------------------------------------------------------------------------- 2796 | 2797 | @container = new Layer 2798 | width: @options.width 2799 | borderRadius: 2 2800 | backgroundColor: "#fff" 2801 | height: @options.visibleItems * 50 + 20 2802 | clip: true 2803 | name: "container" 2804 | 2805 | #------ super --------------------------------------------------------------------------------------------------- 2806 | 2807 | super @options 2808 | 2809 | @container.states = 2810 | open: 2811 | height: @options.visibleItems * 50 + 20 2812 | y: 0 2813 | closed: 2814 | height: 0 2815 | y: 50 2816 | @container.states.switchInstant "closed" 2817 | @container.animationOptions = time: 0.5 2818 | 2819 | @label.parent = @ 2820 | @placeHolder.parent = @ 2821 | @container.parent = @arrow.parent = @line.parent = @ 2822 | 2823 | @arrow.y = Align.center(2) 2824 | @arrow.x = @options.width - 24 2825 | @container.y = 50 2826 | 2827 | placeHolder = @placeHolder 2828 | label = @label 2829 | container = @container 2830 | activeSelection = @activeSelection 2831 | labelColor = @labelColor 2832 | 2833 | #------ shadows ------------------------------------------------------------------------------------------------- 2834 | 2835 | shadow = new Shadow 2836 | parent: @ 2837 | height: @options.visibleItems * 50 + 20 2838 | width: @width 2839 | borderRadius: @container.borderRadius 2840 | y: 0 2841 | name: "shadows" 2842 | 2843 | for item in shadow.array 2844 | item.states.open = 2845 | y: 0 2846 | height: @options.visibleItems * 50 + 20 2847 | item.states.closed = 2848 | height: 0 2849 | y: 50 2850 | 2851 | item.animationOptions = time: 0.5 2852 | 2853 | item.states.switchInstant "_2dp" 2854 | item.states.switchInstant "closed" 2855 | 2856 | #------ scroll area ------------------------------------------------------------------------------------------ 2857 | 2858 | container_ScrollArea = new ScrollComponent 2859 | parent: @container 2860 | width: @container.width 2861 | backgroundColor: "" 2862 | height: @options.visibleItems * 50 + 20 2863 | name: "scrollArea" 2864 | container_ScrollArea.content.draggable.overdrag = false 2865 | container_ScrollArea.content.draggable.bounce = false 2866 | container_ScrollArea.mouseWheelEnabled = true 2867 | 2868 | #------ slider ------------------------------------------------------------------------------------------ 2869 | 2870 | slider = new SliderComponent 2871 | width: 5 2872 | height: container_ScrollArea.height - 30 2873 | y: 15 2874 | borderRadius: 0 2875 | parent: container_ScrollArea 2876 | x: container_ScrollArea.width - 5 2877 | backgroundColor: "" 2878 | min: 0 2879 | max: (@options.choices.length * 50) - 200 2880 | value: -15 2881 | name: slider 2882 | slider.fill.backgroundColor = "" 2883 | 2884 | slider.knob.backgroundColor = "BDBDBD" 2885 | slider.knob.shadowY = 0 2886 | slider.knob.shadowSpread = 0 2887 | slider.knob.shadowBlur = 0 2888 | slider.knob.borderRadius = 1 2889 | slider.knob.width = 5 2890 | slider.knob.height = 30 2891 | 2892 | slider.on "change:value", -> 2893 | container_ScrollArea.content.y = - this.value 2894 | 2895 | container_ScrollArea.onMove -> 2896 | slider.value = container_ScrollArea.scrollY 2897 | 2898 | #------ choice loop ------------------------------------------------------------------------------------------ 2899 | 2900 | as = null 2901 | 2902 | for i in [0...@options.choices.length] 2903 | choice = new Layer 2904 | parent: container_ScrollArea.content 2905 | width: container_ScrollArea.width 2906 | height: 50 2907 | y: 50 * i + 10 2908 | backgroundColor: "" 2909 | name: "choice" 2910 | 2911 | choice_label = new Label 2912 | text: @options.choices[i] 2913 | parent: choice 2914 | x: 20 2915 | y: Align.center 2916 | name: @options.choices[i] + "label" 2917 | color: label_light 2918 | 2919 | choice.onMouseOver -> 2920 | this.backgroundColor = "#eee" 2921 | 2922 | choice.onMouseOut -> 2923 | this.backgroundColor = "#fff" 2924 | 2925 | choice.onClick -> 2926 | as = this.children[0].text 2927 | placeHolder.text = this.children[0].text 2928 | placeHolder.color = labelColor 2929 | container.states.switch "closed" 2930 | label.visible = true 2931 | for item in shadow.array 2932 | item.states.switch "closed" 2933 | 2934 | container = @container 2935 | 2936 | #------ events --------------------------------------------------------------------------------------------------- 2937 | 2938 | @onClick -> 2939 | for item in shadow.array 2940 | item.states.switch "open" 2941 | container.states.switch "open" 2942 | @activeSelection = as 2943 | 2944 | if Utils.isDesktop() 2945 | @onMouseOver @hoverOn 2946 | @onMouseOut @hoverOff 2947 | 2948 | #------event function --------------------------------------------------------------------------------------------- 2949 | 2950 | hoverOn: -> 2951 | @line.height = 2 2952 | @line.backgroundColor = @lineHoverColor 2953 | 2954 | hoverOff: -> 2955 | @line.height = 1 2956 | @line.backgroundColor = @lineColor 2957 | 2958 | #------ getters and setters ----------------------------------------------------------------------------------------- 2959 | 2960 | @define 'color', 2961 | get: -> 2962 | @options.color 2963 | set: (value) -> 2964 | @options.color = value 2965 | 2966 | @define 'choices', 2967 | get: -> 2968 | @options.choices 2969 | set: (value) -> 2970 | @options.choices = value 2971 | 2972 | @define 'activeSelection', 2973 | get: -> 2974 | @options.activeSelection 2975 | set: (value) -> 2976 | @options.activeSelection = value 2977 | 2978 | 2979 | 2980 | 2981 | 2982 | 2983 | ################################################## 12. AppBar ######################################################## 2984 | class exports.AppBar extends Layer 2985 | 2986 | constructor: (@options={}) -> 2987 | 2988 | #------ default properties ------------------------------------------------------------------------------------------ 2989 | 2990 | @options.width ?= Screen.width 2991 | @options.labelText ?= "Form" 2992 | @options.fontSize ?= 22 2993 | @options.fontWeight ?= 500 2994 | @options.fontFamily ?= "'Roboto', sans serif" 2995 | @options.labelColor = "#fff" 2996 | @options.themeColor ?= "#009688" 2997 | @options.backgroundColor ?= @options.themeColor 2998 | @options.mobile ?= false 2999 | @options.menuIconVisble ?= true 3000 | @options.name ?= "app bar" 3001 | @options.statusIconsY ?= Align.center(-8) 3002 | @options.menuIconY ?= Align.center() 3003 | 3004 | #------ elements ------------------------------------------------------------------------------------------------- 3005 | 3006 | @appCont = new Layer 3007 | height: 56 3008 | width: @options.width 3009 | backgroundColor: "" 3010 | name: "app bar contianer" 3011 | 3012 | if Utils.isMobile() or @options.mobile is true 3013 | @statusBar = new Layer 3014 | width: @options.width 3015 | height: 24 3016 | backgroundColor: "rgba(0,0,0,0.30)" 3017 | name: "status bar" 3018 | @options.height ?= 80 3019 | @appCont.y = 24 3020 | else 3021 | @options.height ?= 56 3022 | 3023 | @menuIcon = new Layer 3024 | size: 48 3025 | backgroundColor: "" 3026 | visible: @options.menuIconVisble 3027 | name: "menu icon" 3028 | 3029 | @title = new TextLayer 3030 | text: @options.labelText 3031 | fontSize: @options.fontSize 3032 | fontFamily: @options.fontFamily 3033 | color: @options.labelColor 3034 | fontWeight: @options.fontWeight 3035 | name: "title" 3036 | 3037 | #------ super ------------------------------------------------------------------------------------------------- 3038 | 3039 | super @options 3040 | 3041 | shadow = new Shadow 3042 | width: @width 3043 | height: @height 3044 | name: "shadows" 3045 | 3046 | shadow.parent = @ 3047 | @title.parent = @ 3048 | @title.y = Align.center() 3049 | @title.x = 16 3050 | @appCont.parent = @ 3051 | @menuIcon.parent = @title.parent = @appCont 3052 | @menuIcon.x = 16 3053 | @menuIcon.y = @options.menuIconY 3054 | 3055 | if @menuIcon.visible is true 3056 | @title.x = 48 + 16 + 16 3057 | 3058 | #------ menu icon ------------------------------------------------------------------------------------------------- 3059 | 3060 | 3061 | menuIcon = new Layer 3062 | html: '' 3063 | width: 18 3064 | height: 12 3065 | parent: @menuIcon 3066 | x: Align.center() 3067 | y: Align.center() 3068 | backgroundColor: "" 3069 | name: "icon" 3070 | 3071 | #------ status bar ------------------------------------------------------------------------------------------------- 3072 | 3073 | if Utils.isMobile() or @options.mobile is true 3074 | @statusBar.parent = @ 3075 | @title.y = Align.center(10) 3076 | 3077 | statusBarTime = new TextLayer 3078 | fontSize: 13 3079 | parent: @statusBar 3080 | y: Align.center 3081 | x: @width - 55 3082 | color : "#fff" 3083 | fontFamily: "'Roboto', sans serif" 3084 | textAlign: "right" 3085 | name: "status bar time" 3086 | 3087 | setTime = () -> 3088 | date = new Date 3089 | minute = date.getMinutes() 3090 | hour = date.getHours() 3091 | 3092 | zone = "AM" 3093 | 3094 | if hour < 10 3095 | hour = '0' + hour 3096 | 3097 | if hour > 12 3098 | hour = hour - 12 3099 | zone = "PM" 3100 | else 3101 | zone = "AM" 3102 | 3103 | if minute < 10 3104 | minute = '0' + minute 3105 | 3106 | statusBarTime.text = "#{hour}:#{minute} #{zone}" 3107 | 3108 | Utils.delay 30, -> 3109 | setTime() 3110 | 3111 | setTime() 3112 | 3113 | statusIcons = new Layer 3114 | name: "status icons" 3115 | parent: @statusBar 3116 | html: '' 3117 | backgroundColor: "" 3118 | width: 53 3119 | height: 16 3120 | y: @options.statusIconsY 3121 | x: @width - statusBarTime.width - 70 3122 | 3123 | @title.y = Align.center 3124 | 3125 | #------ on resize ------------------------------------------------------------------------------------------------- 3126 | 3127 | at = @ 3128 | statusBar = @statusBar 3129 | isMob = @options.mobile 3130 | 3131 | window.onresize = -> 3132 | at.width = Screen.width 3133 | shadow.umbra.width = Screen.width 3134 | shadow.ambient.width = Screen.width 3135 | shadow.penumbra.width = Screen.width 3136 | if Utils.isMobile() or isMob is true 3137 | statusBar.width = Screen.width 3138 | statusBarTime.x = Screen.width - 55 3139 | statusIcons.x = Screen.width - statusBarTime.width - 68 3140 | 3141 | 3142 | 3143 | 3144 | 3145 | 3146 | 3147 | 3148 | 3149 | 3150 | 3151 | 3152 | 3153 | 3154 | 3155 | 3156 | 3157 | 3158 | 3159 | 3160 | 3161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MaterialComponents version 1 2 | 3 | Easily create, use and modify various Material Design components using this simple module. All of the components are design according to eh Material Design Guidelines — hopefully making your prototyping life a little easier. 4 | 5 | — FULL DISCLOSURE — 6 | 1. While I tried to follow the Material Design guidelines as closely as possible — I probably made a mistake here or there where it doesn’t follow the guidelines exactly. 7 | 2. This is my first module that I have shared — and there are still lots (x100) of bugs, especially where icons are involved. 8 | 9 | This version contains 10 | 1. Color 11 | 2. FlatButton 12 | 3. RaisedButton 13 | 4. FAB 14 | 5. Checkboxes 15 | 6. Radio Buttons 16 | 7. Switch 17 | 8. TextField (frankenstiend from Jordan Robert Dobson's InputField) 18 | 9. TextField_Validation (frankenstiend from Jordan Robert Dobson's InputField) 19 | 10. TextArea (frankenstiend from Jordan Robert Dobson's InputField and Blaine Billingsley's Autogrow) 20 | 11. TextField_Dropdown 21 | 12. AppBar 22 | 23 | installation: 24 | 1. put the MaterialComponents.coffee in the 'modules' folder of your prototype. 25 | 2. in your prototype in Framer, add: MaterialComponents = require 'MaterialComponents' 26 | 3. create components by just going: button = new MaterialComponents.RaisedButton 27 | 28 | Enjoy! and let me know if you find any bugs, x 29 | 30 | --------------------------------------------------------------------------------