@rolemodel/optics 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.eslintrc.json +14 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. package/.github/pull_request_template.md +30 -0
  5. package/.github/workflows/linting.yml +38 -0
  6. package/.github/workflows/publish-storybook.yml +26 -0
  7. package/.github/workflows/release-package.yml +33 -0
  8. package/.prettierignore +0 -0
  9. package/.prettierrc.json +8 -0
  10. package/.storybook/ModeSwitcher.jsx +98 -0
  11. package/.storybook/documentation.scss +65 -0
  12. package/.storybook/main.js +10 -0
  13. package/.storybook/manager.js +22 -0
  14. package/.storybook/preview.js +12 -0
  15. package/.storybook/rolemodelTheme.js +10 -0
  16. package/.stylelintrc.json +15 -0
  17. package/LICENSE +21 -0
  18. package/README.md +57 -0
  19. package/build_token_json.js +149 -0
  20. package/dist/css/optics.css +2586 -0
  21. package/dist/css/optics.css.map +1 -0
  22. package/dist/scss/addons/rails-modal-and-panel/index.scss +2 -0
  23. package/dist/scss/addons/rails-modal-and-panel/modal.scss +86 -0
  24. package/dist/scss/addons/rails-modal-and-panel/panel.scss +36 -0
  25. package/dist/scss/addons/tom-select.scss +77 -0
  26. package/dist/scss/components/alert.scss +158 -0
  27. package/dist/scss/components/badge.scss +80 -0
  28. package/dist/scss/components/button.scss +235 -0
  29. package/dist/scss/components/button_group.scss +35 -0
  30. package/dist/scss/components/card.scss +65 -0
  31. package/dist/scss/components/flash.scss +58 -0
  32. package/dist/scss/components/form.scss +178 -0
  33. package/dist/scss/components/icon.scss +109 -0
  34. package/dist/scss/components/index.scss +10 -0
  35. package/dist/scss/components/sidebar.scss +255 -0
  36. package/dist/scss/components/table.scss +132 -0
  37. package/dist/scss/core/base.scss +95 -0
  38. package/dist/scss/core/layout.scss +36 -0
  39. package/dist/scss/core/tokens/base_tokens.scss +251 -0
  40. package/dist/scss/core/tokens/dark_mode_tokens.scss +324 -0
  41. package/dist/scss/core/tokens/index.scss +3 -0
  42. package/dist/scss/core/tokens/scale_color_tokens.scss +303 -0
  43. package/dist/scss/core/utilities.scss +548 -0
  44. package/dist/scss/optics.scss +13 -0
  45. package/dist/scss/recipes/16six-sidebar.scss +97 -0
  46. package/dist/scss/recipes/domains-sidebar.scss +60 -0
  47. package/dist/tokens/tokens.json +391 -0
  48. package/package.json +80 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "root": true,
3
+ "extends": ["standard", "prettier"],
4
+ "rules": {
5
+ "no-unused-vars": [
6
+ "warn",
7
+ {
8
+ "argsIgnorePattern": "^_", // Allow unused arguments starting with an underscore
9
+ "varsIgnorePattern": "^_", // Allow unused variables starting with an underscore
10
+ "ignoreRestSiblings": true
11
+ }
12
+ ]
13
+ }
14
+ }
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+ ---
8
+
9
+ **Describe the bug**
10
+ A clear and concise description of what the bug is.
11
+
12
+ **To Reproduce**
13
+ Steps to reproduce the behavior:
14
+
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
+
28
+ - OS: [e.g. iOS]
29
+ - Browser [e.g. chrome, safari]
30
+ - Version [e.g. 22]
31
+
32
+ **Smartphone (please complete the following information):**
33
+
34
+ - Device: [e.g. iPhone6]
35
+ - OS: [e.g. iOS8.1]
36
+ - Browser [e.g. stock browser, safari]
37
+ - Version [e.g. 22]
38
+
39
+ **Additional context**
40
+ Add any other context about the problem here.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+ ---
8
+
9
+ **Is your feature request related to a problem? Please describe.**
10
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11
+
12
+ **Describe the solution you'd like**
13
+ A clear and concise description of what you want to happen.
14
+
15
+ **Describe alternatives you've considered**
16
+ A clear and concise description of any alternative solutions or features you've considered.
17
+
18
+ **Additional context**
19
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,30 @@
1
+ ## Task
2
+
3
+ [TR #XXX]()
4
+
5
+ ## Why?
6
+
7
+ Why were the changes needed? What issues were the changes addressing?
8
+ (Note: some changes may seem unrelated to the ticket, this is a great place to explain further.)
9
+
10
+ ## What Changed
11
+
12
+ What changed in this PR?
13
+
14
+ - [ ] Change 1
15
+ - [ ] Change 2
16
+ - [ ] ...
17
+
18
+ ## Sanity Check
19
+
20
+ - [ ] Have you updated any usage of changed tokens?
21
+ - [ ] Have you updated the docs with any component changes?
22
+ - [ ] Have you run linters?
23
+ - [ ] Have you run prettier?
24
+ - [ ] Have you tried building the css?
25
+ - [ ] Have you tried building storybook?
26
+ - [ ] Do you need to update the package version?
27
+
28
+ ## Screenshots
29
+
30
+ If any UI changes need to be shown off, please add screenshots here.
@@ -0,0 +1,38 @@
1
+ # This workflow will do a clean installation of node dependencies, cache/restore them, and run linting
2
+
3
+ name: Linting CI
4
+
5
+ on:
6
+ push:
7
+ branches: ['main']
8
+ pull_request:
9
+ branches: ['main']
10
+
11
+ jobs:
12
+ build:
13
+ name: Run linters and check build scripts
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Checkout repository
17
+ uses: actions/checkout@v3
18
+ - name: Use Node.js
19
+ uses: actions/setup-node@v3
20
+ with:
21
+ node-version: '16.x'
22
+ cache: 'npm'
23
+ - name: Install
24
+ run: npm install
25
+ - name: Run ESLint
26
+ run: npm run lint:js
27
+ - name: Run Stylelint
28
+ run: npm run lint:css
29
+ - name: Run Prettier
30
+ run: npm run prettier-check
31
+ - name: Build CSS
32
+ run: npm run build:css
33
+ - name: Build SCSS
34
+ run: npm run build:scss
35
+ - name: Build Tokens
36
+ run: npm run build:tokens
37
+ - name: Build Storybook
38
+ run: npm run build-storybook
@@ -0,0 +1,26 @@
1
+ name: Build and Deploy Storybook Documentation
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ jobs:
8
+ build-and-deploy:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - name: Checkout 🛎️
12
+ uses: actions/checkout@v3
13
+ with:
14
+ persist-credentials: false
15
+ - name: Install and Build 🔧
16
+ run: | # Install npm packages and build the Storybook files
17
+ npm install
18
+ npm run build-storybook
19
+ - name: Deploy 🚀
20
+ uses: JamesIves/github-pages-deploy-action@3.6.2
21
+ with:
22
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23
+ BRANCH: gh-pages # The branch the action should deploy to.
24
+ FOLDER: docs-build # The folder that the build-storybook script generates files.
25
+ CLEAN: true # Automatically remove deleted files from the deploy branch
26
+ TARGET_FOLDER: docs # The folder that we serve our Storybook files from
@@ -0,0 +1,33 @@
1
+ name: Deploy to NPM and GHP
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build-npm:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v3
12
+ - uses: actions/setup-node@v3
13
+ with:
14
+ node-version: '16.x'
15
+ registry-url: 'https://registry.npmjs.org'
16
+ - run: npm ci
17
+ - run: npm run build
18
+ - run: npm publish --access public
19
+ env:
20
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
21
+ build-gph:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v3
25
+ - uses: actions/setup-node@v3
26
+ with:
27
+ node-version: '16.x'
28
+ registry-url: https://npm.pkg.github.com/
29
+ - run: npm ci
30
+ - run: npm run build
31
+ - run: npm publish --access public
32
+ env:
33
+ NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "semi": false,
4
+ "singleQuote": true,
5
+ "trailingComma": "es5",
6
+ "printWidth": 120,
7
+ "arrowParens": "always"
8
+ }
@@ -0,0 +1,98 @@
1
+ import React, { useState } from 'react'
2
+ import { Button } from '@storybook/components'
3
+
4
+ import { useGlobals } from '@storybook/api'
5
+
6
+ // Destructuring like:
7
+ // const [globals, setGlobals] = useGlobals()
8
+ // or
9
+ // setGlobals({ ...globals, themeMode: mode })
10
+ // is not working so I had to work around it.
11
+
12
+ const ModeButton = ({ children, mode, currentThemeMode, updateThemeMode }) => {
13
+ const hoverState = useState(false)
14
+ const hover = hoverState[0]
15
+ const setHover = hoverState[1]
16
+
17
+ const backgroundColor = () => {
18
+ if (hover) {
19
+ return 'rgba(30, 167, 253, 0.12)'
20
+ }
21
+ return currentThemeMode === mode ? 'rgba(30,167,253,0.07)' : 'transparent'
22
+ }
23
+
24
+ const textColor = () => {
25
+ if (hover) {
26
+ return '#1EA7FD'
27
+ }
28
+ return currentThemeMode === mode ? '#1EA7FD' : '#999'
29
+ }
30
+
31
+ const buttonStyles = (mode) => {
32
+ return {
33
+ borderRadius: 0,
34
+ padding: 8,
35
+ color: textColor(),
36
+ backgroundColor: backgroundColor(),
37
+ }
38
+ }
39
+
40
+ return (
41
+ <Button
42
+ onMouseEnter={() => setHover(true)}
43
+ onMouseLeave={() => setHover(false)}
44
+ style={buttonStyles(mode)}
45
+ onClick={() => updateThemeMode(mode)}
46
+ title={`Set canvas to ${mode} mode`}
47
+ >
48
+ {children}
49
+ </Button>
50
+ )
51
+ }
52
+
53
+ const ModeSwitcher = () => {
54
+ const globalState = useGlobals()
55
+ const globals = globalState[0]
56
+ const setGlobals = globalState[1]
57
+
58
+ const setCanvasDocumentThemeMode = (mode) => {
59
+ const frame = document.getElementById('storybook-preview-iframe')
60
+
61
+ if (frame) {
62
+ const frameDocument = frame.contentWindow.document
63
+ frameDocument.children[0].dataset.themeMode = mode
64
+ }
65
+ }
66
+
67
+ const updateThemeMode = (mode) => {
68
+ setCanvasDocumentThemeMode(mode)
69
+ globals.themeMode = mode
70
+ setGlobals(globals)
71
+ }
72
+
73
+ if (!globals.themeMode) {
74
+ updateThemeMode('light')
75
+ }
76
+
77
+ const containerStyles = () => {
78
+ return {
79
+ border: '1px solid rgb(0 0 0 / 10%)',
80
+ margin: 5,
81
+ borderRadius: '3em',
82
+ overflow: 'hidden',
83
+ }
84
+ }
85
+
86
+ return (
87
+ <div style={containerStyles()}>
88
+ <ModeButton mode="light" currentThemeMode={globals.themeMode} updateThemeMode={updateThemeMode}>
89
+ Light
90
+ </ModeButton>
91
+ <ModeButton mode="dark" currentThemeMode={globals.themeMode} updateThemeMode={updateThemeMode}>
92
+ Dark
93
+ </ModeButton>
94
+ </div>
95
+ )
96
+ }
97
+
98
+ export default ModeSwitcher
@@ -0,0 +1,65 @@
1
+ @import './src/optics.scss';
2
+
3
+ @keyframes transitionDemo {
4
+ from {
5
+ background-color: var(--rm-color-white);
6
+ color: var(--rm-color-black);
7
+ }
8
+
9
+ to {
10
+ background-color: var(--rm-color-primary-base);
11
+ color: var(--rm-color-primary-on-base);
12
+ }
13
+ }
14
+
15
+ .transition-demo {
16
+ display: inline-block;
17
+
18
+ background-color: var(--rm-color-primary-base);
19
+ color: var(--rm-color-primary-on-base);
20
+
21
+ padding: var(--rm-space-medium);
22
+
23
+ animation-name: transitionDemo;
24
+ animation-duration: var(--rm-transition-input);
25
+ animation-iteration-count: 1;
26
+ }
27
+
28
+ .transition-demo--input {
29
+ animation-duration: var(--rm-transition-input);
30
+ }
31
+ .transition-demo--navigation {
32
+ animation-duration: var(--rm-transition-navigation);
33
+ }
34
+ .transition-demo--sidebar {
35
+ animation-duration: var(--rm-transition-sidebar);
36
+ }
37
+ .transition-demo--modal {
38
+ animation-duration: var(--rm-transition-modal);
39
+ }
40
+ .transition-demo--panel {
41
+ animation-duration: var(--rm-transition-panel);
42
+ }
43
+ .transition-demo--flash {
44
+ animation-duration: var(--rm-transition-flash);
45
+ }
46
+
47
+ .flash--demo {
48
+ position: relative;
49
+ animation: none;
50
+ top: 0;
51
+ right: 0;
52
+ }
53
+
54
+ @import './src/recipes/domains-sidebar.scss';
55
+ @import './src/recipes/16six-sidebar.scss';
56
+
57
+ .background-primary-plus-four {
58
+ background-color: var(--rm-color-primary-plus-four);
59
+ color: var(--rm-color-primary-on-plus-four);
60
+ }
61
+
62
+ .background-primary-plus-seven {
63
+ background-color: var(--rm-color-primary-plus-seven);
64
+ color: var(--rm-color-primary-on-plus-seven);
65
+ }
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
3
+ addons: [
4
+ '@storybook/addon-links',
5
+ '@storybook/addon-essentials',
6
+ '@storybook/addon-interactions',
7
+ '@storybook/preset-scss',
8
+ ],
9
+ framework: '@storybook/html',
10
+ }
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import { addons, types } from '@storybook/addons'
3
+ import rolemodelTheme from './rolemodelTheme'
4
+
5
+ import { useGlobals } from '@storybook/api' // For some reason this is needed here. ModeSwitcher won't work without it.
6
+
7
+ import ModeSwitcher from './ModeSwitcher'
8
+
9
+ addons.register('rolemodel/toolbar', () => {
10
+ addons.add('rolemodel-toolbar-addon/toolbar', {
11
+ title: 'Control to switch theme mode',
12
+ //👇 Sets the type of UI element in Storybook
13
+ type: types.TOOL,
14
+ //👇 Shows the Toolbar UI element if either the Canvas or Docs tab is active
15
+ match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
16
+ render: () => <ModeSwitcher />,
17
+ })
18
+ })
19
+
20
+ addons.setConfig({
21
+ theme: rolemodelTheme,
22
+ })
@@ -0,0 +1,12 @@
1
+ export const parameters = {
2
+ actions: { argTypesRegex: '^on[A-Z].*' },
3
+ controls: {
4
+ matchers: {
5
+ color: /(background|color)$/i,
6
+ date: /Date$/,
7
+ },
8
+ },
9
+ }
10
+
11
+ import '!style-loader!css-loader!sass-loader!../src/optics.scss'
12
+ import '!style-loader!css-loader!sass-loader!./documentation.scss'
@@ -0,0 +1,10 @@
1
+ import { create } from '@storybook/theming'
2
+
3
+ export default create({
4
+ base: 'light',
5
+ brandTitle: 'Optics, a RoleModel Design System',
6
+ brandUrl: 'https://docs.optics.rolemodel.design/',
7
+ brandImage:
8
+ 'https://rolemodelsoftware.com/assets/rolemodel-logo--blue-5b7cee4303f5b115050586117bad8960640884812d1d51ee4b58817598c896da.svg',
9
+ brandTarget: '_self',
10
+ })
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": ["stylelint-config-standard-scss", "stylelint-config-idiomatic-order", "stylelint-config-prettier-scss"],
3
+ "plugins": ["stylelint-scss", "stylelint-prettier"],
4
+ "overrides": [
5
+ {
6
+ "files": ["**/*.scss"],
7
+ "customSyntax": "postcss-scss"
8
+ }
9
+ ],
10
+ "rules": {
11
+ "prettier/prettier": true,
12
+ "custom-property-pattern": ["(?<=rm-)", { "message": "CSS variables should be prefixed with rm-" }],
13
+ "selector-class-pattern": null
14
+ }
15
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 RoleModel Software
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.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Optics, a RoleModel Design System
2
+
3
+ [![Linting CI](https://github.com/RoleModel/optics/actions/workflows/linting.yml/badge.svg)](https://github.com/RoleModel/optics/actions/workflows/linting.yml)
4
+
5
+ Optics is an scss package that provides base styles and components that can be integrated and customized in a variety of projects.
6
+
7
+ ## Installation
8
+
9
+ ### NPM
10
+
11
+ ```sh
12
+ npm install @rolemodel/optics
13
+ ```
14
+
15
+ ### Yarn
16
+
17
+ ```sh
18
+ yarn add @rolemodel/optics
19
+ ```
20
+
21
+ ### Import
22
+
23
+ If you are using webpack to compile, you can add this import to the top of your root level `scss` file.
24
+
25
+ ```scss
26
+ @import '@rolemodel/optics';
27
+ ```
28
+
29
+ If you are using a different compiler such as Dart Sass, you may need to reference the scss file directly.
30
+
31
+ ```scss
32
+ @import '@rolemodel/optics/dist/scss/optics';
33
+ ```
34
+
35
+ ## Documentation
36
+
37
+ We use [Storybook](https://storybook.js.org/docs/html/get-started/introduction) as a way to provide informative and interactive documentation.
38
+
39
+ It can be found here [Optics Documentation](https://docs.optics.rolemodel.design/)
40
+
41
+ ## Tokens
42
+
43
+ Tokens are defined in `src/core/tokens`
44
+
45
+ - All core tokens are defined in `src/core/tokens/base_tokens.scss`
46
+ - Basic color tokens are defined in `src/core/tokens/example_color_tokens.scss`
47
+ - Color scale tokens are defined in `src/core/tokens/scale_color_tokens.scss`
48
+ - Alert color tokens are defined in `src/core/tokens/alert_color_tokens.scss`
49
+ - Dark mode tokens are defined in `src/core/tokens/dark_mode_tokens.scss`
50
+
51
+ There are also a few component specific tokens that are defined in their respective component file, but those are not indented to be global or used outside of that file.
52
+
53
+ There is a JSON file in `docs/token_structure.json` that lists all the current tokens in one place and shows how the names indicate organization.
54
+
55
+ ## License
56
+
57
+ [MIT](LICENSE)
@@ -0,0 +1,149 @@
1
+ const fs = require('fs')
2
+ const path = require('node:path')
3
+
4
+ function isHyphenated(keys, length = 2) {
5
+ return HYPHENATED_WORDS.concat(HYPHENATED_LUMINOSITIES).includes(keys.slice(0, length).join('-'))
6
+ }
7
+
8
+ const HYPHENATED_WORDS = [
9
+ 'z-index',
10
+ 'neutral-variant',
11
+ 'on-background',
12
+ 'line-height',
13
+ 'letter-spacing',
14
+ 'scale-unit',
15
+ 'input-height',
16
+ 'width-large',
17
+ 'width-x-large',
18
+ 'card-outline',
19
+ 'x-small',
20
+ '2x-small',
21
+ '3x-small',
22
+ '4x-small',
23
+ '5x-small',
24
+ 'x-large',
25
+ '2x-large',
26
+ '3x-large',
27
+ '4x-large',
28
+ '5x-large',
29
+ 'extra-light',
30
+ 'extra-bold',
31
+ 'semi-bold',
32
+ 'dialog-backdrop',
33
+ 'dialog-content',
34
+ 'alert-group',
35
+ 'on-minus-one',
36
+ 'on-minus-two',
37
+ 'on-minus-three',
38
+ 'on-minus-four',
39
+ 'on-minus-five',
40
+ 'on-minus-six',
41
+ 'on-minus-seven',
42
+ 'on-minus-eight',
43
+ 'on-minus-max',
44
+ 'on-plus-one',
45
+ 'on-plus-two',
46
+ 'on-plus-three',
47
+ 'on-plus-four',
48
+ 'on-plus-five',
49
+ 'on-plus-six',
50
+ 'on-plus-seven',
51
+ 'on-plus-eight',
52
+ 'on-plus-max',
53
+ 'minus-one',
54
+ 'minus-two',
55
+ 'minus-three',
56
+ 'minus-four',
57
+ 'minus-five',
58
+ 'minus-six',
59
+ 'minus-seven',
60
+ 'minus-eight',
61
+ 'minus-max',
62
+ 'plus-one',
63
+ 'plus-two',
64
+ 'plus-three',
65
+ 'plus-four',
66
+ 'plus-five',
67
+ 'plus-six',
68
+ 'plus-seven',
69
+ 'plus-eight',
70
+ 'plus-max',
71
+ 'on-base',
72
+ ]
73
+
74
+ // This is used in the isHyphenated method so that any key of luminosity-x returns true.
75
+ const HYPHENATED_LUMINOSITIES = [...Array(101).keys()].map((luminosity) => `luminosity-${luminosity}`)
76
+
77
+ function splitKey(key) {
78
+ let keys = key.slice(2).split('-')
79
+ return keys
80
+ }
81
+
82
+ function addToJson(keys, data, value) {
83
+ let currentKey, remainingKeys
84
+
85
+ if (isHyphenated(keys, 2)) {
86
+ ;[currentKey, remainingKeys] = [keys.slice(0, 2).join('-'), keys.slice(2)]
87
+ } else if (isHyphenated(keys, 3)) {
88
+ ;[currentKey, remainingKeys] = [keys.join('-'), keys.slice(3)]
89
+ } else {
90
+ ;[currentKey, ...remainingKeys] = keys
91
+ }
92
+
93
+ data[currentKey] = data[currentKey] ?? {}
94
+
95
+ switch (remainingKeys.length) {
96
+ case 0:
97
+ data[currentKey] = value
98
+ break
99
+ case 1:
100
+ data[currentKey][remainingKeys[0]] = value
101
+ break
102
+ default:
103
+ data[currentKey] = addToJson(remainingKeys, data[currentKey], value)
104
+ break
105
+ }
106
+
107
+ return data
108
+ }
109
+
110
+ try {
111
+ const arguments = {}
112
+ process.argv.forEach((argument) => {
113
+ const values = argument.slice(2).split('=')
114
+ if (values.length === 2) {
115
+ arguments[values[0]] = values[1]
116
+ }
117
+ })
118
+
119
+ const source = arguments['source'] || 'src/core/tokens'
120
+ const output = arguments['output'] || './dist/tokens'
121
+ const outputPath = path.dirname(output)
122
+ const outputFile = path.basename(output)
123
+
124
+ if (!fs.existsSync(outputPath)) {
125
+ fs.mkdirSync(outputPath, { recursive: true })
126
+ }
127
+
128
+ fs.readdir(source, { withFileTypes: true }, (_errors, files) => {
129
+ let variables = {}
130
+ files
131
+ .filter(
132
+ (directoryEntry) =>
133
+ directoryEntry.isFile() &&
134
+ directoryEntry.name !== 'dark_mode_tokens.scss' &&
135
+ directoryEntry.name !== 'index.scss'
136
+ )
137
+ .forEach((directoryEntry) => {
138
+ const fileContents = fs.readFileSync(`${source}/${directoryEntry.name}`)
139
+ const matches = fileContents.toString().match(/^\s*--.*?(?=;)/gm)
140
+ matches.forEach((match) => {
141
+ const [key, value] = match.split(':')
142
+ variables = addToJson(splitKey(key.trim()), variables, value.trim())
143
+ })
144
+ })
145
+ fs.writeFileSync(`${outputPath}/${outputFile}`, JSON.stringify(variables, null, '\t'))
146
+ })
147
+ } catch (err) {
148
+ console.log(err)
149
+ }