├── .editorconfig ├── .github ├── CONTRIBUTING.md └── ISSUE_TEMPLATE.md ├── .gitignore ├── .history ├── package_20200211104813.json └── package_20200211105030.json ├── .npmrc ├── .prettierignore ├── .storybook ├── addons.js ├── config.js ├── preview-head.html ├── stories-generator.js └── webpack.config.js ├── LICENSE ├── package-lock.json ├── package.json ├── readme.md ├── src ├── components.d.ts ├── components │ ├── gallery │ │ ├── gallery.css │ │ ├── gallery.tsx │ │ └── readme.md │ ├── organism │ │ ├── organism.css │ │ ├── organism.tsx │ │ └── readme.md │ ├── pay-with-card │ │ ├── pay-with-card.css │ │ ├── pay-with-card.tsx │ │ └── readme.md │ ├── star-rating-scoped │ │ ├── readme.md │ │ ├── star-rating-scoped.css │ │ └── star-rating-scoped.tsx │ ├── star-rating-shadow │ │ ├── readme.md │ │ ├── star-rating-shadow.css │ │ └── star-rating-shadow.tsx │ ├── star-rating │ │ ├── readme.md │ │ ├── star-rating.css │ │ ├── star-rating.spec.ts │ │ ├── star-rating.stories.js │ │ └── star-rating.tsx │ ├── table │ │ ├── readme.md │ │ ├── table.css │ │ ├── table.stories.js │ │ └── table.tsx │ └── test-component │ │ ├── readme.md │ │ ├── test-component.stories.js │ │ └── test-component.tsx ├── core.json └── index.html ├── stencil.config.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in contributing to the Stencil Component Starter! :tada: 4 | 5 | 6 | ## Contributing Etiquette 7 | 8 | Please see our [Contributor Code of Conduct](https://github.com/ionic-team/stencil/blob/master/CODE_OF_CONDUCT.md) for information on our rules of conduct. 9 | 10 | 11 | ## Creating an Issue 12 | 13 | * If you have a question about using Stencil, please ask in the [Stencil Worldwide Slack](https://join.slack.com/t/stencil-worldwide/shared_invite/enQtMjQ2MzkyMTY0MTk0LTQ4ODgzYjFjNjdkNDY3YWVhMmNlMTljMWQxNTM3Yjg0ZTIyZTM1MmU2YWE5YzNjNzE1MmQ3ZTk2NjQ1YzM5ZDM group. 14 | 15 | * It is required that you clearly describe the steps necessary to reproduce the issue you are running into. Although we would love to help our users as much as possible, diagnosing issues without clear reproduction steps is extremely time-consuming and simply not sustainable. 16 | 17 | * The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately. 18 | 19 | * Issues with no clear steps to reproduce will not be triaged. If an issue is labeled with "needs reply" and receives no further replies from the author of the issue for more than 5 days, it will be closed. 20 | 21 | * If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/ionic-team/stencil/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution. 22 | 23 | * Next, [create a new issue](https://github.com/ionic-team/stencil-component-starter/issues/new) that thoroughly explains the problem. Please fill out the populated issue form before submitting the issue. 24 | 25 | 26 | ## Creating a Pull Request 27 | 28 | * We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort. 29 | 30 | * Looking for an issue to fix? Make sure to look through our issues with the [help wanted](https://github.com/ionic-team/stencil-component-starter/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label! 31 | 32 | ### Setup 33 | 34 | 1. Fork the repo. 35 | 2. Clone your fork. 36 | 3. Make a branch for your change. 37 | 4. Run `npm install` (make sure you have [node](https://nodejs.org/en/) and [npm](http://blog.npmjs.org/post/85484771375/how-to-install-npm) installed first) 38 | 39 | 40 | #### Updates 41 | 42 | 1. Unit test. Unit test. Unit test. Please take a look at how other unit tests are written, and you can't write too many tests. 43 | 2. If there is a `*.spec.ts` file located in the components folder, update it to include a test for your change, if needed. If this file doesn't exist, please notify us. 44 | 3. Run `npm run test` or `npm run test.watch` to make sure all tests are working, regardless if a test was added. 45 | 46 | 47 | ## Commit Message Format 48 | 49 | We have very precise rules over how our git commit messages should be formatted. This leads to readable messages that are easy to follow when looking through the project history. We also use the git commit messages to generate our changelog. (Ok you got us, it's basically Angular's commit message format). 50 | 51 | `type(scope): subject` 52 | 53 | #### Type 54 | Must be one of the following: 55 | 56 | * **feat**: A new feature 57 | * **fix**: A bug fix 58 | * **docs**: Documentation only changes 59 | * **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 60 | * **refactor**: A code change that neither fixes a bug nor adds a feature 61 | * **perf**: A code change that improves performance 62 | * **test**: Adding missing tests 63 | * **chore**: Changes to the build process or auxiliary tools and libraries such as documentation generation 64 | 65 | #### Scope 66 | The scope can be anything specifying place of the commit change. For example `renderer`, `compiler`, etc. 67 | 68 | #### Subject 69 | The subject contains succinct description of the change: 70 | 71 | * use the imperative, present tense: "change" not "changed" nor "changes" 72 | * do not capitalize first letter 73 | * do not place a period `.` at the end 74 | * entire length of the commit message must not go over 50 characters 75 | * describe what the commit does, not what issue it relates to or fixes 76 | * **be brief, yet descriptive** - we should have a good understanding of what the commit does by reading the subject 77 | 78 | 79 | #### Adding Documentation 80 | 81 | Please see the [stencil-site](https://github.com/ionic-team/stencil-site) repo to update documentation. 82 | 83 | 84 | ## License 85 | 86 | By contributing your code to the ionic-team/stencil GitHub Repository, you agree to license your contribution under the MIT license. 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Resources:** 2 | Before submitting an issue, please consult our [docs](https://stenciljs.com/). 3 | 4 | **Stencil version:** (run `npm list @stencil/core` from a terminal/cmd prompt and paste output below): 5 | 6 | ``` 7 | insert the output from npm list @stencil/core here 8 | ``` 9 | 10 | **I'm submitting a ...** (check one with "x") 11 | [ ] bug report 12 | [ ] feature request 13 | [ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://stencil-worldwide.slack.com 14 | 15 | **Current behavior:** 16 | 17 | 18 | **Expected behavior:** 19 | 20 | 21 | **Steps to reproduce:** 22 | 24 | 25 | **Related code:** 26 | 27 | ``` 28 | insert any relevant code here 29 | ``` 30 | 31 | **Other information:** 32 | 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | www/ 3 | 4 | *~ 5 | *.sw[mnpcod] 6 | *.log 7 | *.lock 8 | *.tmp 9 | *.tmp.* 10 | log.txt 11 | *.sublime-project 12 | *.sublime-workspace 13 | 14 | .stencil/ 15 | .idea/ 16 | .vscode/ 17 | .sass-cache/ 18 | .versions/ 19 | .history/ 20 | loader/ 21 | node_modules/ 22 | $RECYCLE.BIN/ 23 | 24 | .DS_Store 25 | Thumbs.db 26 | UserInterfaceState.xcuserstate 27 | .env 28 | jest-test-results.json -------------------------------------------------------------------------------- /.history/package_20200211104813.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@madnesslabs/enjin-components", 3 | "version": "0.0.8", 4 | "description": "A set of components to make it easier to build apps", 5 | "module": "dist/esm/index.js", 6 | "main": "dist/index.js", 7 | "types": "dist/types/components.d.ts", 8 | "collection": "dist/collection/collection-manifest.json", 9 | "files": [ 10 | "dist/" 11 | ], 12 | "scripts": { 13 | "prepublish": "npm run build", 14 | "build": "stencil build", 15 | "start": "stencil build --dev --watch --docs", 16 | "test": "stencil test --spec", 17 | "test:e2e": "stencil test --e2e", 18 | "test:snapshot": "stencil test --e2e --screenshot", 19 | "test:generate": "stencil test --spec --json --outputFile=jest-test-results.json", 20 | "test:generate:watch": "stencil test --spec --json --outputFile=jest-test-results.json --watch", 21 | "test:watch": "stencil test --spec --watch", 22 | "story": "npm-run-all --parallel start storybook", 23 | "story:test": "npm run test:generate && npm run story", 24 | "storybook": "start-storybook -p 9001 -c .storybook -s www" 25 | }, 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "@babel/core": "^7.6.0", 29 | "@stencil/core": "^1.4.0", 30 | "@storybook/addon-actions": "5.2.0", 31 | "@storybook/addon-jest": "5.2.0", 32 | "@storybook/addon-notes": "5.2.0", 33 | "@storybook/addon-viewport": "5.2.0", 34 | "@storybook/html": "5.2.0", 35 | "@types/jest": "24.0.25", 36 | "@types/stripe-v3": "^3.1.7", 37 | "babel-loader": "^8.0.6", 38 | "copy-webpack-plugin": "^5.0.4", 39 | "jest": "24.9.0", 40 | "jest-cli": "24.9.0", 41 | "npm-run-all": "^4.1.5", 42 | "write-file-webpack-plugin": "^4.5.1" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/madnesslabs/enjin-components.git" 47 | }, 48 | "author": "Madness Labs", 49 | "license": "MIT", 50 | "bugs": { 51 | "url": "https://github.com/madnesslabs/enjin-components/issues" 52 | }, 53 | "homepage": "https://github.com/madnesslabs/enjin-components" 54 | } 55 | -------------------------------------------------------------------------------- /.history/package_20200211105030.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@madnesslabs/enjin-components", 3 | "version": "0.0.8", 4 | "description": "A set of components to make it easier to build apps", 5 | "module": "dist/index.mjs", 6 | "main": "dist/index.js", 7 | "types": "dist/types/components.d.ts", 8 | "collection": "dist/collection/collection-manifest.json", 9 | "files": [ 10 | "dist/" 11 | ], 12 | "scripts": { 13 | "prepublish": "npm run build", 14 | "build": "stencil build", 15 | "start": "stencil build --dev --watch --docs", 16 | "test": "stencil test --spec", 17 | "test:e2e": "stencil test --e2e", 18 | "test:snapshot": "stencil test --e2e --screenshot", 19 | "test:generate": "stencil test --spec --json --outputFile=jest-test-results.json", 20 | "test:generate:watch": "stencil test --spec --json --outputFile=jest-test-results.json --watch", 21 | "test:watch": "stencil test --spec --watch", 22 | "story": "npm-run-all --parallel start storybook", 23 | "story:test": "npm run test:generate && npm run story", 24 | "storybook": "start-storybook -p 9001 -c .storybook -s www" 25 | }, 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "@babel/core": "^7.6.0", 29 | "@stencil/core": "^1.4.0", 30 | "@storybook/addon-actions": "5.2.0", 31 | "@storybook/addon-jest": "5.2.0", 32 | "@storybook/addon-notes": "5.2.0", 33 | "@storybook/addon-viewport": "5.2.0", 34 | "@storybook/html": "5.2.0", 35 | "@types/jest": "24.0.25", 36 | "@types/stripe-v3": "^3.1.7", 37 | "babel-loader": "^8.0.6", 38 | "copy-webpack-plugin": "^5.0.4", 39 | "jest": "24.9.0", 40 | "jest-cli": "24.9.0", 41 | "npm-run-all": "^4.1.5", 42 | "write-file-webpack-plugin": "^4.5.1" 43 | }, 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/madnesslabs/enjin-components.git" 47 | }, 48 | "author": "Madness Labs", 49 | "license": "MIT", 50 | "bugs": { 51 | "url": "https://github.com/madnesslabs/enjin-components/issues" 52 | }, 53 | "homepage": "https://github.com/madnesslabs/enjin-components" 54 | } 55 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | @madnesslabs:registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .stencil/ 3 | .github/ 4 | www/ 5 | .editorconfig 6 | .gitignore -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import "@storybook/addon-notes/register"; 2 | import "@storybook/addon-viewport/register"; 3 | import "@storybook/addon-knobs/register"; 4 | import "@storybook/addon-a11y/register"; 5 | import "@storybook/addon-actions/register"; 6 | import "@storybook/addon-jest/register"; 7 | import "@storybook/addon-storysource/register"; 8 | import "@storybook/addon-backgrounds/register"; 9 | import "@storybook/addon-links/register"; 10 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { addParameters, configure, addDecorator } from "@storybook/html"; 2 | import { withKnobs } from "@storybook/addon-knobs"; 3 | import { withA11y } from "@storybook/addon-a11y"; 4 | import { withActions, configureActions } from "@storybook/addon-actions"; 5 | import { withLinks } from "@storybook/addon-links"; 6 | import { withTests } from "@storybook/addon-jest"; 7 | import results from "../jest-test-results.json"; 8 | // import buildStencilStories from "./stories-generator"; 9 | 10 | addParameters({ 11 | options: { 12 | panelPosition: "right" 13 | }, 14 | 15 | backgrounds: [ 16 | { name: "white", value: "#ffffff", default: true }, 17 | { name: "light", value: "#eeeeee" }, 18 | { name: "gainsboro", value: "#DCDCDC" }, 19 | { name: "lightgrey", value: "#D3D3D3" }, 20 | { name: "silver", value: "#C0C0C0" }, 21 | { name: "darkgrey", value: "#A9A9A9" }, 22 | { name: "grey", value: "#808080" }, 23 | { name: "dimgrey", value: "#696969" }, 24 | { name: "lightslategrey", value: "#778899" }, 25 | { name: "slategrey", value: "#708090" }, 26 | { name: "darkslategrey", value: "#2F4F4F" }, 27 | { name: "dark", value: "#555555" }, 28 | { name: "black", value: "#000000" } 29 | ] 30 | }); 31 | 32 | addDecorator(withKnobs); 33 | addDecorator(withA11y); 34 | addDecorator(withLinks); 35 | addDecorator(withActions("click")); 36 | addDecorator( 37 | withTests({ 38 | results, 39 | filesExt: ".spec.ts" 40 | }) 41 | ); 42 | 43 | configureActions({ 44 | depth: 100, 45 | // Limit the number of items logged into the actions panel 46 | limit: 20 47 | }); 48 | 49 | const loader = require("../loader/index.cjs.js"); 50 | // const general_stories = require.context('../general-stories', true, /.\.stories\.js$/); 51 | const local_stories = require.context( 52 | "../src", 53 | true, 54 | /\/[^/ ]+?\/.+\/.+\.stories\.js$/ 55 | ); 56 | // const auto_generated_stories = [ 57 | // { 58 | // name: "ALL COMPONENTS|", 59 | // components: require.context( 60 | // "../dist/collection", 61 | // true, 62 | // /\/[^/ ]+?\/(?:[^/]+\/)*?([^/]+)\/\1\.js$/ 63 | // ), 64 | // stories: require.context( 65 | // "../dist/collection", 66 | // true, 67 | // /\/[^/ ]+?\/(?:[^/]+\/)*?([^/]+)\/\1[^/]*?\.stories\.js$/ 68 | // ), 69 | // notes: require.context("../src", true, /\/[^/ ]+?\/.+\/.+\.md$/) 70 | // } 71 | // ]; 72 | 73 | const loadStories = () => { 74 | loader.defineCustomElements(window); 75 | // general_stories.keys().forEach(filename => general_stories(filename)); 76 | local_stories.keys().forEach(filename => local_stories(filename)); 77 | // auto_generated_stories.forEach(({ name, components, stories, notes }) => { 78 | // buildStencilStories(name, components, stories, notes); 79 | // }); 80 | }; 81 | 82 | configure(loadStories, module); 83 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.storybook/stories-generator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Daniel Lehmann 3 | * @Date: 2019/08/23 4 | * @Email: code@dreammedia.info 5 | * @Last modified by: Daniel Lehmann 6 | * @Last modified time: 2019/09/27 7 | * @copyright Daniel Lehmann (code@dreammedia.info) 8 | * 9 | * Heavily inspired and mostly build upon / copied from https://github.com/shanmugapriyaEK/stencil-storybook#readme . 10 | */ 11 | 12 | import path from "path"; 13 | import Case from "case"; 14 | import { storiesOf } from "@storybook/html"; 15 | import * as KNOBS from "@storybook/addon-knobs"; 16 | 17 | const DEFAULT_DATE = new Date(); 18 | 19 | /** 20 | * Given a module, iterates over the exports and returns the first 21 | * one which looks like a stencil component (using duck typing). 22 | */ 23 | function getComponentFromExports(_module) { 24 | const key = Object.keys(_module).find(exportKey => { 25 | const _export = _module[exportKey]; 26 | // does it quack like a stencil class component? 27 | if (_export.prototype && _export.is) { 28 | return true; 29 | } 30 | }); 31 | 32 | return _module[key]; 33 | } 34 | 35 | /** 36 | * Cleans the notes, which should be in markdown format. 37 | * The markdown parser used by the notes addon is not the best, so 38 | * we have to fix some issues before rendering. 39 | */ 40 | function cleanNotes(notes, compKey) { 41 | if (notes) { 42 | 43 | // converting relative links into storybook links 44 | if (compKey) { 45 | let component = compKey.split('/'); 46 | component.pop(); 47 | component.shift(); 48 | 49 | if (component.length) { 50 | component.unshift('/info/all-components'); 51 | let links = [], link, i, l; 52 | let reg_exp = /\[[^\]]+?\]\(([^\)]+?)\)/g; 53 | 54 | while (link = reg_exp.exec(notes)) { 55 | let path = link[1].split("\\"); 56 | if (path.length < 2) path = link[1].split("/"); 57 | if (path.length < 2) continue; 58 | if (path[0] != "..") continue; 59 | 60 | let final = component.concat(); 61 | let name = path.pop(); 62 | while (path[0] == "..") { 63 | final.pop(); 64 | path.shift(); 65 | } 66 | final = final.concat(path); 67 | links.push([link[1], final.join("-")+"--"+name]); 68 | } 69 | 70 | for (i=0, l=links.length; i { 87 | 88 | const _module = componentsCtx(compKey); 89 | const Component = getComponentFromExports(_module); 90 | 91 | if (!Component) return obj; 92 | 93 | const compName = path.basename(path.dirname(compKey)); 94 | const dirName = "/" + compName + "/"; 95 | const noteKey = notesKeys.find(k => k.indexOf(dirName+"readme.md") > -1); 96 | const stories_keys = storiesKeys.filter(k => { 97 | const reg_exp = new RegExp(dirName+compName+"[^/]*?\\.stories\\.js$"); 98 | return k.search(reg_exp) > -1; 99 | }); 100 | 101 | let _name_path = path.dirname(compKey).split("/"); 102 | _name_path.shift(); 103 | _name_path.pop(); 104 | _name_path = _name_path.join("/"); 105 | if (_name_path) _name_path = "/" + _name_path; 106 | 107 | let _stories_paths = []; 108 | for (let i = 0; i < stories_keys.length; i++) { 109 | const _regExp_paths = /\\n[ ]*?storiesOf[ ]*?\([ ]*?('|"|`)(.+?)\1[ ]*?,[ ]*?module[ ]*?\)/g; 110 | let _paths; 111 | while ( 112 | (_paths = _regExp_paths.exec(storiesCtx(stories_keys[i]).default)) 113 | ) { 114 | if (_paths.length >= 2) _stories_paths.push(_paths[2]); 115 | } 116 | } 117 | 118 | if (noteKey) { 119 | const _notes = notesCtx(noteKey).default; 120 | 121 | // If the default export is a function, then that function should 122 | // be used to create the story. It will be passed the "stories" object 123 | // where it should call stories.add(...) manually. 124 | 125 | return Object.assign(obj, { 126 | [Component.name]: { 127 | Component, 128 | notes: cleanNotes(_notes, compKey), 129 | name_path: _name_path, 130 | stories_paths: _stories_paths 131 | } 132 | }); 133 | } 134 | 135 | return Object.assign(obj, { 136 | [Component.name]: { 137 | Component, 138 | name_path: _name_path, 139 | stories_paths: _stories_paths 140 | } 141 | }); 142 | }, {}); 143 | } 144 | 145 | /** 146 | * Given a stencil Component and knob options, returns an dictionary of 147 | * all the properties and default values. 148 | */ 149 | function getPropsWithKnobValues(Component, knobOptions = {}) { 150 | if (!Component.properties) return {}; 151 | 152 | return Object.keys(Component.properties).reduce((obj, key) => { 153 | const property = Component.properties[key]; 154 | 155 | // normalize older "attr" into newer "attribute" property 156 | if (property.hasOwnProperty("attr")) { 157 | property.attribute = property.attr; 158 | } 159 | 160 | if (property.hasOwnProperty("attribute")) { 161 | obj[key] = getKnobForProp(property, knobOptions); 162 | } 163 | 164 | return obj; 165 | }, {}); 166 | } 167 | 168 | /** 169 | * Given a property (from stencil Component.properties) and an optional 170 | * knobOptions object generates a knob which can be used to 171 | * dynamically update the properties of the component. 172 | */ 173 | function getKnobForProp(prop, knobOptions = {}) { 174 | let type = "text"; 175 | let args = [prop.attribute]; 176 | 177 | // knob options can defined using camelCase or kebab-case 178 | const propCamel = Case.camel(prop.attribute); 179 | const options = knobOptions[propCamel] || knobOptions[prop.attribute]; 180 | 181 | // if knob options are defined, use those 182 | if (options) { 183 | type = options.type; 184 | args = args.concat(options.args); 185 | } 186 | 187 | // otherwise, implicitly create knobs based on prop type or attribute name 188 | else if (/^(?:number|boolean|object)$/i.test(prop.type)) { 189 | type = prop.type.toLowerCase(); 190 | } else if (prop.attribute.indexOf("date") !== -1) { 191 | type = "date"; 192 | args[1] = DEFAULT_DATE; 193 | } else if (prop.attribute.indexOf("color") !== -1) { 194 | type = "color"; 195 | } 196 | 197 | if (prop.defaultValue) { 198 | let default_value = prop.defaultValue; 199 | if (prop.type == "string") { 200 | if (default_value.substr(0, 1) == "'" && default_value.substr(-1) == "'") 201 | default_value = '"' + default_value.substr(1, default_value.length - 2) + '"'; 202 | if (default_value.substr(0, 1) == "`" && default_value.substr(-1) == "`") 203 | default_value = '"' + default_value.substr(1, default_value.length - 2) + '"'; 204 | } 205 | try { 206 | if (["{", "["].indexOf(default_value.substr(0, 1)) >= 0) { 207 | type = "object"; 208 | eval(`default_value = ${default_value};`); 209 | args[1] = default_value; 210 | } else { 211 | args[1] = JSON.parse(default_value); 212 | } 213 | } catch (error) { 214 | console.log("Error setting default value to knob.", error); 215 | } 216 | } 217 | 218 | //console.log('generating', type, 'knob with args:', args); 219 | 220 | const val = KNOBS[type].apply(null, args); 221 | 222 | switch (type) { 223 | // knobs returns UNIX timestamp for "date" type 224 | // and we need to convert it to ISO-8601 225 | case "date": 226 | return new Date(val).toISOString(); 227 | } 228 | 229 | return val; 230 | } 231 | 232 | /** 233 | * Generates an interactive knobs-enabled story for a stencil Component. 234 | * For any additional states, a static rendering is generated with 235 | * the given state (see existing components for examples). 236 | * 237 | * Example "states" array: 238 | * 239 | * [{ 240 | * title: 'A title for this state', 241 | * description: 'A description of why this state exists', 242 | * props: { 243 | * --- props to set on your component --- 244 | * } 245 | * }] 246 | * 247 | * Example "knobs" config: 248 | * 249 | * { 250 | * someProp: { // A decorated @Prop() on your component 251 | * type: 'color', // The type of "knob" to use in the knobs panel 252 | * args: [ // Additional arguments to pass to the knob **after the "label" argument** 253 | * '#ff99cc', // The defaultValue for the "color" knob 254 | * 'GROUP-1' // The groupId for the "color" knob 255 | * ] 256 | * } 257 | * } 258 | */ 259 | function createStencilStory( 260 | { Component, notes, states, knobs, stories_paths }, 261 | stories 262 | ) { 263 | // It is important that the main container element 264 | // is NOT created inside of the render function below!! 265 | const mainEl = document.createElement("div"); 266 | const storyOpts = notes ? { notes } : {}; 267 | const tag = Component.is; 268 | 269 | mainEl.className = "stencil-component-story"; 270 | 271 | // Clone the "states" array and add the default state first 272 | states = states && states.length ? states.slice(0) : []; 273 | states.unshift({ 274 | title: "Default state (use Knobs to edit properties):", 275 | tag: Component.is, 276 | props: {} 277 | }); 278 | 279 | let dashed = Component.name.replace(/[A-Z]/g, m => "-" + m.toLowerCase()); 280 | 281 | // Create the story with all of the states 282 | stories.add( 283 | dashed.substr(1), 284 | () => { 285 | mainEl.innerHTML = ""; 286 | 287 | // First, add the knobs-enabled props to the default state. 288 | // This MUST be done inside this render function!! 289 | states[0].props = getPropsWithKnobValues(Component, knobs); 290 | 291 | // Next, render each state. Only the first one is interactive (with knobs). 292 | // This is sort of a light-weight "chapters" addon because the community 293 | // "chapters" addon only works with react :/ 294 | 295 | states.forEach(({ title, description, props }) => { 296 | const containerEl = document.createElement("div"); 297 | const componentEl = document.createElement(tag); 298 | 299 | Object.keys(props).forEach(prop => { 300 | componentEl[prop] = props[prop]; 301 | }); 302 | 303 | containerEl.innerHTML = getStencilTemplate({ 304 | title, 305 | description, 306 | tag, 307 | props, 308 | stories_paths 309 | }); 310 | 311 | containerEl 312 | .querySelector(`.stencil-component-story-placeholder`) 313 | .appendChild(componentEl); 314 | mainEl.appendChild(containerEl); 315 | }); 316 | 317 | return mainEl; 318 | }, 319 | storyOpts 320 | ); 321 | } 322 | 323 | /** 324 | * Template used to render a single stencil component. To use this template 325 | * do something like the following code snippet: 326 | * 327 | * ``` 328 | * const container = document.createElement('div'); 329 | * const component = document.createElement('your-component'); 330 | * container.innerHTML = getStencilTemplate('Some Title', 'Some Description'); 331 | * container.querySelector('.stencil-component-story-placeholder').appendChild(component); 332 | * ``` 333 | */ 334 | function getStencilTemplate({ title, description, tag, props, stories_paths }) { 335 | // build attribute="value" strings 336 | const attrs = Object.keys(props || {}) 337 | .filter(prop => props[prop] != null) 338 | .map(prop => { 339 | return `${Case.kebab(prop)}={${JSON.stringify(props[prop])}}`; 340 | }) 341 | .join(" "); 342 | 343 | let template = 344 | ` 345 |

${title}

346 | ${description ? "

" + description + "

" : ""} 347 |
348 |
349 |
` +
350 |     `<${tag}${attrs ? " " + attrs : ""}></${tag}>` +
351 |     `
352 | Select Code 353 |
354 | `; 355 | 356 | if (stories_paths.length) { 357 | template += 358 | '

Example' + 359 | (stories_paths.length > 1 ? "s" : "") + 360 | "

"; 361 | for (let i = 0; i < stories_paths.length; i++) { 362 | template += 363 | '
' + 366 | stories_paths[i] + 367 | "
"; 368 | } 369 | template += "
"; 370 | } 371 | 372 | return template; 373 | } 374 | 375 | /** 376 | * Iterates over all of the stencil contexts and builds a "config" object 377 | * which is used to generate the individual stories. 378 | */ 379 | function buildStencilStories(name, components, stories, notes) { 380 | const configs = buildGeneratorConfigs(components, stories, notes); 381 | 382 | Object.keys(configs) 383 | .map(comp => configs[comp]) 384 | .forEach(config => { 385 | const stories_of = storiesOf(name + config.name_path, module); 386 | createStencilStory(config, stories_of); 387 | }); 388 | } 389 | 390 | export default buildStencilStories; 391 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | // Export a function. Accept the base config as the only param. 4 | module.exports = async ({ config, mode }) => { 5 | // `mode` has a value of 'DEVELOPMENT' or 'PRODUCTION' 6 | // You can change the configuration based on that. 7 | // 'PRODUCTION' is used when building the static version of storybook. 8 | config.entry.push('webpack-hot-middleware/client.js?reload=true'); 9 | config.mode = process.env.NODE_ENV || "development"; 10 | config.devServer = { 11 | watchContentBase: true, 12 | contentBase: path.join(__dirname, "src"), 13 | historyApiFallback: true 14 | }; 15 | 16 | config.module.rules[0].use[0].options.sourceType = "unambiguous"; 17 | 18 | config.module.rules.push({ 19 | test: /.\.stories\.js$/, 20 | loaders: [require.resolve("@storybook/addon-storysource/loader")], 21 | enforce: "pre" 22 | }); 23 | 24 | config.module.rules.push({ 25 | test: /.\.stories\.js$/, 26 | exclude: /(src|general-stories)/, 27 | loader: require.resolve("raw-loader") 28 | }); 29 | config.resolve.extensions.push(".stories.js"); 30 | 31 | config.resolve.alias = { 32 | "@src": path.resolve(__dirname, "../dist/collection") 33 | }; 34 | 35 | return config; 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ionic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@madnesslabs/enjin-components", 3 | "namespace": "enjin", 4 | "version": "0.0.10", 5 | "description": "A set of components to make it easier to build apps", 6 | "main": "./dist/index.cjs.js", 7 | "module": "./dist/index.js", 8 | "es2015": "./dist/esm/index.mjs", 9 | "es2017": "./dist/esm/index.mjs", 10 | "types": "./dist/types/components.d.ts", 11 | "unpkg": "./dist/enjin-components/enjin-components.js", 12 | "collection:main": "./dist/collection/index.js", 13 | "collection": "./dist/collection/collection-manifest.json", 14 | "files": [ 15 | "dist/" 16 | ], 17 | "jest": { 18 | "preset": "@stencil/core/testing" 19 | }, 20 | "scripts": { 21 | "prepublish": "npm run build", 22 | "build": "stencil build", 23 | "build:watch": "stencil build --docs --watch", 24 | "start": "stencil build --serve --dev --watch --docs", 25 | "test": "stencil test --spec", 26 | "test:e2e": "stencil test --e2e", 27 | "test:snapshot": "stencil test --e2e --screenshot", 28 | "test:generate": "stencil test --spec --json --outputFile=jest-test-results.json", 29 | "test:generate:watch": "stencil test --spec --json --outputFile=jest-test-results.json --watch", 30 | "test:watch": "stencil test --spec --watch", 31 | "story": "npm-run-all --parallel build:watch storybook", 32 | "story:test": "npm run test:generate && npm run story", 33 | "storybook": "start-storybook -p 9001 -c .storybook -s www" 34 | }, 35 | "dependencies": {}, 36 | "devDependencies": { 37 | "@babel/core": "^7.14.6", 38 | "@stencil/core": "^2.6.0", 39 | "@storybook/addon-jest": "6.2.9", 40 | "@storybook/addon-a11y": "^6.2.9", 41 | "@storybook/addon-actions": "^6.2.9", 42 | "@storybook/addon-backgrounds": "^6.2.9", 43 | "@storybook/addon-knobs": "^6.2.9", 44 | "@storybook/addon-links": "^6.2.9", 45 | "@storybook/addon-notes": "^5.3.21", 46 | "@storybook/addon-storysource": "^6.2.9", 47 | "@storybook/addon-viewport": "^6.2.9", 48 | "@storybook/html": "^6.2.9", 49 | "@types/jest": "26.0.23", 50 | "@types/stripe-v3": "^3.1.15", 51 | "babel-loader": "^8.0.6", 52 | "copy-webpack-plugin": "^5.1.1", 53 | "jest": "27.0.4", 54 | "jest-cli": "27.0.4", 55 | "npm-run-all": "^4.1.5", 56 | "write-file-webpack-plugin": "^4.5.1" 57 | }, 58 | "repository": { 59 | "type": "git", 60 | "url": "git+https://github.com/madnesslabs/enjin-components.git" 61 | }, 62 | "author": "Madness Labs", 63 | "license": "MIT", 64 | "bugs": { 65 | "url": "https://github.com/madnesslabs/enjin-components/issues" 66 | }, 67 | "homepage": "https://github.com/madnesslabs/enjin-components" 68 | } 69 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![Built With Stencil](https://img.shields.io/badge/-Built%20With%20Stencil-16161d.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI%2BCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI%2BCgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cjwvc3R5bGU%2BCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MjQuNywzNzMuOWMwLDM3LjYtNTUuMSw2OC42LTkyLjcsNjguNkgxODAuNGMtMzcuOSwwLTkyLjctMzAuNy05Mi43LTY4LjZ2LTMuNmgzMzYuOVYzNzMuOXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTQyNC43LDI5Mi4xSDE4MC40Yy0zNy42LDAtOTIuNy0zMS05Mi43LTY4LjZ2LTMuNkgzMzJjMzcuNiwwLDkyLjcsMzEsOTIuNyw2OC42VjI5Mi4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNDI0LjcsMTQxLjdIODcuN3YtMy42YzAtMzcuNiw1NC44LTY4LjYsOTIuNy02OC42SDMzMmMzNy45LDAsOTIuNywzMC43LDkyLjcsNjguNlYxNDEuN3oiLz4KPC9zdmc%2BCg%3D%3D&colorA=16161d&style=flat-square) 2 | 3 | # Enjin Components 4 | 5 | This is a set of components to aide in the app bulding process. 6 | 7 | # Stencil 8 | 9 | Stencil is a compiler for building fast web apps using Web Components. 10 | 11 | Stencil combines the best concepts of the most popular frontend frameworks into a compile-time rather than run-time tool. Stencil takes TypeScript, JSX, a tiny virtual DOM layer, efficient one-way data binding, an asynchronous rendering pipeline (similar to React Fiber), and lazy-loading out of the box, and generates 100% standards-based Web Components that run in any browser supporting the Custom Elements v1 spec. 12 | 13 | Stencil components are just Web Components, so they work in any major framework or with no framework at all. 14 | 15 | ## Getting Started 16 | 17 | To start building a new web component using Stencil, clone this repo to a new directory: 18 | 19 | ```bash 20 | git clone https://github.com/ionic-team/stencil-component-starter.git my-component 21 | cd my-component 22 | git remote rm origin 23 | ``` 24 | 25 | and run: 26 | 27 | ```bash 28 | npm install 29 | npm start 30 | ``` 31 | 32 | To build the component for production, run: 33 | 34 | ```bash 35 | npm run build 36 | ``` 37 | 38 | To run the unit tests for the components, run: 39 | 40 | ```bash 41 | npm test 42 | ``` 43 | 44 | Need help? Check out our docs [here](https://stenciljs.com/docs/my-first-component). 45 | 46 | 47 | ## Naming Components 48 | 49 | When creating new component tags, we recommend _not_ using `stencil` in the component name (ex: ``). This is because the generated component has little to nothing to do with Stencil; it's just a web component! 50 | 51 | Instead, use a prefix that fits your company or any name for a group of related components. For example, all of the Ionic generated web components use the prefix `ion`. 52 | 53 | 54 | ## Using this component 55 | 56 | ### Script tag 57 | 58 | - [Publish to NPM](https://docs.npmjs.com/getting-started/publishing-npm-packages) 59 | - Put a script tag similar to this `` in the head of your index.html 60 | - Then you can use the element anywhere in your template, JSX, html etc 61 | 62 | ### Node Modules 63 | - Run `npm install my-component --save` 64 | - Put a script tag similar to this `` in the head of your index.html 65 | - Then you can use the element anywhere in your template, JSX, html etc 66 | 67 | ### In a stencil-starter app 68 | - Run `npm install my-component --save` 69 | - Add an import to the npm packages `import my-component;` 70 | - Then you can use the element anywhere in your template, JSX, html etc 71 | -------------------------------------------------------------------------------- /src/components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* tslint:disable */ 3 | /** 4 | * This is an autogenerated file created by the Stencil compiler. 5 | * It contains typing information for all components that exist in this project. 6 | */ 7 | import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; 8 | export namespace Components { 9 | interface EnjinGallery { 10 | } 11 | interface EnjinOrganism { 12 | /** 13 | * A description of what the organism does 14 | */ 15 | "description"?: string; 16 | /** 17 | * The name of the organism 18 | */ 19 | "name": string; 20 | /** 21 | * A list of props with descriptions 22 | */ 23 | "propList"?: { 24 | /** 25 | * The name of the prop 26 | */ 27 | name: string; 28 | /** 29 | * A description of the prop 30 | */ 31 | description: string; 32 | }[]; 33 | /** 34 | * Shrink organism to only show name and description 35 | */ 36 | "viewLess": () => Promise; 37 | /** 38 | * Expand organism to show preview frame and props info 39 | */ 40 | "viewMore": (options?: { scrollIntoView: boolean; }) => Promise; 41 | } 42 | interface EnjinPayWithCard { 43 | "stripeKey": string; 44 | } 45 | interface EnjinStarRating { 46 | /** 47 | * Whether or not the field is disabled 48 | */ 49 | "disabled": boolean; 50 | /** 51 | * The max available star rating 52 | */ 53 | "maxRating": number; 54 | /** 55 | * The name of the input 56 | */ 57 | "name": string; 58 | /** 59 | * Set the current rating 60 | */ 61 | "setCurrentRating": (rating: any) => Promise; 62 | /** 63 | * The value of the rating input 64 | */ 65 | "value": string; 66 | } 67 | interface EnjinStarRatingScoped { 68 | "disabled": boolean; 69 | "maxRating": number; 70 | "name": string; 71 | "setCurrentRating": (rating: any) => Promise; 72 | "value": string; 73 | } 74 | interface EnjinStarRatingShadow { 75 | "disabled": boolean; 76 | "maxRating": number; 77 | "name": string; 78 | "setCurrentRating": (rating: any) => Promise; 79 | "value": string; 80 | } 81 | interface EnjinTable { 82 | /** 83 | * The columns to show for the table 84 | */ 85 | "columns": { 86 | header: string; 87 | type?: "date"; 88 | key?: string; 89 | value?: string; 90 | sortable?: boolean; 91 | }[]; 92 | /** 93 | * The rows of data to display 94 | */ 95 | "rows": any[]; 96 | } 97 | interface EnjinTestComponent { 98 | } 99 | } 100 | declare global { 101 | interface HTMLEnjinGalleryElement extends Components.EnjinGallery, HTMLStencilElement { 102 | } 103 | var HTMLEnjinGalleryElement: { 104 | prototype: HTMLEnjinGalleryElement; 105 | new (): HTMLEnjinGalleryElement; 106 | }; 107 | interface HTMLEnjinOrganismElement extends Components.EnjinOrganism, HTMLStencilElement { 108 | } 109 | var HTMLEnjinOrganismElement: { 110 | prototype: HTMLEnjinOrganismElement; 111 | new (): HTMLEnjinOrganismElement; 112 | }; 113 | interface HTMLEnjinPayWithCardElement extends Components.EnjinPayWithCard, HTMLStencilElement { 114 | } 115 | var HTMLEnjinPayWithCardElement: { 116 | prototype: HTMLEnjinPayWithCardElement; 117 | new (): HTMLEnjinPayWithCardElement; 118 | }; 119 | interface HTMLEnjinStarRatingElement extends Components.EnjinStarRating, HTMLStencilElement { 120 | } 121 | var HTMLEnjinStarRatingElement: { 122 | prototype: HTMLEnjinStarRatingElement; 123 | new (): HTMLEnjinStarRatingElement; 124 | }; 125 | interface HTMLEnjinStarRatingScopedElement extends Components.EnjinStarRatingScoped, HTMLStencilElement { 126 | } 127 | var HTMLEnjinStarRatingScopedElement: { 128 | prototype: HTMLEnjinStarRatingScopedElement; 129 | new (): HTMLEnjinStarRatingScopedElement; 130 | }; 131 | interface HTMLEnjinStarRatingShadowElement extends Components.EnjinStarRatingShadow, HTMLStencilElement { 132 | } 133 | var HTMLEnjinStarRatingShadowElement: { 134 | prototype: HTMLEnjinStarRatingShadowElement; 135 | new (): HTMLEnjinStarRatingShadowElement; 136 | }; 137 | interface HTMLEnjinTableElement extends Components.EnjinTable, HTMLStencilElement { 138 | } 139 | var HTMLEnjinTableElement: { 140 | prototype: HTMLEnjinTableElement; 141 | new (): HTMLEnjinTableElement; 142 | }; 143 | interface HTMLEnjinTestComponentElement extends Components.EnjinTestComponent, HTMLStencilElement { 144 | } 145 | var HTMLEnjinTestComponentElement: { 146 | prototype: HTMLEnjinTestComponentElement; 147 | new (): HTMLEnjinTestComponentElement; 148 | }; 149 | interface HTMLElementTagNameMap { 150 | "enjin-gallery": HTMLEnjinGalleryElement; 151 | "enjin-organism": HTMLEnjinOrganismElement; 152 | "enjin-pay-with-card": HTMLEnjinPayWithCardElement; 153 | "enjin-star-rating": HTMLEnjinStarRatingElement; 154 | "enjin-star-rating-scoped": HTMLEnjinStarRatingScopedElement; 155 | "enjin-star-rating-shadow": HTMLEnjinStarRatingShadowElement; 156 | "enjin-table": HTMLEnjinTableElement; 157 | "enjin-test-component": HTMLEnjinTestComponentElement; 158 | } 159 | } 160 | declare namespace LocalJSX { 161 | interface EnjinGallery { 162 | } 163 | interface EnjinOrganism { 164 | /** 165 | * A description of what the organism does 166 | */ 167 | "description"?: string; 168 | /** 169 | * The name of the organism 170 | */ 171 | "name"?: string; 172 | /** 173 | * A list of props with descriptions 174 | */ 175 | "propList"?: { 176 | /** 177 | * The name of the prop 178 | */ 179 | name: string; 180 | /** 181 | * A description of the prop 182 | */ 183 | description: string; 184 | }[]; 185 | } 186 | interface EnjinPayWithCard { 187 | "onEnjinCardSubmit"?: (event: CustomEvent) => void; 188 | "stripeKey"?: string; 189 | } 190 | interface EnjinStarRating { 191 | /** 192 | * Whether or not the field is disabled 193 | */ 194 | "disabled"?: boolean; 195 | /** 196 | * The max available star rating 197 | */ 198 | "maxRating"?: number; 199 | /** 200 | * The name of the input 201 | */ 202 | "name"?: string; 203 | "onEnjinStarRating"?: (event: CustomEvent) => void; 204 | /** 205 | * The value of the rating input 206 | */ 207 | "value"?: string; 208 | } 209 | interface EnjinStarRatingScoped { 210 | "disabled"?: boolean; 211 | "maxRating"?: number; 212 | "name"?: string; 213 | "onFtStarRating"?: (event: CustomEvent) => void; 214 | "value"?: string; 215 | } 216 | interface EnjinStarRatingShadow { 217 | "disabled"?: boolean; 218 | "maxRating"?: number; 219 | "name"?: string; 220 | "onFtStarRating"?: (event: CustomEvent) => void; 221 | "value"?: string; 222 | } 223 | interface EnjinTable { 224 | /** 225 | * The columns to show for the table 226 | */ 227 | "columns"?: { 228 | header: string; 229 | type?: "date"; 230 | key?: string; 231 | value?: string; 232 | sortable?: boolean; 233 | }[]; 234 | /** 235 | * Fires when the column header is clicked 236 | */ 237 | "onEnjinSort"?: (event: CustomEvent<{ 238 | event: any; 239 | sort: { ["key"]?: "asc" | "desc" }; 240 | }>) => void; 241 | /** 242 | * The rows of data to display 243 | */ 244 | "rows"?: any[]; 245 | } 246 | interface EnjinTestComponent { 247 | } 248 | interface IntrinsicElements { 249 | "enjin-gallery": EnjinGallery; 250 | "enjin-organism": EnjinOrganism; 251 | "enjin-pay-with-card": EnjinPayWithCard; 252 | "enjin-star-rating": EnjinStarRating; 253 | "enjin-star-rating-scoped": EnjinStarRatingScoped; 254 | "enjin-star-rating-shadow": EnjinStarRatingShadow; 255 | "enjin-table": EnjinTable; 256 | "enjin-test-component": EnjinTestComponent; 257 | } 258 | } 259 | export { LocalJSX as JSX }; 260 | declare module "@stencil/core" { 261 | export namespace JSX { 262 | interface IntrinsicElements { 263 | "enjin-gallery": LocalJSX.EnjinGallery & JSXBase.HTMLAttributes; 264 | "enjin-organism": LocalJSX.EnjinOrganism & JSXBase.HTMLAttributes; 265 | "enjin-pay-with-card": LocalJSX.EnjinPayWithCard & JSXBase.HTMLAttributes; 266 | "enjin-star-rating": LocalJSX.EnjinStarRating & JSXBase.HTMLAttributes; 267 | "enjin-star-rating-scoped": LocalJSX.EnjinStarRatingScoped & JSXBase.HTMLAttributes; 268 | "enjin-star-rating-shadow": LocalJSX.EnjinStarRatingShadow & JSXBase.HTMLAttributes; 269 | "enjin-table": LocalJSX.EnjinTable & JSXBase.HTMLAttributes; 270 | "enjin-test-component": LocalJSX.EnjinTestComponent & JSXBase.HTMLAttributes; 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/components/gallery/gallery.css: -------------------------------------------------------------------------------- 1 | enjin-organism { 2 | 3 | } -------------------------------------------------------------------------------- /src/components/gallery/gallery.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Listen, h } from "@stencil/core"; 2 | 3 | @Component({ 4 | tag: "enjin-gallery", 5 | styleUrl: "gallery.css" 6 | }) 7 | export class Gallery { 8 | @Listen("enjinStarRating") 9 | onStarRating(event) { 10 | console.log(event); 11 | } 12 | 13 | render() { 14 | return [ 15 | 26 | 27 | , 28 | 33 | 34 | , 35 | 40 | 41 | , 42 | 47 | 48 | , 49 | 59 | 60 | , 61 | 71 | 72 | , 73 | 83 | 84 | , 85 | 95 | 96 | 97 | ]; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/components/gallery/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-gallery 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Dependencies 9 | 10 | ### Depends on 11 | 12 | - [enjin-organism](../organism) 13 | - [enjin-pay-with-card](../pay-with-card) 14 | - [enjin-star-rating](../star-rating) 15 | - [enjin-star-rating-scoped](../star-rating-scoped) 16 | - [enjin-star-rating-shadow](../star-rating-shadow) 17 | - [enjin-test-component](../test-component) 18 | 19 | ### Graph 20 | ```mermaid 21 | graph TD; 22 | enjin-gallery --> enjin-organism 23 | enjin-gallery --> enjin-pay-with-card 24 | enjin-gallery --> enjin-star-rating 25 | enjin-gallery --> enjin-star-rating-scoped 26 | enjin-gallery --> enjin-star-rating-shadow 27 | enjin-gallery --> enjin-test-component 28 | style enjin-gallery fill:#f9f,stroke:#333,stroke-width:4px 29 | ``` 30 | 31 | ---------------------------------------------- 32 | 33 | *Built with [StencilJS](https://stenciljs.com/)* 34 | -------------------------------------------------------------------------------- /src/components/organism/organism.css: -------------------------------------------------------------------------------- 1 | .flex-grid{ 2 | display: flex; 3 | justify-content: center; 4 | } 5 | 6 | .flex-grid.fullscreen { 7 | display: block; 8 | } 9 | 10 | .flex-grid .col { 11 | flex: 1; 12 | position: relative; 13 | } 14 | 15 | .info { 16 | padding: 15px; 17 | font-family: var(--organism-font-family, inherit); 18 | color: var(--organism-color, inherit); 19 | } 20 | 21 | .info h2 { 22 | font-family: var(--organism-name-font-family, var(--organism-font-family, inherit)); 23 | color: var(--organism-name-color, var(--organism-color, inherit)); 24 | } 25 | 26 | .info p { 27 | font-family: var(--organism-description-font-family, var(--organism-font-family, inherit)); 28 | color: var(--organism-description-color, var(--organism-color, inherit)); 29 | } 30 | 31 | .info ul { 32 | font-family: var(--organism-props-font-family, var(--organism-font-family, inherit)); 33 | color: var(--organism-props-color, var(--organism-color, inherit)); 34 | } 35 | 36 | .frame { 37 | background-color: var(--frame-background-color, transparent); 38 | position: relative; 39 | width: var(--frame-width, 320px); 40 | margin: 0 auto; 41 | border: var(--frame-border-width, 1px) var(--frame-border-style, solid) var(--frame-border-color, #cccccc); 42 | min-height: var(--frame-min-height, auto); 43 | max-height: var(--frame-max-height, 640px); 44 | overflow-y: auto; 45 | resize: both; 46 | } 47 | 48 | .fullscreen .frame { 49 | resize: none; 50 | width: 100% !important; 51 | border-left: 0; 52 | border-right: 0; 53 | transition: width 1s ease; 54 | } 55 | 56 | .resize-button { 57 | padding: 2px 15px; 58 | font-size: 11px; 59 | margin: 0 auto; 60 | display: block; 61 | width: 150px; 62 | font-family: var(--organism-font-family, inherit); 63 | text-decoration: none; 64 | color: var(--organism-button-color, var(--organism-color, inherit)); 65 | background-color: var(--organism-button-background-color, #ececec); 66 | border-radius: 0 0 var(--organism-border-radius, 5px) var(--organism-border-radius, 5px); 67 | } 68 | 69 | .resize-button b { 70 | padding-left: 8px; 71 | float: right; 72 | } 73 | 74 | .more-button, .less-button { 75 | float: right; 76 | text-decoration: none; 77 | font-family: var(--organism-font-family, inherit); 78 | padding: 15px; 79 | color: var(--organism-button-color, var(--organism-color, inherit)); 80 | text-align: center; 81 | border-radius: var(--organism-border-radius, 5px); 82 | background-color: var(--organism-button-background-color, #ececec); 83 | } 84 | 85 | .more-button { 86 | display: none; 87 | } 88 | 89 | .tools { 90 | position: relative; 91 | } 92 | 93 | .synopsis .more-button { 94 | display: inline-block; 95 | } 96 | 97 | .synopsis .less-button { 98 | display: none; 99 | } 100 | 101 | .synopsis .info ul { 102 | display: none; 103 | } 104 | 105 | .synopsis .tools { 106 | display: none; 107 | } 108 | 109 | @media (max-width: 800px) { 110 | .flex-grid { 111 | display: block !important; 112 | } 113 | } -------------------------------------------------------------------------------- /src/components/organism/organism.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Element, Listen, Method, Prop, State, h } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'enjin-organism', 5 | styleUrl: 'organism.css', 6 | shadow: true 7 | }) 8 | export class Organism { 9 | @Element() organismEl: HTMLEnjinOrganismElement; 10 | /** 11 | * An interval loop to watch the frame size 12 | */ 13 | frameWatcher: any; 14 | /** 15 | * The name of the organism 16 | */ 17 | @Prop() 18 | name: string; 19 | /** 20 | * A description of what the organism does 21 | */ 22 | @Prop() 23 | description?: string; 24 | /** 25 | * A list of props with descriptions 26 | */ 27 | @Prop() 28 | propList?: { 29 | /** 30 | * The name of the prop 31 | */ 32 | name: string; 33 | /** 34 | * A description of the prop 35 | */ 36 | description: string; 37 | }[] = []; 38 | 39 | /** 40 | * The fame HTML element 41 | */ 42 | @State() frameEl: HTMLElement; 43 | /** 44 | * Is the frame in fullscreen mode? 45 | */ 46 | @State() 47 | fullscreenMode = false; 48 | /** 49 | * Is the frame in synopsis Mode? 50 | */ 51 | @State() 52 | synopsisMode = true; 53 | /** 54 | * The current size of the frame 55 | */ 56 | @State() 57 | frameSize: { 58 | height: number, 59 | width: number 60 | } = { 61 | height: 0, 62 | width: 0 63 | }; 64 | 65 | /** 66 | * Listen for hash change and show everything is hash is #all 67 | */ 68 | @Listen('hashchange', {target: 'window'}) 69 | async onhashchange() { 70 | if (window.location.hash === '#all') { 71 | this.viewMore(); 72 | } 73 | } 74 | 75 | /** 76 | * Expand organism to show preview frame and props info 77 | */ 78 | @Method() 79 | async viewMore(options = {scrollIntoView: true}) { 80 | this.synopsisMode = false; 81 | this.startFrameWatcher(); 82 | if (options.scrollIntoView) { 83 | setTimeout(() => { 84 | this.organismEl.scrollIntoView(); 85 | }, 100); 86 | } 87 | } 88 | 89 | /** 90 | * Shrink organism to only show name and description 91 | */ 92 | @Method() 93 | async viewLess() { 94 | this.synopsisMode = true; 95 | this.stopFrameWatcher(); 96 | } 97 | 98 | /** 99 | * Toggle the frame to fullscreen and back to responsive 100 | */ 101 | resizeToggle(event) { 102 | event.preventDefault(); 103 | this.fullscreenMode = !this.fullscreenMode; 104 | setTimeout(() => { 105 | this.updateFrameSize(); 106 | }, 10); 107 | } 108 | 109 | /** 110 | * Update the frameSize from height and width of the frame 111 | */ 112 | updateFrameSize() { 113 | if (this.frameSize.height === this.frameEl.clientHeight && this.frameSize.width === this.frameEl.clientWidth) { 114 | return false; 115 | } 116 | this.frameSize = { 117 | height: this.frameEl.clientHeight, 118 | width: this.frameEl.clientWidth 119 | }; 120 | } 121 | 122 | /** 123 | * Start a set interval loop to watch the frame size 124 | */ 125 | startFrameWatcher() { 126 | this.updateFrameSize(); 127 | this.frameWatcher = setInterval(() => { 128 | this.updateFrameSize(); 129 | }, 300); 130 | } 131 | 132 | /** 133 | * Stop frame size watcher 134 | */ 135 | stopFrameWatcher() { 136 | clearInterval(this.frameWatcher); 137 | } 138 | 139 | /** 140 | * Use the name of the the organism to create an element id 141 | */ 142 | getElementIdFromName() { 143 | return this.name 144 | .toLowerCase() 145 | .replace(/[^a-z0-9\s-]/ig,'') 146 | .trim() 147 | .replace(/\s+/g, '-'); 148 | } 149 | 150 | componentDidLoad() { 151 | // / 152 | // __ // 153 | // -\~,\=\ // 154 | // --=_\=---//= 155 | // -_ =/ \/ //\/ 156 | // _,~/ |_ _|\, 157 | // __ ,/_/ \' | `/_ 158 | // //\\ / | | |\_ 159 | // /(\ _\________/ (,_,)` 160 | // J(\_/ \ 161 | // ,)\/ v \ | 162 | // / Y ( Y | /J 163 | // (7 | \ | '/ \ 164 | // '| ( /\_______\_ _Y_ \ 165 | // 'Y \ / \ 7 \ / \ \ 166 | // ',) ( / ) / | / ( ) 167 | // '~( ) / __/ i J / / -Anna Eklund- 168 | // \ / \ \ | | _/ / 169 | // | | )_\_ )_\_/__\/ 170 | // /_\ |___\ |___\ 171 | // (___) 172 | this.organismEl.id = this.getElementIdFromName(); 173 | if (`#${this.organismEl.id}` === window.location.hash || window.location.hash === '#all') { 174 | this.viewMore({ 175 | scrollIntoView: !(window.location.hash === '#all') 176 | }); 177 | } 178 | } 179 | 180 | render() { 181 | return ( 182 |
183 |
184 | this.viewMore()}>More 185 | this.viewLess()}>Less 186 |

{this.name}

187 | {this.description ?

{this.description}

: null} 188 |
    189 | {this.propList.map(prop => ( 190 |
  • 191 | {prop.name} - {prop.description} 192 |
  • 193 | ))} 194 |
195 |
196 | 205 |
206 | ); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/components/organism/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-organism 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ------------- | ------------- | --------------------------------------- | ------------------------------------------ | ----------- | 12 | | `description` | `description` | A description of what the organism does | `string` | `undefined` | 13 | | `name` | `name` | The name of the organism | `string` | `undefined` | 14 | | `propList` | -- | A list of props with descriptions | `{ name: string; description: string; }[]` | `[]` | 15 | 16 | 17 | ## Methods 18 | 19 | ### `viewLess() => Promise` 20 | 21 | Shrink organism to only show name and description 22 | 23 | #### Returns 24 | 25 | Type: `Promise` 26 | 27 | 28 | 29 | ### `viewMore(options?: { scrollIntoView: boolean; }) => Promise` 30 | 31 | Expand organism to show preview frame and props info 32 | 33 | #### Returns 34 | 35 | Type: `Promise` 36 | 37 | 38 | 39 | 40 | ## Dependencies 41 | 42 | ### Used by 43 | 44 | - [enjin-gallery](../gallery) 45 | 46 | ### Graph 47 | ```mermaid 48 | graph TD; 49 | enjin-gallery --> enjin-organism 50 | style enjin-organism fill:#f9f,stroke:#333,stroke-width:4px 51 | ``` 52 | 53 | ---------------------------------------------- 54 | 55 | *Built with [StencilJS](https://stenciljs.com/)* 56 | -------------------------------------------------------------------------------- /src/components/pay-with-card/pay-with-card.css: -------------------------------------------------------------------------------- 1 | .StripeElement { 2 | background-color: white; 3 | height: 40px; 4 | padding: 10px 12px; 5 | border-radius: 4px; 6 | border: 1px solid transparent; 7 | box-shadow: 0 1px 3px 0 #e6ebf1; 8 | -webkit-transition: box-shadow 150ms ease; 9 | transition: box-shadow 150ms ease; 10 | } 11 | 12 | .StripeElement--focus { 13 | box-shadow: 0 1px 3px 0 #cfd7df; 14 | } 15 | 16 | .StripeElement--invalid { 17 | border-color: #fa755a; 18 | } 19 | 20 | .StripeElement--webkit-autofill { 21 | background-color: #fefde5 !important; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/pay-with-card/pay-with-card.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Event, EventEmitter, Listen, Prop, State, h } from "@stencil/core"; 2 | 3 | @Component({ 4 | tag: "enjin-pay-with-card", 5 | styleUrl: "pay-with-card.css" 6 | }) 7 | export class PayWithCard { 8 | stripe: stripe.Stripe; 9 | 10 | @Event() enjinCardSubmit: EventEmitter; 11 | 12 | @Prop() stripeKey: string; 13 | 14 | @State() card: stripe.elements.Element; 15 | @State() error: string; 16 | 17 | @Listen("submit") 18 | async onFormSubmit(event) { 19 | event.preventDefault(); 20 | 21 | this.stripe.createToken(this.card).then(result => { 22 | if (result.error) { 23 | this.error = result.error.message; 24 | } else { 25 | this.enjinCardSubmit.emit({event, token: result.token}); 26 | } 27 | }); 28 | } 29 | 30 | componentDidLoad() { 31 | if (this.stripeKey) { 32 | this.initializeStripeElements(); 33 | } else { 34 | alert("Please provide a Stripe key!"); 35 | } 36 | } 37 | 38 | initializeStripeElements() { 39 | this.stripe = Stripe(this.stripeKey); 40 | const elements = this.stripe.elements(); 41 | const style: any = { 42 | base: { 43 | color: "#32325d", 44 | lineHeight: "18px", 45 | fontFamily: '"Helvetica Neue", Helvetica, sans-serif', 46 | fontSmoothing: "antialiased", 47 | fontSize: "16px", 48 | "::placeholder": { 49 | color: "#aab7c4" 50 | } 51 | }, 52 | invalid: { 53 | color: "#fa755a", 54 | iconColor: "#fa755a" 55 | } 56 | }; 57 | 58 | this.card = elements.create("card", { style: style }); 59 | this.card.mount("#card-element"); 60 | this.card.on("change", event => { 61 | this.error = event.error ? event.error.message : null; 62 | }); 63 | } 64 | 65 | render() { 66 | return ( 67 |
68 |
69 | 70 |
71 |
{this.error}
72 |
73 | 74 | 75 | 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/components/pay-with-card/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-pay-with-card 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ----------- | ------------ | ----------- | -------- | ----------- | 12 | | `stripeKey` | `stripe-key` | | `string` | `undefined` | 13 | 14 | 15 | ## Events 16 | 17 | | Event | Description | Type | 18 | | ----------------- | ----------- | ------------------ | 19 | | `enjinCardSubmit` | | `CustomEvent` | 20 | 21 | 22 | ## Dependencies 23 | 24 | ### Used by 25 | 26 | - [enjin-gallery](../gallery) 27 | 28 | ### Graph 29 | ```mermaid 30 | graph TD; 31 | enjin-gallery --> enjin-pay-with-card 32 | style enjin-pay-with-card fill:#f9f,stroke:#333,stroke-width:4px 33 | ``` 34 | 35 | ---------------------------------------------- 36 | 37 | *Built with [StencilJS](https://stenciljs.com/)* 38 | -------------------------------------------------------------------------------- /src/components/star-rating-scoped/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-star-rating-scoped 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ----------- | ------------ | ----------- | --------- | ----------------- | 12 | | `disabled` | `disabled` | | `boolean` | `false` | 13 | | `maxRating` | `max-rating` | | `number` | `5` | 14 | | `name` | `name` | | `string` | `"rating-scoped"` | 15 | | `value` | `value` | | `string` | `undefined` | 16 | 17 | 18 | ## Events 19 | 20 | | Event | Description | Type | 21 | | -------------- | ----------- | ------------------ | 22 | | `ftStarRating` | | `CustomEvent` | 23 | 24 | 25 | ## Methods 26 | 27 | ### `setCurrentRating(rating: any) => Promise` 28 | 29 | 30 | 31 | #### Returns 32 | 33 | Type: `Promise` 34 | 35 | 36 | 37 | 38 | ## Dependencies 39 | 40 | ### Used by 41 | 42 | - [enjin-gallery](../gallery) 43 | 44 | ### Graph 45 | ```mermaid 46 | graph TD; 47 | enjin-gallery --> enjin-star-rating-scoped 48 | style enjin-star-rating-scoped fill:#f9f,stroke:#333,stroke-width:4px 49 | ``` 50 | 51 | ---------------------------------------------- 52 | 53 | *Built with [StencilJS](https://stenciljs.com/)* 54 | -------------------------------------------------------------------------------- /src/components/star-rating-scoped/star-rating-scoped.css: -------------------------------------------------------------------------------- 1 | :host { 2 | --star-rating-default: #ccc; 3 | --star-rating-active: #f90; 4 | --star-rating-hover: #fc0; 5 | --star-rating-size: 30px; 6 | display: flex; 7 | flex-direction: row-reverse; 8 | justify-content: space-around; 9 | text-align: center; 10 | width: var( 11 | --star-rating-width, 12 | calc( 13 | (var(--star-rating-size, 25px) * var(--star-rating-max, 5)) + 14 | var(--star-rating-spacing, -10px) 15 | ) 16 | ); 17 | } 18 | 19 | :host input { 20 | display: none; 21 | } 22 | :host > label { 23 | color: var(--star-rating-default, #fff); 24 | font-size: var(--star-rating-size, 25px); 25 | cursor: pointer; 26 | } 27 | :host .star-active { 28 | color: var(--star-rating-active, #f90); 29 | } 30 | :host:not(.is-disabled) label:hover, 31 | :host:not(.is-disabled) label:hover ~ label { 32 | color: var(--star-rating-hover, #fc0); 33 | } 34 | -------------------------------------------------------------------------------- /src/components/star-rating-scoped/star-rating-scoped.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Element, 4 | Event, 5 | EventEmitter, 6 | Host, 7 | Method, 8 | Prop, 9 | State, 10 | Watch, 11 | h 12 | } from "@stencil/core"; 13 | 14 | @Component({ 15 | tag: "enjin-star-rating-scoped", 16 | styleUrl: "star-rating-scoped.css", 17 | scoped: true 18 | }) 19 | export class EnjinStarRatingScoped { 20 | @Element() starRatingEl: HTMLElement; 21 | 22 | @Event() ftStarRating: EventEmitter; 23 | 24 | @Prop() disabled = false; 25 | @Prop() name = "rating-scoped"; 26 | @Prop() maxRating = 5; 27 | @Prop() value: string; 28 | 29 | @State() currentRating: number; 30 | 31 | @Method() 32 | async setCurrentRating(rating: any) { 33 | this.currentRating = parseFloat(rating); 34 | } 35 | 36 | @Watch("value") 37 | async onValueChange() { 38 | this.currentRating = parseFloat(this.value); 39 | } 40 | 41 | componentWillLoad() { 42 | this.currentRating = parseFloat(this.value ? this.value : "0"); 43 | } 44 | 45 | componentDidLoad() { 46 | this.currentRating = parseFloat(this.value ? this.value : "0"); 47 | } 48 | 49 | onInput(event) { 50 | if (this.disabled) { 51 | return false; 52 | } 53 | this.currentRating = parseFloat(event.target.value); 54 | this.ftStarRating.emit({ 55 | event, 56 | name: this.name, 57 | value: this.currentRating 58 | }); 59 | } 60 | 61 | render() { 62 | return ( 63 | 69 | {[...Array(this.maxRating)].map((_radio, index) => [ 70 | 85 | ])} 86 | 87 | ); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/components/star-rating-shadow/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-star-rating-shadow 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ----------- | ------------ | ----------- | --------- | ----------------- | 12 | | `disabled` | `disabled` | | `boolean` | `false` | 13 | | `maxRating` | `max-rating` | | `number` | `5` | 14 | | `name` | `name` | | `string` | `"rating-shadow"` | 15 | | `value` | `value` | | `string` | `undefined` | 16 | 17 | 18 | ## Events 19 | 20 | | Event | Description | Type | 21 | | -------------- | ----------- | ------------------ | 22 | | `ftStarRating` | | `CustomEvent` | 23 | 24 | 25 | ## Methods 26 | 27 | ### `setCurrentRating(rating: any) => Promise` 28 | 29 | 30 | 31 | #### Returns 32 | 33 | Type: `Promise` 34 | 35 | 36 | 37 | 38 | ## Dependencies 39 | 40 | ### Used by 41 | 42 | - [enjin-gallery](../gallery) 43 | 44 | ### Graph 45 | ```mermaid 46 | graph TD; 47 | enjin-gallery --> enjin-star-rating-shadow 48 | style enjin-star-rating-shadow fill:#f9f,stroke:#333,stroke-width:4px 49 | ``` 50 | 51 | ---------------------------------------------- 52 | 53 | *Built with [StencilJS](https://stenciljs.com/)* 54 | -------------------------------------------------------------------------------- /src/components/star-rating-shadow/star-rating-shadow.css: -------------------------------------------------------------------------------- 1 | :host { 2 | --star-rating-default: #ccc; 3 | --star-rating-active: #f90; 4 | --star-rating-hover: #fc0; 5 | --star-rating-size: 30px; 6 | display: flex; 7 | flex-direction: row-reverse; 8 | justify-content: space-around; 9 | text-align: center; 10 | width: var( 11 | --star-rating-width, 12 | calc( 13 | (var(--star-rating-size, 25px) * var(--star-rating-max, 5)) + 14 | var(--star-rating-spacing, -10px) 15 | ) 16 | ); 17 | } 18 | 19 | input { 20 | display: none; 21 | } 22 | label { 23 | color: var(--star-rating-default, #fff); 24 | font-size: var(--star-rating-size, 25px); 25 | cursor: pointer; 26 | } 27 | .star-active { 28 | color: var(--star-rating-active, #f90); 29 | } 30 | :host(:not(.is-disabled)) label:hover, 31 | :host(:not(.is-disabled)) label:hover ~ label { 32 | color: var(--star-rating-hover, #fc0); 33 | } 34 | -------------------------------------------------------------------------------- /src/components/star-rating-shadow/star-rating-shadow.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Element, 4 | Event, 5 | EventEmitter, 6 | Method, 7 | Prop, 8 | State, 9 | Watch, 10 | h 11 | } from "@stencil/core"; 12 | 13 | @Component({ 14 | tag: "enjin-star-rating-shadow", 15 | styleUrl: "star-rating-shadow.css", 16 | shadow: true 17 | }) 18 | export class EnjinStarRatingShadow { 19 | @Element() starRatingEl: HTMLElement; 20 | 21 | @Event() ftStarRating: EventEmitter; 22 | 23 | @Prop() disabled = false; 24 | @Prop() name = "rating-shadow"; 25 | @Prop() maxRating = 5; 26 | @Prop() value: string; 27 | 28 | @State() currentRating: number; 29 | 30 | onInput(event) { 31 | if (this.disabled) { 32 | return false; 33 | } 34 | this.currentRating = parseFloat(event.target.value); 35 | this.ftStarRating.emit({ 36 | event, 37 | name: this.name, 38 | value: this.currentRating 39 | }); 40 | } 41 | 42 | @Method() 43 | async setCurrentRating(rating: any) { 44 | this.currentRating = parseFloat(rating); 45 | } 46 | 47 | @Watch("value") 48 | async onValueChange() { 49 | this.currentRating = parseFloat(this.value); 50 | } 51 | 52 | componentWillLoad() { 53 | this.currentRating = parseFloat(this.value ? this.value : "0"); 54 | } 55 | 56 | componentDidLoad() { 57 | this.currentRating = parseFloat(this.value ? this.value : "0"); 58 | } 59 | 60 | hostData() { 61 | return { 62 | class: this.disabled ? "star-rating is-disabled" : "star-rating", 63 | style: { 64 | "--star-rating-max": this.maxRating 65 | } 66 | }; 67 | } 68 | 69 | render() { 70 | return [...Array(this.maxRating)].map((_radio, index) => [ 71 | 86 | ]); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/components/star-rating/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-star-rating 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | ----------- | ------------ | ------------------------------------ | --------- | ----------- | 12 | | `disabled` | `disabled` | Whether or not the field is disabled | `boolean` | `false` | 13 | | `maxRating` | `max-rating` | The max available star rating | `number` | `5` | 14 | | `name` | `name` | The name of the input | `string` | `"rating"` | 15 | | `value` | `value` | The value of the rating input | `string` | `undefined` | 16 | 17 | 18 | ## Events 19 | 20 | | Event | Description | Type | 21 | | ----------------- | ----------- | ------------------ | 22 | | `enjinStarRating` | | `CustomEvent` | 23 | 24 | 25 | ## Methods 26 | 27 | ### `setCurrentRating(rating: any) => Promise` 28 | 29 | Set the current rating 30 | 31 | #### Returns 32 | 33 | Type: `Promise` 34 | 35 | 36 | 37 | 38 | ## Dependencies 39 | 40 | ### Used by 41 | 42 | - [enjin-gallery](../gallery) 43 | 44 | ### Graph 45 | ```mermaid 46 | graph TD; 47 | enjin-gallery --> enjin-star-rating 48 | style enjin-star-rating fill:#f9f,stroke:#333,stroke-width:4px 49 | ``` 50 | 51 | ---------------------------------------------- 52 | 53 | *Built with [StencilJS](https://stenciljs.com/)* 54 | -------------------------------------------------------------------------------- /src/components/star-rating/star-rating.css: -------------------------------------------------------------------------------- 1 | .star-rating { 2 | --star-rating-default: #ccc; 3 | --star-rating-active: #f90; 4 | --star-rating-hover: #fc0; 5 | --star-rating-size: 30px; 6 | display: flex; 7 | flex-direction: row-reverse; 8 | justify-content: space-around; 9 | text-align: center; 10 | width: var( 11 | --star-rating-width, 12 | calc( 13 | (var(--star-rating-size, 25px) * var(--star-rating-max, 5)) + 14 | var(--star-rating-spacing, -10px) 15 | ) 16 | ); 17 | } 18 | 19 | .star-rating input { 20 | display: none; 21 | } 22 | .star-rating > label { 23 | color: var(--star-rating-default, #fff); 24 | font-size: var(--star-rating-size, 25px); 25 | cursor: pointer; 26 | } 27 | .star-rating .star-active { 28 | color: var(--star-rating-active, #f90); 29 | } 30 | .star-rating:not(.is-disabled) label:hover, 31 | .star-rating:not(.is-disabled) label:hover ~ label { 32 | color: var(--star-rating-hover, #fc0); 33 | } 34 | -------------------------------------------------------------------------------- /src/components/star-rating/star-rating.spec.ts: -------------------------------------------------------------------------------- 1 | import { EnjinStarRating } from "./star-rating"; 2 | 3 | it("should render", () => { 4 | expect(new EnjinStarRating()).toBeTruthy(); 5 | }); 6 | -------------------------------------------------------------------------------- /src/components/star-rating/star-rating.stories.js: -------------------------------------------------------------------------------- 1 | import { storiesOf } from '@storybook/html'; 2 | import { withActions } from "@storybook/addon-actions"; 3 | import { withKnobs, number, boolean } from "@storybook/addon-knobs"; 4 | 5 | import readme from "./readme.md"; 6 | 7 | const storyOptions = { 8 | notes: { 9 | markdown: readme 10 | } 11 | }; 12 | 13 | storiesOf('Star Rating', module) 14 | .addDecorator(withActions("enjinStarRating")) 15 | .addDecorator(withKnobs) 16 | .addParameters({ jest: ["star-rating"] }) 17 | .add('Default', () => '', storyOptions) 18 | .add('With Rating', () => { 19 | const starRatingEl = document.createElement('enjin-star-rating'); 20 | starRatingEl.value = number('value', 3); 21 | 22 | return starRatingEl; 23 | }, storyOptions) 24 | .add('Disabled', () => { 25 | const starRatingEl = document.createElement('enjin-star-rating'); 26 | starRatingEl.disabled = boolean('disabled', true); 27 | 28 | return starRatingEl; 29 | }, storyOptions); -------------------------------------------------------------------------------- /src/components/star-rating/star-rating.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Element, 4 | Event, 5 | EventEmitter, 6 | Method, 7 | Prop, 8 | State, 9 | Watch, 10 | h 11 | } from "@stencil/core"; 12 | 13 | @Component({ 14 | tag: "enjin-star-rating", 15 | styleUrl: "star-rating.css" 16 | }) 17 | export class EnjinStarRating { 18 | @Element() starRatingEl: HTMLElement; 19 | 20 | @Event() enjinStarRating: EventEmitter; 21 | 22 | /** 23 | * Whether or not the field is disabled 24 | */ 25 | @Prop() disabled = false; 26 | /** 27 | * The name of the input 28 | */ 29 | @Prop() name = "rating"; 30 | /** 31 | * The max available star rating 32 | */ 33 | @Prop() maxRating = 5; 34 | /** 35 | * The value of the rating input 36 | */ 37 | @Prop() value: string; 38 | 39 | /** 40 | * The current rating set 41 | */ 42 | @State() currentRating: number; 43 | 44 | onInput(event) { 45 | if (this.disabled) { 46 | return false; 47 | } 48 | this.currentRating = parseFloat(event.target.value); 49 | this.enjinStarRating.emit({ 50 | event, 51 | name: this.name, 52 | value: this.currentRating 53 | }); 54 | } 55 | 56 | /** 57 | * Set the current rating 58 | */ 59 | @Method() 60 | async setCurrentRating(rating: any) { 61 | this.currentRating = parseFloat(rating); 62 | } 63 | 64 | @Watch("value") 65 | async onValueChange() { 66 | this.currentRating = parseFloat(this.value); 67 | } 68 | 69 | componentWillLoad() { 70 | this.currentRating = parseFloat(this.value ? this.value : "0"); 71 | } 72 | 73 | componentDidLoad() { 74 | this.currentRating = parseFloat(this.value ? this.value : "0"); 75 | } 76 | 77 | hostData() { 78 | return { 79 | class: this.disabled ? "star-rating is-disabled" : "star-rating", 80 | style: { 81 | "--star-rating-max": this.maxRating 82 | } 83 | }; 84 | } 85 | 86 | 87 | render() { 88 | return [...Array(this.maxRating)].map((_radio, index) => [ 89 | 103 | ]); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/components/table/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-table 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Properties 9 | 10 | | Property | Attribute | Description | Type | Default | 11 | | --------- | --------- | --------------------------------- | ---------------------------------------------------------------------------------------- | ------- | 12 | | `columns` | -- | The columns to show for the table | `{ header: string; type?: "date"; key?: string; value?: string; sortable?: boolean; }[]` | `[]` | 13 | | `rows` | -- | The rows of data to display | `any[]` | `[]` | 14 | 15 | 16 | ## Events 17 | 18 | | Event | Description | Type | 19 | | ----------- | --------------------------------------- | ---------------------------------------------------------------- | 20 | | `enjinSort` | Fires when the column header is clicked | `CustomEvent<{ event: any; sort: { key?: "asc" \| "desc"; }; }>` | 21 | 22 | 23 | ---------------------------------------------- 24 | 25 | *Built with [StencilJS](https://stenciljs.com/)* 26 | -------------------------------------------------------------------------------- /src/components/table/table.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | border-spacing: 0; 4 | } 5 | td, 6 | th { 7 | padding: 0; 8 | } 9 | table { 10 | background-color: transparent; 11 | } 12 | caption { 13 | padding-top: 8px; 14 | padding-bottom: 8px; 15 | color: #777777; 16 | text-align: left; 17 | } 18 | th { 19 | text-align: left; 20 | } 21 | .table { 22 | width: 100%; 23 | max-width: 100%; 24 | margin-bottom: 20px; 25 | } 26 | .table > thead > tr > th, 27 | .table > tbody > tr > th, 28 | .table > tfoot > tr > th, 29 | .table > thead > tr > td, 30 | .table > tbody > tr > td, 31 | .table > tfoot > tr > td { 32 | padding: 8px; 33 | line-height: 1.42857143; 34 | vertical-align: top; 35 | border-top: 1px solid #dddddd; 36 | } 37 | .table > thead > tr > th { 38 | vertical-align: bottom; 39 | border-bottom: 2px solid #dddddd; 40 | } 41 | .table > caption + thead > tr:first-child > th, 42 | .table > colgroup + thead > tr:first-child > th, 43 | .table > thead:first-child > tr:first-child > th, 44 | .table > caption + thead > tr:first-child > td, 45 | .table > colgroup + thead > tr:first-child > td, 46 | .table > thead:first-child > tr:first-child > td { 47 | border-top: 0; 48 | } 49 | .table > tbody + tbody { 50 | border-top: 2px solid #dddddd; 51 | } 52 | .table .table { 53 | background-color: #ffffff; 54 | } 55 | .table-condensed > thead > tr > th, 56 | .table-condensed > tbody > tr > th, 57 | .table-condensed > tfoot > tr > th, 58 | .table-condensed > thead > tr > td, 59 | .table-condensed > tbody > tr > td, 60 | .table-condensed > tfoot > tr > td { 61 | padding: 5px; 62 | } 63 | .table-bordered { 64 | border: 1px solid #dddddd; 65 | } 66 | .table-bordered > thead > tr > th, 67 | .table-bordered > tbody > tr > th, 68 | .table-bordered > tfoot > tr > th, 69 | .table-bordered > thead > tr > td, 70 | .table-bordered > tbody > tr > td, 71 | .table-bordered > tfoot > tr > td { 72 | border: 1px solid #dddddd; 73 | } 74 | .table-bordered > thead > tr > th, 75 | .table-bordered > thead > tr > td { 76 | border-bottom-width: 2px; 77 | } 78 | .table-striped > tbody > tr:nth-of-type(odd) { 79 | background-color: #f9f9f9; 80 | } 81 | .table-hover > tbody > tr:hover { 82 | background-color: #f5f5f5; 83 | } 84 | table col[class*="col-"] { 85 | position: static; 86 | float: none; 87 | display: table-column; 88 | } 89 | table td[class*="col-"], 90 | table th[class*="col-"] { 91 | position: static; 92 | float: none; 93 | display: table-cell; 94 | } 95 | .table > thead > tr > td.active, 96 | .table > tbody > tr > td.active, 97 | .table > tfoot > tr > td.active, 98 | .table > thead > tr > th.active, 99 | .table > tbody > tr > th.active, 100 | .table > tfoot > tr > th.active, 101 | .table > thead > tr.active > td, 102 | .table > tbody > tr.active > td, 103 | .table > tfoot > tr.active > td, 104 | .table > thead > tr.active > th, 105 | .table > tbody > tr.active > th, 106 | .table > tfoot > tr.active > th { 107 | background-color: #f5f5f5; 108 | } 109 | .table-hover > tbody > tr > td.active:hover, 110 | .table-hover > tbody > tr > th.active:hover, 111 | .table-hover > tbody > tr.active:hover > td, 112 | .table-hover > tbody > tr:hover > .active, 113 | .table-hover > tbody > tr.active:hover > th { 114 | background-color: #e8e8e8; 115 | } 116 | .table > thead > tr > td.success, 117 | .table > tbody > tr > td.success, 118 | .table > tfoot > tr > td.success, 119 | .table > thead > tr > th.success, 120 | .table > tbody > tr > th.success, 121 | .table > tfoot > tr > th.success, 122 | .table > thead > tr.success > td, 123 | .table > tbody > tr.success > td, 124 | .table > tfoot > tr.success > td, 125 | .table > thead > tr.success > th, 126 | .table > tbody > tr.success > th, 127 | .table > tfoot > tr.success > th { 128 | background-color: #dff0d8; 129 | } 130 | .table-hover > tbody > tr > td.success:hover, 131 | .table-hover > tbody > tr > th.success:hover, 132 | .table-hover > tbody > tr.success:hover > td, 133 | .table-hover > tbody > tr:hover > .success, 134 | .table-hover > tbody > tr.success:hover > th { 135 | background-color: #d0e9c6; 136 | } 137 | .table > thead > tr > td.info, 138 | .table > tbody > tr > td.info, 139 | .table > tfoot > tr > td.info, 140 | .table > thead > tr > th.info, 141 | .table > tbody > tr > th.info, 142 | .table > tfoot > tr > th.info, 143 | .table > thead > tr.info > td, 144 | .table > tbody > tr.info > td, 145 | .table > tfoot > tr.info > td, 146 | .table > thead > tr.info > th, 147 | .table > tbody > tr.info > th, 148 | .table > tfoot > tr.info > th { 149 | background-color: #d9edf7; 150 | } 151 | .table-hover > tbody > tr > td.info:hover, 152 | .table-hover > tbody > tr > th.info:hover, 153 | .table-hover > tbody > tr.info:hover > td, 154 | .table-hover > tbody > tr:hover > .info, 155 | .table-hover > tbody > tr.info:hover > th { 156 | background-color: #c4e3f3; 157 | } 158 | .table > thead > tr > td.warning, 159 | .table > tbody > tr > td.warning, 160 | .table > tfoot > tr > td.warning, 161 | .table > thead > tr > th.warning, 162 | .table > tbody > tr > th.warning, 163 | .table > tfoot > tr > th.warning, 164 | .table > thead > tr.warning > td, 165 | .table > tbody > tr.warning > td, 166 | .table > tfoot > tr.warning > td, 167 | .table > thead > tr.warning > th, 168 | .table > tbody > tr.warning > th, 169 | .table > tfoot > tr.warning > th { 170 | background-color: #fcf8e3; 171 | } 172 | .table-hover > tbody > tr > td.warning:hover, 173 | .table-hover > tbody > tr > th.warning:hover, 174 | .table-hover > tbody > tr.warning:hover > td, 175 | .table-hover > tbody > tr:hover > .warning, 176 | .table-hover > tbody > tr.warning:hover > th { 177 | background-color: #faf2cc; 178 | } 179 | .table > thead > tr > td.danger, 180 | .table > tbody > tr > td.danger, 181 | .table > tfoot > tr > td.danger, 182 | .table > thead > tr > th.danger, 183 | .table > tbody > tr > th.danger, 184 | .table > tfoot > tr > th.danger, 185 | .table > thead > tr.danger > td, 186 | .table > tbody > tr.danger > td, 187 | .table > tfoot > tr.danger > td, 188 | .table > thead > tr.danger > th, 189 | .table > tbody > tr.danger > th, 190 | .table > tfoot > tr.danger > th { 191 | background-color: #f2dede; 192 | } 193 | .table-hover > tbody > tr > td.danger:hover, 194 | .table-hover > tbody > tr > th.danger:hover, 195 | .table-hover > tbody > tr.danger:hover > td, 196 | .table-hover > tbody > tr:hover > .danger, 197 | .table-hover > tbody > tr.danger:hover > th { 198 | background-color: #ebcccc; 199 | } 200 | .table-responsive { 201 | overflow-x: auto; 202 | min-height: 0.01%; 203 | } 204 | @media screen and (max-width: 767px) { 205 | .table-responsive { 206 | width: 100%; 207 | margin-bottom: 15px; 208 | overflow-y: hidden; 209 | -ms-overflow-style: -ms-autohiding-scrollbar; 210 | border: 1px solid #dddddd; 211 | } 212 | .table-responsive > .table { 213 | margin-bottom: 0; 214 | } 215 | .table-responsive > .table > thead > tr > th, 216 | .table-responsive > .table > tbody > tr > th, 217 | .table-responsive > .table > tfoot > tr > th, 218 | .table-responsive > .table > thead > tr > td, 219 | .table-responsive > .table > tbody > tr > td, 220 | .table-responsive > .table > tfoot > tr > td { 221 | white-space: nowrap; 222 | } 223 | .table-responsive > .table-bordered { 224 | border: 0; 225 | } 226 | .table-responsive > .table-bordered > thead > tr > th:first-child, 227 | .table-responsive > .table-bordered > tbody > tr > th:first-child, 228 | .table-responsive > .table-bordered > tfoot > tr > th:first-child, 229 | .table-responsive > .table-bordered > thead > tr > td:first-child, 230 | .table-responsive > .table-bordered > tbody > tr > td:first-child, 231 | .table-responsive > .table-bordered > tfoot > tr > td:first-child { 232 | border-left: 0; 233 | } 234 | .table-responsive > .table-bordered > thead > tr > th:last-child, 235 | .table-responsive > .table-bordered > tbody > tr > th:last-child, 236 | .table-responsive > .table-bordered > tfoot > tr > th:last-child, 237 | .table-responsive > .table-bordered > thead > tr > td:last-child, 238 | .table-responsive > .table-bordered > tbody > tr > td:last-child, 239 | .table-responsive > .table-bordered > tfoot > tr > td:last-child { 240 | border-right: 0; 241 | } 242 | .table-responsive > .table-bordered > tbody > tr:last-child > th, 243 | .table-responsive > .table-bordered > tfoot > tr:last-child > th, 244 | .table-responsive > .table-bordered > tbody > tr:last-child > td, 245 | .table-responsive > .table-bordered > tfoot > tr:last-child > td { 246 | border-bottom: 0; 247 | } 248 | } 249 | 250 | table.table { 251 | margin-bottom: 0; 252 | border-bottom: 0; 253 | border-left: none !important; 254 | border-right: none !important; 255 | } 256 | 257 | table.table tr { 258 | border-bottom: 1px solid var(--theme-light-grey); 259 | } 260 | 261 | table.table th, 262 | table.table td { 263 | text-align: left; 264 | border: none !important; 265 | } 266 | 267 | table.table th:first-of-type, 268 | table.table td:first-of-type { 269 | text-align: left; 270 | } 271 | 272 | table.table thead td { 273 | font-weight: bold; 274 | } 275 | 276 | table.table tbody { 277 | color: var(--theme-dark); 278 | } 279 | 280 | table.table tbody .title-col { 281 | font-weight: 600; 282 | } 283 | 284 | table.table .button-md { 285 | height: 25px; 286 | margin: 0; 287 | font-size: 12px; 288 | padding-left: 5px; 289 | padding-right: 5px; 290 | } 291 | 292 | .table-responsive table tbody td:not(.actions) { 293 | padding-top: 15px; 294 | } -------------------------------------------------------------------------------- /src/components/table/table.stories.js: -------------------------------------------------------------------------------- 1 | import { storiesOf } from '@storybook/html'; 2 | import { withActions } from "@storybook/addon-actions"; 3 | 4 | import readme from "./readme.md"; 5 | 6 | storiesOf('Table', module) 7 | .addDecorator(withActions("enjinSort")) 8 | .addParameters({ jest: ["table"] }) 9 | .add('Default', () => '', { 10 | notes: { 11 | markdown: readme 12 | } 13 | }) 14 | .add('With Data', () => { 15 | const tableEl = document.createElement('enjin-table'); 16 | tableEl.columns = [ 17 | { 18 | header: "Column 1", 19 | key: "col1", 20 | sortable: true 21 | } 22 | ]; 23 | tableEl.rows = [{ 24 | col1: 'testing' 25 | }]; 26 | 27 | return tableEl; 28 | }, { 29 | notes: { 30 | markdown: readme 31 | } 32 | }); -------------------------------------------------------------------------------- /src/components/table/table.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Event, 4 | EventEmitter, 5 | Prop, 6 | State, 7 | h 8 | } from "@stencil/core"; 9 | 10 | @Component({ 11 | tag: "enjin-table", 12 | styleUrl: "table.css" 13 | }) 14 | export class EnjinTable { 15 | tableEl: HTMLTableElement; 16 | 17 | /** 18 | * The rows of data to display 19 | */ 20 | @Prop() rows: any[] = []; 21 | /** 22 | * The columns to show for the table 23 | */ 24 | @Prop() columns: { 25 | header: string; 26 | type?: "date"; 27 | key?: string; 28 | value?: string; 29 | sortable?: boolean; 30 | }[] = []; 31 | 32 | @State() currentSort: { ["key"]?: "asc" | "desc" } = {}; 33 | 34 | /** 35 | * Fires when the column header is clicked 36 | */ 37 | @Event() enjinSort: EventEmitter<{ 38 | event: any; 39 | sort: { ["key"]?: "asc" | "desc" }; 40 | }>; 41 | 42 | /** 43 | * Get the value for the current table cell 44 | * @param record The row of data 45 | * @param key The key of the data to display 46 | * @param type The formatting type of the cell 47 | */ 48 | getValue(record: any, key: string) { 49 | let value = !key 50 | ? record 51 | : key && key.indexOf(".") >= 0 52 | ? key.split(".").reduce((p, c) => (p && p[c]) || null, record) 53 | : key && typeof record[key] !== "undefined" 54 | ? record[key] 55 | : null; 56 | 57 | return value; 58 | } 59 | 60 | sortColumn( 61 | event, 62 | column: { 63 | header: string; 64 | type?: "date"; 65 | key?: string; 66 | value?: string; 67 | sortable?: boolean; 68 | } 69 | ) { 70 | this.currentSort[column.key] = 71 | this.currentSort[column.key] && 72 | this.currentSort[column.key] === "asc" 73 | ? "desc" 74 | : this.currentSort[column.key] && 75 | this.currentSort[column.key] === "desc" 76 | ? (this.currentSort[column.key] = null) 77 | : "asc"; 78 | this.currentSort = { ...this.currentSort }; 79 | this.enjinSort.emit({ event, sort: this.currentSort }); 80 | } 81 | 82 | render() { 83 | return ( 84 |
85 | 86 | 87 | 88 | {this.columns && 89 | this.columns.map && 90 | this.columns.map(column => ( 91 | 111 | ))} 112 | 113 | 114 | 115 | {this.rows && 116 | this.rows.map && 117 | this.rows.map((row, _index: any) => ( 118 | 119 | {this.columns && 120 | this.columns.map && 121 | this.columns.map(column => ( 122 | 130 | ))} 131 | 132 | ))} 133 | 134 |
93 | column.sortable 94 | ? this.sortColumn(event, column) 95 | : null 96 | } 97 | > 98 | {column.header} 99 | {this.currentSort[column.key] && ( 100 | 109 | )} 110 |
123 | {column.key 124 | ? this.getValue( 125 | row, 126 | column.key 127 | ) 128 | : column.value} 129 |
135 |
136 | ); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/components/test-component/readme.md: -------------------------------------------------------------------------------- 1 | # enjin-test-component 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Dependencies 9 | 10 | ### Used by 11 | 12 | - [enjin-gallery](../gallery) 13 | 14 | ### Graph 15 | ```mermaid 16 | graph TD; 17 | enjin-gallery --> enjin-test-component 18 | style enjin-test-component fill:#f9f,stroke:#333,stroke-width:4px 19 | ``` 20 | 21 | ---------------------------------------------- 22 | 23 | *Built with [StencilJS](https://stenciljs.com/)* 24 | -------------------------------------------------------------------------------- /src/components/test-component/test-component.stories.js: -------------------------------------------------------------------------------- 1 | import { storiesOf } from '@storybook/html'; 2 | 3 | import readme from "./readme.md"; 4 | 5 | storiesOf('Test Component', module) 6 | .add('Default', () => '', { 7 | notes: { 8 | markdown: readme 9 | } 10 | }); -------------------------------------------------------------------------------- /src/components/test-component/test-component.tsx: -------------------------------------------------------------------------------- 1 | import { Component, h } from '@stencil/core'; 2 | 3 | 4 | @Component({ 5 | tag: 'enjin-test-component' 6 | }) 7 | export class TestComponent { 8 | render() { 9 | return ( 10 |
11 |

Gotta Catch 'Em All! ^_^

12 |
13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/core.json: -------------------------------------------------------------------------------- 1 | { 2 | "timestamp": "2019-09-11T15:52:31", 3 | "compiler": { 4 | "name": "@stencil/core", 5 | "version": "1.2.2", 6 | "typescriptVersion": "3.5.3" 7 | }, 8 | "components": [ 9 | { 10 | "tag": "enjin-gallery", 11 | "encapsulation": "scoped", 12 | "readme": "# enjin-gallery\n\n\n", 13 | "docs": "", 14 | "docsTags": [], 15 | "usage": {}, 16 | "props": [], 17 | "methods": [], 18 | "events": [], 19 | "styles": [], 20 | "slots": [] 21 | }, 22 | { 23 | "tag": "enjin-organism", 24 | "encapsulation": "none", 25 | "readme": "# enjin-organism\n\n\n", 26 | "docs": "", 27 | "docsTags": [], 28 | "usage": {}, 29 | "props": [ 30 | { 31 | "name": "component", 32 | "type": "{ docs: string; docsTags: any[]; encapsulation: string; events: any[]; methods: any[]; phases: any; props: { attr: string; default: any; docs: string; docsTags: any[]; mutable: boolean; name: string; optional: boolean; reflectToAttr: boolean; required: boolean; type: string; }[]; readme: string; slots: any[]; styles: any[]; tag: string; usage: any; }", 33 | "mutable": true, 34 | "reflectToAttr": false, 35 | "docs": "", 36 | "docsTags": [], 37 | "optional": false, 38 | "required": false 39 | }, 40 | { 41 | "name": "match", 42 | "type": "MatchResults", 43 | "mutable": false, 44 | "reflectToAttr": false, 45 | "docs": "", 46 | "docsTags": [], 47 | "optional": false, 48 | "required": false 49 | } 50 | ], 51 | "methods": [], 52 | "events": [], 53 | "styles": [], 54 | "slots": [] 55 | }, 56 | { 57 | "tag": "enjin-pay-with-card", 58 | "encapsulation": "none", 59 | "readme": "# enjin-pay-with-card\n\n\n", 60 | "docs": "", 61 | "docsTags": [], 62 | "usage": {}, 63 | "props": [ 64 | { 65 | "name": "stripeKey", 66 | "type": "string", 67 | "mutable": false, 68 | "attr": "stripe-key", 69 | "reflectToAttr": false, 70 | "docs": "", 71 | "docsTags": [], 72 | "optional": false, 73 | "required": false 74 | } 75 | ], 76 | "methods": [], 77 | "events": [ 78 | { 79 | "event": "enjinCardSubmit", 80 | "detail": "any", 81 | "bubbles": true, 82 | "cancelable": true, 83 | "composed": true, 84 | "docs": "", 85 | "docsTags": [] 86 | } 87 | ], 88 | "styles": [], 89 | "slots": [] 90 | }, 91 | { 92 | "tag": "enjin-sidebar", 93 | "encapsulation": "none", 94 | "readme": "# enjin-sidebar\n\n\n", 95 | "docs": "", 96 | "docsTags": [], 97 | "usage": {}, 98 | "props": [ 99 | { 100 | "name": "components", 101 | "type": "any", 102 | "mutable": false, 103 | "attr": "components", 104 | "reflectToAttr": false, 105 | "docs": "", 106 | "docsTags": [], 107 | "default": "[]", 108 | "optional": false, 109 | "required": false 110 | } 111 | ], 112 | "methods": [], 113 | "events": [], 114 | "styles": [], 115 | "slots": [] 116 | }, 117 | { 118 | "tag": "enjin-sidebar-component", 119 | "encapsulation": "shadow", 120 | "readme": "# enjin-sidebar-component\n\n\n", 121 | "docs": "", 122 | "docsTags": [], 123 | "usage": {}, 124 | "props": [ 125 | { 126 | "name": "component", 127 | "type": "{ docs: string; docsTags: any[]; encapsulation: string; events: any[]; methods: any[]; phases: any; props: { attr: string; default: any; docs: string; docsTags: any[]; mutable: boolean; name: string; optional: boolean; reflectToAttr: boolean; required: boolean; type: string; }[]; readme: string; slots: any[]; styles: any[]; tag: string; usage: any; }", 128 | "mutable": false, 129 | "reflectToAttr": false, 130 | "docs": "", 131 | "docsTags": [], 132 | "optional": false, 133 | "required": false 134 | } 135 | ], 136 | "methods": [], 137 | "events": [ 138 | { 139 | "event": "enjinSetPhase", 140 | "detail": "any", 141 | "bubbles": true, 142 | "cancelable": true, 143 | "composed": true, 144 | "docs": "", 145 | "docsTags": [] 146 | } 147 | ], 148 | "styles": [], 149 | "slots": [] 150 | }, 151 | { 152 | "tag": "enjin-star-rating", 153 | "encapsulation": "none", 154 | "readme": "# enjin-star-rating\n\n\n", 155 | "docs": "", 156 | "docsTags": [], 157 | "usage": {}, 158 | "props": [ 159 | { 160 | "name": "disabled", 161 | "type": "boolean", 162 | "mutable": false, 163 | "attr": "disabled", 164 | "reflectToAttr": false, 165 | "docs": "Whether or not the field is disabled", 166 | "docsTags": [], 167 | "default": "false", 168 | "optional": false, 169 | "required": false 170 | }, 171 | { 172 | "name": "maxRating", 173 | "type": "number", 174 | "mutable": false, 175 | "attr": "max-rating", 176 | "reflectToAttr": false, 177 | "docs": "The max available star rating", 178 | "docsTags": [], 179 | "default": "5", 180 | "optional": false, 181 | "required": false 182 | }, 183 | { 184 | "name": "name", 185 | "type": "string", 186 | "mutable": false, 187 | "attr": "name", 188 | "reflectToAttr": false, 189 | "docs": "The name of the input", 190 | "docsTags": [], 191 | "default": "\"rating\"", 192 | "optional": false, 193 | "required": false 194 | }, 195 | { 196 | "name": "value", 197 | "type": "string", 198 | "mutable": false, 199 | "attr": "value", 200 | "reflectToAttr": false, 201 | "docs": "The value of the rating input", 202 | "docsTags": [], 203 | "optional": false, 204 | "required": false 205 | } 206 | ], 207 | "methods": [ 208 | { 209 | "name": "setCurrentRating", 210 | "returns": { 211 | "type": "Promise", 212 | "docs": "" 213 | }, 214 | "signature": "setCurrentRating(rating: any) => Promise", 215 | "parameters": [], 216 | "docs": "Set the current rating", 217 | "docsTags": [] 218 | } 219 | ], 220 | "events": [ 221 | { 222 | "event": "enjinStarRating", 223 | "detail": "any", 224 | "bubbles": true, 225 | "cancelable": true, 226 | "composed": true, 227 | "docs": "", 228 | "docsTags": [] 229 | } 230 | ], 231 | "styles": [], 232 | "slots": [] 233 | }, 234 | { 235 | "tag": "enjin-star-rating-scoped", 236 | "encapsulation": "scoped", 237 | "readme": "# enjin-star-rating-scoped\n\n\n", 238 | "docs": "", 239 | "docsTags": [], 240 | "usage": {}, 241 | "props": [ 242 | { 243 | "name": "disabled", 244 | "type": "boolean", 245 | "mutable": false, 246 | "attr": "disabled", 247 | "reflectToAttr": false, 248 | "docs": "", 249 | "docsTags": [], 250 | "default": "false", 251 | "optional": false, 252 | "required": false 253 | }, 254 | { 255 | "name": "maxRating", 256 | "type": "number", 257 | "mutable": false, 258 | "attr": "max-rating", 259 | "reflectToAttr": false, 260 | "docs": "", 261 | "docsTags": [], 262 | "default": "5", 263 | "optional": false, 264 | "required": false 265 | }, 266 | { 267 | "name": "name", 268 | "type": "string", 269 | "mutable": false, 270 | "attr": "name", 271 | "reflectToAttr": false, 272 | "docs": "", 273 | "docsTags": [], 274 | "default": "\"rating-scoped\"", 275 | "optional": false, 276 | "required": false 277 | }, 278 | { 279 | "name": "value", 280 | "type": "string", 281 | "mutable": false, 282 | "attr": "value", 283 | "reflectToAttr": false, 284 | "docs": "", 285 | "docsTags": [], 286 | "optional": false, 287 | "required": false 288 | } 289 | ], 290 | "methods": [ 291 | { 292 | "name": "setCurrentRating", 293 | "returns": { 294 | "type": "Promise", 295 | "docs": "" 296 | }, 297 | "signature": "setCurrentRating(rating: any) => Promise", 298 | "parameters": [], 299 | "docs": "", 300 | "docsTags": [] 301 | } 302 | ], 303 | "events": [ 304 | { 305 | "event": "ftStarRating", 306 | "detail": "any", 307 | "bubbles": true, 308 | "cancelable": true, 309 | "composed": true, 310 | "docs": "", 311 | "docsTags": [] 312 | } 313 | ], 314 | "styles": [], 315 | "slots": [] 316 | }, 317 | { 318 | "tag": "enjin-star-rating-shadow", 319 | "encapsulation": "shadow", 320 | "readme": "# enjin-star-rating-shadow\n\n\n", 321 | "docs": "", 322 | "docsTags": [], 323 | "usage": {}, 324 | "props": [ 325 | { 326 | "name": "disabled", 327 | "type": "boolean", 328 | "mutable": false, 329 | "attr": "disabled", 330 | "reflectToAttr": false, 331 | "docs": "", 332 | "docsTags": [], 333 | "default": "false", 334 | "optional": false, 335 | "required": false 336 | }, 337 | { 338 | "name": "maxRating", 339 | "type": "number", 340 | "mutable": false, 341 | "attr": "max-rating", 342 | "reflectToAttr": false, 343 | "docs": "", 344 | "docsTags": [], 345 | "default": "5", 346 | "optional": false, 347 | "required": false 348 | }, 349 | { 350 | "name": "name", 351 | "type": "string", 352 | "mutable": false, 353 | "attr": "name", 354 | "reflectToAttr": false, 355 | "docs": "", 356 | "docsTags": [], 357 | "default": "\"rating-shadow\"", 358 | "optional": false, 359 | "required": false 360 | }, 361 | { 362 | "name": "value", 363 | "type": "string", 364 | "mutable": false, 365 | "attr": "value", 366 | "reflectToAttr": false, 367 | "docs": "", 368 | "docsTags": [], 369 | "optional": false, 370 | "required": false 371 | } 372 | ], 373 | "methods": [ 374 | { 375 | "name": "setCurrentRating", 376 | "returns": { 377 | "type": "Promise", 378 | "docs": "" 379 | }, 380 | "signature": "setCurrentRating(rating: any) => Promise", 381 | "parameters": [], 382 | "docs": "", 383 | "docsTags": [] 384 | } 385 | ], 386 | "events": [ 387 | { 388 | "event": "ftStarRating", 389 | "detail": "any", 390 | "bubbles": true, 391 | "cancelable": true, 392 | "composed": true, 393 | "docs": "", 394 | "docsTags": [] 395 | } 396 | ], 397 | "styles": [], 398 | "slots": [] 399 | }, 400 | { 401 | "tag": "enjin-test-component", 402 | "encapsulation": "none", 403 | "readme": "# enjin-test-component\n\n\n", 404 | "docs": "", 405 | "docsTags": [], 406 | "usage": {}, 407 | "props": [], 408 | "methods": [], 409 | "events": [], 410 | "styles": [], 411 | "slots": [] 412 | } 413 | ] 414 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Enjin Components 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /stencil.config.ts: -------------------------------------------------------------------------------- 1 | import { Config } from '@stencil/core'; 2 | 3 | export const config: Config = { 4 | namespace: 'Enjin', 5 | outputTargets:[ 6 | { 7 | type: 'dist', 8 | esmLoaderPath: "../loader" 9 | }, 10 | { 11 | type: 'www', 12 | serviceWorker: null 13 | }, 14 | { 15 | type: 'docs-readme' 16 | } 17 | ], 18 | preamble: '(C) Madness Labs https://MadnessLabs.net - MIT License', 19 | }; 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "allowUnreachableCode": false, 5 | "declaration": false, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "dom", 9 | "es2017" 10 | ], 11 | "moduleResolution": "node", 12 | "module": "esnext", 13 | "target": "es2017", 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "jsx": "react", 17 | "jsxFactory": "h" 18 | }, 19 | "include": [ 20 | "src", 21 | "types/jsx.d.ts" 22 | ], 23 | "exclude": [ 24 | "node_modules" 25 | ] 26 | } 27 | --------------------------------------------------------------------------------