├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .storybook
├── main.js
└── preview.js
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FOLO-sm.png
├── FOLO.png
├── LICENSE.md
├── README.md
├── babel.config.js
├── jest.config.js
├── lerna.json
├── package.json
├── packages
├── auto-position
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.md
│ ├── babel.config.js
│ ├── package.json
│ ├── src
│ │ ├── AutoPositionCell.js
│ │ └── index.js
│ └── test
│ │ └── AutoPositionCell.test.js
├── folo-forms
│ ├── LICENSE
│ ├── README.md
│ ├── babel.config.js
│ ├── foloForms-demo.gif
│ ├── package.json
│ ├── src
│ │ └── index.js
│ └── stories-legacy
│ │ ├── README.md
│ │ ├── _directories.js
│ │ ├── mainBasic.stories.js
│ │ └── mainCustom.stories.js
├── folo-layout
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.md
│ ├── babel.config.js
│ ├── foloLayout-demo.gif
│ ├── package.json
│ ├── src
│ │ ├── components
│ │ │ ├── Grid.js
│ │ │ └── GridItem.js
│ │ ├── constants.js
│ │ ├── index.js
│ │ ├── positionStore.js
│ │ └── stories
│ │ │ ├── Implicit.stories.js
│ │ │ ├── examples
│ │ │ ├── ExplicitGrid.js
│ │ │ └── ImplicitGrid.js
│ │ │ └── explicit.stories.js
│ └── test
│ │ ├── Grid.test.js
│ │ ├── GridItem.test.js
│ │ └── __snapshots__
│ │ ├── Grid.test.js.snap
│ │ └── GridItem.test.js.snap
├── folo-store
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.MD
│ ├── babel.config.js
│ ├── package.json
│ ├── src
│ │ ├── Registry.ts
│ │ └── index.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── subscribe.test.js.snap
│ │ │ └── updater.test.js.snap
│ │ ├── subscribe.test.js
│ │ └── updater.test.js
│ └── tsconfig.json
├── folo-utils
│ ├── LICENSE.md
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── index.js
│ │ └── utils.js
├── folo-values
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.md
│ ├── babel.config.js
│ ├── examples
│ │ ├── AddressForm.js
│ │ ├── BasicForm.js
│ │ └── GroupToggle.js
│ ├── foloValues-demo.gif
│ ├── package.json
│ ├── src
│ │ ├── components
│ │ │ ├── Core.js
│ │ │ ├── Field.js
│ │ │ └── Form.js
│ │ ├── constants.js
│ │ ├── index.js
│ │ ├── utils
│ │ │ └── cellRecognizer.js
│ │ └── valuesStore.js
│ ├── stories
│ │ ├── Field.stories.js
│ │ ├── FormsSubmit.stories.js
│ │ └── FormsToggle.stories.js
│ └── test
│ │ ├── Field.test.js
│ │ ├── cellRecognizer.test.js
│ │ └── setupTests.js
└── folo-withcontext
│ ├── LICENSE.md
│ ├── README.md
│ ├── package.json
│ ├── src
│ ├── index.js
│ └── withcontext.jsx
│ └── test
│ └── withContext.test.jsx
├── scripts
├── babel-preset-folo-dev
│ ├── package.json
│ └── src
│ │ ├── babel.config.js
│ │ └── index.js
├── eslint-config-folo-react
│ ├── config.eslintrc.js
│ ├── index.js
│ └── package.json
├── eslint-config-folo-ts
│ ├── config.eslintrc.js
│ ├── index.js
│ └── package.json
└── eslint-config-folo
│ ├── package.json
│ └── src
│ ├── config.eslintrc.js
│ └── index.js
├── tsconfig.base.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | [{*.cjs, *.html, *.js, *.json, *.jsx, *.mjs, *.rjson, *.ts}]
2 | end_of_line = lf
3 | trim_trailing_whitespace = true
4 | insert_final_newline = true
5 | charset = utf-8
6 | indent_style = tab
7 | indent_size = 2
8 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | lib/
4 | draft/
5 | pubic/
6 | .cache/
7 | coverage/
8 | packages/*/dist
9 | stories-legacy
10 | folo-withcontext
11 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint-config-folo"],
3 | };
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | node_modules
3 | coverage
4 | dist
5 | lib
6 | _gh-pages
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: [
3 | "../packages/folo-values/stories/*.stories.@(js|jsx|ts|tsx)",
4 | "../packages/folo-layout/src/stories/*.stories.@(js|jsx|ts|tsx)",
5 | ],
6 | addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
7 | };
8 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 |
2 | export const parameters = {
3 | actions: { argTypesRegex: "^on[A-Z].*" },
4 | }
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at mitchell@hamil.town. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 |
3 | - [Node.js](https://nodejs.org/en/) >= v10 must be installed.
4 | - [Yarn](https://classic.yarnpkg.com/en/docs/install)
5 |
6 | ## Installation
7 |
8 | - Run `yarn` in the repository's root directory to install everything you need
9 | for development.
10 | - Run `yarn build` in the root directory to build the modules.
11 |
12 | ## Running Tests
13 |
14 | - `yarn test` to run the tests in each package available in workspace.
15 |
16 | ## Dealing with packages
17 |
18 | - Use `yarn workspace` followed by Folo package name in `package.json`.
19 | So, If you deal with `folo-layout` for example you can use:
20 |
21 | `yarn workspace @folo/layout add -D dotenv`
22 |
23 | ## Documentation
24 |
25 | - Run above installation steps and then
26 | - Run `yarn storybook` runs story for each modules.
27 |
--------------------------------------------------------------------------------
/FOLO-sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jalal246/folo/f9d5577f0e9e86bbbf5461a22041f583222d986b/FOLO-sm.png
--------------------------------------------------------------------------------
/FOLO.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jalal246/folo/f9d5577f0e9e86bbbf5461a22041f583222d986b/FOLO.png
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
6 | Project designed and being developed to deal with forms
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ## Packages Overview
25 |
26 | - [**@folo/store** ](https://github.com/jalal246/folo/tree/master/packages/folo-store) JS Store Holds & Helps Controlling Data In Forms.
27 | - [**@folo/values**](https://github.com/jalal246/folo/tree/master/packages/folo-values)
28 | React Data Form components
29 | - [**@folo/layout**](https://github.com/jalal246/folo/tree/master/packages/folo-layout)
30 | CSS Grid React components
31 | - [**@folo/forms**](https://github.com/jalal246/folo/tree/master/packages/folo-forms)
32 | Full package combined of `@folo/layout` & `@folo/values` for React
33 |
34 | ## Installation
35 |
36 | Run locally:
37 |
38 | - `git clone https://github.com/jalal246/folo.git`
39 | - `yarn`
40 | - `yarn build`
41 | - `yarn storybook`
42 | - Go to http://localhost:6006/
43 |
44 | ## Contribution
45 |
46 | Need some company in this repo. PRs welcome! :point_right: [Contribute](Contribution.md) :blue_heart:
47 |
48 | ## License
49 |
50 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/LICENSE)
51 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ["@babel/preset-env", { targets: { node: "current" } }],
4 | ["@babel/preset-typescript"],
5 | ["@babel/preset-react"],
6 | ],
7 | };
8 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * For a detailed explanation regarding each configuration property, visit:
3 | * https://jestjs.io/docs/en/configuration.html
4 | */
5 |
6 | module.exports = {
7 | // All imported modules in your tests should be mocked automatically
8 | // automock: false,
9 |
10 | // Stop running tests after `n` failures
11 | // bail: 0,
12 |
13 | // The directory where Jest should store its cached dependency information
14 | // cacheDirectory: "C:\\Users\\jalal\\AppData\\Local\\Temp\\jest",
15 |
16 | // Automatically clear mock calls and instances between every test
17 | clearMocks: true,
18 |
19 | // Indicates whether the coverage information should be collected while executing the test
20 | // collectCoverage: false,
21 |
22 | // An array of glob patterns indicating a set of files for which coverage information should be collected
23 | // collectCoverageFrom: undefined,
24 |
25 | // The directory where Jest should output its coverage files
26 | coverageDirectory: "coverage",
27 |
28 | // An array of regexp pattern strings used to skip coverage collection
29 | // coveragePathIgnorePatterns: [
30 | // "\\\\node_modules\\\\"
31 | // ],
32 |
33 | // Indicates which provider should be used to instrument code for coverage
34 | // coverageProvider: "babel",
35 |
36 | // A list of reporter names that Jest uses when writing coverage reports
37 | // coverageReporters: [
38 | // "json",
39 | // "text",
40 | // "lcov",
41 | // "clover"
42 | // ],
43 |
44 | // An object that configures minimum threshold enforcement for coverage results
45 | // coverageThreshold: undefined,
46 |
47 | // A path to a custom dependency extractor
48 | // dependencyExtractor: undefined,
49 |
50 | // Make calling deprecated APIs throw helpful error messages
51 | // errorOnDeprecated: false,
52 |
53 | // Force coverage collection from ignored files using an array of glob patterns
54 | // forceCoverageMatch: [],
55 |
56 | // A path to a module which exports an async function that is triggered once before all test suites
57 | // globalSetup: undefined,
58 |
59 | // A path to a module which exports an async function that is triggered once after all test suites
60 | // globalTeardown: undefined,
61 |
62 | // A set of global variables that need to be available in all test environments
63 | // globals: {},
64 |
65 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
66 | // maxWorkers: "50%",
67 |
68 | // An array of directory names to be searched recursively up from the requiring module's location
69 | // moduleDirectories: [
70 | // "node_modules"
71 | // ],
72 |
73 | // An array of file extensions your modules use
74 | // moduleFileExtensions: [
75 | // "js",
76 | // "json",
77 | // "jsx",
78 | // "ts",
79 | // "tsx",
80 | // "node"
81 | // ],
82 |
83 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
84 | // moduleNameMapper: {},
85 |
86 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
87 | modulePathIgnorePatterns: ["folo-withcontext"],
88 |
89 | // Activates notifications for test results
90 | // notify: false,
91 |
92 | // An enum that specifies notification mode. Requires { notify: true }
93 | // notifyMode: "failure-change",
94 |
95 | // A preset that is used as a base for Jest's configuration
96 | // preset: undefined,
97 |
98 | // Run tests from one or more projects
99 | // projects: undefined,
100 |
101 | // Use this configuration option to add custom reporters to Jest
102 | // reporters: undefined,
103 |
104 | // Automatically reset mock state between every test
105 | // resetMocks: false,
106 |
107 | // Reset the module registry before running each individual test
108 | // resetModules: false,
109 |
110 | // A path to a custom resolver
111 | // resolver: undefined,
112 |
113 | // Automatically restore mock state between every test
114 | // restoreMocks: false,
115 |
116 | // The root directory that Jest should scan for tests and modules within
117 | // rootDir: undefined,
118 |
119 | // A list of paths to directories that Jest should use to search for files in
120 | // roots: [
121 | // ""
122 | // ],
123 |
124 | // Allows you to use a custom runner instead of Jest's default test runner
125 | // runner: "jest-runner",
126 |
127 | // The paths to modules that run some code to configure or set up the testing environment before each test
128 | // setupFiles: [],
129 |
130 | // A list of paths to modules that run some code to configure or set up the testing framework before each test
131 | // setupFilesAfterEnv: [],
132 |
133 | // The number of seconds after which a test is considered as slow and reported as such in the results.
134 | // slowTestThreshold: 5,
135 |
136 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing
137 | // snapshotSerializers: [],
138 |
139 | // The test environment that will be used for testing
140 | // testEnvironment: "jest-environment-jsdom",
141 |
142 | // Options that will be passed to the testEnvironment
143 | // testEnvironmentOptions: {},
144 |
145 | // Adds a location field to test results
146 | // testLocationInResults: false,
147 |
148 | // The glob patterns Jest uses to detect test files
149 | // testMatch: [
150 | // "**/__tests__/**/*.[jt]s?(x)",
151 | // "**/?(*.)+(spec|test).[tj]s?(x)"
152 | // ],
153 |
154 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
155 | // testPathIgnorePatterns: [
156 | // "\\\\node_modules\\\\"
157 | // ],
158 |
159 | // The regexp pattern or array of patterns that Jest uses to detect test files
160 | // testRegex: [],
161 |
162 | // This option allows the use of a custom results processor
163 | // testResultsProcessor: undefined,
164 |
165 | // This option allows use of a custom test runner
166 | // testRunner: "jasmine2",
167 |
168 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
169 | // testURL: "http://localhost",
170 |
171 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
172 | // timers: "real",
173 |
174 | // A map from regular expressions to paths to transformers
175 | // transform: undefined,
176 |
177 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
178 | // transformIgnorePatterns: [
179 | // "\\\\node_modules\\\\",
180 | // "\\.pnp\\.[^\\\\]+$"
181 | // ],
182 |
183 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
184 | // unmockedModulePathPatterns: undefined,
185 |
186 | // Indicates whether each individual test should be reported during the run
187 | // verbose: undefined,
188 |
189 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
190 | // watchPathIgnorePatterns: [],
191 |
192 | // Whether to use watchman for file crawling
193 | // watchman: true,
194 | };
195 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "independent",
3 | "npmClient": "yarn",
4 | "packages": [
5 | "packages/auto-position",
6 | "packages/folo-store",
7 | "packages/folo-values",
8 | "packages/folo-layout",
9 | "packages/folo-forms",
10 | "packages/folo-utils"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "folo",
3 | "private": true,
4 | "workspaces": [
5 | "packages/**",
6 | "scripts/**"
7 | ],
8 | "repository": "https://github.com/jalal246/folo",
9 | "author": "Jalal Maskoun jimmy002020@gmail.com>",
10 | "license": "MIT",
11 | "scripts": {
12 | "test": "jest",
13 | "build": "lerna run build",
14 | "prepublish": "yarn build",
15 | "publish": "lerna publish",
16 | "storybook": "start-storybook -p 6006",
17 | "gh-pages:clean": "rimraf _gh-pages",
18 | "gh-pages:build": "build-storybook -c .storybook -o _gh-pages",
19 | "gh-pages:publish": "gh-pages -d _gh-pages",
20 | "gh-pages": "yarn gh-pages:clean && yarn gh-pages:build && yarn gh-pages:publish"
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7.12.10",
24 | "@babel/preset-env": "^7.12.11",
25 | "@babel/preset-react": "^7.12.10",
26 | "@babel/preset-typescript": "^7.12.7",
27 | "@storybook/addon-actions": "^6.1.11",
28 | "@storybook/addon-essentials": "^6.1.11",
29 | "@storybook/addon-links": "^6.1.11",
30 | "@storybook/react": "^6.1.11",
31 | "@testing-library/jest-dom": "^5.11.6",
32 | "@testing-library/react": "^11.2.2",
33 | "@testing-library/user-event": "^13.1.8",
34 | "babel-jest": "^26.6.3",
35 | "babel-loader": "^8.2.2",
36 | "gh-pages": "^3.1.0",
37 | "jest": "^26.6.3",
38 | "lerna": "^3.22.1",
39 | "react": "^17.0.1",
40 | "react-dom": "^17.0.1",
41 | "rimraf": "^3.0.2",
42 | "typescript": "^4.1.3"
43 | },
44 | "dependencies": {
45 | "builderz": "0.11.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/auto-position/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint-config-folo"],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/auto-position/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 20120-20201 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/auto-position/README.md:
--------------------------------------------------------------------------------
1 | // TODO
2 |
--------------------------------------------------------------------------------
/packages/auto-position/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [["@babel/preset-env"]],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/auto-position/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/auto-position",
3 | "version": "0.1.2",
4 | "source": "src/index.js",
5 | "main": "dist/autoPosition.min.cjs.js",
6 | "umd:main": "dist/autoPosition.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "build": "builderz --output=autoPosition"
12 | },
13 | "homepage": "https://github.com/jalal246/folo/tree/master/packages/auto-position",
14 | "repository": "https://github.com/jalal246/folo",
15 | "files": [
16 | "src",
17 | "dist",
18 | "LICENSE"
19 | ],
20 | "keywords": [
21 | "@folo",
22 | "@folo/auto-position",
23 | "@folo/forms",
24 | "@folo/layout",
25 | "@folo/store",
26 | "@folo/utils",
27 | "@folo/values",
28 | "@folo/withcontext",
29 | "dflex",
30 | "react",
31 | "react-component",
32 | "css-grid",
33 | "css-layout",
34 | "form-builder-api",
35 | "dynamic-forms"
36 | ],
37 | "publishConfig": {
38 | "registry": "https://registry.npmjs.org/",
39 | "access": "public"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/auto-position/src/AutoPositionCell.js:
--------------------------------------------------------------------------------
1 | class AutoPositionCell {
2 | constructor() {
3 | // store cells number according to its name
4 | this.cellPositions = {};
5 |
6 | this.biggestRowItem = 0;
7 | }
8 |
9 | /**
10 | * Auto set the row number
11 | * If we don't have row then take the highest value
12 | * depending on biggestRowItem which updated with each grid item
13 | * Otherwise set the row do you have and update biggestRowItem
14 | *
15 | * This helps to assign position value according to highest value
16 | * If we start from 10, the next will be 11 and so on.
17 | *
18 | * @param {object} GridItem - GridItem that should be register and calculated
19 | * @param {string} GridItem.key unique key generated in GridItem
20 | * @param {number} GridItem.row
21 | * @param {number} GridItem.toRow
22 | * @return {number} row position
23 | */
24 | autoPosition({ key, row, toRow }) {
25 | const parseRow = parseInt(row, 10);
26 | const parseToRow = parseInt(toRow, 10);
27 |
28 | if (parseToRow && parseRow) {
29 | this.cellPositions[key] = parseRow;
30 |
31 | const bigger = parseToRow > parseRow ? parseToRow : parseRow;
32 | if (bigger > this.biggestRowItem) {
33 | this.biggestRowItem = bigger;
34 | }
35 | } else if (parseRow) {
36 | this.cellPositions[key] = parseRow;
37 |
38 | if (parseRow > this.biggestRowItem) {
39 | this.biggestRowItem = parseRow;
40 | }
41 | } else {
42 | this.biggestRowItem += 1;
43 | this.cellPositions[key] = this.biggestRowItem;
44 |
45 | if (parseToRow > this.biggestRowItem) {
46 | this.biggestRowItem = parseToRow;
47 | }
48 | }
49 |
50 | return this.cellPositions[key];
51 | }
52 | }
53 |
54 | export default AutoPositionCell;
55 |
--------------------------------------------------------------------------------
/packages/auto-position/src/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./AutoPositionCell";
2 |
--------------------------------------------------------------------------------
/packages/auto-position/test/AutoPositionCell.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable operator-assignment */
2 | import AutoPositionCell from "../src";
3 |
4 | const autoPositionTest = new AutoPositionCell();
5 |
6 | const key = () => new Date().getTime();
7 |
8 | let POSITION;
9 |
10 | let EXPECTED_BIGGEST_ROW;
11 |
12 | let CELL_1;
13 | let EXPECTED_ROW_1;
14 |
15 | let CELL_2;
16 | let EXPECTED_ROW_2;
17 |
18 | let CELL_3;
19 | let EXPECTED_ROW_3;
20 |
21 | let CELL_4;
22 | let EXPECTED_ROW_4;
23 |
24 | let CELL_5;
25 | let EXPECTED_ROW_5;
26 |
27 | let CELL_6;
28 | let EXPECTED_ROW_6;
29 |
30 | let CELL_7;
31 | let EXPECTED_ROW_7;
32 |
33 | let CELL_8;
34 | let EXPECTED_ROW_8;
35 |
36 | let CELL_9;
37 | let EXPECTED_ROW_9;
38 |
39 | let CELL_10;
40 | let EXPECTED_ROW_10;
41 |
42 | describe("Testing AutoPositionCell Algorithm", () => {
43 | it("Works for known row", () => {
44 | CELL_1 = {
45 | key,
46 | row: 10,
47 | toRow: 0,
48 | };
49 | EXPECTED_ROW_1 = 10;
50 | EXPECTED_BIGGEST_ROW = 10;
51 |
52 | POSITION = autoPositionTest.autoPosition(CELL_1);
53 |
54 | expect(EXPECTED_ROW_1).toBe(10);
55 | expect(EXPECTED_BIGGEST_ROW).toBe(10);
56 |
57 | expect(POSITION).toBe(EXPECTED_ROW_1); // 10
58 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW); // 10
59 | });
60 |
61 | it("Calculates row number prev_row + 1", () => {
62 | CELL_2 = {
63 | key,
64 | row: null,
65 | toRow: 0,
66 | };
67 | EXPECTED_ROW_2 = CELL_1.row + 1;
68 | EXPECTED_BIGGEST_ROW = EXPECTED_ROW_2;
69 |
70 | POSITION = autoPositionTest.autoPosition(CELL_2);
71 |
72 | expect(EXPECTED_ROW_2).toBe(11);
73 | expect(EXPECTED_BIGGEST_ROW).toBe(11);
74 |
75 | expect(POSITION).toBe(EXPECTED_ROW_2);
76 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
77 | });
78 |
79 | it("No change when passing the same value", () => {
80 | // same value in cell 2
81 | CELL_3 = {
82 | key,
83 | row: EXPECTED_ROW_2, // 11
84 | toRow: 0,
85 | };
86 | EXPECTED_ROW_3 = CELL_3.row; // no change for the same value: 11
87 | // no change for EXPECTED_BIGGEST_ROW
88 |
89 | POSITION = autoPositionTest.autoPosition(CELL_3);
90 |
91 | expect(EXPECTED_ROW_3).toBe(11);
92 |
93 | expect(POSITION).toBe(EXPECTED_ROW_3);
94 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
95 | });
96 |
97 | it("Assigns lower row value, to test biggest value", () => {
98 | CELL_4 = {
99 | key,
100 | row: 2,
101 | toRow: 0,
102 | };
103 | EXPECTED_ROW_4 = CELL_4.row;
104 | // no change for EXPECTED_BIGGEST_ROW
105 |
106 | POSITION = autoPositionTest.autoPosition(CELL_4);
107 |
108 | expect(EXPECTED_ROW_4).toBe(2);
109 |
110 | expect(POSITION).toBe(EXPECTED_ROW_4);
111 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
112 | });
113 |
114 | it("No row, the expected is not prev + 1, must be biggest +1", () => {
115 | CELL_5 = {
116 | key,
117 | row: null,
118 | toRow: 0,
119 | };
120 | EXPECTED_ROW_5 = EXPECTED_BIGGEST_ROW + 1;
121 | EXPECTED_BIGGEST_ROW = EXPECTED_ROW_5;
122 |
123 | POSITION = autoPositionTest.autoPosition(CELL_5);
124 |
125 | expect(EXPECTED_ROW_5).toBe(12);
126 | expect(EXPECTED_BIGGEST_ROW).toBe(12);
127 |
128 | expect(POSITION).toBe(EXPECTED_ROW_5);
129 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
130 | });
131 |
132 | it("No row, but toRow, the expected is prev + 1", () => {
133 | CELL_6 = {
134 | key,
135 | row: null,
136 | toRow: 200,
137 | };
138 | EXPECTED_ROW_6 = EXPECTED_ROW_5 + 1;
139 | EXPECTED_BIGGEST_ROW = CELL_6.toRow;
140 |
141 | POSITION = autoPositionTest.autoPosition(CELL_6);
142 |
143 | expect(EXPECTED_ROW_6).toBe(13);
144 | expect(EXPECTED_BIGGEST_ROW).toBe(200);
145 |
146 | expect(POSITION).toBe(EXPECTED_ROW_6);
147 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
148 | });
149 |
150 | it("No row, but lower toRow, biggest + 1", () => {
151 | CELL_7 = {
152 | key,
153 | row: null,
154 | toRow: 3,
155 | };
156 | EXPECTED_ROW_7 = EXPECTED_BIGGEST_ROW + 1;
157 | EXPECTED_BIGGEST_ROW = EXPECTED_BIGGEST_ROW + 1;
158 |
159 | POSITION = autoPositionTest.autoPosition(CELL_7);
160 |
161 | expect(EXPECTED_ROW_7).toBe(201);
162 | expect(EXPECTED_BIGGEST_ROW).toBe(201);
163 |
164 | expect(POSITION).toBe(EXPECTED_ROW_7);
165 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
166 | });
167 |
168 | it("Passes toRow & row both smaller than prev biggest", () => {
169 | CELL_8 = {
170 | key,
171 | row: 100,
172 | toRow: 3,
173 | };
174 | EXPECTED_ROW_8 = CELL_8.row;
175 | // no change for EXPECTED_BIGGEST_ROW
176 |
177 | POSITION = autoPositionTest.autoPosition(CELL_8);
178 |
179 | expect(EXPECTED_ROW_8).toBe(100);
180 |
181 | expect(POSITION).toBe(EXPECTED_ROW_8);
182 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
183 | });
184 |
185 | it("Passes toRow & row both but row bigger than biggest", () => {
186 | CELL_9 = {
187 | key,
188 | row: 205,
189 | toRow: 3,
190 | };
191 | EXPECTED_ROW_9 = CELL_9.row;
192 | EXPECTED_BIGGEST_ROW = EXPECTED_ROW_9;
193 |
194 | POSITION = autoPositionTest.autoPosition(CELL_9);
195 |
196 | expect(EXPECTED_ROW_9).toBe(205);
197 | expect(EXPECTED_BIGGEST_ROW).toBe(205);
198 |
199 | expect(POSITION).toBe(EXPECTED_ROW_9);
200 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
201 | });
202 |
203 | it("Passes toRow & row both but toRow bigger than biggest", () => {
204 | CELL_10 = {
205 | key,
206 | row: 88,
207 | toRow: 210,
208 | };
209 | EXPECTED_ROW_10 = CELL_10.row;
210 | EXPECTED_BIGGEST_ROW = CELL_10.toRow;
211 |
212 | POSITION = autoPositionTest.autoPosition(CELL_10);
213 |
214 | expect(EXPECTED_ROW_10).toBe(88);
215 | expect(EXPECTED_BIGGEST_ROW).toBe(210);
216 |
217 | expect(POSITION).toBe(EXPECTED_ROW_10);
218 | expect(autoPositionTest.biggestRowItem).toBe(EXPECTED_BIGGEST_ROW);
219 | });
220 | });
221 |
--------------------------------------------------------------------------------
/packages/folo-forms/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-forms/README.md:
--------------------------------------------------------------------------------
1 | # 📋 @folo/forms
2 |
3 | > React components combined of @folo/layout & @folo/values
4 |
5 |
6 | [](https://www.npmjs.com/package/@folo/forms)
7 | [](https://www.npmjs.com/package/@folo/forms)
8 | [](https://www.npmjs.com/package/@folo/forms)
9 | [](https://www.npmjs.com/package/@folo/forms)
10 | [](https://github.com/jalal246/folo/blob/master/packages/folo-forms/LICENSE)
11 | [](https://github.com/jalal246/folo/tree/master)
12 | [](https://codecov.io/gh/jalal246/folo)
13 |
14 |
15 | ## Installation
16 |
17 | ```sh
18 | npm install @folo/forms
19 | ```
20 |
21 | ## Overview
22 |
23 | `@folo/forms` has two major concepts defined in
24 | [Field](https://github.com/jalal246/folo/tree/master/packages/folo-values)
25 | to deal with data. And
26 | [Grid](https://github.com/jalal246/folo/tree/master/packages/folo-layout) for
27 | designing layout.
28 |
29 | ### Components
30 |
31 | ```js
32 | import { Form, Field, Grid, GridItem } from "@folo/forms";
33 | ```
34 |
35 | ## Contribution 😇
36 |
37 | If you have ideas or issues don't hesitate. You are always welcome.
38 |
39 | ## License
40 |
41 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/packages/folo-forms/LICENSE)
42 |
--------------------------------------------------------------------------------
/packages/folo-forms/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [["@babel/preset-env"], ["@babel/preset-react"]],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-forms/foloForms-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jalal246/folo/f9d5577f0e9e86bbbf5461a22041f583222d986b/packages/folo-forms/foloForms-demo.gif
--------------------------------------------------------------------------------
/packages/folo-forms/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/forms",
3 | "version": "1.0.2",
4 | "source": "src/index.js",
5 | "main": "dist/foloForms.min.cjs.js",
6 | "umd:main": "dist/foloForms.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "build": "builderz --output=foloForms"
12 | },
13 | "homepage": "https://github.com/jalal246/folo/tree/master/packages/folo-forms",
14 | "repository": "https://github.com/jalal246/folo",
15 | "bundledDependencies": [
16 | "@folo/layout",
17 | "@folo/values"
18 | ],
19 | "peerDependencies": {
20 | "react": ">=16"
21 | },
22 | "files": [
23 | "src",
24 | "dist",
25 | "LICENSE"
26 | ],
27 | "keywords": [
28 | "@folo",
29 | "@folo/auto-position",
30 | "@folo/forms",
31 | "@folo/layout",
32 | "@folo/store",
33 | "@folo/utils",
34 | "@folo/values",
35 | "@folo/withcontext",
36 | "dflex",
37 | "react",
38 | "react-component",
39 | "css-grid",
40 | "css-layout",
41 | "form-builder-api",
42 | "dynamic-forms"
43 | ],
44 | "publishConfig": {
45 | "registry": "https://registry.npmjs.org/",
46 | "access": "public"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/folo-forms/src/index.js:
--------------------------------------------------------------------------------
1 | import { Form, Field } from "@folo/values/src";
2 | import { GridItem, Grid } from "@folo/layout/src";
3 |
4 | export { Form, Grid, Field, GridItem };
5 |
--------------------------------------------------------------------------------
/packages/folo-forms/stories-legacy/README.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | Migrate stories
4 |
--------------------------------------------------------------------------------
/packages/folo-forms/stories-legacy/_directories.js:
--------------------------------------------------------------------------------
1 | export const MAIN_APP = "folo-forms";
2 |
3 | export const BASIC = "basic form";
4 | export const CUSTOM = "using costum components";
5 |
--------------------------------------------------------------------------------
/packages/folo-forms/stories-legacy/mainBasic.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { storiesOf } from "@storybook/react";
4 | import { action } from "@storybook/addon-actions";
5 |
6 | import { MAIN_APP, BASIC } from "./_directories";
7 |
8 | import { Folo, Form, Grid, Cell } from "../src";
9 |
10 | storiesOf(`${MAIN_APP}/${BASIC}`, module)
11 | .add("form with auto-grid", () => (
12 |
13 |
45 |
46 | ))
47 | .add("form with explicit grid", () => (
48 |
49 |
78 |
79 | ));
80 |
--------------------------------------------------------------------------------
/packages/folo-forms/stories-legacy/mainCustom.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { storiesOf } from "@storybook/react";
4 | import { action } from "@storybook/addon-actions";
5 |
6 | import TextField from "@material-ui/core/TextField";
7 | import List from "@material-ui/core/List";
8 | import ListItem from "@material-ui/core/ListItem";
9 | import ListItemText from "@material-ui/core/ListItemText";
10 | import Checkbox from "@material-ui/core/Checkbox";
11 | import Button from "@material-ui/core/Button";
12 |
13 | import { MAIN_APP, CUSTOM } from "./_directories";
14 |
15 | import { Folo, Form, Grid, Cell } from "../src";
16 |
17 | storiesOf(`${MAIN_APP}/${CUSTOM}`, module).add(
18 | "using component form material-ui",
19 | () => (
20 |
21 |
69 |
70 | )
71 | );
72 |
--------------------------------------------------------------------------------
/packages/folo-layout/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint-config-folo-react"],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-layout/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-layout/README.md:
--------------------------------------------------------------------------------
1 | # 📋 @folo/layout
2 |
3 | > React CSS Grid Components
4 |
5 | 
6 |
7 |
8 | [](https://www.npmjs.com/package/@folo/layout)
9 | [](https://www.npmjs.com/package/@folo/layout)
10 | [](https://www.npmjs.com/package/@folo/layout)
11 | [](https://www.npmjs.com/package/@folo/layout)
12 | [](https://github.com/jalal246/folo/blob/master/packages/folo-layout/LICENSE)
13 | [](https://github.com/jalal246/folo/tree/master)
14 | [](https://codecov.io/gh/jalal246/folo)
15 |
16 |
17 | ## Installation
18 |
19 | ```sh
20 | npm install @folo/layout
21 | ```
22 |
23 | ## Usage
24 |
25 | ```js
26 | import { Grid, GridItem } from "@folo/layout";
27 |
28 | const MyGrid = () => (
29 |
30 |
31 | item
32 |
33 |
34 | item
35 |
36 |
37 | item
38 |
39 |
40 | item
41 |
42 |
43 | item
44 |
45 |
46 | );
47 | ```
48 |
49 | ### Components
50 |
51 | ```js
52 | import { Grid, GridItem } from "@folo/layout";
53 | ```
54 |
55 | ### Components Props
56 |
57 | All components accept custom props.
58 |
59 | #### Grid
60 |
61 | | property | type | description | default |
62 | | ------------- | ------------- | ------------------------- | ------- |
63 | | `component` | node/function | custom render-component | `div` |
64 | | `col` | number | number of columns in grid | |
65 | | `colWidth` | string | fixed column width | |
66 | | `colMinWidth` | string | column minimum width | `auto` |
67 | | `colMaxWidth` | string | column maximum width | `1fr` |
68 | | `row` | number | number of rows in grid | |
69 | | `rowWidth` | string | fixed row width | |
70 | | `rowMinWidth` | string | row minimum width | `auto` |
71 | | `rowMaxWidth` | string | row maximum width | `1fr` |
72 |
73 | #### GridItem
74 |
75 | Used for implicit grid layout.
76 |
77 | | property | type | description | default |
78 | | -------------- | ------------- | ------------------------- | ------- |
79 | | `component` | node/function | custom render-component | `div` |
80 | | `row` | number | number of columns in grid | |
81 | | `toRow` | number | column width | |
82 | | `col` | number | column minimum width | `0` |
83 | | `toCol` | number | column maximum width | |
84 | | `isCenter` | Boolean | number of rows in grid | `false` |
85 | | `isHorizontal` | Boolean | | `true` |
86 |
87 | ## Contribution 😇
88 |
89 | If you have ideas to improve this package or issues don't hesitate. You are always welcome.
90 |
91 | ## License
92 |
93 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/packages/folo-layout/LICENSE)
94 |
--------------------------------------------------------------------------------
/packages/folo-layout/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [["@babel/preset-env"], ["@babel/preset-react"]],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-layout/foloLayout-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jalal246/folo/f9d5577f0e9e86bbbf5461a22041f583222d986b/packages/folo-layout/foloLayout-demo.gif
--------------------------------------------------------------------------------
/packages/folo-layout/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/layout",
3 | "version": "1.0.2",
4 | "source": "src/index.js",
5 | "main": "dist/foloLayout.min.cjs.js",
6 | "umd:main": "dist/foloLayout.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "build": "builderz --output=foloLayout"
12 | },
13 | "homepage": "https://github.com/jalal246/folo/tree/master/packages/folo-layout",
14 | "repository": "https://github.com/jalal246/folo",
15 | "bundledDependencies": [
16 | "@folo/auto-position",
17 | "@folo/values"
18 | ],
19 | "peerDependencies": {
20 | "react": ">=16"
21 | },
22 | "devDependencies": {
23 | "react": "^17.0.1"
24 | },
25 | "files": [
26 | "src",
27 | "dist",
28 | "LICENSE"
29 | ],
30 | "keywords": [
31 | "@folo",
32 | "@folo/auto-position",
33 | "@folo/forms",
34 | "@folo/layout",
35 | "@folo/store",
36 | "@folo/utils",
37 | "@folo/values",
38 | "@folo/withcontext",
39 | "dflex",
40 | "react",
41 | "react-component",
42 | "css-grid",
43 | "css-layout",
44 | "form-builder-api",
45 | "dynamic-forms"
46 | ],
47 | "publishConfig": {
48 | "registry": "https://registry.npmjs.org/",
49 | "access": "public"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/components/Grid.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import {
4 | GRID,
5 | STRETCH,
6 | CENTER,
7 | SPACE_BETWEEN,
8 | AUTO,
9 | FR,
10 | AUTO_FIT,
11 | DEFAULT_GAP,
12 | } from "../constants";
13 |
14 | /**
15 | * call repeat() CSS function
16 | * depending on length, min,max
17 | * with some enhancements
18 | *
19 | *
20 | * @param {number} length row or column number in grid
21 | * @param {string} min minimum unit for row or column
22 | * @param {string} max maximum unit for row or column
23 | * @return {string} repeat() CSS function represents a repeated fragment of the track list
24 | */
25 | function repeat(length, fixed, min, max) {
26 | return `repeat(${length}, ${fixed || `minmax(${min}, ${max})`})`;
27 | }
28 |
29 | const Grid = (props) => {
30 | const {
31 | component: CellComponent = "div",
32 |
33 | col = null,
34 | colWidth,
35 | colMinWidth = AUTO,
36 | colMaxWidth = FR,
37 |
38 | row = null,
39 | rowWidth,
40 | rowMinWidth = AUTO,
41 | rowMaxWidth = FR,
42 |
43 | isCenter = false,
44 |
45 | style: {
46 | display = GRID,
47 |
48 | alignItems = isCenter ? CENTER : STRETCH,
49 |
50 | // eslint-disable-next-line
51 | justifyContent = col || colWidth
52 | ? SPACE_BETWEEN
53 | : isCenter
54 | ? CENTER
55 | : STRETCH,
56 |
57 | gap = DEFAULT_GAP,
58 |
59 | ...otherStyles
60 | } = {},
61 | children,
62 |
63 | //
64 | ...rest
65 | } = props;
66 |
67 | const style = {
68 | display,
69 |
70 | ...(row
71 | ? { gridTemplateRows: repeat(row, rowWidth, rowMinWidth, rowMaxWidth) }
72 | : rowWidth && { gridAutoRows: rowWidth }),
73 |
74 | ...(colWidth && !col
75 | ? { gridAutoColumns: colWidth }
76 | : {
77 | gridTemplateColumns: repeat(
78 | col || AUTO_FIT,
79 | colWidth,
80 | colMinWidth,
81 | colMaxWidth
82 | ),
83 | }),
84 |
85 | alignItems,
86 | justifyContent,
87 | gap,
88 | ...otherStyles,
89 | };
90 |
91 | return (
92 |
93 | {children}
94 |
95 | );
96 | };
97 |
98 | export default Grid;
99 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/components/GridItem.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import positionStore from "../positionStore";
3 |
4 | import {
5 | CENTER,
6 | SPACE_BETWEEN,
7 | ROW,
8 | COLUMN,
9 | DISPLAY_FLEX,
10 | STRETCH,
11 | } from "../constants";
12 |
13 | function location(from, to) {
14 | if (from !== null && to !== null) {
15 | return `${from} / ${to}`;
16 | }
17 | return `${from}`;
18 | }
19 |
20 | /**
21 | * For implicit grid
22 | * Takes column and row number
23 | * to inform the grid parent of total positions
24 | *
25 | * It collects numbers report it to Grid
26 | */
27 | const GridItem = (props) => {
28 | const {
29 | component: CellComponent = "div",
30 |
31 | row = null,
32 | toRow = null,
33 |
34 | col = 0,
35 | toCol = null,
36 |
37 | isCenter = false,
38 | isHorizontal = true,
39 |
40 | style: {
41 | display = DISPLAY_FLEX,
42 |
43 | flexDirection: fDirection,
44 | alignItems: aItems,
45 | ...otherStyle
46 | } = {},
47 |
48 | id,
49 | children,
50 |
51 | ...rest
52 | } = props;
53 |
54 | const calculatedPosition = positionStore.autoPosition({
55 | key: id || `${new Date().getTime()}`,
56 | row,
57 | toRow,
58 | });
59 |
60 | const container = {
61 | display,
62 |
63 | ...(isHorizontal
64 | ? {
65 | flexDirection: fDirection || ROW,
66 | alignItems: aItems || CENTER,
67 | }
68 | : {
69 | flexDirection: fDirection || COLUMN,
70 | alignItems: aItems || STRETCH,
71 | }),
72 |
73 | justifyContent: isCenter ? CENTER : SPACE_BETWEEN,
74 |
75 | gridRow: location(calculatedPosition, toRow),
76 | gridColumn: location(col, toCol),
77 |
78 | ...otherStyle,
79 | };
80 |
81 | return (
82 |
83 | {children}
84 |
85 | );
86 | };
87 |
88 | export default GridItem;
89 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/constants.js:
--------------------------------------------------------------------------------
1 | export const GRID = "grid";
2 |
3 | export const STRETCH = "stretch";
4 | export const CENTER = "center";
5 | export const SPACE_BETWEEN = "space-between";
6 |
7 | export const FR = "1fr";
8 | export const AUTO_FIT = "auto-fit";
9 | export const AUTO = "auto";
10 | export const DEFAULT_GAP = "1em";
11 |
12 | export const ROW = "row";
13 | export const COLUMN = "column";
14 | export const DISPLAY_FLEX = "flex";
15 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/index.js:
--------------------------------------------------------------------------------
1 | import GridItem from "./components/GridItem";
2 | import Grid from "./components/Grid";
3 |
4 | export { GridItem, Grid };
5 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/positionStore.js:
--------------------------------------------------------------------------------
1 | import AutoPositionCell from "@folo/auto-position/src";
2 |
3 | export default (function init() {
4 | const positionStore = new AutoPositionCell();
5 |
6 | return positionStore;
7 | })();
8 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/stories/Implicit.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Grid from "../components/Grid";
4 |
5 | import { FriendlyLadder, ArtCollectionProps } from "./examples/ImplicitGrid";
6 |
7 | export default {
8 | title: "Grid Layout/Implicit Layout",
9 | component: Grid,
10 | };
11 |
12 | export { FriendlyLadder };
13 |
14 | export const ArtCollection = (args) => ;
15 | ArtCollection.args = {
16 | items1: { col1: 1, row1: 1, toRow1: 4, backgroundColor1: "blue" },
17 | items2: { col2: 3, row2: 1, toRow2: 2, backgroundColor2: "orange" },
18 | items3: { col3: 2, row3: 3, toRow3: 5, backgroundColor3: "pink" },
19 | };
20 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/stories/examples/ExplicitGrid.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Grid from "../../components/Grid";
4 |
5 | const styleLabel = {
6 | backgroundColor: " #444",
7 | color: "#fff",
8 | padding: "20px",
9 | fontSize: "150%",
10 | };
11 |
12 | export const FourColumnsProps = ({ col = 4 }) => (
13 |
19 | 1
20 | 2
21 | 3
22 | 4
23 | 5
24 | 6
25 | 7
26 | 8
27 |
28 | );
29 |
30 | export const ThreeColumnsThreeRowsProps = ({ col = 3, row = 4 }) => (
31 |
38 | 1
39 | 2
40 | 3
41 | 4
42 | 5
43 | 6
44 | 7
45 | 8
46 | 9
47 |
48 | );
49 |
50 | const styleLabel2 = {
51 | width: "172px",
52 | height: "81px",
53 | backgroundColor: " #444",
54 | color: "#fff",
55 | padding: "20px",
56 | fontSize: "150%",
57 | };
58 |
59 | export const MinimumWidthProps = ({
60 | gap = "0.3em",
61 | col = 3,
62 | row = 2,
63 | rowMinWid = "140px",
64 | colMinWidth = "300px",
65 | }) => (
66 |
75 | 1
76 | 2
77 | 3
78 | 4
79 | 5
80 | 6
81 |
82 | );
83 |
84 | export const CenterWithFixedWidthProps = ({
85 | gap = 0,
86 | isCenter = true,
87 | col = 2,
88 | row = 2,
89 | rowWidth = "220px",
90 | colWidth = "500px",
91 | }) => (
92 |
102 | 2
103 | 1
104 | 3
105 | 4
106 |
107 | );
108 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/stories/examples/ImplicitGrid.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Grid from "../../components/Grid";
4 | import GridItem from "../../components/GridItem";
5 |
6 | const styleLabel = {
7 | backgroundColor: "red",
8 | color: "#fff",
9 | padding: "10px",
10 | fontSize: "100%",
11 | };
12 |
13 | export const FriendlyLadder = () => (
14 |
19 |
20 | item
21 |
22 | {/* next one will be prev + 1 */}
23 |
24 | item
25 |
26 |
27 | item
28 |
29 |
30 | item
31 |
32 |
33 | item
34 |
35 |
36 | );
37 |
38 | export const ArtCollectionProps = () => (
39 |
44 |
51 |
58 |
65 |
66 | );
67 |
--------------------------------------------------------------------------------
/packages/folo-layout/src/stories/explicit.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Grid from "../components/Grid";
4 |
5 | import {
6 | FourColumnsProps,
7 | ThreeColumnsThreeRowsProps,
8 | MinimumWidthProps,
9 | CenterWithFixedWidthProps,
10 | } from "./examples/ExplicitGrid";
11 |
12 | export default {
13 | title: "Grid Layout/Explicit Layout",
14 | component: Grid,
15 | };
16 |
17 | export const FourColumns = (args) => ;
18 | FourColumns.args = {
19 | col: 4,
20 | };
21 |
22 | export const ThreeColumnsThreeRows = (args) => (
23 |
24 | );
25 | ThreeColumnsThreeRows.args = {
26 | col: 3,
27 | row: 4,
28 | };
29 |
30 | export const MinimumWidth = (args) => ;
31 | MinimumWidth.args = {
32 | gap: "0.3em",
33 | col: 3,
34 | row: 2,
35 | rowMinWid: "140px",
36 | colMinWidth: "300px",
37 | };
38 |
39 | export const CenterWithFixedWidth = (args) => (
40 |
41 | );
42 | CenterWithFixedWidth.args = {
43 | gap: 0,
44 | isCenter: true,
45 | col: 2,
46 | row: 2,
47 | rowWidth: "220px",
48 | colWidth: "500px",
49 | };
50 |
--------------------------------------------------------------------------------
/packages/folo-layout/test/Grid.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen, cleanup } from "@testing-library/react";
3 |
4 | import Grid from "../src/components/Grid";
5 |
6 | const TEST_ID = "testForGrid";
7 |
8 | const DEFAULT_DISPLAY = "grid";
9 | const STRETCH = "stretch";
10 | const DEFAULT_GAP = "1em";
11 | const SPACE_BETWEEN = "space-between";
12 | const AUTO_FIT = "auto-fit";
13 | const CENTER = "center";
14 |
15 | const MyGrid = (props = {}) => (
16 |
17 |
18 |
19 | );
20 |
21 | describe("Grid - Explicit Layout", () => {
22 | afterEach(() => {
23 | cleanup();
24 | });
25 |
26 | describe("Testing Style", () => {
27 | it("Returns default style", () => {
28 | render( );
29 |
30 | const { baseElement, style } = screen.getByTestId(TEST_ID);
31 |
32 | const expected = {
33 | display: DEFAULT_DISPLAY,
34 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
35 | alignItems: STRETCH,
36 | justifyContent: STRETCH,
37 | gap: DEFAULT_GAP,
38 | };
39 |
40 | expect(baseElement).toMatchSnapshot();
41 | expect(style).toMatchObject(expected);
42 | });
43 |
44 | it("Returns default style", () => {
45 | const DISPLAY_INLINE = "inline-grid";
46 | render( );
47 |
48 | const { baseElement, style } = screen.getByTestId(TEST_ID);
49 |
50 | const expected = {
51 | display: DISPLAY_INLINE,
52 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
53 | alignItems: STRETCH,
54 | justifyContent: STRETCH,
55 | gap: DEFAULT_GAP,
56 | };
57 |
58 | expect(baseElement).toMatchSnapshot();
59 | expect(style).toMatchObject(expected);
60 | });
61 | });
62 |
63 | describe("Testing alignItems", () => {
64 | it("Returns alignItems justifyContent center when no columns passed", () => {
65 | render( );
66 | const { baseElement, style } = screen.getByTestId(TEST_ID);
67 |
68 | const expected = {
69 | display: DEFAULT_DISPLAY,
70 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
71 | alignItems: CENTER,
72 | justifyContent: CENTER,
73 | gap: DEFAULT_GAP,
74 | };
75 |
76 | expect(baseElement).toMatchSnapshot();
77 | expect(style).toMatchObject(expected);
78 | });
79 |
80 | it("Returns alignItems center and justifyContent when columns passed", () => {
81 | render( );
82 | const { baseElement, style } = screen.getByTestId(TEST_ID);
83 |
84 | const expected = {
85 | display: DEFAULT_DISPLAY,
86 | gridTemplateColumns: "repeat(1, minmax(auto, 1fr))",
87 | alignItems: CENTER,
88 | justifyContent: SPACE_BETWEEN,
89 | gap: DEFAULT_GAP,
90 | };
91 |
92 | expect(baseElement).toMatchSnapshot();
93 | expect(style).toMatchObject(expected);
94 | });
95 | });
96 |
97 | describe("Testing rows", () => {
98 | it("Returns gridTemplateRows when passing row with minmax", () => {
99 | render( );
100 | const { baseElement, style } = screen.getByTestId(TEST_ID);
101 |
102 | const expected = {
103 | display: DEFAULT_DISPLAY,
104 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
105 | gridTemplateRows: "repeat(1, minmax(auto, 1fr))",
106 | alignItems: STRETCH,
107 | justifyContent: STRETCH,
108 | gap: DEFAULT_GAP,
109 | };
110 |
111 | expect(baseElement).toMatchSnapshot();
112 | expect(style).toMatchObject(expected);
113 | });
114 |
115 | it("Returns gridTemplateRows when passing row with width", () => {
116 | render( );
117 | const { baseElement, style } = screen.getByTestId(TEST_ID);
118 |
119 | const expected = {
120 | display: DEFAULT_DISPLAY,
121 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
122 | gridTemplateRows: "repeat(1, 20px)",
123 | alignItems: STRETCH,
124 | justifyContent: STRETCH,
125 | gap: DEFAULT_GAP,
126 | };
127 |
128 | expect(baseElement).toMatchSnapshot();
129 | expect(style).toMatchObject(expected);
130 | });
131 |
132 | it("Returns gridAutoRows when passing rowWidth only", () => {
133 | render( );
134 | const { baseElement, style } = screen.getByTestId(TEST_ID);
135 |
136 | const expected = {
137 | display: DEFAULT_DISPLAY,
138 | gridTemplateColumns: `repeat(${AUTO_FIT}, minmax(auto, 1fr))`,
139 | gridAutoRows: "20px",
140 | alignItems: STRETCH,
141 | justifyContent: STRETCH,
142 | gap: DEFAULT_GAP,
143 | };
144 |
145 | expect(baseElement).toMatchSnapshot();
146 | expect(style).toMatchObject(expected);
147 | });
148 | });
149 |
150 | describe("Testing columns", () => {
151 | it("Returns gridAutoColumns when passing colWidth only", () => {
152 | render( );
153 | const { baseElement, style } = screen.getByTestId(TEST_ID);
154 |
155 | const expected = {
156 | display: DEFAULT_DISPLAY,
157 | gridAutoColumns: "20px",
158 | alignItems: STRETCH,
159 | justifyContent: SPACE_BETWEEN,
160 | gap: DEFAULT_GAP,
161 | };
162 |
163 | expect(baseElement).toMatchSnapshot();
164 | expect(style).toMatchObject(expected);
165 | });
166 |
167 | it("Returns gridTemplateColumns when passing col", () => {
168 | render( );
169 | const { baseElement, style } = screen.getByTestId(TEST_ID);
170 |
171 | const expected = {
172 | display: DEFAULT_DISPLAY,
173 | gridTemplateColumns: "repeat(4, minmax(auto, 1fr))",
174 | alignItems: STRETCH,
175 | justifyContent: SPACE_BETWEEN,
176 | gap: DEFAULT_GAP,
177 | };
178 |
179 | expect(baseElement).toMatchSnapshot();
180 | expect(style).toMatchObject(expected);
181 | });
182 |
183 | it("Returns gridTemplateColumns when passing colWidth and col", () => {
184 | render( );
185 | const { baseElement, style } = screen.getByTestId(TEST_ID);
186 |
187 | const expected = {
188 | display: DEFAULT_DISPLAY,
189 | gridTemplateColumns: "repeat(4, 20px)",
190 | alignItems: STRETCH,
191 | justifyContent: SPACE_BETWEEN,
192 | gap: DEFAULT_GAP,
193 | };
194 |
195 | expect(baseElement).toMatchSnapshot();
196 | expect(style).toMatchObject(expected);
197 | });
198 | });
199 | });
200 |
--------------------------------------------------------------------------------
/packages/folo-layout/test/GridItem.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, screen, cleanup } from "@testing-library/react";
3 |
4 | import GridItem from "../src/components/GridItem";
5 |
6 | const TEST_ID = "testForGrid";
7 |
8 | const CENTER = "center";
9 | const ROW = "row";
10 | const COLUMN = "column";
11 | const DISPLAY_FLEX = "flex";
12 | const SPACE_BETWEEN = "space-between";
13 | const STRETCH = "stretch";
14 |
15 | const MyGridItem = (props = {}) => (
16 |
17 | );
18 |
19 | describe("GridItem - Implicit Layout", () => {
20 | afterEach(() => {
21 | cleanup();
22 | });
23 |
24 | describe("Testing Style", () => {
25 | it("Returns default style", () => {
26 | render( );
27 | const { baseElement, style } = screen.getByTestId(TEST_ID);
28 |
29 | const expected = {
30 | display: DISPLAY_FLEX,
31 | alignItems: CENTER,
32 | flexDirection: ROW,
33 | // gridRow: "0",
34 | gridColumn: "0",
35 | justifyContent: SPACE_BETWEEN,
36 | };
37 |
38 | expect(baseElement).toMatchSnapshot();
39 | expect(style).toMatchObject(expected);
40 | });
41 |
42 | it("Returns flexDirection column when it is isHorizontal = false", () => {
43 | render( );
44 | const { baseElement, style } = screen.getByTestId(TEST_ID);
45 |
46 | const expected = {
47 | display: DISPLAY_FLEX,
48 | alignItems: STRETCH,
49 | flexDirection: COLUMN,
50 | // gridRow: "0",
51 | gridColumn: "0",
52 | justifyContent: SPACE_BETWEEN,
53 | };
54 |
55 | expect(baseElement).toMatchSnapshot();
56 | expect(style).toMatchObject(expected);
57 | });
58 |
59 | it("Overrides styles", () => {
60 | render(
61 |
67 | );
68 | const { baseElement, style } = screen.getByTestId(TEST_ID);
69 |
70 | const expected = {
71 | display: DISPLAY_FLEX,
72 | alignItems: STRETCH,
73 | flexDirection: COLUMN,
74 | // gridRow: "0",
75 | gridColumn: "0",
76 | justifyContent: SPACE_BETWEEN,
77 | };
78 |
79 | expect(baseElement).toMatchSnapshot();
80 | expect(style).toMatchObject(expected);
81 | });
82 |
83 | it("Returns center", () => {
84 | render( );
85 | const { baseElement, style } = screen.getByTestId(TEST_ID);
86 |
87 | const expected = {
88 | display: DISPLAY_FLEX,
89 | alignItems: CENTER,
90 | flexDirection: ROW,
91 | // gridRow: "0",
92 | gridColumn: "0",
93 | justifyContent: CENTER,
94 | };
95 |
96 | expect(baseElement).toMatchSnapshot();
97 | expect(style).toMatchObject(expected);
98 | });
99 | });
100 |
101 | describe("Testing gridRow", () => {
102 | it("Returns gridRow with toRow and alignItems center", () => {
103 | render( );
104 | const { baseElement, style } = screen.getByTestId(TEST_ID);
105 |
106 | const expected = {
107 | display: DISPLAY_FLEX,
108 | alignItems: CENTER,
109 | flexDirection: ROW,
110 | // gridRow: "0 / 6",
111 | gridColumn: "0",
112 | justifyContent: SPACE_BETWEEN,
113 | };
114 |
115 | expect(baseElement).toMatchSnapshot();
116 | expect(style).toMatchObject(expected);
117 | });
118 |
119 | it("Returns gridRow with toRow =0", () => {
120 | render( );
121 | const { baseElement, style } = screen.getByTestId(TEST_ID);
122 |
123 | const expected = {
124 | display: DISPLAY_FLEX,
125 | alignItems: CENTER,
126 | flexDirection: ROW,
127 | // gridRow: "0 / 0",
128 | gridColumn: "0",
129 | justifyContent: SPACE_BETWEEN,
130 | };
131 |
132 | expect(baseElement).toMatchSnapshot();
133 | expect(style).toMatchObject(expected);
134 | });
135 |
136 | it("Returns gridRow with toRow =0", () => {
137 | render( );
138 | const { baseElement, style } = screen.getByTestId(TEST_ID);
139 |
140 | const expected = {
141 | display: DISPLAY_FLEX,
142 | alignItems: CENTER,
143 | flexDirection: ROW,
144 | // gridRow: "0 / 0",
145 | gridColumn: "0",
146 | justifyContent: SPACE_BETWEEN,
147 | };
148 |
149 | expect(baseElement).toMatchSnapshot();
150 | expect(style).toMatchObject(expected);
151 | });
152 | });
153 |
154 | describe("Testing gridColumn", () => {
155 | it("Returns column position with when col is provided", () => {
156 | render( );
157 | const { baseElement, style } = screen.getByTestId(TEST_ID);
158 |
159 | const expected = {
160 | display: DISPLAY_FLEX,
161 | alignItems: CENTER,
162 | flexDirection: ROW,
163 | // gridRow: "0",
164 | gridColumn: "10",
165 | justifyContent: SPACE_BETWEEN,
166 | };
167 |
168 | expect(baseElement).toMatchSnapshot();
169 | expect(style).toMatchObject(expected);
170 | });
171 |
172 | it("Returns column position with justifyContent, when toCol is provided", () => {
173 | render( );
174 | const { baseElement, style } = screen.getByTestId(TEST_ID);
175 |
176 | const expected = {
177 | display: DISPLAY_FLEX,
178 | alignItems: CENTER,
179 | flexDirection: ROW,
180 | // gridRow: "0",
181 | gridColumn: "0 / 10",
182 | justifyContent: SPACE_BETWEEN,
183 | };
184 |
185 | expect(baseElement).toMatchSnapshot();
186 | expect(style).toMatchObject(expected);
187 | });
188 | });
189 | });
190 |
--------------------------------------------------------------------------------
/packages/folo-layout/test/__snapshots__/Grid.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Grid - Explicit Layout Testing Style Returns default style 1`] = `undefined`;
4 |
5 | exports[`Grid - Explicit Layout Testing Style Returns default style 2`] = `undefined`;
6 |
7 | exports[`Grid - Explicit Layout Testing alignItems Returns alignItems center and justifyContent when columns passed 1`] = `undefined`;
8 |
9 | exports[`Grid - Explicit Layout Testing alignItems Returns alignItems justifyContent center when no columns passed 1`] = `undefined`;
10 |
11 | exports[`Grid - Explicit Layout Testing columns Returns gridAutoColumns when passing colWidth only 1`] = `undefined`;
12 |
13 | exports[`Grid - Explicit Layout Testing columns Returns gridTemplateColumns when passing col 1`] = `undefined`;
14 |
15 | exports[`Grid - Explicit Layout Testing columns Returns gridTemplateColumns when passing colWidth and col 1`] = `undefined`;
16 |
17 | exports[`Grid - Explicit Layout Testing rows Returns gridAutoRows when passing rowWidth only 1`] = `undefined`;
18 |
19 | exports[`Grid - Explicit Layout Testing rows Returns gridTemplateRows when passing row with minmax 1`] = `undefined`;
20 |
21 | exports[`Grid - Explicit Layout Testing rows Returns gridTemplateRows when passing row with width 1`] = `undefined`;
22 |
--------------------------------------------------------------------------------
/packages/folo-layout/test/__snapshots__/GridItem.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`GridItem - Implicit Layout Testing Style Overrides styles 1`] = `undefined`;
4 |
5 | exports[`GridItem - Implicit Layout Testing Style Returns center 1`] = `undefined`;
6 |
7 | exports[`GridItem - Implicit Layout Testing Style Returns default style 1`] = `undefined`;
8 |
9 | exports[`GridItem - Implicit Layout Testing Style Returns flexDirection column when it is isHorizontal = false 1`] = `undefined`;
10 |
11 | exports[`GridItem - Implicit Layout Testing gridColumn Returns column position with justifyContent, when toCol is provided 1`] = `undefined`;
12 |
13 | exports[`GridItem - Implicit Layout Testing gridColumn Returns column position with when col is provided 1`] = `undefined`;
14 |
15 | exports[`GridItem - Implicit Layout Testing gridRow Returns gridRow with toRow =0 1`] = `undefined`;
16 |
17 | exports[`GridItem - Implicit Layout Testing gridRow Returns gridRow with toRow =0 2`] = `undefined`;
18 |
19 | exports[`GridItem - Implicit Layout Testing gridRow Returns gridRow with toRow and alignItems center 1`] = `undefined`;
20 |
--------------------------------------------------------------------------------
/packages/folo-store/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint-config-folo-ts"],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-store/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-20201 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-store/README.MD:
--------------------------------------------------------------------------------
1 | # 📋 @folo/store
2 |
3 | > A Plain JavaScript Store Holds & Helps Controlling Data In Forms
4 |
5 |
6 | [](https://www.npmjs.com/package/@folo/store)
7 | [](https://www.npmjs.com/package/@folo/store)
8 | [](https://www.npmjs.com/package/@folo/store)
9 | [](https://www.npmjs.com/package/@folo/store)
10 | [](https://github.com/jalal246/folo/blob/master/packages/folo-store/LICENSE)
11 | [](https://github.com/jalal246/folo/tree/master)
12 | [](https://codecov.io/gh/jalal246/folo)
13 |
14 |
15 | ## Installation
16 |
17 | ```sh
18 | npm install @folo/store
19 | ```
20 |
21 | A store that holds data and triggers the connected components to update their
22 | values when necessary. Designed to deal optimally with forms.
23 |
24 | **How this is going to affect your UI performance?**
25 |
26 | Instead of re-mount, all elements exist in the form. This approach
27 | guarantees that only controlled elements in the UI will be triggered. This is
28 | important because usually global store and in most cases means to update all
29 | associated elements.
30 |
31 | ## Getting started
32 |
33 | Create a shared registry for your app. No matter how many forms you have, You
34 | need one registry instance.
35 |
36 | ```js
37 | import Registry from "@folo/store";
38 |
39 | const registry = new Registry();
40 | ```
41 |
42 | ## API
43 |
44 | ### Subscribe
45 |
46 | - Subscribe your elements to the registry:
47 |
48 | ```ts
49 | registry.subscribe(subscribeInfo: Object, triggerHandler:? Function);
50 | ```
51 |
52 | Where `SubscribeInfo: Object` an object contains:
53 |
54 | - `nameRef: string` - key reference to the element value.
55 | - `initValue: StoreValue` - Initial value for the element.
56 | - `groupName?: string` - Only for button group.
57 | - `storeID?: string` - In case you are running multiple forms, this value
58 | creates umbrella branch for you form.
59 |
60 | And `triggerHandler: Function` - Triggered when local value needs to be
61 | updated. This is strict to group buttons only.
62 |
63 | #### Example for subscribe
64 |
65 | ```js
66 | const btn1Info = {
67 | nameRef: "btn1",
68 | initValue: false,
69 | groupName: "choices",
70 | };
71 |
72 | const btn1Handler = (newValue) => {
73 | console.log(`I am triggered when my siblings value change! ${newValue}`);
74 | };
75 |
76 | registry.subscribe(btn1Info, btn1Handler);
77 |
78 | const btn2Info = {
79 | nameRef: "btn2",
80 | initValue: true,
81 | groupName: "choices",
82 | };
83 |
84 | const btn2Handler = (newValue) => {
85 | console.log(`I am triggered when my siblings value change! ${newValue}`);
86 | };
87 |
88 | registry.subscribe(btn2Info, btn2Handler);
89 |
90 | // ...
91 | registry.subscribe(text1Info, btn2Handler);
92 | registry.subscribe(text2Info, btn2Handler);
93 | ```
94 |
95 | ### updater
96 |
97 | - Update value in the registry and triggered handlers if necessary:
98 |
99 | ```ts
100 | registry.updater(updaterInfo: Object);
101 | ```
102 |
103 | Where `updaterInfo: Object` an object contains:
104 |
105 | - `nameRef: string` - key reference to the stored element.
106 | - `newValue: StoreValue` - The new value for the element.
107 | - `groupName?: string` - Only for button group.
108 | - `storeID?: string` - In case the element is registered under store id.
109 |
110 | What's going to happen is updating store values and trigger handlers for all
111 | buttons boolean values under the same group name toggling their values.
112 |
113 | #### Example for updater
114 |
115 | - Receive new value:
116 |
117 | ```js
118 | const btn2NewInfo = {
119 | nameRef: "btn2",
120 | newValue: true,
121 | groupName: "choices",
122 | };
123 |
124 | registry.updater(btn2NewInfo);
125 |
126 | //
127 |
128 | registry.updater(text1NewInfo);
129 | registry.updater(text2NewInfo);
130 | ```
131 |
132 | So, `btn1Handler` will be triggered with `false`. Why? Since we updated `btn1`
133 | and `btn2` values, UI should be informed to re-render.
134 |
135 | This is the only case when functions are triggered. Otherwise. data flow will be
136 | from UI to the store until submit is asking for all elements values.
137 |
138 | ### getDataByStoreID
139 |
140 | - Get store data
141 |
142 | ```ts
143 | registry.getDataByStoreID(storeID?: string): Object
144 | ```
145 |
146 | ### clear
147 |
148 | - Clear store data
149 |
150 | ```ts
151 | registry.clear(storeID?: string)
152 | ```
153 |
154 | ### destroy
155 |
156 | - Reset the whole registry
157 |
158 | ```ts
159 | registry.destroy();
160 | ```
161 |
162 | ## Test
163 |
164 | ```sh
165 | yarn test folo-store
166 | ```
167 |
168 | ## Implementation
169 |
170 | - With react:
171 | [folo-values](https://github.com/jalal246/folo/tree/master/packages/folo-values)
172 |
173 | ## Contribution 😇
174 |
175 | If you have ideas or issues don't hesitate. You are always welcome.
176 |
177 | ## License
178 |
179 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/packages/folo-store/LICENSE)
180 |
--------------------------------------------------------------------------------
/packages/folo-store/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [["@babel/preset-env"]],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-store/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/store",
3 | "version": "0.1.3",
4 | "source": "src/index.js",
5 | "main": "dist/foloStore.min.cjs.js",
6 | "umd:main": "dist/foloStore.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "compile": "tsc",
12 | "prebuild": "yarn compile",
13 | "build": "builderz --entires=./lib/index.js --output=foloStore"
14 | },
15 | "homepage": "https://github.com/jalal246/folo/tree/master/packages/folo-store",
16 | "repository": "https://github.com/jalal246/folo",
17 | "files": [
18 | "src",
19 | "dist",
20 | "types",
21 | "README.md",
22 | "LICENSE"
23 | ],
24 | "keywords": [
25 | "@folo",
26 | "@folo/auto-position",
27 | "@folo/forms",
28 | "@folo/layout",
29 | "@folo/store",
30 | "@folo/utils",
31 | "@folo/values",
32 | "@folo/withcontext",
33 | "@dflex",
34 | "store",
35 | "json",
36 | "forms",
37 | "storage"
38 | ],
39 | "publishConfig": {
40 | "registry": "https://registry.npmjs.org/",
41 | "access": "public"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/folo-store/src/Registry.ts:
--------------------------------------------------------------------------------
1 | type StoreValue = string | Boolean;
2 |
3 | interface SubscribeInfo {
4 | nameRef: string;
5 | initValue: StoreValue;
6 | groupName?: string;
7 | storeID?: string;
8 | }
9 |
10 | interface UpdaterInfo {
11 | nameRef: string;
12 | newValue: StoreValue;
13 | groupName?: string;
14 | storeID?: string;
15 | }
16 |
17 | interface DataHolder {
18 | [key: string]: { [key: string]: Object };
19 | }
20 |
21 | interface Triggers {
22 | [key: string]: { [key: string]: Function };
23 | }
24 |
25 | interface BtnGroup {
26 | [key: string]: { [key: string]: Set };
27 | }
28 |
29 | const DEFAULT_STORE = "unrecognized";
30 |
31 | class Registry {
32 | dataHolder: DataHolder;
33 |
34 | triggers: Triggers;
35 |
36 | activeStore: string;
37 |
38 | activeField: string;
39 |
40 | btnGroup: BtnGroup;
41 |
42 | constructor() {
43 | this.dataHolder = {};
44 | this.triggers = {};
45 | this.btnGroup = {};
46 |
47 | this.activeStore = "";
48 | this.activeField = "";
49 | }
50 |
51 | setActive(nameRef?: string, storeID?: string) {
52 | this.activeStore = storeID || DEFAULT_STORE;
53 | if (nameRef) this.activeField = nameRef;
54 | }
55 |
56 | initNewStore() {
57 | this.dataHolder[this.activeStore] = {};
58 | this.btnGroup[this.activeStore] = {};
59 | this.triggers[this.activeStore] = {};
60 | }
61 |
62 | assignValueToStore(storeValue: StoreValue) {
63 | if (!this.dataHolder[this.activeStore]) {
64 | this.initNewStore();
65 | }
66 |
67 | this.dataHolder[this.activeStore][this.activeField] = storeValue;
68 | }
69 |
70 | assignTrigger(triggerHandler: Function) {
71 | this.triggers[this.activeStore][this.activeField] = triggerHandler;
72 | }
73 |
74 | triggerHandler(withValue: StoreValue) {
75 | this.triggers[this.activeStore][this.activeField](withValue);
76 | }
77 |
78 | /**
79 | * Add field to dataBranches
80 | * Add groupName to btnGroup
81 | *
82 | * This function will be called when cells mount
83 | * after componentDidMount, the data in dataBranches will be moved to state
84 | * dataBranches is a temp object holds value to avoid update state while rendering
85 | * in this case will init all cells in dataBranches until rendering happens
86 | * then update the state so all the values update happen in state
87 | *
88 | * @param {object} field - new field that should be register
89 | * @param {string} field.nameRef key for value
90 | * @param {string||boolean} field.initValue value
91 | * @param {string} field.groupName group name in case the field is group-toggle
92 | */
93 | subscribe(
94 | { nameRef, initValue, groupName, storeID }: SubscribeInfo,
95 | triggerHandler: Function
96 | ) {
97 | this.setActive(nameRef, storeID);
98 |
99 | this.assignValueToStore(initValue);
100 |
101 | // if it has group, handle it
102 | if (groupName) {
103 | this.assignTrigger(triggerHandler);
104 |
105 | if (!this.btnGroup[this.activeStore][groupName]) {
106 | /*
107 | * Check if group name not exist then add it and create its own set
108 | * then add the field to its group
109 | */
110 |
111 | // create new set for the group
112 | this.btnGroup[this.activeStore][groupName] = new Set();
113 | }
114 |
115 | if (!this.btnGroup[this.activeStore][groupName].has(nameRef)) {
116 | // then add the field name to where its belong
117 | // to its group
118 | this.btnGroup[this.activeStore][groupName].add(nameRef);
119 | }
120 | }
121 | }
122 |
123 | updater({ nameRef, newValue, groupName, storeID }: UpdaterInfo) {
124 | this.setActive(nameRef, storeID);
125 | this.assignValueToStore(newValue);
126 |
127 | if (groupName) {
128 | if (newValue !== false) {
129 | // update group of values
130 |
131 | // toggle group values
132 | this.btnGroup[this.activeStore][groupName].forEach((FieldNameRef) => {
133 | // toggle all except the targeted key name which called nameRef
134 | // since we already changed its value above
135 | if (FieldNameRef !== nameRef) {
136 | this.setActive(FieldNameRef, storeID);
137 | this.assignValueToStore(!newValue);
138 | this.triggerHandler(!newValue);
139 | }
140 | });
141 | }
142 | }
143 | }
144 |
145 | getDataByStoreID(storeID?: string): Object {
146 | this.setActive(undefined, storeID);
147 |
148 | return this.dataHolder[this.activeStore];
149 | }
150 |
151 | clear(storeID?: string) {
152 | this.setActive(undefined, storeID);
153 |
154 | this.dataHolder[this.activeStore] = {};
155 | this.triggers[this.activeStore] = {};
156 | this.btnGroup[this.activeStore] = {};
157 | }
158 |
159 | destroy() {
160 | this.dataHolder = {};
161 | this.triggers = {};
162 | this.btnGroup = {};
163 | }
164 | }
165 |
166 | export default Registry;
167 |
--------------------------------------------------------------------------------
/packages/folo-store/src/index.ts:
--------------------------------------------------------------------------------
1 | import Registry from "./Registry";
2 |
3 | export default Registry;
4 |
--------------------------------------------------------------------------------
/packages/folo-store/test/__snapshots__/subscribe.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Testing subscribe effects on dataHolder/btnGroup Initializes data Obj holder with first register Checks button group 1`] = `
4 | Object {
5 | "unrecognized": Object {
6 | "gr1": Set {
7 | "nameTest1",
8 | },
9 | },
10 | }
11 | `;
12 |
13 | exports[`Testing subscribe effects on dataHolder/btnGroup Pushing a second obj with same group name Checks button group 1`] = `
14 | Object {
15 | "unrecognized": Object {
16 | "gr1": Set {
17 | "nameTest1",
18 | "nameTest2",
19 | },
20 | },
21 | }
22 | `;
23 |
24 | exports[`Testing subscribe effects on dataHolder/btnGroup Pushing a second obj with same group name Checks trigger handlers 1`] = `
25 | Object {
26 | "unrecognized": Object {
27 | "nameTest1": [MockFunction],
28 | "nameTest2": [MockFunction],
29 | },
30 | }
31 | `;
32 |
33 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing 2 branches of button group Checks button group 1`] = `
34 | Object {
35 | "unrecognized": Object {
36 | "gr1": Set {
37 | "nameTest1",
38 | "nameTest2",
39 | },
40 | "gr2": Set {
41 | "nameTest3",
42 | },
43 | },
44 | }
45 | `;
46 |
47 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing 2 branches of button group Checks trigger handlers 1`] = `
48 | Object {
49 | "unrecognized": Object {
50 | "nameTest1": [MockFunction],
51 | "nameTest2": [MockFunction],
52 | "nameTest3": [MockFunction],
53 | },
54 | }
55 | `;
56 |
57 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with non-grouped obj Checks button group 1`] = `
58 | Object {
59 | "unrecognized": Object {
60 | "gr1": Set {
61 | "nameTest1",
62 | "nameTest2",
63 | },
64 | "gr2": Set {
65 | "nameTest3",
66 | },
67 | },
68 | }
69 | `;
70 |
71 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with non-grouped obj Checks button group 2`] = `
72 | Object {
73 | "unrecognized": Object {
74 | "gr1": Set {
75 | "nameTest1",
76 | "nameTest2",
77 | },
78 | "gr2": Set {
79 | "nameTest3",
80 | },
81 | },
82 | }
83 | `;
84 |
85 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with non-grouped obj Checks trigger handlers 1`] = `
86 | Object {
87 | "unrecognized": Object {
88 | "nameTest1": [MockFunction],
89 | "nameTest2": [MockFunction],
90 | "nameTest3": [MockFunction],
91 | },
92 | }
93 | `;
94 |
95 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with non-grouped obj Checks trigger handlers 2`] = `
96 | Object {
97 | "unrecognized": Object {
98 | "nameTest1": [MockFunction],
99 | "nameTest2": [MockFunction],
100 | "nameTest3": [MockFunction],
101 | },
102 | }
103 | `;
104 |
105 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with same ref and group name obj and new value Checks button group 1`] = `
106 | Object {
107 | "unrecognized": Object {
108 | "gr1": Set {
109 | "nameTest1",
110 | "nameTest2",
111 | },
112 | "gr2": Set {
113 | "nameTest3",
114 | },
115 | },
116 | }
117 | `;
118 |
119 | exports[`Testing subscribe effects on dataHolder/btnGroup Testing registry.subscribe with same ref and group name obj and new value Checks trigger handlers 1`] = `
120 | Object {
121 | "unrecognized": Object {
122 | "nameTest1": [MockFunction],
123 | "nameTest2": [MockFunction],
124 | "nameTest3": [MockFunction],
125 | },
126 | }
127 | `;
128 |
--------------------------------------------------------------------------------
/packages/folo-store/test/__snapshots__/updater.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Registry updater Toggles boolean value in a group button 1`] = `
4 | Object {
5 | "unrecognized": Object {
6 | "input1": "some value",
7 | "input2": true,
8 | "input3": false,
9 | },
10 | }
11 | `;
12 |
13 | exports[`Registry updater Updates string value 1`] = `
14 | Object {
15 | "unrecognized": Object {
16 | "input1": "some value",
17 | "input2": false,
18 | "input3": false,
19 | },
20 | }
21 | `;
22 |
--------------------------------------------------------------------------------
/packages/folo-store/test/subscribe.test.js:
--------------------------------------------------------------------------------
1 | import Registry from "../src";
2 |
3 | let registry;
4 |
5 | const MUTUAL_GROUP_MANE_1 = "gr1";
6 |
7 | const NAME_REF_1 = "nameTest1";
8 | const INIT_VAL_1 = false;
9 |
10 | const NAME_REF_2 = "nameTest2";
11 | const INIT_VAL_2 = true;
12 |
13 | const MUTUAL_GROUP_MANE_2 = "gr2";
14 |
15 | const NAME_REF_3 = "nameTest3";
16 | const INIT_VAL_3 = true;
17 |
18 | const NAME_REF_4 = "nameTest4";
19 | const INIT_VAL_4 = "test";
20 |
21 | const INIT_VAL_5 = "new test value";
22 |
23 | const GENERAL_STORE_ID = "unrecognized";
24 |
25 | const handler = jest.fn((newValue) => newValue);
26 |
27 | describe("Testing subscribe effects on dataHolder/btnGroup", () => {
28 | beforeAll(() => {
29 | registry = new Registry();
30 | });
31 |
32 | describe("Initializes data Obj holder with first register", () => {
33 | beforeAll(() => {
34 | const obj1 = {
35 | nameRef: NAME_REF_1,
36 | initValue: INIT_VAL_1,
37 | groupName: MUTUAL_GROUP_MANE_1,
38 | };
39 |
40 | registry.subscribe(obj1, handler);
41 | });
42 |
43 | it("Checks dataHolder", () => {
44 | expect(registry.dataHolder).toMatchObject({
45 | [GENERAL_STORE_ID]: { [NAME_REF_1]: INIT_VAL_1 },
46 | });
47 | });
48 |
49 | it("Checks button group", () => {
50 | expect(registry.btnGroup).toMatchSnapshot();
51 | });
52 |
53 | it("Checks trigger handlers", () => {
54 | expect(registry.triggers[GENERAL_STORE_ID][NAME_REF_1]).toBeDefined();
55 | });
56 | });
57 |
58 | describe("Pushing a second obj with same group name", () => {
59 | beforeAll(() => {
60 | const obj2 = {
61 | nameRef: NAME_REF_2,
62 | initValue: INIT_VAL_2,
63 | groupName: MUTUAL_GROUP_MANE_1,
64 | };
65 |
66 | registry.subscribe(obj2, handler);
67 | });
68 |
69 | it("Checks dataHolder", () => {
70 | expect(registry.dataHolder).toMatchObject({
71 | [GENERAL_STORE_ID]: {
72 | [NAME_REF_1]: INIT_VAL_1,
73 | [NAME_REF_2]: INIT_VAL_2,
74 | },
75 | });
76 | });
77 |
78 | it("Checks button group", () => {
79 | expect(registry.btnGroup).toMatchSnapshot();
80 | });
81 |
82 | it("Checks trigger handlers", () => {
83 | expect(registry.triggers).toMatchSnapshot();
84 | });
85 | });
86 |
87 | describe("Testing 2 branches of button group", () => {
88 | beforeAll(() => {
89 | const obj3 = {
90 | nameRef: NAME_REF_3,
91 | initValue: INIT_VAL_3,
92 | groupName: MUTUAL_GROUP_MANE_2,
93 | };
94 |
95 | registry.subscribe(obj3, handler);
96 | });
97 |
98 | it("Checks dataHolder", () => {
99 | expect(registry.dataHolder).toMatchObject({
100 | [GENERAL_STORE_ID]: {
101 | [NAME_REF_1]: INIT_VAL_1,
102 | [NAME_REF_2]: INIT_VAL_2,
103 | [NAME_REF_3]: INIT_VAL_3,
104 | },
105 | });
106 | });
107 |
108 | it("Checks button group", () => {
109 | expect(registry.btnGroup).toMatchSnapshot();
110 | });
111 |
112 | it("Checks trigger handlers", () => {
113 | expect(registry.triggers).toMatchSnapshot();
114 | });
115 | });
116 |
117 | describe("Testing registry.subscribe with non-grouped obj", () => {
118 | beforeAll(() => {
119 | const obj4 = {
120 | nameRef: NAME_REF_4,
121 | initValue: INIT_VAL_4,
122 | groupName: null,
123 | };
124 |
125 | registry.subscribe(obj4);
126 | });
127 |
128 | it("Checks dataHolder", () => {
129 | expect(registry.dataHolder).toMatchObject({
130 | [GENERAL_STORE_ID]: {
131 | [NAME_REF_1]: INIT_VAL_1,
132 | [NAME_REF_2]: INIT_VAL_2,
133 | [NAME_REF_3]: INIT_VAL_3,
134 | [NAME_REF_4]: INIT_VAL_4,
135 | },
136 | });
137 | });
138 |
139 | it("Checks button group", () => {
140 | expect(registry.btnGroup).toMatchSnapshot();
141 | });
142 |
143 | it("Checks trigger handlers", () => {
144 | expect(registry.triggers).toMatchSnapshot();
145 | });
146 | });
147 |
148 | describe("Testing registry.subscribe with non-grouped obj", () => {
149 | beforeAll(() => {
150 | const obj4 = {
151 | nameRef: NAME_REF_4,
152 | initValue: INIT_VAL_4,
153 | groupName: null,
154 | };
155 |
156 | registry.subscribe(obj4, handler);
157 | });
158 |
159 | it("Checks dataHolder", () => {
160 | expect(registry.dataHolder).toMatchObject({
161 | [GENERAL_STORE_ID]: {
162 | [NAME_REF_1]: INIT_VAL_1,
163 | [NAME_REF_2]: INIT_VAL_2,
164 | [NAME_REF_3]: INIT_VAL_3,
165 | [NAME_REF_4]: INIT_VAL_4,
166 | },
167 | });
168 | });
169 |
170 | it("Checks button group", () => {
171 | expect(registry.btnGroup).toMatchSnapshot();
172 | });
173 |
174 | it("Checks trigger handlers", () => {
175 | expect(registry.triggers).toMatchSnapshot();
176 | });
177 | });
178 |
179 | describe("Testing registry.subscribe with same ref and group name obj and new value", () => {
180 | beforeAll(() => {
181 | const obj5 = {
182 | nameRef: NAME_REF_3,
183 | initValue: INIT_VAL_5,
184 | groupName: MUTUAL_GROUP_MANE_2,
185 | };
186 |
187 | registry.subscribe(obj5, handler);
188 | });
189 |
190 | it("Checks dataHolder", () => {
191 | expect(registry.dataHolder).toMatchObject({
192 | [GENERAL_STORE_ID]: {
193 | [NAME_REF_1]: INIT_VAL_1,
194 | [NAME_REF_2]: INIT_VAL_2,
195 | [NAME_REF_3]: INIT_VAL_5,
196 | [NAME_REF_4]: INIT_VAL_4,
197 | },
198 | });
199 | });
200 |
201 | it("Checks button group", () => {
202 | expect(registry.btnGroup).toMatchSnapshot();
203 | });
204 |
205 | it("Checks trigger handlers", () => {
206 | expect(registry.triggers).toMatchSnapshot();
207 | });
208 | });
209 | });
210 |
--------------------------------------------------------------------------------
/packages/folo-store/test/updater.test.js:
--------------------------------------------------------------------------------
1 | import Registry from "../src";
2 |
3 | let registry;
4 |
5 | const NAME_REF_1 = "input1";
6 |
7 | const NAME_REF_2 = "input2";
8 | const NAME_REF_3 = "input3";
9 |
10 | const BTN_GROUP = "group1";
11 |
12 | const btnGroup = new Set();
13 | btnGroup.add(BTN_GROUP);
14 | btnGroup.add(BTN_GROUP);
15 | btnGroup.group1 = new Set();
16 | btnGroup[BTN_GROUP].add(NAME_REF_2);
17 | btnGroup[BTN_GROUP].add(NAME_REF_3);
18 |
19 | const GENERAL_STORE_ID = "unrecognized";
20 |
21 | const TEXT_NEW_VALUE = "some value";
22 |
23 | const updater1 = jest.fn((newValue) => newValue);
24 | const updater2 = jest.fn((newValue) => newValue);
25 |
26 | describe("Registry updater", () => {
27 | beforeAll(() => {
28 | registry = new Registry();
29 |
30 | const input1 = {
31 | nameRef: NAME_REF_1,
32 | initValue: "",
33 | groupName: null,
34 | };
35 | registry.subscribe(input1);
36 |
37 | const input2 = {
38 | nameRef: NAME_REF_2,
39 | initValue: false,
40 | groupName: BTN_GROUP,
41 | };
42 | registry.subscribe(input2, updater1);
43 |
44 | const input3 = {
45 | nameRef: NAME_REF_3,
46 | initValue: false,
47 | groupName: BTN_GROUP,
48 | };
49 | registry.subscribe(input3, updater2);
50 | });
51 |
52 | it("Updates string value", () => {
53 | registry.updater({
54 | nameRef: NAME_REF_1,
55 | newValue: TEXT_NEW_VALUE,
56 | });
57 |
58 | expect(registry.dataHolder).toStrictEqual({
59 | [GENERAL_STORE_ID]: {
60 | [NAME_REF_1]: TEXT_NEW_VALUE,
61 | [NAME_REF_2]: false,
62 | [NAME_REF_3]: false,
63 | },
64 | });
65 |
66 | expect(registry.dataHolder).toMatchSnapshot();
67 | });
68 |
69 | it("Toggles boolean value in a group button", () => {
70 | registry.updater({
71 | nameRef: NAME_REF_2,
72 | newValue: true,
73 | groupName: BTN_GROUP,
74 | });
75 |
76 | expect(registry.dataHolder).toStrictEqual({
77 | [GENERAL_STORE_ID]: {
78 | [NAME_REF_1]: TEXT_NEW_VALUE,
79 | [NAME_REF_2]: true,
80 | [NAME_REF_3]: false,
81 | },
82 | });
83 |
84 | expect(updater1).toHaveBeenCalledTimes(0);
85 | expect(updater2).toHaveBeenCalledWith(false);
86 |
87 | expect(registry.dataHolder).toMatchSnapshot();
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/packages/folo-store/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "include": ["src/**/*"],
4 |
5 | "compilerOptions": {
6 | "outDir": "./lib"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/folo-utils/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-utils/README.md:
--------------------------------------------------------------------------------
1 | # @folo/utils
2 |
3 | > utils used in folo packages
4 |
5 |
6 |
7 |
8 | [](https://www.npmjs.com/package/@folo/utils)
9 | [](https://www.npmjs.com/package/@folo/utils)
10 | [](https://www.npmjs.com/package/@folo/utils)
11 | [](https://www.npmjs.com/package/@folo/utils)
12 | [](https://github.com/jalal246/folo/blob/master/LICENSE)
13 | [](https://circleci.com/gh/jalal246/folo/tree/master)
14 | [](https://codecov.io/gh/jalal246/folo)
15 |
16 |
17 | ## Installation
18 |
19 | ```
20 | npm install @folo/utils
21 | ```
22 |
23 | ## License
24 |
25 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/LICENSE)
26 |
--------------------------------------------------------------------------------
/packages/folo-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/utils",
3 | "version": "0.1.5",
4 | "source": "src/index.js",
5 | "main": "dist/foloUtils.min.cjs.js",
6 | "umd:main": "dist/foloUtils.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "build": "builderz --output=foloUtils"
12 | },
13 | "repository": "https://github.com/jalal246/folo/tree/master/packages/folo-utils",
14 | "files": [
15 | "src",
16 | "dist",
17 | "LICENSE"
18 | ],
19 | "keywords": [
20 | "@folo",
21 | "@folo/auto-position",
22 | "@folo/forms",
23 | "@folo/layout",
24 | "@folo/store",
25 | "@folo/utils",
26 | "@folo/values",
27 | "@folo/withcontext",
28 | "dflex",
29 | "react",
30 | "react-component",
31 | "css-grid",
32 | "css-layout",
33 | "form-builder-api",
34 | "dynamic-forms"
35 | ],
36 | "publishConfig": {
37 | "registry": "https://registry.npmjs.org/",
38 | "access": "public"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/folo-utils/src/index.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line
2 | export { keyGenerator } from "./utils";
3 |
--------------------------------------------------------------------------------
/packages/folo-utils/src/utils.js:
--------------------------------------------------------------------------------
1 | let lastId = 0;
2 |
3 | /**
4 | * generate unique ID for key
5 | * @param {String} prefix the prefix for the id
6 | * @return {String} the unique ID
7 | */
8 | // eslint-disable-next-line
9 | export function keyGenerator(prefix = "folo") {
10 | lastId += 1;
11 | return prefix + lastId;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/folo-values/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["eslint-config-folo-react"],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-values/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-values/README.md:
--------------------------------------------------------------------------------
1 | # 📋 @folo/values
2 |
3 | > A from store returns input values with zero config
4 |
5 |
6 |
7 | 
8 |
9 |
10 | [](https://www.npmjs.com/package/@folo/values)
11 | [](https://www.npmjs.com/package/@folo/values)
12 | [](https://www.npmjs.com/package/@folo/values)
13 | [](https://www.npmjs.com/package/@folo/values)
14 | [](https://github.com/jalal246/folo/blob/master/packages/folo-values/LICENSE)
15 | [](https://github.com/jalal246/folo/tree/master)
16 | [](https://codecov.io/gh/jalal246/folo)
17 |
18 |
19 | ## Installation
20 |
21 | ```sh
22 | npm install @folo/values
23 | ```
24 |
25 | - ☑️ A simple, lightweight package, comes with two components connected to global
26 | JavaScript store. That's it. No complexity, no unnecessary code.
27 |
28 | - ☑️ Instead of implementing your own store, `@folo/values` can do it for you with a
29 | store that holds inputs and knows exactly when to trigger connected components
30 | to re-render.
31 |
32 | - ☑️ Doesn't require using Redux/Mobx/Context. While these technologies are
33 | amazing it always comes with a cost. That's why every update that happens in `Folo`
34 | happens locally. The store is just the Maestro.
35 |
36 | - ☑️ You can add multiple forms connect them to the store or create branches
37 | yourself. It's all about `StoreID` my friends.
38 |
39 | - ☑️ Friendly code. What you do for a form written in JS, Can do it here. No
40 | external API. No external functionality. `onSubmit`, `onChange` are still here and
41 | not going anywhere.
42 |
43 | - ☑️ It's well tested code, with nearly 100% of code coverage 🥳
44 |
45 | ## Usage
46 |
47 | ```js
48 | import { Form, Field } from "@folo/values";
49 |
50 | const MyComponent = ({ onSubmit }) => (
51 |
70 | );
71 | // submit function will return: (event, {myName: "" myPass: "", alphabet:""})
72 | ```
73 |
74 | ## Available Components
75 |
76 | ```js
77 | import { Form, Field } from "@folo/values";
78 | ```
79 |
80 | All components accept custom props + children which is required in all except `Field`
81 |
82 | ### Form
83 |
84 | | property | type | description | default |
85 | | ----------- | ------------------ | ---------------------------------------------------------------- | -------------- |
86 | | `component` | HTMLElement/string | custom render-component | `form` |
87 | | `onSubmit` | function | submit function returns values in all cells (event, {...values}) | `() {}` |
88 | | `storeID` | string | unique id shared with form and fields | `unrecognized` |
89 |
90 | ### Field
91 |
92 | Essential to register values in the store, returns its value when submit.
93 | Accepts all events handlers.
94 |
95 | | property | type | description | default |
96 | | ----------- | ------------------ | ---------------------------------------- | ------------------- |
97 | | `component` | HTMLElement/string | custom render-component | `div` |
98 | | `storeID` | string | unique id shared with form and fields | `unrecognized` |
99 | | `valueKey` | string | key used to store value in values object | `id` or `timestamp` |
100 | | `value` | string | Initial value if type is not a button | `""` |
101 | | `checked` | Boolean | Initial value if type is a button | `false` |
102 | | `type` | string | Input type | `text` |
103 | | `groupName` | string | only for button toggle group | `null` |
104 |
105 | ## Examples
106 |
107 | You can clone all the examples used in these packages
108 | [here](https://github.com/jalal246/folo/tree/master/packages/folo-values/examples).
109 | With an example for [Simple
110 | Form](https://jalal246.github.io/folo/?path=/story/forms-forms-with-submit--simple-form)
111 | Or a [Custom
112 | Form](https://jalal246.github.io/folo/?path=/story/forms-forms-with-submit--custom-components)
113 | built with custom components. It includes All [Available
114 | fields](https://jalal246.github.io/folo/?path=/story/forms-available-fields--default-input)
115 | and examples that show you how to [handle toggle button groups](https://jalal246.github.io/folo/?path=/story/forms-toggle-groups--group-toggle-no-init-value).
116 |
117 | ## Test
118 |
119 | ```sh
120 | yarn test folo-values
121 | ```
122 |
123 | ## Contribution 😇
124 |
125 | If you have ideas or issues don't hesitate. You are always welcome.
126 |
127 | ## License
128 |
129 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/packages/folo-values/LICENSE)
130 |
--------------------------------------------------------------------------------
/packages/folo-values/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [["@babel/preset-env"], ["@babel/preset-react"]],
3 | };
4 |
--------------------------------------------------------------------------------
/packages/folo-values/examples/AddressForm.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/jsx-wrap-multilines */
2 | /* eslint-disable import/no-extraneous-dependencies */
3 |
4 | import React from "react";
5 |
6 | import Grid from "@material-ui/core/Grid";
7 | import Typography from "@material-ui/core/Typography";
8 | import TextField from "@material-ui/core/TextField";
9 | import FormControlLabel from "@material-ui/core/FormControlLabel";
10 | import Checkbox from "@material-ui/core/Checkbox";
11 | import Button from "@material-ui/core/Button";
12 |
13 | import Field from "../src/components/Field";
14 | import Form from "../src/components/Form";
15 |
16 | const AddressForm = ({ onSubmit }) => (
17 |
24 |
33 |
34 | Shipping address
35 |
36 |
148 |
149 |
150 | );
151 |
152 | export default AddressForm;
153 |
--------------------------------------------------------------------------------
/packages/folo-values/examples/BasicForm.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/label-has-associated-control */
2 | import React from "react";
3 |
4 | import Field from "../src/components/Field";
5 | import Form from "../src/components/Form";
6 |
7 | const styleForm = {
8 | display: "flex",
9 | flexDirection: "column",
10 | background: "#d4e2d4",
11 | width: "40%",
12 | margin: "10px",
13 | padding: "17px",
14 | };
15 |
16 | const styleLabel = {
17 | marginTop: "20px",
18 | fontSize: "18px",
19 | };
20 |
21 | const styleText = {
22 | paddingRight: "10px",
23 | };
24 |
25 | const BasicForm = ({ onSubmit }) => (
26 |
67 | );
68 |
69 | export default BasicForm;
70 |
--------------------------------------------------------------------------------
/packages/folo-values/examples/GroupToggle.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Field from "../src/components/Field";
4 | import Form from "../src/components/Form";
5 |
6 | export const GroupToggleNoInitValue = () => (
7 |
27 | );
28 |
29 | export const GroupToggleWithInitValue = () => (
30 |
51 | );
52 |
53 | export const GroupToggleDifferentGroupName = () => (
54 |
82 | );
83 |
--------------------------------------------------------------------------------
/packages/folo-values/foloValues-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jalal246/folo/f9d5577f0e9e86bbbf5461a22041f583222d986b/packages/folo-values/foloValues-demo.gif
--------------------------------------------------------------------------------
/packages/folo-values/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/values",
3 | "version": "1.0.3",
4 | "source": "src/index.js",
5 | "main": "dist/foloValues.min.cjs.js",
6 | "umd:main": "dist/foloValues.min.umd.js",
7 | "author": "Jalal Maskoun ",
8 | "license": "MIT",
9 | "scripts": {
10 | "test": "jest",
11 | "build": "builderz --output=foloValues"
12 | },
13 | "homepage": "https://github.com/jalal246/folo/tree/master/packages/folo-values",
14 | "repository": "https://github.com/jalal246/folo",
15 | "bundledDependencies": [
16 | "@folo/store"
17 | ],
18 | "peerDependencies": {
19 | "react": ">=16"
20 | },
21 | "devDependencies": {
22 | "@material-ui/core": "^4.11.2",
23 | "react": "^17.0.1"
24 | },
25 | "files": [
26 | "src",
27 | "dist",
28 | "LICENSE"
29 | ],
30 | "keywords": [
31 | "@folo",
32 | "@folo/auto-position",
33 | "@folo/forms",
34 | "@folo/layout",
35 | "@folo/store",
36 | "@folo/utils",
37 | "@folo/values",
38 | "@folo/withcontext",
39 | "@dflex",
40 | "react",
41 | "react-component",
42 | "form-builder-api",
43 | "dynamic-forms",
44 | "store",
45 | "json",
46 | "forms",
47 | "storage"
48 | ],
49 | "publishConfig": {
50 | "registry": "https://registry.npmjs.org/",
51 | "access": "public"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/folo-values/src/components/Core.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import registry from "../valuesStore";
4 |
5 | const BLUR = "blur";
6 |
7 | /**
8 | * manage value updates for all cell types
9 | * all controlled
10 | */
11 | const Core = ({
12 | coreComponent: Component,
13 | initValue,
14 | nameRef,
15 | groupName,
16 | valueRef,
17 | isInput,
18 | storeID,
19 | onBlur: onBlurProps,
20 | onChange: onChangeProps,
21 | children,
22 | ...rest
23 | }) => {
24 | const [localValue, setValue] = React.useState(initValue);
25 |
26 | React.useEffect(() => {
27 | registry.subscribe(
28 | {
29 | nameRef,
30 | initValue,
31 | groupName,
32 | storeID,
33 | },
34 | setValue
35 | );
36 | }, [initValue]);
37 |
38 | function eventHandler(e) {
39 | const {
40 | target: { [valueRef]: newValue },
41 | type,
42 | } = e;
43 |
44 | if (type === BLUR && typeof onBlurProps === "function") {
45 | // trigger onBlur coming form props
46 | onBlurProps(e);
47 | } else {
48 | // update local value while the change is happening
49 | // don't notify the global store yet
50 | setValue(newValue);
51 |
52 | if (typeof onChangeProps === "function") {
53 | onChangeProps(e);
54 | }
55 | }
56 |
57 | if (!isInput || type === BLUR) {
58 | // inform the store with the new changes we have here
59 | // only when bur or change happens in non-input element
60 | registry.updater({
61 | nameRef,
62 | newValue,
63 | groupName,
64 | storeID,
65 | });
66 | }
67 | }
68 |
69 | return (
70 |
76 | {children}
77 |
78 | );
79 | };
80 |
81 | export default Core;
82 |
--------------------------------------------------------------------------------
/packages/folo-values/src/components/Field.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Core from "./Core";
4 |
5 | import cellRecognizer from "../utils/cellRecognizer";
6 | import { TEXT } from "../constants";
7 |
8 | const Field = ({
9 | component,
10 | valueKey,
11 | id,
12 | value = "",
13 | checked = false,
14 | type = TEXT,
15 | groupName = null,
16 | storeID,
17 | children,
18 | ...rest
19 | }) => {
20 | const {
21 | valueRef,
22 | isInput,
23 | initValue,
24 | RecommendedComponent,
25 | } = cellRecognizer({ type, checked, value });
26 |
27 | const nameRef = valueKey || id || `${new Date().getTime()}`;
28 |
29 | return (
30 |
42 | {children}
43 |
44 | );
45 | };
46 |
47 | export default Field;
48 |
--------------------------------------------------------------------------------
/packages/folo-values/src/components/Form.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import registry from "../valuesStore";
4 |
5 | const Form = ({
6 | component: FormComponent = "form",
7 | onSubmit: onSubmitProps,
8 | storeID,
9 | children,
10 | ...rest
11 | }) => {
12 | React.useEffect(
13 | () =>
14 | function cleanup() {
15 | registry.clear(storeID);
16 | }
17 | );
18 |
19 | function onSubmit(e) {
20 | e.preventDefault();
21 |
22 | if (typeof onSubmitProps === "function") {
23 | onSubmitProps(e, registry.getDataByStoreID(storeID));
24 | }
25 | }
26 |
27 | return (
28 |
29 | {children}
30 |
31 | );
32 | };
33 |
34 | export default Form;
35 |
--------------------------------------------------------------------------------
/packages/folo-values/src/constants.js:
--------------------------------------------------------------------------------
1 | export const VALUE = "value";
2 | export const CHECKED = "checked";
3 |
4 | export const TEXT = "text";
5 |
6 | export const INPUT = "input";
7 | export const SELECT = "select";
8 | export const LIST = "list";
9 | export const CHECKBOX = "checkbox";
10 | export const RADIO = "radio";
11 | export const BTN = "button";
12 |
--------------------------------------------------------------------------------
/packages/folo-values/src/index.js:
--------------------------------------------------------------------------------
1 | import Field from "./components/Field";
2 | import Form from "./components/Form";
3 |
4 | export { Field, Form };
5 |
--------------------------------------------------------------------------------
/packages/folo-values/src/utils/cellRecognizer.js:
--------------------------------------------------------------------------------
1 | import {
2 | VALUE,
3 | CHECKED,
4 | SELECT,
5 | LIST,
6 | CHECKBOX,
7 | RADIO,
8 | INPUT,
9 | } from "../constants";
10 |
11 | /**
12 | * Gets the cell type
13 | * returns booleans type flag.
14 | *
15 | * @param {string} type
16 | * @param {boolean} checked
17 | * @param {string} value
18 | * @return {{isInput:boolean, valueRef: string, initValue: string||boolean, RecommendedComponent: string }}
19 | */
20 | function cellRecognizer({ type, checked, value }) {
21 | // only true when cell is button
22 | let isInput = false;
23 |
24 | // input or select
25 | let RecommendedComponent = INPUT;
26 |
27 | // value ref to the element: value or checked; depends on the type
28 | let valueRef = VALUE;
29 |
30 | // is it boolean or string; depends on the type
31 | let initValue = value;
32 |
33 | if (type === SELECT || type === LIST) {
34 | RecommendedComponent = SELECT;
35 | } else if (type === CHECKBOX || type === RADIO) {
36 | valueRef = CHECKED;
37 | initValue = checked;
38 | } else {
39 | isInput = true;
40 | }
41 |
42 | return {
43 | isInput,
44 | valueRef,
45 | initValue,
46 | RecommendedComponent,
47 | };
48 | }
49 |
50 | export default cellRecognizer;
51 |
--------------------------------------------------------------------------------
/packages/folo-values/src/valuesStore.js:
--------------------------------------------------------------------------------
1 | import Registry from "@folo/store/src";
2 |
3 | export default (function init() {
4 | const registry = new Registry();
5 |
6 | return registry;
7 | })();
8 |
--------------------------------------------------------------------------------
/packages/folo-values/stories/Field.stories.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 | import React from "react";
3 | import TextField from "@material-ui/core/TextField";
4 |
5 | import Field from "../src/components/Field";
6 |
7 | export default {
8 | title: "Forms/Available Fields",
9 | component: Field,
10 | argTypes: {
11 | onChange: {
12 | action: "onChange",
13 | },
14 | onBlur: {
15 | action: "onBlur",
16 | },
17 | },
18 | };
19 |
20 | const Template = (args) => ;
21 |
22 | export const DefaultInput = Template.bind({});
23 |
24 | export const TextInput = Template.bind({});
25 | TextInput.args = {
26 | type: "text",
27 | value: "Initial Value",
28 | };
29 |
30 | export const EmailInputWithCustomComponent = Template.bind({});
31 | EmailInputWithCustomComponent.args = {
32 | type: "email",
33 | component: TextField,
34 | label: "Name",
35 | margin: "normal",
36 | };
37 |
38 | export const PasswordInputWithHandlers = Template.bind({});
39 | PasswordInputWithHandlers.args = {
40 | type: "password",
41 | // onBlur:{action("onBlur")}
42 | };
43 |
44 | export const RadioButtonInput = Template.bind({});
45 | RadioButtonInput.args = {
46 | type: "radio",
47 | groupName: "choices",
48 | };
49 |
50 | export const CheckboxInput = Template.bind({});
51 | CheckboxInput.args = {
52 | type: "checkbox",
53 | };
54 |
55 | export const ColorInput = Template.bind({});
56 | ColorInput.args = {
57 | type: "color",
58 | };
59 |
60 | export const DateInput = Template.bind({});
61 | DateInput.args = {
62 | type: "date",
63 | };
64 |
65 | export const SelectOpts = Template.bind({});
66 | SelectOpts.args = {
67 | type: "select",
68 | children: (
69 | <>
70 | A
71 | B
72 | C
73 | >
74 | ),
75 | };
76 |
--------------------------------------------------------------------------------
/packages/folo-values/stories/FormsSubmit.stories.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/label-has-associated-control */
2 | import React from "react";
3 |
4 | import Form from "../src/components/Form";
5 |
6 | import BasicForm from "../examples/BasicForm";
7 | import AddressForm from "../examples/AddressForm";
8 |
9 | export default {
10 | title: "Forms/Forms with Submit",
11 | component: Form,
12 | argTypes: {
13 | onSubmit: {
14 | action: "onSubmit",
15 | },
16 | },
17 | };
18 |
19 | export const SimpleForm = (args) => ;
20 |
21 | export const CustomComponents = (args) => ;
22 |
--------------------------------------------------------------------------------
/packages/folo-values/stories/FormsToggle.stories.js:
--------------------------------------------------------------------------------
1 | import Form from "../src/components/Form";
2 |
3 | import {
4 | GroupToggleNoInitValue,
5 | GroupToggleWithInitValue,
6 | GroupToggleDifferentGroupName,
7 | } from "../examples/GroupToggle";
8 |
9 | export default {
10 | title: "Forms/Toggle groups",
11 | component: Form,
12 | onSubmit: {
13 | action: "onSubmit",
14 | },
15 | };
16 |
17 | export { GroupToggleNoInitValue };
18 |
19 | export { GroupToggleWithInitValue };
20 |
21 | export { GroupToggleDifferentGroupName };
22 |
--------------------------------------------------------------------------------
/packages/folo-values/test/Field.test.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render, fireEvent, screen, cleanup } from "@testing-library/react";
3 |
4 | import Field from "../src/components/Field";
5 | import Form from "../src/components/Form";
6 |
7 | const TEST_TEXT_1 = "default";
8 | const TEST_BTN_1 = "btn1";
9 | const TEST_BTN_2 = "btn2";
10 | const TEST_FORM = "form";
11 |
12 | const GROUP_NAME = "group1";
13 |
14 | const NEW_VAL = "hello!";
15 |
16 | const onSubmitMock = jest.fn((e, value) => value);
17 |
18 | const App = () => (
19 |
35 | );
36 |
37 | let txt;
38 | let btn1;
39 | let btn2;
40 | let form;
41 |
42 | describe("Testing Fields & Form", () => {
43 | beforeEach(() => {
44 | render( );
45 |
46 | txt = screen.getByTestId(TEST_TEXT_1);
47 |
48 | btn1 = screen.getByTestId(TEST_BTN_1);
49 | btn2 = screen.getByTestId(TEST_BTN_2);
50 |
51 | form = screen.getByTestId(TEST_FORM);
52 | });
53 |
54 | afterAll(() => {
55 | cleanup();
56 | });
57 |
58 | describe("Testing submit event on form for initial value", () => {
59 | it("returns context value when submit", () => {
60 | fireEvent.submit(form, {});
61 |
62 | // to
63 | expect(onSubmitMock).toHaveReturnedWith(
64 | expect.objectContaining({
65 | [TEST_TEXT_1]: "",
66 | [TEST_BTN_1]: false,
67 | [TEST_BTN_2]: true,
68 | })
69 | );
70 | });
71 | });
72 |
73 | describe("Testing toggle group in buttons", () => {
74 | it("Gets initial values", () => {
75 | expect(btn1.checked).toBe(false);
76 | });
77 |
78 | it("Sets one btn to false doesn't toggle the other one which is false", () => {
79 | fireEvent.blur(btn2, { target: { checked: false } });
80 |
81 | expect(btn1.checked).toBe(false);
82 | expect(btn2.checked).toBe(false);
83 | });
84 |
85 | it("Sets one btn to true doesn't toggle the other one which is false", () => {
86 | fireEvent.blur(btn2, { target: { checked: true } });
87 |
88 | expect(btn1.checked).toBe(false);
89 | expect(btn2.checked).toBe(true);
90 | });
91 |
92 | it("Sets one btn to true, toggles the other to false", () => {
93 | fireEvent.blur(btn1, { target: { checked: true } });
94 | expect(btn1.checked).toBe(true);
95 | expect(btn2.checked).toBe(false);
96 | });
97 |
98 | describe("Testing text input", () => {
99 | it("Gets initial values", () => {
100 | expect(txt.value).toBe("");
101 | });
102 |
103 | it("Sets new value to text input", () => {
104 | fireEvent.change(txt, { target: { value: NEW_VAL } });
105 |
106 | expect(txt.value).toBe(NEW_VAL);
107 | });
108 |
109 | it("sets the same value to text input", () => {
110 | fireEvent.change(txt, { target: { value: NEW_VAL } });
111 |
112 | expect(txt.value).toBe(NEW_VAL);
113 | });
114 | });
115 | });
116 | });
117 |
--------------------------------------------------------------------------------
/packages/folo-values/test/cellRecognizer.test.js:
--------------------------------------------------------------------------------
1 | import cellRecognizer from "../src/utils/cellRecognizer";
2 |
3 | import {
4 | VALUE,
5 | CHECKED,
6 | SELECT,
7 | LIST,
8 | CHECKBOX,
9 | RADIO,
10 | INPUT,
11 | } from "../src/constants";
12 |
13 | const MY_VAL = "HELLO WORLD!";
14 |
15 | describe("cellRecognizer function", () => {
16 | it("Testing type=INPUT", () => {
17 | expect(
18 | cellRecognizer({ type: INPUT, checked: false, value: MY_VAL })
19 | ).toMatchObject({
20 | valueRef: VALUE,
21 | isInput: true,
22 | initValue: MY_VAL,
23 | RecommendedComponent: INPUT,
24 | });
25 | });
26 |
27 | it("Testing type=CHECKBOX or RADIO", () => {
28 | const RESULT_CHECKBOX = cellRecognizer({
29 | type: CHECKBOX,
30 | checked: true,
31 | value: MY_VAL,
32 | });
33 |
34 | const RESULT_RADIO = cellRecognizer({
35 | type: RADIO,
36 | checked: true,
37 | value: MY_VAL,
38 | });
39 |
40 | const expected = {
41 | valueRef: CHECKED,
42 | isInput: false,
43 | initValue: true,
44 | RecommendedComponent: INPUT,
45 | };
46 |
47 | expect(RESULT_CHECKBOX).toMatchObject(expected);
48 | expect(RESULT_RADIO).toMatchObject(expected);
49 | });
50 |
51 | it("Testing type=SELECT or LIST", () => {
52 | const RESULT_SELECT = cellRecognizer({
53 | type: SELECT,
54 | checked: true,
55 | value: MY_VAL,
56 | });
57 |
58 | const RESULT_LIST = cellRecognizer({
59 | type: LIST,
60 | checked: true,
61 | value: MY_VAL,
62 | });
63 |
64 | const expected = {
65 | valueRef: VALUE,
66 | isInput: false,
67 | initValue: MY_VAL,
68 | RecommendedComponent: SELECT,
69 | };
70 |
71 | expect(RESULT_SELECT).toMatchObject(expected);
72 | expect(RESULT_LIST).toMatchObject(expected);
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/packages/folo-values/test/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import "@testing-library/jest-dom";
6 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 Jalal Maskoun
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 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/README.md:
--------------------------------------------------------------------------------
1 | # @folo/withcontext
2 |
3 | > micro HOC compose component accepts custom context values as props
4 |
5 |
6 |
7 |
8 | [](https://www.npmjs.com/package/@folo/withcontext)
9 | [](https://www.npmjs.com/package/@folo/withcontext)
10 | [](https://www.npmjs.com/package/@folo/withcontext)
11 | [](https://www.npmjs.com/package/@folo/withcontext)
12 | [](https://github.com/jalal246/folo/blob/master/LICENSE)
13 | [](https://circleci.com/gh/jalal246/folo/tree/master)
14 | [](https://codecov.io/gh/jalal246/folo)
15 |
16 |
17 | ## Installation
18 |
19 | ```
20 | npm install @folo/withcontext
21 | ```
22 |
23 | ## Usage
24 |
25 | ```js
26 | import withcontext from "@folo/withcontext";
27 |
28 | const ComponentWithContext = withcontext({
29 | Component: MyComponent,
30 | Consumer,
31 | contextProps: ["prop1", "prop4"], // with no contextProps provided, it accepts all context props
32 | });
33 | ```
34 |
35 | You can compose all context props by not passing `contextProps`
36 |
37 | ```js
38 | const ComponentWithAllContextProps = withcontext({
39 | Component: MyComponent,
40 | Consumer,
41 | });
42 | ```
43 |
44 | ## License
45 |
46 | This project is licensed under the [MIT License](https://github.com/jalal246/folo/blob/master/LICENSE)
47 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@folo/withcontext",
3 | "version": "0.1.5",
4 | "description": "micro HOC compose component accepts custom context values as props",
5 | "main": "dist/foloWithcontext.cjs.js",
6 | "umd:main": "dist/foloWithcontext.min.umd.js",
7 | "module": "dist/foloWithcontext.esm.js",
8 | "scripts": {},
9 | "repository": "https://github.com/jalal246/folo/tree/master/packages/folo-withcontext",
10 | "author": "Jalal Maskoun ",
11 | "license": "MIT",
12 | "bugs": {
13 | "url": "https://github.com/jalal246/folo/issues"
14 | },
15 | "homepage": "https://github.com/jalal246/folo",
16 | "files": [
17 | "src",
18 | "dist",
19 | "README.md"
20 | ],
21 | "keywords": [
22 | "@folo",
23 | "@folo/forms",
24 | "@folo/withcontext",
25 | "@folo/values",
26 | "@folo/layout",
27 | "@folo/utils",
28 | "react",
29 | "react-component",
30 | "utility"
31 | ],
32 | "peerDependencies": {
33 | "react": "^16.4.1"
34 | },
35 | "publishConfig": {
36 | "access": "public"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/src/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./withcontext";
2 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/src/withcontext.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | /**
4 | * HOC component
5 | * Connect component to props
6 | *
7 | * @param {Component} targeted_component
8 | * @param {Component} consumer_context
9 | * @param {Array} contextProps contains props required from consumer
10 | * @return {Component} - new component connected to context props
11 | */
12 | export default function ({ Component, Consumer, contextProps = [] }) {
13 | return function ComponentWithContext(props) {
14 | return (
15 |
16 | {(context) => {
17 | let cn = contextProps.length > 0 ? {} : context;
18 | /**
19 | * if contextProps length is zero, pass all context props
20 | * otherwise extract the required props
21 | */
22 | if (contextProps.length > 0) {
23 | contextProps.forEach((prop) => {
24 | cn[prop] = context[prop];
25 | });
26 | }
27 | return React.createElement(Component, Object.assign({}, props, cn));
28 | }}
29 |
30 | );
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/packages/folo-withcontext/test/withContext.test.jsx:
--------------------------------------------------------------------------------
1 | import React, { createContext } from "react";
2 | import { render, cleanup } from "react-testing-library";
3 |
4 | import withcontext from "../src/withcontext";
5 |
6 | const orginalProps = {
7 | type: "text"
8 | };
9 |
10 | const MyComponent = ({
11 | type = orginalProps.type,
12 | /* form context? */ disabled,
13 | /* form context? */ id,
14 | /* form context */ value,
15 | /* form context */ placeholder
16 | }) => (
17 | {}}
21 | value={value}
22 | placeholder={placeholder}
23 | disabled={disabled}
24 | id={id}
25 | />
26 | );
27 |
28 | const contextProps = {
29 | value: "test",
30 | placeholder: "Username",
31 | id: "unique",
32 | disabled: true
33 | };
34 |
35 | const { Consumer, Provider } = createContext({});
36 |
37 | const CNProvider = ({ children }) => (
38 | {children}
39 | );
40 |
41 | let MyComponentWIithContextConsumer;
42 |
43 | const App = () => (
44 |
45 |
46 |
47 | );
48 |
49 | afterEach(cleanup);
50 |
51 | describe("withcontext", () => {
52 | describe("custom context props", () => {
53 | MyComponentWIithContextConsumer = withcontext({
54 | Component: MyComponent,
55 | Consumer,
56 | contextProps: ["value", "placeholder"]
57 | });
58 |
59 | const { getByTestId } = render( );
60 |
61 | const { value, placeholder, type, disabled } = getByTestId(
62 | "withcontextTest"
63 | );
64 |
65 | it("returns component props bind with context values", () => {
66 | expect(value).toBe(contextProps.value);
67 |
68 | expect(placeholder).toBe(contextProps.placeholder);
69 | });
70 |
71 | it("retruns all context props when contextProps is not defined", () => {
72 | expect(disabled).toBe(false);
73 | });
74 |
75 | it("orginal component props still exist", () => {
76 | expect(type).toBe(orginalProps.type);
77 | });
78 | });
79 |
80 | describe("all context props", () => {
81 | it("does not have all context props, just the required", () => {
82 | MyComponentWIithContextConsumer = withcontext({
83 | Component: MyComponent,
84 | Consumer
85 | });
86 |
87 | const { getByTestId } = render( );
88 |
89 | const { disabled, id } = getByTestId("withcontextTest");
90 |
91 | expect(disabled).toBe(true);
92 |
93 | expect(id).toBe(contextProps.id);
94 | });
95 | });
96 | });
97 |
--------------------------------------------------------------------------------
/scripts/babel-preset-folo-dev/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel-preset-folo-dev",
3 | "main": "src/index",
4 | "version": "0.1.2",
5 | "private": true,
6 | "author": "Jalal Maskoun ",
7 | "license": "MIT",
8 | "dependencies": {
9 | "@babel/core": "^7.1.6",
10 | "@babel/plugin-proposal-class-properties": "^7.3.0",
11 | "@babel/plugin-proposal-export-default-from": "^7.0.0",
12 | "@babel/plugin-proposal-object-rest-spread": "^7.3.2",
13 | "@babel/plugin-transform-runtime": "^7.1.0",
14 | "@babel/preset-env": "^7.3.1",
15 | "@babel/preset-react": "^7.0.0",
16 | "@babel/runtime": "^7.3.1",
17 | "babel-plugin-minify-dead-code-elimination": "^0.5.0",
18 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/scripts/babel-preset-folo-dev/src/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = ({
2 | BUILD_FORMAT = process.env.BUILD_FORMAT,
3 | BABEL_ENV = process.env.BABEL_ENV || process.env.NODE_ENV || "development"
4 | }) => {
5 | const preset = {
6 | presets: [
7 | [
8 | require.resolve("@babel/preset-env"),
9 | {
10 | modules: BABEL_ENV === "test" ? "cjs" : false,
11 | loose: true
12 | }
13 | ],
14 |
15 | [require.resolve("@babel/preset-react")]
16 | ],
17 |
18 | plugins: [
19 | [
20 | // By default, this plugin uses Babel's extends helper which polyfills Object.assign.
21 | // Enabling useBuiltIns option will use Object.assign directly.
22 | require.resolve("@babel/plugin-proposal-object-rest-spread"),
23 | {
24 | useBuiltIns: true
25 | }
26 | ],
27 |
28 | // Compile export default to ES2015
29 | [require.resolve("@babel/plugin-proposal-export-default-from")],
30 |
31 | // This plugin transforms static class properties as well as properties declared with the property initializer syntax
32 | [
33 | require.resolve("@babel/plugin-proposal-class-properties"),
34 | { loose: true }
35 | ]
36 | ]
37 | };
38 |
39 | if (BABEL_ENV === "production") {
40 | preset.plugins.push.apply(preset.plugins, [
41 | [
42 | require.resolve("@babel/plugin-transform-runtime"),
43 | {
44 | useESModules: BUILD_FORMAT !== "cjs"
45 | }
46 | ],
47 |
48 | [
49 | require.resolve("babel-plugin-transform-react-remove-prop-types"),
50 | {
51 | mode: "remove",
52 | removeImport: true
53 | }
54 | ],
55 | [
56 | // remove inused code
57 | require.resolve("babel-plugin-minify-dead-code-elimination")
58 | ]
59 | ]);
60 | }
61 |
62 | // solving this issue: https://github.com/webpack/webpack/issues/4039
63 | if (BABEL_ENV === "storybook") {
64 | preset.plugins.push.apply(preset.plugins, [
65 | [require.resolve("@babel/plugin-transform-modules-commonjs")]
66 | ]);
67 | }
68 | return preset;
69 | };
70 |
--------------------------------------------------------------------------------
/scripts/babel-preset-folo-dev/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./babel.config.js");
2 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-react/config.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["airbnb", "prettier", "plugin:react/recommended"],
3 | parserOptions: {
4 | ecmaFeatures: {
5 | jsx: true,
6 | },
7 | ecmaVersion: 2018,
8 | sourceType: "module",
9 | },
10 | plugins: ["react"],
11 | rules: {
12 | "linebreak-style": 0,
13 | "react/jsx-filename-extension": 0,
14 | "react/prop-types": 0,
15 | "comma-dangle": 0,
16 | "react/jsx-props-no-spreading": 0,
17 | "import/no-unresolved": ["error", { ignore: ["^react$"] }],
18 | "import/no-extraneous-dependencies": "off",
19 | },
20 | settings: {
21 | "import/resolver": {
22 | node: {
23 | extensions: [".js", ".jsx", ".ts", ".tsx"],
24 | },
25 | },
26 | },
27 | overrides: [
28 | {
29 | files: ["packages/**/stories/*.stories.js"],
30 | rules: {
31 | "jsx-a11y/label-has-associated-control": "off",
32 | "jsx-a11y/label-has-for": "off",
33 | },
34 | },
35 | {
36 | files: ["packages/**/test/*.test.js"],
37 | rules: {
38 | "import/no-extraneous-dependencies": "off",
39 | },
40 | },
41 | ],
42 | };
43 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-react/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./config.eslintrc.js");
2 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-config-folo-react",
3 | "version": "0.1.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "eslint-config-airbnb": "^18.1.0",
8 | "eslint-config-prettier": "^8.3.0",
9 | "eslint-plugin-jsx-a11y": "^6.2.3",
10 | "eslint-plugin-react": "^7.19.0",
11 | "eslint-plugin-react-hooks": "^2.5.0"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-ts/config.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es2021: true,
5 | "jest/globals": true,
6 | },
7 | extends: ["airbnb-base", "prettier"],
8 | parser: "@typescript-eslint/parser",
9 | parserOptions: {
10 | ecmaVersion: 12,
11 | sourceType: "module",
12 | },
13 | plugins: ["@typescript-eslint", "tree-shaking", "jest"],
14 | rules: {
15 | "import/extensions": [
16 | "error",
17 | "ignorePackages",
18 | {
19 | js: "never",
20 | jsx: "never",
21 | ts: "never",
22 | tsx: "never",
23 | },
24 | ],
25 | },
26 | settings: {
27 | "import/resolver": {
28 | node: {
29 | extensions: [".js", ".jsx", ".ts", ".tsx"],
30 | },
31 | },
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-ts/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./config.eslintrc.js");
2 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo-ts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-config-folo-ts",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "@typescript-eslint/eslint-plugin": "^4.11.0",
8 | "@typescript-eslint/parser": "^4.11.0",
9 | "eslint": "^7.16.0",
10 | "eslint-config-airbnb-base": "^14.2.1",
11 | "eslint-config-prettier": "^8.3.0",
12 | "eslint-plugin-import": "^2.22.1",
13 | "eslint-plugin-jest": "^24.1.3",
14 | "eslint-plugin-tree-shaking": "^1.8.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-config-folo",
3 | "main": "src/index.js",
4 | "version": "0.1.1",
5 | "private": true,
6 | "author": "Jalal Maskoun ",
7 | "license": "MIT",
8 | "dependencies": {
9 | "babel-eslint": "^10.1.0",
10 | "eslint": "^7.16.0",
11 | "eslint-config-airbnb-base": "^14.1.0",
12 | "eslint-config-prettier": "^8.3.0",
13 | "eslint-plugin-import": "^2.20.1",
14 | "eslint-plugin-jest": "^24.1.3",
15 | "eslint-plugin-prettier": "^3.1.3",
16 | "eslint-plugin-tree-shaking": "^1.8.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo/src/config.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: "babel-eslint",
3 | env: {
4 | browser: true,
5 | es6: true,
6 | "jest/globals": true,
7 | },
8 | extends: ["airbnb-base", "prettier"],
9 | parserOptions: {
10 | ecmaVersion: 11,
11 | sourceType: "module",
12 | },
13 | rules: {},
14 | plugins: ["tree-shaking", "jest"],
15 | };
16 |
--------------------------------------------------------------------------------
/scripts/eslint-config-folo/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require("./config.eslintrc.js");
2 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
8 | "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
9 | // "lib": [], /* Specify library files to be included in the compilation. */
10 | // "allowJs": true, /* Allow javascript files to be compiled. */
11 | // "checkJs": true, /* Report errors in .js files. */
12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 | // "sourceMap": true, /* Generates corresponding '.map' file. */
16 | // "outFile": "./", /* Concatenate and emit output to single file. */
17 | // "outDir": "./", /* Redirect output structure to the directory. */
18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 | // "composite": true, /* Enable project compilation */
20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
21 | // "removeComments": true, /* Do not emit comments to output. */
22 | // "noEmit": true, /* Do not emit outputs. */
23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 |
27 | /* Strict Type-Checking Options */
28 | "strict": true /* Enable all strict type-checking options. */,
29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
30 | // "strictNullChecks": true, /* Enable strict null checks. */
31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
36 |
37 | /* Additional Checks */
38 | // "noUnusedLocals": true, /* Report errors on unused locals. */
39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
43 |
44 | /* Module Resolution Options */
45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
47 | // "paths": {} /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */,
48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
49 | // "typeRoots": [], /* List of folders to include type definitions from. */
50 | // "types": [], /* Type declaration files to be included in compilation. */
51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
52 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
55 |
56 | /* Source Map Options */
57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
61 |
62 | /* Experimental Options */
63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
65 |
66 | /* Advanced Options */
67 | "skipLibCheck": true /* Skip type checking of declaration files. */,
68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
69 | }
70 | }
71 |
--------------------------------------------------------------------------------