├── .circleci └── config.yml ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── everything-else.md │ └── feature_request.md ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .storybook ├── main.js ├── manager.js ├── preview-head.html └── preview.js ├── LICENSE ├── README.md ├── __snapshots__ ├── chameleon-accordion.md ├── chameleon-accordions.md ├── chameleon-chart.md ├── chameleon-checkbox.md ├── chameleon-date.md ├── chameleon-input.md ├── chameleon-multiselect.md ├── chameleon-radio.md ├── chameleon-select.md ├── chameleon-sheet.md └── chameleon-table.md ├── babel.config.json ├── docs ├── assets │ └── chameleon.jpg └── typography.md ├── karma.conf.js ├── lerna.json ├── netlify.toml ├── package.json ├── packages ├── accordions │ ├── README.md │ ├── __tests__ │ │ ├── chameleon-accordion.test.js │ │ └── chameleon-accordions.test.js │ ├── chameleon-accordion.js │ ├── chameleon-accordions.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonAccordion.js │ │ ├── ChameleonAccordionStyle.js │ │ ├── ChameleonAccordions.js │ │ └── ChameleonAccordionsStyle.js ├── alert │ ├── README.md │ ├── __tests__ │ │ └── chameleon-alert.test.js │ ├── chameleon-alert.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonAlert.js │ │ └── ChameleonAlertStyle.js ├── button │ ├── README.md │ ├── __tests__ │ │ └── chameleon-button.test.js │ ├── chameleon-button.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonButton.js │ │ └── ChameleonButtonStyle.js ├── card │ ├── README.md │ ├── __tests__ │ │ ├── chameleon-card-footer.test.js │ │ ├── chameleon-card-header.test.js │ │ ├── chameleon-card-image.test.js │ │ └── chameleon-card.test.js │ ├── chameleon-card-footer.js │ ├── chameleon-card-header.js │ ├── chameleon-card-image.js │ ├── chameleon-card.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonCard.js │ │ ├── ChameleonCardFooter.js │ │ ├── ChameleonCardFooterStyle.js │ │ ├── ChameleonCardHeader.js │ │ ├── ChameleonCardHeaderStyle.js │ │ ├── ChameleonCardImage.js │ │ ├── ChameleonCardImageStyle.js │ │ └── ChameleonCardStyle.js ├── chart │ ├── README.md │ ├── __tests__ │ │ └── chameleon-chart.test.js │ ├── chameleon-chart.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonChart.js │ │ └── ChameleonChartStyle.js ├── checkbox │ ├── README.md │ ├── __tests__ │ │ └── chameleon-checkbox.test.js │ ├── chameleon-checkbox.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonCheckbox.js │ │ └── ChameleonCheckboxStyle.js ├── chip │ ├── README.md │ ├── __tests__ │ │ └── chameleon-chip.test.js │ ├── chameleon-chip.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonChip.js │ │ └── ChameleonChipStyle.js ├── date │ ├── README.md │ ├── __tests__ │ │ └── chameleon-date.test.js │ ├── chameleon-date.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonDate.js │ │ └── ChameleonDateStyle.js ├── dialog │ ├── README.md │ ├── __tests__ │ │ └── chameleon-dialog.test.js │ ├── chameleon-dialog.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonDialog.js │ │ └── ChameleonDialogStyle.js ├── hero │ ├── README.md │ ├── __tests__ │ │ └── chameleon-hero.test.js │ ├── chameleon-hero.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonHero.js │ │ └── ChameleonHeroStyle.js ├── input │ ├── README.md │ ├── __tests__ │ │ └── chameleon-input.test.js │ ├── chameleon-input.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonInput.js │ │ └── ChameleonInputStyle.js ├── loader │ ├── README.md │ ├── __tests__ │ │ └── chameleon-loader.test.js │ ├── chameleon-loader.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonLoader.js │ │ ├── ChameleonLoaderEllipsisStyle.js │ │ ├── ChameleonLoaderSpinnerStyle.js │ │ └── ChameleonLoaderStyle.js ├── modal │ ├── README.md │ ├── __tests__ │ │ └── chameleon-modal.test.js │ ├── chameleon-modal.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonModal.js │ │ └── ChameleonModalStyle.js ├── multiselect │ ├── README.md │ ├── __tests__ │ │ └── chameleon-multiselect.test.js │ ├── chameleon-multiselect.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonMultiselect.js │ │ └── ChameleonMultiselectStyle.js ├── paginator │ ├── README.md │ ├── __tests__ │ │ └── chameleon-paginator.test.js │ ├── chameleon-paginator.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonPaginator.js │ │ └── ChameleonPaginatorStyle.js ├── progress-bar │ ├── README.md │ ├── __tests__ │ │ └── chameleon-progress-bar.test.js │ ├── chameleon-progress-bar.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonProgressBar.js │ │ └── ChameleonProgressBarStyle.js ├── radio │ ├── README.md │ ├── __tests__ │ │ └── chameleon-radio.test.js │ ├── chameleon-radio.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonRadio.js │ │ └── ChameleonRadioStyle.js ├── select │ ├── README.md │ ├── __tests__ │ │ └── chameleon-select.test.js │ ├── chameleon-select.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonSelect.js │ │ └── ChameleonSelectStyle.js ├── sheet │ ├── README.md │ ├── __tests__ │ │ ├── chameleon-sheet.test.js │ │ └── sheet-content.test.js │ ├── chameleon-sheet.js │ ├── index.js │ ├── package.json │ ├── sheet-content.js │ └── src │ │ ├── ChameleonSheet.js │ │ └── SheetContent.js ├── skeleton │ ├── README.md │ ├── __tests__ │ │ └── chameleon-skeleton.test.js │ ├── chameleon-skeleton.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonSkeleton.js │ │ └── ChameleonSkeletonStyle.js ├── switch │ ├── README.md │ ├── __tests__ │ │ └── chameleon-switch.test.js │ ├── chameleon-switch.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonSwitch.js │ │ └── ChameleonSwitchStyle.js ├── table │ ├── README.md │ ├── __tests__ │ │ └── chameleon-table.test.js │ ├── chameleon-table.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonTable.js │ │ └── ChameleonTableStyle.js ├── tabs │ ├── README.md │ ├── __tests__ │ │ └── chameleon-tabs.test.js │ ├── chameleon-tab.js │ ├── chameleon-tabs.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonTab.js │ │ ├── ChameleonTabs.js │ │ └── ChameleonTabsStyle.js ├── textarea │ ├── README.md │ ├── __tests__ │ │ └── chameleon-textarea.test.js │ ├── chameleon-textarea.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonTextarea.js │ │ └── ChameleonTextareaStyle.js ├── theme │ ├── README.md │ ├── base │ │ └── index.js │ └── package.json ├── timezone │ ├── README.md │ ├── __tests__ │ │ └── chameleon-timezone.test.js │ ├── chameleon-timezone.js │ ├── data │ │ └── timezones.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── ChameleonTimezone.js │ │ └── ChameleonTimezoneStyle.js └── toast │ ├── README.md │ ├── __tests__ │ └── chameleon-toast.test.js │ ├── chameleon-toast.js │ ├── index.js │ ├── package.json │ └── src │ ├── ChameleonToast.js │ └── ChameleonToastStyle.js ├── scripts └── linker.js └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build: 4 | working_directory: ~/chameleon 5 | docker: 6 | - image: circleci/node:current-browsers 7 | environment: 8 | TZ: "America/Chicago" 9 | steps: 10 | - checkout 11 | - run: 12 | name: Install Dependencies 13 | command: | 14 | npm config set prefix '~/.npm-global' 15 | yarn setup 16 | - run: # run tests 17 | name: Test 18 | command: yarn test 19 | # COMMENTING THIS OUT UNTIL @open-wc/testing-karma GETS 20 | # UPDATED WITH THE LATEST ISTANBUL LIBRARIES 21 | # - run: # run coverage report 22 | # name: Code Coverage 23 | # command: | 24 | # yarn run generate:codecov 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/everything-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Everything Else 3 | about: For everything else 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE REQUEST]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | npm-debug.log* 3 | lerna-debug.log* 4 | yarn-error.log* 5 | 6 | # Coverage directory used by tools like istanbul 7 | coverage 8 | *.lcov 9 | 10 | # Dependency directories 11 | node_modules/ 12 | 13 | # System files 14 | .DS_Store 15 | 16 | # Generated distribution files 17 | lib/ 18 | site/ 19 | 20 | # Compiler Output 21 | /**/*.js.map 22 | /**/*.d.ts 23 | /**/*.d.ts.map 24 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v12 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | docs/ 2 | __snapshots__/ 3 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ["../README.md", "../docs/**/*.md", "../packages/*/README.md"], 3 | addons: [ 4 | "storybook-prebuilt/addon-knobs/register.js", 5 | "storybook-prebuilt/addon-docs/register.js", 6 | "storybook-prebuilt/addon-viewport/register.js", 7 | "storybook-prebuilt/addon-backgrounds/register.js", 8 | ], 9 | esDevServer: { 10 | nodeResolve: true, 11 | watch: true, 12 | open: true, 13 | babel: true, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { addons } from "storybook-prebuilt/addons.js"; 2 | import { create } from "storybook-prebuilt/theming/create.js"; 3 | 4 | addons.setConfig({ 5 | theme: create({ 6 | base: "light", 7 | brandTitle: "Chameleon", 8 | brandUrl: "https://github.com/maritzstl/chameleon", 9 | }), 10 | }); 11 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { addParameters, setCustomElements } from "@open-wc/demoing-storybook"; 2 | 3 | addParameters({ 4 | docs: { 5 | iframeHeight: "300px", 6 | }, 7 | }); 8 | 9 | async function run() { 10 | // const customElements = await ( 11 | // await fetch(new URL("../custom-elements.json", import.meta.url)) 12 | // ).json(); 13 | 14 | setCustomElements({}); 15 | } 16 | 17 | run(); 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maritz Motivation Solutions, Inc. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | [![Netlify Status](https://api.netlify.com/api/v1/badges/1dec763c-8977-46bc-b008-140b158960f6/deploy-status)](https://app.netlify.com/sites/chameleon-design-system/deploys) 6 | [![CircleCI](https://circleci.com/gh/MaritzSTL/chameleon/tree/master.svg?style=shield)](https://circleci.com/gh/MaritzSTL/chameleon/tree/master) 7 | [![codecov](https://codecov.io/gh/MaritzSTL/chameleon/branch/master/graph/badge.svg)](https://codecov.io/gh/MaritzSTL/chameleon) 8 | 9 | # Chameleon Web Components 10 | 11 | ```js script 12 | export default { 13 | title: "Intro|Chameleon Web Components", 14 | options: { selectedPanel: "storybookjs/docs/panel" }, 15 | }; 16 | ``` 17 | 18 | Chameleon Web Components - A collection of lightweight, unidirectional, framework-agnostic elements based on the Chameleon Design System. 19 | 20 | ## Prerequisites 21 | 22 | The Chameleon project relies on some awesome tools in order to work properly. You'll want to have the following installed: 23 | 24 | - [Node.js](https://nodejs.org) - JavaScript runtime built on Chrome's V8 JavaScript Engine (this project uses v12.7.0) 25 | - [Git](https://git-scm.com/downloads) - Version control software for cloning this repository 26 | - [NVM (Node Version Manager)](https://github.com/nvm-sh/nvm) - A bash script to manage multiple active node.js versions 27 | - [Yarn](https://yarnpkg.com/lang/en/) - Package manager used for Yarn workspaces 28 | 29 | ## Setup 30 | 31 | **Note:** Please ensure you have all the prerequisite software installed before running any of these commands! 32 | 33 | To setup Chameleon for development, run the following in your folder of choice: 34 | 35 | ```bash 36 | git clone git@github.com:MaritzSTL/chameleon.git && cd chameleon && nvm use && yarn setup 37 | ``` 38 | 39 | Chameleon uses storybook for development, so when you're ready to get going just run: 40 | 41 | ```bash 42 | yarn dev 43 | ``` 44 | 45 | To build each element and package for distribution, run: 46 | 47 | ```bash 48 | yarn build 49 | ``` 50 | 51 | If something looks wrong or you need to refresh your dependencies for whatever reason you can run: 52 | 53 | ```bash 54 | yarn clean 55 | ``` 56 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-accordion.md: -------------------------------------------------------------------------------- 1 | # `chameleon-accordion` 2 | 3 | #### `renders !expanded correctly` 4 | 5 | ```html 6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 | 20 | 21 | ``` 22 | 23 | ```html 24 |
25 |
26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 |
34 | 38 | ``` 39 | 40 | #### `renders expanded correctly` 41 | 42 | ```html 43 |
44 |
45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 | 58 | ``` 59 | 60 | ```html 61 |
62 |
63 | 64 | 65 | 66 | 67 |
68 | 69 | 70 |
71 |
72 | 73 | 74 |
75 | ``` 76 | 77 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-accordions.md: -------------------------------------------------------------------------------- 1 | # `chameleon-accordions` 2 | 3 | #### `renders any slotted content` 4 | 5 | ```html 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ``` 14 | 15 | ```html 16 | 17 | 18 | 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-chart.md: -------------------------------------------------------------------------------- 1 | # `chameleon-chart` 2 | 3 | #### `returns the arc chart type` 4 | 5 | ```html 6 | 13 | 14 | 21 | 22 | 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-checkbox.md: -------------------------------------------------------------------------------- 1 | # `chameleon-checkbox` 2 | 3 | #### `shows aria-invalid when invalid` 4 | 5 | ```html 6 | 12 | 13 | 14 | 15 | ``` 16 | 17 | #### `shows name attribute` 18 | 19 | ```html 20 | 26 | 27 | 28 | 29 | ``` 30 | 31 | #### `shows required attribute` 32 | 33 | ```html 34 | 41 | 42 | 43 | 44 | ``` 45 | 46 | #### `shows readonly attribute` 47 | 48 | ```html 49 | 55 | 56 | 57 | 58 | ``` 59 | 60 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-date.md: -------------------------------------------------------------------------------- 1 | # `chameleon-date` 2 | 3 | #### `prevIcon() returns default icon if none is supplied` 4 | 5 | ```html 6 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | ``` 23 | 24 | #### `prevIcon() returns the slot if one is provided` 25 | 26 | ```html 27 | 28 | 29 | 30 | ``` 31 | 32 | #### `nextIcon() returns default icon if none is supplied` 33 | 34 | ```html 35 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | ``` 52 | 53 | #### `nextIcon() returns the slot if one is provided` 54 | 55 | ```html 56 | 57 | 58 | 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-input.md: -------------------------------------------------------------------------------- 1 | # `chameleon-input` 2 | 3 | #### `_inputEl renders number type` 4 | 5 | ```html 6 | 15 | 16 | ``` 17 | 18 | #### `_inputEl renders default type` 19 | 20 | ```html 21 | 28 | 29 | ``` 30 | 31 | #### `_inputEl renders disabled` 32 | 33 | ```html 34 | 42 | 43 | ``` 44 | 45 | #### `_inputEl renders readonly` 46 | 47 | ```html 48 | 56 | 57 | ``` 58 | 59 | #### `renders errorText` 60 | 61 | ```html 62 | 66 | chameleon 67 | 68 | 69 | ``` 70 | 71 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-radio.md: -------------------------------------------------------------------------------- 1 | # `chameleon-radio` 2 | 3 | #### `shows aria-invalid when invalid` 4 | 5 | ```html 6 | 12 | 13 | 14 | 15 | ``` 16 | 17 | #### `shows name attribute` 18 | 19 | ```html 20 | 26 | 27 | 28 | 29 | ``` 30 | 31 | #### `shows disabled attribute` 32 | 33 | ```html 34 | 40 | 41 | 42 | 43 | ``` 44 | 45 | #### `shows readonly attribute` 46 | 47 | ```html 48 | 54 | 55 | 56 | 57 | ``` 58 | 59 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-sheet.md: -------------------------------------------------------------------------------- 1 | # `chameleon-sheet` 2 | 3 | #### `updatesSlot` 4 | 5 | ```html 6 |
7 |
8 | test 9 |
10 |
11 | 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /__snapshots__/chameleon-table.md: -------------------------------------------------------------------------------- 1 | # `chameleon-table` 2 | 3 | #### `doesn't render pagination if .hidePagination is true` 4 | 5 | ```html 6 | 7 | 8 | 9 | 24 | 31 | 38 | 45 | 46 | 47 | 48 | 49 | 52 | 55 | 58 | 61 | 62 | 63 | 64 | 68 | 71 | 74 | 77 | 80 | 81 | 85 | 86 | 87 |
10 |
11 |
12 | Column 1 13 |
14 | 21 | 22 |
23 |
25 |
26 |
27 | Column 2 28 |
29 |
30 |
32 |
33 |
34 | Column 3 35 |
36 |
37 |
39 |
40 |
41 | Column 4 42 |
43 |
44 |
50 | Row 1 - Field 1 51 | 53 | Row 1 - Field 2 54 | 56 | Row 1 - Field 3 57 | 59 | Row 1 - Field 4 60 |
69 | Row 2 - Field 1 70 | 72 | Row 2 - Field 2 73 | 75 | Row 2 - Field 3 76 | 78 | Row 2 - Field 4 79 |
88 | 89 | ``` 90 | 91 | #### `renderColumnSort` 92 | 93 | ```html 94 |
95 |
96 |
97 |
98 |
99 |
100 | 101 | ``` 102 | 103 | ## `icons` 104 | 105 | #### `renders chevronUpIcon` 106 | 107 | ```html 108 | 109 | 110 | 111 | ``` 112 | 113 | #### `renders chevronDownIcon` 114 | 115 | ```html 116 | 117 | 118 | 119 | ``` 120 | 121 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | ["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }], 4 | "@babel/plugin-proposal-class-properties", 5 | "@babel/plugin-proposal-nullish-coalescing-operator", 6 | "@babel/plugin-proposal-optional-chaining" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /docs/assets/chameleon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaritzSTL/chameleon/31383542fea4cd03d00fc690a5116f698c8bca65/docs/assets/chameleon.jpg -------------------------------------------------------------------------------- /docs/typography.md: -------------------------------------------------------------------------------- 1 | # Typography 2 | 3 | ```js script 4 | export default { 5 | title: "Intro|Typography" 6 | }; 7 | ``` 8 | 9 | ## Typefaces 10 | 11 | ### Primary Typeface 12 | 13 | #### Lato 14 | 15 | ### Secondary Typeface 16 | 17 | #### Source Sans Pro 18 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const { createDefaultConfig } = require("@open-wc/testing-karma"); 2 | const merge = require("deepmerge"); 3 | 4 | module.exports = (config) => { 5 | config.set( 6 | merge(createDefaultConfig(config), { 7 | files: [ 8 | { 9 | pattern: config.grep ? config.grep : "packages/**/*.test.js", 10 | type: "module", 11 | }, 12 | ], 13 | plugins: [require.resolve("@open-wc/karma-esm"), "karma-*"], 14 | frameworks: ["esm"], 15 | esm: { 16 | nodeResolve: true, 17 | babel: true, 18 | fileExtensions: [".js"], 19 | coverageExclude: ["packages/**/*.test.js"], 20 | }, 21 | coverageIstanbulReporter: { 22 | thresholds: { 23 | emitWarning: true, 24 | global: { 25 | statements: 90, 26 | functions: 90, 27 | branches: 90, 28 | }, 29 | }, 30 | }, 31 | }) 32 | ); 33 | return config; 34 | }; 35 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*"], 3 | "version": "independent" 4 | } 5 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "yarn build-storybook" 3 | publish = "site/" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chameleon-ds", 3 | "version": "2.0.0", 4 | "description": "Chameleon Web Components - A collection of lightweight, unidirectional, framework-agnostic elements based on the Chameleon Design System", 5 | "scripts": { 6 | "prepare": "yarn build", 7 | "setup": "yarn install", 8 | "clean": "lerna clean --yes && del-cli node_modules coverage **/dist && git clean -fX", 9 | "test": "karma start", 10 | "test:debug": "karma start --coverage --log-level DEBUG", 11 | "test:watch": "karma start --auto-watch=true --single-run=false", 12 | "test:update-snapshots": "karma start --update-snapshots", 13 | "test:prune-snapshots": "karma start --prune-snapshots", 14 | "dev": "start-storybook -p 60000", 15 | "generate:codecov": "codecov", 16 | "generate:custom-element-file": "wca analyze 'packages/**/src/**/*.js' --outFile custom-elements.json", 17 | "build:ci": "lerna exec --concurrency 2 -- yarn run build", 18 | "build": "lerna exec yarn run build", 19 | "build-storybook": "del-cli docs/assets/storybook/ && build-storybook -o site", 20 | "bump-versions": "lerna version", 21 | "publish-packages": "lerna publish --yes from-package" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 26 | }, 27 | "author": "Maritz Motivation Solutions, Inc.", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/MaritzSTL/chameleon/issues" 31 | }, 32 | "homepage": "https://github.com/MaritzSTL/chameleon#readme", 33 | "private": true, 34 | "workspaces": [ 35 | "packages/*" 36 | ], 37 | "devDependencies": { 38 | "@babel/cli": "^7.10.1", 39 | "@babel/core": "^7.10.2", 40 | "@babel/plugin-proposal-class-properties": "^7.10.1", 41 | "@babel/plugin-proposal-decorators": "^7.10.1", 42 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1", 43 | "@babel/plugin-proposal-optional-chaining": "^7.10.1", 44 | "@babel/plugin-transform-react-jsx": "^7.10.1", 45 | "@open-wc/demoing-storybook": "^2.3.6", 46 | "@open-wc/karma-esm": "^2.13.21", 47 | "@open-wc/testing": "^2.5.8", 48 | "@open-wc/testing-karma": "^3.3.10", 49 | "@storybook/theming": "^5.3.19", 50 | "codecov": "^3.6.5", 51 | "deepmerge": "^4.2.2", 52 | "del-cli": "^3.0.0", 53 | "eslint": "^6.8.0", 54 | "husky": "^4.2.3", 55 | "lerna": "^3.20.2", 56 | "lit-html": "^1.2.1", 57 | "prettier": "^2.0.2", 58 | "pretty-quick": "^2.0.1", 59 | "react": "^16.3.0", 60 | "react-dom": "^16.3.0", 61 | "rollup": "^1.20.0", 62 | "sinon": "^7.5.0", 63 | "web-component-analyzer": "^1.0.3" 64 | }, 65 | "husky": { 66 | "hooks": { 67 | "pre-commit": "pretty-quick --staged" 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/accordions/__tests__/chameleon-accordions.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-accordion.js"; 3 | import "../chameleon-accordions.js"; 4 | 5 | const fixture = html` 6 | 7 | 8 | 9 | 10 | `; 11 | 12 | describe("chameleon-accordions", () => { 13 | let el; 14 | 15 | beforeEach(async () => { 16 | el = await litFixture(fixture); 17 | }); 18 | 19 | it("renders any slotted content", () => { 20 | expect(el).dom.to.equalSnapshot({ ignoreAttributes: ["uid"] }); 21 | expect(el).shadowDom.to.equalSnapshot(); 22 | }); 23 | it("registers accordions on `accordion-connected`", () => { 24 | expect(el.accordions.length).to.equal(2); 25 | }); 26 | it("unregisters accordions on `accordion-disconnected`", async () => { 27 | const initialAccordions = Array.from( 28 | el.querySelectorAll("chameleon-accordion") 29 | ).map((acc) => acc.uid); 30 | const accordion = el.querySelector("chameleon-accordion"); 31 | const removedUid = accordion.uid; 32 | 33 | accordion.disconnectedCallback(); 34 | 35 | expect(initialAccordions.length).to.equal(2); 36 | expect(el.accordions.length).to.equal(1); 37 | expect(el.accordions.indexOf(removedUid)).to.equal(-1); 38 | }); 39 | it("toggles targeted accordion on `toggle-accordion`", () => { 40 | const accordion = el.querySelector("chameleon-accordion"); 41 | expect(accordion.expanded).to.equal(false); 42 | accordion.header.click(); 43 | expect(accordion.expanded).to.equal(true); 44 | }); 45 | it("closes all other registered accordions of targeted accordion is expanded", () => { 46 | const accordions = Array.from(el.querySelectorAll("chameleon-accordion")); 47 | accordions[0].expanded = true; 48 | 49 | expect(accordions[0].expanded).to.equal(true); 50 | expect(accordions[1].expanded).to.equal(false); 51 | 52 | accordions[1].header.click(); 53 | 54 | expect(accordions[0].expanded).to.equal(false); 55 | expect(accordions[1].expanded).to.equal(true); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /packages/accordions/chameleon-accordion.js: -------------------------------------------------------------------------------- 1 | import { ChameleonAccordion } from "./lib/ChameleonAccordion.js"; 2 | 3 | customElements.define("chameleon-accordion", ChameleonAccordion); 4 | -------------------------------------------------------------------------------- /packages/accordions/chameleon-accordions.js: -------------------------------------------------------------------------------- 1 | import { ChameleonAccordions } from "./lib/ChameleonAccordions.js"; 2 | 3 | customElements.define("chameleon-accordions", ChameleonAccordions); 4 | -------------------------------------------------------------------------------- /packages/accordions/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonAccordion } from "./lib/ChameleonAccordion.js"; 2 | export { ChameleonAccordionStyle } from "./lib/ChameleonAccordionStyle.js"; 3 | export { ChameleonAccordions } from "./lib/ChameleonAccordions.js"; 4 | export { ChameleonAccordionsStyle } from "./lib/ChameleonAccordionsStyle.js"; 5 | -------------------------------------------------------------------------------- /packages/accordions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/accordions", 3 | "version": "4.0.1", 4 | "description": "Chameleon accordions", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/accordions#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-accordion.js", 16 | "chameleon-accordions.js", 17 | "/lib/" 18 | ], 19 | "scripts": { 20 | "test": "echo \"Error: run tests from root\" && exit 1", 21 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/MaritzSTL/chameleon/issues" 25 | }, 26 | "dependencies": { 27 | "lit-element": "^2.2.1" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/accordions/src/ChameleonAccordionStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonAccordionStyle = css` 4 | :host { 5 | display: block; 6 | } 7 | 8 | .header { 9 | background-color: var(--accordion-background-color, #ffffff); 10 | border: 1px solid var(--color-gray-dark, #9fa4a8); 11 | border-radius: var(--border-radius, 0.5rem); 12 | cursor: pointer; 13 | display: flex; 14 | flex-direction: column; 15 | padding: 13px; 16 | } 17 | 18 | :host([expanded]) .header { 19 | border-radius: var(--border-radius, 0.5rem) var(--border-radius, 0.5rem) 0 0; 20 | } 21 | 22 | .header-toggle { 23 | align-items: center; 24 | display: flex; 25 | } 26 | 27 | .header-toggle chameleon-button { 28 | margin: 0 15px; 29 | } 30 | 31 | .panel { 32 | border: 1px solid var(--color-gray-dark, #9fa4a8); 33 | border-radius: 0 0 var(--border-radius, 0.5rem) var(--border-radius, 0.5rem); 34 | border-top: none; 35 | padding: 13px; 36 | } 37 | 38 | .panel.collapsed { 39 | display: none; 40 | } 41 | 42 | .panel.expanded { 43 | display: block; 44 | } 45 | 46 | .toggle-icon { 47 | margin: 0 30px 0 17px; 48 | } 49 | 50 | .toggle-icon svg { 51 | transition: transform 0.2s ease-in-out; 52 | } 53 | 54 | .toggle-icon.rotate svg { 55 | transform: rotate(90deg); 56 | } 57 | `; 58 | -------------------------------------------------------------------------------- /packages/accordions/src/ChameleonAccordions.js: -------------------------------------------------------------------------------- 1 | import { LitElement, property, html } from "lit-element"; 2 | import { ChameleonAccordionsStyle } from "./ChameleonAccordionsStyle.js"; 3 | 4 | export class ChameleonAccordions extends LitElement { 5 | /** 6 | * Lifecycle Methods 7 | */ 8 | constructor() { 9 | super(); 10 | this.addEventListener("accordion-connected", this._registerAccordion); 11 | this.addEventListener("toggle-accordion", this._handleToggle); 12 | this.addEventListener("accordion-disconnected", this._unregisterAccordion); 13 | } 14 | /** 15 | * Properties 16 | */ 17 | @property({ type: Array }) accordions = []; 18 | 19 | /** 20 | * Styles 21 | */ 22 | static styles = [ChameleonAccordionsStyle]; 23 | 24 | /** 25 | * Template 26 | */ 27 | render() { 28 | return html``; 29 | } 30 | 31 | _registerAccordion(e) { 32 | this.accordions = [...this.accordions, e.target]; 33 | e.detail.connected = true; 34 | e.stopPropagation(); 35 | } 36 | 37 | _unregisterAccordion(e) { 38 | this.accordions = [ 39 | ...this.accordions.filter((accordion) => accordion.uid !== e.target.uid), 40 | ]; 41 | e.stopPropagation(); 42 | } 43 | 44 | _handleToggle(e) { 45 | const accordionToToggle = this.accordions.find( 46 | (accordion) => accordion.uid === e.target.uid 47 | ); 48 | accordionToToggle.expanded = !accordionToToggle.expanded; 49 | 50 | // if opening one, close all others 51 | if (accordionToToggle.expanded) { 52 | this.accordions 53 | .filter((accordion) => accordion !== accordionToToggle) 54 | .forEach((accordion) => (accordion.expanded = false)); 55 | } 56 | 57 | e.stopPropagation(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/accordions/src/ChameleonAccordionsStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonAccordionsStyle = css` 4 | :host { 5 | display: block; 6 | width: var(--accordion-width, 100%); 7 | font-family: var(--font-family, sans-serif); 8 | } 9 | 10 | ::slotted(chameleon-accordion:not(:last-of-type)) { 11 | margin-bottom: 25px; 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /packages/alert/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Alert 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import "./chameleon-alert.js"; 6 | 7 | export default { 8 | title: "Components|Feedback/Alert", 9 | component: "chameleon-alert", 10 | options: { selectedPanel: "storybookjs/docs/panel" }, 11 | }; 12 | ``` 13 | 14 | ## Examples 15 | 16 | ### Default 17 | 18 | ```js preview-story 19 | export const Default = () => html` 20 | 21 | Riverside cleanup will meet at the Gateway Arch on Saturday! 22 | 23 | `; 24 | ``` 25 | -------------------------------------------------------------------------------- /packages/alert/__tests__/chameleon-alert.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-alert.js"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-alert", () => { 7 | let element; 8 | 9 | beforeEach(async () => { 10 | element = await litFixture(fixture); 11 | }); 12 | 13 | it("renders", () => { 14 | expect(Boolean(element.shadowRoot)).to.equal(true); 15 | }); 16 | 17 | // TODO: this test passes when it shouldn't 18 | xit("handle close removes the element from the DOM", async () => { 19 | // element.handleClose(); 20 | // element.requestUpdate(); 21 | // await element.updateComplete; 22 | 23 | expect(element).lightDom.to.equal(""); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/alert/chameleon-alert.js: -------------------------------------------------------------------------------- 1 | import { ChameleonAlert } from "./lib/ChameleonAlert.js"; 2 | 3 | customElements.define("chameleon-alert", ChameleonAlert); 4 | -------------------------------------------------------------------------------- /packages/alert/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonAlert } from "./lib/ChameleonAlert.js"; 2 | export { ChameleonAlertStyle } from "./lib/ChameleonAlertStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/alert/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/alert", 3 | "version": "2.0.1", 4 | "description": "Chameleon alert", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/alert#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-alert.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/alert/src/ChameleonAlert.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, svg } from "lit-element"; 2 | import { ChameleonAlertStyle } from "./ChameleonAlertStyle"; 3 | 4 | export class ChameleonAlert extends LitElement { 5 | /** 6 | * Styles 7 | */ 8 | static styles = [ChameleonAlertStyle]; 9 | 10 | /** 11 | * Template 12 | */ 13 | render() { 14 | return html` 15 | ${this.alertIcon} 16 | 17 | 18 | ${this.closeIcon} 19 | 20 | `; 21 | } 22 | 23 | handleClose() { 24 | this.remove(); 25 | } 26 | 27 | get alertIcon() { 28 | return svg` 29 | 40 | 41 | 42 | 43 | 44 | 45 | `; 46 | } 47 | 48 | get closeIcon() { 49 | return svg` 50 | 60 | 61 | 62 | 63 | `; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/alert/src/ChameleonAlertStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonAlertStyle = css` 4 | :host { 5 | align-items: center; 6 | background-color: var(--color-error-lightest, #f1d1d0); 7 | border: 1px solid var(--color-error, #bc1c16); 8 | border-radius: var(--border-radius-input, 0.313rem); 9 | color: var(--color-error, #bc1c16); 10 | display: inline-flex; 11 | padding: 14px 10px; 12 | } 13 | 14 | .closebtn { 15 | color: var(--color-error, #bc1c16); 16 | cursor: pointer; 17 | display: flex; 18 | margin: 0px 0px 0px 15px; 19 | } 20 | 21 | .icon { 22 | height: 24px; 23 | margin: 0px 15px 0px 0px; 24 | } 25 | 26 | .message { 27 | font-size: var(--font-size-input, 0.938rem); 28 | font-weight: 600; 29 | } 30 | `; 31 | -------------------------------------------------------------------------------- /packages/button/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Button 2 | 3 | ```js script 4 | import { html, svg } from "lit-html"; 5 | import "./chameleon-button.js"; 6 | 7 | export default { 8 | title: "Components|Buttons/Button", 9 | component: "chameleon-button", 10 | options: { selectedPanel: "storybookjs/docs/panel" }, 11 | }; 12 | ``` 13 | 14 | ## Properties 15 | 16 | | Property Name | Type(s) | Default Value | Description | 17 | | ------------- | ------- | ------------- | ----------------------------------------------------------- | 18 | | `disabled` | Boolean | `false` | Whether or not the button is disabled | 19 | | `loading` | Boolean | `false` | When true, a loading spinner will display | 20 | | `theme` | String | `"primary"` | The theme of the button ("primary", "secondary", or "text") | 21 | | `icon-left` | Boolean | `false` | When true, will display a left icon | 22 | | `icon-right` | Boolean | `false` | When true, will display a right icon | 23 | | `icon-only` | Boolean | `false` | When true, will display only an icon | 24 | | `href` | String | `null` | The link href | 25 | | `target` | String | `"_top"` | The link target | 26 | 27 | ## Examples 28 | 29 | ### Default 30 | 31 | ```js preview-story 32 | export const Default = () => html`Login`; 33 | ``` 34 | 35 | ### Secondary Theme 36 | 37 | ```js preview-story 38 | export const SecondaryTheme = () => 39 | html`Login`; 40 | ``` 41 | 42 | ### Text Theme 43 | 44 | ```js preview-story 45 | export const TextTheme = () => 46 | html`Login`; 47 | ``` 48 | 49 | ### Text with Icon 50 | 51 | ```js preview-story 52 | const heartIconLeft = svg``; 53 | 54 | export const TextWithIcon = () => 55 | html`${heartIconLeft} Love`; 58 | ``` 59 | 60 | ### Icon Only 61 | 62 | ```js preview-story 63 | const heartIcon = svg``; 64 | 65 | export const IconOnly = () => 66 | html`${heartIcon}`; 69 | ``` 70 | -------------------------------------------------------------------------------- /packages/button/__tests__/chameleon-button.test.js: -------------------------------------------------------------------------------- 1 | import { fixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-button.js"; 3 | 4 | describe("chameleon-button", () => { 5 | it("renders", async () => { 6 | const el = await fixture(html` `); 7 | expect(Boolean(el.shadowRoot)).to.equal(true); 8 | }); 9 | 10 | it("renders as a button when no href is set", async () => { 11 | const el = await fixture(html` `); 12 | expect(Boolean(el.shadowRoot.querySelector(":host > button"))).to.equal( 13 | true 14 | ); 15 | expect(Boolean(el.shadowRoot.querySelector(":host > a"))).to.equal(false); 16 | }); 17 | 18 | it("renders as a link when an href is set", async () => { 19 | const el = await fixture( 20 | html` 21 | 24 | ` 25 | ); 26 | 27 | expect(Boolean(el.shadowRoot.querySelector(":host > a"))).to.equal(true); 28 | expect(Boolean(el.shadowRoot.querySelector(":host > button"))).to.equal( 29 | false 30 | ); 31 | }); 32 | 33 | it("anchor sets target to _top when target is missing", async () => { 34 | const el = await fixture( 35 | html` 36 | 39 | ` 40 | ); 41 | 42 | expect( 43 | Boolean(el.shadowRoot.querySelector(":host > a[target='_top']")) 44 | ).to.equal(true); 45 | }); 46 | 47 | it("anchor sets target to _top when target set to _top", async () => { 48 | const el = await fixture( 49 | html` 50 | 54 | ` 55 | ); 56 | 57 | expect( 58 | Boolean(el.shadowRoot.querySelector(":host > a[target='_top']")) 59 | ).to.equal(true); 60 | }); 61 | 62 | it("anchor sets target to _blank when target set to _blank", async () => { 63 | const el = await fixture( 64 | html` 65 | 69 | ` 70 | ); 71 | 72 | expect( 73 | Boolean(el.shadowRoot.querySelector(":host > a[target='_blank']")) 74 | ).to.equal(true); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /packages/button/chameleon-button.js: -------------------------------------------------------------------------------- 1 | import { ChameleonButton } from "./lib/ChameleonButton.js"; 2 | 3 | customElements.define("chameleon-button", ChameleonButton); 4 | -------------------------------------------------------------------------------- /packages/button/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonButton } from "./lib/ChameleonButton.js"; 2 | export { ChameleonButtonStyle } from "./lib/ChameleonButtonStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/button", 3 | "version": "2.0.1", 4 | "description": "Chameleon button", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/button#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-button.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/loader": "^2.0.1", 27 | "lit-element": "^2.2.1" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | }, 32 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 33 | } 34 | -------------------------------------------------------------------------------- /packages/button/src/ChameleonButton.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { classMap } from "lit-html/directives/class-map"; 4 | import { ChameleonButtonStyle } from "./ChameleonButtonStyle.js"; 5 | import "@chameleon-ds/loader/chameleon-loader.js"; 6 | 7 | export class ChameleonButton extends LitElement { 8 | /** 9 | * Properties 10 | */ 11 | @property({ type: Boolean, reflect: true }) 12 | disabled = false; 13 | 14 | @property({ type: Boolean, reflect: true }) 15 | loading = false; 16 | 17 | @property({ type: String, reflect: true }) 18 | theme = "primary"; 19 | 20 | // Element has a left icon 21 | @property({ type: Boolean, reflect: true }) 22 | "icon-left" = false; 23 | 24 | // Element has a right icon 25 | @property({ type: Boolean, reflect: true }) 26 | "icon-right" = false; 27 | 28 | // Element has a icon only 29 | @property({ type: Boolean, reflect: true }) 30 | "icon-only" = false; 31 | 32 | // Element has an href 33 | @property({ type: String, reflect: true }) 34 | href = null; 35 | 36 | // Element should honor the target 37 | @property({ type: String, reflect: true }) 38 | target = "_top"; 39 | 40 | /** 41 | * Styles 42 | */ 43 | static styles = [ChameleonButtonStyle]; 44 | 45 | /** 46 | * Template 47 | */ 48 | render() { 49 | return html` 50 | ${this.href && !this.disabled 51 | ? html` 52 | 53 | ${this.renderButton()} 54 | 55 | ` 56 | : html` ${this.renderButton()} `} 57 | `; 58 | } 59 | 60 | renderButton() { 61 | return html` 62 | 78 | `; 79 | } 80 | 81 | getRel() { 82 | return this.target === "_blank" ? `noopener noreferrer` : ``; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/button/src/ChameleonButtonStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonButtonStyle = css` 4 | :host { 5 | --button-border-color: var(--color-primary, #2c6fb7); 6 | --button-hover-color: var(--color-primary-dark, #004587); 7 | --button-hover-text-color: var(--color-surface, #ffffff); 8 | --button-text-color: var(--color-primary, #2c6fb7); 9 | display: inline-flex; 10 | height: var(--button-height, 40px); 11 | } 12 | 13 | :host([full-width]) { 14 | width: 100%; 15 | } 16 | 17 | :host([full-width]) a, 18 | :host([full-width]) button { 19 | width: 100%; 20 | } 21 | 22 | :host([icon-only]), 23 | :host([theme="text"]) { 24 | --button-height: auto; 25 | } 26 | 27 | :host([icon-only]) button, 28 | :host([icon-left]) button, 29 | :host([icon-right]) button { 30 | padding: 0; 31 | } 32 | 33 | :host([disabled]) { 34 | pointer-events: none; 35 | } 36 | 37 | a { 38 | display: inline-block; 39 | text-decoration: none; 40 | } 41 | 42 | button[disabled] { 43 | background-color: var(--color-gray-lightest, #e1e3e4); 44 | border-color: var(--color-gray-lightest, #e1e3e4); 45 | color: var(--color-gray-darkest, #6c737a); 46 | } 47 | 48 | button { 49 | align-items: center; 50 | background-color: var(--color-primary, #2c6fb7); 51 | border-radius: var(--border-radius-input, 0.313rem); 52 | border: 1px solid var(--button-border-color); 53 | color: var(--color-surface, #ffffff); 54 | cursor: pointer; 55 | display: flex; 56 | font-family: var(--font-family, sans-serif); 57 | font-weight: var(--font-weight, 600); 58 | font-size: var(--font-size-paragraph-medium, 0.938rem); 59 | justify-content: center; 60 | letter-spacing: var(--font-letter-spacing, 0.018rem); 61 | line-height: 1; 62 | padding: var(--button-padding, 0.75rem 1.375rem); 63 | position: relative; 64 | transition: background-color 150ms linear, color 150ms linear, 65 | border 150ms linear; 66 | height: 100%; 67 | width: 100%; 68 | } 69 | 70 | button:hover { 71 | background-color: var(--button-hover-color); 72 | border-color: var(--button-hover-color); 73 | } 74 | 75 | .secondary { 76 | background-color: unset; 77 | color: var(--button-text-color); 78 | } 79 | 80 | .secondary:hover { 81 | color: var(--button-hover-text-color); 82 | } 83 | 84 | .text { 85 | background-color: transparent; 86 | color: var(--color-primary, #2c6fb7); 87 | text-decoration: underline; 88 | align-self: center; 89 | padding: 0; 90 | border: none; 91 | } 92 | 93 | .text:hover { 94 | background-color: transparent; 95 | color: var(--color-primary-dark, #004587); 96 | } 97 | 98 | button[disabled].text { 99 | background-color: transparent; 100 | } 101 | 102 | ::slotted([slot="icon-left"]) { 103 | margin-right: 0.1875rem; 104 | } 105 | 106 | ::slotted([slot="icon-right"]) { 107 | margin-left: 0.1875rem; 108 | } 109 | 110 | ::slotted(svg) { 111 | height: 1.5rem; 112 | width: 1.5rem; 113 | } 114 | 115 | slot[name="icon-loading"] > * { 116 | height: calc(100% - 1rem); 117 | margin: 0.5rem 0; 118 | position: absolute; 119 | top: 0; 120 | width: 25%; 121 | } 122 | 123 | /* If the loading icon is rendered, hide the rest of the button content */ 124 | slot[name="icon-loading"] ~ * { 125 | visibility: hidden; 126 | } 127 | `; 128 | -------------------------------------------------------------------------------- /packages/card/__tests__/chameleon-card-footer.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-card-footer.js"; 3 | 4 | describe("chameleon-card-footer", () => { 5 | it("renders", async () => { 6 | const el = await litFixture(html` 7 | 8 | `); 9 | expect(Boolean(el.shadowRoot)).to.equal(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/card/__tests__/chameleon-card-header.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-card-header.js"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-card-header", () => { 7 | let element; 8 | 9 | beforeEach(async () => { 10 | element = await litFixture(fixture); 11 | }); 12 | 13 | it("renders", () => { 14 | expect(Boolean(element.shadowRoot)).to.equal(true); 15 | }); 16 | 17 | it("renders subtitle", async () => { 18 | element.subtitle = "chameleon"; 19 | element.requestUpdate(); 20 | await element.updateComplete; 21 | 22 | expect(element).shadowDom.to.equal("

chameleon

"); 23 | }); 24 | 25 | it("renders title", async () => { 26 | element.title = "chameleon"; 27 | element.requestUpdate(); 28 | await element.updateComplete; 29 | 30 | expect(element).shadowDom.to.equal("

chameleon

"); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/card/__tests__/chameleon-card-image.test.js: -------------------------------------------------------------------------------- 1 | import "../chameleon-card-image.js"; 2 | import { fixture, html, expect } from "@open-wc/testing"; 3 | 4 | describe("chameleon-card-image", () => { 5 | it("renders", async () => { 6 | const el = await fixture(html` 7 | 8 | `); 9 | expect(Boolean(el.shadowRoot)).to.equal(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/card/__tests__/chameleon-card.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-card.js"; 3 | 4 | describe("chameleon-card", () => { 5 | it("renders", async () => { 6 | const element = await litFixture(html` `); 7 | 8 | expect(Boolean(element.shadowRoot)).to.equal(true); 9 | }); 10 | 11 | it("should set default accentColor", async () => { 12 | const element = await litFixture( 13 | html` ` 14 | ); 15 | 16 | expect(element.style.borderTop).to.equal( 17 | "7px solid var(--color-primary, #2c6fb7)" 18 | ); 19 | }); 20 | 21 | it("should set accentColor", async () => { 22 | const element = await litFixture( 23 | html` ` 24 | ); 25 | 26 | expect(element.style.borderTop).to.equal("7px solid green"); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/card/chameleon-card-footer.js: -------------------------------------------------------------------------------- 1 | import { ChameleonCardFooter } from "./lib/ChameleonCardFooter.js"; 2 | 3 | customElements.define("chameleon-card-footer", ChameleonCardFooter); 4 | -------------------------------------------------------------------------------- /packages/card/chameleon-card-header.js: -------------------------------------------------------------------------------- 1 | import { ChameleonCardHeader } from "./lib/ChameleonCardHeader.js"; 2 | 3 | customElements.define("chameleon-card-header", ChameleonCardHeader); 4 | -------------------------------------------------------------------------------- /packages/card/chameleon-card-image.js: -------------------------------------------------------------------------------- 1 | import { ChameleonCardImage } from "./lib/ChameleonCardImage.js"; 2 | 3 | customElements.define("chameleon-card-image", ChameleonCardImage); 4 | -------------------------------------------------------------------------------- /packages/card/chameleon-card.js: -------------------------------------------------------------------------------- 1 | import { ChameleonCard } from "./lib/ChameleonCard.js"; 2 | 3 | customElements.define("chameleon-card", ChameleonCard); 4 | -------------------------------------------------------------------------------- /packages/card/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonCard } from "./lib/ChameleonCard.js"; 2 | export { ChameleonCardFooter } from "./lib/ChameleonCardFooter.js"; 3 | export { ChameleonCardFooterStyle } from "./lib/ChameleonCardFooterStyle.js"; 4 | export { ChameleonCardHeader } from "./lib/ChameleonCardHeader.js"; 5 | export { ChameleonCardHeaderStyle } from "./lib/ChameleonCardHeaderStyle.js"; 6 | export { ChameleonCardImage } from "./lib/ChameleonCardImage.js"; 7 | export { ChameleonCardImageStyle } from "./lib/ChameleonCardImageStyle.js"; 8 | export { ChameleonCardStyle } from "./lib/ChameleonCardStyle.js"; 9 | -------------------------------------------------------------------------------- /packages/card/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/card", 3 | "version": "2.0.1", 4 | "description": "Chameleon card", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/card#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-card.js", 16 | "chameleon-card-footer.js", 17 | "chameleon-card-header.js", 18 | "chameleon-card-image.js", 19 | "/lib/" 20 | ], 21 | "scripts": { 22 | "test": "echo \"Error: run tests from root\" && exit 1", 23 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/MaritzSTL/chameleon/issues" 27 | }, 28 | "dependencies": { 29 | "lit-element": "^2.2.1" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | }, 34 | "gitHead": "903c637e2d1f3693b6c0b5fca5c1e6363ecb15c1" 35 | } 36 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCard.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { ChameleonCardStyle } from "./ChameleonCardStyle.js"; 3 | import { nothing } from "lit-html"; 4 | 5 | export class ChameleonCard extends LitElement { 6 | /** 7 | * Styles 8 | */ 9 | static styles = [ChameleonCardStyle]; 10 | 11 | /** 12 | * Properties 13 | */ 14 | @property({ type: String }) 15 | accentColor = null; 16 | 17 | @property({ type: String, reflect: true }) 18 | complication = null; 19 | 20 | /** 21 | * Template 22 | */ 23 | render() { 24 | return html` 25 | ${this.complicationText} 26 | 27 | `; 28 | } 29 | 30 | get complicationText() { 31 | return this.complication !== null 32 | ? html`
${this.complication}
` 33 | : nothing; 34 | } 35 | 36 | updated(changedProperties) { 37 | if (changedProperties.has("accentColor") && this.accentColor !== "") 38 | this.style.borderTop = `7px solid ${this.accentColor}`; 39 | 40 | if ( 41 | changedProperties.has("accentColor") && 42 | this.accentColor === "" && 43 | this.accentColor !== undefined 44 | ) { 45 | this.style.borderTop = `7px solid var(--color-primary, #2c6fb7)`; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardFooter.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html } from "lit-element"; 2 | import { ChameleonCardFooterStyle } from "./ChameleonCardFooterStyle.js"; 3 | 4 | export class ChameleonCardFooter extends LitElement { 5 | /** 6 | * Styles 7 | */ 8 | static styles = [ChameleonCardFooterStyle]; 9 | 10 | /** 11 | * Template 12 | */ 13 | render() { 14 | return html``; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardFooterStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonCardFooterStyle = css` 4 | :host { 5 | display: flex; 6 | margin: 1.5rem 0 0.625rem 0; 7 | } 8 | `; 9 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardHeader.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { ChameleonCardHeaderStyle } from "./ChameleonCardHeaderStyle.js"; 4 | 5 | export class ChameleonCardHeader extends LitElement { 6 | /** 7 | * Styles 8 | */ 9 | static styles = [ChameleonCardHeaderStyle]; 10 | 11 | /** 12 | * Properties 13 | */ 14 | @property({ type: String }) 15 | title = ""; 16 | 17 | @property({ type: String }) 18 | subtitle = ""; 19 | 20 | /** 21 | * Template 22 | */ 23 | render() { 24 | return html` 25 | ${this.subtitle !== "" ? html`

${this.subtitle}

` : nothing} 26 | ${this.title !== "" ? html`

${this.title}

` : nothing} 27 | `; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardHeaderStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | export const ChameleonCardHeaderStyle = css` 3 | :host { 4 | display: block; 5 | margin-bottom: 11px; 6 | } 7 | 8 | h3, 9 | h2 { 10 | overflow: hidden; 11 | margin: 0; 12 | text-overflow: ellipsis; 13 | } 14 | 15 | h3 { 16 | color: var(--color-secondary-dark, #349889); 17 | font-size: var(--font-size-subtitle, 0.938rem); 18 | line-height: 21px; 19 | white-space: nowrap; 20 | } 21 | 22 | h2 { 23 | font-size: var(--font-size-title, 1.4rem); 24 | line-height: 27px; 25 | max-height: 52px; 26 | } 27 | `; 28 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardImage.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { ChameleonCardImageStyle } from "./ChameleonCardImageStyle.js"; 3 | 4 | export class ChameleonCardImage extends LitElement { 5 | /** 6 | * Properties 7 | */ 8 | 9 | // The image's source URL 10 | @property({ type: String }) 11 | src = ""; 12 | 13 | // The image's alt text 14 | @property({ type: String }) 15 | alt = ""; 16 | 17 | /** 18 | * Styles 19 | */ 20 | static styles = [ChameleonCardImageStyle]; 21 | 22 | /** 23 | * Template 24 | */ 25 | render() { 26 | return this.src !== "" 27 | ? html`${this.alt}` 28 | : html`
`; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardImageStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonCardImageStyle = css` 4 | :host { 5 | display: inline-block; 6 | } 7 | 8 | img { 9 | border-radius: var(--border-radius, 0.5rem); 10 | vertical-align: top; 11 | width: 100%; 12 | } 13 | 14 | .placeholder { 15 | background-image: linear-gradient( 16 | to top, 17 | var(--color-primary-dark, #004587), 18 | var(--color-primary-light, #679dea) 19 | ); 20 | border-radius: var(--border-radius, 0.5rem); 21 | min-height: 100px; 22 | } 23 | `; 24 | -------------------------------------------------------------------------------- /packages/card/src/ChameleonCardStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonCardStyle = css` 4 | :host { 5 | background-color: var(--color-surface, #ffffff); 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: space-between; 9 | padding: 16px; 10 | } 11 | 12 | :host([outline]) { 13 | border: 1px solid var(--color-gray-lightest, #e1e3e4); 14 | } 15 | 16 | :host([rounded]) { 17 | border-radius: var(--border-radius, 0.5rem); 18 | } 19 | 20 | :host([complication]) { 21 | padding-top: 35px; 22 | position: relative; 23 | } 24 | 25 | .complication { 26 | background-color: var(--color-secondary, #69c9b9); 27 | border-radius: var(--border-radius, 0.5rem) 0 var(--border-radius, 0.5rem) 0; 28 | font-size: var(--font-size-label, 0.875rem); 29 | padding: 4px 16px; 30 | color: var(--color-surface, #ffffff); 31 | position: absolute; 32 | top: 0; 33 | left: 0; 34 | } 35 | `; 36 | -------------------------------------------------------------------------------- /packages/chart/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Chart 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, number } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-chart.js"; 7 | 8 | export default { 9 | title: "Components|Data and Visualizations/Chart", 10 | component: "chameleon-chart", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | ------------------------------------------- | 20 | | `type` | String | `""` | The type of chart | 21 | | `color` | String | `"#00870a"` | The hex value of the chart color | 22 | | `percentage` | Number | `0` | The percentage to be displayed in the chart | 23 | | `label` | String | `"0"` | The value to show in the label | 24 | | `subLabel` | String | `""` | The value to show in the sublabel | 25 | 26 | ## Examples 27 | 28 | ### Default 29 | 30 | ```js preview-story 31 | export const Default = () => { 32 | const color = text("Color", "#00870a"); 33 | const label = text("Label", "1,000"); 34 | const subLabel = text("SubLabel", "Funds Remaining"); 35 | const percentage = number("Percentage", 90); 36 | 37 | return html` 38 | 45 | `; 46 | }; 47 | ``` 48 | -------------------------------------------------------------------------------- /packages/chart/__tests__/chameleon-chart.test.js: -------------------------------------------------------------------------------- 1 | import "../chameleon-chart.js"; 2 | import { litFixture, html, expect } from "@open-wc/testing"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-chart", () => { 7 | let element; 8 | 9 | beforeEach(async () => { 10 | element = await litFixture(fixture); 11 | }); 12 | 13 | it("renders", async () => { 14 | expect(Boolean(element.shadowRoot)).to.equal(true); 15 | }); 16 | 17 | it("convert percentage to degrees", async () => { 18 | const percentage = 10; 19 | 20 | const degrees = element._percentageToDegrees(percentage); 21 | const expectedDegrees = -96; 22 | expect(degrees).to.be.equal(expectedDegrees); 23 | }); 24 | 25 | it("returns the arc chart type", async () => { 26 | element.type = "arc"; 27 | const chart = await litFixture(element.chart); 28 | 29 | expect(chart).lightDom.to.equalSnapshot(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /packages/chart/chameleon-chart.js: -------------------------------------------------------------------------------- 1 | import { ChameleonChart } from "./lib/ChameleonChart.js"; 2 | 3 | customElements.define("chameleon-chart", ChameleonChart); 4 | -------------------------------------------------------------------------------- /packages/chart/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonChart } from "./lib/ChameleonChart.js"; 2 | export { ChameleonChartStyle } from "./lib/ChameleonChartStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/chart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/chart", 3 | "version": "2.0.1", 4 | "description": "Chameleon chart", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/chart#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-chart.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/chart/src/ChameleonChart.js: -------------------------------------------------------------------------------- 1 | import { LitElement, property, html, svg } from "lit-element"; 2 | import { ChameleonChartStyle } from "./ChameleonChartStyle.js"; 3 | import { nothing } from "lit-html"; 4 | 5 | export class ChameleonChart extends LitElement { 6 | /** 7 | * Properties 8 | */ 9 | @property({ type: String }) 10 | type = ""; 11 | 12 | /*The color of the chart*/ 13 | 14 | @property({ type: String, reflect: true }) 15 | color = "#00870a"; 16 | 17 | /* percentage to be displayed in the donut chart */ 18 | @property({ type: Number }) 19 | percentage = 0; 20 | 21 | /* value to show in the the label */ 22 | @property({ type: String }) 23 | label = "0"; 24 | 25 | /* value to show in the the subLabel */ 26 | @property({ type: String }) 27 | subLabel = ""; 28 | 29 | /** 30 | * Styles 31 | */ 32 | static styles = [ChameleonChartStyle]; 33 | 34 | /** 35 | * Template 36 | */ 37 | render() { 38 | return html` 39 | ${this.chart} 40 |
41 | 42 | 43 |
44 | `; 45 | } 46 | 47 | get chart() { 48 | switch (this.type) { 49 | case "arc": 50 | return this.arc; 51 | default: 52 | return nothing; 53 | } 54 | } 55 | 56 | get arc() { 57 | return svg` 58 | 59 | 66 | 75 | 76 | `; 77 | } 78 | 79 | _polarToCartesian(centerX, centerY, radius, angleInDegrees) { 80 | const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0; 81 | 82 | return { 83 | x: centerX + radius * Math.cos(angleInRadians), 84 | y: centerY + radius * Math.sin(angleInRadians), 85 | }; 86 | } 87 | 88 | _percentageToDegrees(percentage) { 89 | const degrees = (percentage / 100) * 240 - 120; 90 | 91 | return degrees; 92 | } 93 | 94 | _describeArc(x, y, radius, startAngle, endAngle) { 95 | const start = this._polarToCartesian(x, y, radius, endAngle); 96 | const end = this._polarToCartesian(x, y, radius, startAngle); 97 | 98 | const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; 99 | 100 | const d = [ 101 | "M", 102 | start.x, 103 | start.y, 104 | "A", 105 | radius, 106 | radius, 107 | 0, 108 | largeArcFlag, 109 | 0, 110 | end.x, 111 | end.y, 112 | ].join(" "); 113 | 114 | return d; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /packages/chart/src/ChameleonChartStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonChartStyle = css` 4 | :host { 5 | display: inline-block; 6 | max-width: 130px; 7 | } 8 | 9 | .labels { 10 | text-align: center; 11 | } 12 | 13 | label { 14 | display: block; 15 | color: var(--color-gray-dark, #9fa4a8); 16 | font-size: 0.75rem; 17 | } 18 | `; 19 | -------------------------------------------------------------------------------- /packages/checkbox/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Checkbox 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-checkbox.js"; 7 | 8 | export default { 9 | title: "Components|Form Elements/Checkbox", 10 | component: "chameleon-checkbox", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ---------------- | -------------------------------------------------------------------------------- | 20 | | `label` | String | `""` | The checkbox's label | 21 | | `name` | String | `"cha-checkbox"` | The checkbox's form name | 22 | | `checked` | Boolean | `false` | A Boolean which, if true, indicates that the checkbox is selected | 23 | | `value` | String | `""` | The checkbox's current value | 24 | | `readonly` | Boolean | `false` | A Boolean attribute which, if true, indicates that the checkbox cannot be edited | 25 | | `disabled` | Boolean | `false` | The checkbox's enabled/disabled status | 26 | | `invalid` | Boolean | `false` | Invalid boolean to allow validity access from higher level form errors | 27 | | `required` | boolean | `false` | A Boolean to indicate the input is required | 28 | 29 | ## Examples 30 | 31 | ### Default 32 | 33 | ```js preview-story 34 | export const Default = () => { 35 | const label = text("Label", ""); 36 | const checked = boolean("Checked", true); 37 | const disabled = boolean("Disabled", false); 38 | const invalid = boolean("Invalid", false); 39 | 40 | return html` 41 | 47 | `; 48 | }; 49 | ``` 50 | -------------------------------------------------------------------------------- /packages/checkbox/__tests__/chameleon-checkbox.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-checkbox.js"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-checkbox", () => { 7 | let element; 8 | 9 | beforeEach(async () => { 10 | element = await litFixture(fixture); 11 | }); 12 | 13 | it("renders", () => { 14 | expect(Boolean(element.shadowRoot)).to.equal(true); 15 | }); 16 | 17 | it("shows label text", () => { 18 | element.label = "chameleon"; 19 | expect(element.labelText).to.equal("chameleon"); 20 | }); 21 | it("shows aria-invalid when invalid", () => { 22 | element.invalid = true; 23 | expect(element).shadowDom.to.equalSnapshot(); 24 | }); 25 | it("shows name attribute", () => { 26 | element.name = "formName"; 27 | expect(element).shadowDom.to.equalSnapshot(); 28 | }); 29 | it("shows required attribute", async () => { 30 | element.required = true; 31 | await element.updateComplete; 32 | expect(element).shadowDom.to.equalSnapshot(); 33 | }); 34 | it("shows readonly attribute", () => { 35 | element.readonly = true; 36 | expect(element).shadowDom.to.equalSnapshot(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/checkbox/chameleon-checkbox.js: -------------------------------------------------------------------------------- 1 | import { ChameleonCheckbox } from "./lib/ChameleonCheckbox.js"; 2 | 3 | customElements.define("chameleon-checkbox", ChameleonCheckbox); 4 | -------------------------------------------------------------------------------- /packages/checkbox/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonCheckbox } from "./lib/ChameleonCheckbox.js"; 2 | export { ChameleonCheckboxStyle } from "./lib/ChameleonCheckboxStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/checkbox/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/checkbox", 3 | "version": "2.0.1", 4 | "description": "Chameleon checkbox", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/checkbox#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-checkbox.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/checkbox/src/ChameleonCheckbox.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { ChameleonCheckboxStyle } from "./ChameleonCheckboxStyle.js"; 4 | 5 | export class ChameleonCheckbox extends LitElement { 6 | /** 7 | * Properties 8 | */ 9 | 10 | // The checkbox's label 11 | @property({ type: String }) 12 | label = ""; 13 | 14 | // The checkbox's form name 15 | @property({ type: String }) 16 | name = "cha-checkbox"; 17 | 18 | // A Boolean which, if true, indicates that the checkbox is selected 19 | @property({ type: Boolean, reflect: true }) 20 | checked = false; 21 | 22 | // The checkbox's current value 23 | @property({ type: String }) 24 | value = ""; 25 | 26 | // A Boolean attribute which, if true, indicates that the checkbox cannot be edited 27 | @property({ type: Boolean, reflect: true }) 28 | readonly = false; 29 | 30 | // The checkbox's enabled/disabled status 31 | @property({ type: Boolean, reflect: true }) 32 | disabled = false; 33 | 34 | // Invalid boolean to allow validity access from higher level form errors 35 | @property({ type: Boolean, reflect: true }) 36 | invalid = false; 37 | 38 | // A Boolean to indicate the input is required 39 | @property({ type: Boolean, reflect: true }) 40 | required = false; 41 | 42 | /** 43 | * Styles 44 | */ 45 | static styles = [ChameleonCheckboxStyle]; 46 | 47 | /** 48 | * Template 49 | */ 50 | render() { 51 | return html` 52 | 63 | 64 | ${this.labelText} 65 | `; 66 | } 67 | 68 | get labelText() { 69 | if (this.label !== "") return this.label; 70 | else return nothing; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/checkbox/src/ChameleonCheckboxStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonCheckboxStyle = css` 4 | :host([readonly]), 5 | :host([disabled]) { 6 | pointer-events: none; 7 | } 8 | 9 | :host { 10 | align-items: center; 11 | cursor: pointer; 12 | display: inline-flex; 13 | font-size: var(--font-size-input, 0.938rem); 14 | -webkit-user-select: none; 15 | -moz-user-select: none; 16 | -ms-user-select: none; 17 | user-select: none; 18 | vertical-align: top; 19 | } 20 | 21 | input { 22 | cursor: pointer; 23 | display: none; 24 | } 25 | 26 | .checkmark { 27 | background-color: transparent; 28 | border: 2px solid var(--color-gray-lightest, #e1e3e4); 29 | border-radius: 3px; 30 | box-sizing: border-box; 31 | display: inline-block; 32 | height: 20px; 33 | margin-right: 10px; 34 | position: relative; 35 | width: 20px; 36 | } 37 | 38 | :host:hover input ~ .checkmark { 39 | background-color: var(--color-surface, #ffffff); 40 | } 41 | 42 | input:checked ~ .checkmark { 43 | background-color: var(--color-primary, #2c6fb7); 44 | border: none; 45 | } 46 | 47 | .checkmark:after { 48 | border-bottom: 2px solid var(--color-surface, #ffffff); 49 | border-right: 2px solid var(--color-surface, #ffffff); 50 | content: ""; 51 | display: none; 52 | height: 13px; 53 | margin-left: 7px; 54 | margin-top: 1px; 55 | transform: rotate(45deg); 56 | width: 4px; 57 | } 58 | 59 | input:checked ~ .checkmark::after { 60 | display: inline-block; 61 | } 62 | 63 | :host([invalid]) .checkmark { 64 | border-color: var(--color-error, #bc1c16); 65 | } 66 | 67 | :host([invalid]) input:checked ~ .checkmark { 68 | border: 2px solid var(--color-error, #bc1c16); 69 | } 70 | 71 | :host([invalid]) input:checked ~ .checkmark:after { 72 | margin-top: -1px; 73 | margin-left: 5px; 74 | } 75 | 76 | :host([disabled]) { 77 | pointer-events: none; 78 | } 79 | 80 | :host([disabled]) input:checked ~ .checkmark { 81 | background-color: var(--color-gray-lightest, #e1e3e4); 82 | } 83 | 84 | :host([disabled]) .checkmark { 85 | position: relative; 86 | } 87 | 88 | :host([disabled]) .checkmark:after { 89 | border: none; 90 | background-color: var(--color-surface, #ffffff); 91 | height: 2px; 92 | left: 50%; 93 | margin: 0; 94 | position: absolute; 95 | top: 50%; 96 | transform: translate(-50%, -50%); 97 | width: 12px; 98 | } 99 | `; 100 | -------------------------------------------------------------------------------- /packages/chip/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Chip 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import "./chameleon-chip.js"; 6 | 7 | export default { 8 | title: "Components|Data and Visualizations/Chip", 9 | component: "chameleon-chip", 10 | options: { selectedPanel: "storybookjs/docs/panel" }, 11 | }; 12 | ``` 13 | 14 | ## Properties 15 | 16 | | Property Name | Type(s) | Default Value | Description | 17 | | ------------- | ------- | ------------- | ------------------------------------- | 18 | | `closeable` | Boolean | `false` | Whether or not the chip can be closed | 19 | | `value` | String | `""` | The chip's value | 20 | 21 | ## Examples 22 | 23 | ### Default 24 | 25 | ```js preview-story 26 | export const Default = () => html` Filter `; 27 | ``` 28 | 29 | ### Closeable 30 | 31 | ```js preview-story 32 | export const Closeable = () => html` 33 | Filter 34 | `; 35 | ``` 36 | -------------------------------------------------------------------------------- /packages/chip/__tests__/chameleon-chip.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import sinon from "sinon"; 3 | import "../chameleon-chip.js"; 4 | 5 | const fixture = html` chameleon `; 6 | 7 | describe("chameleon-chip", () => { 8 | let element; 9 | 10 | beforeEach(async () => { 11 | element = await litFixture(fixture); 12 | }); 13 | 14 | it("renders", async () => { 15 | expect(Boolean(element.shadowRoot)).to.equal(true); 16 | }); 17 | 18 | it("_remove dispatches an event with the value", () => { 19 | const dispatchEvent = sinon.spy(element, "dispatchEvent"); 20 | 21 | element._remove(); 22 | 23 | expect(dispatchEvent).to.be.calledOnce; 24 | }); 25 | 26 | // Would like to rewrite this to be better 27 | it("renders the removeIcon", async () => { 28 | const icon = await litFixture(element.removeIcon); 29 | 30 | expect(icon).to.contain.html(" { 34 | element.value = "chameleon"; 35 | element.requestUpdate(); 36 | await element.updateComplete; 37 | 38 | expect(element.value).to.equal("chameleon"); 39 | }); 40 | 41 | it("renders close icon if [closeable] is true", async () => { 42 | element.closeable = true; 43 | element.requestUpdate(); 44 | await element.updateComplete; 45 | 46 | expect(element).shadowDom.to.equal(``); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/chip/chameleon-chip.js: -------------------------------------------------------------------------------- 1 | import { ChameleonChip } from "./lib/ChameleonChip.js"; 2 | 3 | customElements.define("chameleon-chip", ChameleonChip); 4 | -------------------------------------------------------------------------------- /packages/chip/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonChip } from "./lib/ChameleonChip.js"; 2 | export { ChameleonChipStyle } from "./lib/ChameleonChipStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/chip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/chip", 3 | "version": "2.0.1", 4 | "description": "Chameleon chip", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/chip#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-chip.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/chip/src/ChameleonChip.js: -------------------------------------------------------------------------------- 1 | import { LitElement, property, html, svg } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { ChameleonChipStyle } from "./ChameleonChipStyle.js"; 4 | 5 | export class ChameleonChip extends LitElement { 6 | /** 7 | * Properties 8 | */ 9 | @property({ type: Boolean, reflect: true }) 10 | closeable = false; 11 | 12 | @property({ type: String }) 13 | _value = ""; 14 | 15 | /** 16 | * Styles 17 | */ 18 | static styles = [ChameleonChipStyle]; 19 | 20 | /** 21 | * Template 22 | */ 23 | render() { 24 | return html` 25 | 26 | ${this.closeable 27 | ? html` ${this.removeIcon} ` 28 | : nothing} 29 | `; 30 | } 31 | 32 | _remove() { 33 | const e = new CustomEvent("remove-chip", { 34 | detail: { value: this.value }, 35 | bubbles: true, 36 | composed: true, 37 | }); 38 | 39 | this.dispatchEvent(e); 40 | } 41 | 42 | get removeIcon() { 43 | return svg``; 44 | } 45 | 46 | get value() { 47 | if (this._value !== "") { 48 | return this._value; 49 | } else { 50 | return this.innerText; 51 | } 52 | } 53 | 54 | set value(value) { 55 | this._value = value; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/chip/src/ChameleonChipStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonChipStyle = css` 4 | :host { 5 | align-items: center; 6 | background-color: var(--color-primary, #2c6fb7); 7 | border-radius: 1.25rem; 8 | color: var(--color-surface, #ffffff); 9 | display: inline-flex; 10 | flex-direction: row; 11 | font-size: var(--font-size-input, 0.938rem); 12 | line-height: 1.125rem; 13 | padding: 4px 11px; 14 | transition: background-color 0.3s ease; 15 | } 16 | 17 | :host([closeable]:hover) { 18 | background-color: var(--color-primary-dark, #004587); 19 | } 20 | 21 | span { 22 | display: flex; 23 | cursor: pointer; 24 | } 25 | 26 | svg { 27 | padding-left: 10px; 28 | height: 13px; 29 | } 30 | `; 31 | -------------------------------------------------------------------------------- /packages/date/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Date 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-date.js"; 7 | 8 | export default { 9 | title: "Components|Form Elements/Date", 10 | component: "chameleon-date", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------------- | ------- | ------------- | ------------------------------------------------ | 20 | | `name` | String | `"cha-date"` | The date's form name | 21 | | `active` | Boolean | `false` | Whether or not the date picker drawer is open | 22 | | `renderedDate` | Object | `null` | The Date object of the rendered date | 23 | | `placeholder` | String | `""` | The date's placeholder text | 24 | | `label` | String | `""` | The date's label text | 25 | | `readonly` | Boolean | `false` | Whether or not the date picker is readonly | 26 | | `value` | String | `""` | The date picker's text value (YYYY-MM-DD) | 27 | | `min` | String | `null` | The date picker's minimum value (YYYY-MM-DD) | 28 | | `max` | String | `null` | The date picker's maximum value (YYYY-MM-DD) | 29 | | `required` | Boolean | `false` | Whether or not the date value is required | 30 | | `canDelete` | Boolean | `true` | If the date is able to be deleted | 31 | | `disabled` | Boolean | `false` | Whether or not the date picker is disabled | 32 | | `validationMessage` | String | `""` | The date picker's validation message | 33 | | `invalid` | Boolean | `false` | Whether or not the date picker is invalid | 34 | | `overlayRenderMode` | String | `"month"` | The date picker's overlay mode ("year", "month") | 35 | 36 | ## Examples 37 | 38 | ### Default 39 | 40 | ```js preview-story 41 | export const Default = () => { 42 | const placeholder = text("Placeholder", "Select Date"); 43 | const label = text("Label", "Date *"); 44 | const minValue = text("Min Value (YYYY-MM-DD)", ""); 45 | const maxValue = text("Max Value (YYYY-MM-DD)", ""); 46 | const readonly = boolean("Read Only", false); 47 | const invalid = boolean("Invalid", false); 48 | const required = boolean("Required", false); 49 | const disabled = boolean("Disabled", false); 50 | const error = text("Error", ""); 51 | const name = text("Name", "input-form-name"); 52 | 53 | return html` 54 | 66 | `; 67 | }; 68 | ``` 69 | 70 | ### Error State 71 | 72 | ```js preview-story 73 | export const ErrorState = () => html` 74 | 80 | `; 81 | ``` 82 | -------------------------------------------------------------------------------- /packages/date/chameleon-date.js: -------------------------------------------------------------------------------- 1 | import { ChameleonDate } from "./lib/ChameleonDate.js"; 2 | 3 | customElements.define("chameleon-date", ChameleonDate); 4 | -------------------------------------------------------------------------------- /packages/date/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonDate } from "./lib/ChameleonDate.js"; 2 | export { ChameleonDateStyle } from "./lib/ChameleonDateStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/date/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/date", 3 | "version": "2.0.1", 4 | "description": "Chameleon date", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/date#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-date.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/button": "^2.0.1", 27 | "@chameleon-ds/input": "^2.0.1", 28 | "lit-element": "^2.2.1" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "gitHead": "f42fb52b4423dce1ed5f2d20344fc254da1daf36" 34 | } 35 | -------------------------------------------------------------------------------- /packages/dialog/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Dialog 2 | 3 | ```js script 4 | import { html, svg } from "lit-html"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-dialog.js"; 7 | 8 | export default { 9 | title: "Components|Overlays/Dialog", 10 | component: "chameleon-dialog", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | ---------------------------------------- | 20 | | `open` | Boolean | `false` | Whether or not the dialog is open | 21 | | `icon` | Boolean | `false` | Whether or not the card has an icon | 22 | | `dismissible` | Boolean | `false` | Whether or not the card has a close icon | 23 | | `canGoBack` | Boolean | `false` | Whether or not the dialog can go back | 24 | | `fullScreen` | Boolean | `false` | Display full screen | 25 | 26 | ## Examples 27 | 28 | ### Default 29 | 30 | ```js preview-story 31 | export const Default = () => { 32 | const defaultIcon = svg` 33 | 34 | `; 35 | 36 | return html` 37 | 38 | ${defaultIcon} 39 |

Title

40 | We’re sorry but your session has expired. You will need to log back in to 41 | continue. 42 |
43 | 44 | Okay 45 | 46 |
47 |
48 | 49 | Cancel 50 | 51 |
52 |
53 | `; 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /packages/dialog/chameleon-dialog.js: -------------------------------------------------------------------------------- 1 | import { ChameleonDialog } from "./lib/ChameleonDialog.js"; 2 | 3 | customElements.define("chameleon-dialog", ChameleonDialog); 4 | -------------------------------------------------------------------------------- /packages/dialog/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonDialog } from "./lib/ChameleonDialog.js"; 2 | export { ChameleonDialogStyle } from "./lib/ChameleonDialogStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/dialog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/dialog", 3 | "version": "2.1.0", 4 | "description": "Chameleon dialog", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/dialog#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-dialog.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/button": "^2.0.1", 27 | "@chameleon-ds/card": "^2.0.1", 28 | "lit-element": "^2.2.1" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/dialog/src/ChameleonDialogStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonDialogStyle = css` 4 | .open { 5 | display: flex; 6 | } 7 | .close { 8 | display: none; 9 | } 10 | .dialog { 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | align-content: center; 15 | padding: 0.5em; 16 | } 17 | 18 | .overlay { 19 | width: 100vw; 20 | height: 100vh; 21 | background-color: rgba(0, 0, 0, 0.4); 22 | position: fixed; 23 | top: 0; 24 | right: 0; 25 | bottom: 0; 26 | left: 0; 27 | z-index: 9999; 28 | } 29 | 30 | chameleon-card { 31 | flex-direction: column; 32 | border-top: solid var(--color-secondary) 10px; 33 | position: absolute; 34 | left: 50%; 35 | top: 50%; 36 | transform: translate(-50%, -50%); 37 | border-radius: 5px; 38 | box-shadow: 0 5px 12px 0 rgba(44, 111, 183, 0.2), 39 | 0 2px 6px -1px rgba(44, 111, 183, 0.12), 40 | 0 1px 4px 0 rgba(44, 111, 183, 0.14); 41 | margin: auto; 42 | background-color: #ffffff; 43 | width: var(--dialog-width, 18.75rem); 44 | padding: 48px; 45 | animation-name: dialogopen; 46 | animation-duration: 1s; 47 | } 48 | 49 | .full-screen { 50 | border-radius: unset; 51 | position: relative; 52 | width: 100%; 53 | margin-bottom: 0; 54 | margin-top: 0; 55 | } 56 | 57 | .actions { 58 | display: flex; 59 | flex-direction: column; 60 | align-self: stretch; 61 | margin-top: 1.5em; 62 | } 63 | 64 | .close-icon { 65 | display: flex; 66 | cursor: pointer; 67 | position: absolute; 68 | margin: 0; 69 | top: 25px; 70 | right: 25px; 71 | } 72 | 73 | .back-icon { 74 | display: flex; 75 | cursor: pointer; 76 | position: absolute; 77 | margin: 0; 78 | top: 25px; 79 | left: 25px; 80 | } 81 | 82 | svg { 83 | width: 100%; 84 | height: 100%; 85 | color: var(--color-gray-darkest); 86 | } 87 | 88 | :slotted(*) { 89 | color: var(--color-gray-darkest); 90 | height: 1.125em; 91 | position: absolute; 92 | top: 50%; 93 | transform: translateY(-50%); 94 | width: auto; 95 | } 96 | 97 | ::slotted([slot="icon"]) { 98 | color: var(--color-secondary-dark, #349889); 99 | height: 2.625em; 100 | } 101 | 102 | ::slotted([slot="title"]) { 103 | color: var(--color-primary); 104 | font-size: 2em; 105 | font-weight: 300; 106 | letter-spacing: 0.016em; 107 | margin: 1em 0; 108 | } 109 | 110 | ::slotted([slot="accept-action"]) { 111 | margin-top: 1em; 112 | } 113 | 114 | ::slotted([slot="decline-action"]) { 115 | margin-top: 1em; 116 | } 117 | 118 | @keyframes dialogopen { 119 | from { 120 | opacity: 0; 121 | } 122 | to { 123 | opacity: 1; 124 | } 125 | } 126 | `; 127 | -------------------------------------------------------------------------------- /packages/hero/chameleon-hero.js: -------------------------------------------------------------------------------- 1 | import { ChameleonHero } from "./lib/ChameleonHero.js"; 2 | 3 | customElements.define("chameleon-hero", ChameleonHero); 4 | -------------------------------------------------------------------------------- /packages/hero/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonHero } from "./lib/ChameleonHero.js"; 2 | export { ChameleonHeroStyle } from "./lib/ChameleonHeroStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/hero/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/hero", 3 | "version": "2.0.1", 4 | "description": "Chameleon hero", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/hero#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-hero.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/skeleton": "^2.0.1", 27 | "lit-element": "^2.2.1" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/hero/src/ChameleonHero.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { styleMap } from "lit-html/directives/style-map.js"; 3 | import { nothing } from "lit-html"; 4 | import { ChameleonHeroStyle } from "./ChameleonHeroStyle.js"; 5 | import "@chameleon-ds/skeleton/chameleon-skeleton"; 6 | 7 | export class ChameleonHero extends LitElement { 8 | /** 9 | * Properties 10 | */ 11 | @property({ type: String }) 12 | title = ""; 13 | 14 | @property({ type: String }) 15 | subTitle = ""; 16 | 17 | @property({ type: String }) 18 | heroText = ""; 19 | 20 | @property({ type: String }) 21 | imageUrl = ""; 22 | 23 | @property({ type: String }) 24 | type = "gradient"; 25 | 26 | @property({ type: String }) 27 | gradient = "var(--color-primary-dark), var(--color-secondary-dark)"; 28 | 29 | @property({ type: Number }) 30 | gradientAlpha = 0.5; 31 | 32 | @property({ type: Boolean }) 33 | loading = false; 34 | 35 | /** 36 | * Styles 37 | */ 38 | static styles = [ChameleonHeroStyle]; 39 | 40 | /** 41 | * Template 42 | */ 43 | render() { 44 | return html` 45 | ${this.loading 46 | ? html` ` 47 | : html` 48 |
49 |
50 | ${this.title 51 | ? html` 52 |

${this.title}

53 | ` 54 | : nothing} 55 | ${this.subTitle 56 | ? html` 57 |

58 | ${this.subTitle} 59 |

60 | ` 61 | : nothing} 62 | ${this.heroText 63 | ? html` 64 |

65 | ${this.heroText} 66 |

67 | ` 68 | : nothing} 69 | 70 |
71 |
72 | `} 73 | `; 74 | } 75 | 76 | get backgroundImageStyles() { 77 | switch (this.type) { 78 | case "image-gradient": 79 | return { 80 | backgroundImage: `linear-gradient(to right, ${this.gradientOverlay}), url(${this.imageUrl})`, 81 | }; 82 | case "gradient": 83 | return { 84 | backgroundImage: `linear-gradient(to right, ${this.gradientHex})`, 85 | }; 86 | case "image": 87 | return { 88 | backgroundImage: `url(${this.imageUrl})`, 89 | }; 90 | default: 91 | return { 92 | backgroundImage: `linear-gradient(to right, ${this.gradientHex})`, 93 | }; 94 | } 95 | } 96 | 97 | get gradientHex() { 98 | return this.gradient.split(",").map((h) => h.trim()); 99 | } 100 | 101 | get gradientOverlay() { 102 | return this.gradient 103 | .split(",") 104 | .map((h) => this.hex2rgba(h.trim(), this.gradientAlpha)); 105 | } 106 | 107 | hex2rgba(hex, alpha = 0.5) { 108 | const [r, g, b] = hex.match(/\w\w/g).map((x) => parseInt(x, 16)); 109 | return `rgba(${r},${g},${b},${alpha})`; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /packages/hero/src/ChameleonHeroStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonHeroStyle = css` 4 | header { 5 | padding: 0 5em; 6 | } 7 | 8 | .hero { 9 | align-items: center; 10 | background-position: top; 11 | background-repeat: no-repeat; 12 | background-size: cover; 13 | display: flex; 14 | min-height: 400px; 15 | width: 100%; 16 | } 17 | 18 | .hero-title { 19 | font-size: var(--font-size-hero-title, 3rem); 20 | font-weight: normal; 21 | letter-spacing: -0.72px; 22 | margin: 0 0 8px; 23 | } 24 | 25 | .hero-subtitle { 26 | font-size: var(--font-size-hero-subtitle, 1.375rem); 27 | font-weight: normal; 28 | margin: 0 0 16px; 29 | } 30 | 31 | .hero-text { 32 | font-size: var(--font-size-paragraph-medium); 33 | letter-spacing: 0.25px; 34 | margin: 0; 35 | } 36 | 37 | .hero-title, 38 | .hero-subtitle, 39 | .hero-text { 40 | color: var(--color-hero-text, #ffffff); 41 | } 42 | `; 43 | -------------------------------------------------------------------------------- /packages/input/chameleon-input.js: -------------------------------------------------------------------------------- 1 | import { ChameleonInput } from "./lib/ChameleonInput.js"; 2 | 3 | customElements.define("chameleon-input", ChameleonInput); 4 | -------------------------------------------------------------------------------- /packages/input/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonInput } from "./lib/ChameleonInput.js"; 2 | export { ChameleonInputStyle } from "./lib/ChameleonInputStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/input/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/input", 3 | "version": "2.0.1", 4 | "description": "Chameleon input", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/input#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-input.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 32 | } 33 | -------------------------------------------------------------------------------- /packages/input/src/ChameleonInputStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonInputStyle = css` 4 | :host { 5 | display: inline-block; 6 | font-family: var(--font-family, sans-serif); 7 | } 8 | 9 | .component-wrapper { 10 | display: inline-flex; 11 | flex-direction: column; 12 | width: 100%; 13 | } 14 | 15 | input { 16 | border: 1px solid var(--color-gray-light, #c4c7ca); 17 | border-radius: var(--border-radius-input, 0.313rem); 18 | box-sizing: border-box; 19 | font-size: var(--font-size-input, 0.938rem); 20 | font-family: var(--font-family, sans-serif); 21 | height: 100%; 22 | max-height: 40px; 23 | width: 100%; 24 | padding: var(--input-padding, 0.625rem 0.5rem); 25 | } 26 | 27 | .invalid input { 28 | border-color: var(--color-error, #bc1c16); 29 | } 30 | 31 | input:invalid { 32 | box-shadow: none; 33 | } 34 | 35 | .component-wrapper:hover:not(.invalid) input:not([disabled]), 36 | .component-wrapper:active:not(.invalid) input:not([disabled]) { 37 | border-color: var(--color-primary, #2c6fb7); 38 | } 39 | 40 | .label-row { 41 | display: flex; 42 | } 43 | .label-row.split-row { 44 | justify-content: space-between; 45 | } 46 | label, 47 | .label-row span { 48 | color: var(--color-gray-darkest, #6c737a); 49 | font-size: var(--font-size-label, 0.875rem); 50 | margin-bottom: 10px; 51 | } 52 | 53 | .component-wrapper.invalid .label-row span, 54 | label.invalid { 55 | color: var(--color-error, #bc1c16); 56 | } 57 | 58 | .label-row span { 59 | display: flex; 60 | align-items: flex-end; 61 | } 62 | 63 | .label-row span svg { 64 | padding-right: 3px; 65 | } 66 | 67 | .component-wrapper:hover:not(.invalid):not(.disabled) label, 68 | .component-wrapper:active:not(.invalid):not(.disabled) label, 69 | .component-wrapper:hover:not(.invalid):not(.disabled) .label-row span, 70 | .component-wrapper:active:not(.invalid):not(.disabled) .label-row span { 71 | color: var(--color-primary, #2c6fb7); 72 | } 73 | 74 | .error { 75 | color: var(--color-error, #bc1c16); 76 | font-size: var(--font-size-label, 0.875rem); 77 | margin-top: 3px; 78 | display: flex; 79 | align-items: center; 80 | } 81 | 82 | .error svg { 83 | padding-right: 0.5rem; 84 | } 85 | 86 | .input-wrapper { 87 | position: relative; 88 | } 89 | 90 | .input-wrapper.icon-left input { 91 | padding-left: 45px; 92 | } 93 | 94 | .input-wrapper.icon-right input { 95 | padding-right: 45px; 96 | } 97 | 98 | // We currently only support svg icons 99 | svg { 100 | width: 100%; 101 | height: 100%; 102 | color: var(--color-gray-darkest, #6c737a); 103 | } 104 | 105 | ::slotted(*) { 106 | color: var(--color-gray-darkest, #6c737a); 107 | height: 18px; 108 | position: absolute; 109 | top: 50%; 110 | transform: translateY(-50%); 111 | width: auto; 112 | } 113 | 114 | .invalid ::slotted(svg) { 115 | color: var(--color-error, #bc1c16); 116 | } 117 | 118 | ::slotted([slot="icon-left"]) { 119 | left: 13px; 120 | } 121 | 122 | ::slotted([slot="icon-right"]) { 123 | right: 13px; 124 | } 125 | 126 | .no-stepper input[type="number"]::-webkit-inner-spin-button, 127 | .no-stepper input[type="number"]::-webkit-outer-spin-button { 128 | -webkit-appearance: none; 129 | margin: 0; 130 | } 131 | .no-stepper input[type="number"] { 132 | -moz-appearance: textfield; 133 | } 134 | `; 135 | -------------------------------------------------------------------------------- /packages/loader/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Loader 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-loader.js"; 7 | 8 | export default { 9 | title: "Components|Feedback/Loader", 10 | component: "chameleon-loader", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | ------------------------------------------ | 20 | | `loader` | String | `"spinner"` | The loader's style ("spinner", "ellipsis") | 21 | | `size` | String | `"auto"` | The loader's size | 22 | 23 | ## Examples 24 | 25 | ### Default 26 | 27 | ```js preview-story 28 | export const Default = () => { 29 | const size = text("Size", "21px"); 30 | 31 | return html` 32 | 33 | `; 34 | }; 35 | ``` 36 | 37 | ### Ellipsis 38 | 39 | ```js preview-story 40 | export const Ellipsis = () => html` 41 | 42 | `; 43 | ``` 44 | -------------------------------------------------------------------------------- /packages/loader/__tests__/chameleon-loader.test.js: -------------------------------------------------------------------------------- 1 | import { fixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-loader.js"; 3 | 4 | describe("chameleon-loader", () => { 5 | it("renders", async () => { 6 | const el = await fixture(html` `); 7 | expect(Boolean(el.shadowRoot)).to.equal(true); 8 | }); 9 | 10 | it("renders a spinner by default", async () => { 11 | const el = await fixture(html` `); 12 | expect(Boolean(el.shadowRoot.querySelector(".spinner"))).to.equal(true); 13 | }); 14 | 15 | it("renders a spinner", async () => { 16 | const el = await fixture(html` 17 | 18 | `); 19 | expect(Boolean(el.shadowRoot.querySelector(".spinner"))).to.equal(true); 20 | }); 21 | 22 | it("renders an ellipsis", async () => { 23 | const el = await fixture(html` 24 | 25 | `); 26 | expect(Boolean(el.shadowRoot.querySelector(".ellipsis"))).to.equal(true); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/loader/chameleon-loader.js: -------------------------------------------------------------------------------- 1 | import { ChameleonLoader } from "./lib/ChameleonLoader.js"; 2 | 3 | customElements.define("chameleon-loader", ChameleonLoader); 4 | -------------------------------------------------------------------------------- /packages/loader/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonLoader } from "./lib/ChameleonLoader.js"; 2 | export { ChameleonLoaderEllipsisStyle } from "./lib/ChameleonLoaderEllipsisStyle.js"; 3 | export { ChameleonLoaderSpinnerStyle } from "./lib/ChameleonLoaderSpinnerStyle.js"; 4 | export { ChameleonLoaderStyle } from "./lib/ChameleonLoaderStyle.js"; 5 | -------------------------------------------------------------------------------- /packages/loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/loader", 3 | "version": "2.0.1", 4 | "description": "Chameleon loader", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/loader#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-loader.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/loader/src/ChameleonLoader.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { ChameleonLoaderStyle } from "./ChameleonLoaderStyle.js"; 3 | import { ChameleonLoaderSpinnerStyle } from "./ChameleonLoaderSpinnerStyle.js"; 4 | import { ChameleonLoaderEllipsisStyle } from "./ChameleonLoaderEllipsisStyle.js"; 5 | 6 | export class ChameleonLoader extends LitElement { 7 | /** 8 | * Styles 9 | */ 10 | static styles = [ChameleonLoaderStyle]; 11 | 12 | @property({ type: String, reflect: true }) 13 | loader = "spinner"; 14 | 15 | @property({ type: String, reflect: true }) 16 | size = "auto"; 17 | 18 | /** 19 | * Template 20 | */ 21 | render() { 22 | switch (this.loader) { 23 | case "ellipsis": 24 | return this.renderEllipsisLoader(); 25 | case "spinner": 26 | default: 27 | return this.renderSpinnerLoader(); 28 | } 29 | } 30 | 31 | renderEllipsisLoader() { 32 | return html` 33 | 36 | 37 |
38 |
39 |
40 |
41 |
42 |
43 | `; 44 | } 45 | 46 | renderSpinnerLoader() { 47 | return html` 48 | 51 | 52 | 59 | 60 | 61 | `; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/loader/src/ChameleonLoaderEllipsisStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonLoaderEllipsisStyle = css` 4 | .ellipsis { 5 | display: inline-block; 6 | position: relative; 7 | width: 64px; 8 | height: 64px; 9 | } 10 | 11 | .ellipsis div { 12 | position: absolute; 13 | top: 27px; 14 | width: 11px; 15 | height: 11px; 16 | border-radius: 50%; 17 | background: var(--loader-color); 18 | animation-timing-function: cubic-bezier(0, 1, 1, 0); 19 | } 20 | 21 | .ellipsis div:nth-child(1) { 22 | left: 6px; 23 | animation: ellipsis1 0.6s infinite; 24 | } 25 | 26 | .ellipsis div:nth-child(2) { 27 | left: 6px; 28 | animation: ellipsis2 0.6s infinite; 29 | } 30 | 31 | .ellipsis div:nth-child(3) { 32 | left: 26px; 33 | animation: ellipsis2 0.6s infinite; 34 | } 35 | 36 | .ellipsis div:nth-child(4) { 37 | left: 45px; 38 | animation: ellipsis3 0.6s infinite; 39 | } 40 | 41 | @keyframes ellipsis1 { 42 | 0% { 43 | transform: scale(0); 44 | } 45 | 100% { 46 | transform: scale(1); 47 | } 48 | } 49 | 50 | @keyframes ellipsis3 { 51 | 0% { 52 | transform: scale(1); 53 | } 54 | 100% { 55 | transform: scale(0); 56 | } 57 | } 58 | 59 | @keyframes ellipsis2 { 60 | 0% { 61 | transform: translate(0, 0); 62 | } 63 | 100% { 64 | transform: translate(19px, 0); 65 | } 66 | } 67 | `; 68 | -------------------------------------------------------------------------------- /packages/loader/src/ChameleonLoaderSpinnerStyle.js: -------------------------------------------------------------------------------- 1 | /* ! 2 | * Materialize v1.0.0 (http://materializecss.com) 3 | * Copyright 2014-2017 Materialize 4 | * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) 5 | */ 6 | import { css } from "lit-element"; 7 | 8 | export const ChameleonLoaderSpinnerStyle = css` 9 | /* SVG styles. */ 10 | svg { 11 | animation: 2s linear infinite svg-animation; 12 | } 13 | 14 | /* SVG animation. */ 15 | @keyframes svg-animation { 16 | 0% { 17 | transform: rotateZ(0deg); 18 | } 19 | 100% { 20 | transform: rotateZ(360deg); 21 | } 22 | } 23 | 24 | /* Circle styles. */ 25 | circle { 26 | animation: 1.4s ease-in-out infinite both circle-animation; 27 | display: block; 28 | fill: transparent; 29 | stroke: var(--loader-color, #2c6fb7); 30 | stroke-linecap: round; 31 | stroke-dasharray: 283; 32 | stroke-dashoffset: 280; 33 | stroke-width: 10px; 34 | transform-origin: 50% 50%; 35 | } 36 | 37 | /* Circle animation. */ 38 | @keyframes circle-animation { 39 | 0%, 40 | 25% { 41 | stroke-dashoffset: 280; 42 | transform: rotate(0); 43 | } 44 | 45 | 50%, 46 | 75% { 47 | stroke-dashoffset: 75; 48 | transform: rotate(45deg); 49 | } 50 | 51 | 100% { 52 | stroke-dashoffset: 280; 53 | transform: rotate(360deg); 54 | } 55 | } 56 | `; 57 | -------------------------------------------------------------------------------- /packages/loader/src/ChameleonLoaderStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonLoaderStyle = css` 4 | :host { 5 | box-sizing: border-box; 6 | --loader-color: var(--color-primary, #2c6fb7); 7 | } 8 | 9 | :host * { 10 | box-sizing: border-box; 11 | } 12 | `; 13 | -------------------------------------------------------------------------------- /packages/modal/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Modal 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import "./chameleon-modal.js"; 6 | 7 | export default { 8 | title: "Components|Overlays/Modal", 9 | component: "chameleon-modal", 10 | options: { selectedPanel: "storybookjs/docs/panel" }, 11 | }; 12 | ``` 13 | 14 | ## Properties 15 | 16 | | Property Name | Type(s) | Default Value | Description | 17 | | ------------- | ------- | ------------- | ------------------------------------------- | 18 | | `open` | Boolean | `false` | If the modal is open | 19 | | `dismissible` | Boolean | `false` | If the modal is dismissible | 20 | | `fullScreen` | Boolean | `false` | Whether or not the modal appears fullscreen | 21 | 22 | ## Examples 23 | 24 | ### Default 25 | 26 | ```js preview-story 27 | export const Default = () => html` 28 | 29 |

Contact Form

30 |
31 | 32 | 33 | 34 |
35 | 36 | Cancel 37 | 38 | 39 | Continue 40 | 41 |
42 | `; 43 | ``` 44 | -------------------------------------------------------------------------------- /packages/modal/__tests__/chameleon-modal.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import sinon from "sinon"; 3 | import "../chameleon-modal.js"; 4 | 5 | const fixture = html``; 6 | 7 | describe("chameleon-modal", () => { 8 | let element; 9 | 10 | beforeEach(async () => { 11 | element = await litFixture(fixture); 12 | }); 13 | 14 | it("renders", () => { 15 | expect(Boolean(element.shadowRoot)).to.equal(true); 16 | }); 17 | 18 | describe("_togglemodal", () => { 19 | it("should set open to true", () => { 20 | element.open = false; 21 | element._togglemodal(); 22 | 23 | expect(element.open).to.be.true; 24 | }); 25 | 26 | it("should set open to false", () => { 27 | element.open = true; 28 | element._togglemodal(); 29 | 30 | expect(element.open).to.be.false; 31 | }); 32 | 33 | it("should dispatch a toggle-modal event", () => { 34 | const spy = sinon.spy(); 35 | element.addEventListener("toggle-modal", spy); 36 | element._togglemodal({}); 37 | expect(spy).to.be.calledOnce; 38 | }); 39 | }); 40 | 41 | describe("closeIcon", () => { 42 | it("closeIcon returns an Svg if close-icon slot is defined", async () => { 43 | element = await litFixture( 44 | html` ` 45 | ); 46 | const closeIcon = await litFixture(element.closeIcon); 47 | 48 | expect(closeIcon).dom.to.equal( 49 | `` 50 | ); 51 | }); 52 | 53 | it("closeIcon returns a slot if close-icon is undefined", async () => { 54 | element = await litFixture( 55 | html` ` 56 | ); 57 | const closeIcon = await litFixture(element.closeIcon); 58 | 59 | expect(closeIcon).dom.to.equal(""); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /packages/modal/chameleon-modal.js: -------------------------------------------------------------------------------- 1 | import { ChameleonModal } from "./lib/ChameleonModal.js"; 2 | 3 | customElements.define("chameleon-modal", ChameleonModal); 4 | -------------------------------------------------------------------------------- /packages/modal/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonModal } from "./lib/ChameleonModal.js"; 2 | export { ChameleonModalStyle } from "./lib/ChameleonModalStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/modal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/modal", 3 | "version": "1.0.1", 4 | "description": "Chameleon modal", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/modal#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-modal.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/button": "^2.0.1", 27 | "@chameleon-ds/card": "^2.0.1", 28 | "lit-element": "^2.2.1" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/modal/src/ChameleonModal.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing, svg } from "lit-html"; 3 | import { classMap } from "lit-html/directives/class-map"; 4 | import { ChameleonModalStyle } from "./ChameleonModalStyle.js"; 5 | import "@chameleon-ds/card/chameleon-card"; 6 | import "@chameleon-ds/button/chameleon-button"; 7 | 8 | export class ChameleonModal extends LitElement { 9 | /** 10 | * Properties 11 | */ 12 | @property({ type: Boolean, reflect: true }) 13 | open = false; 14 | 15 | // Card has a close icon 16 | @property({ type: Boolean, reflect: true }) 17 | dismissible = false; 18 | 19 | @property({ type: Boolean, reflect: true }) 20 | fullScreen = false; 21 | 22 | /** 23 | * Styles 24 | */ 25 | static styles = [ChameleonModalStyle]; 26 | 27 | /** 28 | * Template 29 | */ 30 | render() { 31 | return html` 32 |
39 | 40 |
41 | 42 | ${this.dismissible 43 | ? html` 44 | 50 | ${this.closeIcon} 51 | 52 | ` 53 | : nothing} 54 |
55 |
56 | 57 |
58 | 62 |
63 |
64 | `; 65 | } 66 | 67 | _togglemodal() { 68 | this.open = !this.open; 69 | const e = new CustomEvent("toggle-modal", { 70 | bubbles: true, 71 | composed: true, 72 | }); 73 | this.dispatchEvent(e); 74 | } 75 | 76 | get closeIcon() { 77 | const slots = Array.from(this.querySelectorAll("[slot]")); 78 | const closeIcon = slots.find((slot) => slot.slot === "close-icon"); 79 | 80 | if (closeIcon === undefined) 81 | return svg``; 82 | else return html` `; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/modal/src/ChameleonModalStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonModalStyle = css` 4 | .open { 5 | display: flex; 6 | } 7 | 8 | .close { 9 | display: none; 10 | } 11 | 12 | ::slotted([slot="body"]) { 13 | display: grid; 14 | grid-template-rows: auto; 15 | grid-column-gap: 20px; 16 | grid-row-gap: 20px; 17 | grid-template-columns: repeat(2, 1fr); 18 | } 19 | 20 | .header { 21 | display: grid; 22 | max-height: 80px; 23 | grid-template-rows: auto; 24 | grid-column-gap: 1rem; 25 | grid-template-columns: 1fr; 26 | } 27 | 28 | .footer { 29 | display: grid; 30 | grid-template-rows: auto; 31 | grid-column-gap: 20px; 32 | grid-row-gap: 20px; 33 | grid-template-columns: repeat(10, 1fr); 34 | } 35 | 36 | .header { 37 | border-bottom: 1px var(--color-gray-light, #c4c7ca) solid; 38 | padding: 30px 30px; 39 | } 40 | 41 | .footer { 42 | padding: 0 30px 30px; 43 | } 44 | 45 | .overlay { 46 | width: 100vw; 47 | height: 100vh; 48 | background-color: rgba(0, 0, 0, 0.4); 49 | position: fixed; 50 | top: 0; 51 | right: 0; 52 | bottom: 0; 53 | left: 0; 54 | z-index: 9999; 55 | } 56 | 57 | chameleon-card { 58 | flex-direction: column; 59 | border-top: solid var(--color-secondary) 10px; 60 | position: absolute; 61 | left: 50%; 62 | top: 50%; 63 | padding: 0px !important; 64 | transform: translate(-50%, -50%); 65 | border-radius: 5px; 66 | box-shadow: 0 8px 16px 0 rgba(12, 0, 51, 0.1); 67 | margin: auto; 68 | background-color: #ffffff; 69 | width: 600px; 70 | padding: 30px; 71 | animation-name: modalopen; 72 | animation-duration: 1s; 73 | } 74 | 75 | .full-screen { 76 | border-radius: unset; 77 | position: relative; 78 | width: 100%; 79 | margin-bottom: 0; 80 | margin-top: 0; 81 | } 82 | 83 | .close-icon { 84 | cursor: pointer; 85 | grid-column: 10 / span 1; 86 | justify-self: right; 87 | } 88 | 89 | ::slotted([slot="right-button"]) { 90 | cursor: pointer; 91 | grid-column: 9 / span 2; 92 | } 93 | 94 | @media (max-width: 480px) { 95 | ::slotted([slot="right-button"]) { 96 | grid-column: 8 / span 3; 97 | } 98 | } 99 | 100 | svg { 101 | height: 24px; 102 | color: var(--color-gray-darkest); 103 | } 104 | 105 | ::slotted(h3) { 106 | color: var(--color-primary-dark, #004587); 107 | margin: 0; 108 | } 109 | 110 | ::slotted(h3, [slot="title"]), 111 | ::slotted([slot="left-button"]) { 112 | color: var(--color-primary-dark, #004587); 113 | height: 19px; 114 | font-family: Lato; 115 | font-size: 18px; 116 | font-weight: normal; 117 | font-stretch: normal; 118 | font-style: normal; 119 | line-height: 1.17; 120 | letter-spacing: normal; 121 | margin: 0; 122 | } 123 | 124 | ::slotted([slot="body"]) { 125 | padding: 20px 30px 40px; 126 | } 127 | 128 | @keyframes modalopen { 129 | from { 130 | opacity: 0; 131 | } 132 | to { 133 | opacity: 1; 134 | } 135 | } 136 | `; 137 | -------------------------------------------------------------------------------- /packages/multiselect/chameleon-multiselect.js: -------------------------------------------------------------------------------- 1 | import { ChameleonMultiselect } from "./lib/ChameleonMultiselect.js"; 2 | 3 | customElements.define("chameleon-multiselect", ChameleonMultiselect); 4 | -------------------------------------------------------------------------------- /packages/multiselect/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonMultiselect } from "./lib/ChameleonMultiselect.js"; 2 | export { ChameleonMultiselectStyle } from "./lib/ChameleonMultiselectStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/multiselect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/multiselect", 3 | "version": "2.0.1", 4 | "description": "Chameleon multiselect", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/multiselect#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-multiselect.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/chip": "^2.0.1", 27 | "@chameleon-ds/loader": "^2.0.1", 28 | "lit-element": "^2.2.1" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 34 | } 35 | -------------------------------------------------------------------------------- /packages/paginator/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Pagniator 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, number } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-paginator.js"; 7 | 8 | export default { 9 | title: "Components|Navigation/Paginator", 10 | component: "chameleon-paginator", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | -------------------------------------- | 20 | | `totalItems` | Number | `null` | The total number of items in all pages | 21 | | `pageSize` | Number | `null` | The amount of pages of items | 22 | | `currentPage` | Number | `1` | The multiselect's current page | 23 | | `maxLength` | Number | `7` | The max length of visible pages | 24 | | `separator` | String | `"..."` | The separator for skipped pages | 25 | 26 | ## Examples 27 | 28 | ### Default 29 | 30 | ```js preview-story 31 | export const Default = () => { 32 | const totalItems = number("Total Items", 100); 33 | const pageSize = number("Page Size", 10); 34 | 35 | return html` 36 | 40 | `; 41 | }; 42 | ``` 43 | -------------------------------------------------------------------------------- /packages/paginator/chameleon-paginator.js: -------------------------------------------------------------------------------- 1 | import { ChameleonPaginator } from "./lib/ChameleonPaginator.js"; 2 | 3 | customElements.define("chameleon-paginator", ChameleonPaginator); 4 | -------------------------------------------------------------------------------- /packages/paginator/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonPaginator } from "./lib/ChameleonPaginator.js"; 2 | export { ChameleonPaginatorStyle } from "./lib/ChameleonPaginatorStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/paginator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/paginator", 3 | "version": "2.0.1", 4 | "description": "Chameleon paginator", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/paginator#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-paginator.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/button": "^2.0.1", 27 | "lit-element": "^2.2.1" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/paginator/src/ChameleonPaginatorStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonPaginatorStyle = css` 4 | :host { 5 | align-items: center; 6 | display: flex; 7 | } 8 | 9 | .pages { 10 | list-style: none; 11 | margin: 0; 12 | padding: 0; 13 | } 14 | 15 | .page { 16 | box-sizing: border-box; 17 | cursor: pointer; 18 | display: inline-block; 19 | margin: 18px; 20 | } 21 | 22 | .page a { 23 | color: var(--color-primary, #2c6fb7); 24 | } 25 | 26 | .separator { 27 | cursor: auto; 28 | margin: 14px; 29 | } 30 | 31 | .current, 32 | .page:not(.separator):hover { 33 | color: var(--color-surface, #ffffff); 34 | margin: 0 4px; 35 | } 36 | 37 | a { 38 | text-decoration: none; 39 | } 40 | 41 | .current a, 42 | .page a:not(.separator):hover { 43 | align-items: center; 44 | background-color: var(--color-primary, #2c6fb7); 45 | color: var(--color-surface, #ffffff); 46 | border-radius: 50%; 47 | display: inline-flex; 48 | height: 36px; 49 | justify-content: center; 50 | width: 36px; 51 | } 52 | 53 | .placeholder { 54 | width: 68px; 55 | } 56 | `; 57 | -------------------------------------------------------------------------------- /packages/progress-bar/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Progress Bar 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, number, text } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-progress-bar.js"; 7 | 8 | export default { 9 | title: "Components|Status/Progress Bar", 10 | component: "chameleon-progress-bar", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | -------------------------------------- | 20 | | `percent` | Number | `undefined` | The total number of items in all pages | 21 | | `total` | Number | `0` | The amount of pages of items | 22 | | `completed` | Number | `0` | The multiselect's current page | 23 | | `label` | String | `""` | The max length of visible pages | 24 | 25 | ## Examples 26 | 27 | ### Default 28 | 29 | ```js preview-story 30 | export const Default = () => { 31 | const percent = number("Percent", 75); 32 | const label = text("Label", "Processing..."); 33 | 34 | return html` 35 | 36 | 37 | `; 38 | }; 39 | ``` 40 | -------------------------------------------------------------------------------- /packages/progress-bar/__tests__/chameleon-progress-bar.test.js: -------------------------------------------------------------------------------- 1 | import { fixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-progress-bar.js"; 3 | 4 | describe("chameleon-progress-bar", () => { 5 | it("renders", async () => { 6 | const el = await fixture(html` 7 | 8 | `); 9 | expect(Boolean(el.shadowRoot)).to.equal(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/progress-bar/chameleon-progress-bar.js: -------------------------------------------------------------------------------- 1 | import { ChameleonProgressBar } from "./lib/ChameleonProgressBar.js"; 2 | 3 | customElements.define("chameleon-progress-bar", ChameleonProgressBar); 4 | -------------------------------------------------------------------------------- /packages/progress-bar/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonProgressBar } from "./lib/ChameleonProgressBar.js"; 2 | export { ChameleonProgressBarStyle } from "./lib/ChameleonProgressBarStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/progress-bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/progress-bar", 3 | "version": "1.0.1", 4 | "description": "Chameleon progress bar", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/progress-bar#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-progress-bar.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/progress-bar/src/ChameleonProgressBar.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { ChameleonProgressBarStyle } from "./ChameleonProgressBarStyle.js"; 3 | 4 | export class ChameleonProgressBar extends LitElement { 5 | /** 6 | * Properties 7 | */ 8 | @property({ type: Number, reflect: true }) 9 | percent = undefined; 10 | 11 | @property({ type: Number, reflect: true }) 12 | total = 0; 13 | 14 | @property({ type: Number, reflect: true }) 15 | completed = 0; 16 | 17 | @property({ type: String, reflect: true }) 18 | label = ""; 19 | 20 | /** 21 | * Styles 22 | */ 23 | static styles = [ChameleonProgressBarStyle]; 24 | 25 | /** 26 | * Template 27 | */ 28 | render() { 29 | return html` 30 |
31 |
32 |
40 |
41 | 44 | 49 |
50 | `; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/progress-bar/src/ChameleonProgressBarStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonProgressBarStyle = css` 4 | :host { 5 | display: inline-flex; 6 | } 7 | 8 | .progress-bar-container { 9 | width: 100%; 10 | } 11 | 12 | .background { 13 | height: 12px; 14 | position: relative; 15 | background-color: rgba(44, 111, 183, 0.05); 16 | padding: 4px 6px; 17 | border-radius: 3px; 18 | } 19 | 20 | .progress-bar { 21 | height: 12px; 22 | background-color: rgba(44, 111, 183, 1); 23 | border-radius: 3px; 24 | } 25 | 26 | label { 27 | font-family: var(--font-family, sans-serif); 28 | font-size: var(--font-size-label, 0.875rem); 29 | } 30 | 31 | .total-item-label { 32 | font-weight: bold; 33 | color: rgba(44, 111, 183, 1); 34 | } 35 | `; 36 | -------------------------------------------------------------------------------- /packages/radio/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Radio 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-radio.js"; 7 | 8 | export default { 9 | title: "Components|Form Elements/Radio", 10 | component: "chameleon-radio", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | ------------------------------------------------------------------------------------ | 20 | | `label` | String | `""` | The radio's label | 21 | | `name` | String | `"cha-radio"` | The radio's form name | 22 | | `checked` | Boolean | `false` | A Boolean which, if true, indicates that the radio is selected | 23 | | `value` | String | `""` | The radio's current value | 24 | | `disabled` | Boolean | `false` | A Boolean to disable radio button | 25 | | `readonly` | Boolean | `false` | A Boolean attribute which, if true, indicates that the radio button cannot be edited | 26 | | `invalid` | Boolean | `false` | Invalid boolean to allow validity access from higher level form errors | 27 | 28 | ## Examples 29 | 30 | ### Default 31 | 32 | ```js preview-story 33 | export const Default = () => { 34 | const label = text("Label", ""); 35 | const checked = boolean("Checked", true); 36 | const disabled = boolean("Disabled", false); 37 | const invalid = boolean("Invalid", false); 38 | 39 | return html` 40 | 46 | `; 47 | }; 48 | ``` 49 | -------------------------------------------------------------------------------- /packages/radio/__tests__/chameleon-radio.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-radio.js"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-radio", () => { 7 | let element; 8 | 9 | beforeEach(async () => { 10 | element = await litFixture(fixture); 11 | }); 12 | 13 | it("renders", () => { 14 | expect(Boolean(element.shadowRoot)).to.equal(true); 15 | }); 16 | 17 | it("shows aria-invalid when invalid", () => { 18 | element.invalid = true; 19 | expect(element).shadowDom.to.equalSnapshot(); 20 | }); 21 | it("shows name attribute", () => { 22 | element.name = "formName"; 23 | expect(element).shadowDom.to.equalSnapshot(); 24 | }); 25 | it("shows disabled attribute", () => { 26 | element.required = true; 27 | expect(element).shadowDom.to.equalSnapshot(); 28 | }); 29 | it("shows readonly attribute", () => { 30 | element.readonly = true; 31 | expect(element).shadowDom.to.equalSnapshot(); 32 | }); 33 | 34 | it("renders labelText", () => { 35 | element.label = "chameleon"; 36 | 37 | expect(element.labelText).to.equal("chameleon"); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/radio/chameleon-radio.js: -------------------------------------------------------------------------------- 1 | import { ChameleonRadio } from "./lib/ChameleonRadio.js"; 2 | 3 | customElements.define("chameleon-radio", ChameleonRadio); 4 | -------------------------------------------------------------------------------- /packages/radio/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonRadio } from "./lib/ChameleonRadio.js"; 2 | export { ChameleonRadioStyle } from "./lib/ChameleonRadioStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/radio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/radio", 3 | "version": "2.0.1", 4 | "description": "Chameleon radio", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/radio#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-radio.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/radio/src/ChameleonRadio.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { ChameleonRadioStyle } from "./ChameleonRadioStyle.js"; 4 | 5 | export class ChameleonRadio extends LitElement { 6 | /** 7 | * Properties 8 | */ 9 | 10 | // The radio's label 11 | @property({ type: String }) 12 | label = ""; 13 | 14 | @property({ type: String }) 15 | name = "cha-radio"; 16 | 17 | // A Boolean which, if true, indicates that the radio is selected 18 | @property({ type: Boolean, reflect: true }) 19 | checked = false; 20 | 21 | // The radio's current value 22 | @property({ type: String }) 23 | value = ""; 24 | 25 | // A Boolean to disable radio button 26 | @property({ type: Boolean, reflect: true }) 27 | disabled = false; 28 | 29 | // A Boolean attribute which, if true, indicates that the radio button cannot be edited 30 | @property({ type: Boolean, reflect: true }) 31 | readonly = false; 32 | 33 | // Invalid boolean to allow validity access from higher level form errors 34 | @property({ type: Boolean, reflect: true }) 35 | invalid = false; 36 | 37 | /** 38 | * Styles 39 | */ 40 | static styles = [ChameleonRadioStyle]; 41 | 42 | /** 43 | * Template 44 | */ 45 | render() { 46 | return html` 47 | 57 | 58 | ${this.labelText} 59 | `; 60 | } 61 | 62 | get labelText() { 63 | if (this.label !== "") return this.label; 64 | else return nothing; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/radio/src/ChameleonRadioStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonRadioStyle = css` 4 | :host { 5 | align-items: center; 6 | cursor: pointer; 7 | display: inline-flex; 8 | font-size: var(--font-size-input, 0.938rem); 9 | -webkit-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | input { 16 | cursor: pointer; 17 | display: none; 18 | } 19 | 20 | .checkmark { 21 | background-color: var(--color-surface, #ffffff); 22 | border: 2px solid var(--color-gray-lightest, #e1e3e4); 23 | border-radius: 50%; 24 | box-sizing: border-box; 25 | display: inline-block; 26 | height: 20px; 27 | margin-right: 10px; 28 | position: relative; 29 | width: 20px; 30 | } 31 | 32 | :host:hover input ~ .checkmark { 33 | background-color: var(--color-surface, #ffffff); 34 | } 35 | 36 | input:checked ~ .checkmark { 37 | background-color: var(--color-primary, #2c6fb7); 38 | border: none; 39 | } 40 | 41 | .checkmark:after { 42 | content: ""; 43 | display: none; 44 | position: absolute; 45 | } 46 | 47 | input:checked ~ .checkmark:after { 48 | display: block; 49 | } 50 | 51 | .checkmark:after { 52 | background: var(--color-surface, #ffffff); 53 | border-radius: 50%; 54 | height: 8px; 55 | left: 50%; 56 | top: 50%; 57 | transform: translate(-50%, -50%); 58 | width: 8px; 59 | } 60 | :host([invalid]) .checkmark { 61 | border-color: var(--color-error, #bc1c16); 62 | } 63 | 64 | :host([invalid]) input:checked ~ .checkmark { 65 | border: 2px solid var(--color-error, #bc1c16); 66 | } 67 | 68 | :host([readonly]), 69 | :host([disabled]), 70 | input[disabled] { 71 | pointer-events: none; 72 | } 73 | 74 | input:checked ~ .checkmark.disabled { 75 | background-color: var(--color-gray-lightest, #e1e3e4); 76 | pointer-events: none; 77 | } 78 | `; 79 | -------------------------------------------------------------------------------- /packages/select/chameleon-select.js: -------------------------------------------------------------------------------- 1 | import { ChameleonSelect } from "./lib/ChameleonSelect.js"; 2 | 3 | customElements.define("chameleon-select", ChameleonSelect); 4 | -------------------------------------------------------------------------------- /packages/select/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonSelect } from "./lib/ChameleonSelect.js"; 2 | export { ChameleonSelectStyle } from "./lib/ChameleonSelectStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/select/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/select", 3 | "version": "2.0.2", 4 | "description": "Chameleon select", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/select#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-select.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.0" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 32 | } 33 | -------------------------------------------------------------------------------- /packages/sheet/__tests__/chameleon-sheet.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-sheet.js"; 3 | import "../sheet-content.js"; 4 | 5 | describe("chameleon-sheet", () => { 6 | let el; 7 | beforeEach(async () => { 8 | el = await litFixture(html` 9 | 10 |
content
11 | 12 |
13 | `); 14 | }); 15 | 16 | it("is not opened by default", () => { 17 | expect(el.opened).not.to.equal(true); 18 | }); 19 | it("opens when invoker is clicked", async () => { 20 | const invoker = el.querySelector("[slot='invoker']"); 21 | invoker.click(); 22 | await el.updateComplete; 23 | expect(el.opened).to.equal(true); 24 | }); 25 | it("relocates content slot", () => { 26 | const globalRootNode = document.body.querySelector(".global-overlays"); 27 | const relocatedNode = globalRootNode.lastChild; 28 | expect(relocatedNode.innerHTML).to.equal( 29 | `
content
` 30 | ); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/sheet/__tests__/sheet-content.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-sheet.js"; 3 | import "../sheet-content.js"; 4 | 5 | describe("sheet-content", () => { 6 | let el; 7 | beforeEach(async () => { 8 | el = await litFixture(html` 9 | 10 |

content

11 |
12 | `); 13 | }); 14 | 15 | it("has customizable width", async () => { 16 | expect(el.width).to.equal("320px"); 17 | el.width = "75vw"; 18 | await el.updateComplete; 19 | const styleNode = el.shadowRoot.querySelector("style"); 20 | expect(styleNode.textContent.includes("75vw")).to.equal(true); 21 | }); 22 | it("maintains width-per-instance", async () => { 23 | const el2 = await litFixture(html` 24 | 25 |

content

26 |
27 | `); 28 | const styleNode = el.shadowRoot.querySelector("style"); 29 | const styleNode2 = el2.shadowRoot.querySelector("style"); 30 | expect(el.width).to.equal("320px"); 31 | expect(styleNode.textContent.includes("320px")).to.equal(true); 32 | expect(el2.width).to.equal(`75vw`); 33 | expect(styleNode2.textContent.includes("75vw")).to.equal(true); 34 | }); 35 | it("accepts default slotted content", () => { 36 | const assignedElement = el.querySelector("#myContent"); 37 | const slot = el.shadowRoot.querySelector("slot"); 38 | expect(slot.assignedElements().includes(assignedElement)).to.equal(true); 39 | }); 40 | it("is dismissable by default", () => { 41 | expect(el.dismissable).to.equal(true); 42 | }); 43 | it("displays close icon when dismissable", () => { 44 | expect( 45 | el.shadowRoot.querySelector(".close-icon").innerHTML.includes("svg") 46 | ).to.equal(true); 47 | expect(el.shadowRoot.querySelector(".close-icon")).to.not.equal(null); 48 | }); 49 | it("doesn't show close icon when not dismissable", async () => { 50 | el.dismissable = false; 51 | await el.updateComplete; 52 | expect(el.shadowRoot.querySelector(".close-icon")).to.equal(null); 53 | }); 54 | it("close icon dispatches close-overlay event when clicked", () => { 55 | let called = false; 56 | const listener = (e) => { 57 | called = true; 58 | }; 59 | el.addEventListener("close-overlay", listener); 60 | el.shadowRoot.querySelector(".close-icon").click(); 61 | expect(called).to.equal(true); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /packages/sheet/chameleon-sheet.js: -------------------------------------------------------------------------------- 1 | import { ChameleonSheet } from "./lib/ChameleonSheet.js"; 2 | 3 | customElements.define("chameleon-sheet", ChameleonSheet); 4 | -------------------------------------------------------------------------------- /packages/sheet/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonSheet } from "./lib/ChameleonSheet.js"; 2 | export { SheetContent } from "./lib/SheetContent.js"; 3 | -------------------------------------------------------------------------------- /packages/sheet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/sheet", 3 | "version": "3.0.2", 4 | "description": "Chameleon sheet", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/sheet#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-sheet.js", 16 | "sheet-content.js", 17 | "/lib/" 18 | ], 19 | "scripts": { 20 | "test": "echo \"Error: run tests from root\" && exit 1", 21 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/MaritzSTL/chameleon/issues" 25 | }, 26 | "dependencies": { 27 | "@chameleon-ds/button": "^2.0.1", 28 | "@lion/overlays": "0.16.0", 29 | "lit-element": "^2.2.1" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/sheet/sheet-content.js: -------------------------------------------------------------------------------- 1 | import { SheetContent } from "./lib/SheetContent.js"; 2 | 3 | customElements.define("sheet-content", SheetContent); 4 | -------------------------------------------------------------------------------- /packages/sheet/src/ChameleonSheet.js: -------------------------------------------------------------------------------- 1 | import { OverlayMixin } from "@lion/overlays"; 2 | import { LitElement, html, property } from "lit-element"; 3 | 4 | export class ChameleonSheet extends OverlayMixin(LitElement) { 5 | __toggle; 6 | 7 | @property({ type: Boolean }) trapsKeyboardFocus = true; 8 | @property({ type: Boolean }) hasBackdrop = true; 9 | @property({ type: Boolean }) hidesOnOutsideClick = true; 10 | @property({ type: Boolean }) hidesOnEsc = true; 11 | @property({ type: Boolean }) preventsScroll = true; 12 | 13 | // eslint-disable-next-line class-methods-use-this 14 | _defineOverlayConfig() { 15 | return { 16 | placementMode: "global", 17 | viewportConfig: { 18 | placement: "right", 19 | }, 20 | handleAccessibility: true, 21 | hasBackdrop: this.hasBackdrop, 22 | hidesOnEsc: this.hidesOnEsc, 23 | hidesOnOutsideClick: this.hidesOnOutsideClick, 24 | preventsScroll: this.preventsScroll, 25 | trapsKeyboardFocus: this.trapsKeyboardFocus, 26 | }; 27 | } 28 | 29 | _setupOpenCloseListeners() { 30 | super._setupOpenCloseListeners(); 31 | this.__toggle = () => { 32 | this.opened = !this.opened; 33 | }; 34 | 35 | if (this._overlayInvokerNode) { 36 | this._overlayInvokerNode.addEventListener("click", this.__toggle); 37 | } 38 | } 39 | 40 | _teardownOpenCloseListeners() { 41 | super._teardownOpenCloseListeners(); 42 | 43 | if (this._overlayInvokerNode) { 44 | this._overlayInvokerNode.removeEventListener("click", this.__toggle); 45 | } 46 | } 47 | 48 | render() { 49 | return html` 50 | 51 | 52 |
53 | 54 |
55 | `; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/sheet/src/SheetContent.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, svg, css, property } from "lit-element"; 2 | 3 | export class SheetContent extends LitElement { 4 | static get closeIcon() { 5 | return svg``; 6 | } 7 | 8 | static get styles() { 9 | return [ 10 | css` 11 | @keyframes sheet-slide { 12 | 10% { 13 | transform: translateX(90%); 14 | } 15 | 20% { 16 | transform: translateX(80%); 17 | } 18 | 30% { 19 | transform: translateX(70%); 20 | } 21 | 40% { 22 | transform: translateX(60%); 23 | } 24 | 50% { 25 | transform: translateX(50%); 26 | } 27 | 60% { 28 | transform: translateX(40%); 29 | } 30 | 70% { 31 | transform: translateX(30%); 32 | } 33 | 80% { 34 | transform: translateX(20%); 35 | } 36 | 90% { 37 | transform: translateX(10%); 38 | } 39 | 100% { 40 | transform: translateX(0); 41 | } 42 | } 43 | 44 | :host { 45 | height: 100%; 46 | background-color: #ffffff; 47 | transform: translateX(100%); 48 | -webkit-animation: sheet-slide 0.3s forwards; 49 | animation: sheet-slide 0.3s forwards; 50 | } 51 | 52 | .close-icon { 53 | display: flex; 54 | cursor: pointer; 55 | margin: 0; 56 | position: absolute; 57 | top: 14px; 58 | right: 14px; 59 | z-index: 10; 60 | } 61 | `, 62 | ]; 63 | } 64 | @property({ type: Boolean, reflect: true }) dismissable = true; 65 | @property({ type: String, reflect: true }) width = "320px"; 66 | 67 | close() { 68 | this.dispatchEvent(new Event("close-overlay", { bubbles: true })); 69 | } 70 | 71 | get defaultCloseIcon() { 72 | return html` 73 | 74 | ${SheetContent.closeIcon} 75 | 76 | `; 77 | } 78 | 79 | render() { 80 | return html` 81 | 86 | ${this.dismissable ? this.defaultCloseIcon : ""} 87 | 88 | `; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Skeleton 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, number } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-skeleton.js"; 7 | 8 | export default { 9 | title: "Components|Data and Visualizations/Skeleton", 10 | component: "chameleon-skeleton", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | --------------------------------------------- | 20 | | `theme` | String | `"primary"` | The skeleton's theme ("primary", "secondary") | 21 | | `height` | String | `"100%"` | The skeleton's height | 22 | | `width` | String | `"100%"` | The skeleton's width | 23 | | `cHeight` | Number | `50` | The skeleton's circle height | 24 | 25 | ## Examples 26 | 27 | ### Default 28 | 29 | ```js preview-story 30 | export const Default = () => { 31 | const height = text("Height", "100%"); 32 | const width = text("Width", "100%"); 33 | const theme = text("Theme", "primary"); 34 | const cHeight = number("Circle Height", 50); 35 | 36 | return theme === "primary" 37 | ? html` 38 | 39 | 40 | ` 41 | : theme === "secondary" 42 | ? html` 43 | ` 44 | : ""; 45 | }; 46 | ``` 47 | -------------------------------------------------------------------------------- /packages/skeleton/__tests__/chameleon-skeleton.test.js: -------------------------------------------------------------------------------- 1 | import { fixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-skeleton.js"; 3 | 4 | describe("chameleon-skeleton", () => { 5 | it("renders", async () => { 6 | const el = await fixture(html``); 7 | expect(Boolean(el.shadowRoot)).to.equal(true); 8 | }); 9 | it("returns a radius half the size of the circle height if theme is secondary", async () => { 10 | const el = await fixture(html``); 11 | el.theme = "secondary"; 12 | el.cHeight = 50; 13 | expect(el.circleRadius).to.eql(25); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/skeleton/chameleon-skeleton.js: -------------------------------------------------------------------------------- 1 | import { ChameleonSkeleton } from "./lib/ChameleonSkeleton.js"; 2 | 3 | customElements.define("chameleon-skeleton", ChameleonSkeleton); 4 | -------------------------------------------------------------------------------- /packages/skeleton/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonSkeleton } from "./lib/ChameleonSkeleton.js"; 2 | export { ChameleonSkeletonStyle } from "./lib/ChameleonSkeletonStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/skeleton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/skeleton", 3 | "version": "2.0.1", 4 | "description": "Chameleon skeleton", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/skeleton#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-skeleton.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 32 | } 33 | -------------------------------------------------------------------------------- /packages/skeleton/src/ChameleonSkeleton.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property, svg } from "lit-element"; 2 | import { ChameleonSkeletonStyle } from "./ChameleonSkeletonStyle.js"; 3 | 4 | export class ChameleonSkeleton extends LitElement { 5 | /** 6 | * Properties 7 | */ 8 | @property({ type: String, reflect: true }) 9 | theme = "primary"; 10 | 11 | @property({ type: String, reflect: true }) 12 | height = "100%"; 13 | 14 | @property({ type: String, reflect: true }) 15 | width = "100%"; 16 | 17 | @property({ type: Number, reflect: true }) 18 | cHeight = 50; 19 | 20 | /** 21 | * Styles 22 | */ 23 | static styles = [ChameleonSkeletonStyle]; 24 | 25 | /** 26 | * Template 27 | */ 28 | render() { 29 | //TODO: add linear gradient animation 30 | /* 31 | 32 | 33 | 34 | 35 | 36 | */ 37 | return html` 38 | 39 | ${this.theme === "primary" 40 | ? svg` 41 | 50 | ` 51 | : this.theme === "secondary" 52 | ? svg` 53 | ` 54 | : ``} 55 | 56 | `; 57 | } 58 | 59 | get circleRadius() { 60 | return this.cHeight * 0.5; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/skeleton/src/ChameleonSkeletonStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonSkeletonStyle = css` 4 | .rectangle { 5 | fill: var(--color-gray-lightest, #e1e3e4); 6 | } 7 | 8 | .circle { 9 | fill: var(--color-gray-lightest, #e1e3e4); 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /packages/switch/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Switch 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-switch.js"; 7 | 8 | export default { 9 | title: "Components|Form Elements/Switch", 10 | component: "chameleon-switch", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------- | ------- | ------------- | --------------------------------- | 20 | | `label` | String | `""` | The switch's label | 21 | | `checked` | Boolean | `false` | If the switch is checked | 22 | | `readonly` | Boolean | `false` | If the switch's value is readonly | 23 | | `value` | String | `""` | The switch's current value | 24 | 25 | ## Examples 26 | 27 | ### Default 28 | 29 | ```js preview-story 30 | export const Default = () => { 31 | const label = text("Label", ""); 32 | const checked = boolean("Checked", true); 33 | const readonly = boolean("Read Only", false); 34 | 35 | return html` 36 | 41 | `; 42 | }; 43 | ``` 44 | -------------------------------------------------------------------------------- /packages/switch/__tests__/chameleon-switch.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import "../chameleon-switch.js"; 3 | 4 | const fixture = html` `; 5 | 6 | describe("chameleon-switch", () => { 7 | let element; 8 | 9 | it("renders", async () => { 10 | element = await litFixture(fixture); 11 | expect(Boolean(element.shadowRoot)).to.equal(true); 12 | }); 13 | 14 | it("renders labelText", () => { 15 | element.label = "chameleon"; 16 | 17 | expect(element.labelText).to.equal("chameleon"); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/switch/chameleon-switch.js: -------------------------------------------------------------------------------- 1 | import { ChameleonSwitch } from "./lib/ChameleonSwitch.js"; 2 | 3 | customElements.define("chameleon-switch", ChameleonSwitch); 4 | -------------------------------------------------------------------------------- /packages/switch/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonSwitch } from "./lib/ChameleonSwitch.js"; 2 | export { ChameleonSwitchStyle } from "./lib/ChameleonSwitchStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/switch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/switch", 3 | "version": "2.0.1", 4 | "description": "Chameleon switch", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/switch#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-switch.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/switch/src/ChameleonSwitch.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { nothing } from "lit-html"; 3 | import { ChameleonSwitchStyle } from "./ChameleonSwitchStyle.js"; 4 | 5 | export class ChameleonSwitch extends LitElement { 6 | /** 7 | * Properties 8 | */ 9 | 10 | // The switch's label 11 | @property({ type: String }) 12 | label = ""; 13 | 14 | // A Boolean which, if true, indicates that the switch is selected 15 | @property({ type: Boolean, reflect: true }) 16 | checked = false; 17 | 18 | // A Boolean attribute which, if true, indicates that the switch cannot be edited 19 | @property({ type: Boolean, reflect: true }) 20 | readonly = false; 21 | 22 | // The switch's current value 23 | @property({ type: String }) 24 | value = ""; 25 | 26 | /** 27 | * Styles 28 | */ 29 | static styles = [ChameleonSwitchStyle]; 30 | 31 | /** 32 | * Template 33 | */ 34 | render() { 35 | return html` 36 |
37 | 38 | 39 |
40 | ${this.labelText} 41 | `; 42 | } 43 | 44 | get labelText() { 45 | if (this.label !== "") return this.label; 46 | else return nothing; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/switch/src/ChameleonSwitchStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonSwitchStyle = css` 4 | :host { 5 | align-items: center; 6 | display: inline-flex; 7 | font-size: var(--font-size-input, 0.938rem); 8 | } 9 | 10 | :host([readonly]) { 11 | pointer-events: none; 12 | } 13 | 14 | .switch { 15 | display: inline-block; 16 | height: 20px; 17 | margin-right: 10px; 18 | position: relative; 19 | width: 32px; 20 | } 21 | 22 | .switch input { 23 | display: none; 24 | } 25 | 26 | .slider { 27 | background-color: var(--color-gray-lightest, #e1e3e4); 28 | border-radius: 10px; 29 | bottom: 0; 30 | cursor: pointer; 31 | left: 0; 32 | position: absolute; 33 | right: 0; 34 | top: 0; 35 | transition: 0.4s; 36 | } 37 | 38 | .slider:before { 39 | background-color: var(--color-surface, #ffffff); 40 | border-radius: 50%; 41 | bottom: 2px; 42 | box-shadow: 1px 0 3px var(--color-box-shadow, rgba(159, 164, 168, 0.6)); 43 | content: ""; 44 | height: 16px; 45 | left: 2px; 46 | position: absolute; 47 | transition: 0.4s; 48 | width: 16px; 49 | } 50 | 51 | input:checked + .slider { 52 | background-color: var(--color-primary, #2c6fb7); 53 | } 54 | 55 | input:focus + .slider { 56 | box-shadow: 0 0 3px var(--color-gray-dark, #9fa4a8); 57 | } 58 | 59 | input:checked + .slider:before { 60 | box-shadow: none; 61 | transform: translateX(12px); 62 | } 63 | `; 64 | -------------------------------------------------------------------------------- /packages/table/chameleon-table.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTable } from "./lib/ChameleonTable.js"; 2 | 3 | customElements.define("chameleon-table", ChameleonTable); 4 | -------------------------------------------------------------------------------- /packages/table/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonTable } from "./lib/ChameleonTable.js"; 2 | export { ChameleonTableStyle } from "./lib/ChameleonTableStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/table/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/table", 3 | "version": "2.0.1", 4 | "description": "Chameleon Table", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/tables#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-table.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "@chameleon-ds/input": "^2.0.1", 27 | "@chameleon-ds/multiselect": "^2.0.1", 28 | "@chameleon-ds/paginator": "^2.0.1", 29 | "lit-element": "^2.2.1" 30 | }, 31 | "publishConfig": { 32 | "access": "public" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/tabs/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Tabs 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import "./chameleon-tab.js"; 6 | import "./chameleon-tabs.js"; 7 | 8 | export default { 9 | title: "Components|Navigation/Tabs", 10 | component: "chameleon-tabs", 11 | options: { selectedPanel: "storybookjs/docs/panel" }, 12 | }; 13 | ``` 14 | 15 | ## Properties 16 | 17 | ### chameleon-tabs 18 | 19 | | Property Name | Type(s) | Default Value | Description | 20 | | ------------- | ------- | ------------- | -------------------------------------------------------------- | 21 | | `urlRewrite` | Boolean | `true` | Automatically rewrite URL with tab index information when true | 22 | | `selected` | Number | `0` | The selected tab's index | 23 | 24 | ## Examples 25 | 26 | ### Default 27 | 28 | ```js preview-story 29 | export const Default = () => html` 30 | 31 | 32 | Tab One 33 | 34 | 35 | Tab Two 36 | 37 | 38 | Tab Three 39 | 40 | 41 | `; 42 | ``` 43 | -------------------------------------------------------------------------------- /packages/tabs/__tests__/chameleon-tabs.test.js: -------------------------------------------------------------------------------- 1 | import { litFixture, html, expect } from "@open-wc/testing"; 2 | import sinon from "sinon"; 3 | import { ChameleonTabs } from "../index.js"; 4 | import "../chameleon-tab.js"; 5 | import "../chameleon-tabs.js"; 6 | 7 | const fixture = html` 8 | 9 | `; 10 | 11 | describe("chameleon-tabs", () => { 12 | let element; 13 | 14 | beforeEach(async () => { 15 | element = await litFixture(fixture); 16 | }); 17 | 18 | it("renders", async () => { 19 | expect(Boolean(element.shadowRoot)).to.equal(true); 20 | }); 21 | 22 | it("dispatches an event on handleToggle", () => { 23 | const tab = element.querySelector("chameleon-tab"); 24 | const spy = sinon.spy(tab, "dispatchEvent"); 25 | 26 | tab.handleToggle(); 27 | 28 | expect(spy).to.be.calledOnce; 29 | }); 30 | 31 | it("throws error if no tabs are given", () => { 32 | expect(() => new ChameleonTabs().firstUpdated()).to.throw(); 33 | }); 34 | 35 | it("updates selected tab", async () => { 36 | element.selected = 0; 37 | element.requestUpdate(); 38 | await element.updateComplete; 39 | 40 | expect(element.selected).to.equal(0); 41 | }); 42 | 43 | it("sets active attribute to true", async () => { 44 | element = await litFixture( 45 | html` 46 | 47 | 48 | 49 | 50 | ` 51 | ); 52 | element.selected = 0; 53 | element.requestUpdate(); 54 | await element.updateComplete; 55 | 56 | expect(element.selected).to.equal(0); 57 | 58 | element.selected = 1; 59 | element.requestUpdate(); 60 | await element.updateComplete; 61 | 62 | expect(element.selected).to.equal(1); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /packages/tabs/chameleon-tab.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTab } from "./lib/ChameleonTab.js"; 2 | 3 | customElements.define("chameleon-tab", ChameleonTab); 4 | -------------------------------------------------------------------------------- /packages/tabs/chameleon-tabs.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTabs } from "./lib/ChameleonTabs.js"; 2 | 3 | customElements.define("chameleon-tabs", ChameleonTabs); 4 | -------------------------------------------------------------------------------- /packages/tabs/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonTab } from "./lib/ChameleonTab.js"; 2 | export { ChameleonTabs } from "./lib/ChameleonTabs.js"; 3 | export { ChameleonTabsStyle } from "./lib/ChameleonTabsStyle.js"; 4 | -------------------------------------------------------------------------------- /packages/tabs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/tabs", 3 | "version": "2.0.1", 4 | "description": "Chameleon tabs", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/tabs#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-tab.js", 16 | "chameleon-tabs.js", 17 | "/lib/" 18 | ], 19 | "scripts": { 20 | "test": "echo \"Error: run tests from root\" && exit 1", 21 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/MaritzSTL/chameleon/issues" 25 | }, 26 | "dependencies": { 27 | "lit-element": "^2.2.1" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/tabs/src/ChameleonTab.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html } from "lit-element"; 2 | 3 | export class ChameleonTab extends LitElement { 4 | constructor() { 5 | super(); 6 | 7 | this.addEventListener("click", this.handleToggle); 8 | } 9 | 10 | /** 11 | * Template 12 | */ 13 | render() { 14 | return html``; 15 | } 16 | 17 | handleToggle() { 18 | this.dispatchEvent( 19 | new CustomEvent("chameleon.tabs.selected-changed", { 20 | detail: { 21 | value: this.dataset.index, 22 | }, 23 | bubbles: true, 24 | composed: true, 25 | }) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/tabs/src/ChameleonTabs.js: -------------------------------------------------------------------------------- 1 | import { LitElement, property, html } from "lit-element"; 2 | import { ChameleonTabsStyle } from "./ChameleonTabsStyle.js"; 3 | 4 | export class ChameleonTabs extends LitElement { 5 | constructor() { 6 | super(); 7 | this.addEventListener( 8 | "chameleon.tabs.selected-changed", 9 | this._handleSelectedChanged 10 | ); 11 | } 12 | 13 | /** 14 | * Lifecycle Methods 15 | */ 16 | firstUpdated() { 17 | // Index tabs 18 | const tabs = Array.from(this.querySelectorAll("chameleon-tab")); 19 | if (tabs.length <= 0) 20 | throw new Error( 21 | " must have at least one element" 22 | ); 23 | tabs.forEach((tab, i) => tab.setAttribute("data-index", i.toString())); 24 | 25 | // If has an id, allow the selected tab index to 26 | // be set using query params: ?tabs_=1 27 | if (this.id) { 28 | const params = new URLSearchParams(window.location.search); 29 | if (params.has(`tabs_${this.id}`)) { 30 | const index = parseInt(params.get(`tabs_${this.id}`)); 31 | this.selected = index <= tabs.length - 1 ? index : 0; 32 | } else { 33 | if (this.urlRewrite) 34 | params.append(`tabs_${this.id}`, String(this.selected)); 35 | } 36 | } 37 | } 38 | 39 | updated(changedProperties) { 40 | if (changedProperties.has("selected")) { 41 | const tabs = Array.from(this.querySelectorAll("chameleon-tab")); 42 | 43 | tabs.forEach((tab, i) => { 44 | tab.removeAttribute("active"); 45 | if (i === this.selected) tab.setAttribute("active", "true"); 46 | }); 47 | } 48 | } 49 | 50 | /** 51 | * Properties 52 | */ 53 | @property({ type: Number, reflect: true }) 54 | selected = 0; 55 | 56 | /** Automatically rewrite URL with tab index information. Default: true. */ 57 | @property({ type: Boolean }) 58 | urlRewrite = true; 59 | 60 | /** 61 | * Styles 62 | */ 63 | static styles = [ChameleonTabsStyle]; 64 | 65 | /** 66 | * Template 67 | */ 68 | render() { 69 | return html``; 70 | } 71 | 72 | _handleSelectedChanged(e) { 73 | e.preventDefault(); 74 | this.selected = parseInt(e.detail.value); 75 | this.updateQueryParams(); 76 | } 77 | 78 | updateQueryParams() { 79 | const params = new URLSearchParams(window.location.search); 80 | if (this.urlRewrite) params.set(`tabs_${this.id}`, String(this.selected)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /packages/tabs/src/ChameleonTabsStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonTabsStyle = css` 4 | :host { 5 | box-shadow: inset 0 -1px 0 0 rgba(26, 57, 96, 0.1); 6 | display: flex; 7 | justify-content: space-around; 8 | } 9 | 10 | ::slotted(chameleon-tab) { 11 | align-items: center; 12 | box-sizing: border-box; 13 | display: flex; 14 | flex-grow: 1; 15 | font-size: 1.125em; 16 | height: 65px; 17 | justify-content: center; 18 | padding: 8px 12px; 19 | color: var(--color-gray-light, #c4c7ca); 20 | } 21 | 22 | ::slotted(chameleon-tab:hover) { 23 | cursor: pointer; 24 | color: var(--color-secondary, #69c9b9); 25 | } 26 | 27 | ::slotted([active]) { 28 | border-bottom: solid 1px var(--color-secondary, #69c9b9); 29 | box-shadow: inset 0 -2px 0 0 var(--color-secondary, #69c9b9); 30 | color: var(--color-secondary, #69c9b9); 31 | } 32 | `; 33 | -------------------------------------------------------------------------------- /packages/textarea/__tests__/chameleon-textarea.test.js: -------------------------------------------------------------------------------- 1 | import "../chameleon-textarea.js"; 2 | import { litFixture, html, expect } from "@open-wc/testing"; 3 | import sinon from "sinon"; 4 | 5 | const fixture = html` `; 6 | 7 | describe("chameleon-textarea", () => { 8 | let element; 9 | 10 | beforeEach(async () => { 11 | element = await litFixture(fixture); 12 | }); 13 | 14 | it("renders", () => { 15 | expect(Boolean(element.shadowRoot)).to.equal(true); 16 | }); 17 | 18 | it("returns _el", () => { 19 | const el = element._el; 20 | expect(el.constructor.name).to.equal("HTMLTextAreaElement"); 21 | }); 22 | 23 | it("_el returns null if shadowRoot is null", () => { 24 | sinon.stub(element, "shadowRoot").get(() => null); 25 | 26 | expect(element._el).to.be.null; 27 | }); 28 | 29 | it("renders labelText", () => { 30 | element.label = "chameleon"; 31 | expect(element.labelText.constructor.name).to.equal("TemplateResult"); 32 | }); 33 | 34 | it("renders errorText", () => { 35 | element.validationMessage = "chameleon"; 36 | expect(element.errorText.constructor.name).to.equal("TemplateResult"); 37 | }); 38 | 39 | it("returns validity", () => { 40 | expect(element.validity.constructor.name).to.equal("ValidityState"); 41 | }); 42 | 43 | it("validity returns undefined if _el is null", () => { 44 | sinon.stub(element, "_el").get(() => null); 45 | 46 | expect(element.validity).to.be.undefined; 47 | }); 48 | 49 | it("willValidate returns a boolean", () => { 50 | expect(typeof element.willValidate).to.equal("boolean"); 51 | }); 52 | 53 | it("willValidate returns false if _el is null", () => { 54 | sinon.stub(element, "_el").get(() => null); 55 | 56 | expect(element.willValidate).to.be.false; 57 | }); 58 | 59 | it("checkValidity returns a boolean", () => { 60 | expect(typeof element.checkValidity()).to.equal("boolean"); 61 | }); 62 | 63 | it("checkValidity returns false if _el is null", () => { 64 | sinon.stub(element, "_el").get(() => null); 65 | 66 | expect(element.checkValidity()).to.be.false; 67 | }); 68 | 69 | it("invalid sets aria-invalid attribute", async () => { 70 | element.value = ""; 71 | element.invalid = true; 72 | await element.updateComplete; 73 | expect(element._el).to.have.attribute("aria-invalid"); 74 | }); 75 | 76 | it("_handleBlur calls checkValidity", () => { 77 | // TBH I'm not convinced this test is actually behaving expectedly... 78 | const checkValidity = sinon.spy(element, "checkValidity"); 79 | const handleBlur = sinon.spy(element, "_handleBlur"); 80 | 81 | element._handleBlur(); 82 | 83 | expect(checkValidity.calledImmediatelyAfter(handleBlur)); 84 | }); 85 | 86 | it("_handleInvalid sets validationMessage", () => { 87 | element._handleInvalid(); 88 | expect(element.validationMessage).to.equal(element._el.validationMessage); 89 | }); 90 | 91 | it("_handleInvalid returns an empty string if _el is null", () => { 92 | sinon.stub(element, "_el").get(() => null); 93 | element._handleInvalid(); 94 | 95 | expect(element.validationMessage).to.equal(""); 96 | }); 97 | 98 | it("handles input", () => { 99 | element._handleInput({ target: { value: "chameleon" } }); 100 | expect(element.value).to.equal("chameleon"); 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /packages/textarea/chameleon-textarea.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTextarea } from "./lib/ChameleonTextarea.js"; 2 | 3 | customElements.define("chameleon-textarea", ChameleonTextarea); 4 | -------------------------------------------------------------------------------- /packages/textarea/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonTextarea } from "./lib/ChameleonTextarea.js"; 2 | export { ChameleonTextareaStyle } from "./lib/ChameleonTextareaStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/textarea/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/textarea", 3 | "version": "2.0.1", 4 | "description": "Chameleon textarea", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/textarea#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-textarea.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | }, 31 | "gitHead": "0f8abecfe290971a220b969fc4d82fba4f6869ad" 32 | } 33 | -------------------------------------------------------------------------------- /packages/textarea/src/ChameleonTextareaStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonTextareaStyle = css` 4 | :host { 5 | display: inline-flex; 6 | flex-direction: column; 7 | font-family: var(--font-family, sans-serif); 8 | } 9 | 10 | textarea { 11 | border: 1px solid var(--color-gray-light, #c4c7ca); 12 | border-radius: var(--border-radius-input, 0.313rem); 13 | font-family: inherit; 14 | font-size: var(--font-size-input, 0.938rem); 15 | padding: var(--textarea-padding, 0.438rem 0.813rem); 16 | } 17 | 18 | textarea[nonresizeable] { 19 | resize: none; 20 | } 21 | 22 | label { 23 | color: var(--color-gray-darkest, #6c737a); 24 | font-size: var(--font-size-label, 0.875rem); 25 | margin-bottom: 10px; 26 | } 27 | 28 | .error { 29 | color: var(--color-error, #bc1c16); 30 | font-size: var(--font-size-label, 0.875rem); 31 | margin-top: 3px; 32 | } 33 | :host([invalid]) textarea, 34 | textarea.invalid { 35 | border-color: var(--color-error, #bc1c16); 36 | } 37 | `; 38 | -------------------------------------------------------------------------------- /packages/theme/README.md: -------------------------------------------------------------------------------- 1 | # Global Theme Variables 2 | 3 | ```js script 4 | export default { 5 | title: "Theming|Global", 6 | }; 7 | ``` 8 | 9 | ```css 10 | :host { 11 | --border-radius: 0.5rem; 12 | --border-radius-input: 0.313rem; 13 | --button-padding: 0.75rem 1.375rem; 14 | --input-padding: 0.625rem 0.5rem; 15 | --textarea-padding: 0.438rem 0.813rem; 16 | --select-padding: 0.438rem 0.5rem; 17 | --dialog-width: 18.75rem; 18 | 19 | --color-surface: #ffffff; 20 | --color-black: #252a33; 21 | --color-background: #f5f5f8; 22 | --color-primary: #2c6fb7; 23 | --color-primary-light: #679dea; 24 | --color-primary-dark: #004587; 25 | --color-secondary: #69c9b9; 26 | --color-secondary-light: #9cfceb; 27 | --color-secondary-dark: #349889; 28 | --color-gray-lightest: #e1e3e4; 29 | --color-gray-light: #c4c7ca; 30 | --color-gray-dark: #9fa4a8; 31 | --color-gray-darkest: #6c737a; 32 | --color-warning: #fcb61a; 33 | --color-warning-light: #fdd375; 34 | --color-warning-lightest: #fef0d1; 35 | --color-error: #bc1c16; 36 | --color-error-light: #fdd375; 37 | --color-error-lightest: #fef0d1; 38 | --color-success: #00870a; 39 | --color-success-light: #fdd375; 40 | --color-success-lightest: #fef0d1; 41 | --color-box-shadow: rgba(159, 164, 168, 0.6); 42 | 43 | --font-letter-spacing: 0.018rem; 44 | --font-size-paragraph-medium: 0.938rem; 45 | --font-size-subtitle: 0.938rem; 46 | --font-size-title: 1.4rem; 47 | --font-size-input: 0.938rem; 48 | --font-size-label: 0.875rem; 49 | --font-family: sans-serif; 50 | --font-size-table-header: 1rem; 51 | --font-size-table-content: 0.875rem; 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /packages/theme/base/index.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export default css` 4 | :host { 5 | --border-radius: 0.5rem; 6 | --border-radius-input: 0.313rem; 7 | --button-padding: 0.75rem 1.375rem; 8 | --input-padding: 0.625rem 0.5rem; 9 | --textarea-padding: 0.438rem 0.813rem; 10 | --select-padding: 0.438rem 0.5rem; 11 | --dialog-width: 18.75rem; 12 | 13 | --color-surface: #ffffff; 14 | --color-black: #252a33; 15 | --color-background: #f5f5f8; 16 | --color-primary: #2c6fb7; 17 | --color-primary-light: #679dea; 18 | --color-primary-dark: #004587; 19 | --color-secondary: #69c9b9; 20 | --color-secondary-light: #9cfceb; 21 | --color-secondary-dark: #349889; 22 | --color-gray-lightest: #e1e3e4; 23 | --color-gray-light: #c4c7ca; 24 | --color-gray-dark: #9fa4a8; 25 | --color-gray-darkest: #6c737a; 26 | --color-warning: #fcb61a; 27 | --color-warning-light: #fdd375; 28 | --color-warning-lightest: #fef0d1; 29 | --color-error: #bc1c16; 30 | --color-error-light: #fdd375; 31 | --color-error-lightest: #fef0d1; 32 | --color-success: #00870a; 33 | --color-success-light: #fdd375; 34 | --color-success-lightest: #fef0d1; 35 | --color-box-shadow: rgba(159, 164, 168, 0.6); 36 | 37 | --font-letter-spacing: 0.018rem; 38 | --font-size-paragraph-medium: 0.938rem; 39 | --font-size-subtitle: 0.938rem; 40 | --font-size-title: 1.4rem; 41 | --font-size-input: 0.938rem; 42 | --font-size-label: 0.875rem; 43 | --font-family: sans-serif; 44 | --font-size-table-header: 1rem; 45 | --font-size-table-content: 0.875rem; 46 | } 47 | `; 48 | -------------------------------------------------------------------------------- /packages/theme/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/theme", 3 | "version": "2.0.1", 4 | "description": "Chameleon design language", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/core#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "/lib/" 16 | ], 17 | "scripts": { 18 | "test": "echo \"Error: run tests from root\" && exit 1", 19 | "build": "babel base --out-dir lib --config-file ../../babel.config.json" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/MaritzSTL/chameleon/issues" 23 | }, 24 | "dependencies": { 25 | "lit-element": "^2.2.1" 26 | }, 27 | "publishConfig": { 28 | "access": "public" 29 | }, 30 | "gitHead": "903c637e2d1f3693b6c0b5fca5c1e6363ecb15c1" 31 | } 32 | -------------------------------------------------------------------------------- /packages/timezone/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Timezone 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-timezone.js"; 7 | 8 | export default { 9 | title: "Components|Form Elements/Timezone", 10 | component: "chameleon-timezone", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/docs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ------------------ | ------- | ---------------- | -------------------------------------------------------------------------------------------------------- | 20 | | `required` | Boolean | `false` | A Boolean which, if true, indicates that the timezone must have a value before the form can be submitted | 21 | | `invalid` | Boolean | `false` | Invalid boolean to allow validity access from higher level form errors | 22 | | `readonly` | Boolean | `false` | A Boolean attribute which, if true, indicates that the timezone cannot be edited | 23 | | `disabled` | Boolean | `false` | A Boolean attribute which is present if the timezone should be disabled | 24 | | `name` | String | `"cha-timezone"` | The timezone's form name | 25 | | `timezoneLabel` | String | `""` | The timezone's label | 26 | | `timezoneSubLabel` | String | `""` | The timezone's sub label | 27 | | `errors` | Array | `[]` | The skeleton's circle height | 28 | 29 | ## Examples 30 | 31 | ### Default 32 | 33 | ```js preview-story 34 | export const Default = () => { 35 | const timezoneLabel = text("Label", "Please select your Timezone"); 36 | const timezoneSubLabel = text("Sub Label", ""); 37 | const readonly = boolean("Read Only", false); 38 | const invalid = boolean("Invalid", false); 39 | const required = boolean("Required", false); 40 | const disabled = boolean("Disabled", false); 41 | 42 | return html` 43 | 51 | `; 52 | }; 53 | ``` 54 | 55 | ### Error State 56 | 57 | ```js preview-story 58 | export const ErrorState = () => html` 59 | 64 | `; 65 | ``` 66 | -------------------------------------------------------------------------------- /packages/timezone/__tests__/chameleon-timezone.test.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTimezone, ChameleonTimezoneStyle } from "../index.js"; 2 | import "../chameleon-timezone.js"; 3 | 4 | /** 5 | * TODO(ryuhhnn): 4/3/2020 - Commented these all out because it's causing a test 6 | * failure and don't have time to look into it right now 7 | */ 8 | // import { html, fixture, expect } from "@open-wc/testing"; 9 | 10 | // describe("chameleon-timezone", () => { 11 | // const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; 12 | // let element; 13 | 14 | // beforeEach(async () => { 15 | // element = await fixture( 16 | // html`` 17 | // ); 18 | // }); 19 | 20 | // it("should have tag name defined", () => { 21 | // expect(element.tagName.toLowerCase()).to.equal("chameleon-timezone"); 22 | // }); 23 | 24 | // describe("timezone()", () => { 25 | // it("should set timezone", () => { 26 | // element.timezone = timezone; 27 | // expect(element.timezone).to.equal(element._timezoneValue); 28 | // }); 29 | 30 | // it("should get timezone", () => { 31 | // expect(element.timezone).to.equal(element._timezoneValue); 32 | // }); 33 | 34 | // // TODO 35 | // xit("should default to local timezone if none is supplied", () => { 36 | // expect(element.timezone).to.equal(element.localTimeone); 37 | // }); 38 | // }); 39 | 40 | // describe("render()", () => { 41 | // it("should render shadowDom", () => { 42 | // expect(element).shadowDom.to.equalSnapshot(); 43 | // }); 44 | 45 | // it("should render lightDom", () => { 46 | // expect(element).lightDom.to.equal(``); 47 | // }); 48 | 49 | // /** 50 | // * Labels 51 | // */ 52 | 53 | // it("should render timezoneLabel", async () => { 54 | // element = await fixture( 55 | // html`` 56 | // ); 57 | // expect(element).shadowDom.to.equalSnapshot(); 58 | // }); 59 | 60 | // it("should render timeoneSubLabel", async () => { 61 | // element = await fixture( 62 | // html` 63 | // 64 | // ` 65 | // ); 66 | // expect(element).shadowDom.to.equalSnapshot(); 67 | // }); 68 | 69 | // it("should render errors", async () => { 70 | // element.errors = ["asdf"]; 71 | // expect( 72 | // element.shadowRoot.querySelector(".mdc-text-field-error-text") 73 | // ).to.not.equal(undefined); 74 | // }); 75 | // }); 76 | 77 | // describe("localTimezone()", () => { 78 | // it("should return the users's local timeZone", () => { 79 | // expect(element.timezone).to.equal( 80 | // Intl.DateTimeFormat().resolvedOptions().timeZone 81 | // ); 82 | // }); 83 | // }); 84 | 85 | // describe("handleInput()", () => { 86 | // it("should update timezone value", () => { 87 | // element.value = "US/Pacific"; 88 | // expect(element._timezoneValue).to.equal("US/Pacific"); 89 | // }); 90 | // }); 91 | // }); 92 | -------------------------------------------------------------------------------- /packages/timezone/chameleon-timezone.js: -------------------------------------------------------------------------------- 1 | import { ChameleonTimezone } from "./lib/ChameleonTimezone.js"; 2 | 3 | customElements.define("chameleon-timezone", ChameleonTimezone); 4 | -------------------------------------------------------------------------------- /packages/timezone/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonTimezone } from "./lib/ChameleonTimezone.js"; 2 | export { ChameleonTimezoneStyle } from "./lib/ChameleonTimezoneStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/timezone/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/timezone", 3 | "version": "2.0.1", 4 | "description": "Chameleon timezone", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/timezone#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-timezone.js", 16 | "/lib/", 17 | "/data/" 18 | ], 19 | "scripts": { 20 | "test": "echo \"Error: run tests from root\" && exit 1", 21 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/MaritzSTL/chameleon/issues" 25 | }, 26 | "dependencies": { 27 | "@chameleon-ds/select": "^2.0.1", 28 | "lit-element": "^2.2.1" 29 | }, 30 | "publishConfig": { 31 | "access": "public" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/timezone/src/ChameleonTimezoneStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonTimezoneStyle = css` 4 | :host([readonly]), 5 | :host([disabled]) { 6 | pointer-events: none; 7 | } 8 | 9 | :host([disabled]) * { 10 | background-color: #f5f5f8; 11 | } 12 | 13 | input { 14 | border: 1px solid #e8e8e8); 15 | border-radius: var(--border-radius-input, 5px); 16 | font-family: inherit; 17 | font-size: 16px; 18 | padding: var(--select-padding, 0.438rem 0.5rem); 19 | } 20 | 21 | .mdc-text-field-error-text { 22 | color: var(--color-error-light, #fef0d1); 23 | } 24 | 25 | .label { 26 | color: var(--color-gray-darkest, #6c737a); 27 | font-family: var(--font-family, sans-serif); 28 | font-size: var(--font-size-label, 0.875rem); 29 | display: grid; 30 | font-weight: 500; 31 | font-size: 14px; 32 | margin: 7px 0; 33 | } 34 | 35 | .datetime-inputs.invalid .label{ 36 | color: var(--color-error, #bc1c16); 37 | } 38 | 39 | @media screen and (max-width: 768px) { 40 | .inputSpacing { 41 | grid-template-columns: 1fr 1fr; 42 | grid-template-rows: 1fr 1fr; 43 | } 44 | } 45 | 46 | @media screen and (max-width: 375px) { 47 | .inputSpacing { 48 | grid-template-columns: 1fr; 49 | grid-template-rows: 1fr; 50 | } 51 | } 52 | `; 53 | -------------------------------------------------------------------------------- /packages/toast/README.md: -------------------------------------------------------------------------------- 1 | # Chameleon Toast 2 | 3 | ```js script 4 | import { html } from "@open-wc/demoing-storybook"; 5 | import { withKnobs, text, boolean } from "@open-wc/demoing-storybook"; 6 | import "./chameleon-toast.js"; 7 | 8 | export default { 9 | title: "Components|Overlays/Toast", 10 | component: "chameleon-toast", 11 | decorators: [withKnobs], 12 | options: { selectedPanel: "storybookjs/knobs/panel" }, 13 | }; 14 | ``` 15 | 16 | ## Properties 17 | 18 | | Property Name | Type(s) | Default Value | Description | 19 | | ----------------- | ------- | ------------- | -------------------------------------- | 20 | | `color` | String | `color` | The toast's color | 21 | | `showCloseable` | Boolean | `true` | Whether or not the toast can be closed | 22 | | `backgroundColor` | String | `null` | The toast's background color | 23 | 24 | ## Examples 25 | 26 | ### Default 27 | 28 | ```js preview-story 29 | export const Default = () => { 30 | const color = text("Color", ""); 31 | const backgroundColor = text("Background Color", ""); 32 | const showCloseable = boolean("Show", true); 33 | const imageUrl = text( 34 | "Image Url", 35 | "https://media.istockphoto.com/photos/chocolate-chip-cookie-isolated-picture-id517109442?k=6&m=517109442&s=612x612&w=0&h=NvQ5y8ENWZvpr84vEFWmxUgV2rCgtOGEsjJXa3IYsZ4=" 36 | ); 37 | const toastText = text( 38 | "Text", 39 | "This website uses cookies to remember you and improve your experience. By using our site, you accept our use of cookies." 40 | ); 41 | 42 | return html` 43 | 48 | ${toastText} 49 | 50 | 51 | `; 52 | }; 53 | ``` 54 | -------------------------------------------------------------------------------- /packages/toast/__tests__/chameleon-toast.test.js: -------------------------------------------------------------------------------- 1 | import { ChameleonToast, ChameleonToastStyle } from "../index.js"; 2 | import "../chameleon-toast.js"; 3 | import { litFixture, html, expect } from "@open-wc/testing"; 4 | import sinon from "sinon"; 5 | 6 | const fixture = html` `; 7 | 8 | describe("chameleon-toast", () => { 9 | let element; 10 | 11 | beforeEach(async () => { 12 | element = await litFixture(fixture); 13 | }); 14 | 15 | it("renders", async () => { 16 | expect(Boolean(element.shadowRoot)).to.equal(true); 17 | }); 18 | 19 | it("closes toast", () => { 20 | const dispatchEvent = sinon.spy(element, "dispatchEvent"); 21 | const showCloseable = element.showCloseable; 22 | 23 | element.closeToast(); 24 | 25 | expect(dispatchEvent).to.be.calledOnce; 26 | expect(element.showCloseable).to.not.equal(showCloseable); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/toast/chameleon-toast.js: -------------------------------------------------------------------------------- 1 | import { ChameleonToast } from "./lib/ChameleonToast.js"; 2 | 3 | customElements.define("chameleon-toast", ChameleonToast); 4 | -------------------------------------------------------------------------------- /packages/toast/index.js: -------------------------------------------------------------------------------- 1 | export { ChameleonToast } from "./lib/ChameleonToast.js"; 2 | export { ChameleonToastStyle } from "./lib/ChameleonToastStyle.js"; 3 | -------------------------------------------------------------------------------- /packages/toast/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@chameleon-ds/toast", 3 | "version": "2.0.1", 4 | "description": "Chameleon toast", 5 | "author": "Maritz Motivation Solutions, Inc.", 6 | "license": "MIT", 7 | "homepage": "https://github.com/MaritzSTL/chameleon/tree/master/packages/toast#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/MaritzSTL/chameleon.git" 11 | }, 12 | "main": "index.js", 13 | "module": "index.js", 14 | "files": [ 15 | "chameleon-toast.js", 16 | "/lib/" 17 | ], 18 | "scripts": { 19 | "test": "echo \"Error: run tests from root\" && exit 1", 20 | "build": "babel src --out-dir lib --config-file ../../babel.config.json" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/MaritzSTL/chameleon/issues" 24 | }, 25 | "dependencies": { 26 | "lit-element": "^2.2.1" 27 | }, 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/toast/src/ChameleonToast.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, property } from "lit-element"; 2 | import { ChameleonToastStyle } from "./ChameleonToastStyle.js"; 3 | 4 | export class ChameleonToast extends LitElement { 5 | /** 6 | * Lifecycle Methods 7 | */ 8 | updated(changedProperties) { 9 | if (changedProperties.has("backgroundColor")) { 10 | this.style.backgroundColor = this.backgroundColor ?? ""; 11 | } 12 | } 13 | 14 | /** 15 | * Properties 16 | */ 17 | // The font color of the toast 18 | @property({ type: String }) 19 | color = ""; 20 | 21 | // A Boolean which, if true, the toast is visible 22 | @property({ type: Boolean, reflect: true }) 23 | showCloseable = true; 24 | 25 | // The background color of the toast 26 | @property({ type: String }) 27 | backgroundColor = null; 28 | 29 | /** 30 | * Styles 31 | */ 32 | static styles = [ChameleonToastStyle]; 33 | 34 | /** 35 | * Template 36 | */ 37 | render() { 38 | return html` 39 |
40 | 41 | This website uses cookies to remember you and improve your experience. 42 | By using our site, you accept our use of cookies. 43 | 44 |
45 | 46 | x 47 | 48 | `; 49 | } 50 | 51 | closeToast() { 52 | this.showCloseable = false; 53 | 54 | this.dispatchEvent( 55 | new CustomEvent("close-toast", { 56 | bubbles: true, 57 | composed: true, 58 | }) 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/toast/src/ChameleonToastStyle.js: -------------------------------------------------------------------------------- 1 | import { css } from "lit-element"; 2 | 3 | export const ChameleonToastStyle = css` 4 | :host { 5 | align-items: center; 6 | animation: fadeout 0.5s forwards; 7 | background-color: var(--color-black, #252a33); 8 | border-radius: var(--border-radius, 0.5rem); 9 | bottom: 30px; 10 | box-sizing: border-box; 11 | left: 30px; 12 | color: var(--color-surface, #ffffff); 13 | display: flex; 14 | font-size: var(--font-size-label, 0.875rem); 15 | justify-content: space-between; 16 | line-height: 1.125rem; 17 | padding: 16px 24px; 18 | position: fixed; 19 | width: 456px; 20 | } 21 | 22 | :host([showcloseable]) { 23 | visibility: visible; 24 | animation: fadein 0.5s; 25 | } 26 | 27 | .toast-text { 28 | margin-right: 10px; 29 | } 30 | 31 | .close-icon { 32 | display: flex; 33 | } 34 | 35 | ::slotted([slot="close-icon"]) { 36 | cursor: pointer; 37 | height: 20px; 38 | width: 20px; 39 | border-radius: 50%; 40 | } 41 | 42 | @media only screen and (max-width: 768px) { 43 | :host { 44 | bottom: 10px; 45 | left: 10px; 46 | width: calc(100vw - 20px); 47 | } 48 | 49 | @keyframes fadein { 50 | from { 51 | bottom: 0; 52 | opacity: 0; 53 | } 54 | to { 55 | bottom: 10px; 56 | opacity: 1; 57 | } 58 | } 59 | 60 | @keyframes fadeout { 61 | from { 62 | bottom: 10px; 63 | opacity: 1; 64 | } 65 | to { 66 | bottom: 0; 67 | opacity: 0; 68 | } 69 | } 70 | } 71 | 72 | @keyframes fadein { 73 | from { 74 | bottom: 0; 75 | opacity: 0; 76 | } 77 | to { 78 | bottom: 30px; 79 | opacity: 1; 80 | } 81 | } 82 | 83 | @keyframes fadeout { 84 | from { 85 | bottom: 30px; 86 | opacity: 1; 87 | } 88 | to { 89 | bottom: 0; 90 | opacity: 0; 91 | } 92 | } 93 | `; 94 | -------------------------------------------------------------------------------- /scripts/linker.js: -------------------------------------------------------------------------------- 1 | // To run this script, install deno, 2 | // ensure you're in root, and: 3 | // deno run --allow-read linker.js 4 | 5 | const packageNames = async () => { 6 | const PACKAGE_DIR = "./packages"; 7 | 8 | const packages = await Deno.readDirSync(PACKAGE_DIR); 9 | const names = []; 10 | 11 | for (const entry of packages) { 12 | try { 13 | const rawPackage = Deno.readTextFileSync( 14 | `${PACKAGE_DIR}/${entry.name}/package.json` 15 | ); 16 | const packageJson = JSON.parse(rawPackage); 17 | names.push(packageJson.name); 18 | } catch (error) { 19 | // ignore dirs without package.json 20 | } 21 | } 22 | 23 | return names; 24 | }; 25 | 26 | const allNames = await packageNames(); 27 | 28 | console.log("In this directory, run:"); 29 | console.log(""); 30 | console.log(`\t npx lerna exec yarn link`); 31 | console.log(""); 32 | console.log("To use these in target directory, run:"); 33 | console.log(""); 34 | console.log(`\t yarn link ${allNames.join(" ")}`); 35 | console.log(""); 36 | console.log("To stop using these in target directory, run:"); 37 | console.log(""); 38 | console.log(`\t yarn unlink ${allNames.join(" ")}`); 39 | --------------------------------------------------------------------------------