diff --git a/.gitignore b/.gitignore index 9eabc997..a5109d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,6 @@ storybook-static .DS_Store .nyc_output /docs/.vuepress/dist/ -/packages/tailwind/COLORS.JSON # Yarn .pnp.* @@ -65,3 +64,4 @@ storybook-static !.yarn/sdks !.yarn/versions +**/tsconfig.*.tsbuildinfo diff --git a/.storybook/main.ts b/.storybook/main.ts index 12f9ba17..d59901ba 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,14 +1,27 @@ import type { StorybookConfig } from "@storybook/react-vite"; const config: StorybookConfig = { - staticDirs: ["../packages/tailwind/build"], + staticDirs: ["../packages/tailwind-formio/build"], stories: [ "../stories/Getting-started.mdx", "../stories/**/*.mdx", - "../packages/{tailwind-formio,react-formio}/src/**/*.mdx", - "../packages/{tailwind-formio,react-formio}/src/**/*.stories.@(js|jsx|ts|tsx)", - "../packages/{tailwind-formio,react-formio}/src/**/*.story.@(js|jsx|ts|tsx)" + { + titlePrefix: "Styling", + directory: "../packages/tailwind-formio" + }, + { + titlePrefix: "Atoms", + directory: "../packages/react-formio/src/atoms" + }, + { + titlePrefix: "Molecules", + directory: "../packages/react-formio/src/molecules" + }, + { + titlePrefix: "Organisms", + directory: "../packages/react-formio/src/organisms" + } ], addons: [ @@ -18,8 +31,8 @@ const config: StorybookConfig = { "@storybook/addon-essentials", "@storybook/addon-mdx-gfm", "@storybook/addon-links", - "@storybook/addon-interactions", - "@chromatic-com/storybook" + "@chromatic-com/storybook", + "storybook-addon-mock" ], framework: { diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 3b1b2456..dbcb3327 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -11,17 +11,14 @@ Templates.framework = "tailwind"; /** @type { import('@storybook/react').Preview } */ const preview = { parameters: { - actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/ - } + docs: { + source: { language: "tsx" } } }, viewport: { viewports: INITIAL_VIEWPORTS - } + }, + tags: ["autodocs"] }; export default preview; diff --git a/README.md b/README.md index a3df9417..9bcd003f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Ts.ED logo + Ts.ED logo

@@ -14,11 +14,11 @@
- Website + Website   •   - Tutorial + Tutorial   •   - Slack + Slack   •   Twitter
@@ -33,11 +33,11 @@ Dedicated repository for Formio front-end related packages. - Provide a better TypeScript support, - Provide a [@tsed/tailwind-formio](./packages/tailwind-formio/readme.md) package to support tailwind CSS framework with formio. - Provide a lightweight redux utils packages. -- Provide a [storybook](https://formio.tsed.io) +- Provide a [storybook](https://formio.tsed.dev) ## Documentation -Documentation is available on [https://formio.tsed.io](https://formio.tsed.io). +Documentation is available on [https://formio.tsed.dev](https://formio.tsed.dev). ## Projects examples diff --git a/commitlint.config.cjs b/commitlint.config.cjs deleted file mode 100644 index 5073c20d..00000000 --- a/commitlint.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = { extends: ["@commitlint/config-conventional"] }; diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..fa584fb6 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1 @@ +export default { extends: ["@commitlint/config-conventional"] }; diff --git a/lerna.json b/lerna.json index fd1355e9..1cb5ddcb 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "packages": [ "packages/*" ], - "version": "2.3.2" + "version": "3.0.0-alpha.9" } diff --git a/package.json b/package.json index e9b9f5a1..645e0f8c 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,32 @@ { "name": "@tsed/root", - "version": "2.3.2", + "version": "3.0.0-alpha.9", "description": "", "author": "Romain Lenzotti", "private": true, "type": "module", "repository": { "type": "git", - "url": "https://github.com/TypedProject/tsed-formio.git" + "url": "https://github.com/tsedio/tsed-formio.git" }, "bugs": { - "url": "https://github.com/TypedProject/tsed-formio/issues" + "url": "https://github.com/tsedio/tsed-formio/issues" }, - "homepage": "https://github.com/TypedProject/tsed-formio", + "homepage": "https://github.com/tsedio/tsed-formio", "scripts": { - "postinstall": "lerna run build --stream", "configure": "monorepo ci configure", "test": "lerna run test --stream", - "test:coverage:update": "lerna run test:coverage:update --stream", "lint": "eslint", "lint:fix": "eslint", "build": "monorepo build --verbose", "publish": "monorepo publish --dry-run", "start": "lerna run start --stream --parallel", - "tailwind:build": "lerna run tailwind:build --stream --scope @tsed/tailwind", + "tailwind:build": "lerna run build --stream --scope @tsed/tailwind-formio", "release": "semantic-release", "prepare": "is-ci || husky install", - "storybook:test": "yarn test-storybook", - "storybook:test:ci": "yarn test-storybook --maxWorkers=2", - "storybook:start": "storybook dev -p 6006", + "storybook:test": "yarn build && yarn test-storybook", + "storybook:test:ci": "yarn build && yarn test-storybook --maxWorkers=2", + "storybook:start": "yarn tailwind:build && storybook dev -p 6006", "storybook:build": "yarn run tailwind:build && yarn run build-storybook", "build-storybook": "storybook build -c .storybook", "caniuse": "npx -y update-browserslist-db@latest", @@ -38,6 +36,7 @@ "dependencies": { "@formio/choices.js": "^9.0.1", "@types/classnames": "^2.2.11", + "@types/lodash": "4.17.13", "@types/react": "^18.2.8", "@types/react-dnd": "3.0.2", "@types/react-dnd-html5-backend": "3.0.2", @@ -47,15 +46,17 @@ "@types/react-router-dom": "^5.3.3", "@types/react-table": "^7.7.14", "connected-react-router": "6.9.1", - "formiojs": "^4.14.13", + "formiojs": "4.21.6", "history": "5.3.0", "lerna": "8.1.2", "lodash": "4.17.21", + "nodemon": "3.1.9", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "7.2.6", "react-router": "5.2.1", "react-router-dom": "5.2.1", + "react-select": "^5.9.0", "react-table": "^7.8.0", "redux-thunk": "^2.4.1", "tooltip.js": "^1.3.3" @@ -77,21 +78,21 @@ "@storybook/test-runner": "0.21.0", "@swc/core": "^1.2.208", "@swc/jest": "^0.2.21", - "@testing-library/dom": "^8.14.0", - "@testing-library/jest-dom": "^5.16.4", - "@testing-library/react": "^12.1.5", - "@testing-library/user-event": "^14.2.1", - "@tsed/monorepo-utils": "2.1.2", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.5.0", + "@testing-library/react": "16.1.0", + "@testing-library/user-event": "14.5.2", + "@tsed/monorepo-utils": "2.3.10", "@types/ejs": "^3.0.5", "@types/jest": "27.0.2", "@types/lodash": "4.14.168", - "@types/node": "^18.11.18", - "@types/prop-types": "^15.7.5", + "@types/node": "^20.14.8", "@types/react-dnd": "3.0.2", "@types/react-dnd-html5-backend": "3.0.2", "@typescript-eslint/eslint-plugin": "8.18.2", "@typescript-eslint/parser": "8.18.2", "@vitejs/plugin-react": "^4.3.4", + "@vitest/coverage-v8": "2.1.8", "autoprefixer": "^10.4.7", "camelcase": "6.3.0", "chromatic": "11.20.2", @@ -107,36 +108,33 @@ "eslint-plugin-testing-library": "7.1.1", "eslint-plugin-workspaces": "0.10.1", "fs-extra": "10.1.0", + "globby": "^14.0.2", "husky": "^8.0.1", - "jest": "^28.1.2", - "jest-environment-jsdom": "^28.1.2", - "jest-watch-typeahead": "^1.1.0", + "jsdom": "25.0.1", "lint-staged": "13.0.3", - "microbundle": "0.13.0", "playwright": "1.49.1", - "postcss": "^8.4.14", - "postcss-flexbugs-fixes": "5.0.2", - "postcss-nested": "^5.0.6", - "postcss-normalize": "10.0.1", - "postcss-preset-env": "7.7.2", - "postcss-safe-parser": "6.0.0", + "postcss": "8.4.49", + "postcss-nested": "7.0.2", + "postcss-normalize": "13.0.1", "prettier": "3.4.2", - "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-svg": "10.0.23", + "react": "18.3.1", + "react-dom": "18.3.1", "rimraf": "^3.0.2", + "rollup-preserve-directives": "^1.1.3", "semantic-release": "23.0.5", "semantic-release-slack-bot": "4.0.2", "storybook": "^8.4.7", - "typescript": "4.9.5", - "vite": "5.1.8", + "storybook-addon-mock": "5.0.0", + "typescript": "5.7.2", + "vite": "5.4.11", + "vite-plugin-dts": "4.4.0", "vite-plugin-svgr": "^2.4.0", - "webpack": "4.44.2" + "vitest": "2.1.8" }, "workspaces": { "packages": [ - "packages/*" + "packages/*", + "tools/*" ] }, "monorepo": { diff --git a/packages/config/.eslintignore b/packages/config/.eslintignore deleted file mode 100644 index 474be905..00000000 --- a/packages/config/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -**/node_modules -docs -docs-references -**/lib -**/build -**/dist -**/coverage -**/.nyc_output -**/node_modules -*-lock.json -*.lock -benchmarks.* -**/generated diff --git a/packages/config/.eslintrc.js b/packages/config/.eslintrc.js deleted file mode 100644 index 08c246f5..00000000 --- a/packages/config/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("./eslint/node.js"); diff --git a/packages/config/.prettierrc b/packages/config/.prettierrc deleted file mode 100644 index 78072afd..00000000 --- a/packages/config/.prettierrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "printWidth": 140, - "singleQuote": false, - "jsxSingleQuote": true, - "semi": true, - "tabWidth": 2, - "bracketSpacing": true, - "arrowParens": "always", - "trailingComma": "none" -} diff --git a/packages/config/bin/package.json b/packages/config/bin/package.json deleted file mode 100644 index 3dbc1ca5..00000000 --- a/packages/config/bin/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/packages/config/bin/write-coverage.js b/packages/config/bin/write-coverage.js deleted file mode 100755 index 5785d0c4..00000000 --- a/packages/config/bin/write-coverage.js +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env node -import fs from "fs-extra"; -import { join } from "path"; - -async function writeCoverage(cwd) { - const coveragePath = join(cwd, "coverage.json"); - - const { - total: { lines, statements, functions, branches } - } = await fs.readJson(join(cwd, "coverage/coverage-summary.json")); - - fs.writeJson( - coveragePath, - { - statements: statements.pct, - branches: branches.pct, - functions: functions.pct, - lines: lines.pct - }, - { spaces: 2 } - ); -} - -writeCoverage(process.cwd()); diff --git a/packages/config/eslint/node.js b/packages/config/eslint/node.js deleted file mode 100644 index a3a26ddd..00000000 --- a/packages/config/eslint/node.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = { - parser: "@typescript-eslint/parser", - extends: ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], - plugins: ["workspaces", "simple-import-sort"], - parserOptions: { - ecmaVersion: 2020, - sourceType: "module" - }, - env: { - node: true, - es6: true - }, - rules: { - "@typescript-eslint/ban-ts-comment": 0, - "@typescript-eslint/camelcase": 0, - "@typescript-eslint/no-inferrable-types": 0, - "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/explicit-module-boundary-types": 0, - "@typescript-eslint/no-unused-vars": 0, - "@typescript-eslint/no-explicit-any": 0, - "@typescript-eslint/no-non-null-assertion": 0, - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "workspaces/no-absolute-imports": "error" - }, - overrides: [ - { - files: ["**/*.spec.ts", "**/test/**", "**/__mock__/**"], - rules: { - "workspaces/no-absolute-imports": 0 - } - }, - { - files: ["**/*.js"], - rules: { - "@typescript-eslint/no-var-requires": 0 - } - } - ] -}; diff --git a/packages/config/eslint/web.js b/packages/config/eslint/web.js deleted file mode 100644 index 88a81ddb..00000000 --- a/packages/config/eslint/web.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - extends: ["react-app", "react-app/jest", "plugin:jsx-a11y/strict"], - plugins: ["workspaces", "prettier", "simple-import-sort"], - rules: { - "prettier/prettier": "error", - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "workspaces/no-absolute-imports": "error" - } -}; diff --git a/packages/config/jest/cssTransform.js b/packages/config/jest/cssTransform.js deleted file mode 100644 index 443ee4b5..00000000 --- a/packages/config/jest/cssTransform.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a custom Jest transformer turning style imports into empty objects. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process() { - return { code: "module.exports = {};" }; - }, - getCacheKey() { - // The output is always the same. - return "cssTransform"; - } -}; diff --git a/packages/config/jest/fileTransform.js b/packages/config/jest/fileTransform.js deleted file mode 100644 index f8f596fb..00000000 --- a/packages/config/jest/fileTransform.js +++ /dev/null @@ -1,40 +0,0 @@ -const path = require("path"); -const camelcase = require("camelcase"); - -// This is a custom Jest transformer turning file imports into filenames. -// http://facebook.github.io/jest/docs/en/webpack.html - -module.exports = { - process(src, filename) { - const assetFilename = JSON.stringify(path.basename(filename)); - - if (filename.match(/\.svg$/)) { - // Based on how SVGR generates a component name: - // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 - const pascalCaseFilename = camelcase(path.parse(filename).name, { - pascalCase: true - }); - const componentName = `Svg${pascalCaseFilename}`; - return { - code: `const React = require('react'); - module.exports = { - __esModule: true, - default: ${assetFilename}, - ReactComponent: React.forwardRef(function ${componentName}(props, ref) { - return { - $$typeof: Symbol.for('react.element'), - type: 'svg', - ref: ref, - key: null, - props: Object.assign({}, props, { - children: ${assetFilename} - }) - }; - }), - };` - }; - } - - return { code: `module.exports = ${assetFilename};` }; - } -}; diff --git a/packages/config/jest/jest.node.config.js b/packages/config/jest/jest.node.config.js deleted file mode 100644 index 6d57cd1d..00000000 --- a/packages/config/jest/jest.node.config.js +++ /dev/null @@ -1,26 +0,0 @@ -/** @type {import("ts-jest/dist/types").InitialOptionsTsJest} */ - -module.exports = { - roots: ["/src"], - collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts", "!src/mocks/**", "!src/__mock__/**"], - coveragePathIgnorePatterns: [], - testEnvironment: "node", - transform: { - "^.+\\.(t|j)sx?$": ["@swc/jest", require("./swc.node.json")] - // "^.+\\.(t|j)sx?$": ["ts-jest"] - }, - transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$", "^.+\\.module\\.(css|sass|scss)$"], - modulePaths: ["/src"], - moduleNameMapper: {}, - moduleFileExtensions: [ - // Place tsx and ts to beginning as suggestion from Jest team - // https://jestjs.io/docs/configuration#modulefileextensions-arraystring - "tsx", - "ts", - "js", - "json", - "jsx", - "node" - ], - watchPlugins: ["jest-watch-typeahead/filename", "jest-watch-typeahead/testname"] -}; diff --git a/packages/config/jest/jest.web.config.js b/packages/config/jest/jest.web.config.js deleted file mode 100644 index a92f4b29..00000000 --- a/packages/config/jest/jest.web.config.js +++ /dev/null @@ -1,35 +0,0 @@ -/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ -module.exports = { - roots: ["/src"], - collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"], - coveragePathIgnorePatterns: [".stories.tsx", "__mock__/", "mocks/"], - testEnvironment: "jsdom", - setupFilesAfterEnv: [require.resolve("./setupTest.js")], - transform: { - "^.+\\.(t|j)sx?$": ["@swc/jest", require("./swc.web.json")], - "^.+\\.css$": require.resolve("./cssTransform.js"), - "^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": require.resolve("./fileTransform.js") - }, - transformIgnorePatterns: ["^.+\\.module\\.(css|sass|scss)$"], - modulePaths: ["/src"], - moduleNameMapper: { - "^react-native$": "react-native-web", - "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy" - }, - moduleFileExtensions: [ - // Place tsx and ts to beginning as suggestion from Jest team - // https://jestjs.io/docs/configuration#modulefileextensions-arraystring - "tsx", - "ts", - "web.js", - "js", - "web.ts", - "web.tsx", - "json", - "web.jsx", - "jsx", - "node" - ], - watchPlugins: ["jest-watch-typeahead/filename", "jest-watch-typeahead/testname"], - coverageReporters: ["clover", "json", "lcov", ["text", { skipFull: true }], "json-summary"] -}; diff --git a/packages/config/jest/setupTest.js b/packages/config/jest/setupTest.js deleted file mode 100644 index c6228da1..00000000 --- a/packages/config/jest/setupTest.js +++ /dev/null @@ -1,29 +0,0 @@ -import "@testing-library/jest-dom/extend-expect"; - -window.matchMedia = (query) => ({ - matches: false, - media: query, - onchange: null, - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), - addListener: jest.fn(), - removeListener: jest.fn() -}); - -Object.defineProperty(URL, "createObjectURL", { - writable: true, - value: jest.fn() -}); - -if (typeof window !== "undefined") { - window.scrollTo = jest.fn(); - - jest.mock( - "react-svg", - () => - function Svg() { - return ""; - } - ); -} diff --git a/packages/config/jest/swc.node.json b/packages/config/jest/swc.node.json deleted file mode 100644 index f68740ae..00000000 --- a/packages/config/jest/swc.node.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "jsc": { - "target": "es2021", - "parser": { - "syntax": "typescript", - "tsx": true, - "decorators": true, - "dynamicImport": true, - "privateMethod": true, - "exportDefaultFrom": true, - "importMeta": true - }, - "transform": { - "hidden": { - "jest": true - }, - "legacyDecorator": true, - "decoratorMetadata": true - } - }, - "module": { - "type": "commonjs", - "strict": false, - "strictMode": true, - "lazy": false, - "noInterop": false - } -} diff --git a/packages/config/jest/swc.web.json b/packages/config/jest/swc.web.json deleted file mode 100644 index 30025bf1..00000000 --- a/packages/config/jest/swc.web.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "jsc": { - "target": "es2017", - "parser": { - "syntax": "typescript", - "tsx": true, - "decorators": false, - "dynamicImport": false - }, - "transform": { - "react": { - "pragma": "React.createElement", - "pragmaFrag": "React.Fragment", - "throwIfNamespace": true, - "development": false, - "useBuiltins": false, - "runtime": "automatic" - }, - "hidden": { - "jest": true - } - } - }, - "module": { - "type": "commonjs", - "strict": false, - "strictMode": true, - "lazy": false, - "noInterop": false - } -} diff --git a/packages/config/package.json b/packages/config/package.json deleted file mode 100644 index 56073413..00000000 --- a/packages/config/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@tsed/config", - "version": "2.3.2", - "main": "src/index.js", - "main:src": "src/index.js", - "description": "Shared configuration", - "author": "Romain Lenzotti", - "license": "MIT", - "private": true, - "type": "commonjs", - "bin": { - "write-coverage": "./bin/write-coverage.js" - }, - "devDependencies": { - "@tsed/tailwind": "2.3.2", - "@tsed/yarn-workspaces": "1.19.3" - } -} diff --git a/packages/config/postcss.config.js b/packages/config/postcss.config.js deleted file mode 100644 index bb604e27..00000000 --- a/packages/config/postcss.config.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - plugins: [ - require("postcss-flexbugs-fixes"), - require("postcss-preset-env")({ - autoprefixer: { - flexbox: "no-2009" - }, - stage: 3 - }), - require("postcss-normalize"), - require("tailwindcss"), - require("postcss-nested"), - require("autoprefixer") - ] -}; diff --git a/packages/config/tsconfig.node.json b/packages/config/tsconfig.node.json deleted file mode 100644 index d6831da7..00000000 --- a/packages/config/tsconfig.node.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "esnext", - "sourceMap": true, - "declaration": false, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "moduleResolution": "node", - "isolatedModules": false, - "preserveConstEnums": true, - "noImplicitAny": true, - "strictNullChecks": true, - "noUnusedLocals": false, - "noUnusedParameters": false, - "allowSyntheticDefaultImports": true, - "importHelpers": true, - "newLine": "LF", - "noEmit": true, - "esModuleInterop": true, - "resolveJsonModule": true, - "composite": true, - "lib": ["es7", "dom", "ESNext.AsyncIterable"] - } -} diff --git a/packages/integration/index.html b/packages/integration/index.html new file mode 100644 index 00000000..e4b78eae --- /dev/null +++ b/packages/integration/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/packages/integration/package.json b/packages/integration/package.json new file mode 100644 index 00000000..efdeee32 --- /dev/null +++ b/packages/integration/package.json @@ -0,0 +1,34 @@ +{ + "name": "@tsed/react-formio-integration", + "version": "3.0.0-alpha.9", + "description": "", + "private": true, + "type": "module", + "license": "MIT", + "scripts": { + "dev": "vite dev" + }, + "dependencies": { + "classnames": "^2.3.1", + "eventemitter2": "^6.4.3" + }, + "peerDependencies": { + "@formio/choices.js": ">=9.0.1", + "formiojs": ">=4.0.0", + "lodash": ">=4.17.20", + "react": ">=16.14.0", + "react-dnd": ">=16.0.1", + "react-dnd-html5-backend": ">=16.0.1", + "react-dom": ">=16.14.0", + "react-table": ">=7.6.3", + "tooltip.js": ">=1.3.3" + }, + "devDependencies": { + "@tsed/react-formio": "workspace:*", + "@tsed/tailwind-formio": "workspace:*", + "@tsed/typescript": "workspace:*", + "microbundle": "0.13.0", + "vite": "5.4.11", + "vitest": "2.1.8" + } +} diff --git a/packages/integration/postcss.config.js b/packages/integration/postcss.config.js new file mode 100644 index 00000000..93b9521b --- /dev/null +++ b/packages/integration/postcss.config.js @@ -0,0 +1,8 @@ +export default { + plugins: { + "postcss-normalize": {}, + "tailwindcss/nesting": {}, + tailwindcss: {}, + autoprefixer: {} + } +}; diff --git a/packages/integration/public/vite.svg b/packages/integration/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/packages/integration/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/integration/src/App.tsx b/packages/integration/src/App.tsx new file mode 100644 index 00000000..c12ebca6 --- /dev/null +++ b/packages/integration/src/App.tsx @@ -0,0 +1,118 @@ +import { defaultDisplayChoices, FormEdit } from "@tsed/react-formio"; + +const opts: any = { + typeChoices: [ + { label: "Form", value: "form" }, + { label: "Resources", value: "resource" } + ], + displayChoices: defaultDisplayChoices, + enableTags: true, + // options: { template: "tailwind", iconset: "bx" }, + form: { + type: "form", + tags: [], + owner: "5d0797a382461b6656d2c790", + components: [ + { + label: "Text Field", + labelPosition: "top", + placeholder: "", + description: "", + tooltip: "", + prefix: "", + suffix: "", + widget: { type: "input" }, + inputMask: "", + allowMultipleMasks: false, + customClass: "", + tabindex: "", + autocomplete: "", + hidden: false, + hideLabel: false, + showWordCount: false, + showCharCount: false, + mask: false, + autofocus: false, + spellcheck: true, + disabled: false, + tableView: true, + modalEdit: false, + multiple: false, + persistent: true, + inputFormat: "plain", + protected: false, + dbIndex: false, + case: "", + encrypted: false, + redrawOn: "", + clearOnHide: true, + customDefaultValue: "", + calculateValue: "", + calculateServer: false, + allowCalculateOverride: false, + validateOn: "change", + validate: { + required: true, + pattern: "", + customMessage: "", + custom: "", + customPrivate: false, + json: "", + minLength: "", + maxLength: "", + strictDateValidation: false, + multiple: false, + unique: false + }, + unique: false, + errorLabel: "", + key: "textField", + tags: [], + properties: {}, + conditional: { show: null, when: null, eq: "", json: "" }, + customConditional: "", + logic: [], + attributes: {}, + overlay: { + style: "", + page: "", + left: "", + top: "", + width: "", + height: "" + }, + type: "textfield", + input: true, + refreshOn: "", + inputType: "text", + id: "eqb1o4r", + defaultValue: "" + } + ], + title: "text-field", + display: "form", + access: [ + { + roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"], + type: "read_all" + } + ], + submissionAccess: [], + controller: "", + properties: {}, + settings: {}, + name: "textField", + path: "textfield", + machineName: "tcspjwhsevrzpcd:textField" + } +}; + +function App() { + return ( +
+ +
+ ); +} + +export default App; diff --git a/packages/integration/src/assets/react.svg b/packages/integration/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/packages/integration/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/integration/src/main.tsx b/packages/integration/src/main.tsx new file mode 100644 index 00000000..72b1d875 --- /dev/null +++ b/packages/integration/src/main.tsx @@ -0,0 +1,18 @@ +import "./styles/index.css"; + +import { Formio, Templates } from "@tsed/react-formio"; +import tailwind from "@tsed/tailwind-formio"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; + +import App from "./App"; + +// eslint-disable-next-line react-hooks/rules-of-hooks +Formio.use(tailwind); +Templates.framework = "tailwind"; + +createRoot(document.getElementById("root")!).render( + + + +); diff --git a/packages/integration/src/styles/fonts/bxicons/animations.css b/packages/integration/src/styles/fonts/bxicons/animations.css new file mode 100644 index 00000000..a7c97930 --- /dev/null +++ b/packages/integration/src/styles/fonts/bxicons/animations.css @@ -0,0 +1,341 @@ +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-webkit-keyframes burst { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + + opacity: 1; + } + 90% { + -webkit-transform: scale(1.5); + transform: scale(1.5); + + opacity: 0; + } +} + +@keyframes burst { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + + opacity: 1; + } + 90% { + -webkit-transform: scale(1.5); + transform: scale(1.5); + + opacity: 0; + } +} + +@-webkit-keyframes flashing { + 0% { + opacity: 1; + } + 45% { + opacity: 0; + } + 90% { + opacity: 1; + } +} + +@keyframes flashing { + 0% { + opacity: 1; + } + 45% { + opacity: 0; + } + 90% { + opacity: 1; + } +} + +@-webkit-keyframes fade-left { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + + opacity: 0; + } +} + +@keyframes fade-left { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-right { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(20px); + transform: translateX(20px); + + opacity: 0; + } +} + +@keyframes fade-right { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(20px); + transform: translateX(20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-up { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + + opacity: 0; + } +} + +@keyframes fade-up { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-down { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(20px); + transform: translateY(20px); + + opacity: 0; + } +} + +@keyframes fade-down { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(20px); + transform: translateY(20px); + + opacity: 0; + } +} + +@-webkit-keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.bx-spin { + -webkit-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +.bx-spin-hover:hover { + -webkit-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +.bx-tada { + -webkit-animation: tada 1.5s ease infinite; + animation: tada 1.5s ease infinite; +} + +.bx-tada-hover:hover { + -webkit-animation: tada 1.5s ease infinite; + animation: tada 1.5s ease infinite; +} + +.bx-flashing { + -webkit-animation: flashing 1.5s infinite linear; + animation: flashing 1.5s infinite linear; +} + +.bx-flashing-hover:hover { + -webkit-animation: flashing 1.5s infinite linear; + animation: flashing 1.5s infinite linear; +} + +.bx-burst { + -webkit-animation: burst 1.5s infinite linear; + animation: burst 1.5s infinite linear; +} + +.bx-burst-hover:hover { + -webkit-animation: burst 1.5s infinite linear; + animation: burst 1.5s infinite linear; +} + +.bx-fade-up { + -webkit-animation: fade-up 1.5s infinite linear; + animation: fade-up 1.5s infinite linear; +} + +.bx-fade-up-hover:hover { + -webkit-animation: fade-up 1.5s infinite linear; + animation: fade-up 1.5s infinite linear; +} + +.bx-fade-down { + -webkit-animation: fade-down 1.5s infinite linear; + animation: fade-down 1.5s infinite linear; +} + +.bx-fade-down-hover:hover { + -webkit-animation: fade-down 1.5s infinite linear; + animation: fade-down 1.5s infinite linear; +} + +.bx-fade-left { + -webkit-animation: fade-left 1.5s infinite linear; + animation: fade-left 1.5s infinite linear; +} + +.bx-fade-left-hover:hover { + -webkit-animation: fade-left 1.5s infinite linear; + animation: fade-left 1.5s infinite linear; +} + +.bx-fade-right { + -webkit-animation: fade-right 1.5s infinite linear; + animation: fade-right 1.5s infinite linear; +} + +.bx-fade-right-hover:hover { + -webkit-animation: fade-right 1.5s infinite linear; + animation: fade-right 1.5s infinite linear; +} \ No newline at end of file diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.css b/packages/integration/src/styles/fonts/bxicons/boxicons.css new file mode 100644 index 00000000..ee25cb0a --- /dev/null +++ b/packages/integration/src/styles/fonts/bxicons/boxicons.css @@ -0,0 +1,6477 @@ +@font-face { + font-family: 'boxicons'; + font-weight: normal; + font-style: normal; + + src: url('boxicons.eot'); + src: url('boxicons.eot') format('embedded-opentype'), + url('boxicons.woff2') format('woff2'), + url('boxicons.woff') format('woff'), + url('boxicons.ttf') format('truetype'), + url('boxicons.svg?#boxicons') format('svg'); +} + +.bx { + font-family: 'boxicons' !important; + font-weight: normal; + font-style: normal; + font-variant: normal; + line-height: 1; + + display: inline-block; + + text-transform: none; + + speak: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bx-ul { + margin-left: 2em; + padding-left: 0; + + list-style: none; +} + +.bx-ul > li { + position: relative; +} + +.bx-ul .bx { + font-size: inherit; + line-height: inherit; + + position: absolute; + left: -2em; + + width: 2em; + + text-align: center; +} + +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@-webkit-keyframes burst { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + + opacity: 1; + } + 90% { + -webkit-transform: scale(1.5); + transform: scale(1.5); + + opacity: 0; + } +} + +@keyframes burst { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + + opacity: 1; + } + 90% { + -webkit-transform: scale(1.5); + transform: scale(1.5); + + opacity: 0; + } +} + +@-webkit-keyframes flashing { + 0% { + opacity: 1; + } + 45% { + opacity: 0; + } + 90% { + opacity: 1; + } +} + +@keyframes flashing { + 0% { + opacity: 1; + } + 45% { + opacity: 0; + } + 90% { + opacity: 1; + } +} + +@-webkit-keyframes fade-left { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + + opacity: 0; + } +} + +@keyframes fade-left { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(-20px); + transform: translateX(-20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-right { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(20px); + transform: translateX(20px); + + opacity: 0; + } +} + +@keyframes fade-right { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateX(20px); + transform: translateX(20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-up { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + + opacity: 0; + } +} + +@keyframes fade-up { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + + opacity: 0; + } +} + +@-webkit-keyframes fade-down { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(20px); + transform: translateY(20px); + + opacity: 0; + } +} + +@keyframes fade-down { + 0% { + -webkit-transform: translateY(0); + transform: translateY(0); + + opacity: 1; + } + 75% { + -webkit-transform: translateY(20px); + transform: translateY(20px); + + opacity: 0; + } +} + +@-webkit-keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, -10deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + transform: scale3d(.95, .95, .95) rotate3d(0, 0, 1, -10deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + transform: scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.bx-spin { + -webkit-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +.bx-spin-hover:hover { + -webkit-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; +} + +.bx-tada { + -webkit-animation: tada 1.5s ease infinite; + animation: tada 1.5s ease infinite; +} + +.bx-tada-hover:hover { + -webkit-animation: tada 1.5s ease infinite; + animation: tada 1.5s ease infinite; +} + +.bx-flashing { + -webkit-animation: flashing 1.5s infinite linear; + animation: flashing 1.5s infinite linear; +} + +.bx-flashing-hover:hover { + -webkit-animation: flashing 1.5s infinite linear; + animation: flashing 1.5s infinite linear; +} + +.bx-burst { + -webkit-animation: burst 1.5s infinite linear; + animation: burst 1.5s infinite linear; +} + +.bx-burst-hover:hover { + -webkit-animation: burst 1.5s infinite linear; + animation: burst 1.5s infinite linear; +} + +.bx-fade-up { + -webkit-animation: fade-up 1.5s infinite linear; + animation: fade-up 1.5s infinite linear; +} + +.bx-fade-up-hover:hover { + -webkit-animation: fade-up 1.5s infinite linear; + animation: fade-up 1.5s infinite linear; +} + +.bx-fade-down { + -webkit-animation: fade-down 1.5s infinite linear; + animation: fade-down 1.5s infinite linear; +} + +.bx-fade-down-hover:hover { + -webkit-animation: fade-down 1.5s infinite linear; + animation: fade-down 1.5s infinite linear; +} + +.bx-fade-left { + -webkit-animation: fade-left 1.5s infinite linear; + animation: fade-left 1.5s infinite linear; +} + +.bx-fade-left-hover:hover { + -webkit-animation: fade-left 1.5s infinite linear; + animation: fade-left 1.5s infinite linear; +} + +.bx-fade-right { + -webkit-animation: fade-right 1.5s infinite linear; + animation: fade-right 1.5s infinite linear; +} + +.bx-fade-right-hover:hover { + -webkit-animation: fade-right 1.5s infinite linear; + animation: fade-right 1.5s infinite linear; +} + +.bx-xs { + font-size: 1rem !important; +} + +.bx-sm { + font-size: 1.55rem !important; +} + +.bx-md { + font-size: 2.25rem !important; +} + +.bx-fw { + font-size: 1.2857142857em; + line-height: .8em; + + width: 1.2857142857em; + height: .8em; + margin-top: -.2em !important; + + vertical-align: middle; +} + +.bx-lg { + font-size: 3.0rem !important; +} + +.bx-pull-left { + float: left; + + margin-right: .3em !important; +} + +.bx-pull-right { + float: right; + + margin-left: .3em !important; +} + +.bx-rotate-90 { + transform: rotate(90deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)'; +} + +.bx-rotate-180 { + transform: rotate(180deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)'; +} + +.bx-rotate-270 { + transform: rotate(270deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; +} + +.bx-flip-horizontal { + transform: scaleX(-1); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)'; +} + +.bx-flip-vertical { + transform: scaleY(-1); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)'; +} + +.bx-border { + padding: .25em; + + border: .07em solid rgba(0, 0, 0, .1); + border-radius: .25em; +} + +.bx-border-circle { + padding: .25em; + + border: .07em solid rgba(0, 0, 0, .1); + border-radius: 50%; +} + +.bx-abacus:before { + content: "\e900"; +} + +.bx-accessibility:before { + content: "\e901"; +} + +.bx-add-to-queue:before { + content: "\e902"; +} + +.bx-adjust:before { + content: "\e903"; +} + +.bx-alarm:before { + content: "\e904"; +} + +.bx-alarm-add:before { + content: "\e905"; +} + +.bx-alarm-exclamation:before { + content: "\e906"; +} + +.bx-alarm-off:before { + content: "\e907"; +} + +.bx-alarm-snooze:before { + content: "\e908"; +} + +.bx-album:before { + content: "\e909"; +} + +.bx-align-justify:before { + content: "\e90a"; +} + +.bx-align-left:before { + content: "\e90b"; +} + +.bx-align-middle:before { + content: "\e90c"; +} + +.bx-align-right:before { + content: "\e90d"; +} + +.bx-analyse:before { + content: "\e90e"; +} + +.bx-anchor:before { + content: "\e90f"; +} + +.bx-angry:before { + content: "\e910"; +} + +.bx-aperture:before { + content: "\e911"; +} + +.bx-arch:before { + content: "\e912"; +} + +.bx-archive:before { + content: "\e913"; +} + +.bx-archive-in:before { + content: "\e914"; +} + +.bx-archive-out:before { + content: "\e915"; +} + +.bx-area:before { + content: "\e916"; +} + +.bx-arrow-back:before { + content: "\e917"; +} + +.bx-arrow-from-bottom:before { + content: "\e918"; +} + +.bx-arrow-from-left:before { + content: "\e919"; +} + +.bx-arrow-from-right:before { + content: "\e91a"; +} + +.bx-arrow-from-top:before { + content: "\e91b"; +} + +.bx-arrow-to-bottom:before { + content: "\e91c"; +} + +.bx-arrow-to-left:before { + content: "\e91d"; +} + +.bx-arrow-to-right:before { + content: "\e91e"; +} + +.bx-arrow-to-top:before { + content: "\e91f"; +} + +.bx-at:before { + content: "\e920"; +} + +.bx-atom:before { + content: "\e921"; +} + +.bx-award:before { + content: "\e922"; +} + +.bx-badge:before { + content: "\e923"; +} + +.bx-badge-check:before { + content: "\e924"; +} + +.bx-ball:before { + content: "\e925"; +} + +.bx-band-aid:before { + content: "\e926"; +} + +.bx-bar-chart:before { + content: "\e927"; +} + +.bx-bar-chart-alt:before { + content: "\e928"; +} + +.bx-bar-chart-alt-2:before { + content: "\e929"; +} + +.bx-bar-chart-square:before { + content: "\e92a"; +} + +.bx-barcode:before { + content: "\e92b"; +} + +.bx-barcode-reader:before { + content: "\e92c"; +} + +.bx-baseball:before { + content: "\e92d"; +} + +.bx-basket:before { + content: "\e92e"; +} + +.bx-basketball:before { + content: "\e92f"; +} + +.bx-bath:before { + content: "\e930"; +} + +.bx-battery:before { + content: "\e931"; +} + +.bx-bed:before { + content: "\e932"; +} + +.bx-been-here:before { + content: "\e933"; +} + +.bx-beer:before { + content: "\e934"; +} + +.bx-bell:before { + content: "\e935"; +} + +.bx-bell-minus:before { + content: "\e936"; +} + +.bx-bell-off:before { + content: "\e937"; +} + +.bx-bell-plus:before { + content: "\e938"; +} + +.bx-bible:before { + content: "\e939"; +} + +.bx-bitcoin:before { + content: "\e93a"; +} + +.bx-blanket:before { + content: "\e93b"; +} + +.bx-block:before { + content: "\e93c"; +} + +.bx-bluetooth:before { + content: "\e93d"; +} + +.bx-body:before { + content: "\e93e"; +} + +.bx-bold:before { + content: "\e93f"; +} + +.bx-bolt-circle:before { + content: "\e940"; +} + +.bx-bomb:before { + content: "\e941"; +} + +.bx-bone:before { + content: "\e942"; +} + +.bx-bong:before { + content: "\e943"; +} + +.bx-book:before { + content: "\e944"; +} + +.bx-book-add:before { + content: "\e945"; +} + +.bx-book-alt:before { + content: "\e946"; +} + +.bx-book-bookmark:before { + content: "\e947"; +} + +.bx-book-content:before { + content: "\e948"; +} + +.bx-book-heart:before { + content: "\e949"; +} + +.bx-bookmark:before { + content: "\e94a"; +} + +.bx-bookmark-alt:before { + content: "\e94b"; +} + +.bx-bookmark-alt-minus:before { + content: "\e94c"; +} + +.bx-bookmark-alt-plus:before { + content: "\e94d"; +} + +.bx-bookmark-heart:before { + content: "\e94e"; +} + +.bx-bookmark-minus:before { + content: "\e94f"; +} + +.bx-bookmark-plus:before { + content: "\e950"; +} + +.bx-bookmarks:before { + content: "\e951"; +} + +.bx-book-open:before { + content: "\e952"; +} + +.bx-book-reader:before { + content: "\e953"; +} + +.bx-border-all:before { + content: "\e954"; +} + +.bx-border-bottom:before { + content: "\e955"; +} + +.bx-border-inner:before { + content: "\e956"; +} + +.bx-border-left:before { + content: "\e957"; +} + +.bx-border-none:before { + content: "\e958"; +} + +.bx-border-outer:before { + content: "\e959"; +} + +.bx-border-radius:before { + content: "\e95a"; +} + +.bx-border-right:before { + content: "\e95b"; +} + +.bx-border-top:before { + content: "\e95c"; +} + +.bx-bot:before { + content: "\e95d"; +} + +.bx-bowling-ball:before { + content: "\e95e"; +} + +.bx-box:before { + content: "\e95f"; +} + +.bx-bracket:before { + content: "\e960"; +} + +.bx-braille:before { + content: "\e961"; +} + +.bx-brain:before { + content: "\e962"; +} + +.bx-briefcase:before { + content: "\e963"; +} + +.bx-briefcase-alt:before { + content: "\e964"; +} + +.bx-briefcase-alt-2:before { + content: "\e965"; +} + +.bx-brightness:before { + content: "\e966"; +} + +.bx-brightness-half:before { + content: "\e967"; +} + +.bx-broadcast:before { + content: "\e968"; +} + +.bx-brush:before { + content: "\e969"; +} + +.bx-brush-alt:before { + content: "\e96a"; +} + +.bx-bug:before { + content: "\e96b"; +} + +.bx-bug-alt:before { + content: "\e96c"; +} + +.bx-building:before { + content: "\e96d"; +} + +.bx-building-house:before { + content: "\e96e"; +} + +.bx-buildings:before { + content: "\e96f"; +} + +.bx-bulb:before { + content: "\e970"; +} + +.bx-bullseye:before { + content: "\e971"; +} + +.bx-buoy:before { + content: "\e972"; +} + +.bx-bus:before { + content: "\e973"; +} + +.bx-bus-school:before { + content: "\e974"; +} + +.bx-cabinet:before { + content: "\e975"; +} + +.bx-cake:before { + content: "\e976"; +} + +.bx-calculator:before { + content: "\e977"; +} + +.bx-calendar:before { + content: "\e978"; +} + +.bx-calendar-alt:before { + content: "\e979"; +} + +.bx-calendar-check:before { + content: "\e97a"; +} + +.bx-calendar-edit:before { + content: "\e97b"; +} + +.bx-calendar-event:before { + content: "\e97c"; +} + +.bx-calendar-exclamation:before { + content: "\e97d"; +} + +.bx-calendar-heart:before { + content: "\e97e"; +} + +.bx-calendar-minus:before { + content: "\e97f"; +} + +.bx-calendar-plus:before { + content: "\e980"; +} + +.bx-calendar-star:before { + content: "\e981"; +} + +.bx-calendar-week:before { + content: "\e982"; +} + +.bx-calendar-x:before { + content: "\e983"; +} + +.bx-camera:before { + content: "\e984"; +} + +.bx-camera-home:before { + content: "\e985"; +} + +.bx-camera-movie:before { + content: "\e986"; +} + +.bx-camera-off:before { + content: "\e987"; +} + +.bx-capsule:before { + content: "\e988"; +} + +.bx-captions:before { + content: "\e989"; +} + +.bx-car:before { + content: "\e98a"; +} + +.bx-card:before { + content: "\e98b"; +} + +.bx-caret-down:before { + content: "\e98c"; +} + +.bx-caret-down-circle:before { + content: "\e98d"; +} + +.bx-caret-down-square:before { + content: "\e98e"; +} + +.bx-caret-left:before { + content: "\e98f"; +} + +.bx-caret-left-circle:before { + content: "\e990"; +} + +.bx-caret-left-square:before { + content: "\e991"; +} + +.bx-caret-right:before { + content: "\e992"; +} + +.bx-caret-right-circle:before { + content: "\e993"; +} + +.bx-caret-right-square:before { + content: "\e994"; +} + +.bx-caret-up:before { + content: "\e995"; +} + +.bx-caret-up-circle:before { + content: "\e996"; +} + +.bx-caret-up-square:before { + content: "\e997"; +} + +.bx-carousel:before { + content: "\e998"; +} + +.bx-cart:before { + content: "\e999"; +} + +.bx-cart-alt:before { + content: "\e99a"; +} + +.bx-cast:before { + content: "\e99b"; +} + +.bx-category:before { + content: "\e99c"; +} + +.bx-category-alt:before { + content: "\e99d"; +} + +.bx-cctv:before { + content: "\e99e"; +} + +.bx-certification:before { + content: "\e99f"; +} + +.bx-chair:before { + content: "\e9a0"; +} + +.bx-chalkboard:before { + content: "\e9a1"; +} + +.bx-chart:before { + content: "\e9a2"; +} + +.bx-chat:before { + content: "\e9a3"; +} + +.bx-check:before { + content: "\e9a4"; +} + +.bx-checkbox:before { + content: "\e9a5"; +} + +.bx-checkbox-checked:before { + content: "\e9a6"; +} + +.bx-checkbox-square:before { + content: "\e9a7"; +} + +.bx-check-circle:before { + content: "\e9a8"; +} + +.bx-check-double:before { + content: "\e9a9"; +} + +.bx-check-shield:before { + content: "\e9aa"; +} + +.bx-check-square:before { + content: "\e9ab"; +} + +.bx-chevron-down:before { + content: "\e9ac"; +} + +.bx-chevron-down-circle:before { + content: "\e9ad"; +} + +.bx-chevron-down-square:before { + content: "\e9ae"; +} + +.bx-chevron-left:before { + content: "\e9af"; +} + +.bx-chevron-left-circle:before { + content: "\e9b0"; +} + +.bx-chevron-left-square:before { + content: "\e9b1"; +} + +.bx-chevron-right:before { + content: "\e9b2"; +} + +.bx-chevron-right-circle:before { + content: "\e9b3"; +} + +.bx-chevron-right-square:before { + content: "\e9b4"; +} + +.bx-chevrons-down:before { + content: "\e9b5"; +} + +.bx-chevrons-left:before { + content: "\e9b6"; +} + +.bx-chevrons-right:before { + content: "\e9b7"; +} + +.bx-chevrons-up:before { + content: "\e9b8"; +} + +.bx-chevron-up:before { + content: "\e9b9"; +} + +.bx-chevron-up-circle:before { + content: "\e9ba"; +} + +.bx-chevron-up-square:before { + content: "\e9bb"; +} + +.bx-chip:before { + content: "\e9bc"; +} + +.bx-church:before { + content: "\e9bd"; +} + +.bx-circle:before { + content: "\e9be"; +} + +.bx-clinic:before { + content: "\e9bf"; +} + +.bx-clipboard:before { + content: "\e9c0"; +} + +.bx-closet:before { + content: "\e9c1"; +} + +.bx-cloud:before { + content: "\e9c2"; +} + +.bx-cloud-download:before { + content: "\e9c3"; +} + +.bx-cloud-drizzle:before { + content: "\e9c4"; +} + +.bx-cloud-lightning:before { + content: "\e9c5"; +} + +.bx-cloud-light-rain:before { + content: "\e9c6"; +} + +.bx-cloud-rain:before { + content: "\e9c7"; +} + +.bx-cloud-snow:before { + content: "\e9c8"; +} + +.bx-cloud-upload:before { + content: "\e9c9"; +} + +.bx-code:before { + content: "\e9ca"; +} + +.bx-code-alt:before { + content: "\e9cb"; +} + +.bx-code-block:before { + content: "\e9cc"; +} + +.bx-code-curly:before { + content: "\e9cd"; +} + +.bx-coffee:before { + content: "\e9ce"; +} + +.bx-coffee-togo:before { + content: "\e9cf"; +} + +.bx-cog:before { + content: "\e9d0"; +} + +.bx-coin:before { + content: "\e9d1"; +} + +.bx-coin-stack:before { + content: "\e9d2"; +} + +.bx-collapse:before { + content: "\e9d3"; +} + +.bx-collection:before { + content: "\e9d4"; +} + +.bx-color-fill:before { + content: "\e9d5"; +} + +.bx-columns:before { + content: "\e9d6"; +} + +.bx-command:before { + content: "\e9d7"; +} + +.bx-comment:before { + content: "\e9d8"; +} + +.bx-comment-add:before { + content: "\e9d9"; +} + +.bx-comment-check:before { + content: "\e9da"; +} + +.bx-comment-detail:before { + content: "\e9db"; +} + +.bx-comment-dots:before { + content: "\e9dc"; +} + +.bx-comment-edit:before { + content: "\e9dd"; +} + +.bx-comment-error:before { + content: "\e9de"; +} + +.bx-comment-minus:before { + content: "\e9df"; +} + +.bx-comment-x:before { + content: "\e9e0"; +} + +.bx-compass:before { + content: "\e9e1"; +} + +.bx-confused:before { + content: "\e9e2"; +} + +.bx-conversation:before { + content: "\e9e3"; +} + +.bx-cookie:before { + content: "\e9e4"; +} + +.bx-cool:before { + content: "\e9e5"; +} + +.bx-copy:before { + content: "\e9e6"; +} + +.bx-copy-alt:before { + content: "\e9e7"; +} + +.bx-copyright:before { + content: "\e9e8"; +} + +.bx-credit-card:before { + content: "\e9e9"; +} + +.bx-credit-card-alt:before { + content: "\e9ea"; +} + +.bx-credit-card-front:before { + content: "\e9eb"; +} + +.bx-crop:before { + content: "\e9ec"; +} + +.bx-crosshair:before { + content: "\e9ed"; +} + +.bx-crown:before { + content: "\e9ee"; +} + +.bx-cube:before { + content: "\e9ef"; +} + +.bx-cube-alt:before { + content: "\e9f0"; +} + +.bx-cuboid:before { + content: "\e9f1"; +} + +.bx-current-location:before { + content: "\e9f2"; +} + +.bx-customize:before { + content: "\e9f3"; +} + +.bx-cut:before { + content: "\e9f4"; +} + +.bx-cycling:before { + content: "\e9f5"; +} + +.bx-cylinder:before { + content: "\e9f6"; +} + +.bx-data:before { + content: "\e9f7"; +} + +.bx-desktop:before { + content: "\e9f8"; +} + +.bx-detail:before { + content: "\e9f9"; +} + +.bx-devices:before { + content: "\e9fa"; +} + +.bx-dialpad:before { + content: "\e9fb"; +} + +.bx-dialpad-alt:before { + content: "\e9fc"; +} + +.bx-diamond:before { + content: "\e9fd"; +} + +.bx-dice-1:before { + content: "\e9fe"; +} + +.bx-dice-2:before { + content: "\e9ff"; +} + +.bx-dice-3:before { + content: "\ea00"; +} + +.bx-dice-4:before { + content: "\ea01"; +} + +.bx-dice-5:before { + content: "\ea02"; +} + +.bx-dice-6:before { + content: "\ea03"; +} + +.bx-directions:before { + content: "\ea04"; +} + +.bx-disc:before { + content: "\ea05"; +} + +.bx-dish:before { + content: "\ea06"; +} + +.bx-dislike:before { + content: "\ea07"; +} + +.bx-dizzy:before { + content: "\ea08"; +} + +.bx-dna:before { + content: "\ea09"; +} + +.bx-dock-bottom:before { + content: "\ea0a"; +} + +.bx-dock-left:before { + content: "\ea0b"; +} + +.bx-dock-right:before { + content: "\ea0c"; +} + +.bx-dock-top:before { + content: "\ea0d"; +} + +.bx-dollar:before { + content: "\ea0e"; +} + +.bx-dollar-circle:before { + content: "\ea0f"; +} + +.bx-donate-blood:before { + content: "\ea10"; +} + +.bx-donate-heart:before { + content: "\ea11"; +} + +.bx-door-open:before { + content: "\ea12"; +} + +.bx-dots-horizontal:before { + content: "\ea13"; +} + +.bx-dots-horizontal-rounded:before { + content: "\ea14"; +} + +.bx-dots-vertical:before { + content: "\ea15"; +} + +.bx-dots-vertical-rounded:before { + content: "\ea16"; +} + +.bx-doughnut-chart:before { + content: "\ea17"; +} + +.bx-down-arrow:before { + content: "\ea18"; +} + +.bx-down-arrow-alt:before { + content: "\ea19"; +} + +.bx-down-arrow-circle:before { + content: "\ea1a"; +} + +.bx-download:before { + content: "\ea1b"; +} + +.bx-downvote:before { + content: "\ea1c"; +} + +.bx-drink:before { + content: "\ea1d"; +} + +.bx-droplet:before { + content: "\ea1e"; +} + +.bx-dumbbell:before { + content: "\ea1f"; +} + +.bx-duplicate:before { + content: "\ea20"; +} + +.bx-edit:before { + content: "\ea21"; +} + +.bx-edit-alt:before { + content: "\ea22"; +} + +.bx-envelope:before { + content: "\ea23"; +} + +.bx-envelope-open:before { + content: "\ea24"; +} + +.bx-equalizer:before { + content: "\ea25"; +} + +.bx-eraser:before { + content: "\ea26"; +} + +.bx-error:before { + content: "\ea27"; +} + +.bx-error-alt:before { + content: "\ea28"; +} + +.bx-error-circle:before { + content: "\ea29"; +} + +.bx-euro:before { + content: "\ea2a"; +} + +.bx-exclude:before { + content: "\ea2b"; +} + +.bx-exit:before { + content: "\ea2c"; +} + +.bx-exit-fullscreen:before { + content: "\ea2d"; +} + +.bx-expand:before { + content: "\ea2e"; +} + +.bx-expand-alt:before { + content: "\ea2f"; +} + +.bx-export:before { + content: "\ea30"; +} + +.bx-extension:before { + content: "\ea31"; +} + +.bx-face:before { + content: "\ea32"; +} + +.bx-fast-forward:before { + content: "\ea33"; +} + +.bx-fast-forward-circle:before { + content: "\ea34"; +} + +.bx-female:before { + content: "\ea35"; +} + +.bx-female-sign:before { + content: "\ea36"; +} + +.bx-file:before { + content: "\ea37"; +} + +.bx-file-blank:before { + content: "\ea38"; +} + +.bx-file-find:before { + content: "\ea39"; +} + +.bx-film:before { + content: "\ea3a"; +} + +.bx-filter:before { + content: "\ea3b"; +} + +.bx-filter-alt:before { + content: "\ea3c"; +} + +.bx-fingerprint:before { + content: "\ea3d"; +} + +.bx-first-aid:before { + content: "\ea3e"; +} + +.bx-first-page:before { + content: "\ea3f"; +} + +.bx-flag:before { + content: "\ea40"; +} + +.bx-folder:before { + content: "\ea41"; +} + +.bx-folder-minus:before { + content: "\ea42"; +} + +.bx-folder-open:before { + content: "\ea43"; +} + +.bx-folder-plus:before { + content: "\ea44"; +} + +.bx-font:before { + content: "\ea45"; +} + +.bx-font-color:before { + content: "\ea46"; +} + +.bx-font-family:before { + content: "\ea47"; +} + +.bx-font-size:before { + content: "\ea48"; +} + +.bx-food-menu:before { + content: "\ea49"; +} + +.bx-food-tag:before { + content: "\ea4a"; +} + +.bx-football:before { + content: "\ea4b"; +} + +.bx-fridge:before { + content: "\ea4c"; +} + +.bx-fullscreen:before { + content: "\ea4d"; +} + +.bx-game:before { + content: "\ea4e"; +} + +.bx-gas-pump:before { + content: "\ea4f"; +} + +.bx-ghost:before { + content: "\ea50"; +} + +.bx-gift:before { + content: "\ea51"; +} + +.bx-git-branch:before { + content: "\ea52"; +} + +.bx-git-commit:before { + content: "\ea53"; +} + +.bx-git-compare:before { + content: "\ea54"; +} + +.bx-git-merge:before { + content: "\ea55"; +} + +.bx-git-pull-request:before { + content: "\ea56"; +} + +.bx-git-repo-forked:before { + content: "\ea57"; +} + +.bx-glasses:before { + content: "\ea58"; +} + +.bx-glasses-alt:before { + content: "\ea59"; +} + +.bx-globe:before { + content: "\ea5a"; +} + +.bx-globe-alt:before { + content: "\ea5b"; +} + +.bx-grid:before { + content: "\ea5c"; +} + +.bx-grid-alt:before { + content: "\ea5d"; +} + +.bx-grid-horizontal:before { + content: "\ea5e"; +} + +.bx-grid-small:before { + content: "\ea5f"; +} + +.bx-grid-vertical:before { + content: "\ea60"; +} + +.bx-group:before { + content: "\ea61"; +} + +.bx-handicap:before { + content: "\ea62"; +} + +.bx-happy:before { + content: "\ea63"; +} + +.bx-happy-alt:before { + content: "\ea64"; +} + +.bx-happy-beaming:before { + content: "\ea65"; +} + +.bx-happy-heart-eyes:before { + content: "\ea66"; +} + +.bx-hash:before { + content: "\ea67"; +} + +.bx-hdd:before { + content: "\ea68"; +} + +.bx-heading:before { + content: "\ea69"; +} + +.bx-headphone:before { + content: "\ea6a"; +} + +.bx-health:before { + content: "\ea6b"; +} + +.bx-heart:before { + content: "\ea6c"; +} + +.bx-heart-circle:before { + content: "\ea6d"; +} + +.bx-heart-square:before { + content: "\ea6e"; +} + +.bx-help-circle:before { + content: "\ea6f"; +} + +.bx-hide:before { + content: "\ea70"; +} + +.bx-highlight:before { + content: "\ea71"; +} + +.bx-history:before { + content: "\ea72"; +} + +.bx-hive:before { + content: "\ea73"; +} + +.bx-home:before { + content: "\ea74"; +} + +.bx-home-alt:before { + content: "\ea75"; +} + +.bx-home-circle:before { + content: "\ea76"; +} + +.bx-home-heart:before { + content: "\ea77"; +} + +.bx-home-smile:before { + content: "\ea78"; +} + +.bx-horizontal-center:before { + content: "\ea79"; +} + +.bx-hotel:before { + content: "\ea7a"; +} + +.bx-hourglass:before { + content: "\ea7b"; +} + +.bx-id-card:before { + content: "\ea7c"; +} + +.bx-image:before { + content: "\ea7d"; +} + +.bx-image-add:before { + content: "\ea7e"; +} + +.bx-image-alt:before { + content: "\ea7f"; +} + +.bx-images:before { + content: "\ea80"; +} + +.bx-import:before { + content: "\ea81"; +} + +.bx-infinite:before { + content: "\ea82"; +} + +.bx-info-circle:before { + content: "\ea83"; +} + +.bx-info-square:before { + content: "\ea84"; +} + +.bx-intersect:before { + content: "\ea85"; +} + +.bx-italic:before { + content: "\ea86"; +} + +.bx-joystick:before { + content: "\ea87"; +} + +.bx-joystick-alt:before { + content: "\ea88"; +} + +.bx-joystick-button:before { + content: "\ea89"; +} + +.bx-key:before { + content: "\ea8a"; +} + +.bx-label:before { + content: "\ea8b"; +} + +.bx-landscape:before { + content: "\ea8c"; +} + +.bx-laptop:before { + content: "\ea8d"; +} + +.bx-last-page:before { + content: "\ea8e"; +} + +.bx-laugh:before { + content: "\ea8f"; +} + +.bx-layer:before { + content: "\ea90"; +} + +.bx-layer-minus:before { + content: "\ea91"; +} + +.bx-layer-plus:before { + content: "\ea92"; +} + +.bx-layout:before { + content: "\ea93"; +} + +.bx-left-arrow:before { + content: "\ea94"; +} + +.bx-left-arrow-alt:before { + content: "\ea95"; +} + +.bx-left-arrow-circle:before { + content: "\ea96"; +} + +.bx-left-down-arrow-circle:before { + content: "\ea97"; +} + +.bx-left-indent:before { + content: "\ea98"; +} + +.bx-left-top-arrow-circle:before { + content: "\ea99"; +} + +.bx-library:before { + content: "\ea9a"; +} + +.bx-like:before { + content: "\ea9b"; +} + +.bx-line-chart:before { + content: "\ea9c"; +} + +.bx-line-chart-down:before { + content: "\ea9d"; +} + +.bx-link:before { + content: "\ea9e"; +} + +.bx-link-alt:before { + content: "\ea9f"; +} + +.bx-link-external:before { + content: "\eaa0"; +} + +.bx-lira:before { + content: "\eaa1"; +} + +.bx-list-check:before { + content: "\eaa2"; +} + +.bx-list-minus:before { + content: "\eaa3"; +} + +.bx-list-ol:before { + content: "\eaa4"; +} + +.bx-list-plus:before { + content: "\eaa5"; +} + +.bx-list-ul:before { + content: "\eaa6"; +} + +.bx-loader:before { + content: "\eaa7"; +} + +.bx-loader-alt:before { + content: "\eaa8"; +} + +.bx-loader-circle:before { + content: "\eaa9"; +} + +.bx-location-plus:before { + content: "\eaaa"; +} + +.bx-lock:before { + content: "\eaab"; +} + +.bx-lock-alt:before { + content: "\eaac"; +} + +.bx-lock-open:before { + content: "\eaad"; +} + +.bx-lock-open-alt:before { + content: "\eaae"; +} + +.bx-log-in:before { + content: "\eaaf"; +} + +.bx-log-in-circle:before { + content: "\eab0"; +} + +.bx-log-out:before { + content: "\eab1"; +} + +.bx-log-out-circle:before { + content: "\eab2"; +} + +.bx-low-vision:before { + content: "\eab3"; +} + +.bx-magnet:before { + content: "\eab4"; +} + +.bx-mail-send:before { + content: "\eab5"; +} + +.bx-male:before { + content: "\eab6"; +} + +.bx-male-sign:before { + content: "\eab7"; +} + +.bx-map:before { + content: "\eab8"; +} + +.bx-map-alt:before { + content: "\eab9"; +} + +.bx-map-pin:before { + content: "\eaba"; +} + +.bx-mask:before { + content: "\eabb"; +} + +.bx-medal:before { + content: "\eabc"; +} + +.bx-meh:before { + content: "\eabd"; +} + +.bx-meh-alt:before { + content: "\eabe"; +} + +.bx-meh-blank:before { + content: "\eabf"; +} + +.bx-memory-card:before { + content: "\eac0"; +} + +.bx-menu:before { + content: "\eac1"; +} + +.bx-menu-alt-left:before { + content: "\eac2"; +} + +.bx-menu-alt-right:before { + content: "\eac3"; +} + +.bx-merge:before { + content: "\eac4"; +} + +.bx-message:before { + content: "\eac5"; +} + +.bx-message-add:before { + content: "\eac6"; +} + +.bx-message-alt:before { + content: "\eac7"; +} + +.bx-message-alt-add:before { + content: "\eac8"; +} + +.bx-message-alt-check:before { + content: "\eac9"; +} + +.bx-message-alt-detail:before { + content: "\eaca"; +} + +.bx-message-alt-dots:before { + content: "\eacb"; +} + +.bx-message-alt-edit:before { + content: "\eacc"; +} + +.bx-message-alt-error:before { + content: "\eacd"; +} + +.bx-message-alt-minus:before { + content: "\eace"; +} + +.bx-message-alt-x:before { + content: "\eacf"; +} + +.bx-message-check:before { + content: "\ead0"; +} + +.bx-message-detail:before { + content: "\ead1"; +} + +.bx-message-dots:before { + content: "\ead2"; +} + +.bx-message-edit:before { + content: "\ead3"; +} + +.bx-message-error:before { + content: "\ead4"; +} + +.bx-message-minus:before { + content: "\ead5"; +} + +.bx-message-rounded:before { + content: "\ead6"; +} + +.bx-message-rounded-add:before { + content: "\ead7"; +} + +.bx-message-rounded-check:before { + content: "\ead8"; +} + +.bx-message-rounded-detail:before { + content: "\ead9"; +} + +.bx-message-rounded-dots:before { + content: "\eada"; +} + +.bx-message-rounded-edit:before { + content: "\eadb"; +} + +.bx-message-rounded-error:before { + content: "\eadc"; +} + +.bx-message-rounded-minus:before { + content: "\eadd"; +} + +.bx-message-rounded-x:before { + content: "\eade"; +} + +.bx-message-square:before { + content: "\eadf"; +} + +.bx-message-square-add:before { + content: "\eae0"; +} + +.bx-message-square-check:before { + content: "\eae1"; +} + +.bx-message-square-detail:before { + content: "\eae2"; +} + +.bx-message-square-dots:before { + content: "\eae3"; +} + +.bx-message-square-edit:before { + content: "\eae4"; +} + +.bx-message-square-error:before { + content: "\eae5"; +} + +.bx-message-square-minus:before { + content: "\eae6"; +} + +.bx-message-square-x:before { + content: "\eae7"; +} + +.bx-message-x:before { + content: "\eae8"; +} + +.bx-meteor:before { + content: "\eae9"; +} + +.bx-microchip:before { + content: "\eaea"; +} + +.bx-microphone:before { + content: "\eaeb"; +} + +.bx-microphone-off:before { + content: "\eaec"; +} + +.bx-minus:before { + content: "\eaed"; +} + +.bx-minus-back:before { + content: "\eaee"; +} + +.bx-minus-circle:before { + content: "\eaef"; +} + +.bx-minus-front:before { + content: "\eaf0"; +} + +.bx-mobile:before { + content: "\eaf1"; +} + +.bx-mobile-alt:before { + content: "\eaf2"; +} + +.bx-mobile-landscape:before { + content: "\eaf3"; +} + +.bx-mobile-vibration:before { + content: "\eaf4"; +} + +.bx-money:before { + content: "\eaf5"; +} + +.bx-moon:before { + content: "\eaf6"; +} + +.bx-mouse:before { + content: "\eaf7"; +} + +.bx-mouse-alt:before { + content: "\eaf8"; +} + +.bx-move:before { + content: "\eaf9"; +} + +.bx-move-horizontal:before { + content: "\eafa"; +} + +.bx-move-vertical:before { + content: "\eafb"; +} + +.bx-movie:before { + content: "\eafc"; +} + +.bx-movie-play:before { + content: "\eafd"; +} + +.bx-music:before { + content: "\eafe"; +} + +.bx-navigation:before { + content: "\eaff"; +} + +.bx-network-chart:before { + content: "\eb00"; +} + +.bx-news:before { + content: "\eb01"; +} + +.bx-no-entry:before { + content: "\eb02"; +} + +.bx-note:before { + content: "\eb03"; +} + +.bx-notepad:before { + content: "\eb04"; +} + +.bx-notification:before { + content: "\eb05"; +} + +.bx-notification-off:before { + content: "\eb06"; +} + +.bx-outline:before { + content: "\eb07"; +} + +.bx-package:before { + content: "\eb08"; +} + +.bx-paint:before { + content: "\eb09"; +} + +.bx-paint-roll:before { + content: "\eb0a"; +} + +.bx-palette:before { + content: "\eb0b"; +} + +.bx-paperclip:before { + content: "\eb0c"; +} + +.bx-paper-plane:before { + content: "\eb0d"; +} + +.bx-paragraph:before { + content: "\eb0e"; +} + +.bx-paste:before { + content: "\eb0f"; +} + +.bx-pause:before { + content: "\eb10"; +} + +.bx-pause-circle:before { + content: "\eb11"; +} + +.bx-pen:before { + content: "\eb12"; +} + +.bx-pencil:before { + content: "\eb13"; +} + +.bx-phone:before { + content: "\eb14"; +} + +.bx-phone-call:before { + content: "\eb15"; +} + +.bx-phone-incoming:before { + content: "\eb16"; +} + +.bx-phone-outgoing:before { + content: "\eb17"; +} + +.bx-photo-album:before { + content: "\eb18"; +} + +.bx-pie-chart:before { + content: "\eb19"; +} + +.bx-pie-chart-alt:before { + content: "\eb1a"; +} + +.bx-pie-chart-alt-2:before { + content: "\eb1b"; +} + +.bx-pin:before { + content: "\eb1c"; +} + +.bx-planet:before { + content: "\eb1d"; +} + +.bx-play:before { + content: "\eb1e"; +} + +.bx-play-circle:before { + content: "\eb1f"; +} + +.bx-plug:before { + content: "\eb20"; +} + +.bx-plus:before { + content: "\eb21"; +} + +.bx-plus-circle:before { + content: "\eb22"; +} + +.bx-plus-medical:before { + content: "\eb23"; +} + +.bx-pointer:before { + content: "\eb24"; +} + +.bx-poll:before { + content: "\eb25"; +} + +.bx-polygon:before { + content: "\eb26"; +} + +.bx-pound:before { + content: "\eb27"; +} + +.bx-power-off:before { + content: "\eb28"; +} + +.bx-printer:before { + content: "\eb29"; +} + +.bx-pulse:before { + content: "\eb2a"; +} + +.bx-purchase-tag:before { + content: "\eb2b"; +} + +.bx-purchase-tag-alt:before { + content: "\eb2c"; +} + +.bx-pyramid:before { + content: "\eb2d"; +} + +.bx-question-mark:before { + content: "\eb2e"; +} + +.bx-radar:before { + content: "\eb2f"; +} + +.bx-radio:before { + content: "\eb30"; +} + +.bx-radio-circle:before { + content: "\eb31"; +} + +.bx-radio-circle-marked:before { + content: "\eb32"; +} + +.bx-receipt:before { + content: "\eb33"; +} + +.bx-rectangle:before { + content: "\eb34"; +} + +.bx-recycle:before { + content: "\eb35"; +} + +.bx-redo:before { + content: "\eb36"; +} + +.bx-refresh:before { + content: "\eb37"; +} + +.bx-rename:before { + content: "\eb38"; +} + +.bx-repeat:before { + content: "\eb39"; +} + +.bx-reply:before { + content: "\eb3a"; +} + +.bx-reply-all:before { + content: "\eb3b"; +} + +.bx-repost:before { + content: "\eb3c"; +} + +.bx-reset:before { + content: "\eb3d"; +} + +.bx-restaurant:before { + content: "\eb3e"; +} + +.bx-revision:before { + content: "\eb3f"; +} + +.bx-rewind:before { + content: "\eb40"; +} + +.bx-rewind-circle:before { + content: "\eb41"; +} + +.bx-right-arrow:before { + content: "\eb42"; +} + +.bx-right-arrow-alt:before { + content: "\eb43"; +} + +.bx-right-arrow-circle:before { + content: "\eb44"; +} + +.bx-right-down-arrow-circle:before { + content: "\eb45"; +} + +.bx-right-indent:before { + content: "\eb46"; +} + +.bx-right-top-arrow-circle:before { + content: "\eb47"; +} + +.bx-rocket:before { + content: "\eb48"; +} + +.bx-rotate-left:before { + content: "\eb49"; +} + +.bx-rotate-right:before { + content: "\eb4a"; +} + +.bx-rss:before { + content: "\eb4b"; +} + +.bx-ruble:before { + content: "\eb4c"; +} + +.bx-ruler:before { + content: "\eb4d"; +} + +.bx-run:before { + content: "\eb4e"; +} + +.bx-rupee:before { + content: "\eb4f"; +} + +.bx-sad:before { + content: "\eb50"; +} + +.bx-save:before { + content: "\eb51"; +} + +.bx-scan:before { + content: "\eb52"; +} + +.bx-screenshot:before { + content: "\eb53"; +} + +.bx-search:before { + content: "\eb54"; +} + +.bx-search-alt:before { + content: "\eb55"; +} + +.bx-search-alt-2:before { + content: "\eb56"; +} + +.bx-selection:before { + content: "\eb57"; +} + +.bx-select-multiple:before { + content: "\eb58"; +} + +.bx-send:before { + content: "\eb59"; +} + +.bx-server:before { + content: "\eb5a"; +} + +.bx-shape-circle:before { + content: "\eb5b"; +} + +.bx-shape-polygon:before { + content: "\eb5c"; +} + +.bx-shape-square:before { + content: "\eb5d"; +} + +.bx-shape-triangle:before { + content: "\eb5e"; +} + +.bx-share:before { + content: "\eb5f"; +} + +.bx-share-alt:before { + content: "\eb60"; +} + +.bx-shekel:before { + content: "\eb61"; +} + +.bx-shield:before { + content: "\eb62"; +} + +.bx-shield-alt:before { + content: "\eb63"; +} + +.bx-shield-alt-2:before { + content: "\eb64"; +} + +.bx-shield-quarter:before { + content: "\eb65"; +} + +.bx-shield-x:before { + content: "\eb66"; +} + +.bx-shocked:before { + content: "\eb67"; +} + +.bx-shopping-bag:before { + content: "\eb68"; +} + +.bx-show:before { + content: "\eb69"; +} + +.bx-show-alt:before { + content: "\eb6a"; +} + +.bx-shuffle:before { + content: "\eb6b"; +} + +.bx-sidebar:before { + content: "\eb6c"; +} + +.bx-sitemap:before { + content: "\eb6d"; +} + +.bx-skip-next:before { + content: "\eb6e"; +} + +.bx-skip-next-circle:before { + content: "\eb6f"; +} + +.bx-skip-previous:before { + content: "\eb70"; +} + +.bx-skip-previous-circle:before { + content: "\eb71"; +} + +.bx-sleepy:before { + content: "\eb72"; +} + +.bx-slider:before { + content: "\eb73"; +} + +.bx-slider-alt:before { + content: "\eb74"; +} + +.bx-slideshow:before { + content: "\eb75"; +} + +.bx-smile:before { + content: "\eb76"; +} + +.bx-sort:before { + content: "\eb77"; +} + +.bx-sort-alt-2:before { + content: "\eb78"; +} + +.bx-sort-a-z:before { + content: "\eb79"; +} + +.bx-sort-down:before { + content: "\eb7a"; +} + +.bx-sort-up:before { + content: "\eb7b"; +} + +.bx-sort-z-a:before { + content: "\eb7c"; +} + +.bx-spa:before { + content: "\eb7d"; +} + +.bx-space-bar:before { + content: "\eb7e"; +} + +.bx-spray-can:before { + content: "\eb7f"; +} + +.bx-spreadsheet:before { + content: "\eb80"; +} + +.bx-square:before { + content: "\eb81"; +} + +.bx-square-rounded:before { + content: "\eb82"; +} + +.bx-star:before { + content: "\eb83"; +} + +.bx-station:before { + content: "\eb84"; +} + +.bx-stats:before { + content: "\eb85"; +} + +.bx-sticker:before { + content: "\eb86"; +} + +.bx-stop:before { + content: "\eb87"; +} + +.bx-stop-circle:before { + content: "\eb88"; +} + +.bx-stopwatch:before { + content: "\eb89"; +} + +.bx-store:before { + content: "\eb8a"; +} + +.bx-store-alt:before { + content: "\eb8b"; +} + +.bx-street-view:before { + content: "\eb8c"; +} + +.bx-strikethrough:before { + content: "\eb8d"; +} + +.bx-subdirectory-left:before { + content: "\eb8e"; +} + +.bx-subdirectory-right:before { + content: "\eb8f"; +} + +.bx-sun:before { + content: "\eb90"; +} + +.bx-support:before { + content: "\eb91"; +} + +.bx-swim:before { + content: "\eb92"; +} + +.bx-sync:before { + content: "\eb93"; +} + +.bx-tab:before { + content: "\eb94"; +} + +.bx-table:before { + content: "\eb95"; +} + +.bx-tachometer:before { + content: "\eb96"; +} + +.bx-tag:before { + content: "\eb97"; +} + +.bx-tag-alt:before { + content: "\eb98"; +} + +.bx-target-lock:before { + content: "\eb99"; +} + +.bx-task:before { + content: "\eb9a"; +} + +.bx-task-x:before { + content: "\eb9b"; +} + +.bx-taxi:before { + content: "\eb9c"; +} + +.bx-tennis-ball:before { + content: "\eb9d"; +} + +.bx-terminal:before { + content: "\eb9e"; +} + +.bx-test-tube:before { + content: "\eb9f"; +} + +.bx-text:before { + content: "\eba0"; +} + +.bx-time:before { + content: "\eba1"; +} + +.bx-time-five:before { + content: "\eba2"; +} + +.bx-timer:before { + content: "\eba3"; +} + +.bx-tired:before { + content: "\eba4"; +} + +.bx-toggle-left:before { + content: "\eba5"; +} + +.bx-toggle-right:before { + content: "\eba6"; +} + +.bx-tone:before { + content: "\eba7"; +} + +.bx-traffic-cone:before { + content: "\eba8"; +} + +.bx-train:before { + content: "\eba9"; +} + +.bx-transfer:before { + content: "\ebaa"; +} + +.bx-transfer-alt:before { + content: "\ebab"; +} + +.bx-trash:before { + content: "\ebac"; +} + +.bx-trash-alt:before { + content: "\ebad"; +} + +.bx-trending-down:before { + content: "\ebae"; +} + +.bx-trending-up:before { + content: "\ebaf"; +} + +.bx-trim:before { + content: "\ebb0"; +} + +.bx-trip:before { + content: "\ebb1"; +} + +.bx-trophy:before { + content: "\ebb2"; +} + +.bx-tv:before { + content: "\ebb3"; +} + +.bx-underline:before { + content: "\ebb4"; +} + +.bx-undo:before { + content: "\ebb5"; +} + +.bx-unite:before { + content: "\ebb6"; +} + +.bx-unlink:before { + content: "\ebb7"; +} + +.bx-up-arrow:before { + content: "\ebb8"; +} + +.bx-up-arrow-alt:before { + content: "\ebb9"; +} + +.bx-up-arrow-circle:before { + content: "\ebba"; +} + +.bx-upload:before { + content: "\ebbb"; +} + +.bx-upside-down:before { + content: "\ebbc"; +} + +.bx-upvote:before { + content: "\ebbd"; +} + +.bx-usb:before { + content: "\ebbe"; +} + +.bx-user:before { + content: "\ebbf"; +} + +.bx-user-check:before { + content: "\ebc0"; +} + +.bx-user-circle:before { + content: "\ebc1"; +} + +.bx-user-minus:before { + content: "\ebc2"; +} + +.bx-user-pin:before { + content: "\ebc3"; +} + +.bx-user-plus:before { + content: "\ebc4"; +} + +.bx-user-voice:before { + content: "\ebc5"; +} + +.bx-user-x:before { + content: "\ebc6"; +} + +.bx-vector:before { + content: "\ebc7"; +} + +.bx-vertical-center:before { + content: "\ebc8"; +} + +.bx-vial:before { + content: "\ebc9"; +} + +.bx-video:before { + content: "\ebca"; +} + +.bx-video-off:before { + content: "\ebcb"; +} + +.bx-video-plus:before { + content: "\ebcc"; +} + +.bx-video-recording:before { + content: "\ebcd"; +} + +.bx-voicemail:before { + content: "\ebce"; +} + +.bx-volume:before { + content: "\ebcf"; +} + +.bx-volume-full:before { + content: "\ebd0"; +} + +.bx-volume-low:before { + content: "\ebd1"; +} + +.bx-volume-mute:before { + content: "\ebd2"; +} + +.bx-walk:before { + content: "\ebd3"; +} + +.bx-wallet:before { + content: "\ebd4"; +} + +.bx-wallet-alt:before { + content: "\ebd5"; +} + +.bx-water:before { + content: "\ebd6"; +} + +.bx-webcam:before { + content: "\ebd7"; +} + +.bx-wifi:before { + content: "\ebd8"; +} + +.bx-wifi-0:before { + content: "\ebd9"; +} + +.bx-wifi-1:before { + content: "\ebda"; +} + +.bx-wifi-2:before { + content: "\ebdb"; +} + +.bx-wifi-off:before { + content: "\ebdc"; +} + +.bx-wind:before { + content: "\ebdd"; +} + +.bx-window:before { + content: "\ebde"; +} + +.bx-window-alt:before { + content: "\ebdf"; +} + +.bx-window-close:before { + content: "\ebe0"; +} + +.bx-window-open:before { + content: "\ebe1"; +} + +.bx-windows:before { + content: "\ebe2"; +} + +.bx-wine:before { + content: "\ebe3"; +} + +.bx-wink-smile:before { + content: "\ebe4"; +} + +.bx-wink-tongue:before { + content: "\ebe5"; +} + +.bx-won:before { + content: "\ebe6"; +} + +.bx-world:before { + content: "\ebe7"; +} + +.bx-wrench:before { + content: "\ebe8"; +} + +.bx-x:before { + content: "\ebe9"; +} + +.bx-x-circle:before { + content: "\ebea"; +} + +.bx-yen:before { + content: "\ebeb"; +} + +.bx-zoom-in:before { + content: "\ebec"; +} + +.bx-zoom-out:before { + content: "\ebed"; +} + +.bxs-add-to-queue:before { + content: "\ebee"; +} + +.bxs-adjust:before { + content: "\ebef"; +} + +.bxs-adjust-alt:before { + content: "\ebf0"; +} + +.bxs-alarm:before { + content: "\ebf1"; +} + +.bxs-alarm-add:before { + content: "\ebf2"; +} + +.bxs-alarm-exclamation:before { + content: "\ebf3"; +} + +.bxs-alarm-off:before { + content: "\ebf4"; +} + +.bxs-alarm-snooze:before { + content: "\ebf5"; +} + +.bxs-album:before { + content: "\ebf6"; +} + +.bxs-ambulance:before { + content: "\ebf7"; +} + +.bxs-analyse:before { + content: "\ebf8"; +} + +.bxs-angry:before { + content: "\ebf9"; +} + +.bxs-arch:before { + content: "\ebfa"; +} + +.bxs-archive:before { + content: "\ebfb"; +} + +.bxs-archive-in:before { + content: "\ebfc"; +} + +.bxs-archive-out:before { + content: "\ebfd"; +} + +.bxs-area:before { + content: "\ebfe"; +} + +.bxs-arrow-from-bottom:before { + content: "\ebff"; +} + +.bxs-arrow-from-left:before { + content: "\ec00"; +} + +.bxs-arrow-from-right:before { + content: "\ec01"; +} + +.bxs-arrow-from-top:before { + content: "\ec02"; +} + +.bxs-arrow-to-bottom:before { + content: "\ec03"; +} + +.bxs-arrow-to-left:before { + content: "\ec04"; +} + +.bxs-arrow-to-right:before { + content: "\ec05"; +} + +.bxs-arrow-to-top:before { + content: "\ec06"; +} + +.bxs-award:before { + content: "\ec07"; +} + +.bxs-baby-carriage:before { + content: "\ec08"; +} + +.bxs-backpack:before { + content: "\ec09"; +} + +.bxs-badge:before { + content: "\ec0a"; +} + +.bxs-badge-check:before { + content: "\ec0b"; +} + +.bxs-badge-dollar:before { + content: "\ec0c"; +} + +.bxs-ball:before { + content: "\ec0d"; +} + +.bxs-band-aid:before { + content: "\ec0e"; +} + +.bxs-bank:before { + content: "\ec0f"; +} + +.bxs-bar-chart-alt-2:before { + content: "\ec10"; +} + +.bxs-bar-chart-square:before { + content: "\ec11"; +} + +.bxs-barcode:before { + content: "\ec12"; +} + +.bxs-baseball:before { + content: "\ec13"; +} + +.bxs-basket:before { + content: "\ec14"; +} + +.bxs-basketball:before { + content: "\ec15"; +} + +.bxs-bath:before { + content: "\ec16"; +} + +.bxs-battery:before { + content: "\ec17"; +} + +.bxs-battery-charging:before { + content: "\ec18"; +} + +.bxs-battery-full:before { + content: "\ec19"; +} + +.bxs-battery-low:before { + content: "\ec1a"; +} + +.bxs-bed:before { + content: "\ec1b"; +} + +.bxs-been-here:before { + content: "\ec1c"; +} + +.bxs-beer:before { + content: "\ec1d"; +} + +.bxs-bell:before { + content: "\ec1e"; +} + +.bxs-bell-minus:before { + content: "\ec1f"; +} + +.bxs-bell-off:before { + content: "\ec20"; +} + +.bxs-bell-plus:before { + content: "\ec21"; +} + +.bxs-bell-ring:before { + content: "\ec22"; +} + +.bxs-bible:before { + content: "\ec23"; +} + +.bxs-binoculars:before { + content: "\ec24"; +} + +.bxs-blanket:before { + content: "\ec25"; +} + +.bxs-bolt:before { + content: "\ec26"; +} + +.bxs-bolt-circle:before { + content: "\ec27"; +} + +.bxs-bomb:before { + content: "\ec28"; +} + +.bxs-bone:before { + content: "\ec29"; +} + +.bxs-bong:before { + content: "\ec2a"; +} + +.bxs-book:before { + content: "\ec2b"; +} + +.bxs-book-add:before { + content: "\ec2c"; +} + +.bxs-book-alt:before { + content: "\ec2d"; +} + +.bxs-book-bookmark:before { + content: "\ec2e"; +} + +.bxs-book-content:before { + content: "\ec2f"; +} + +.bxs-book-heart:before { + content: "\ec30"; +} + +.bxs-bookmark:before { + content: "\ec31"; +} + +.bxs-bookmark-alt:before { + content: "\ec32"; +} + +.bxs-bookmark-alt-minus:before { + content: "\ec33"; +} + +.bxs-bookmark-alt-plus:before { + content: "\ec34"; +} + +.bxs-bookmark-heart:before { + content: "\ec35"; +} + +.bxs-bookmark-minus:before { + content: "\ec36"; +} + +.bxs-bookmark-plus:before { + content: "\ec37"; +} + +.bxs-bookmarks:before { + content: "\ec38"; +} + +.bxs-bookmark-star:before { + content: "\ec39"; +} + +.bxs-book-open:before { + content: "\ec3a"; +} + +.bxs-book-reader:before { + content: "\ec3b"; +} + +.bxs-bot:before { + content: "\ec3c"; +} + +.bxs-bowling-ball:before { + content: "\ec3d"; +} + +.bxs-box:before { + content: "\ec3e"; +} + +.bxs-brain:before { + content: "\ec3f"; +} + +.bxs-briefcase:before { + content: "\ec40"; +} + +.bxs-briefcase-alt:before { + content: "\ec41"; +} + +.bxs-briefcase-alt-2:before { + content: "\ec42"; +} + +.bxs-brightness:before { + content: "\ec43"; +} + +.bxs-brightness-half:before { + content: "\ec44"; +} + +.bxs-brush:before { + content: "\ec45"; +} + +.bxs-brush-alt:before { + content: "\ec46"; +} + +.bxs-bug:before { + content: "\ec47"; +} + +.bxs-bug-alt:before { + content: "\ec48"; +} + +.bxs-building:before { + content: "\ec49"; +} + +.bxs-building-house:before { + content: "\ec4a"; +} + +.bxs-buildings:before { + content: "\ec4b"; +} + +.bxs-bulb:before { + content: "\ec4c"; +} + +.bxs-bullseye:before { + content: "\ec4d"; +} + +.bxs-buoy:before { + content: "\ec4e"; +} + +.bxs-bus:before { + content: "\ec4f"; +} + +.bxs-business:before { + content: "\ec50"; +} + +.bxs-bus-school:before { + content: "\ec51"; +} + +.bxs-cabinet:before { + content: "\ec52"; +} + +.bxs-cake:before { + content: "\ec53"; +} + +.bxs-calculator:before { + content: "\ec54"; +} + +.bxs-calendar:before { + content: "\ec55"; +} + +.bxs-calendar-alt:before { + content: "\ec56"; +} + +.bxs-calendar-check:before { + content: "\ec57"; +} + +.bxs-calendar-edit:before { + content: "\ec58"; +} + +.bxs-calendar-event:before { + content: "\ec59"; +} + +.bxs-calendar-exclamation:before { + content: "\ec5a"; +} + +.bxs-calendar-heart:before { + content: "\ec5b"; +} + +.bxs-calendar-minus:before { + content: "\ec5c"; +} + +.bxs-calendar-plus:before { + content: "\ec5d"; +} + +.bxs-calendar-star:before { + content: "\ec5e"; +} + +.bxs-calendar-week:before { + content: "\ec5f"; +} + +.bxs-calendar-x:before { + content: "\ec60"; +} + +.bxs-camera:before { + content: "\ec61"; +} + +.bxs-camera-home:before { + content: "\ec62"; +} + +.bxs-camera-movie:before { + content: "\ec63"; +} + +.bxs-camera-off:before { + content: "\ec64"; +} + +.bxs-camera-plus:before { + content: "\ec65"; +} + +.bxs-capsule:before { + content: "\ec66"; +} + +.bxs-captions:before { + content: "\ec67"; +} + +.bxs-car:before { + content: "\ec68"; +} + +.bxs-car-battery:before { + content: "\ec69"; +} + +.bxs-car-crash:before { + content: "\ec6a"; +} + +.bxs-card:before { + content: "\ec6b"; +} + +.bxs-caret-down-circle:before { + content: "\ec6c"; +} + +.bxs-caret-down-square:before { + content: "\ec6d"; +} + +.bxs-caret-left-circle:before { + content: "\ec6e"; +} + +.bxs-caret-left-square:before { + content: "\ec6f"; +} + +.bxs-caret-right-circle:before { + content: "\ec70"; +} + +.bxs-caret-right-square:before { + content: "\ec71"; +} + +.bxs-caret-up-circle:before { + content: "\ec72"; +} + +.bxs-caret-up-square:before { + content: "\ec73"; +} + +.bxs-car-garage:before { + content: "\ec74"; +} + +.bxs-car-mechanic:before { + content: "\ec75"; +} + +.bxs-carousel:before { + content: "\ec76"; +} + +.bxs-cart:before { + content: "\ec77"; +} + +.bxs-cart-add:before { + content: "\ec78"; +} + +.bxs-cart-alt:before { + content: "\ec79"; +} + +.bxs-cart-download:before { + content: "\ec7a"; +} + +.bxs-car-wash:before { + content: "\ec7b"; +} + +.bxs-category:before { + content: "\ec7c"; +} + +.bxs-category-alt:before { + content: "\ec7d"; +} + +.bxs-cctv:before { + content: "\ec7e"; +} + +.bxs-certification:before { + content: "\ec7f"; +} + +.bxs-chalkboard:before { + content: "\ec80"; +} + +.bxs-chart:before { + content: "\ec81"; +} + +.bxs-chat:before { + content: "\ec82"; +} + +.bxs-checkbox:before { + content: "\ec83"; +} + +.bxs-checkbox-checked:before { + content: "\ec84"; +} + +.bxs-check-circle:before { + content: "\ec85"; +} + +.bxs-check-shield:before { + content: "\ec86"; +} + +.bxs-check-square:before { + content: "\ec87"; +} + +.bxs-chess:before { + content: "\ec88"; +} + +.bxs-chevron-down:before { + content: "\ec89"; +} + +.bxs-chevron-down-circle:before { + content: "\ec8a"; +} + +.bxs-chevron-down-square:before { + content: "\ec8b"; +} + +.bxs-chevron-left:before { + content: "\ec8c"; +} + +.bxs-chevron-left-circle:before { + content: "\ec8d"; +} + +.bxs-chevron-left-square:before { + content: "\ec8e"; +} + +.bxs-chevron-right:before { + content: "\ec8f"; +} + +.bxs-chevron-right-circle:before { + content: "\ec90"; +} + +.bxs-chevron-right-square:before { + content: "\ec91"; +} + +.bxs-chevrons-down:before { + content: "\ec92"; +} + +.bxs-chevrons-left:before { + content: "\ec93"; +} + +.bxs-chevrons-right:before { + content: "\ec94"; +} + +.bxs-chevrons-up:before { + content: "\ec95"; +} + +.bxs-chevron-up:before { + content: "\ec96"; +} + +.bxs-chevron-up-circle:before { + content: "\ec97"; +} + +.bxs-chevron-up-square:before { + content: "\ec98"; +} + +.bxs-chip:before { + content: "\ec99"; +} + +.bxs-church:before { + content: "\ec9a"; +} + +.bxs-circle:before { + content: "\ec9b"; +} + +.bxs-city:before { + content: "\ec9c"; +} + +.bxs-clinic:before { + content: "\ec9d"; +} + +.bxs-cloud:before { + content: "\ec9e"; +} + +.bxs-cloud-download:before { + content: "\ec9f"; +} + +.bxs-cloud-lightning:before { + content: "\eca0"; +} + +.bxs-cloud-rain:before { + content: "\eca1"; +} + +.bxs-cloud-upload:before { + content: "\eca2"; +} + +.bxs-coffee:before { + content: "\eca3"; +} + +.bxs-coffee-alt:before { + content: "\eca4"; +} + +.bxs-coffee-togo:before { + content: "\eca5"; +} + +.bxs-cog:before { + content: "\eca6"; +} + +.bxs-coin:before { + content: "\eca7"; +} + +.bxs-coin-stack:before { + content: "\eca8"; +} + +.bxs-collection:before { + content: "\eca9"; +} + +.bxs-color-fill:before { + content: "\ecaa"; +} + +.bxs-comment:before { + content: "\ecab"; +} + +.bxs-comment-add:before { + content: "\ecac"; +} + +.bxs-comment-check:before { + content: "\ecad"; +} + +.bxs-comment-detail:before { + content: "\ecae"; +} + +.bxs-comment-dots:before { + content: "\ecaf"; +} + +.bxs-comment-edit:before { + content: "\ecb0"; +} + +.bxs-comment-error:before { + content: "\ecb1"; +} + +.bxs-comment-minus:before { + content: "\ecb2"; +} + +.bxs-comment-x:before { + content: "\ecb3"; +} + +.bxs-compass:before { + content: "\ecb4"; +} + +.bxs-component:before { + content: "\ecb5"; +} + +.bxs-confused:before { + content: "\ecb6"; +} + +.bxs-contact:before { + content: "\ecb7"; +} + +.bxs-conversation:before { + content: "\ecb8"; +} + +.bxs-cookie:before { + content: "\ecb9"; +} + +.bxs-cool:before { + content: "\ecba"; +} + +.bxs-copy:before { + content: "\ecbb"; +} + +.bxs-copy-alt:before { + content: "\ecbc"; +} + +.bxs-copyright:before { + content: "\ecbd"; +} + +.bxs-coupon:before { + content: "\ecbe"; +} + +.bxs-credit-card:before { + content: "\ecbf"; +} + +.bxs-credit-card-alt:before { + content: "\ecc0"; +} + +.bxs-credit-card-front:before { + content: "\ecc1"; +} + +.bxs-crop:before { + content: "\ecc2"; +} + +.bxs-crown:before { + content: "\ecc3"; +} + +.bxs-cube:before { + content: "\ecc4"; +} + +.bxs-cube-alt:before { + content: "\ecc5"; +} + +.bxs-cuboid:before { + content: "\ecc6"; +} + +.bxs-customize:before { + content: "\ecc7"; +} + +.bxs-cylinder:before { + content: "\ecc8"; +} + +.bxs-dashboard:before { + content: "\ecc9"; +} + +.bxs-data:before { + content: "\ecca"; +} + +.bxs-detail:before { + content: "\eccb"; +} + +.bxs-devices:before { + content: "\eccc"; +} + +.bxs-diamond:before { + content: "\eccd"; +} + +.bxs-dice-1:before { + content: "\ecce"; +} + +.bxs-dice-2:before { + content: "\eccf"; +} + +.bxs-dice-3:before { + content: "\ecd0"; +} + +.bxs-dice-4:before { + content: "\ecd1"; +} + +.bxs-dice-5:before { + content: "\ecd2"; +} + +.bxs-dice-6:before { + content: "\ecd3"; +} + +.bxs-direction-left:before { + content: "\ecd4"; +} + +.bxs-direction-right:before { + content: "\ecd5"; +} + +.bxs-directions:before { + content: "\ecd6"; +} + +.bxs-disc:before { + content: "\ecd7"; +} + +.bxs-discount:before { + content: "\ecd8"; +} + +.bxs-dish:before { + content: "\ecd9"; +} + +.bxs-dislike:before { + content: "\ecda"; +} + +.bxs-dizzy:before { + content: "\ecdb"; +} + +.bxs-dock-bottom:before { + content: "\ecdc"; +} + +.bxs-dock-left:before { + content: "\ecdd"; +} + +.bxs-dock-right:before { + content: "\ecde"; +} + +.bxs-dock-top:before { + content: "\ecdf"; +} + +.bxs-dollar-circle:before { + content: "\ece0"; +} + +.bxs-donate-blood:before { + content: "\ece1"; +} + +.bxs-donate-heart:before { + content: "\ece2"; +} + +.bxs-door-open:before { + content: "\ece3"; +} + +.bxs-doughnut-chart:before { + content: "\ece4"; +} + +.bxs-down-arrow:before { + content: "\ece5"; +} + +.bxs-down-arrow-alt:before { + content: "\ece6"; +} + +.bxs-down-arrow-circle:before { + content: "\ece7"; +} + +.bxs-down-arrow-square:before { + content: "\ece8"; +} + +.bxs-download:before { + content: "\ece9"; +} + +.bxs-downvote:before { + content: "\ecea"; +} + +.bxs-drink:before { + content: "\eceb"; +} + +.bxs-droplet:before { + content: "\ecec"; +} + +.bxs-droplet-half:before { + content: "\eced"; +} + +.bxs-dryer:before { + content: "\ecee"; +} + +.bxs-duplicate:before { + content: "\ecef"; +} + +.bxs-edit:before { + content: "\ecf0"; +} + +.bxs-edit-alt:before { + content: "\ecf1"; +} + +.bxs-edit-location:before { + content: "\ecf2"; +} + +.bxs-eject:before { + content: "\ecf3"; +} + +.bxs-envelope:before { + content: "\ecf4"; +} + +.bxs-envelope-open:before { + content: "\ecf5"; +} + +.bxs-eraser:before { + content: "\ecf6"; +} + +.bxs-error:before { + content: "\ecf7"; +} + +.bxs-error-alt:before { + content: "\ecf8"; +} + +.bxs-error-circle:before { + content: "\ecf9"; +} + +.bxs-ev-station:before { + content: "\ecfa"; +} + +.bxs-exit:before { + content: "\ecfb"; +} + +.bxs-extension:before { + content: "\ecfc"; +} + +.bxs-eyedropper:before { + content: "\ecfd"; +} + +.bxs-face:before { + content: "\ecfe"; +} + +.bxs-face-mask:before { + content: "\ecff"; +} + +.bxs-factory:before { + content: "\ed00"; +} + +.bxs-fast-forward-circle:before { + content: "\ed01"; +} + +.bxs-file:before { + content: "\ed02"; +} + +.bxs-file-archive:before { + content: "\ed03"; +} + +.bxs-file-blank:before { + content: "\ed04"; +} + +.bxs-file-css:before { + content: "\ed05"; +} + +.bxs-file-doc:before { + content: "\ed06"; +} + +.bxs-file-export:before { + content: "\ed07"; +} + +.bxs-file-find:before { + content: "\ed08"; +} + +.bxs-file-gif:before { + content: "\ed09"; +} + +.bxs-file-html:before { + content: "\ed0a"; +} + +.bxs-file-image:before { + content: "\ed0b"; +} + +.bxs-file-import:before { + content: "\ed0c"; +} + +.bxs-file-jpg:before { + content: "\ed0d"; +} + +.bxs-file-js:before { + content: "\ed0e"; +} + +.bxs-file-json:before { + content: "\ed0f"; +} + +.bxs-file-md:before { + content: "\ed10"; +} + +.bxs-file-pdf:before { + content: "\ed11"; +} + +.bxs-file-plus:before { + content: "\ed12"; +} + +.bxs-file-png:before { + content: "\ed13"; +} + +.bxs-file-txt:before { + content: "\ed14"; +} + +.bxs-film:before { + content: "\ed15"; +} + +.bxs-filter-alt:before { + content: "\ed16"; +} + +.bxs-first-aid:before { + content: "\ed17"; +} + +.bxs-flag:before { + content: "\ed18"; +} + +.bxs-flag-alt:before { + content: "\ed19"; +} + +.bxs-flag-checkered:before { + content: "\ed1a"; +} + +.bxs-flame:before { + content: "\ed1b"; +} + +.bxs-flask:before { + content: "\ed1c"; +} + +.bxs-florist:before { + content: "\ed1d"; +} + +.bxs-folder:before { + content: "\ed1e"; +} + +.bxs-folder-minus:before { + content: "\ed1f"; +} + +.bxs-folder-open:before { + content: "\ed20"; +} + +.bxs-folder-plus:before { + content: "\ed21"; +} + +.bxs-food-menu:before { + content: "\ed22"; +} + +.bxs-fridge:before { + content: "\ed23"; +} + +.bxs-game:before { + content: "\ed24"; +} + +.bxs-gas-pump:before { + content: "\ed25"; +} + +.bxs-ghost:before { + content: "\ed26"; +} + +.bxs-gift:before { + content: "\ed27"; +} + +.bxs-graduation:before { + content: "\ed28"; +} + +.bxs-grid:before { + content: "\ed29"; +} + +.bxs-grid-alt:before { + content: "\ed2a"; +} + +.bxs-group:before { + content: "\ed2b"; +} + +.bxs-guitar-amp:before { + content: "\ed2c"; +} + +.bxs-hand-down:before { + content: "\ed2d"; +} + +.bxs-hand-left:before { + content: "\ed2e"; +} + +.bxs-hand-right:before { + content: "\ed2f"; +} + +.bxs-hand-up:before { + content: "\ed30"; +} + +.bxs-happy:before { + content: "\ed31"; +} + +.bxs-happy-alt:before { + content: "\ed32"; +} + +.bxs-happy-beaming:before { + content: "\ed33"; +} + +.bxs-happy-heart-eyes:before { + content: "\ed34"; +} + +.bxs-hdd:before { + content: "\ed35"; +} + +.bxs-heart:before { + content: "\ed36"; +} + +.bxs-heart-circle:before { + content: "\ed37"; +} + +.bxs-heart-square:before { + content: "\ed38"; +} + +.bxs-help-circle:before { + content: "\ed39"; +} + +.bxs-hide:before { + content: "\ed3a"; +} + +.bxs-home:before { + content: "\ed3b"; +} + +.bxs-home-circle:before { + content: "\ed3c"; +} + +.bxs-home-heart:before { + content: "\ed3d"; +} + +.bxs-home-smile:before { + content: "\ed3e"; +} + +.bxs-hot:before { + content: "\ed3f"; +} + +.bxs-hotel:before { + content: "\ed40"; +} + +.bxs-hourglass:before { + content: "\ed41"; +} + +.bxs-hourglass-bottom:before { + content: "\ed42"; +} + +.bxs-hourglass-top:before { + content: "\ed43"; +} + +.bxs-id-card:before { + content: "\ed44"; +} + +.bxs-image:before { + content: "\ed45"; +} + +.bxs-image-add:before { + content: "\ed46"; +} + +.bxs-image-alt:before { + content: "\ed47"; +} + +.bxs-inbox:before { + content: "\ed48"; +} + +.bxs-info-circle:before { + content: "\ed49"; +} + +.bxs-info-square:before { + content: "\ed4a"; +} + +.bxs-institution:before { + content: "\ed4b"; +} + +.bxs-joystick:before { + content: "\ed4c"; +} + +.bxs-joystick-alt:before { + content: "\ed4d"; +} + +.bxs-joystick-button:before { + content: "\ed4e"; +} + +.bxs-key:before { + content: "\ed4f"; +} + +.bxs-keyboard:before { + content: "\ed50"; +} + +.bxs-label:before { + content: "\ed51"; +} + +.bxs-landmark:before { + content: "\ed52"; +} + +.bxs-landscape:before { + content: "\ed53"; +} + +.bxs-laugh:before { + content: "\ed54"; +} + +.bxs-layer:before { + content: "\ed55"; +} + +.bxs-layer-minus:before { + content: "\ed56"; +} + +.bxs-layer-plus:before { + content: "\ed57"; +} + +.bxs-layout:before { + content: "\ed58"; +} + +.bxs-left-arrow:before { + content: "\ed59"; +} + +.bxs-left-arrow-alt:before { + content: "\ed5a"; +} + +.bxs-left-arrow-circle:before { + content: "\ed5b"; +} + +.bxs-left-arrow-square:before { + content: "\ed5c"; +} + +.bxs-left-down-arrow-circle:before { + content: "\ed5d"; +} + +.bxs-left-top-arrow-circle:before { + content: "\ed5e"; +} + +.bxs-like:before { + content: "\ed5f"; +} + +.bxs-location-plus:before { + content: "\ed60"; +} + +.bxs-lock:before { + content: "\ed61"; +} + +.bxs-lock-alt:before { + content: "\ed62"; +} + +.bxs-lock-open:before { + content: "\ed63"; +} + +.bxs-lock-open-alt:before { + content: "\ed64"; +} + +.bxs-log-in:before { + content: "\ed65"; +} + +.bxs-log-in-circle:before { + content: "\ed66"; +} + +.bxs-log-out:before { + content: "\ed67"; +} + +.bxs-log-out-circle:before { + content: "\ed68"; +} + +.bxs-low-vision:before { + content: "\ed69"; +} + +.bxs-magic-wand:before { + content: "\ed6a"; +} + +.bxs-magnet:before { + content: "\ed6b"; +} + +.bxs-map:before { + content: "\ed6c"; +} + +.bxs-map-alt:before { + content: "\ed6d"; +} + +.bxs-map-pin:before { + content: "\ed6e"; +} + +.bxs-mask:before { + content: "\ed6f"; +} + +.bxs-medal:before { + content: "\ed70"; +} + +.bxs-megaphone:before { + content: "\ed71"; +} + +.bxs-meh:before { + content: "\ed72"; +} + +.bxs-meh-alt:before { + content: "\ed73"; +} + +.bxs-meh-blank:before { + content: "\ed74"; +} + +.bxs-memory-card:before { + content: "\ed75"; +} + +.bxs-message:before { + content: "\ed76"; +} + +.bxs-message-add:before { + content: "\ed77"; +} + +.bxs-message-alt:before { + content: "\ed78"; +} + +.bxs-message-alt-add:before { + content: "\ed79"; +} + +.bxs-message-alt-check:before { + content: "\ed7a"; +} + +.bxs-message-alt-detail:before { + content: "\ed7b"; +} + +.bxs-message-alt-dots:before { + content: "\ed7c"; +} + +.bxs-message-alt-edit:before { + content: "\ed7d"; +} + +.bxs-message-alt-error:before { + content: "\ed7e"; +} + +.bxs-message-alt-minus:before { + content: "\ed7f"; +} + +.bxs-message-alt-x:before { + content: "\ed80"; +} + +.bxs-message-check:before { + content: "\ed81"; +} + +.bxs-message-detail:before { + content: "\ed82"; +} + +.bxs-message-dots:before { + content: "\ed83"; +} + +.bxs-message-edit:before { + content: "\ed84"; +} + +.bxs-message-error:before { + content: "\ed85"; +} + +.bxs-message-minus:before { + content: "\ed86"; +} + +.bxs-message-rounded:before { + content: "\ed87"; +} + +.bxs-message-rounded-add:before { + content: "\ed88"; +} + +.bxs-message-rounded-check:before { + content: "\ed89"; +} + +.bxs-message-rounded-detail:before { + content: "\ed8a"; +} + +.bxs-message-rounded-dots:before { + content: "\ed8b"; +} + +.bxs-message-rounded-edit:before { + content: "\ed8c"; +} + +.bxs-message-rounded-error:before { + content: "\ed8d"; +} + +.bxs-message-rounded-minus:before { + content: "\ed8e"; +} + +.bxs-message-rounded-x:before { + content: "\ed8f"; +} + +.bxs-message-square:before { + content: "\ed90"; +} + +.bxs-message-square-add:before { + content: "\ed91"; +} + +.bxs-message-square-check:before { + content: "\ed92"; +} + +.bxs-message-square-detail:before { + content: "\ed93"; +} + +.bxs-message-square-dots:before { + content: "\ed94"; +} + +.bxs-message-square-edit:before { + content: "\ed95"; +} + +.bxs-message-square-error:before { + content: "\ed96"; +} + +.bxs-message-square-minus:before { + content: "\ed97"; +} + +.bxs-message-square-x:before { + content: "\ed98"; +} + +.bxs-message-x:before { + content: "\ed99"; +} + +.bxs-meteor:before { + content: "\ed9a"; +} + +.bxs-microchip:before { + content: "\ed9b"; +} + +.bxs-microphone:before { + content: "\ed9c"; +} + +.bxs-microphone-alt:before { + content: "\ed9d"; +} + +.bxs-microphone-off:before { + content: "\ed9e"; +} + +.bxs-minus-circle:before { + content: "\ed9f"; +} + +.bxs-minus-square:before { + content: "\eda0"; +} + +.bxs-mobile:before { + content: "\eda1"; +} + +.bxs-mobile-vibration:before { + content: "\eda2"; +} + +.bxs-moon:before { + content: "\eda3"; +} + +.bxs-mouse:before { + content: "\eda4"; +} + +.bxs-mouse-alt:before { + content: "\eda5"; +} + +.bxs-movie:before { + content: "\eda6"; +} + +.bxs-movie-play:before { + content: "\eda7"; +} + +.bxs-music:before { + content: "\eda8"; +} + +.bxs-navigation:before { + content: "\eda9"; +} + +.bxs-network-chart:before { + content: "\edaa"; +} + +.bxs-news:before { + content: "\edab"; +} + +.bxs-no-entry:before { + content: "\edac"; +} + +.bxs-note:before { + content: "\edad"; +} + +.bxs-notepad:before { + content: "\edae"; +} + +.bxs-notification:before { + content: "\edaf"; +} + +.bxs-notification-off:before { + content: "\edb0"; +} + +.bxs-offer:before { + content: "\edb1"; +} + +.bxs-package:before { + content: "\edb2"; +} + +.bxs-paint:before { + content: "\edb3"; +} + +.bxs-paint-roll:before { + content: "\edb4"; +} + +.bxs-palette:before { + content: "\edb5"; +} + +.bxs-paper-plane:before { + content: "\edb6"; +} + +.bxs-parking:before { + content: "\edb7"; +} + +.bxs-paste:before { + content: "\edb8"; +} + +.bxs-pen:before { + content: "\edb9"; +} + +.bxs-pencil:before { + content: "\edba"; +} + +.bxs-phone:before { + content: "\edbb"; +} + +.bxs-phone-call:before { + content: "\edbc"; +} + +.bxs-phone-incoming:before { + content: "\edbd"; +} + +.bxs-phone-outgoing:before { + content: "\edbe"; +} + +.bxs-photo-album:before { + content: "\edbf"; +} + +.bxs-piano:before { + content: "\edc0"; +} + +.bxs-pie-chart:before { + content: "\edc1"; +} + +.bxs-pie-chart-alt:before { + content: "\edc2"; +} + +.bxs-pie-chart-alt-2:before { + content: "\edc3"; +} + +.bxs-pin:before { + content: "\edc4"; +} + +.bxs-pizza:before { + content: "\edc5"; +} + +.bxs-plane:before { + content: "\edc6"; +} + +.bxs-plane-alt:before { + content: "\edc7"; +} + +.bxs-plane-land:before { + content: "\edc8"; +} + +.bxs-planet:before { + content: "\edc9"; +} + +.bxs-plane-take-off:before { + content: "\edca"; +} + +.bxs-playlist:before { + content: "\edcb"; +} + +.bxs-plug:before { + content: "\edcc"; +} + +.bxs-plus-circle:before { + content: "\edcd"; +} + +.bxs-plus-square:before { + content: "\edce"; +} + +.bxs-pointer:before { + content: "\edcf"; +} + +.bxs-polygon:before { + content: "\edd0"; +} + +.bxs-printer:before { + content: "\edd1"; +} + +.bxs-purchase-tag:before { + content: "\edd2"; +} + +.bxs-purchase-tag-alt:before { + content: "\edd3"; +} + +.bxs-pyramid:before { + content: "\edd4"; +} + +.bxs-quote-alt-left:before { + content: "\edd5"; +} + +.bxs-quote-alt-right:before { + content: "\edd6"; +} + +.bxs-quote-left:before { + content: "\edd7"; +} + +.bxs-quote-right:before { + content: "\edd8"; +} + +.bxs-quote-single-left:before { + content: "\edd9"; +} + +.bxs-quote-single-right:before { + content: "\edda"; +} + +.bxs-radiation:before { + content: "\eddb"; +} + +.bxs-radio:before { + content: "\eddc"; +} + +.bxs-receipt:before { + content: "\eddd"; +} + +.bxs-rectangle:before { + content: "\edde"; +} + +.bxs-rename:before { + content: "\eddf"; +} + +.bxs-report:before { + content: "\ede0"; +} + +.bxs-rewind-circle:before { + content: "\ede1"; +} + +.bxs-right-arrow:before { + content: "\ede2"; +} + +.bxs-right-arrow-alt:before { + content: "\ede3"; +} + +.bxs-right-arrow-circle:before { + content: "\ede4"; +} + +.bxs-right-arrow-square:before { + content: "\ede5"; +} + +.bxs-right-down-arrow-circle:before { + content: "\ede6"; +} + +.bxs-right-top-arrow-circle:before { + content: "\ede7"; +} + +.bxs-rocket:before { + content: "\ede8"; +} + +.bxs-ruler:before { + content: "\ede9"; +} + +.bxs-sad:before { + content: "\edea"; +} + +.bxs-save:before { + content: "\edeb"; +} + +.bxs-school:before { + content: "\edec"; +} + +.bxs-search:before { + content: "\eded"; +} + +.bxs-search-alt-2:before { + content: "\edee"; +} + +.bxs-select-multiple:before { + content: "\edef"; +} + +.bxs-send:before { + content: "\edf0"; +} + +.bxs-server:before { + content: "\edf1"; +} + +.bxs-shapes:before { + content: "\edf2"; +} + +.bxs-share:before { + content: "\edf3"; +} + +.bxs-share-alt:before { + content: "\edf4"; +} + +.bxs-shield:before { + content: "\edf5"; +} + +.bxs-shield-alt-2:before { + content: "\edf6"; +} + +.bxs-shield-x:before { + content: "\edf7"; +} + +.bxs-ship:before { + content: "\edf8"; +} + +.bxs-shocked:before { + content: "\edf9"; +} + +.bxs-shopping-bag:before { + content: "\edfa"; +} + +.bxs-shopping-bag-alt:before { + content: "\edfb"; +} + +.bxs-shopping-bags:before { + content: "\edfc"; +} + +.bxs-show:before { + content: "\edfd"; +} + +.bxs-skip-next-circle:before { + content: "\edfe"; +} + +.bxs-skip-previous-circle:before { + content: "\edff"; +} + +.bxs-skull:before { + content: "\ee00"; +} + +.bxs-sleepy:before { + content: "\ee01"; +} + +.bxs-slideshow:before { + content: "\ee02"; +} + +.bxs-smile:before { + content: "\ee03"; +} + +.bxs-sort-alt:before { + content: "\ee04"; +} + +.bxs-spa:before { + content: "\ee05"; +} + +.bxs-spray-can:before { + content: "\ee06"; +} + +.bxs-spreadsheet:before { + content: "\ee07"; +} + +.bxs-square:before { + content: "\ee08"; +} + +.bxs-square-rounded:before { + content: "\ee09"; +} + +.bxs-star:before { + content: "\ee0a"; +} + +.bxs-star-half:before { + content: "\ee0b"; +} + +.bxs-sticker:before { + content: "\ee0c"; +} + +.bxs-stopwatch:before { + content: "\ee0d"; +} + +.bxs-store:before { + content: "\ee0e"; +} + +.bxs-store-alt:before { + content: "\ee0f"; +} + +.bxs-sun:before { + content: "\ee10"; +} + +.bxs-tachometer:before { + content: "\ee11"; +} + +.bxs-tag:before { + content: "\ee12"; +} + +.bxs-tag-alt:before { + content: "\ee13"; +} + +.bxs-tag-x:before { + content: "\ee14"; +} + +.bxs-taxi:before { + content: "\ee15"; +} + +.bxs-tennis-ball:before { + content: "\ee16"; +} + +.bxs-terminal:before { + content: "\ee17"; +} + +.bxs-thermometer:before { + content: "\ee18"; +} + +.bxs-time:before { + content: "\ee19"; +} + +.bxs-time-five:before { + content: "\ee1a"; +} + +.bxs-timer:before { + content: "\ee1b"; +} + +.bxs-tired:before { + content: "\ee1c"; +} + +.bxs-toggle-left:before { + content: "\ee1d"; +} + +.bxs-toggle-right:before { + content: "\ee1e"; +} + +.bxs-tone:before { + content: "\ee1f"; +} + +.bxs-torch:before { + content: "\ee20"; +} + +.bxs-to-top:before { + content: "\ee21"; +} + +.bxs-traffic:before { + content: "\ee22"; +} + +.bxs-traffic-barrier:before { + content: "\ee23"; +} + +.bxs-traffic-cone:before { + content: "\ee24"; +} + +.bxs-train:before { + content: "\ee25"; +} + +.bxs-trash:before { + content: "\ee26"; +} + +.bxs-trash-alt:before { + content: "\ee27"; +} + +.bxs-tree:before { + content: "\ee28"; +} + +.bxs-trophy:before { + content: "\ee29"; +} + +.bxs-truck:before { + content: "\ee2a"; +} + +.bxs-t-shirt:before { + content: "\ee2b"; +} + +.bxs-tv:before { + content: "\ee2c"; +} + +.bxs-up-arrow:before { + content: "\ee2d"; +} + +.bxs-up-arrow-alt:before { + content: "\ee2e"; +} + +.bxs-up-arrow-circle:before { + content: "\ee2f"; +} + +.bxs-up-arrow-square:before { + content: "\ee30"; +} + +.bxs-upside-down:before { + content: "\ee31"; +} + +.bxs-upvote:before { + content: "\ee32"; +} + +.bxs-user:before { + content: "\ee33"; +} + +.bxs-user-account:before { + content: "\ee34"; +} + +.bxs-user-badge:before { + content: "\ee35"; +} + +.bxs-user-check:before { + content: "\ee36"; +} + +.bxs-user-circle:before { + content: "\ee37"; +} + +.bxs-user-detail:before { + content: "\ee38"; +} + +.bxs-user-minus:before { + content: "\ee39"; +} + +.bxs-user-pin:before { + content: "\ee3a"; +} + +.bxs-user-plus:before { + content: "\ee3b"; +} + +.bxs-user-rectangle:before { + content: "\ee3c"; +} + +.bxs-user-voice:before { + content: "\ee3d"; +} + +.bxs-user-x:before { + content: "\ee3e"; +} + +.bxs-vector:before { + content: "\ee3f"; +} + +.bxs-vial:before { + content: "\ee40"; +} + +.bxs-video:before { + content: "\ee41"; +} + +.bxs-video-off:before { + content: "\ee42"; +} + +.bxs-video-plus:before { + content: "\ee43"; +} + +.bxs-video-recording:before { + content: "\ee44"; +} + +.bxs-videos:before { + content: "\ee45"; +} + +.bxs-virus:before { + content: "\ee46"; +} + +.bxs-virus-block:before { + content: "\ee47"; +} + +.bxs-volume:before { + content: "\ee48"; +} + +.bxs-volume-full:before { + content: "\ee49"; +} + +.bxs-volume-low:before { + content: "\ee4a"; +} + +.bxs-volume-mute:before { + content: "\ee4b"; +} + +.bxs-wallet:before { + content: "\ee4c"; +} + +.bxs-wallet-alt:before { + content: "\ee4d"; +} + +.bxs-washer:before { + content: "\ee4e"; +} + +.bxs-watch:before { + content: "\ee4f"; +} + +.bxs-watch-alt:before { + content: "\ee50"; +} + +.bxs-webcam:before { + content: "\ee51"; +} + +.bxs-widget:before { + content: "\ee52"; +} + +.bxs-window-alt:before { + content: "\ee53"; +} + +.bxs-wine:before { + content: "\ee54"; +} + +.bxs-wink-smile:before { + content: "\ee55"; +} + +.bxs-wink-tongue:before { + content: "\ee56"; +} + +.bxs-wrench:before { + content: "\ee57"; +} + +.bxs-x-circle:before { + content: "\ee58"; +} + +.bxs-x-square:before { + content: "\ee59"; +} + +.bxs-yin-yang:before { + content: "\ee5a"; +} + +.bxs-zap:before { + content: "\ee5b"; +} + +.bxs-zoom-in:before { + content: "\ee5c"; +} + +.bxs-zoom-out:before { + content: "\ee5d"; +} + +.bxl-500px:before { + content: "\ee5e"; +} + +.bxl-adobe:before { + content: "\ee5f"; +} + +.bxl-airbnb:before { + content: "\ee60"; +} + +.bxl-algolia:before { + content: "\ee61"; +} + +.bxl-amazon:before { + content: "\ee62"; +} + +.bxl-android:before { + content: "\ee63"; +} + +.bxl-angular:before { + content: "\ee64"; +} + +.bxl-apple:before { + content: "\ee65"; +} + +.bxl-audible:before { + content: "\ee66"; +} + +.bxl-baidu:before { + content: "\ee67"; +} + +.bxl-behance:before { + content: "\ee68"; +} + +.bxl-bing:before { + content: "\ee69"; +} + +.bxl-bitcoin:before { + content: "\ee6a"; +} + +.bxl-blender:before { + content: "\ee6b"; +} + +.bxl-blogger:before { + content: "\ee6c"; +} + +.bxl-bootstrap:before { + content: "\ee6d"; +} + +.bxl-chrome:before { + content: "\ee6e"; +} + +.bxl-codepen:before { + content: "\ee6f"; +} + +.bxl-c-plus-plus:before { + content: "\ee70"; +} + +.bxl-creative-commons:before { + content: "\ee71"; +} + +.bxl-css3:before { + content: "\ee72"; +} + +.bxl-dailymotion:before { + content: "\ee73"; +} + +.bxl-deviantart:before { + content: "\ee74"; +} + +.bxl-dev-to:before { + content: "\ee75"; +} + +.bxl-digg:before { + content: "\ee76"; +} + +.bxl-digitalocean:before { + content: "\ee77"; +} + +.bxl-discord:before { + content: "\ee78"; +} + +.bxl-discourse:before { + content: "\ee79"; +} + +.bxl-django:before { + content: "\ee7a"; +} + +.bxl-dribbble:before { + content: "\ee7b"; +} + +.bxl-dropbox:before { + content: "\ee7c"; +} + +.bxl-drupal:before { + content: "\ee7d"; +} + +.bxl-ebay:before { + content: "\ee7e"; +} + +.bxl-edge:before { + content: "\ee7f"; +} + +.bxl-etsy:before { + content: "\ee80"; +} + +.bxl-facebook:before { + content: "\ee81"; +} + +.bxl-facebook-circle:before { + content: "\ee82"; +} + +.bxl-facebook-square:before { + content: "\ee83"; +} + +.bxl-figma:before { + content: "\ee84"; +} + +.bxl-firebase:before { + content: "\ee85"; +} + +.bxl-firefox:before { + content: "\ee86"; +} + +.bxl-flickr:before { + content: "\ee87"; +} + +.bxl-flickr-square:before { + content: "\ee88"; +} + +.bxl-foursquare:before { + content: "\ee89"; +} + +.bxl-git:before { + content: "\ee8a"; +} + +.bxl-github:before { + content: "\ee8b"; +} + +.bxl-gitlab:before { + content: "\ee8c"; +} + +.bxl-google:before { + content: "\ee8d"; +} + +.bxl-google-cloud:before { + content: "\ee8e"; +} + +.bxl-google-plus:before { + content: "\ee8f"; +} + +.bxl-google-plus-circle:before { + content: "\ee90"; +} + +.bxl-html5:before { + content: "\ee91"; +} + +.bxl-imdb:before { + content: "\ee92"; +} + +.bxl-instagram:before { + content: "\ee93"; +} + +.bxl-instagram-alt:before { + content: "\ee94"; +} + +.bxl-internet-explorer:before { + content: "\ee95"; +} + +.bxl-invision:before { + content: "\ee96"; +} + +.bxl-javascript:before { + content: "\ee97"; +} + +.bxl-joomla:before { + content: "\ee98"; +} + +.bxl-jquery:before { + content: "\ee99"; +} + +.bxl-jsfiddle:before { + content: "\ee9a"; +} + +.bxl-kickstarter:before { + content: "\ee9b"; +} + +.bxl-kubernetes:before { + content: "\ee9c"; +} + +.bxl-less:before { + content: "\ee9d"; +} + +.bxl-linkedin:before { + content: "\ee9e"; +} + +.bxl-linkedin-square:before { + content: "\ee9f"; +} + +.bxl-magento:before { + content: "\eea0"; +} + +.bxl-mailchimp:before { + content: "\eea1"; +} + +.bxl-markdown:before { + content: "\eea2"; +} + +.bxl-mastercard:before { + content: "\eea3"; +} + +.bxl-medium:before { + content: "\eea4"; +} + +.bxl-medium-old:before { + content: "\eea5"; +} + +.bxl-medium-square:before { + content: "\eea6"; +} + +.bxl-messenger:before { + content: "\eea7"; +} + +.bxl-microsoft:before { + content: "\eea8"; +} + +.bxl-microsoft-teams:before { + content: "\eea9"; +} + +.bxl-nodejs:before { + content: "\eeaa"; +} + +.bxl-ok-ru:before { + content: "\eeab"; +} + +.bxl-opera:before { + content: "\eeac"; +} + +.bxl-patreon:before { + content: "\eead"; +} + +.bxl-paypal:before { + content: "\eeae"; +} + +.bxl-periscope:before { + content: "\eeaf"; +} + +.bxl-pinterest:before { + content: "\eeb0"; +} + +.bxl-pinterest-alt:before { + content: "\eeb1"; +} + +.bxl-play-store:before { + content: "\eeb2"; +} + +.bxl-pocket:before { + content: "\eeb3"; +} + +.bxl-product-hunt:before { + content: "\eeb4"; +} + +.bxl-python:before { + content: "\eeb5"; +} + +.bxl-quora:before { + content: "\eeb6"; +} + +.bxl-react:before { + content: "\eeb7"; +} + +.bxl-redbubble:before { + content: "\eeb8"; +} + +.bxl-reddit:before { + content: "\eeb9"; +} + +.bxl-redux:before { + content: "\eeba"; +} + +.bxl-sass:before { + content: "\eebb"; +} + +.bxl-shopify:before { + content: "\eebc"; +} + +.bxl-skype:before { + content: "\eebd"; +} + +.bxl-slack:before { + content: "\eebe"; +} + +.bxl-slack-old:before { + content: "\eebf"; +} + +.bxl-snapchat:before { + content: "\eec0"; +} + +.bxl-soundcloud:before { + content: "\eec1"; +} + +.bxl-spotify:before { + content: "\eec2"; +} + +.bxl-spring-boot:before { + content: "\eec3"; +} + +.bxl-squarespace:before { + content: "\eec4"; +} + +.bxl-stack-overflow:before { + content: "\eec5"; +} + +.bxl-stripe:before { + content: "\eec6"; +} + +.bxl-telegram:before { + content: "\eec7"; +} + +.bxl-trello:before { + content: "\eec8"; +} + +.bxl-tumblr:before { + content: "\eec9"; +} + +.bxl-tux:before { + content: "\eeca"; +} + +.bxl-twitch:before { + content: "\eecb"; +} + +.bxl-twitter:before { + content: "\eecc"; +} + +.bxl-unsplash:before { + content: "\eecd"; +} + +.bxl-vimeo:before { + content: "\eece"; +} + +.bxl-visa:before { + content: "\eecf"; +} + +.bxl-vk:before { + content: "\eed0"; +} + +.bxl-vuejs:before { + content: "\eed1"; +} + +.bxl-whatsapp:before { + content: "\eed2"; +} + +.bxl-whatsapp-square:before { + content: "\eed3"; +} + +.bxl-wikipedia:before { + content: "\eed4"; +} + +.bxl-windows:before { + content: "\eed5"; +} + +.bxl-wix:before { + content: "\eed6"; +} + +.bxl-wordpress:before { + content: "\eed7"; +} + +.bxl-yahoo:before { + content: "\eed8"; +} + +.bxl-yelp:before { + content: "\eed9"; +} + +.bxl-youtube:before { + content: "\eeda"; +} + +.bxl-zoom:before { + content: "\eedb"; +} + \ No newline at end of file diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.eot b/packages/integration/src/styles/fonts/bxicons/boxicons.eot new file mode 100644 index 00000000..09b170b3 Binary files /dev/null and b/packages/integration/src/styles/fonts/bxicons/boxicons.eot differ diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.svg b/packages/integration/src/styles/fonts/bxicons/boxicons.svg new file mode 100644 index 00000000..dc784e6a --- /dev/null +++ b/packages/integration/src/styles/fonts/bxicons/boxicons.svg @@ -0,0 +1,1510 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.ttf b/packages/integration/src/styles/fonts/bxicons/boxicons.ttf new file mode 100644 index 00000000..32834610 Binary files /dev/null and b/packages/integration/src/styles/fonts/bxicons/boxicons.ttf differ diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.woff b/packages/integration/src/styles/fonts/bxicons/boxicons.woff new file mode 100644 index 00000000..7c231050 Binary files /dev/null and b/packages/integration/src/styles/fonts/bxicons/boxicons.woff differ diff --git a/packages/integration/src/styles/fonts/bxicons/boxicons.woff2 b/packages/integration/src/styles/fonts/bxicons/boxicons.woff2 new file mode 100644 index 00000000..d4079f6f Binary files /dev/null and b/packages/integration/src/styles/fonts/bxicons/boxicons.woff2 differ diff --git a/packages/integration/src/styles/fonts/bxicons/index.css b/packages/integration/src/styles/fonts/bxicons/index.css new file mode 100644 index 00000000..f5f919da --- /dev/null +++ b/packages/integration/src/styles/fonts/bxicons/index.css @@ -0,0 +1,3 @@ +@import "boxicons.css"; +@import "animations.css"; +@import "transformations.css"; \ No newline at end of file diff --git a/packages/integration/src/styles/fonts/bxicons/transformations.css b/packages/integration/src/styles/fonts/bxicons/transformations.css new file mode 100644 index 00000000..a4634073 --- /dev/null +++ b/packages/integration/src/styles/fonts/bxicons/transformations.css @@ -0,0 +1,29 @@ +.bx-rotate-90 { + transform: rotate(90deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)'; +} + +.bx-rotate-180 { + transform: rotate(180deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)'; +} + +.bx-rotate-270 { + transform: rotate(270deg); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; +} + +.bx-flip-horizontal { + transform: scaleX(-1); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)'; +} + +.bx-flip-vertical { + transform: scaleY(-1); + + -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)'; +} diff --git a/packages/integration/src/styles/fonts/inconsolata/index.css b/packages/integration/src/styles/fonts/inconsolata/index.css new file mode 100644 index 00000000..36643be1 --- /dev/null +++ b/packages/integration/src/styles/fonts/inconsolata/index.css @@ -0,0 +1,27 @@ + +/* vietnamese */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + src: local('Inconsolata Regular'), local('Inconsolata-Regular'), url(https://fonts.gstatic.com/s/inconsolata/v16/QldKNThLqRwH-OJ1UHjlKGlW5qhExfHwNJU.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + src: local('Inconsolata Regular'), local('Inconsolata-Regular'), url(https://fonts.gstatic.com/s/inconsolata/v16/QldKNThLqRwH-OJ1UHjlKGlX5qhExfHwNJU.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Inconsolata'; + font-style: normal; + font-weight: 400; + src: local('Inconsolata Regular'), local('Inconsolata-Regular'), url(https://fonts.gstatic.com/s/inconsolata/v16/QldKNThLqRwH-OJ1UHjlKGlZ5qhExfHw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/packages/integration/src/styles/fonts/index.css b/packages/integration/src/styles/fonts/index.css new file mode 100644 index 00000000..a92aee58 --- /dev/null +++ b/packages/integration/src/styles/fonts/index.css @@ -0,0 +1,3 @@ +@import "bxicons/index.css"; +@import "inconsolata/index.css"; +@import "source-sans-pro/index.css"; diff --git a/packages/integration/src/styles/fonts/source-sans-pro/index.css b/packages/integration/src/styles/fonts/source-sans-pro/index.css new file mode 100644 index 00000000..609c56a4 --- /dev/null +++ b/packages/integration/src/styles/fonts/source-sans-pro/index.css @@ -0,0 +1,188 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu3cOWxw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lujVj9_mf.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lujVj9_mf.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lujVj9_mf.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lujVj9_mf.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lujVj9_mf.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lujVj9_mf.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7lujVj9w.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwkxdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmxdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlBdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmBdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmRdu3cOWxy40.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v11/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdu3cOWxw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/packages/integration/src/styles/index.css b/packages/integration/src/styles/index.css new file mode 100644 index 00000000..25033417 --- /dev/null +++ b/packages/integration/src/styles/index.css @@ -0,0 +1,6 @@ +@import "tailwind.css"; +@import "fonts/index.css"; +@import "typography.css"; +@import "formiojs/dist/formio.full.css"; +@import "@tsed/tailwind-formio/styles/index.css"; + diff --git a/packages/integration/src/styles/tailwind.css b/packages/integration/src/styles/tailwind.css new file mode 100644 index 00000000..f42b270d --- /dev/null +++ b/packages/integration/src/styles/tailwind.css @@ -0,0 +1,2 @@ +@tailwind base; +@tailwind utilities; diff --git a/packages/integration/src/styles/typography.css b/packages/integration/src/styles/typography.css new file mode 100644 index 00000000..f5f2682f --- /dev/null +++ b/packages/integration/src/styles/typography.css @@ -0,0 +1,33 @@ +body { + font-family: Source Sans Pro, sans-serif; +} + +/* Commons styles */ +html { + box-sizing: border-box; + overflow-x: hidden; + background-color: #fff; +} + +*, +*::before, +*::after { + box-sizing: inherit; + + /* Normalization for tailwindcss border utilities */ + border-color: theme('borderColors.default', currentColor); + border-style: solid; + border-width: 0; +} + +body { + min-width: calc(300rem / 16); + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + line-height: 1.4; + min-height: 100vh; + + @apply text-gray-darker; + @apply text-base; + @apply font-sans; +} diff --git a/packages/integration/src/vite-env.d.ts b/packages/integration/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/packages/integration/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/integration/tailwind.config.ts b/packages/integration/tailwind.config.ts new file mode 100644 index 00000000..fa7d3a51 --- /dev/null +++ b/packages/integration/tailwind.config.ts @@ -0,0 +1,8 @@ +import { tailwindPreset } from "@tsed/tailwind-formio/tailwind.preset"; +import type { Config } from "tailwindcss"; + +export default { + content: ["../*/src/**/*.{js,jsx,ts,tsx,mdx,ejs}"], + darkMode: "class", + presets: [tailwindPreset] +} satisfies Config; diff --git a/packages/integration/tsconfig.app.json b/packages/integration/tsconfig.app.json new file mode 100644 index 00000000..d187a0c6 --- /dev/null +++ b/packages/integration/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "Bundler", + "baseUrl": ".", + "noEmit": true, + "declaration": false, + "composite": false + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.mts", "tailwind.config.ts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts", "src/**/*.spec.tsx"] +} diff --git a/packages/integration/tsconfig.json b/packages/integration/tsconfig.json new file mode 100644 index 00000000..94084c57 --- /dev/null +++ b/packages/integration/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "baseUrl": ".", + "composite": true, + "noEmit": true + }, + "include": [], + "exclude": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/packages/integration/vite.config.mts b/packages/integration/vite.config.mts new file mode 100644 index 00000000..9a95af47 --- /dev/null +++ b/packages/integration/vite.config.mts @@ -0,0 +1,17 @@ +import react from "@vitejs/plugin-react"; +import {defineConfig} from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + conditions: [ + // "source", + "import", + "module", + "browser", + "default" + ], + alias: {} + }, +}); diff --git a/packages/react-formio-container/.eslintignore b/packages/react-formio-container/.eslintignore deleted file mode 100644 index 474be905..00000000 --- a/packages/react-formio-container/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -**/node_modules -docs -docs-references -**/lib -**/build -**/dist -**/coverage -**/.nyc_output -**/node_modules -*-lock.json -*.lock -benchmarks.* -**/generated diff --git a/packages/react-formio-container/.eslintrc.js b/packages/react-formio-container/.eslintrc.js deleted file mode 100644 index b4dbf589..00000000 --- a/packages/react-formio-container/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: [require.resolve("@tsed/config/eslint/web")], - rules: { - "import/no-anonymous-default-export": 0 - } -}; diff --git a/packages/react-formio-container/coverage.json b/packages/react-formio-container/coverage.json deleted file mode 100644 index 64ee77c4..00000000 --- a/packages/react-formio-container/coverage.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "statements": 0, - "branches": 0, - "functions": 0, - "lines": 0 -} diff --git a/packages/react-formio-container/jest.config.js b/packages/react-formio-container/jest.config.js deleted file mode 100644 index fe16413a..00000000 --- a/packages/react-formio-container/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - ...require("@tsed/config/jest/jest.web.config.js"), - coverageThreshold: { - global: require("./coverage.json") - } -}; diff --git a/packages/react-formio-container/package.json b/packages/react-formio-container/package.json index bb6dca86..6069676c 100644 --- a/packages/react-formio-container/package.json +++ b/packages/react-formio-container/package.json @@ -1,35 +1,40 @@ { "name": "@tsed/react-formio-container", "description": "Provide advanced components and tools to create your own formio backoffice.", - "version": "2.3.2", + "version": "3.0.0-alpha.9", + "type": "module", "main": "dist/index.js", - "module": "dist/index.modern.js", - "source": "src/index.tsx", + "module": "dist/index.js", + "source": "src/index.ts", "license": "MIT", "exports": { ".": { - "import": "./dist/index.modern.js", - "require": "./dist/index.js" + "types": "./dist/index.d.ts", + "tsed-source": "./src/index.ts", + "default": "./dist/index.js" + }, + "./*": { + "types": "./dist/*.d.ts", + "tsed-source": "./src/*", + "default": "./dist/*.js" } }, "scripts": { - "test": "cross-env NODE_ENV=test jest --coverage", - "test:coverage:update": "write-coverage", - "build": "microbundle --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx", - "watch": "microbundle watch --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx" + "test": "vitest run --coverage", + "build": "vite build", + "watch": "vite watch" }, "peerDependencies": { "@formio/choices.js": "^9.0.1", - "@tsed/react-formio": "2.3.2", - "@tsed/react-formio-stores": "2.3.2", + "@tsed/react-formio": "3.0.0-alpha.9", + "@tsed/react-formio-stores": "3.0.0-alpha.9", "classnames": "^2.3.1", "connected-react-router": "^6.9.1", "file-saver": "^2.0.5", - "formiojs": "^4.14.13", + "formiojs": "^4.21.6", "lodash": "^4.17.21", - "prop-types": "^15.8.1", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", "react-is": "^17.0.1", "react-redux": "^7.2.6", "react-router": "^5.2.1", @@ -42,7 +47,9 @@ "@tsed/react-formio": "workspace:*", "@tsed/react-formio-stores": "workspace:*", "@types/file-saver": "^2.0.1", - "file-saver": "^2.0.5" + "file-saver": "^2.0.5", + "vite": "5.4.11", + "vitest": "2.1.8" }, "peerDependenciesMeta": { "choices.js": { @@ -63,9 +70,6 @@ "lodash": { "optional": false }, - "prop-types": { - "optional": false - }, "react": { "optional": false }, diff --git a/packages/react-formio-container/readme.md b/packages/react-formio-container/readme.md index 00aa402e..b4efb80a 100644 --- a/packages/react-formio-container/readme.md +++ b/packages/react-formio-container/readme.md @@ -1,5 +1,5 @@

- Ts.ED logo + Ts.ED logo

@@ -14,11 +14,11 @@
- Website + Website   •   - Tutorial + Tutorial   •   - Slack + Slack   •   Twitter
@@ -29,7 +29,7 @@ A [React](http://facebook.github.io/react/) library for rendering out forms base This module is based on the original [react-formio](https://github.com/formio/react-formio) and add extra features listed above. -See our [storybook](https://formio.tsed.io/) to see all available components. +See our [storybook](https://formio.tsed.dev/) to see all available components. ## Features diff --git a/packages/react-formio-container/src/formio.container.tsx b/packages/react-formio-container/src/formio.container.tsx index 53647fd4..4651fe86 100644 --- a/packages/react-formio-container/src/formio.container.tsx +++ b/packages/react-formio-container/src/formio.container.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { useParams } from "react-router"; import { Route, Switch } from "react-router-dom"; diff --git a/packages/react-formio-container/src/hooks/useAction.hook.tsx b/packages/react-formio-container/src/hooks/useAction.hook.tsx index fc5b95ad..8677717a 100644 --- a/packages/react-formio-container/src/hooks/useAction.hook.tsx +++ b/packages/react-formio-container/src/hooks/useAction.hook.tsx @@ -1,6 +1,6 @@ import { - ActionInfoSchema, - ActionSchema, + ActionInfoType, + ActionType, deleteAction, getAction, getActionInfo, @@ -11,7 +11,7 @@ import { selectAuth, selectError, selectForm, - Submission, + SubmissionType, Utils } from "@tsed/react-formio-stores"; import { push } from "connected-react-router"; @@ -35,7 +35,7 @@ export function useAction(props: UseActionProps) { const form = useSelector((state) => selectForm(type, state)); const error = useSelector((state) => selectError("action", state)); const action = useSelector(selectAction); - const actionInfo: ActionInfoSchema | undefined = useSelector(selectActionInfo) as any; + const actionInfo: ActionInfoType | undefined = useSelector(selectActionInfo) as any; const fetch = useCallback(() => { if (form?._id) { @@ -47,7 +47,7 @@ export function useAction(props: UseActionProps) { } }, [form?._id, actionId]); - const onSaveDone = (err: Error | null, actionInfo: ActionSchema) => { + const onSaveDone = (err: Error | null, actionInfo: ActionType) => { if (!err) { onSuccess({ name: `${actionAction}:action`, @@ -68,7 +68,7 @@ export function useAction(props: UseActionProps) { } }; - const saveAction = (actionInfo: Submission) => { + const saveAction = (actionInfo: SubmissionType) => { dispatch(saveAct(form?._id!, actionInfo, onSaveDone)); }; diff --git a/packages/react-formio-container/src/hooks/useActions.hook.ts b/packages/react-formio-container/src/hooks/useActions.hook.ts index ce922e4e..60b86de8 100644 --- a/packages/react-formio-container/src/hooks/useActions.hook.ts +++ b/packages/react-formio-container/src/hooks/useActions.hook.ts @@ -1,6 +1,6 @@ import { - ActionInfoSchema, - ActionSchema, + ActionInfoType, + ActionType, Operation, selectActions, selectAuth, @@ -37,13 +37,13 @@ export function useActions(props: UseActionsProps) { }); const [operation, setOperation] = useState(); - const [currentAction, setCurrentAction] = useState(availableActions[0]); + const [currentAction, setCurrentAction] = useState(availableActions[0]); const addAction = (actionName: string) => { dispatch(push([basePath, actionName, "add"].join("/"))); }; - const dispatchOperation = (actionInfo: ActionSchema, operation: Operation) => { + const dispatchOperation = (actionInfo: ActionType, operation: Operation) => { setOperation(operation); dispatch(push([basePath, (actionInfo as any)._id, operation.action].join("/"))); diff --git a/packages/react-formio-container/src/hooks/useForm.hook.ts b/packages/react-formio-container/src/hooks/useForm.hook.ts index fc7378f3..447d8fbb 100644 --- a/packages/react-formio-container/src/hooks/useForm.hook.ts +++ b/packages/react-formio-container/src/hooks/useForm.hook.ts @@ -1,7 +1,7 @@ import { AuthState, deleteForm, - FormSchema, + FormType, getForm as getFormAction, oneOfIsActive, receiveForm, @@ -99,7 +99,7 @@ export function useForm(props: UseFormProps) { form._id && dispatch(deleteForm(formType, form._id, onRemoveDone)); }; - const duplicateForm = (form: Partial) => { + const duplicateForm = (form: Partial) => { dispatch(receiveForm(formType, { ...form, _id: undefined })); dispatch(push(`${basePath}/create`)); onSuccess({ @@ -110,7 +110,7 @@ export function useForm(props: UseFormProps) { }); }; - const onSaveDone = async (err: Error | null, updatedForm: FormSchema) => { + const onSaveDone = async (err: Error | null, updatedForm: FormType) => { if (!err) { dispatch(refreshForms(formType)); @@ -133,7 +133,7 @@ export function useForm(props: UseFormProps) { } }; - const saveForm = (form: Partial) => { + const saveForm = (form: Partial) => { onSubmitForm(type, form); dispatch(saveFormAction(type, form, onSaveDone)); }; diff --git a/packages/react-formio-container/src/hooks/useForms.hook.ts b/packages/react-formio-container/src/hooks/useForms.hook.ts index 0783023b..8383a18f 100644 --- a/packages/react-formio-container/src/hooks/useForms.hook.ts +++ b/packages/react-formio-container/src/hooks/useForms.hook.ts @@ -1,4 +1,4 @@ -import { FormSchema, FormsState, getForms, Operation, selectRoot } from "@tsed/react-formio-stores"; +import { FormsState, FormType, getForms, Operation, selectRoot } from "@tsed/react-formio-stores"; import { push } from "connected-react-router"; import { useCallback, useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -23,9 +23,9 @@ export function useForms(props: UseFormsProps) { const { error, data, isActive, parameters } = useSelector((state) => selectRoot(formType, state)); const setParameters = useQuery(fetch, parameters); const [operation, setOperation] = useState(); - const [currentData, setCurrentData] = useState(); + const [currentData, setCurrentData] = useState(); - const dispatchOperation = (data: FormSchema, operation: Operation) => { + const dispatchOperation = (data: FormType, operation: Operation) => { setOperation(operation); setCurrentData(currentData); dispatch(push([basePath.replace(":formType", formType), data._id, operation.action].join("/"))); diff --git a/packages/react-formio-container/src/hooks/useQuery.hook.spec.tsx b/packages/react-formio-container/src/hooks/useQuery.hook.spec.tsx index bf2a227e..1e825d94 100644 --- a/packages/react-formio-container/src/hooks/useQuery.hook.spec.tsx +++ b/packages/react-formio-container/src/hooks/useQuery.hook.spec.tsx @@ -1,5 +1,4 @@ import { fireEvent, render, screen } from "@testing-library/react"; -import React from "react"; import { useQuery } from "./useQuery.hook"; @@ -19,7 +18,7 @@ function FixtureQuery(props: any) { describe("useQueryHook", () => { it("should call onChange", () => { - const onChange = jest.fn(); + const onChange = vi.fn(); render( { }); }); it("should not call onChange", () => { - const onChange = jest.fn(); + const onChange = vi.fn(); render( { + const onSaveDone = async (err: Error | null, updatedSubmission: SubmissionType) => { if (!err) { onSuccess({ name: `${submissionAction}:${submissionType}`, @@ -104,7 +104,7 @@ export function useSubmission(props: UseSubmissionProps) { } }; - const saveSubmission = (submission: Submission) => { + const saveSubmission = (submission: SubmissionType) => { onSubmitSubmission(submissionType, formId, submission); dispatch(saveSubmissionAction(submissionType, formId, submission, onSaveDone)); }; diff --git a/packages/react-formio-container/src/hooks/useSubmissions.hook.tsx b/packages/react-formio-container/src/hooks/useSubmissions.hook.tsx index 4a0a6516..1a100e9e 100644 --- a/packages/react-formio-container/src/hooks/useSubmissions.hook.tsx +++ b/packages/react-formio-container/src/hooks/useSubmissions.hook.tsx @@ -1,4 +1,4 @@ -import { getSubmissions, Operation, selectAuth, selectForm, selectRoot, Submission, SubmissionsState } from "@tsed/react-formio-stores"; +import { getSubmissions, Operation, selectAuth, selectForm, selectRoot, SubmissionsState, SubmissionType } from "@tsed/react-formio-stores"; import { push } from "connected-react-router"; import { useCallback, useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -28,9 +28,9 @@ export function useSubmissions(props: UseSubmissionsProps) { const setParameters = useQuery(fetch, parameters); const [operation, setOperation] = useState(); - const [currentData, setCurrentData] = useState(); + const [currentData, setCurrentData] = useState(); - const dispatchOperation = (data: Submission, operation: Operation) => { + const dispatchOperation = (data: SubmissionType, operation: Operation) => { setOperation(operation); setCurrentData(currentData); dispatch(push([basePath, data._id, operation.action].join("/"))); diff --git a/packages/react-formio-container/src/index.tsx b/packages/react-formio-container/src/index.ts similarity index 100% rename from packages/react-formio-container/src/index.tsx rename to packages/react-formio-container/src/index.ts diff --git a/packages/react-formio-container/src/interfaces/FormioContainerOptions.ts b/packages/react-formio-container/src/interfaces/FormioContainerOptions.ts index d034e793..6b10b5c8 100644 --- a/packages/react-formio-container/src/interfaces/FormioContainerOptions.ts +++ b/packages/react-formio-container/src/interfaces/FormioContainerOptions.ts @@ -1,4 +1,4 @@ -import { FormSchema, Submission } from "@tsed/react-formio"; +import { FormType, SubmissionType } from "@tsed/react-formio"; import { FormRoute } from "../views/form.routes"; @@ -54,8 +54,8 @@ export interface FormioContainerOptions extends Record { * Handler called when an event is an error */ onError?: FormioErrorHandler; - onSubmitForm?: (type: string, form: FormSchema) => void; - onSubmitSubmission?: (submissionType: string, formId: string, submission: Submission) => void; + onSubmitForm?: (type: string, form: FormType) => void; + onSubmitSubmission?: (submissionType: string, formId: string, submission: SubmissionType) => void; /** * i18n function to translate sentences */ diff --git a/packages/react-formio-container/src/utils/ExportClient.ts b/packages/react-formio-container/src/utils/ExportClient.ts index 0ab5144d..28facca1 100644 --- a/packages/react-formio-container/src/utils/ExportClient.ts +++ b/packages/react-formio-container/src/utils/ExportClient.ts @@ -1,4 +1,4 @@ -import { FormSchema } from "@tsed/react-formio"; +import { FormType } from "@tsed/react-formio"; import FileSaver from "file-saver"; import moment from "moment"; @@ -8,12 +8,12 @@ async function getDatabase() { return httpClient.get("/export"); } -async function exportForm(form: FormSchema) { +async function exportForm(form: FormType) { const database = await getDatabase(); return database.forms[form.machineName!] || database.resources[form.machineName!]; } -async function exportActions(form: FormSchema) { +async function exportActions(form: FormType) { const database = await getDatabase(); return Object.entries(database.actions).reduce((obj, [machineName, action]) => { @@ -25,7 +25,7 @@ async function exportActions(form: FormSchema) { }, {}); } -async function getContent(form: FormSchema, type: string, format = "json") { +async function getContent(form: FormType, type: string, format = "json") { let result; console.log(form, type, format); switch (type) { diff --git a/packages/react-formio-container/src/views/form.routes.tsx b/packages/react-formio-container/src/views/form.routes.tsx index 2e6fbc4d..6dbd4c54 100644 --- a/packages/react-formio-container/src/views/form.routes.tsx +++ b/packages/react-formio-container/src/views/form.routes.tsx @@ -1,6 +1,6 @@ -import type { TabsItemProps } from "@tsed/react-formio"; -import { AuthState, checkRoleFormAccess, FormSchema } from "@tsed/react-formio-stores"; -import React from "react"; +import type { TabsItemProps } from "@tsed/react-formio/molecules/tabs/Tabs"; +import { AuthState, checkRoleFormAccess, FormType } from "@tsed/react-formio-stores"; +import { ComponentType } from "react"; import { FormAccessView } from "./formAccess.view"; import { FormActionsView } from "./formActions.view"; @@ -10,21 +10,21 @@ import { FormPreviewView } from "./formPreview.view"; import { FormSettingsView } from "./formSettings.view"; import { SubmissionsView } from "./submissions.view"; -export interface FormRoute extends TabsItemProps, Record { +export interface FormRoute extends TabsItemProps, Record { action: string; exact: boolean; - component?: React.ComponentType; + component?: ComponentType; roles?: string[]; - when?(ctx: { formAction: string; auth: AuthState; form: Partial; item: FormRoute }): boolean; + when?(ctx: { formAction: string; auth: AuthState; form: Partial; item: FormRoute }): boolean; } -export interface FormRoutesOptions { +export interface FormRoutesOptions { formRoutes: FormRoute[]; operationsSettings: Record; formAction: string; auth: AuthState; - form: Partial; + form: Partial; } export const defaultFormRoutes: FormRoute[] = [ @@ -99,7 +99,7 @@ export function findRoute(routes: FormRoute[], formAction: string): FormRoute | return routes.find(({ action }) => (formAction === "delete" ? action === "edit" : formAction === action)); } -export function getFormRoutes({ +export function getFormRoutes({ formRoutes = defaultFormRoutes, operationsSettings, formAction, diff --git a/packages/react-formio-container/src/views/form.view.tsx b/packages/react-formio-container/src/views/form.view.tsx index 87a6cfb5..6a0cc988 100644 --- a/packages/react-formio-container/src/views/form.view.tsx +++ b/packages/react-formio-container/src/views/form.view.tsx @@ -1,5 +1,7 @@ -import { Alert, Loader, RemoveModal, Tabs } from "@tsed/react-formio"; -import React from "react"; +import { Alert } from "@tsed/react-formio/molecules/alert/Alert"; +import { Loader } from "@tsed/react-formio/molecules/loader/Loader"; +import { Tabs } from "@tsed/react-formio/molecules/tabs/Tabs"; +import { RemoveModal } from "@tsed/react-formio/organisms/modal/RemoveModal"; import { Route, Switch, useParams } from "react-router"; import { useForm } from "../hooks/useForm.hook"; @@ -14,7 +16,7 @@ function FormComponent({ className, ...props }: ReturnType) { return (
- +
diff --git a/packages/react-formio-container/src/views/formAccess.view.tsx b/packages/react-formio-container/src/views/formAccess.view.tsx index a4ac6a3c..9cf1319e 100644 --- a/packages/react-formio-container/src/views/formAccess.view.tsx +++ b/packages/react-formio-container/src/views/formAccess.view.tsx @@ -1,5 +1,4 @@ -import { FormAccess } from "@tsed/react-formio"; -import React from "react"; +import { FormAccess } from "@tsed/react-formio/organisms/form/access/FormAccess"; import { useForm } from "../hooks/useForm.hook"; diff --git a/packages/react-formio-container/src/views/formAction.view.tsx b/packages/react-formio-container/src/views/formAction.view.tsx index 60acccac..d2f5d1c1 100644 --- a/packages/react-formio-container/src/views/formAction.view.tsx +++ b/packages/react-formio-container/src/views/formAction.view.tsx @@ -1,6 +1,8 @@ -import { FormAction, iconClass, RemoveModal, useTooltip } from "@tsed/react-formio"; +import { useTooltip } from "@tsed/react-formio/hooks/useTooltip"; +import { FormAction } from "@tsed/react-formio/organisms/form/action/FormAction"; +import { RemoveModal } from "@tsed/react-formio/organisms/modal/RemoveModal"; +import { iconClass } from "@tsed/react-formio/utils/iconClass"; import classnames from "classnames"; -import React from "react"; import { useParams } from "react-router"; import { UseActionsProps } from "../hooks"; diff --git a/packages/react-formio-container/src/views/formActions.view.tsx b/packages/react-formio-container/src/views/formActions.view.tsx index b22e50d9..07f710be 100644 --- a/packages/react-formio-container/src/views/formActions.view.tsx +++ b/packages/react-formio-container/src/views/formActions.view.tsx @@ -1,5 +1,4 @@ -import { ActionsTable } from "@tsed/react-formio"; -import React from "react"; +import { ActionsTable } from "@tsed/react-formio/organisms/table/actions/ActionsTable"; import { Route, Switch } from "react-router"; import { useActions, UseActionsProps } from "../hooks/useActions.hook"; diff --git a/packages/react-formio-container/src/views/formEdit.view.tsx b/packages/react-formio-container/src/views/formEdit.view.tsx index 30681a53..12a581f8 100644 --- a/packages/react-formio-container/src/views/formEdit.view.tsx +++ b/packages/react-formio-container/src/views/formEdit.view.tsx @@ -1,6 +1,5 @@ -import { FormEdit } from "@tsed/react-formio"; +import { FormEdit } from "@tsed/react-formio/organisms/form/builder/FormEdit"; import classnames from "classnames"; -import React from "react"; import { useForm } from "../hooks/useForm.hook"; diff --git a/packages/react-formio-container/src/views/formExport.view.tsx b/packages/react-formio-container/src/views/formExport.view.tsx index 0187fc3f..963a4ffd 100644 --- a/packages/react-formio-container/src/views/formExport.view.tsx +++ b/packages/react-formio-container/src/views/formExport.view.tsx @@ -1,5 +1,5 @@ -import { Card, iconClass } from "@tsed/react-formio"; -import React from "react"; +import { Card } from "@tsed/react-formio/molecules/card/Card"; +import { iconClass } from "@tsed/react-formio/utils/iconClass"; import { UseFormProps } from "../hooks/useForm.hook"; import { useFormExport } from "../hooks/useFormExport"; diff --git a/packages/react-formio-container/src/views/formPreview.view.tsx b/packages/react-formio-container/src/views/formPreview.view.tsx index 4172a5cf..f0d93c6a 100644 --- a/packages/react-formio-container/src/views/formPreview.view.tsx +++ b/packages/react-formio-container/src/views/formPreview.view.tsx @@ -1,5 +1,6 @@ -import { Card, Form } from "@tsed/react-formio"; -import React from "react"; +import type { FormType } from "@tsed/react-formio"; +import { Card } from "@tsed/react-formio/molecules/card/Card"; +import { Form } from "@tsed/react-formio/organisms/form/Form"; import { useForm } from "../hooks"; @@ -7,7 +8,7 @@ export function FormPreviewView({ form, i18n }: ReturnType) { return (
-
+
); diff --git a/packages/react-formio-container/src/views/formSettings.view.tsx b/packages/react-formio-container/src/views/formSettings.view.tsx index 4c47c1b5..4cff583c 100644 --- a/packages/react-formio-container/src/views/formSettings.view.tsx +++ b/packages/react-formio-container/src/views/formSettings.view.tsx @@ -1,5 +1,4 @@ -import { FormSettings } from "@tsed/react-formio"; -import React from "react"; +import { FormSettings } from "@tsed/react-formio/organisms/form/settings/FormSettings"; import { useForm } from "../hooks/useForm.hook"; diff --git a/packages/react-formio-container/src/views/forms.stories.tsx b/packages/react-formio-container/src/views/forms.stories.tsx index e7623f9f..1740500e 100644 --- a/packages/react-formio-container/src/views/forms.stories.tsx +++ b/packages/react-formio-container/src/views/forms.stories.tsx @@ -1,5 +1,3 @@ -import React from "react"; - import { FormsComponent } from "./forms.view"; export default { @@ -7,9 +5,7 @@ export default { component: FormsComponent, argTypes: { data: { - control: { - type: "object" - } + control: "object" }, setParameters: { action: "setParameters" }, dispatchOperation: { action: "dispatchOperation" } diff --git a/packages/react-formio-container/src/views/forms.view.tsx b/packages/react-formio-container/src/views/forms.view.tsx index 6768189c..7fc4085c 100644 --- a/packages/react-formio-container/src/views/forms.view.tsx +++ b/packages/react-formio-container/src/views/forms.view.tsx @@ -1,5 +1,5 @@ -import { Alert, FormsTable } from "@tsed/react-formio"; -import React from "react"; +import { Alert } from "@tsed/react-formio/molecules/alert/Alert"; +import { FormsTable } from "@tsed/react-formio/organisms/table/forms/FormsTable"; import { useForms, UseFormsProps } from "../hooks/useForms.hook"; @@ -40,7 +40,7 @@ export function FormsComponent({ return (
- + ) {
- + {submissionAction === "delete" && ( { }; Sandbox.args = { - form: formSchema, + form: FormType, data: formSubmissions }; diff --git a/packages/react-formio-container/src/views/submissions.view.tsx b/packages/react-formio-container/src/views/submissions.view.tsx index f0ab8add..df28a2dd 100644 --- a/packages/react-formio-container/src/views/submissions.view.tsx +++ b/packages/react-formio-container/src/views/submissions.view.tsx @@ -1,5 +1,4 @@ -import { SubmissionsTable } from "@tsed/react-formio"; -import React from "react"; +import { SubmissionsTable } from "@tsed/react-formio/organisms/table/submissions/SubmissionsTable"; import { Route, Switch } from "react-router"; import { UseSubmissionProps } from "../hooks/useSubmission.hook"; diff --git a/packages/react-formio-container/tsconfig.app.json b/packages/react-formio-container/tsconfig.app.json new file mode 100644 index 00000000..ee6ad461 --- /dev/null +++ b/packages/react-formio-container/tsconfig.app.json @@ -0,0 +1,11 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "baseUrl": ".", + "noEmit": true, + "declaration": false, + "composite": false + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts", "src/**/*.spec.tsx"] +} diff --git a/packages/react-formio-container/tsconfig.json b/packages/react-formio-container/tsconfig.json index 6d8ba8e4..9255ac0e 100644 --- a/packages/react-formio-container/tsconfig.json +++ b/packages/react-formio-container/tsconfig.json @@ -1,15 +1,21 @@ { - "extends": "@tsed/config/tsconfig.web.json", "compilerOptions": { - "rootDir": "src" + "baseUrl": ".", + "composite": true }, - "include": ["src"], + "include": [], "references": [ + { + "path": "../react-formio/tsconfig.json" + }, + { + "path": "./tsconfig.app.json" + }, { "path": "./tsconfig.node.json" }, { - "path": "../react-formio/tsconfig.json" + "path": "./tsconfig.spec.json" } ] } diff --git a/packages/react-formio-container/tsconfig.node.json b/packages/react-formio-container/tsconfig.node.json index 8ce10716..4e75ad79 100644 --- a/packages/react-formio-container/tsconfig.node.json +++ b/packages/react-formio-container/tsconfig.node.json @@ -1,8 +1,13 @@ { + "extends": "@tsed/typescript/tsconfig.web.json", "compilerOptions": { - "composite": true, - "module": "esnext", - "moduleResolution": "node" + "module": "NodeNext", + "moduleResolution": "NodeNext", + "baseUrl": ".", + "noEmit": true, + "declaration": false, + "composite": false }, - "include": [] + "include": ["vite.config.mts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts", "src/**/*.spec.tsx"] } diff --git a/packages/react-formio-container/tsconfig.spec.json b/packages/react-formio-container/tsconfig.spec.json new file mode 100644 index 00000000..fe01da05 --- /dev/null +++ b/packages/react-formio-container/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": ".", + "declaration": false, + "composite": false, + "noEmit": true, + "paths": {}, + "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"] + }, + "include": ["src/**/*.spec.tsx", "src/**/*.spec.ts", "vitest.config.mts"], + "exclude": ["node_modules", "dist", "coverage"] +} diff --git a/packages/react-formio-container/tsconfig.test.json b/packages/react-formio-container/tsconfig.test.json deleted file mode 100644 index 2c7b2841..00000000 --- a/packages/react-formio-container/tsconfig.test.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "commonjs" - } -} diff --git a/packages/react-formio-container/vite.config.mts b/packages/react-formio-container/vite.config.mts new file mode 100644 index 00000000..13dda351 --- /dev/null +++ b/packages/react-formio-container/vite.config.mts @@ -0,0 +1,66 @@ +import {fileURLToPath} from "node:url"; + +import react from "@vitejs/plugin-react"; +import {globbySync} from "globby"; +import {extname, relative} from "path"; +import preserveDirectives from "rollup-preserve-directives"; +import {defineConfig} from "vite"; +import dts from "vite-plugin-dts"; +import {resolve} from "node:path"; +import pkg from "./package.json" with {type: "json"}; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + react(), + dts({ + tsconfigPath: "./tsconfig.app.json", + aliasesExclude: [], + include: ["src/**/*.{ts,tsx}"], + exclude: ["**/*.spec.{ts,tsx}", "**/*.stories.{ts,tsx}", "**/__*__/**"] + }) + ], + resolve: {}, + build: { + sourcemap: true, + lib: { + entry: resolve(import.meta.dirname, "src/index.ts"), + formats: ["es"] + }, + copyPublicDir: false, + rollupOptions: { + external: [ + ...Object.keys(pkg.peerDependencies || {}), + "react", + "react-dom", + "react/jsx-runtime", + /lodash\/.*/, + /formiojs\/.*/, + /@tsed\/.*/ + ], + plugins: [preserveDirectives() as any], + input: Object.fromEntries( + globbySync("src/**/*.{ts,tsx}", { + ignore: ["**/*.spec.{ts,tsx}", "**/*.stories.{ts,tsx}", "**/__*__/**"] + }).map((file) => { + return [ + // The name of the entry point + // src/nested/foo.ts becomes nested/foo + relative("src", file.slice(0, file.length - extname(file).length)), + // The absolute path to the entry file + // src/nested/foo.ts becomes /project/src/nested/foo.ts + fileURLToPath(new URL(file, import.meta.url)) + ]; + }) + ), + output: { + assetFileNames: "assets/[name][extname]", + chunkFileNames: "chunks/[name].js", + entryFileNames: "[name].js", + globals: { + react: "React" + } + } + } + } +}); diff --git a/packages/react-formio-container/vitest.config.mts b/packages/react-formio-container/vitest.config.mts new file mode 100644 index 00000000..d759e817 --- /dev/null +++ b/packages/react-formio-container/vitest.config.mts @@ -0,0 +1,21 @@ +// @ts-ignore +import {presets} from "@tsed/vitest/presets"; +import {defineConfig} from "vitest/config"; + +export default defineConfig( + { + ...presets, + test: { + ...presets.test, + coverage: { + ...presets.test.coverage, + thresholds: { + statements: 0, + branches: 0, + functions: 0, + lines: 0 + } + } + } + } +); diff --git a/packages/react-formio-stores/.eslintignore b/packages/react-formio-stores/.eslintignore deleted file mode 100644 index 474be905..00000000 --- a/packages/react-formio-stores/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -**/node_modules -docs -docs-references -**/lib -**/build -**/dist -**/coverage -**/.nyc_output -**/node_modules -*-lock.json -*.lock -benchmarks.* -**/generated diff --git a/packages/react-formio-stores/.eslintrc.js b/packages/react-formio-stores/.eslintrc.js deleted file mode 100644 index 3d887dbf..00000000 --- a/packages/react-formio-stores/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: [require.resolve("@tsed/config/eslint/web")], - rules: { - "import/no-anonymous-default-export": 0, - "jsx-a11y/no-autofocus": 1 - } -}; diff --git a/packages/react-formio-stores/coverage.json b/packages/react-formio-stores/coverage.json deleted file mode 100644 index 64ee77c4..00000000 --- a/packages/react-formio-stores/coverage.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "statements": 0, - "branches": 0, - "functions": 0, - "lines": 0 -} diff --git a/packages/react-formio-stores/jest.config.js b/packages/react-formio-stores/jest.config.js deleted file mode 100644 index fe16413a..00000000 --- a/packages/react-formio-stores/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - ...require("@tsed/config/jest/jest.web.config.js"), - coverageThreshold: { - global: require("./coverage.json") - } -}; diff --git a/packages/react-formio-stores/package.json b/packages/react-formio-stores/package.json index 2ac1bf34..136f8c87 100644 --- a/packages/react-formio-stores/package.json +++ b/packages/react-formio-stores/package.json @@ -1,41 +1,39 @@ { "name": "@tsed/react-formio-stores", - "version": "2.3.2", + "version": "3.0.0-alpha.9", "description": "Provide redux stores and action around formio.js API. Written in TypeScript.", "main": "dist/index.js", - "module": "dist/index.modern.js", + "module": "dist/index.js", "source": "src/index.ts", "license": "MIT", "exports": { ".": { - "import": "./dist/index.modern.js", - "require": "./dist/index.js" + "types": "./dist/index.d.ts", + "tsed-source": "./src/index.js", + "default": "./dist/index.js" } }, "scripts": { - "test": "cross-env NODE_ENV=test jest --coverage", - "test:coverage:update": "write-coverage", - "build": "microbundle --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx", - "watch": "microbundle watch --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx" + "test": "vitest run --coverage", + "build": "vite build", + "watch": "vite watch" }, "dependencies": { "@tsed/react-formio": "workspace:*", - "@tsed/redux-utils": "workspace:*", - "eventemitter2": "^6.4.3", - "prop-types": "15.8.1" + "@tsed/redux-utils": "workspace:*" }, "peerDependencies": { "@formio/choices.js": ">=9.0.1", "formiojs": ">=4.0.0", "lodash": ">=4.17.20", - "prop-types": ">=15.7.2", "react": ">=16.14.0", "react-dom": ">=16.14.0", "react-table": ">=7.6.3", "tooltip.js": ">=1.3.3" }, "devDependencies": { - "@tsed/tailwind": "workspace:*", - "@tsed/tailwind-formio": "workspace:*" + "@tsed/tailwind-formio": "workspace:*", + "vite": "5.4.11", + "vitest": "2.1.8" } } diff --git a/packages/react-formio-stores/readme.md b/packages/react-formio-stores/readme.md index 6cc94900..002a379e 100644 --- a/packages/react-formio-stores/readme.md +++ b/packages/react-formio-stores/readme.md @@ -1,5 +1,5 @@

- Ts.ED logo + Ts.ED logo

@@ -14,11 +14,11 @@
- Website + Website   •   - Tutorial + Tutorial   •   - Slack + Slack   •   Twitter
@@ -31,7 +31,7 @@ platform. This module is based on the original [react-formio](https://github.com/formio/react-formio) and add extra features listed above. -See our [storybook](https://formio.tsed.io/) to see all available components. +See our [storybook](https://formio.tsed.dev/) to see all available components. ## Install diff --git a/packages/react-formio-stores/src/stores/action-info/action-info.actions.spec.ts b/packages/react-formio-stores/src/stores/action-info/action-info.actions.spec.ts index 6e7a87a4..55c97ac3 100644 --- a/packages/react-formio-stores/src/stores/action-info/action-info.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/action-info/action-info.actions.spec.ts @@ -2,17 +2,33 @@ import { Formio } from "formiojs"; import { getActionInfo, receiveActionInfo, requestActionInfo } from "./action-info.actions"; -jest.mock("formiojs/Formio"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() { + return "http://localhost"; + } + + actionInfo() {} + } + }; +}); describe("ActionInfo actions", () => { describe("getAction", () => { it("should get action", async () => { const formId = "formId"; const actionType = "oidc"; - const dispatch = jest.fn(); + const dispatch = vi.fn(); - (Formio.getProjectUrl as any).mockReturnValue("http://localhost"); - (Formio.prototype.actionInfo as any).mockReturnValue({ + vi.spyOn(Formio.prototype, "actionInfo").mockReturnValue({ _id: "actionId", name: "oidc", settingsForm: { @@ -26,7 +42,7 @@ describe("ActionInfo actions", () => { type: requestActionInfo.toString(), name: "actionInfo" }); - expect(Formio).toHaveBeenCalledWith("http://localhost/formId"); + expect((Formio as any).url).toEqual("http://localhost/formId"); expect(Formio.prototype.actionInfo).toHaveBeenCalledWith("oidc"); expect(dispatch).toHaveBeenCalledWith({ type: receiveActionInfo.toString(), diff --git a/packages/react-formio-stores/src/stores/action-info/action-info.actions.ts b/packages/react-formio-stores/src/stores/action-info/action-info.actions.ts index 8d820db5..63137884 100644 --- a/packages/react-formio-stores/src/stores/action-info/action-info.actions.ts +++ b/packages/react-formio-stores/src/stores/action-info/action-info.actions.ts @@ -16,6 +16,7 @@ export const getActionInfo = dispatch(requestActionInfo(ACTION_INFO)); const url = getFormUrl(formId); + const formio = new Formio(url); try { diff --git a/packages/react-formio-stores/src/stores/action-info/action-info.reducers.ts b/packages/react-formio-stores/src/stores/action-info/action-info.reducers.ts index eda2d2ed..c6aa5f33 100644 --- a/packages/react-formio-stores/src/stores/action-info/action-info.reducers.ts +++ b/packages/react-formio-stores/src/stores/action-info/action-info.reducers.ts @@ -1,4 +1,4 @@ -import type { ActionSchema } from "@tsed/react-formio"; +import type { ActionType } from "@tsed/react-formio"; import { createReducer, InitialStateCreator } from "@tsed/redux-utils"; import { failActionInfo, receiveActionInfo, requestActionInfo, resetActionInfo } from "./action-info.actions"; @@ -6,7 +6,7 @@ import { ACTION_INFO } from "./action-info.constant"; export interface ActionInfoState { error: null | Error; - data?: Partial; + data?: Partial; isActive: boolean; } diff --git a/packages/react-formio-stores/src/stores/action-info/action-info.selectors.ts b/packages/react-formio-stores/src/stores/action-info/action-info.selectors.ts index 1da79913..11e4f28a 100644 --- a/packages/react-formio-stores/src/stores/action-info/action-info.selectors.ts +++ b/packages/react-formio-stores/src/stores/action-info/action-info.selectors.ts @@ -1,8 +1,7 @@ -import type { ActionSchema } from "@tsed/react-formio"; +import type { ActionType } from "@tsed/react-formio"; import { selectRoot } from "../root"; import { ACTION_INFO } from "./action-info.constant"; import { ActionInfoState } from "./action-info.reducers"; -export const selectActionInfo = (state: Record): Partial => - selectRoot(ACTION_INFO, state).data!; +export const selectActionInfo = (state: Record): Partial => selectRoot(ACTION_INFO, state).data!; diff --git a/packages/react-formio-stores/src/stores/action/action.actions.spec.ts b/packages/react-formio-stores/src/stores/action/action.actions.spec.ts index 5cd3c2ca..bc19b00a 100644 --- a/packages/react-formio-stores/src/stores/action/action.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/action/action.actions.spec.ts @@ -12,21 +12,37 @@ import { sendAction } from "./action.actions"; -jest.mock("formiojs/Formio"); -jest.mock("../action-info"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + constructor(public url: string) { + (Formio as any).url = url; + } + static getProjectUrl() {} + loadAction() { + return; + } + saveAction() {} + deleteAction() {} + } + }; +}); +vi.mock("../action-info"); describe("Action actions", () => { beforeEach(() => { (getActionInfo as any).mockReturnValue({ type: "actionInfo" }); }); - afterEach(() => jest.resetAllMocks()); + afterEach(() => vi.resetAllMocks()); describe("getAction", () => { it("should get action", async () => { const formId = "formId"; const actionId = "actionId"; - const dispatch = jest.fn(); + const dispatch = vi.fn(); - (Formio.prototype.loadAction as any).mockReturnValue({ + vi.spyOn(Formio.prototype, "loadAction").mockReturnValue({ _id: actionId, name: "oidc" }); @@ -37,7 +53,7 @@ describe("Action actions", () => { type: requestAction.toString(), name: "action" }); - expect(Formio).toHaveBeenCalledWith("/formId/action/actionId"); + expect((Formio as any).url).toEqual("/formId/action/actionId"); expect(Formio.prototype.loadAction).toHaveBeenCalledWith(); expect(getActionInfo).toHaveBeenCalledWith("formId", "oidc"); expect(dispatch).toHaveBeenCalledWith({ type: "actionInfo" }); @@ -57,9 +73,9 @@ describe("Action actions", () => { it("should save action", async () => { const formId = "formId"; const actionId = "actionId"; - const dispatch = jest.fn(); + const dispatch = vi.fn(); - (Formio.prototype.saveAction as any).mockReturnValue({ + vi.spyOn(Formio.prototype, "saveAction").mockReturnValue({ _id: actionId }); @@ -76,7 +92,7 @@ describe("Action actions", () => { action: { _id: actionId } } }); - expect(Formio).toHaveBeenCalledWith("/formId/action"); + expect((Formio as any).url).toEqual("/formId/action"); expect(Formio.prototype.saveAction).toHaveBeenCalledWith({ _id: actionId }); @@ -95,7 +111,9 @@ describe("Action actions", () => { it("should delete action", async () => { const formId = "formId"; const actionId = "actionId"; - const dispatch = jest.fn(); + const dispatch = vi.fn(); + + vi.spyOn(Formio.prototype, "deleteAction"); await deleteAction(formId, actionId)(dispatch); @@ -103,7 +121,7 @@ describe("Action actions", () => { type: clearActionError.toString(), name: "action" }); - expect(Formio).toHaveBeenCalledWith("/formId/action/actionId"); + expect((Formio as any).url).toEqual("/formId/action/actionId"); expect(Formio.prototype.deleteAction).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ type: resetAction.toString(), diff --git a/packages/react-formio-stores/src/stores/action/action.actions.ts b/packages/react-formio-stores/src/stores/action/action.actions.ts index de0dd7bd..7f6f2b71 100644 --- a/packages/react-formio-stores/src/stores/action/action.actions.ts +++ b/packages/react-formio-stores/src/stores/action/action.actions.ts @@ -34,6 +34,7 @@ export const getAction = dispatch(receiveAction(ACTION, { action })); done(null, action); } catch (error) { + console.log(error); dispatch(failAction(ACTION, { error })); done(error); } diff --git a/packages/react-formio-stores/src/stores/action/action.reducers.ts b/packages/react-formio-stores/src/stores/action/action.reducers.ts index 38eb4ccc..6174cc7b 100644 --- a/packages/react-formio-stores/src/stores/action/action.reducers.ts +++ b/packages/react-formio-stores/src/stores/action/action.reducers.ts @@ -1,4 +1,4 @@ -import type { ActionSchema } from "@tsed/react-formio"; +import type { ActionType } from "@tsed/react-formio"; import { createReducer, InitialStateCreator } from "@tsed/redux-utils"; import { clearActionError, failAction, receiveAction, requestAction, resetAction, sendAction } from "./action.actions"; @@ -6,7 +6,7 @@ import { ACTION } from "./action.constant"; export interface ActionState { error: null | Error; - data: ActionSchema; + data: ActionType; isActive: boolean; } diff --git a/packages/react-formio-stores/src/stores/action/action.selectors.ts b/packages/react-formio-stores/src/stores/action/action.selectors.ts index 2413583c..7e346fd0 100644 --- a/packages/react-formio-stores/src/stores/action/action.selectors.ts +++ b/packages/react-formio-stores/src/stores/action/action.selectors.ts @@ -1,7 +1,7 @@ -import type { ActionSchema } from "@tsed/react-formio"; +import type { ActionType } from "@tsed/react-formio"; import { selectRoot } from "../root"; import { ACTION } from "./action.constant"; import { ActionState } from "./action.reducers"; -export const selectAction = (state: Record): ActionSchema => selectRoot(ACTION, state).data; +export const selectAction = (state: Record): ActionType => selectRoot(ACTION, state).data; diff --git a/packages/react-formio-stores/src/stores/actions/actions.actions.spec.ts b/packages/react-formio-stores/src/stores/actions/actions.actions.spec.ts index d7f3867e..9cf945be 100644 --- a/packages/react-formio-stores/src/stores/actions/actions.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/actions/actions.actions.spec.ts @@ -2,22 +2,40 @@ import { Formio } from "formiojs"; import { getActions, receiveActions, requestActions, resetActions } from "./actions.actions"; -jest.mock("formiojs"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() {} + loadActions() {} + availableActions() {} + } + }; +}); describe("Actions actions", () => { + beforeEach(() => { + (Formio as any).url = undefined; + }); describe("getActions", () => { it("should return a result", async () => { const formId = "formId"; const actionId = "actionId"; - const dispatch = jest.fn(); + const dispatch = vi.fn(); - (Formio.prototype.loadActions as any).mockReturnValue([ + vi.spyOn(Formio.prototype, "loadActions").mockReturnValue([ { _id: actionId, name: "oidc" } ]); - (Formio.prototype.availableActions as any).mockReturnValue([ + vi.spyOn(Formio.prototype, "availableActions").mockReturnValue([ { name: "oidc" } @@ -34,7 +52,7 @@ describe("Actions actions", () => { name: "actions" }); - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.loadActions).toHaveBeenCalledWith({ params: {} }); diff --git a/packages/react-formio-stores/src/stores/actions/actions.reducers.ts b/packages/react-formio-stores/src/stores/actions/actions.reducers.ts index 8245af4c..bc67d50e 100644 --- a/packages/react-formio-stores/src/stores/actions/actions.reducers.ts +++ b/packages/react-formio-stores/src/stores/actions/actions.reducers.ts @@ -1,4 +1,4 @@ -import type { ActionInfoSchema, ActionSchema } from "@tsed/react-formio"; +import type { ActionInfoType, ActionType } from "@tsed/react-formio"; import { createReducer, InitialStateCreator } from "@tsed/redux-utils"; import { failActions, receiveActions, requestActions, resetActions } from "./actions.actions"; @@ -6,8 +6,8 @@ import { ACTIONS } from "./actions.constant"; export interface ActionsState { error: null | Error; - data: ActionSchema[]; - availableActions: ActionInfoSchema[]; + data: ActionType[]; + availableActions: ActionInfoType[]; isActive: boolean; } diff --git a/packages/react-formio-stores/src/stores/auth/auth.actions.ts b/packages/react-formio-stores/src/stores/auth/auth.actions.ts index 9c12930e..dfc07dea 100644 --- a/packages/react-formio-stores/src/stores/auth/auth.actions.ts +++ b/packages/react-formio-stores/src/stores/auth/auth.actions.ts @@ -1,12 +1,12 @@ -import type { FormSchema, RoleSchema, Submission } from "@tsed/react-formio"; +import type { FormType, RoleType, SubmissionType } from "@tsed/react-formio"; import { createAction } from "@tsed/redux-utils"; export const requestUser = createAction(); -export const receiveUser = createAction<{ user: Submission }>(); +export const receiveUser = createAction<{ user: SubmissionType }>(); export const failUser = createAction<{ error: Error }>(); export const logoutUser = createAction(); export const submissionAccessUser = createAction<{ submissionAccess: any }>(); export const formAccessUser = createAction<{ formAccess: any }>(); export const projectAccessUser = createAction<{ projectAccess: any }>(); -export const userRoles = createAction<{ roles: Record }>(); -export const userForms = createAction<{ forms: Record }>(); +export const userRoles = createAction<{ roles: Record }>(); +export const userForms = createAction<{ forms: Record }>(); diff --git a/packages/react-formio-stores/src/stores/auth/auth.reducers.ts b/packages/react-formio-stores/src/stores/auth/auth.reducers.ts index c2890ec9..afe27b42 100644 --- a/packages/react-formio-stores/src/stores/auth/auth.reducers.ts +++ b/packages/react-formio-stores/src/stores/auth/auth.reducers.ts @@ -1,4 +1,4 @@ -import type { FormSchema, RoleSchema, Submission } from "@tsed/react-formio"; +import { FormType, JSON, RoleType, SubmissionType } from "@tsed/react-formio"; import { createReducer } from "@tsed/redux-utils"; import { @@ -14,16 +14,16 @@ import { } from "./auth.actions"; import { AUTH } from "./auth.constant"; -export interface AuthState { +export interface AuthState { init: boolean; isActive: boolean; - user: null | Submission; + user: null | SubmissionType; authenticated: boolean; projectAccess: Record; formAccess: Record; submissionAccess: Record; - roles: Record; - forms: Record; + roles: Record; + forms: Record; is: Record; error: null | Error; } @@ -54,7 +54,7 @@ function mapProjectRolesToUserRoles(projectRoles: Record, userRoles ); } -function getUserRoles(projectRoles: Record) { +function getUserRoles(projectRoles: Record) { return Object.keys(projectRoles).reduce( (result, name) => ({ ...result, diff --git a/packages/react-formio-stores/src/stores/auth/auth.selectors.ts b/packages/react-formio-stores/src/stores/auth/auth.selectors.ts index 03db35c5..e83af134 100644 --- a/packages/react-formio-stores/src/stores/auth/auth.selectors.ts +++ b/packages/react-formio-stores/src/stores/auth/auth.selectors.ts @@ -1,4 +1,4 @@ -import type { RoleSchema, Submission } from "@tsed/react-formio"; +import type { RoleType, SubmissionType } from "@tsed/react-formio"; import get from "lodash/get"; import { selectRoot } from "../root"; @@ -7,8 +7,8 @@ import { AuthState } from "./auth.reducers"; export const selectAuth = (state: any) => selectRoot(AUTH, state); -export const selectUser = (state: any): null | Submission => get(selectAuth(state), "user"); +export const selectUser = (state: any): null | SubmissionType => get(selectAuth(state), "user"); -export const selectRoles = (state: any): Record => get(selectAuth(state), "roles"); +export const selectRoles = (state: any): Record => get(selectAuth(state), "roles"); export const selectIsAuthenticated = (state: any): boolean => get(selectAuth(state), "authenticated"); diff --git a/packages/react-formio-stores/src/stores/auth/auth.utils.tsx b/packages/react-formio-stores/src/stores/auth/auth.utils.tsx index c7733d68..26f90812 100644 --- a/packages/react-formio-stores/src/stores/auth/auth.utils.tsx +++ b/packages/react-formio-stores/src/stores/auth/auth.utils.tsx @@ -1,4 +1,4 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import get from "lodash/get"; import { AuthState } from "./auth.reducers"; @@ -24,7 +24,7 @@ export function isAuthorized(auth: AuthState, roles: string[] = []): boolean { return false; } -export function checkRoleFormAccess(auth: AuthState, form?: Partial, roles?: string[]) { +export function checkRoleFormAccess(auth: AuthState, form?: Partial, roles?: string[]) { if (roles && roles.length) { if (isAuthorized(auth, roles)) { return true; diff --git a/packages/react-formio-stores/src/stores/auth/getAccess.action.spec.ts b/packages/react-formio-stores/src/stores/auth/getAccess.action.spec.ts index 26aa5ca9..91f1f65c 100644 --- a/packages/react-formio-stores/src/stores/auth/getAccess.action.spec.ts +++ b/packages/react-formio-stores/src/stores/auth/getAccess.action.spec.ts @@ -4,18 +4,18 @@ import { formAccessUser, submissionAccessUser, userForms, userRoles } from "./au import { AUTH } from "./auth.constant"; import { getAccess } from "./getAccess.action"; -jest.mock("./auth.actions"); +vi.mock("./auth.actions"); describe("getAccess()", () => { beforeEach(() => { - jest.spyOn(Formio, "makeStaticRequest"); - jest.spyOn(Formio, "getProjectUrl"); + vi.spyOn(Formio, "makeStaticRequest"); + vi.spyOn(Formio, "getProjectUrl"); }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it("should get access", async () => { - const dispatch = jest.fn(); + const dispatch = vi.fn(); const access = { roles: { administrator: { diff --git a/packages/react-formio-stores/src/stores/auth/getAccess.action.ts b/packages/react-formio-stores/src/stores/auth/getAccess.action.ts index 1476d75f..42a3ff91 100644 --- a/packages/react-formio-stores/src/stores/auth/getAccess.action.ts +++ b/packages/react-formio-stores/src/stores/auth/getAccess.action.ts @@ -1,10 +1,10 @@ -import type { FormSchema, RoleSchema } from "@tsed/react-formio"; +import type { FormType, RoleType } from "@tsed/react-formio"; import { Formio } from "formiojs"; import { formAccessUser, submissionAccessUser, userForms, userRoles } from "./auth.actions"; import { AUTH } from "./auth.constant"; -function transformSubmissionAccess(forms: Record) { +function transformSubmissionAccess(forms: Record) { return Object.values(forms).reduce( (result, form) => ({ ...result, @@ -20,7 +20,7 @@ function transformSubmissionAccess(forms: Record) { ); } -function transformFormAccess(forms: Record) { +function transformFormAccess(forms: Record) { return Object.values(forms).reduce( (result, form) => ({ ...result, @@ -41,8 +41,8 @@ export async function getAccess(dispatch: any) { try { const result: { - roles: Record; - forms: Record; + roles: Record; + forms: Record; } = await Formio.makeStaticRequest(`${projectUrl}/access`); const submissionAccess = transformSubmissionAccess(result.forms); diff --git a/packages/react-formio-stores/src/stores/auth/initAuth.action.spec.ts b/packages/react-formio-stores/src/stores/auth/initAuth.action.spec.ts index 6d0ece37..e7ed661e 100644 --- a/packages/react-formio-stores/src/stores/auth/initAuth.action.spec.ts +++ b/packages/react-formio-stores/src/stores/auth/initAuth.action.spec.ts @@ -8,22 +8,22 @@ import { initAuth } from "./initAuth.action"; import { logout } from "./logout.action"; import { setUser } from "./setUser.action"; -jest.mock("./getAccess.action"); -jest.mock("./getProjectAccess.action"); -jest.mock("./setUser.action"); -jest.mock("./logout.action"); -jest.mock("./auth.actions"); +vi.mock("./getAccess.action"); +vi.mock("./getProjectAccess.action"); +vi.mock("./setUser.action"); +vi.mock("./logout.action"); +vi.mock("./auth.actions"); describe("initAuth()", () => { beforeEach(() => { - jest.spyOn(Formio, "currentUser"); + vi.spyOn(Formio, "currentUser"); }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it("should init auth", async () => { - const dispatch = jest.fn(); - const done = jest.fn(); + const dispatch = vi.fn(); + const done = vi.fn(); const user = { data: {} }; (Formio.currentUser as any).mockResolvedValue(user); @@ -38,8 +38,8 @@ describe("initAuth()", () => { expect(logout).not.toHaveBeenCalled(); }); it("should call logout when user is null", async () => { - const dispatch = jest.fn(); - const done = jest.fn(); + const dispatch = vi.fn(); + const done = vi.fn(); const user: any = null; (Formio.currentUser as any).mockResolvedValue(user); diff --git a/packages/react-formio-stores/src/stores/auth/logout.action.spec.ts b/packages/react-formio-stores/src/stores/auth/logout.action.spec.ts index 3d762708..bf7e4f00 100644 --- a/packages/react-formio-stores/src/stores/auth/logout.action.spec.ts +++ b/packages/react-formio-stores/src/stores/auth/logout.action.spec.ts @@ -4,18 +4,18 @@ import { logoutUser } from "./auth.actions"; import { AUTH } from "./auth.constant"; import { logout } from "./logout.action"; -jest.mock("./auth.actions"); -jest.mock("formiojs"); +vi.mock("./auth.actions"); +vi.mock("formiojs"); describe("logout()", () => { beforeEach(() => { - jest.spyOn(Formio, "logout"); + vi.spyOn(Formio, "logout"); }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it("should call logout", async () => { - const dispatch = jest.fn(); + const dispatch = vi.fn(); await logout()(dispatch); diff --git a/packages/react-formio-stores/src/stores/auth/setUser.action.spec.ts b/packages/react-formio-stores/src/stores/auth/setUser.action.spec.ts index 015fa23b..aa3c134f 100644 --- a/packages/react-formio-stores/src/stores/auth/setUser.action.spec.ts +++ b/packages/react-formio-stores/src/stores/auth/setUser.action.spec.ts @@ -4,17 +4,17 @@ import { receiveUser } from "./auth.actions"; import { AUTH } from "./auth.constant"; import { setUser } from "./setUser.action"; -jest.mock("./auth.actions"); +vi.mock("./auth.actions"); describe("setUser()", () => { beforeEach(() => { - jest.spyOn(Formio, "setUser"); + vi.spyOn(Formio, "setUser"); }); afterEach(() => { - jest.resetAllMocks(); + vi.resetAllMocks(); }); it("should call logout", async () => { - const dispatch = jest.fn(); + const dispatch = vi.fn(); const user = {}; await setUser(user)(dispatch); diff --git a/packages/react-formio-stores/src/stores/form/form.actions.spec.ts b/packages/react-formio-stores/src/stores/form/form.actions.spec.ts index 036105f5..3a216f23 100644 --- a/packages/react-formio-stores/src/stores/form/form.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/form/form.actions.spec.ts @@ -2,20 +2,35 @@ import { Formio } from "formiojs"; import { deleteForm, failForm, getForm, receiveForm, requestForm, resetForm, saveForm, sendForm } from "./form.actions"; -jest.mock("formiojs"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() {} + loadForms() {} + loadForm() {} + saveForm() {} + deleteForm() {} + } + }; +}); describe("Form actions", () => { + beforeEach(() => { + (Formio as any).url = undefined; + }); describe("getForm", () => { - beforeEach(() => { - // @ts-ignore - Formio.mockClear(); - }); it("should return a result", async () => { // GIVEN - // @ts-ignore - Formio.prototype.loadForm.mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "loadForm").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; @@ -27,7 +42,7 @@ describe("Form actions", () => { await new Promise((resolve) => getForm(name, formId, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.loadForm).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -49,9 +64,9 @@ describe("Form actions", () => { it("should do nothing when submission is already loaded", async () => { // GIVEN // @ts-ignore - Formio.prototype.loadForm.mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "loadForm").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; @@ -68,14 +83,14 @@ describe("Form actions", () => { getForm(name, formId)(dispatch, getState); // THEN - expect(Formio).not.toHaveBeenCalled(); + expect((Formio as any).url).toBeUndefined(); }); it("should throw error", async () => { // GIVEN // @ts-ignore - Formio.prototype.loadForm.mockReturnValue(Promise.reject(new Error("message"))); + vi.spyOn(Formio.prototype, "loadForm").mockRejectedValue(new Error("message")); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; @@ -87,7 +102,7 @@ describe("Form actions", () => { await new Promise((resolve) => getForm(name, formId, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.loadForm).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -101,18 +116,18 @@ describe("Form actions", () => { describe("saveForm", () => { it("should return a result", async () => { // GIVEN - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; const data = { _id: formId }; // @ts-ignore - Formio.prototype.saveForm.mockReturnValue(Promise.resolve(data)); + vi.spyOn(Formio.prototype, "saveForm").mockResolvedValue(data); // WHEN await new Promise((resolve) => saveForm(name, data, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.saveForm).toHaveBeenCalledWith(data); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -132,10 +147,9 @@ describe("Form actions", () => { }); it("should throw error", async () => { // GIVEN - // @ts-ignore - Formio.prototype.saveForm.mockReturnValue(Promise.reject(new Error("message"))); + vi.spyOn(Formio.prototype, "saveForm").mockRejectedValue(new Error("message")); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; const data = { _id: formId }; @@ -144,7 +158,7 @@ describe("Form actions", () => { await new Promise((resolve) => saveForm(name, data, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.saveForm).toHaveBeenCalledWith(data); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -159,9 +173,9 @@ describe("Form actions", () => { it("should return a result", async () => { // GIVEN // @ts-ignore - Formio.prototype.deleteForm.mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "deleteForm").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; @@ -169,7 +183,7 @@ describe("Form actions", () => { await new Promise((resolve) => deleteForm(name, formId, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.deleteForm).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -178,10 +192,9 @@ describe("Form actions", () => { }); it("should throw error", async () => { // GIVEN - // @ts-ignore - Formio.prototype.deleteForm.mockReturnValue(Promise.reject(new Error("message"))); + vi.spyOn(Formio.prototype, "deleteForm").mockRejectedValue(new Error("message")); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; @@ -189,7 +202,7 @@ describe("Form actions", () => { await new Promise((resolve) => deleteForm(name, formId, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId"); + expect((Formio as any).url).toEqual("/formId"); expect(Formio.prototype.deleteForm).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", diff --git a/packages/react-formio-stores/src/stores/form/form.actions.ts b/packages/react-formio-stores/src/stores/form/form.actions.ts index 3386ec3c..e72a062d 100644 --- a/packages/react-formio-stores/src/stores/form/form.actions.ts +++ b/packages/react-formio-stores/src/stores/form/form.actions.ts @@ -1,4 +1,4 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import { createAction } from "@tsed/redux-utils"; import { Formio } from "formiojs"; import noop from "lodash/noop"; @@ -14,7 +14,7 @@ export const failForm = createAction(); export const resetForm = createAction(); export const sendForm = createAction(); -function shouldGet(form: Partial, id: string) { +function shouldGet(form: Partial, id: string) { return form && form.components && Array.isArray(form.components) && form.components.length && form._id === id; } @@ -47,7 +47,7 @@ export const getForm = }; export const saveForm = - (name: string, form: Partial, done = noop) => + (name: string, form: Partial, done = noop) => async (dispatch: any) => { dispatch(clearFormError(name)); dispatch(sendForm(name, { form })); diff --git a/packages/react-formio-stores/src/stores/form/form.reducers.ts b/packages/react-formio-stores/src/stores/form/form.reducers.ts index bc143e78..a86fcb1f 100644 --- a/packages/react-formio-stores/src/stores/form/form.reducers.ts +++ b/packages/react-formio-stores/src/stores/form/form.reducers.ts @@ -1,11 +1,11 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import { createReducer, InitialStateCreator } from "@tsed/redux-utils"; import { clearFormError, failForm, receiveForm, requestForm, resetForm, sendForm } from "./form.actions"; export interface FormState { error: null | Error; - data?: Partial; + data?: Partial; isActive: boolean; lastUpdated: number; url: string; diff --git a/packages/react-formio-stores/src/stores/form/form.selectors.ts b/packages/react-formio-stores/src/stores/form/form.selectors.ts index 6e7dd9f1..4e0d0ee9 100644 --- a/packages/react-formio-stores/src/stores/form/form.selectors.ts +++ b/packages/react-formio-stores/src/stores/form/form.selectors.ts @@ -1,6 +1,6 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import { selectRoot } from "../root"; import { FormState } from "./form.reducers"; -export const selectForm = (name: string, state: any): Partial => selectRoot(name, state).data!; +export const selectForm = (name: string, state: any): Partial => selectRoot(name, state).data!; diff --git a/packages/react-formio-stores/src/stores/forms/forms.actions.spec.ts b/packages/react-formio-stores/src/stores/forms/forms.actions.spec.ts index 9c7da632..4f02eb32 100644 --- a/packages/react-formio-stores/src/stores/forms/forms.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/forms/forms.actions.spec.ts @@ -3,20 +3,37 @@ import { Formio } from "formiojs"; import { mapRequestParams } from "../../utils/mapRequestParams"; import { failForms, getForms, receiveForms, requestForms } from "./forms.actions"; -jest.mock("formiojs"); -jest.mock("../../utils/mapRequestParams"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() {} + loadForms() {} + } + }; +}); +vi.mock("../../utils/mapRequestParams"); describe("Forms actions", () => { beforeEach(() => { + vi.resetAllMocks(); + (Formio as any).url = undefined; (mapRequestParams as any).mockImplementation((o: any) => o); }); - afterEach(() => jest.resetAllMocks()); + describe("getForms", () => { it("should return a result", async () => { // GIVEN - (Formio as any).prototype.loadForms.mockReturnValue(Promise.resolve([{}])); - (Formio as any).getProjectUrl.mockReturnValue("https://formio"); - const dispatch = jest.fn(); + vi.spyOn(Formio.prototype, "loadForms").mockResolvedValue([{}]); + vi.spyOn(Formio, "getProjectUrl").mockReturnValue("https://formio"); + + const dispatch = vi.fn(); const name = "name"; const parameters = { pageSize: 10, @@ -33,7 +50,7 @@ describe("Forms actions", () => { await new Promise((resolve) => getForms(name, parameters, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("https://formio/form"); + expect((Formio as any).url).toEqual("https://formio/form"); expect(Formio.prototype.loadForms).toHaveBeenCalledWith({ params: parameters }); @@ -52,10 +69,10 @@ describe("Forms actions", () => { }); it("should return a error", async () => { // GIVEN - (Formio.prototype.loadForms as any).mockReturnValue(Promise.reject(new Error("message"))); - (Formio.getProjectUrl as any).mockReturnValue("https://formio"); + vi.spyOn(Formio.prototype, "loadForms").mockRejectedValue(new Error("message")); + vi.spyOn(Formio, "getProjectUrl").mockReturnValue("https://formio"); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const parameters = { pageSize: 10, @@ -72,7 +89,7 @@ describe("Forms actions", () => { await new Promise((resolve) => getForms(name, parameters, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("https://formio/form"); + expect((Formio as any).url).toEqual("https://formio/form"); expect(Formio.prototype.loadForms).toHaveBeenCalledWith({ params: parameters }); diff --git a/packages/react-formio-stores/src/stores/forms/forms.actions.ts b/packages/react-formio-stores/src/stores/forms/forms.actions.ts index f10383ec..995eb0f9 100644 --- a/packages/react-formio-stores/src/stores/forms/forms.actions.ts +++ b/packages/react-formio-stores/src/stores/forms/forms.actions.ts @@ -1,4 +1,4 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import { createAction } from "@tsed/redux-utils"; import { Formio } from "formiojs"; import noop from "lodash/noop"; @@ -10,10 +10,10 @@ export const resetForms = createAction(); export const requestForms = createAction<{ parameters: Partial; }>(); -export const receiveForms = createAction<{ forms: FormSchema[] }>(); +export const receiveForms = createAction<{ forms: FormType[] }>(); export const failForms = createAction(); -export type GetFormsCB = (err: any, forms?: FormSchema[]) => void; +export type GetFormsCB = (err: any, forms?: FormType[]) => void; export const getForms = (name: string, parameters: Partial, done: GetFormsCB = noop) => @@ -24,7 +24,7 @@ export const getForms = const requestParams = mapRequestParams(selectFormsParameters(name, getState())); try { - const result: FormSchema[] = await formio.loadForms({ + const result: FormType[] = await formio.loadForms({ params: requestParams }); dispatch(receiveForms(name, { forms: result })); diff --git a/packages/react-formio-stores/src/stores/forms/forms.reducers.ts b/packages/react-formio-stores/src/stores/forms/forms.reducers.ts index 469632ef..59685d08 100644 --- a/packages/react-formio-stores/src/stores/forms/forms.reducers.ts +++ b/packages/react-formio-stores/src/stores/forms/forms.reducers.ts @@ -1,4 +1,4 @@ -import type { FormSchema } from "@tsed/react-formio"; +import type { FormType } from "@tsed/react-formio"; import { createReducer } from "@tsed/redux-utils"; import { failForms, receiveForms, requestForms, resetForms } from "./forms.actions"; @@ -15,7 +15,7 @@ export interface FormsState { sortBy: any[]; filters: any[]; }; - data: FormSchema[]; + data: FormType[]; } const createInitialState = ({ pageIndex = 0, pageSize = 10, query = {}, select = "", sortBy = [] }: any = {}): FormsState => { diff --git a/packages/react-formio-stores/src/stores/submission/submission.actions.spec.ts b/packages/react-formio-stores/src/stores/submission/submission.actions.spec.ts index dcff34cb..0fc203e7 100644 --- a/packages/react-formio-stores/src/stores/submission/submission.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/submission/submission.actions.spec.ts @@ -12,18 +12,35 @@ import { sendSubmission } from "./submission.actions"; -jest.mock("formiojs/Formio"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() {} + + loadSubmission() {} + saveSubmission() {} + deleteSubmission() {} + } + }; +}); describe("Submission actions", () => { + beforeEach(() => { + (Formio as any).url = undefined; + }); describe("getSubmission", () => { - beforeEach(() => { - (Formio as any).mockClear(); - }); it("should return a result", async () => { // GIVEN - (Formio as any).prototype.loadSubmission.mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "loadSubmission").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const id = "123454"; const formId = "formId"; @@ -36,7 +53,7 @@ describe("Submission actions", () => { await new Promise((resolve) => getSubmission(name, formId, id, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.loadSubmission).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -58,9 +75,9 @@ describe("Submission actions", () => { }); it("should do nothing when submission is already loaded", async () => { // GIVEN - (Formio.prototype.loadSubmission as any).mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "loadSubmission").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const id = "123454"; const formId = "formId"; @@ -73,13 +90,13 @@ describe("Submission actions", () => { await getSubmission(name, formId, id)(dispatch, getState); // THEN - expect(Formio).not.toHaveBeenCalled(); + expect((Formio as any).url).toBeUndefined(); }); it("should throw error", async () => { // GIVEN - (Formio.prototype.loadSubmission as any).mockReturnValue(Promise.reject(new Error("message"))); + vi.spyOn(Formio.prototype, "loadSubmission").mockRejectedValue(new Error("message")); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const id = "123454"; const formId = "formId"; @@ -92,7 +109,7 @@ describe("Submission actions", () => { await new Promise((resolve) => getSubmission(name, formId, id, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.loadSubmission).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -106,21 +123,21 @@ describe("Submission actions", () => { describe("saveSubmission", () => { it("should return a result", async () => { // GIVEN - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const data = { _id: "123454" }; const formId = "formId"; - (Formio.prototype.saveSubmission as any).mockReturnValue(Promise.resolve(data)); + vi.spyOn(Formio.prototype, "saveSubmission").mockResolvedValue(data); // WHEN - await new Promise((resolve) => saveSubmission(name, formId, data, resolve)(dispatch)); + await new Promise((resolve) => saveSubmission(name, formId, data as never, resolve)(dispatch)); // THEN expect(dispatch).toHaveBeenCalledWith({ name: "name", type: clearSubmissionError.toString() }); - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.saveSubmission).toHaveBeenCalledWith(data); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -141,20 +158,18 @@ describe("Submission actions", () => { }); it("should throw error", async () => { // GIVEN - (Formio.prototype.saveSubmission as any).mockImplementation(() => { - throw new Error("message"); - }); + vi.spyOn(Formio.prototype, "saveSubmission").mockRejectedValue(new Error("message")); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const data = { _id: "123454" }; const formId = "formId"; // WHEN - await new Promise((resolve) => saveSubmission(name, formId, data, resolve)(dispatch)); + await new Promise((resolve) => saveSubmission(name, formId, data as never, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.saveSubmission).toHaveBeenCalledWith(data); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -168,9 +183,9 @@ describe("Submission actions", () => { describe("deleteSubmission", () => { it("should return a result", async () => { // GIVEN - (Formio.prototype.deleteSubmission as any).mockReturnValue(Promise.resolve({})); + vi.spyOn(Formio.prototype, "deleteSubmission").mockResolvedValue({}); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const id = "123454"; const formId = "formId"; @@ -179,7 +194,7 @@ describe("Submission actions", () => { await new Promise((resolve) => deleteSubmission(name, formId, id, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.deleteSubmission).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", @@ -188,10 +203,8 @@ describe("Submission actions", () => { }); it("should throw error", async () => { // GIVEN - (Formio.prototype.deleteSubmission as any).mockImplementation(() => { - throw new Error("message"); - }); - const dispatch = jest.fn(); + vi.spyOn(Formio.prototype, "deleteSubmission").mockRejectedValue(new Error("message")); + const dispatch = vi.fn(); const name = "name"; const id = "123454"; const formId = "formId"; @@ -200,7 +213,7 @@ describe("Submission actions", () => { await new Promise((resolve) => deleteSubmission(name, formId, id, resolve)(dispatch)); // THEN - expect(Formio).toHaveBeenCalledWith("/formId/submission/123454"); + expect((Formio as any).url).toEqual("/formId/submission/123454"); expect(Formio.prototype.deleteSubmission).toHaveBeenCalledWith(); expect(dispatch).toHaveBeenCalledWith({ name: "name", diff --git a/packages/react-formio-stores/src/stores/submission/submission.actions.ts b/packages/react-formio-stores/src/stores/submission/submission.actions.ts index 6fd90f5f..97243aa4 100644 --- a/packages/react-formio-stores/src/stores/submission/submission.actions.ts +++ b/packages/react-formio-stores/src/stores/submission/submission.actions.ts @@ -1,4 +1,4 @@ -import { Submission } from "@tsed/react-formio"; +import { SubmissionType } from "@tsed/react-formio"; import { createAction } from "@tsed/redux-utils"; import { Formio } from "formiojs"; import noop from "lodash/noop"; @@ -38,7 +38,7 @@ export const getSubmission = }; export const saveSubmission = - (name: string, formId: string, data: Submission, done = noop) => + (name: string, formId: string, data: SubmissionType, done = noop) => async (dispatch: any) => { dispatch(clearSubmissionError(name)); dispatch(sendSubmission(name, { submission: data, formId })); diff --git a/packages/react-formio-stores/src/stores/submission/submission.reducers.ts b/packages/react-formio-stores/src/stores/submission/submission.reducers.ts index 4551402e..abba6e9f 100644 --- a/packages/react-formio-stores/src/stores/submission/submission.reducers.ts +++ b/packages/react-formio-stores/src/stores/submission/submission.reducers.ts @@ -1,4 +1,4 @@ -import type { Submission } from "@tsed/react-formio"; +import type { SubmissionType } from "@tsed/react-formio"; import { createReducer, InitialStateCreator } from "@tsed/redux-utils"; import { @@ -15,7 +15,7 @@ export interface SubmissionState { id: string; isActive: boolean; lastUpdated: number; - data: Partial; + data: Partial; url: string; error: null | Error; } diff --git a/packages/react-formio-stores/src/stores/submission/submission.selectors.ts b/packages/react-formio-stores/src/stores/submission/submission.selectors.ts index 0758dba7..537c371b 100644 --- a/packages/react-formio-stores/src/stores/submission/submission.selectors.ts +++ b/packages/react-formio-stores/src/stores/submission/submission.selectors.ts @@ -1,6 +1,6 @@ -import type { Submission } from "@tsed/react-formio"; +import type { SubmissionType } from "@tsed/react-formio"; import { selectRoot } from "../root"; import { SubmissionState } from "./submission.reducers"; -export const selectSubmission = (name: string, state: any): Partial => selectRoot(name, state).data; +export const selectSubmission = (name: string, state: any): Partial => selectRoot(name, state).data; diff --git a/packages/react-formio-stores/src/stores/submissions/submissions.actions.spec.ts b/packages/react-formio-stores/src/stores/submissions/submissions.actions.spec.ts index fcbaace6..d3beca4b 100644 --- a/packages/react-formio-stores/src/stores/submissions/submissions.actions.spec.ts +++ b/packages/react-formio-stores/src/stores/submissions/submissions.actions.spec.ts @@ -3,8 +3,23 @@ import { Formio } from "formiojs"; import { mapRequestParams } from "../../utils/mapRequestParams"; import { failSubmissions, getSubmissions, receiveSubmissions, requestSubmissions } from "./submissions.actions"; -jest.mock("formiojs"); -jest.mock("../../utils/mapRequestParams"); +vi.mock("formiojs", async (originalImport) => { + return { + ...(await originalImport()), + Formio: class { + static url: string; + + constructor(public url: string) { + (Formio as any).url = url; + } + + static getProjectUrl() {} + loadSubmissions() {} + availableActions() {} + } + }; +}); +vi.mock("../../utils/mapRequestParams"); describe("Submissions actions", () => { beforeEach(() => { @@ -13,10 +28,10 @@ describe("Submissions actions", () => { describe("getSubmissions", () => { it("should return a result", async () => { // GIVEN - (Formio.prototype.loadSubmissions as any).mockReturnValue(Promise.resolve([{}])); - (Formio.getProjectUrl as any).mockReturnValue("https://formio"); + vi.spyOn(Formio.prototype, "loadSubmissions").mockReturnValue(Promise.resolve([{}])); + vi.spyOn(Formio, "getProjectUrl").mockReturnValue("https://formio"); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; const parameters = { @@ -34,7 +49,7 @@ describe("Submissions actions", () => { await new Promise((resolve) => getSubmissions(name, formId, parameters, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("https://formio/formId/submission"); + expect((Formio as any).url).toEqual("https://formio/formId/submission"); expect(Formio.prototype.loadSubmissions).toHaveBeenCalledWith({ params: parameters }); @@ -56,10 +71,10 @@ describe("Submissions actions", () => { }); it("should return a error", async () => { // GIVEN - (Formio.prototype.loadSubmissions as any).mockReturnValue(Promise.reject(new Error("message"))); - (Formio.getProjectUrl as any).mockReturnValue("https://formio"); + vi.spyOn(Formio.prototype, "loadSubmissions").mockRejectedValue(new Error("message")); + vi.spyOn(Formio, "getProjectUrl").mockReturnValue("https://formio"); - const dispatch = jest.fn(); + const dispatch = vi.fn(); const name = "name"; const formId = "formId"; const parameters = { @@ -77,7 +92,7 @@ describe("Submissions actions", () => { await new Promise((resolve) => getSubmissions(name, formId, parameters, resolve)(dispatch, getState)); // THEN - expect(Formio).toHaveBeenCalledWith("https://formio/formId/submission"); + expect((Formio as any).url).toEqual("https://formio/formId/submission"); expect(Formio.prototype.loadSubmissions).toHaveBeenCalledWith({ params: parameters }); diff --git a/packages/react-formio-stores/src/stores/submissions/submissions.reducers.ts b/packages/react-formio-stores/src/stores/submissions/submissions.reducers.ts index 0d838a6a..4a08dab9 100644 --- a/packages/react-formio-stores/src/stores/submissions/submissions.reducers.ts +++ b/packages/react-formio-stores/src/stores/submissions/submissions.reducers.ts @@ -1,4 +1,4 @@ -import type { Submission } from "@tsed/react-formio"; +import type { SubmissionType } from "@tsed/react-formio"; import { createReducer } from "@tsed/redux-utils"; import { failSubmissions, receiveSubmissions, requestSubmissions, resetSubmissions } from "./submissions.actions"; @@ -15,7 +15,7 @@ export interface SubmissionsState { select: any; sortBy: any[]; }; - data: Submission[]; + data: SubmissionType[]; } export function createInitialState({ pageIndex = 0, pageSize = 10, query = {}, select = "", sortBy = [] }: any = {}): SubmissionsState { diff --git a/packages/react-formio-stores/tsconfig.app.json b/packages/react-formio-stores/tsconfig.app.json new file mode 100644 index 00000000..ee6ad461 --- /dev/null +++ b/packages/react-formio-stores/tsconfig.app.json @@ -0,0 +1,11 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "baseUrl": ".", + "noEmit": true, + "declaration": false, + "composite": false + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts", "src/**/*.spec.tsx"] +} diff --git a/packages/react-formio-stores/tsconfig.json b/packages/react-formio-stores/tsconfig.json index d189cbb5..7f5afa49 100644 --- a/packages/react-formio-stores/tsconfig.json +++ b/packages/react-formio-stores/tsconfig.json @@ -1,15 +1,21 @@ { - "extends": "@tsed/config/tsconfig.web.json", "compilerOptions": { - "rootDir": "src" + "baseUrl": ".", + "composite": true }, - "include": ["src"], + "include": [], "references": [ + { + "path": "../redux-utils/tsconfig.json" + }, + { + "path": "./tsconfig.app.json" + }, { "path": "./tsconfig.node.json" }, { - "path": "../redux-utils/tsconfig.json" + "path": "./tsconfig.spec.json" } ] } diff --git a/packages/react-formio-stores/tsconfig.node.json b/packages/react-formio-stores/tsconfig.node.json index 8ce10716..4e75ad79 100644 --- a/packages/react-formio-stores/tsconfig.node.json +++ b/packages/react-formio-stores/tsconfig.node.json @@ -1,8 +1,13 @@ { + "extends": "@tsed/typescript/tsconfig.web.json", "compilerOptions": { - "composite": true, - "module": "esnext", - "moduleResolution": "node" + "module": "NodeNext", + "moduleResolution": "NodeNext", + "baseUrl": ".", + "noEmit": true, + "declaration": false, + "composite": false }, - "include": [] + "include": ["vite.config.mts"], + "exclude": ["node_modules", "dist", "src/**/*.spec.ts", "src/**/*.spec.tsx"] } diff --git a/packages/react-formio-stores/tsconfig.spec.json b/packages/react-formio-stores/tsconfig.spec.json new file mode 100644 index 00000000..804fff86 --- /dev/null +++ b/packages/react-formio-stores/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "@tsed/typescript/tsconfig.web.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": ".", + "declaration": false, + "composite": false, + "noEmit": true, + "paths": {}, + "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"] + }, + "include": ["src/**/*.spec.ts", "test/**/*.spec.ts", "vitest.config.mts"], + "exclude": ["node_modules", "lib", "benchmark", "coverage"] +} diff --git a/packages/react-formio-stores/vite.config.mts b/packages/react-formio-stores/vite.config.mts new file mode 100644 index 00000000..3d062040 --- /dev/null +++ b/packages/react-formio-stores/vite.config.mts @@ -0,0 +1,68 @@ +import {fileURLToPath} from "node:url"; + +import react from "@vitejs/plugin-react"; +import {globbySync} from "globby"; +import {extname, relative} from "path"; +import preserveDirectives from "rollup-preserve-directives"; +import {defineConfig} from "vite"; +import dts from "vite-plugin-dts"; +import {resolve} from "node:path"; +import pkg from "./package.json" with {type: "json"}; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + react(), + dts({ + tsconfigPath: "./tsconfig.app.json", + aliasesExclude: [], + include: ["src/**/*.{ts,tsx}"], + exclude: ["**/*.spec.{ts,tsx}", "**/*.stories.{ts,tsx}", "**/__*__/**"] + }) + ], + resolve: { + alias: {} + }, + build: { + sourcemap: true, + lib: { + entry: resolve(import.meta.dirname, "src/index.ts"), + formats: ["es"] + }, + copyPublicDir: false, + rollupOptions: { + external: [ + ...Object.keys(pkg.peerDependencies || {}), + "react", + "react-dom", + "react/jsx-runtime", + /lodash\/.*/, + /formiojs\/.*/, + /@tsed\/.*/ + ], + plugins: [preserveDirectives() as any], + input: Object.fromEntries( + globbySync("src/**/*.{ts,tsx}", { + ignore: ["**/*.spec.{ts,tsx}", "**/*.stories.{ts,tsx}", "**/__*__/**"] + }).map((file) => { + return [ + // The name of the entry point + // src/nested/foo.ts becomes nested/foo + relative("src", file.slice(0, file.length - extname(file).length)), + // The absolute path to the entry file + // src/nested/foo.ts becomes /project/src/nested/foo.ts + fileURLToPath(new URL(file, import.meta.url)) + ]; + }) + ), + output: { + assetFileNames: "assets/[name][extname]", + chunkFileNames: "chunks/[name].js", + entryFileNames: "[name].js", + globals: { + react: "React" + } + } + } + } +}); diff --git a/packages/react-formio-stores/vitest.config.mts b/packages/react-formio-stores/vitest.config.mts new file mode 100644 index 00000000..d759e817 --- /dev/null +++ b/packages/react-formio-stores/vitest.config.mts @@ -0,0 +1,21 @@ +// @ts-ignore +import {presets} from "@tsed/vitest/presets"; +import {defineConfig} from "vitest/config"; + +export default defineConfig( + { + ...presets, + test: { + ...presets.test, + coverage: { + ...presets.test.coverage, + thresholds: { + statements: 0, + branches: 0, + functions: 0, + lines: 0 + } + } + } + } +); diff --git a/packages/react-formio/.eslintignore b/packages/react-formio/.eslintignore deleted file mode 100644 index 474be905..00000000 --- a/packages/react-formio/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -**/node_modules -docs -docs-references -**/lib -**/build -**/dist -**/coverage -**/.nyc_output -**/node_modules -*-lock.json -*.lock -benchmarks.* -**/generated diff --git a/packages/react-formio/.eslintrc.js b/packages/react-formio/.eslintrc.js deleted file mode 100644 index 3d887dbf..00000000 --- a/packages/react-formio/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: [require.resolve("@tsed/config/eslint/web")], - rules: { - "import/no-anonymous-default-export": 0, - "jsx-a11y/no-autofocus": 1 - } -}; diff --git a/packages/react-formio/coverage.json b/packages/react-formio/coverage.json deleted file mode 100644 index 64ee77c4..00000000 --- a/packages/react-formio/coverage.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "statements": 0, - "branches": 0, - "functions": 0, - "lines": 0 -} diff --git a/packages/react-formio/jest.config.js b/packages/react-formio/jest.config.js deleted file mode 100644 index fe16413a..00000000 --- a/packages/react-formio/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - ...require("@tsed/config/jest/jest.web.config.js"), - coverageThreshold: { - global: require("./coverage.json") - } -}; diff --git a/packages/react-formio/package.json b/packages/react-formio/package.json index d8c0de9d..f83b9212 100644 --- a/packages/react-formio/package.json +++ b/packages/react-formio/package.json @@ -1,44 +1,52 @@ { "name": "@tsed/react-formio", - "version": "2.3.2", + "version": "3.0.0-alpha.9", "description": "Provide a react formio wrapper. Written in TypeScript.", + "type": "module", "main": "./dist/index.js", "module": "./dist/index.modern.js", "exports": { ".": { - "import": "./dist/index.modern.js", - "require": "./dist/index.js" + "types": "./dist/index.d.ts", + "tsed-source": "./src/index.ts", + "default": "./dist/index.js" + }, + "./*": { + "types": "./dist/*.d.ts", + "tsed-source": "./src/*", + "default": "./dist/*.js" } }, "source": "src/index.ts", "license": "MIT", "scripts": { - "lint:fix": "yarn lint --fix", - "test": "cross-env NODE_ENV=test jest --coverage", - "test:coverage:update": "write-coverage", - "build": "microbundle --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx", - "watch": "microbundle watch --no-compress --format modern,cjs --jsx React.createElement --jsxFragment React.Fragment --globals react/jsx-runtime=jsx" + "test": "vitest run --coverage", + "build": "vite build", + "watch": "vite build --watch" }, "dependencies": { "classnames": "^2.3.1", "eventemitter2": "^6.4.3", - "prop-types": "15.8.1" + "use-debounce": "^10.0.4" }, "peerDependencies": { "@formio/choices.js": ">=9.0.1", "formiojs": ">=4.0.0", "lodash": ">=4.17.20", - "prop-types": ">=15.7.2", + "moment": ">=2.30.1", "react": ">=16.14.0", "react-dnd": ">=16.0.1", "react-dnd-html5-backend": ">=16.0.1", "react-dom": ">=16.14.0", + "react-select": ">=5.9.0", "react-table": ">=7.6.3", "tooltip.js": ">=1.3.3" }, "devDependencies": { - "@tsed/tailwind": "workspace:*", "@tsed/tailwind-formio": "workspace:*", - "microbundle": "0.13.0" + "@tsed/typescript": "workspace:*", + "microbundle": "0.13.0", + "vite": "5.4.11", + "vitest": "2.1.8" } } diff --git a/packages/react-formio/readme.md b/packages/react-formio/readme.md index 702b406c..9b99a452 100644 --- a/packages/react-formio/readme.md +++ b/packages/react-formio/readme.md @@ -1,5 +1,5 @@

- Ts.ED logo + Ts.ED logo

@@ -14,11 +14,11 @@
- Website + Website   •   - Tutorial + Tutorial   •   - Slack + Slack   •   Twitter
@@ -31,30 +31,30 @@ platform. This module is based on the original [react-formio](https://github.com/formio/react-formio) and add extra features listed above. -See our [storybook](https://formio.tsed.io/?path=/docs/getting-started--docs) to see all available components. +See our [storybook](https://formio.tsed.dev/?path=/docs/getting-started--docs) to see all available components. ## Features Many components are provided to build your own backoffice based on Formio.js API: -- [ActionsTable](https://formio.tsed.io/?path=story/reactformio-actionstable--sandbox), -- [FormAccess](https://formio.tsed.io/?path=story/reactformio-formaccess--sandbox), -- [FormAction](https://formio.tsed.io/?path=story/reactformio-formaction--sandbox), -- [Form](https://formio.tsed.io/?path=docs/documentation-form--docs), -- [FormBuilder](https://formio.tsed.io/?path=docs/documentation-formbuilder--docs), -- [FormEdit](https://formio.tsed.io/?path=docs/documentation-formedit--docs), -- [FormsTable](https://formio.tsed.io/?path=docs/documentation-formstable--docs), -- [InputTags](https://formio.tsed.io/?path=story/reactformio-inputtags--sandbox), -- [InputText](https://formio.tsed.io/?path=story/reactformio-inputtext--sandbox), -- [Pagination](https://formio.tsed.io/?path=story/reactformio-pagination--sandbox), -- [Select](https://formio.tsed.io/?path=/story/reactformio-select--sandbox), -- [SubmissionsTable](https://formio.tsed.io/?path=/docs/documentation-submissionstable--docs). -- [Table](https://formio.tsed.io/?path=/story/reactformio-table--sandbox), +- ActionsTable, +- FormAccess, +- FormAction, +- Form, +- FormBuilder, +- FormEdit, +- FormsTable, +- InputTags, +- InputText, +- Pagination, +- Select, +- SubmissionsTable. +- Table, - Predefined Reducers for Actions, Action, Form, Forms, Submission, Submissions, etc..., - TypeScript support. - Tailwind support. -## Migrate from v1 +## Migrate to v2 If you use redux actions from v1, you have to install `@tsed/redux-formio-stores` and remplace your imports: @@ -63,6 +63,19 @@ If you use redux actions from v1, you have to install `@tsed/redux-formio-stores + import { defaultFormioReducer, formsReducer } from "@tsed/react-formio-stores"; ``` +## Migrate to v3 + +- `@tsed/react-formio` is now build only for ESM environment. +- `@tsed/react-formio` use tree-shaking to reduce the bundle size, you have to import only what you need from the library. +- `@tsed/react-formio` drop the support of TailwindCSS v2. + +Example: + +```diff +- import { Form } from "@tsed/react-formio"; ++ import { Form } from "@tsed/react-formio/organisms/form/Form"; +``` + ## Install `@tsed/react-formio` can be used on the server, or bundled for the client using an @@ -91,7 +104,7 @@ function App() { export default App; ``` -See more on http://formio.tsed.io/?path=/docs/getting-started--docs +See more on http://formio.tsed.dev/?path=/docs/getting-started--docs ## Contributors diff --git a/packages/react-formio/src/atoms/icon/Icon.stories.tsx b/packages/react-formio/src/atoms/icon/Icon.stories.tsx new file mode 100644 index 00000000..4574bf73 --- /dev/null +++ b/packages/react-formio/src/atoms/icon/Icon.stories.tsx @@ -0,0 +1,124 @@ +import { Meta, StoryObj } from "@storybook/react"; +import Template from "@tsed/tailwind-formio"; + +import { Icon } from "./Icon"; + +/** + * Icon component to display icons based on [BxIcons](https://boxicons.com/). + * + * ## Usage + * + * ```ts + * import {Icon} from "@tsed/react-formio/atoms/icon/Icon"; + * ``` + * + * ## Override Icon + * + * This component is registered with the name `Icon` and can be overridden with the following code: + * + * ```ts + * registerComponent("Icon", MyIconComponent); + * ``` + */ +export default { + title: "Icon", + component: Icon, + argTypes: { + name: { + control: "text" + } + }, + parameters: { + children: "Text", + variant: "primary" + } +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + name: "save" + } +}; + +export const Size: Story = { + args: { + name: "save" + }, + render() { + return ( +
+ {["text-sm", "text-large", "text-xl", "text-3xl", "text-8xl"].map((className) => ( +
+ +
+ ))} +
+ ); + } +}; + +export const Colors: Story = { + args: { + name: "save" + }, + render() { + return ( +
+ {["text-sm text-red-600", "text-large text-primary", "text-xl text-secondary", "text-3xl text-green-600"].map((className) => ( +
+ +
+ ))} +
+ ); + } +}; + +export const Rounded: Story = { + args: { + name: "save" + }, + render() { + return ( +
+ {["text-sm bg-red-600", "text-large bg-primary", "text-xl bg-secondary", "text-3xl bg-green-600"].map((className) => ( +
+ +
+ ))} +
+ ); + } +}; +/** + * Formio needs theses icons to be displayed in the form builder and other places. + */ +export const PresetsForFormio: Story = { + args: { + name: "save" + }, + render() { + return ( +
+ {Object.entries(Template.templates.tailwind.ICONS).map(([icon]) => ( +
+
+
+ +
+ {icon} +
+
+ ))} +
+ ); + } +}; diff --git a/packages/react-formio/src/atoms/icon/Icon.tsx b/packages/react-formio/src/atoms/icon/Icon.tsx new file mode 100644 index 00000000..b319da6e --- /dev/null +++ b/packages/react-formio/src/atoms/icon/Icon.tsx @@ -0,0 +1,16 @@ +import cx from "classnames"; +import type { HTMLAttributes } from "react"; + +import { registerComponent } from "../../registries/components"; +import { iconClass } from "../../utils/iconClass"; + +export interface IconProps extends HTMLAttributes { + iconset?: string; + name: string; +} + +export function Icon({ iconset, name, className, ...props }: IconProps) { + return ; +} + +registerComponent("Icon", Icon); diff --git a/packages/react-formio/src/components/alert/alert.stories.tsx b/packages/react-formio/src/components/alert/alert.stories.tsx deleted file mode 100644 index 3ebd46bc..00000000 --- a/packages/react-formio/src/components/alert/alert.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -import { Alert } from "./alert.component"; - -export default { - title: "ReactFormio/Alert", - component: Alert, - argTypes: {}, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - error: "error placeholder" -}; diff --git a/packages/react-formio/src/components/form-builder/formBuilder.component.tsx b/packages/react-formio/src/components/form-builder/formBuilder.component.tsx deleted file mode 100755 index 77fc7a24..00000000 --- a/packages/react-formio/src/components/form-builder/formBuilder.component.tsx +++ /dev/null @@ -1,195 +0,0 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -import { ComponentSchema } from "formiojs"; -import AllComponents from "formiojs/components"; -import Components from "formiojs/components/Components"; -import FormioFormBuilder from "formiojs/FormBuilder"; -import cloneDeep from "lodash/cloneDeep"; -import noop from "lodash/noop"; -import PropTypes from "prop-types"; -import React from "react"; - -import { callLast } from "../../utils/callLast"; - -Components.setComponents(AllComponents); - -const EVENTS = [ - "addComponent", - "updateComponent", - "removeComponent", - "saveComponent", - "cancelComponent", - "moveComponent", - "editComponent", - "editJson", - "copyComponent", - "pasteComponent" -]; - -const EVENTS_CHANGE = ["addComponent", "saveComponent", "updateComponent", "removeComponent"]; - -async function createBuilder(el: Element, { components = [], display, options, onChange, events = {} }: any): Promise { - const form = { - display, - components: [...components] - }; - - try { - const builder = await new FormioFormBuilder(el, form, { ...options }).ready; - - const handleEvent = (event: string) => { - return (...args: any[]) => { - events[event] && events[event](...args); - - if (EVENTS_CHANGE.includes(event)) { - onChange(builder.form.components); - } - }; - }; - - EVENTS.forEach((event) => builder.on(event, callLast(handleEvent(event), 200))); - - return builder; - } catch (er) { - console.error(er); - } -} - -export interface FormBuilderProps { - components: ComponentSchema[]; - display?: string; - options?: any; - builder?: any; - onChange?: (components: ComponentSchema[]) => void; - onAddComponent?: Function; - onUpdateComponent?: Function; - onRemoveComponent?: Function; - onSaveComponent?: Function; - onCancelComponent?: Function; - onMoveComponent?: Function; - onEditComponent?: Function; - onEditJson?: Function; - onCopyComponent?: Function; - onPasteComponent?: Function; -} - -export class FormBuilder extends React.Component { - static defaultProps = { - options: {}, - onChange: noop, - onReady: noop, - onDestroy: noop - }; - - static propTypes = { - components: PropTypes.array, - display: PropTypes.string, - options: PropTypes.object, - onChange: PropTypes.func, - onAddComponent: PropTypes.func, - onUpdateComponent: PropTypes.func, - onRemoveComponent: PropTypes.func, - onSaveComponent: PropTypes.func, - onCancelComponent: PropTypes.func, - onMoveComponent: PropTypes.func, - onEditComponent: PropTypes.func, - onEditJson: PropTypes.func, - onCopyComponent: PropTypes.func, - onPasteComponent: PropTypes.func - }; - - private elRef: any; - private builderRef: any; - - constructor(props: FormBuilderProps) { - super(props); - - this.state = { - display: props.display, - components: cloneDeep(props.components) - }; - this.elRef = null; - this.builderRef = null; - } - - async componentDidMount(): Promise { - await this.create(this.props); - } - - async create(props: FormBuilderProps) { - const { - options, - display, - components, - onAddComponent, - onUpdateComponent, - onRemoveComponent, - onSaveComponent, - onCancelComponent, - onMoveComponent, - onEditComponent, - onEditJson, - onCopyComponent, - onPasteComponent - } = props; - - this.builderRef = await createBuilder(this.elRef.firstChild, { - display, - options: { ...options }, - components: cloneDeep(components), - onChange: this.whenComponentsChange.bind(this), - events: { - onAddComponent, - onUpdateComponent, - onRemoveComponent, - onSaveComponent, - onCancelComponent, - onMoveComponent, - onEditComponent, - onEditJson, - onCopyComponent, - onPasteComponent - } - }); - } - - componentWillUnmount(): void { - this.builderRef?.destroy(); - } - - // eslint-disable-next-line react/no-deprecated - async componentWillReceiveProps(nextProps: FormBuilderProps) { - if (this.builderRef) { - if (nextProps.display !== this.state.display) { - await this.create({ - ...this.props, - display: nextProps.display - }); - } else if (nextProps.components !== this.state.components) { - this.builderRef.form = { - display: this.state.display, - components: nextProps.components - }; - } - } - } - - whenComponentsChange(components: ComponentSchema[]) { - this.setState({ components }, () => { - this.props?.onChange && this.props.onChange(components); - }); - } - - render() { - return ( -
{ - this.elRef = ref; - }} - onClick={(e) => e.stopPropagation()} - > -
-
- ); - } -} diff --git a/packages/react-formio/src/components/form-builder/formBuilder.stories.tsx b/packages/react-formio/src/components/form-builder/formBuilder.stories.tsx deleted file mode 100644 index a4be3332..00000000 --- a/packages/react-formio/src/components/form-builder/formBuilder.stories.tsx +++ /dev/null @@ -1,3667 +0,0 @@ -import React from "react"; - -import { FormBuilder } from "../../index"; - -export default { - title: "ReactFormio/FormBuilder", - component: FormBuilder, - argTypes: { - display: { - control: { - type: "select", - options: ["form", "wizard", "pdf"] - } - }, - components: { - control: { - type: "object" - } - }, - options: { - control: { - type: "object" - } - }, - onSubmit: { action: "onSubmit" } - }, - parameters: { - docs: { - source: { - type: "code" - } - } - } -}; - -export const Sandbox = { - render: ({ display, options, components }: any) => { - return ; - }, - args: { - display: "form", - options: { template: "tailwind", iconset: "bx" }, - components: [ - { - label: "Text Field", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - inputMask: "", - allowMultipleMasks: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: true, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "textField", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "textfield", - input: true, - refreshOn: "", - inputType: "text", - id: "eqb1o4r", - defaultValue: "" - }, - { - label: "Text Area", - labelPosition: "top", - placeholder: "Placeholder", - description: "description", - tooltip: "tooltip", - prefix: "", - suffix: "", - widget: { type: "input" }, - editor: "", - autoExpand: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "html", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - minWords: "", - maxWords: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "textArea", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - fixedSize: true, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - attributes: {}, - type: "textarea", - rows: 3, - wysiwyg: false, - input: true, - refreshOn: "", - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputMask: "", - id: "e4jsrqc", - defaultValue: "" - }, - { - label: "Number", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - delimiter: false, - requireDecimal: false, - inputFormat: "plain", - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - min: "", - max: "", - strictDateValidation: false, - multiple: false, - unique: false, - step: "any", - integer: "" - }, - errorLabel: "", - key: "number", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "number", - input: true, - unique: false, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ex8zh8u", - defaultValue: null - }, - { - label: "Password", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - case: "", - redrawOn: "", - clearOnHide: true, - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "password", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "password", - input: true, - multiple: false, - defaultValue: null, - protected: true, - unique: false, - persistent: true, - refreshOn: "", - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - encrypted: false, - allowMultipleMasks: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - id: "etqa5pm" - }, - { - label: "Checkbox", - description: "description", - tooltip: "tooltip", - shortcut: "", - inputType: "checkbox", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - defaultValue: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "checkbox", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "checkbox", - name: "", - value: "", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - labelPosition: "right", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - dataGridLabel: true, - id: "em8ln2m" - }, - { - label: "Select Boxes", - labelPosition: "top", - optionsLabelPosition: "right", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - inline: false, - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - values: [ - { label: "label", value: "label", shortcut: "" }, - { label: "lol", value: "lol", shortcut: "" } - ], - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - minSelectedCountMessage: "", - maxSelectedCountMessage: "", - key: "selectBoxes", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "selectboxes", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "checkbox", - fieldSet: false, - id: "esa4upt", - defaultValue: { "": false } - }, - { - label: "Radio", - labelPosition: "top", - optionsLabelPosition: "right", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - inline: false, - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - values: [ - { label: "data", value: "data", shortcut: "" }, - { label: "label", value: "label", shortcut: "" } - ], - dataType: "", - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "radio", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "radio", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "radio", - fieldSet: false, - id: "edh7o6o", - defaultValue: "" - }, - { - label: "Select", - labelPosition: "top", - widget: "choicesjs", - placeholder: "placeholder", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - uniqueOptions: false, - autofocus: false, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - dataSrc: "values", - data: { - values: [ - { label: "label", value: "label" }, - { label: "save", value: "save" } - ], - resource: "", - json: "", - url: "", - custom: "" - }, - valueProperty: "", - dataType: "", - idPath: "id", - template: "{{ item.label }}", - refreshOn: "", - refreshOnBlur: "", - clearOnRefresh: false, - searchEnabled: true, - selectThreshold: 0.3, - readOnlyValue: false, - customOptions: {}, - useExactSearch: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "select", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "select", - indexeddb: { filter: {} }, - selectFields: "", - searchField: "", - minSearch: 0, - filter: "", - limit: 100, - redrawOn: "", - input: true, - prefix: "", - suffix: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - lazyLoad: true, - authenticate: false, - searchThreshold: 0.3, - fuseOptions: { include: "score", threshold: 0.3 }, - id: "ebqtqd6", - defaultValue: "" - }, - { - label: "Select", - labelPosition: "top", - widget: "html5", - placeholder: "placeholder", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - uniqueOptions: false, - autofocus: false, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - dataSrc: "values", - data: { - values: [{ label: "", value: "" }], - resource: "", - json: "", - url: "", - custom: "" - }, - valueProperty: "", - dataType: "", - idPath: "id", - template: "{{ item.label }}", - refreshOn: "", - refreshOnBlur: "", - clearOnRefresh: false, - searchEnabled: true, - selectThreshold: 0.3, - readOnlyValue: false, - customOptions: {}, - useExactSearch: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "select1", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "select", - indexeddb: { filter: {} }, - selectFields: "", - searchField: "", - minSearch: 0, - filter: "", - limit: 100, - redrawOn: "", - input: true, - prefix: "", - suffix: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - lazyLoad: true, - authenticate: false, - searchThreshold: 0.3, - fuseOptions: { include: "score", threshold: 0.3 }, - id: "em8m4qk", - defaultValue: "" - }, - { - label: "Email", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - kickbox: { enabled: false }, - errorLabel: "", - key: "email", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "email", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "email", - inputMask: "", - id: "epj8sj28", - defaultValue: null - }, - { - label: "Url", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "url", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "url", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "url", - inputMask: "", - id: "exw9p4", - defaultValue: null - }, - { - label: "Phone Number", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - inputMask: "(999) 999-9999", - allowMultipleMasks: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - unique: false, - errorLabel: "", - key: "phoneNumber", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "phoneNumber", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - inputType: "tel", - id: "e2c7lpl", - defaultValue: null - }, - { - label: "Tags", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - delimeter: ",", - maxTags: 0, - storeas: "string", - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "tags", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "tags", - input: true, - prefix: "", - suffix: "", - multiple: false, - refreshOn: "", - widget: { type: "input" }, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ejc82t", - defaultValue: null - }, - { - label: "Address", - labelPosition: "top", - enableManualMode: false, - disableClearIcon: false, - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - provider: "google", - manualModeViewString: "", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "address", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "address", - switchToManualModeLabel: "Can't find address? Switch to manual mode.", - input: true, - prefix: "", - suffix: "", - refreshOn: "", - widget: null, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - tree: true, - components: [ - { - label: "Address 1", - tableView: false, - key: "address1", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eecfg6h" - }, - { - label: "Address 2", - tableView: false, - key: "address2", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eajhpuu" - }, - { - label: "City", - tableView: false, - key: "city", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "efpnrca7" - }, - { - label: "State", - tableView: false, - key: "state", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eu3kksv" - }, - { - label: "Country", - tableView: false, - key: "country", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "el39cu9" - }, - { - label: "Zip Code", - tableView: false, - key: "zip", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "epyac4" - } - ], - providerOptions: { params: { key: "fze", region: "" } }, - id: "er02e2gb", - defaultValue: {} - }, - { - label: "Date / Time", - labelPosition: "top", - displayInTimezone: "viewer", - useLocaleSettings: false, - allowInput: true, - format: "yyyy-MM-dd hh:mm a", - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - enableDate: true, - enableMinDateInput: false, - datePicker: { - minDate: null, - maxDate: null, - disable: "", - disableFunction: "", - disableWeekends: false, - disableWeekdays: false, - showWeeks: true, - startingDay: 0, - initDate: "", - minMode: "day", - maxMode: "year", - yearRows: 4, - yearColumns: 5 - }, - enableMaxDateInput: false, - enableTime: true, - timePicker: { - showMeridian: true, - hourStep: 1, - minuteStep: 1, - readonlyInput: false, - mousewheel: true, - arrowkeys: true - }, - multiple: false, - defaultValue: "", - defaultDate: "", - customOptions: {}, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "dateTime", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "datetime", - timezone: "", - input: true, - prefix: "", - suffix: "", - refreshOn: "", - widget: { - type: "calendar", - displayInTimezone: "viewer", - locale: "en", - useLocaleSettings: false, - allowInput: true, - mode: "single", - enableTime: true, - noCalendar: false, - format: "yyyy-MM-dd hh:mm a", - hourIncrement: 1, - minuteIncrement: 1, - minDate: null, - disabledDates: "", - disableWeekends: false, - disableWeekdays: false, - disableFunction: "", - maxDate: null - }, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - datepickerMode: "day", - id: "el9idgl" - }, - { - label: "Day", - hideInputLabels: false, - inputsLabelPosition: "top", - description: "", - useLocaleSettings: false, - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - fields: { - day: { - type: "number", - placeholder: "", - hide: false, - required: false - }, - month: { - type: "select", - placeholder: "", - hide: false, - required: false - }, - year: { - type: "number", - placeholder: "", - hide: false, - required: false - } - }, - dayFirst: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - maxDate: "", - minDate: "", - unique: false, - errorLabel: "", - validate: { - customMessage: "", - custom: "", - customPrivate: false, - json: "", - required: false, - strictDateValidation: false, - multiple: false, - unique: false - }, - key: "day", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "day", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - refreshOn: "", - labelPosition: "top", - widget: null, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ecgefls", - defaultValue: "00/00/0000" - }, - { - label: "Currency", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - currency: "USD", - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false, - min: "", - max: "", - step: "any", - integer: "" - }, - unique: false, - errorLabel: "", - key: "currency", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "currency", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - delimiter: true, - id: "em22wkd", - defaultValue: null - }, - { - type: "button", - label: "Submit", - key: "submit", - size: "md", - block: false, - action: "submit", - disableOnInvalid: true, - theme: "primary", - input: true, - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - tableView: false, - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - leftIcon: "", - rightIcon: "", - dataGridLabel: true, - id: "e08gq3l" - } - ] - } -}; - -export const Wizard = { - render: (args: any) => { - return ; - }, - - args: { - display: "wizard", - components: [ - { - label: "Text Field", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - inputMask: "", - allowMultipleMasks: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: true, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "textField", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "textfield", - input: true, - refreshOn: "", - inputType: "text", - id: "eqb1o4r", - defaultValue: "" - }, - { - label: "Text Area", - labelPosition: "top", - placeholder: "Placeholder", - description: "description", - tooltip: "tooltip", - prefix: "", - suffix: "", - widget: { type: "input" }, - editor: "", - autoExpand: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "html", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - minWords: "", - maxWords: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "textArea", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - fixedSize: true, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - attributes: {}, - type: "textarea", - rows: 3, - wysiwyg: false, - input: true, - refreshOn: "", - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputMask: "", - id: "e4jsrqc", - defaultValue: "" - }, - { - label: "Number", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - delimiter: false, - requireDecimal: false, - inputFormat: "plain", - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - min: "", - max: "", - strictDateValidation: false, - multiple: false, - unique: false, - step: "any", - integer: "" - }, - errorLabel: "", - key: "number", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "number", - input: true, - unique: false, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ex8zh8u", - defaultValue: null - }, - { - label: "Password", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - showWordCount: false, - showCharCount: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - case: "", - redrawOn: "", - clearOnHide: true, - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "password", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "password", - input: true, - multiple: false, - defaultValue: null, - protected: true, - unique: false, - persistent: true, - refreshOn: "", - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - encrypted: false, - allowMultipleMasks: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - id: "etqa5pm" - }, - { - label: "Checkbox", - description: "description", - tooltip: "tooltip", - shortcut: "", - inputType: "checkbox", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - defaultValue: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "checkbox", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "checkbox", - name: "", - value: "", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - labelPosition: "right", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - dataGridLabel: true, - id: "em8ln2m" - }, - { - label: "Select Boxes", - labelPosition: "top", - optionsLabelPosition: "right", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - inline: false, - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - values: [ - { label: "label", value: "label", shortcut: "" }, - { label: "lol", value: "lol", shortcut: "" } - ], - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - minSelectedCountMessage: "", - maxSelectedCountMessage: "", - key: "selectBoxes", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "selectboxes", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "checkbox", - fieldSet: false, - id: "esa4upt", - defaultValue: { "": false } - }, - { - label: "Radio", - labelPosition: "top", - optionsLabelPosition: "right", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - inline: false, - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - values: [ - { label: "data", value: "data", shortcut: "" }, - { label: "label", value: "label", shortcut: "" } - ], - dataType: "", - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - errorLabel: "", - key: "radio", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "radio", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - unique: false, - refreshOn: "", - widget: null, - validateOn: "change", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "radio", - fieldSet: false, - id: "edh7o6o", - defaultValue: "" - }, - { - label: "Select", - labelPosition: "top", - widget: "choicesjs", - placeholder: "placeholder", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - uniqueOptions: false, - autofocus: false, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - dataSrc: "values", - data: { - values: [ - { label: "label", value: "label" }, - { label: "save", value: "save" } - ], - resource: "", - json: "", - url: "", - custom: "" - }, - valueProperty: "", - dataType: "", - idPath: "id", - template: "{{ item.label }}", - refreshOn: "", - refreshOnBlur: "", - clearOnRefresh: false, - searchEnabled: true, - selectThreshold: 0.3, - readOnlyValue: false, - customOptions: {}, - useExactSearch: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "select", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "select", - indexeddb: { filter: {} }, - selectFields: "", - searchField: "", - minSearch: 0, - filter: "", - limit: 100, - redrawOn: "", - input: true, - prefix: "", - suffix: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - lazyLoad: true, - authenticate: false, - searchThreshold: 0.3, - fuseOptions: { include: "score", threshold: 0.3 }, - id: "ebqtqd6", - defaultValue: "" - }, - { - label: "Select", - labelPosition: "top", - widget: "html5", - placeholder: "placeholder", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - uniqueOptions: false, - autofocus: false, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - dataSrc: "values", - data: { - values: [{ label: "", value: "" }], - resource: "", - json: "", - url: "", - custom: "" - }, - valueProperty: "", - dataType: "", - idPath: "id", - template: "{{ item.label }}", - refreshOn: "", - refreshOnBlur: "", - clearOnRefresh: false, - searchEnabled: true, - selectThreshold: 0.3, - readOnlyValue: false, - customOptions: {}, - useExactSearch: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "select1", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "select", - indexeddb: { filter: {} }, - selectFields: "", - searchField: "", - minSearch: 0, - filter: "", - limit: 100, - redrawOn: "", - input: true, - prefix: "", - suffix: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - lazyLoad: true, - authenticate: false, - searchThreshold: 0.3, - fuseOptions: { include: "score", threshold: 0.3 }, - id: "em8m4qk", - defaultValue: "" - }, - { - label: "Email", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - kickbox: { enabled: false }, - errorLabel: "", - key: "email", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "email", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "email", - inputMask: "", - id: "epj8sj28", - defaultValue: null - }, - { - label: "Url", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - pattern: "", - customMessage: "", - custom: "", - customPrivate: false, - json: "", - minLength: "", - maxLength: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - errorLabel: "", - key: "url", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "url", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - inputType: "url", - inputMask: "", - id: "exw9p4", - defaultValue: null - }, - { - label: "Phone Number", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - inputMask: "(999) 999-9999", - allowMultipleMasks: false, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: true, - modalEdit: false, - multiple: false, - persistent: true, - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - unique: false, - errorLabel: "", - key: "phoneNumber", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "phoneNumber", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - inputType: "tel", - id: "e2c7lpl", - defaultValue: null - }, - { - label: "Tags", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - delimeter: ",", - maxTags: 0, - storeas: "string", - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "tags", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "tags", - input: true, - prefix: "", - suffix: "", - multiple: false, - refreshOn: "", - widget: { type: "input" }, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ejc82t", - defaultValue: null - }, - { - label: "Address", - labelPosition: "top", - enableManualMode: false, - disableClearIcon: false, - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - provider: "google", - manualModeViewString: "", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "address", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "address", - switchToManualModeLabel: "Can't find address? Switch to manual mode.", - input: true, - prefix: "", - suffix: "", - refreshOn: "", - widget: null, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - tree: true, - components: [ - { - label: "Address 1", - tableView: false, - key: "address1", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eecfg6h" - }, - { - label: "Address 2", - tableView: false, - key: "address2", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eajhpuu" - }, - { - label: "City", - tableView: false, - key: "city", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "efpnrca7" - }, - { - label: "State", - tableView: false, - key: "state", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "eu3kksv" - }, - { - label: "Country", - tableView: false, - key: "country", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "el39cu9" - }, - { - label: "Zip Code", - tableView: false, - key: "zip", - type: "textfield", - input: true, - customConditional: "show = _.get(instance, 'parent.manualMode', false);", - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: true, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false, - minLength: "", - maxLength: "", - pattern: "" - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - mask: false, - inputType: "text", - inputFormat: "plain", - inputMask: "", - spellcheck: true, - id: "epyac4" - } - ], - providerOptions: { params: { key: "fze", region: "" } }, - id: "er02e2gb", - defaultValue: {} - }, - { - label: "Date / Time", - labelPosition: "top", - displayInTimezone: "viewer", - useLocaleSettings: false, - allowInput: true, - format: "yyyy-MM-dd hh:mm a", - placeholder: "", - description: "", - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - enableDate: true, - enableMinDateInput: false, - datePicker: { - minDate: null, - maxDate: null, - disable: "", - disableFunction: "", - disableWeekends: false, - disableWeekdays: false, - showWeeks: true, - startingDay: 0, - initDate: "", - minMode: "day", - maxMode: "year", - yearRows: 4, - yearColumns: 5 - }, - enableMaxDateInput: false, - enableTime: true, - timePicker: { - showMeridian: true, - hourStep: 1, - minuteStep: 1, - readonlyInput: false, - mousewheel: true, - arrowkeys: true - }, - multiple: false, - defaultValue: "", - defaultDate: "", - customOptions: {}, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false - }, - unique: false, - validateOn: "change", - errorLabel: "", - key: "dateTime", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "datetime", - timezone: "", - input: true, - prefix: "", - suffix: "", - refreshOn: "", - widget: { - type: "calendar", - displayInTimezone: "viewer", - locale: "en", - useLocaleSettings: false, - allowInput: true, - mode: "single", - enableTime: true, - noCalendar: false, - format: "yyyy-MM-dd hh:mm a", - hourIncrement: 1, - minuteIncrement: 1, - minDate: null, - disabledDates: "", - disableWeekends: false, - disableWeekdays: false, - disableFunction: "", - maxDate: null - }, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - datepickerMode: "day", - id: "el9idgl" - }, - { - label: "Day", - hideInputLabels: false, - inputsLabelPosition: "top", - description: "", - useLocaleSettings: false, - tooltip: "", - customClass: "", - tabindex: "", - hidden: false, - hideLabel: false, - autofocus: false, - disabled: false, - tableView: false, - modalEdit: false, - fields: { - day: { - type: "number", - placeholder: "", - hide: false, - required: false - }, - month: { - type: "select", - placeholder: "", - hide: false, - required: false - }, - year: { - type: "number", - placeholder: "", - hide: false, - required: false - } - }, - dayFirst: false, - persistent: true, - protected: false, - dbIndex: false, - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - maxDate: "", - minDate: "", - unique: false, - errorLabel: "", - validate: { - customMessage: "", - custom: "", - customPrivate: false, - json: "", - required: false, - strictDateValidation: false, - multiple: false, - unique: false - }, - key: "day", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "day", - input: true, - placeholder: "", - prefix: "", - suffix: "", - multiple: false, - refreshOn: "", - labelPosition: "top", - widget: null, - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - id: "ecgefls", - defaultValue: "00/00/0000" - }, - { - label: "Currency", - labelPosition: "top", - placeholder: "", - description: "", - tooltip: "", - prefix: "", - suffix: "", - widget: { type: "input" }, - customClass: "", - tabindex: "", - autocomplete: "", - hidden: false, - hideLabel: false, - mask: false, - autofocus: false, - spellcheck: true, - disabled: false, - tableView: false, - modalEdit: false, - multiple: false, - persistent: true, - currency: "USD", - inputFormat: "plain", - protected: false, - dbIndex: false, - case: "", - encrypted: false, - redrawOn: "", - clearOnHide: true, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - allowCalculateOverride: false, - validateOn: "change", - validate: { - required: false, - customMessage: "", - custom: "", - customPrivate: false, - json: "", - strictDateValidation: false, - multiple: false, - unique: false, - min: "", - max: "", - step: "any", - integer: "" - }, - unique: false, - errorLabel: "", - key: "currency", - tags: [], - properties: {}, - conditional: { show: null, when: null, eq: "", json: "" }, - customConditional: "", - logic: [], - attributes: {}, - overlay: { - style: "", - page: "", - left: "", - top: "", - width: "", - height: "" - }, - type: "currency", - input: true, - refreshOn: "", - showCharCount: false, - showWordCount: false, - allowMultipleMasks: false, - delimiter: true, - id: "em22wkd", - defaultValue: null - }, - { - type: "button", - label: "Submit", - key: "submit", - size: "md", - block: false, - action: "submit", - disableOnInvalid: true, - theme: "primary", - input: true, - placeholder: "", - prefix: "", - customClass: "", - suffix: "", - multiple: false, - defaultValue: null, - protected: false, - unique: false, - persistent: false, - hidden: false, - clearOnHide: true, - refreshOn: "", - redrawOn: "", - tableView: false, - modalEdit: false, - labelPosition: "top", - description: "", - errorLabel: "", - tooltip: "", - hideLabel: false, - tabindex: "", - disabled: false, - autofocus: false, - dbIndex: false, - customDefaultValue: "", - calculateValue: "", - calculateServer: false, - widget: { type: "input" }, - attributes: {}, - validateOn: "change", - validate: { - required: false, - custom: "", - customPrivate: false, - strictDateValidation: false, - multiple: false, - unique: false - }, - conditional: { show: null, when: null, eq: "" }, - overlay: { style: "", left: "", top: "", width: "", height: "" }, - allowCalculateOverride: false, - encrypted: false, - showCharCount: false, - showWordCount: false, - properties: {}, - allowMultipleMasks: false, - leftIcon: "", - rightIcon: "", - dataGridLabel: true, - id: "e08gq3l" - } - ], - options: { template: "tailwind", iconset: "bx" } - } -}; diff --git a/packages/react-formio/src/components/form-control/formControl.component.tsx b/packages/react-formio/src/components/form-control/formControl.component.tsx deleted file mode 100644 index 87534cae..00000000 --- a/packages/react-formio/src/components/form-control/formControl.component.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import classnames from "classnames"; -import React from "react"; - -export interface FormControlProps { - name: string; - value?: Data; - required?: boolean; - label?: string; - className?: string; - onChange?: (name: string, value: any) => void; - description?: string | React.ComponentType | any; - prefix?: JSX.Element | React.ComponentType | any; - suffix?: JSX.Element | React.ComponentType | any; - shadow?: boolean; -} - -export function FormControl({ - children, - name, - required, - prefix, - suffix, - description, - label, - className -}: React.PropsWithChildren) { - return ( -
- {label && ( - - )} -
- {prefix && ( -
- - {prefix} - -
- )} - {children} - {suffix && ( -
- - {suffix} - -
- )} -
- {description && ( -
- {description} -
- )} -
- ); -} diff --git a/packages/react-formio/src/components/form-control/formControl.stories.tsx b/packages/react-formio/src/components/form-control/formControl.stories.tsx deleted file mode 100644 index 93925fc6..00000000 --- a/packages/react-formio/src/components/form-control/formControl.stories.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from "react"; - -import { iconClass } from "../../utils/iconClass"; -import { FormControl } from "./formControl.component"; - -export default { - title: "ReactFormio/FormControl", - component: FormControl, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - children: { - control: { - type: HTMLElement || HTMLCollection - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - label: "Label", - children: -}; - -export const WithPrefix = (args: any) => { - return ; -}; - -WithPrefix.args = { - label: "Label", - children: , - prefix: -}; - -export const WithSuffix = (args: any) => { - return ; -}; - -WithSuffix.args = { - label: "Label", - children: , - suffix: -}; - -export const WithDescription = (args: any) => { - return ; -}; - -WithDescription.args = { - label: "Label", - children: -}; diff --git a/packages/react-formio/src/components/form-edit/formCtas.component.tsx b/packages/react-formio/src/components/form-edit/formCtas.component.tsx deleted file mode 100644 index 1468c5b1..00000000 --- a/packages/react-formio/src/components/form-edit/formCtas.component.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import PropTypes from "prop-types"; -import React, { ReactElement } from "react"; - -import { useTooltip } from "../../hooks/useTooltip"; -import { FormOptions } from "../../interfaces"; -import { iconClass } from "../../utils/iconClass"; - -export interface FormEditCTAsProps extends Record { - saveText?: string; - options?: FormOptions; - hasUndo?: boolean; - hasRedo?: boolean; - disabled?: boolean; - onCopy?: Function; - onSubmit?: Function; - onReset?: Function; - onUndo?: Function; - onRedo?: Function; -} - -export function FormEditCTAs({ - saveText = "Save", - disabled, - options = {}, - onCopy, - hasUndo, - hasRedo, - onUndo, - onRedo, - onReset, - onSubmit -}: FormEditCTAsProps): ReactElement { - const { i18n: t = (t: string): string => t } = options; - - const copyTooltipRef: any = useTooltip({ - trigger: "hover", - placement: "top", - title: t("Copy") - }); - - const undoTooltipRef: any = useTooltip({ - trigger: "hover", - placement: "top", - title: t("Undo last change") - }); - - const redoTooltipRef: any = useTooltip({ - trigger: "hover", - placement: "top", - title: t("Redo last change") - }); - - const resetTooltipRef: any = useTooltip({ - trigger: "hover", - placement: "top", - title: t("Reset all changes") - }); - - return ( -
-
- - -
- - - -
- -
- {onCopy && ( - - )} - - -
-
-
- ); -} - -FormEditCTAs.propTypes = { - saveText: PropTypes.string, - options: PropTypes.object, - hasUndo: PropTypes.bool, - hasRedo: PropTypes.bool, - disabled: PropTypes.bool, - onCopy: PropTypes.func, - onSubmit: PropTypes.func, - onReset: PropTypes.func -}; diff --git a/packages/react-formio/src/components/form-edit/formEdit.component.tsx b/packages/react-formio/src/components/form-edit/formEdit.component.tsx deleted file mode 100644 index d2b46db9..00000000 --- a/packages/react-formio/src/components/form-edit/formEdit.component.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import PropTypes from "prop-types"; -import React from "react"; - -import { FormOptions } from "../../interfaces/FormOptions"; -import { FormBuilder } from "../form-builder/formBuilder.component"; -import { FormEditCTAs } from "./formCtas.component"; -import { FormParameters } from "./formParameters.component"; -import { useFormEdit, UseFormEditHookProps } from "./useFormEdit.hook"; - -export interface FormEditProps extends UseFormEditHookProps { - builder?: any; - options?: FormOptions; -} - -export function FormEdit(props: FormEditProps) { - const { form, isValid, setChange, hasRedo, hasChanged, hasUndo, redo, undo, reset, onSubmit, onCopy } = useFormEdit(props); - const { options = {}, builder } = props; - - return ( -
-
- - -
- - { - setChange("components", components); - }} - /> -
- ); -} - -FormEdit.propTypes = { - form: PropTypes.object.isRequired, - options: PropTypes.object, - typeChoices: PropTypes.array, - displayChoices: PropTypes.array, - enableTags: PropTypes.bool, - onSubmit: PropTypes.func -}; diff --git a/packages/react-formio/src/components/form/form.component.tsx b/packages/react-formio/src/components/form/form.component.tsx deleted file mode 100755 index fd734d40..00000000 --- a/packages/react-formio/src/components/form/form.component.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Components } from "formiojs"; -import AllComponents from "formiojs/components"; -import PropTypes from "prop-types"; -import React from "react"; - -import { useForm, UseFormHookProps } from "./useForm.hook"; - -Components.setComponents(AllComponents); - -export interface FormProps extends UseFormHookProps { - name?: string; - /** - * - */ - className?: string; -} - -export function Form(props: Partial>) { - const { element } = useForm(props); - - return
; -} - -Form.propTypes = { - name: PropTypes.string, - className: PropTypes.string, - /** - * - */ - src: PropTypes.string, - /** - * url to fetch form - */ - url: PropTypes.string, - /** - * Raw form object - */ - form: PropTypes.object, - /** - * Data submission - */ - submission: PropTypes.object, - /** - * Configuration option - */ - options: PropTypes.shape({ - readOnly: PropTypes.bool, - noAlerts: PropTypes.bool, - i18n: PropTypes.any, - template: PropTypes.string, - saveDraft: PropTypes.bool, - hooks: PropTypes.any - }), - onPrevPage: PropTypes.func, - onNextPage: PropTypes.func, - onCancel: PropTypes.func, - onChange: PropTypes.func, - onCustomEvent: PropTypes.func, - onComponentChange: PropTypes.func, - onSubmit: PropTypes.func, - onAsyncSubmit: PropTypes.func, - onSubmitDone: PropTypes.func, - onFormLoad: PropTypes.func, - onError: PropTypes.func, - onRender: PropTypes.func, - onAttach: PropTypes.func, - onBuild: PropTypes.func, - onFocus: PropTypes.func, - onBlur: PropTypes.func, - onInitialized: PropTypes.func, - onFormReady: PropTypes.func, - formioform: PropTypes.any -}; diff --git a/packages/react-formio/src/components/form/form.stories.tsx b/packages/react-formio/src/components/form/form.stories.tsx deleted file mode 100644 index 49d75c29..00000000 --- a/packages/react-formio/src/components/form/form.stories.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React, { useState } from "react"; - -import form from "../__fixtures__/form.fixture.json"; -import { Form } from "./form.component"; - -export default { - title: "ReactFormio/Form", - component: Form, - argTypes: { - form: { - control: { - type: "object" - } - }, - onPrevPage: { action: "onPrevPage" }, - onNextPage: { action: "onNextPage" }, - onCancel: { action: "onCancel" }, - onChange: { action: "onChange" }, - onCustomEvent: { action: "onCustomEvent" }, - onComponentChange: { action: "onComponentChange" }, - onSubmit: { action: "onSubmit" }, - onAsyncSubmit: { action: "onAsyncSubmit" }, - onSubmitDone: { action: "onSubmitDone" }, - onFormLoad: { action: "onFormLoad" }, - onError: { action: "onError" }, - onRender: { action: "onRender" }, - onAttach: { action: "onAttach" }, - onBuild: { action: "onBuild" }, - onFocus: { action: "onFocus" }, - onBlur: { action: "onBlur" }, - onInitialized: { action: "onInitialized" }, - onFormReady: { action: "onFormReady" } - } -}; - -function filter(args: any[]) { - return args.map((item) => { - if (item && item._form) { - return "FormioInstance"; - } - - if (item && item.component) { - return ["Component", item.component.type, item.component.key].filter(Boolean).join(":"); - } - - if (item && item.changed) { - return `${item.changed.component.key}(${item.changed.value})`; - } - - return item; - }); -} - -function wrap(args: any) { - return { - ...args, - onPrevPage: (...list: any[]) => { - return args.onPrevPage(...filter(list)); - }, - onNextPage: (...list: any[]) => { - return args.onNextPage(...filter(list)); - }, - onCancel: (...list: any[]) => { - return args.onCancel(...filter(list)); - }, - onChange: (...list: any[]) => { - return args.onChange(...filter(list)); - }, - onCustomEvent: (...list: any[]) => { - return args.onCustomEvent(...filter(list)); - }, - onComponentChange: (...list: any[]) => { - return args.onComponentChange(...filter(list)); - }, - onSubmit: (...list: any[]) => { - return args.onSubmit(...filter(list)); - }, - onAsyncSubmit: (...list: any[]) => { - return args.onAsyncSubmit(...filter(list)); - }, - onSubmitDone: (...list: any[]) => { - return args.onSubmitDone(...filter(list)); - }, - onFormLoad: (...list: any[]) => { - return args.onFormLoad(...filter(list)); - }, - onError: (...list: any[]) => { - return args.onError(...filter(list)); - }, - onRender: (...list: any[]) => { - return args.onRender(...filter(list)); - }, - onAttach: (...list: any[]) => { - return args.onAttach(...filter(list)); - }, - onBuild: (...list: any[]) => { - return args.onBuild(...filter(list)); - }, - onFocus: (...list: any[]) => { - return args.onFocus(...filter(list)); - }, - onBlur: (...list: any[]) => { - return args.onBlur(...filter(list)); - }, - onInitialized: (...list: any[]) => { - return args.onInitialized(...filter(list)); - }, - onFormReady: (...list: any[]) => { - return args.onFormReady(...filter(list)); - } - }; -} - -export const Sandbox = { - args: { - form - }, - render: (args: any) => { - return ; - } -}; - -export const TriggerError = { - render: (args: any) => { - const onAsyncSubmit = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error("server error")); - }, 500); - }).catch((error) => { - error.errors = { - message: "My custom message about this field", - type: "custom", - path: ["firstName"], - level: "error" - }; - throw error; - }); - }; - - return {...wrap(args)} form={args.form} onAsyncSubmit={onAsyncSubmit} />; - }, - args: { - form: { - type: "form", - display: "form", - tags: [], - components: [ - { - label: "First name", - widget: { - type: "input" - }, - errorLabel: "", - key: "firstName", - inputType: "text", - type: "textfield", - id: "eqb1o4r", - defaultValue: "" - }, - { - label: "Submit", - showValidations: false, - tableView: false, - key: "submit", - type: "button", - input: true - } - ] - } - } -}; - -export const ReadOnly = { - render: (args: any) => { - return ( - - ); - }, - - args: { - readonly: true, - form - } -}; - -export const OnChange = { - render: function Render(args: any) { - const [data, setForm] = useState(() => {}); - const props = wrap(args); - - return ( - { - setForm(changedSubmission.data); - }} - /> - ); - }, - - args: { - form: { - type: "form", - display: "form", - tags: [], - components: [ - { - label: "First name", - widget: { - type: "input" - }, - errorLabel: "", - key: "firstName", - inputType: "text", - type: "textfield", - id: "eqb1o4r", - defaultValue: "", - validate: { - required: true - } - }, - { - label: "Last name", - widget: { - type: "input" - }, - errorLabel: "", - key: "lastName", - inputType: "text", - type: "textfield", - id: "eqb1o4r", - defaultValue: "", - validate: { - required: true - } - } - ] - } - } -}; diff --git a/packages/react-formio/src/components/form/useForm.hook.ts b/packages/react-formio/src/components/form/useForm.hook.ts deleted file mode 100644 index d2f4b2a4..00000000 --- a/packages/react-formio/src/components/form/useForm.hook.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { ExtendedComponentSchema, Form } from "formiojs"; -import cloneDeep from "lodash/cloneDeep"; -import isEqual from "lodash/isEqual"; -import { useEffect, useRef } from "react"; - -import { FormOptions, FormSchema, Submission } from "../../interfaces"; - -export interface ChangedSubmission extends Submission { - changed: { - component: ExtendedComponentSchema; - instance: any; - value: any; - } & Record; - isValid: boolean; -} - -export interface FormPageChangeProps { - page: number; - submission: Submission; -} - -export interface UseFormHookProps extends Record { - src?: string; - /** - * url to fetch form - */ - url?: string; - /** - * Raw form object - */ - form?: Partial; - /** - * Configuration option - */ - options?: FormOptions; - /** - * Data submission - */ - submission?: Submission; - - /// events - onPrevPage?: (obj: FormPageChangeProps) => void; - onNextPage?: (obj: FormPageChangeProps) => void; - onCancel?: Function; - onChange?: (submission: ChangedSubmission) => void; - onCustomEvent?: (obj: { type: string; event: string; component: ExtendedComponentSchema; data: any }) => void; - onComponentChange?: (component: ExtendedComponentSchema) => void; - onSubmit?: (submission: Submission) => void; - onAsyncSubmit?: (submission: Submission) => Promise; - onSubmitDone?: (submission: Submission) => void; - onFormLoad?: Function; - onError?: (errors: any) => void; - onRender?: () => void; - onAttach?: Function; - onBuild?: Function; - onFocus?: Function; - onBlur?: Function; - onInitialized?: Function; - onFormReady?: (formio: any) => void; -} - -function useEvent(event: string, callback: any, events: Map) { - useEffect(() => { - if (callback) { - events.set(event, callback); - } - }, [callback, event, events]); -} - -function useEvents(funcs: any) { - const events = useRef>(new Map()); - - const hasEvent = (event: string) => { - return funcs.hasOwnProperty(event) && typeof funcs[event] === "function"; - }; - - const emit = (event: string, ...args: any[]) => { - if (hasEvent(event)) { - const fn = events.current.has(event) ? events.current.get(event) : funcs[event]; - return fn(...args); - } - }; - - useEvent("onBlur", funcs["onBlur"], events.current); - useEvent("onPrevPage", funcs["onPrevPage"], events.current); - useEvent("onNextPage", funcs["onNextPage"], events.current); - useEvent("onCancel", funcs["onCancel"], events.current); - useEvent("onChange", funcs["onChange"], events.current); - useEvent("onCustomEvent", funcs["onCustomEvent"], events.current); - useEvent("onComponentChange", funcs["onComponentChange"], events.current); - useEvent("onSubmit", funcs["onSubmit"], events.current); - useEvent("onAsyncSubmit", funcs["onAsyncSubmit"], events.current); - useEvent("onSubmitDone", funcs["onSubmitDone"], events.current); - useEvent("onFormLoad", funcs["onFormLoad"], events.current); - useEvent("onError", funcs["onError"], events.current); - useEvent("onRender", funcs["onRender"], events.current); - useEvent("onAttach", funcs["onAttach"], events.current); - useEvent("onBuild", funcs["onBuild"], events.current); - useEvent("onFocus", funcs["onFocus"], events.current); - useEvent("onBlur", funcs["onBlur"], events.current); - useEvent("onInitialized", funcs["onInitialized"], events.current); - - return { events, emit, hasEvent }; -} - -export function useForm(props: UseFormHookProps) { - const { src, form, options = {}, submission, url, ...funcs } = props; - const element = useRef(); - const isLoaded = useRef(); - const instance = useRef(); - const { emit, hasEvent } = useEvents(funcs); - - async function customValidation(submission: Submission, callback: (err: Error | null) => void) { - if (hasEvent("onAsyncSubmit")) { - try { - await emit("onAsyncSubmit", submission, instance.current); - } catch (err: any) { - callback(err?.errors || err); - } - } else { - callback(null); - } - } - - const createWebForm = (srcOrForm: any, options: any) => { - options = Object.assign({}, options); - srcOrForm = typeof srcOrForm === "string" ? srcOrForm : cloneDeep(srcOrForm); - - if (!instance.current) { - isLoaded.current = false; - options.hooks = { - ...(options.hooks || {}), - customValidation: options?.hooks?.customValidation || customValidation - }; - - instance.current = new Form(element.current, srcOrForm, options); - - instance.current.onAny((event: string, ...args: any[]): void => { - if (!instance.current) { - return; - } - - if (event.startsWith("formio.")) { - const eventName = `on${event.charAt(7).toUpperCase()}${event.slice(8)}`; - - if (eventName === "onChange" && !args[0].changed) { - return; - } - - emit(eventName, ...args, instance.current); - } - }); - - instance.current.ready.then((formio: any) => { - submission && (formio.submission = cloneDeep(submission)); - - if (props.onFormReady) { - props.onFormReady(formio); - } - - isLoaded.current = true; - }); - } - - return instance.current; - }; - - useEffect(() => { - if (instance.current) { - instance.current.ready.then((formio: any) => { - if (isEqual(formio.submission.data, submission?.data)) { - return; - } - - submission && (formio.submission = cloneDeep(submission)); - }); - } - }, [submission]); - - useEffect(() => { - if (form && instance.current) { - instance.current.ready.then((formio: any) => { - formio.form = form; - if (url) { - formio.url = url; - } - }); - } - }, [form, url]); - - useEffect(() => { - if (src) { - if (instance.current) { - isLoaded.current = false; - (instance.current as any).destroy(true); - } - - createWebForm(src, options); - } - }, [src]); - - useEffect(() => { - if (form) { - createWebForm(form, options); - } - - return () => { - isLoaded.current = false; - instance.current && (instance.current as any).destroy(true); - }; - }, []); - - return { - element - }; -} diff --git a/packages/react-formio/src/components/index.ts b/packages/react-formio/src/components/index.ts deleted file mode 100644 index 21b9b23f..00000000 --- a/packages/react-formio/src/components/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -export * from "./actions-table/actionsTable.component"; -export * from "./alert/alert.component"; -export * from "./card/card.component"; -export * from "./form/form.component"; -export * from "./form/useForm.hook"; -export * from "./form-access/formAccess.component"; -export * from "./form-action/formAction.component"; -export * from "./form-builder/formBuilder.component"; -export * from "./form-control/formControl.component"; -export * from "./form-edit/formCtas.component"; -export * from "./form-edit/formEdit.component"; -export * from "./form-edit/formParameters.component"; -export * from "./form-edit/useFormEdit.hook"; -export * from "./form-settings/formSettings.component"; -export * from "./forms-table/formsTable.component"; -export * from "./input-tags/inputTags.component"; -export * from "./input-text/inputText.component"; -export * from "./loader/loader.component"; -export * from "./modal/modal.component"; -export * from "./modal/removeModal.component"; -export * from "./pagination/pagination.component"; -export * from "./react-component/reactComponent.component"; -export * from "./select/select.component"; -export * from "./submissions-table/submissionsTable.component"; -export * from "./table"; -export * from "./tabs/tabs.component"; diff --git a/packages/react-formio/src/components/input-tags/inputTags.component.tsx b/packages/react-formio/src/components/input-tags/inputTags.component.tsx deleted file mode 100644 index 2bdf5503..00000000 --- a/packages/react-formio/src/components/input-tags/inputTags.component.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import Choices from "@formio/choices.js"; -import uniq from "lodash/uniq"; -import PropTypes from "prop-types"; -import React, { useEffect, useRef } from "react"; - -import { FormControl, FormControlProps } from "../form-control/formControl.component"; - -export interface InputTagsProps extends Omit { - value?: T; - onChange?: (name: string, value: T) => void; - placeholder?: string; - - [key: string]: any; -} - -export function InputTags({ name, value = [], label, onChange, required, description, prefix, suffix, ...props }: InputTagsProps) { - const ref: any = useRef(); - - useEffect(() => { - const instance = new Choices(ref.current, { - delimiter: ",", - editItems: true, - removeItemButton: true - }); - - instance.setValue([].concat(value, [])); - - instance.passedElement.element.addEventListener("addItem", (event: any) => { - onChange && onChange(name, uniq(value.concat(event.detail.value))); - }); - - instance.passedElement.element.addEventListener("removeItem", (event: any) => { - onChange && - onChange( - name, - value.filter((v: string) => v !== event.detail.value) - ); - }); - - return () => { - instance.destroy(); - }; - }, []); - - return ( - - - - ); -} - -InputTags.propTypes = { - label: PropTypes.string, - name: PropTypes.string.isRequired, - value: PropTypes.array, - required: PropTypes.bool, - onChange: PropTypes.func -}; diff --git a/packages/react-formio/src/components/input-tags/inputTags.stories.tsx b/packages/react-formio/src/components/input-tags/inputTags.stories.tsx deleted file mode 100644 index d2319119..00000000 --- a/packages/react-formio/src/components/input-tags/inputTags.stories.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { useState } from "react"; - -import { iconClass } from "../../utils/iconClass"; -import { InputTags } from "./inputTags.component"; - -const useValue = (args: any) => { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - -export default { - title: "ReactFormio/InputTags", - component: InputTags, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - value: { - control: { - type: "object" - } - }, - size: { - control: { - type: "select", - options: ["sm", "normal"] - } - }, - placeholder: { - control: { - type: "text" - } - }, - choices: { - control: { - type: "object" - } - }, - description: { - control: { - type: "text" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - name: "name", - label: "Label", - value: ["test"], - size: "", - placeholder: "Placeholder" -}; - -export const WithPrefix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithPrefix.args = { - label: "Label", - value: [], - name: "name", - size: "", - placeholder: "Placeholder" -}; - -export const WithSuffix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithSuffix.args = { - label: "Label", - value: [], - name: "name", - size: "", - placeholder: "Placeholder" -}; diff --git a/packages/react-formio/src/components/input-text/inputText.component.tsx b/packages/react-formio/src/components/input-text/inputText.component.tsx deleted file mode 100644 index a6ccd7f3..00000000 --- a/packages/react-formio/src/components/input-text/inputText.component.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import classnames from "classnames"; -import PropTypes from "prop-types"; -import React, { useEffect, useMemo, useState } from "react"; - -import { callLast } from "../../utils/callLast"; -import { getEventValue } from "../../utils/getEventValue"; -import { FormControl, FormControlProps } from "../form-control/formControl.component"; - -export interface InputTextProps extends FormControlProps { - type?: string; - value?: T; - /** - * The input size - */ - size?: string; - onChange?: (name: string, value: T) => void; - placeholder?: string; - - [key: string]: any; -} - -export function InputText({ - name, - value, - label, - onChange, - required, - size, - type, - prefix, - suffix, - description, - className, - placeholder, - ...props -}: InputTextProps) { - const [localValue, setValue] = useState(value); - - const change = useMemo(() => onChange && callLast(onChange, 300), [onChange]); - - useEffect(() => { - setValue(value); - }, [value]); - - return ( - - { - const value = getEventValue(event); - setValue(value); - - return change && change(name, value); - }} - /> - - ); -} - -InputText.propTypes = { - label: PropTypes.string, - type: PropTypes.string, - name: PropTypes.string.isRequired, - value: PropTypes.any, - size: PropTypes.string, - required: PropTypes.bool, - onChange: PropTypes.func, - prefix: PropTypes.any, - suffix: PropTypes.any -}; diff --git a/packages/react-formio/src/components/input-text/inputText.stories.tsx b/packages/react-formio/src/components/input-text/inputText.stories.tsx deleted file mode 100644 index 1870b423..00000000 --- a/packages/react-formio/src/components/input-text/inputText.stories.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useState } from "react"; - -import { iconClass } from "../../utils/iconClass"; -import { InputText } from "./inputText.component"; - -const useValue = (args: any) => { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - -export default { - title: "ReactFormio/InputText", - component: InputText, - argTypes: { - label: { - control: { - type: "text" - } - }, - type: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - value: { - control: { - type: "text" - } - }, - size: { - control: { - type: "select", - options: ["sm", "normal"] - } - }, - placeholder: { - control: { - type: "text" - } - }, - choices: { - control: { - type: "object" - } - }, - description: { - control: { - type: "text" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - name: "name", - label: "Label", - value: "", - size: "", - placeholder: "Placeholder" -}; - -export const WithPrefix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithPrefix.args = { - label: "Label", - value: "", - size: "", - placeholder: "Placeholder" -}; - -export const WithSuffix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithSuffix.args = { - label: "Label", - value: "", - size: "", - placeholder: "Placeholder" -}; - -export const TypeNumber = (args: any) => { - return } {...useValue(args)} />; -}; - -TypeNumber.args = { - label: "Label", - type: "number", - value: "", - size: "", - placeholder: "Placeholder", - description: "Use dollars!" -}; - -export const Sizing = (args: any) => { - return } {...useValue(args)} />; -}; - -Sizing.args = { - label: "Label", - type: "number", - value: "", - size: "sm", - placeholder: "Placeholder", - description: "Use dollars!" -}; diff --git a/packages/react-formio/src/components/loader/loader.stories.tsx b/packages/react-formio/src/components/loader/loader.stories.tsx deleted file mode 100644 index 99d3c20f..00000000 --- a/packages/react-formio/src/components/loader/loader.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -import { Loader } from "./loader.component"; - -export default { - title: "ReactFormio/Loader", - component: Loader, - argTypes: {}, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - isActive: true -}; diff --git a/packages/react-formio/src/components/modal/modal.component.spec.tsx b/packages/react-formio/src/components/modal/modal.component.spec.tsx deleted file mode 100644 index 6c9f748b..00000000 --- a/packages/react-formio/src/components/modal/modal.component.spec.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import "@testing-library/jest-dom/extend-expect"; - -import { fireEvent, render, screen } from "@testing-library/react"; -import React from "react"; - -import { WithFooter, WithTitle } from "./modal.stories"; - -describe("Modal", () => { - describe("WithTitle", () => { - it("should display the modal when we click on the button", async () => { - const onClose = jest.fn(); - - render(); - - expect(screen.queryByTestId("modalTitle")).toBeFalsy(); - expect(screen.queryByTestId("modalBody")).toBeFalsy(); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - - fireEvent.click(screen.getByRole("button", { name: "Open modal" })); - - await screen.findByTestId("modalTitle"); - - expect(screen.getByTestId("modalTitle")).toBeTruthy(); - expect(screen.getByTestId("modalTitle")).toHaveTextContent("Modal title"); - expect(screen.getByTestId("modalBody")).toBeTruthy(); - expect(screen.getByTestId("modalBody")).toHaveTextContent("Hello body"); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - - fireEvent.click(screen.getByTestId("closeModal")); - - expect(screen.queryByTestId("modalTitle")).toBeFalsy(); - expect(screen.queryByTestId("modalBody")).toBeFalsy(); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - expect(onClose).toHaveBeenCalledWith(); - }); - }); - - describe("WithFooter", () => { - it("should display the modal when we click on the button", async () => { - render(); - - expect(screen.queryByTestId("modalTitle")).toBeFalsy(); - expect(screen.queryByTestId("modalBody")).toBeFalsy(); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - - fireEvent.click(screen.getByRole("button", { name: "Open modal" })); - - await screen.findByTestId("modalTitle"); - - expect(screen.getByTestId("modalTitle")).toBeTruthy(); - expect(screen.getByTestId("modalTitle")).toHaveTextContent("Modal title"); - expect(screen.getByTestId("modalBody")).toBeTruthy(); - expect(screen.getByTestId("modalBody")).toHaveTextContent("Hello body"); - expect(screen.getByTestId("modalFooter")).toBeTruthy(); - - fireEvent.click(screen.getByTestId("customCloseModal")); - - expect(screen.queryByTestId("modalTitle")).toBeFalsy(); - expect(screen.queryByTestId("modalBody")).toBeFalsy(); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - }); - it("should call the onSubmit listener", async () => { - const onSubmit = jest.fn(); - - render(); - - fireEvent.click(screen.getByRole("button", { name: "Open modal" })); - - await screen.findByTestId("modalTitle"); - - fireEvent.click(screen.getByTestId("customSubmitModal")); - - expect(onSubmit).toHaveBeenCalled(); - expect(screen.queryByTestId("modalTitle")).toBeFalsy(); - expect(screen.queryByTestId("modalBody")).toBeFalsy(); - expect(screen.queryByTestId("modalFooter")).toBeFalsy(); - }); - }); -}); diff --git a/packages/react-formio/src/components/modal/modal.stories.tsx b/packages/react-formio/src/components/modal/modal.stories.tsx deleted file mode 100644 index a6dbb5cc..00000000 --- a/packages/react-formio/src/components/modal/modal.stories.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import React from "react"; - -import { Modal, ModalProps, useModal } from "./modal.component"; -import { RemoveModal, RemoveModalProps } from "./removeModal.component"; - -export default { - title: "ReactFormio/Modal", - component: Modal, - argTypes: { - onSubmit: { - title: { - control: { - type: "text" - } - }, - control: { - action: "onSubmit" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: ModalProps) => { - const modal = useModal(); - - return ( -
-
- -
- -
- Hello body -
-
-
- ); -}; - -Sandbox.args = {}; - -export const WithTitle = (args: ModalProps) => { - const modal = useModal(); - - return ( -
-
- -
- -
- Hello body -
-
-
- ); -}; - -WithTitle.args = { - title: "Modal title" -}; - -export const WithFooter = (args: ModalProps) => { - const modal = useModal(); - - function ModalFooter({ closeModal, onSubmit }: any) { - return ( -
- - - -
- ); - } - - return ( -
-
- -
- -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
- Hello body -
-
-
-
- ); -}; - -WithFooter.args = { - title: "Modal title" -}; - -export const WithRemoveModal = (args: RemoveModalProps) => { - const modal = useModal(); - - return ( -
-
- -
- f} - show={modal.show} - onSubmit={modal.closeModal} - onClose={modal.closeModal} - closeModal={modal.closeModal} - /> -
- ); -}; - -WithRemoveModal.args = { - valueToCompare: "value", - itemType: "form" -}; diff --git a/packages/react-formio/src/components/pagination/pagination.stories.tsx b/packages/react-formio/src/components/pagination/pagination.stories.tsx deleted file mode 100644 index 20e64385..00000000 --- a/packages/react-formio/src/components/pagination/pagination.stories.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React, { useEffect, useState } from "react"; - -import { Pagination } from "./pagination.component"; - -export default { - title: "ReactFormio/Pagination", - component: Pagination, - - parameters: {} -}; - -export const Sandbox = (args: any) => { - const [currentPageIndex, setPageIndex] = useState(args.pageIndex); - - useEffect(() => { - args.gotoPage && args.gotoPage(currentPageIndex); - }, [currentPageIndex]); - - return ( -
- -
- ); -}; - -Sandbox.args = { - pageSizes: [10, 25, 50, 100], - pageCount: 50, - pageIndex: 1 - // gotoPage, - // canPreviousPage, - // previousPage, - // nextPage, - // canNextPage, - // pageCount, - // pageIndex, - // pageOptions, - // pageSize, - // setPageSize, -}; diff --git a/packages/react-formio/src/components/react-component/reactComponent.component.tsx b/packages/react-formio/src/components/react-component/reactComponent.component.tsx deleted file mode 100644 index eea142b6..00000000 --- a/packages/react-formio/src/components/react-component/reactComponent.component.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import { Components, ComponentSchema } from "formiojs"; -import ReactDOM from "react-dom"; - -import { Submission } from "../../interfaces/Submission"; - -export class ReactComponent extends Components.components.field { - public reactInstance: any; - public shouldSetValue?: boolean; - private dataForSetting?: Data; - - /** - * This is the first phase of component building where the component is instantiated. - * - * @param component - The component definition created from the settings form. - * @param options - Any options passed into the renderer. - * @param data - The submission data where this component's data exists. - */ - constructor(component: ComponentSchema, options: any, data: Submission) { - super(component, options, data); - } - - get $reactNode() { - return (this.refs as any)[`react-${this.id}`]; - } - - /** - * This method is called any time the component needs to be rebuilt. It is most frequently used to listen to other - * components using the this.on() function. - */ - init() { - return super.init(); - } - - /** - * This method is called before the component is going to be destroyed, which is when the component instance is - * destroyed. This is different from detach which is when the component instance still exists but the dom instance is - * removed. - */ - destroy() { - return super.destroy(); - } - - /** - * The second phase of component building where the component is rendered as an HTML string. - * - * @returns {string} - The return is the full string of the component - */ - render() { - // For react components, we simply render as a div which will become the react instance. - // By calling super.render(string) it will wrap the component with the needed wrappers to make it a full component. - return super.render(`
`); - } - - /** - * The third phase of component building where the component has been attached to the DOM as 'element' and is ready - * to have its javascript events attached. - * - * @param element - * @returns {Promise} - Return a promise that resolves when the attach is complete. - */ - async attach(element: any) { - super.attach(element); - - // The loadRefs function will find all dom elements that have the "ref" setting that match the object property. - // It can load a single element or multiple elements with the same ref. - this.loadRefs(element, { - [`react-${this.id}`]: "single" - }); - - // @ts-ignore - if (this.refs[`react-${this.id}`]) { - // @ts-ignore - this.reactInstance = this.attachReact(this.refs[`react-${this.id}`]); - - if (this.shouldSetValue) { - this.setValue(this.dataForSetting); - this.updateValue(this.dataForSetting); - } - } - } - - /** - * The fourth phase of component building where the component is being removed from the page. This could be a redraw - * or it is being removed from the form. - */ - detach() { - // @ts-ignore - if (this.refs[`react-${this.id}`]) { - // @ts-ignore - this.detachReact(this.refs[`react-${this.id}`]); - } - super.detach(); - } - - /** - * Override this function to render a react component. - */ - renderReact(): any { - return null; - } - - /** - * Override this function to insert your custom component. - * - * @param element - */ - - attachReact(element?: any) { - // eslint-disable-next-line react/no-render-return-value,react/no-deprecated - return ReactDOM.render(this.renderReact(), element); - } - - /** - * Override this function. - */ - - detachReact(element?: any) { - if (element) { - // eslint-disable-next-line react/no-deprecated - ReactDOM.unmountComponentAtNode(element); - } - } - - /** - * Something external has set a value and our component needs to be updated to reflect that. For example, loading a submission. - * - * @param value - * @param flags - */ - setValue(value: any) { - if (this.reactInstance) { - this.reactInstance.setState({ - value: value - }); - this.shouldSetValue = false; - } else { - this.shouldSetValue = true; - this.dataForSetting = value; - } - - return false; - } - - /** - * The user has changed the value in the component and the value needs to be updated on the main submission object and other components notified of a change event. - * - * @param value - * @param flags - */ - updateValue = (value?: Data, flags?: Record) => { - flags = flags || {}; - - const newValue = value === undefined || value === null ? this.getValue() : value; - - const changed = newValue !== undefined ? this.hasChanged(newValue, this.dataValue) : false; - - this.dataValue = Array.isArray(newValue) ? [...newValue] : newValue; - - this.updateOnChange(flags, changed); - return changed; - }; - - /** - * Get the current value of the component. Should return the value set in the react component. - * - * @returns {*} - */ - getValue(): Data { - if (this.reactInstance) { - return this.reactInstance.state.value; - } - return this.defaultValue; - } - - /** - * Override normal validation check to insert custom validation in react component. - * - * @param data - * @param dirty - * @param rowData - * @returns {boolean} - */ - checkValidity(data: Data, dirty: boolean, rowData: any) { - const valid = super.checkValidity(data, dirty, rowData); - - if (!valid) { - return false; - } - - return this.validate(data, dirty, rowData); - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - validate(data: Data, dirty: boolean, rowData: any) { - return true; - } -} diff --git a/packages/react-formio/src/components/select/select.component.spec.tsx b/packages/react-formio/src/components/select/select.component.spec.tsx deleted file mode 100644 index a8b2983f..00000000 --- a/packages/react-formio/src/components/select/select.component.spec.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import React from "react"; - -import { Choicesjs, Sandbox } from "./select.stories"; - -describe("Select", () => { - describe("select component Sandbox version", () => { - it("should render the select component", () => { - render(); - - expect(screen.getByTestId("select_test-sandbox")).toBeInTheDocument(); - }); - - it("should render the select component with a different size", () => { - render(); - const select = screen.getByTestId("select_test-sandbox"); - expect(select).toBeInTheDocument(); - expect(select).toHaveClass("form-control-small"); - }); - - it("should render select options with 'Placeholder test' as first value", () => { - const choices = [ - { label: "test1", value: "value1" }, - { label: "test2", value: "value2" } - ]; - - const placeHolderTest = "Placeholder test"; - - render(); - - expect(screen.getByRole("option", { name: "Placeholder test" })).toBeInTheDocument(); - expect(screen.getByRole("option", { name: "test1" })).toBeInTheDocument(); - expect(screen.getByRole("option", { name: "test2" })).toBeInTheDocument(); - }); - - it("should have Placeholder label as selected option by default", () => { - const choices = [ - { label: "test1", value: "value1" }, - { label: "test2", value: "value2" } - ]; - const placeHolderTest = "Placeholder test"; - - render(); - const option = screen.getByRole("option", { name: placeHolderTest }) as HTMLOptionElement; - - expect(option.selected).toBeTruthy(); - }); - - it("should change the value of the selected option when you click on another choice", () => { - const choices = [ - { label: "test1", value: "value1" }, - { label: "test2", value: "value2" } - ]; - const placeHolderTest = "Placeholder test"; - const onChange = jest.fn(); - - render(); - - fireEvent.change(screen.getByTestId("select_test-sandbox"), { - target: { value: "value1" } - }); - - const option = screen.getByRole("option", { name: "test1" }) as HTMLOptionElement; - - expect(option.selected).toBeTruthy(); - expect(onChange).toHaveBeenCalledWith("test-sandbox", "value1"); - }); - }); - - describe("select component Choicesjs version", () => { - it("should render select options with 'test1' as first value", () => { - const choices = [ - { label: "test1", value: "value1" }, - { label: "test2", value: "value2" } - ]; - const placeHolderTest = "Placeholder test"; - - render( - - ); - - expect(screen.getByRole("option", { name: "test1" })).toBeInTheDocument(); - }); - }); -}); diff --git a/packages/react-formio/src/components/select/select.component.tsx b/packages/react-formio/src/components/select/select.component.tsx deleted file mode 100644 index 120a4a6f..00000000 --- a/packages/react-formio/src/components/select/select.component.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import Choices from "@formio/choices.js"; -import classnames from "classnames"; -import React, { HTMLAttributes, ReactElement, useEffect, useRef } from "react"; - -import { getEventValue } from "../../utils/getEventValue"; -import { FormControl, FormControlProps } from "../form-control/formControl.component"; - -export interface SelectProps extends FormControlProps, Omit, "onChange" | "prefix"> { - size?: string; - placeholder?: string; - choices: { label: string; value: Data }[]; - layout?: "html5" | "choicesjs"; - disabled?: boolean; - multiple?: boolean; -} - -export function Select({ - name, - label, - size, - onChange, - required, - value, - choices, - description, - placeholder, - prefix, - suffix, - multiple, - layout, - ...props -}: SelectProps): ReactElement { - const ref = useRef(null); - - useEffect(() => { - let instance: any; - - if (layout === "choicesjs") { - instance = new Choices(ref.current as unknown as HTMLInputElement, { - removeItemButton: true, - placeholderValue: placeholder - }); - } - - return () => { - instance && instance.destroy(); - }; - }, []); - - choices = - layout === "choicesjs" || multiple || !placeholder - ? choices - : ([ - { - label: placeholder, - value: "" - }, - ...choices - ] as any[]); - - return ( - - {} - - - ); -} diff --git a/packages/react-formio/src/components/select/select.stories.tsx b/packages/react-formio/src/components/select/select.stories.tsx deleted file mode 100644 index d628419a..00000000 --- a/packages/react-formio/src/components/select/select.stories.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { useState } from "react"; - -import { iconClass } from "../../utils/iconClass"; -import { Select } from "./select.component"; - -const choices = [ - { label: "label1", value: "value1" }, - { label: "label2", value: "value2" } -]; - -const useValue = (args: any) => { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - -export default { - title: "ReactFormio/Select", - component: Select, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - value: { - control: { - type: "select", - options: choices - } - }, - size: { - control: { - type: "select", - options: ["sm", "normal"] - } - }, - layout: { - control: { - type: "select", - options: ["html5", "choicesjs"] - } - }, - placeholder: { - control: { - type: "text" - } - }, - choices: { - control: { - type: "object" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Choicesjs.args = { - label: "Label", - value: "", - size: "", - layout: "choicesjs", - placeholder: "Placeholder", - choices -}; - -export const ChoicesjsPrefix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithPrefix.args = { - label: "Label", - value: "", - size: "", - placeholder: "Placeholder", - choices -}; - -export const WithSuffix = (args: any) => { - return ; -}; - -TypeMultiple.args = { - label: "Label", - name: "name", - value: [], - size: "", - multiple: true, - placeholder: "Placeholder", - description: "Select multiple values", - choices -}; - -export const ChoicesjsMultiple = (args: any) => { - return } {...useValue(args)} />; -}; - -Sizing.args = { - label: "Label", - value: "", - size: "sm", - placeholder: "Placeholder", - description: "Use dollars!", - choices -}; diff --git a/packages/react-formio/src/components/submissions-table/submissionsTable.component.tsx b/packages/react-formio/src/components/submissions-table/submissionsTable.component.tsx deleted file mode 100644 index e84cba95..00000000 --- a/packages/react-formio/src/components/submissions-table/submissionsTable.component.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; - -import { FormSchema, Submission } from "../../interfaces"; -import { TableProps } from "../table/hooks/useCustomTable.hook"; -import { Table } from "../table/table.component"; -import { mapFormToColumns } from "../table/utils/mapFormToColumns"; - -export type SubmissionsTableProps = Omit, "columns"> & { - form?: FormSchema; -}; - -export function SubmissionsTable({ form, ...props }: SubmissionsTableProps) { - const columns: any[] | undefined = form && mapFormToColumns(form); - - return ; -} diff --git a/packages/react-formio/src/components/table/filters/sliderColumnFilter.component.tsx b/packages/react-formio/src/components/table/filters/sliderColumnFilter.component.tsx deleted file mode 100644 index b574402d..00000000 --- a/packages/react-formio/src/components/table/filters/sliderColumnFilter.component.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import { FilterProps } from "react-table"; - -export function SliderColumnFilter = {}>({ - column: { filterValue, setFilter, preFilteredRows, id } -}: FilterProps) { - const [min, max] = React.useMemo(() => { - let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0; - let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0; - preFilteredRows.forEach((row) => { - min = Math.min(row?.values[id], min); - max = Math.max(row?.values[id], max); - }); - return [min, max]; - }, [id, preFilteredRows]); - - return ( - <> - { - setFilter(parseInt(e.target.value, 10)); - }} - /> - - - ); -} diff --git a/packages/react-formio/src/components/table/index.ts b/packages/react-formio/src/components/table/index.ts deleted file mode 100644 index 07ac65e8..00000000 --- a/packages/react-formio/src/components/table/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -export * from "./components/defaultArrowSort.component"; -export * from "./components/defaultCell.component"; -export * from "./components/defaultCellHeader.component"; -export * from "./components/defaultCellHeader.component"; -export * from "./components/defaultCellOperations.component"; -export * from "./components/defaultOperationButton.component"; -export * from "./filters/defaultColumnFilter.component"; -export * from "./filters/selectColumnFilter.component"; -export * from "./filters/sliderColumnFilter.component"; -export * from "./hooks/useCustomTable.hook"; -export * from "./hooks/useOperations.hook"; -export * from "./table.component"; -export * from "./utils/getPageNumbers"; -export * from "./utils/mapFormToColumns"; -export * from "./utils/swapElements"; diff --git a/packages/react-formio/src/components/tabs/tabs.component.stories.tsx b/packages/react-formio/src/components/tabs/tabs.component.stories.tsx deleted file mode 100644 index f0168735..00000000 --- a/packages/react-formio/src/components/tabs/tabs.component.stories.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import React, { useState } from "react"; - -import { Tabs } from "./tabs.component"; - -const useTabs = (args: any) => { - const [current, onClick] = useState(args.value); - - return { - ...args, - current, - onClick - }; -}; - -export default { - title: "ReactFormio/Tabs", - component: Tabs, - argTypes: {}, - parameters: {} -}; - -export const Sandbox = (args: any) => { - const tabs = useTabs(args); - - return ( -
- f}> -
{tabs?.current?.action}
-
-
- ); -}; - -Sandbox.args = { - items: [ - { - action: "back", - exact: true, - icon: "chevron-left", - back: true - }, - { - action: "edit", - exact: true, - icon: "edit", - label: "Edit" - }, - { - action: "submissions", - exact: false, - icon: "data", - label: "Data" - }, - { - action: "preview", - exact: true, - icon: "test-tube", - label: "Preview" - }, - { - action: "actions", - exact: false, - icon: "paper-plane", - label: "Actions" - }, - { - action: "access", - exact: true, - icon: "lock", - label: "Access" - }, - { - action: "export", - exact: true, - icon: "download", - label: "Export" - }, - { - action: "delete", - exact: true, - icon: "trash", - label: "Delete", - roles: ["administrator", "owner"] - } - ] -}; - -function AddButton({ onCreate }: any) { - return ( -
- -
- ); -} - -function HeaderChildren() { - return
test
; -} - -export const WithCloseable = (args: any) => { - args.value = args.value === undefined ? 0 : args.value; - const tabs = useTabs(args); - - return ( -
- f} AddButton={AddButton} HeaderChildren={HeaderChildren}> -
{tabs?.current?.action}
-
-
- ); -}; - -WithCloseable.args = { - reverse: true, - items: [ - { - exact: true, - action: 0, - label: "Test (0)" - }, - { - exact: true, - action: 1, - label: "Test (1)" - } - ] -}; diff --git a/packages/react-formio/src/index.ts b/packages/react-formio/src/index.ts index a7f13584..3741b252 100644 --- a/packages/react-formio/src/index.ts +++ b/packages/react-formio/src/index.ts @@ -2,6 +2,7 @@ import Webform from "formiojs/Webform"; import WebformBuilder from "formiojs/WebformBuilder"; import Wizard from "formiojs/Wizard"; import WizardBuilder from "formiojs/WizardBuilder"; + export { Webform, WebformBuilder, @@ -10,11 +11,5 @@ export { // editFormUtils, }; -export * from "./components"; -export * from "./hooks/useTooltip"; export * from "./interfaces"; -export * from "./utils/callLast"; -export * from "./utils/iconClass"; -export * from "./utils/mapPagination"; -export * from "./utils/stopPropagationWrapper"; export { Components, Formio, Templates, Utils } from "formiojs"; diff --git a/packages/react-formio/src/interfaces/ActionSchema.ts b/packages/react-formio/src/interfaces/ActionSchema.ts deleted file mode 100644 index 3c034bb1..00000000 --- a/packages/react-formio/src/interfaces/ActionSchema.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { FormSchema } from "./FormSchema"; - -export interface ActionDefaultsSchema { - handler: string[]; - method: string[]; - priority: number; - name: string; - title: string; -} - -export interface ActionInfoSchema extends Record { - name: string; - title: string; - description: string; - priority: number; - defaults: ActionDefaultsSchema; -} - -export interface ActionSchema extends ActionInfoSchema { - _id?: string; - settingsForm: Partial; - access?: { - handler: boolean; - method: boolean; - }; -} diff --git a/packages/react-formio/src/interfaces/ActionType.ts b/packages/react-formio/src/interfaces/ActionType.ts new file mode 100644 index 00000000..cb3fd928 --- /dev/null +++ b/packages/react-formio/src/interfaces/ActionType.ts @@ -0,0 +1,26 @@ +import { FormType } from "./FormType"; + +export type ActionDefaultsType = { + handler: string[]; + method: string[]; + priority: number; + name: string; + title: string; +}; + +export interface ActionInfoType extends Record { + name: string; + title: string; + description: string; + priority: number; + defaults: ActionDefaultsType; +} + +export interface ActionType extends ActionInfoType { + _id?: string; + settingsForm: Partial; + access?: { + handler: boolean; + method: boolean; + }; +} diff --git a/packages/react-formio/src/interfaces/ComponentType.ts b/packages/react-formio/src/interfaces/ComponentType.ts new file mode 100644 index 00000000..b6ebab58 --- /dev/null +++ b/packages/react-formio/src/interfaces/ComponentType.ts @@ -0,0 +1,3 @@ +import { ExtendedComponentSchema } from "formiojs"; + +export type ComponentType = ExtendedComponentSchema; diff --git a/packages/react-formio/src/interfaces/FormOptions.ts b/packages/react-formio/src/interfaces/FormOptions.ts index da7079b4..a8f5bcde 100644 --- a/packages/react-formio/src/interfaces/FormOptions.ts +++ b/packages/react-formio/src/interfaces/FormOptions.ts @@ -1,4 +1,4 @@ -import { EventEmitter2 } from "eventemitter2"; +import type { EventEmitter2 } from "eventemitter2"; export interface FormOptions { iconset?: string; @@ -8,4 +8,7 @@ export interface FormOptions { template?: string; saveDraft?: boolean; events?: EventEmitter2; + hooks?: { + customValidation?: Function; + }; } diff --git a/packages/react-formio/src/interfaces/FormSchema.ts b/packages/react-formio/src/interfaces/FormType.ts similarity index 59% rename from packages/react-formio/src/interfaces/FormSchema.ts rename to packages/react-formio/src/interfaces/FormType.ts index b1696396..d3e4b4aa 100644 --- a/packages/react-formio/src/interfaces/FormSchema.ts +++ b/packages/react-formio/src/interfaces/FormType.ts @@ -1,11 +1,11 @@ -import { ExtendedComponentSchema } from "formiojs"; +import type { ComponentType } from "./ComponentType"; -export type FormSchema = { +export type FormType = { _id?: string; title?: string; name?: string; machineName?: string; - components: ExtendedComponentSchema[]; + components: ComponentType[]; tags?: string[]; action?: string; properties?: Record; diff --git a/packages/react-formio/src/interfaces/Operation.ts b/packages/react-formio/src/interfaces/Operation.ts index cca02eb2..b3fc2223 100644 --- a/packages/react-formio/src/interfaces/Operation.ts +++ b/packages/react-formio/src/interfaces/Operation.ts @@ -1,6 +1,6 @@ import React from "react"; -import { OperationButtonProps } from "../components/table/components/defaultOperationButton.component"; +import type { OperationButtonProps } from "../molecules/table"; export type PermissionsResolver = (data: Data, ctx: any) => void; export type OnClickOperation = (data: Data, operation: Operation) => void; diff --git a/packages/react-formio/src/interfaces/RoleSchema.ts b/packages/react-formio/src/interfaces/RoleType.ts similarity index 54% rename from packages/react-formio/src/interfaces/RoleSchema.ts rename to packages/react-formio/src/interfaces/RoleType.ts index 49d8872e..007526df 100644 --- a/packages/react-formio/src/interfaces/RoleSchema.ts +++ b/packages/react-formio/src/interfaces/RoleType.ts @@ -1,4 +1,4 @@ -export interface RoleSchema extends Record { +export interface RoleType extends Record { _id?: string; title: string; admin: boolean; diff --git a/packages/react-formio/src/interfaces/Submission.ts b/packages/react-formio/src/interfaces/Submission.ts deleted file mode 100644 index fe7b5359..00000000 --- a/packages/react-formio/src/interfaces/Submission.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Submission extends Record { - _id?: string; - data: T; - metadata?: any; -} diff --git a/packages/react-formio/src/interfaces/SubmissionType.ts b/packages/react-formio/src/interfaces/SubmissionType.ts new file mode 100644 index 00000000..0bd73c60 --- /dev/null +++ b/packages/react-formio/src/interfaces/SubmissionType.ts @@ -0,0 +1,20 @@ +import type { ComponentType } from "./ComponentType"; + +export type JSON = unknown | string | number | boolean | null | undefined | JSON[] | { [key: string]: JSON }; + +export interface SubmissionType extends Record { + _id?: string; + data: Data; + metadata?: { [key: string]: JSON }; + state?: string; +} + +export interface ChangedSubmission extends SubmissionType { + data: Data; + changed?: { + component: ComponentType; + instance: any; + value: unknown; + } & Record; + isValid: boolean; +} diff --git a/packages/react-formio/src/interfaces/index.ts b/packages/react-formio/src/interfaces/index.ts index a539c2b6..3ea6373a 100644 --- a/packages/react-formio/src/interfaces/index.ts +++ b/packages/react-formio/src/interfaces/index.ts @@ -1,8 +1,9 @@ -export * from "./ActionSchema"; +export * from "./ActionType"; export * from "./ColumnIdentifier"; +export * from "./ComponentType"; export * from "./FormOptions"; -export * from "./FormSchema"; +export * from "./FormType"; export * from "./Operation"; export * from "./QueryOptions"; -export * from "./RoleSchema"; -export * from "./Submission"; +export * from "./RoleType"; +export * from "./SubmissionType"; diff --git a/packages/react-formio/src/components/__fixtures__/form-actions.json b/packages/react-formio/src/molecules/__fixtures__/form-actions.json similarity index 100% rename from packages/react-formio/src/components/__fixtures__/form-actions.json rename to packages/react-formio/src/molecules/__fixtures__/form-actions.json diff --git a/packages/react-formio/src/molecules/__fixtures__/form-firstname.fixture.json b/packages/react-formio/src/molecules/__fixtures__/form-firstname.fixture.json new file mode 100644 index 00000000..9ef826b3 --- /dev/null +++ b/packages/react-formio/src/molecules/__fixtures__/form-firstname.fixture.json @@ -0,0 +1,256 @@ +{ + "type": "form", + "display": "form", + "tags": [], + "components": [ + { + "label": "First name", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "inputMask": "", + "displayMask": "", + "applyMaskOn": "change", + "allowMultipleMasks": false, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "showWordCount": false, + "showCharCount": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "truncateMultipleSpaces": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "validateWhenHidden": false, + "errorLabel": "", + "errors": "", + "key": "firstName", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "textfield", + "dataGridLabel": false, + "input": true, + "refreshOn": "", + "addons": [], + "inputType": "text", + "defaultValue": "" + }, + { + "label": "Last name", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "inputMask": "", + "displayMask": "", + "applyMaskOn": "change", + "allowMultipleMasks": false, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "showWordCount": false, + "showCharCount": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "truncateMultipleSpaces": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "validateWhenHidden": false, + "errorLabel": "", + "errors": "", + "key": "lastName", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "textfield", + "dataGridLabel": false, + "input": true, + "refreshOn": "", + "addons": [], + "inputType": "text", + "defaultValue": "" + }, + { + "type": "button", + "label": "Submit", + "key": "submit", + "size": "md", + "block": false, + "action": "submit", + "disableOnInvalid": true, + "theme": "primary", + "input": true, + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": false, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "tableView": false, + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "leftIcon": "", + "rightIcon": "", + "dataGridLabel": true, + "addons": [] + } + ] +} diff --git a/packages/react-formio/src/components/__fixtures__/form-schema.json b/packages/react-formio/src/molecules/__fixtures__/form-schema.json similarity index 100% rename from packages/react-formio/src/components/__fixtures__/form-schema.json rename to packages/react-formio/src/molecules/__fixtures__/form-schema.json diff --git a/packages/react-formio/src/components/__fixtures__/form-submissions.json b/packages/react-formio/src/molecules/__fixtures__/form-submissions.json similarity index 100% rename from packages/react-formio/src/components/__fixtures__/form-submissions.json rename to packages/react-formio/src/molecules/__fixtures__/form-submissions.json diff --git a/packages/react-formio/src/molecules/__fixtures__/form-wizard.fixture.json b/packages/react-formio/src/molecules/__fixtures__/form-wizard.fixture.json new file mode 100644 index 00000000..33258524 --- /dev/null +++ b/packages/react-formio/src/molecules/__fixtures__/form-wizard.fixture.json @@ -0,0 +1,2042 @@ +{ + "display": "wizard", + "components": [ + { + "label": "Text Field", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "inputMask": "", + "allowMultipleMasks": false, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "showWordCount": false, + "showCharCount": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": true, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "errorLabel": "", + "key": "textField", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "textfield", + "input": true, + "refreshOn": "", + "inputType": "text", + "id": "eqb1o4r", + "defaultValue": "" + }, + { + "label": "Text Area", + "labelPosition": "top", + "placeholder": "Placeholder", + "description": "description", + "tooltip": "tooltip", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "editor": "", + "autoExpand": false, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "showWordCount": false, + "showCharCount": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "html", + "protected": false, + "dbIndex": false, + "case": "", + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "minWords": "", + "maxWords": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "errorLabel": "", + "key": "textArea", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "fixedSize": true, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "attributes": {}, + "type": "textarea", + "rows": 3, + "wysiwyg": false, + "input": true, + "refreshOn": "", + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputMask": "", + "id": "e4jsrqc", + "defaultValue": "" + }, + { + "label": "Number", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": false, + "modalEdit": false, + "multiple": false, + "persistent": true, + "delimiter": false, + "requireDecimal": false, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "min": "", + "max": "", + "strictDateValidation": false, + "multiple": false, + "unique": false, + "step": "any", + "integer": "" + }, + "errorLabel": "", + "key": "number", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "number", + "input": true, + "unique": false, + "refreshOn": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "id": "ex8zh8u", + "defaultValue": null + }, + { + "label": "Password", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "showWordCount": false, + "showCharCount": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": false, + "modalEdit": false, + "case": "", + "redrawOn": "", + "clearOnHide": true, + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "errorLabel": "", + "key": "password", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "password", + "input": true, + "multiple": false, + "defaultValue": null, + "protected": true, + "unique": false, + "persistent": true, + "refreshOn": "", + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "encrypted": false, + "allowMultipleMasks": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "id": "etqa5pm" + }, + { + "label": "Checkbox", + "description": "description", + "tooltip": "tooltip", + "shortcut": "", + "inputType": "checkbox", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "defaultValue": false, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "errorLabel": "", + "key": "checkbox", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "checkbox", + "name": "", + "value": "", + "input": true, + "placeholder": "", + "prefix": "", + "suffix": "", + "multiple": false, + "unique": false, + "refreshOn": "", + "labelPosition": "right", + "widget": null, + "validateOn": "change", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "dataGridLabel": true, + "id": "em8ln2m" + }, + { + "label": "Select Boxes", + "labelPosition": "top", + "optionsLabelPosition": "right", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "inline": false, + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "values": [ + { + "label": "label", + "value": "label", + "shortcut": "" + }, + { + "label": "lol", + "value": "lol", + "shortcut": "" + } + ], + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "errorLabel": "", + "minSelectedCountMessage": "", + "maxSelectedCountMessage": "", + "key": "selectBoxes", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "selectboxes", + "input": true, + "placeholder": "", + "prefix": "", + "suffix": "", + "multiple": false, + "unique": false, + "refreshOn": "", + "widget": null, + "validateOn": "change", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "inputType": "checkbox", + "fieldSet": false, + "id": "esa4upt", + "defaultValue": { + "": false + } + }, + { + "label": "Radio", + "labelPosition": "top", + "optionsLabelPosition": "right", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "inline": false, + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "values": [ + { + "label": "data", + "value": "data", + "shortcut": "" + }, + { + "label": "label", + "value": "label", + "shortcut": "" + } + ], + "dataType": "", + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "errorLabel": "", + "key": "radio", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "radio", + "input": true, + "placeholder": "", + "prefix": "", + "suffix": "", + "multiple": false, + "unique": false, + "refreshOn": "", + "widget": null, + "validateOn": "change", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "inputType": "radio", + "fieldSet": false, + "id": "edh7o6o", + "defaultValue": "" + }, + { + "label": "Select", + "labelPosition": "top", + "widget": "choicesjs", + "placeholder": "placeholder", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "uniqueOptions": false, + "autofocus": false, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "dataSrc": "values", + "data": { + "values": [ + { + "label": "label", + "value": "label" + }, + { + "label": "save", + "value": "save" + } + ], + "resource": "", + "json": "", + "url": "", + "custom": "" + }, + "valueProperty": "", + "dataType": "", + "idPath": "id", + "template": "{{ item.label }}", + "refreshOn": "", + "refreshOnBlur": "", + "clearOnRefresh": false, + "searchEnabled": true, + "selectThreshold": 0.3, + "readOnlyValue": false, + "customOptions": {}, + "useExactSearch": false, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "errorLabel": "", + "key": "select", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "select", + "indexeddb": { + "filter": {} + }, + "selectFields": "", + "searchField": "", + "minSearch": 0, + "filter": "", + "limit": 100, + "redrawOn": "", + "input": true, + "prefix": "", + "suffix": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "lazyLoad": true, + "authenticate": false, + "searchThreshold": 0.3, + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "id": "ebqtqd6", + "defaultValue": "" + }, + { + "label": "Select", + "labelPosition": "top", + "widget": "html5", + "placeholder": "placeholder", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "uniqueOptions": false, + "autofocus": false, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "dataSrc": "values", + "data": { + "values": [ + { + "label": "", + "value": "" + } + ], + "resource": "", + "json": "", + "url": "", + "custom": "" + }, + "valueProperty": "", + "dataType": "", + "idPath": "id", + "template": "{{ item.label }}", + "refreshOn": "", + "refreshOnBlur": "", + "clearOnRefresh": false, + "searchEnabled": true, + "selectThreshold": 0.3, + "readOnlyValue": false, + "customOptions": {}, + "useExactSearch": false, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "errorLabel": "", + "key": "select1", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "select", + "indexeddb": { + "filter": {} + }, + "selectFields": "", + "searchField": "", + "minSearch": 0, + "filter": "", + "limit": 100, + "redrawOn": "", + "input": true, + "prefix": "", + "suffix": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "lazyLoad": true, + "authenticate": false, + "searchThreshold": 0.3, + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "id": "em8m4qk", + "defaultValue": "" + }, + { + "label": "Email", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "kickbox": { + "enabled": false + }, + "errorLabel": "", + "key": "email", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "email", + "input": true, + "refreshOn": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "inputType": "email", + "inputMask": "", + "id": "epj8sj28", + "defaultValue": null + }, + { + "label": "Url", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "pattern": "", + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "minLength": "", + "maxLength": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "errorLabel": "", + "key": "url", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "url", + "input": true, + "refreshOn": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "inputType": "url", + "inputMask": "", + "id": "exw9p4", + "defaultValue": null + }, + { + "label": "Phone Number", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "inputMask": "(999) 999-9999", + "allowMultipleMasks": false, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": true, + "modalEdit": false, + "multiple": false, + "persistent": true, + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "unique": false, + "errorLabel": "", + "key": "phoneNumber", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "phoneNumber", + "input": true, + "refreshOn": "", + "showCharCount": false, + "showWordCount": false, + "inputType": "tel", + "id": "e2c7lpl", + "defaultValue": null + }, + { + "label": "Tags", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "delimeter": ",", + "maxTags": 0, + "storeas": "string", + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "validateOn": "change", + "errorLabel": "", + "key": "tags", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "tags", + "input": true, + "prefix": "", + "suffix": "", + "multiple": false, + "refreshOn": "", + "widget": { + "type": "input" + }, + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "id": "ejc82t", + "defaultValue": null + }, + { + "label": "Address", + "labelPosition": "top", + "enableManualMode": false, + "disableClearIcon": false, + "placeholder": "", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "multiple": false, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "provider": "google", + "manualModeViewString": "", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "validateOn": "change", + "errorLabel": "", + "key": "address", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "address", + "switchToManualModeLabel": "Can't find address? Switch to manual mode.", + "input": true, + "prefix": "", + "suffix": "", + "refreshOn": "", + "widget": null, + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "tree": true, + "components": [ + { + "label": "Address 1", + "tableView": false, + "key": "address1", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "eecfg6h" + }, + { + "label": "Address 2", + "tableView": false, + "key": "address2", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "eajhpuu" + }, + { + "label": "City", + "tableView": false, + "key": "city", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "efpnrca7" + }, + { + "label": "State", + "tableView": false, + "key": "state", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "eu3kksv" + }, + { + "label": "Country", + "tableView": false, + "key": "country", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "el39cu9" + }, + { + "label": "Zip Code", + "tableView": false, + "key": "zip", + "type": "textfield", + "input": true, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": true, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false, + "minLength": "", + "maxLength": "", + "pattern": "" + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "mask": false, + "inputType": "text", + "inputFormat": "plain", + "inputMask": "", + "spellcheck": true, + "id": "epyac4" + } + ], + "providerOptions": { + "params": { + "key": "fze", + "region": "" + } + }, + "id": "er02e2gb", + "defaultValue": {} + }, + { + "label": "Date / Time", + "labelPosition": "top", + "displayInTimezone": "viewer", + "useLocaleSettings": false, + "allowInput": true, + "format": "yyyy-MM-dd hh:mm a", + "placeholder": "", + "description": "", + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "enableDate": true, + "enableMinDateInput": false, + "datePicker": { + "minDate": null, + "maxDate": null, + "disable": "", + "disableFunction": "", + "disableWeekends": false, + "disableWeekdays": false, + "showWeeks": true, + "startingDay": 0, + "initDate": "", + "minMode": "day", + "maxMode": "year", + "yearRows": 4, + "yearColumns": 5 + }, + "enableMaxDateInput": false, + "enableTime": true, + "timePicker": { + "showMeridian": true, + "hourStep": 1, + "minuteStep": 1, + "readonlyInput": false, + "mousewheel": true, + "arrowkeys": true + }, + "multiple": false, + "defaultValue": "", + "defaultDate": "", + "customOptions": {}, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "unique": false, + "validateOn": "change", + "errorLabel": "", + "key": "dateTime", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "datetime", + "timezone": "", + "input": true, + "prefix": "", + "suffix": "", + "refreshOn": "", + "widget": { + "type": "calendar", + "displayInTimezone": "viewer", + "locale": "en", + "useLocaleSettings": false, + "allowInput": true, + "mode": "single", + "enableTime": true, + "noCalendar": false, + "format": "yyyy-MM-dd hh:mm a", + "hourIncrement": 1, + "minuteIncrement": 1, + "minDate": null, + "disabledDates": "", + "disableWeekends": false, + "disableWeekdays": false, + "disableFunction": "", + "maxDate": null + }, + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "datepickerMode": "day", + "id": "el9idgl" + }, + { + "label": "Day", + "hideInputLabels": false, + "inputsLabelPosition": "top", + "description": "", + "useLocaleSettings": false, + "tooltip": "", + "customClass": "", + "tabindex": "", + "hidden": false, + "hideLabel": false, + "autofocus": false, + "disabled": false, + "tableView": false, + "modalEdit": false, + "fields": { + "day": { + "type": "number", + "placeholder": "", + "hide": false, + "required": false + }, + "month": { + "type": "select", + "placeholder": "", + "hide": false, + "required": false + }, + "year": { + "type": "number", + "placeholder": "", + "hide": false, + "required": false + } + }, + "dayFirst": false, + "persistent": true, + "protected": false, + "dbIndex": false, + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "maxDate": "", + "minDate": "", + "unique": false, + "errorLabel": "", + "validate": { + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "required": false, + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "key": "day", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "day", + "input": true, + "placeholder": "", + "prefix": "", + "suffix": "", + "multiple": false, + "refreshOn": "", + "labelPosition": "top", + "widget": null, + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "id": "ecgefls", + "defaultValue": "00/00/0000" + }, + { + "label": "Currency", + "labelPosition": "top", + "placeholder": "", + "description": "", + "tooltip": "", + "prefix": "", + "suffix": "", + "widget": { + "type": "input" + }, + "customClass": "", + "tabindex": "", + "autocomplete": "", + "hidden": false, + "hideLabel": false, + "mask": false, + "autofocus": false, + "spellcheck": true, + "disabled": false, + "tableView": false, + "modalEdit": false, + "multiple": false, + "persistent": true, + "currency": "USD", + "inputFormat": "plain", + "protected": false, + "dbIndex": false, + "case": "", + "encrypted": false, + "redrawOn": "", + "clearOnHide": true, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "allowCalculateOverride": false, + "validateOn": "change", + "validate": { + "required": false, + "customMessage": "", + "custom": "", + "customPrivate": false, + "json": "", + "strictDateValidation": false, + "multiple": false, + "unique": false, + "min": "", + "max": "", + "step": "any", + "integer": "" + }, + "unique": false, + "errorLabel": "", + "key": "currency", + "tags": [], + "properties": {}, + "conditional": { + "show": null, + "when": null, + "eq": "", + "json": "" + }, + "customConditional": "", + "logic": [], + "attributes": {}, + "overlay": { + "style": "", + "page": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "type": "currency", + "input": true, + "refreshOn": "", + "showCharCount": false, + "showWordCount": false, + "allowMultipleMasks": false, + "delimiter": true, + "id": "em22wkd", + "defaultValue": null + }, + { + "type": "button", + "label": "Submit", + "key": "submit", + "size": "md", + "block": false, + "action": "submit", + "disableOnInvalid": true, + "theme": "primary", + "input": true, + "placeholder": "", + "prefix": "", + "customClass": "", + "suffix": "", + "multiple": false, + "defaultValue": null, + "protected": false, + "unique": false, + "persistent": false, + "hidden": false, + "clearOnHide": true, + "refreshOn": "", + "redrawOn": "", + "tableView": false, + "modalEdit": false, + "labelPosition": "top", + "description": "", + "errorLabel": "", + "tooltip": "", + "hideLabel": false, + "tabindex": "", + "disabled": false, + "autofocus": false, + "dbIndex": false, + "customDefaultValue": "", + "calculateValue": "", + "calculateServer": false, + "widget": { + "type": "input" + }, + "attributes": {}, + "validateOn": "change", + "validate": { + "required": false, + "custom": "", + "customPrivate": false, + "strictDateValidation": false, + "multiple": false, + "unique": false + }, + "conditional": { + "show": null, + "when": null, + "eq": "" + }, + "overlay": { + "style": "", + "left": "", + "top": "", + "width": "", + "height": "" + }, + "allowCalculateOverride": false, + "encrypted": false, + "showCharCount": false, + "showWordCount": false, + "properties": {}, + "allowMultipleMasks": false, + "leftIcon": "", + "rightIcon": "", + "dataGridLabel": true, + "id": "e08gq3l" + } + ] +} diff --git a/packages/react-formio/src/components/__fixtures__/form.fixture.json b/packages/react-formio/src/molecules/__fixtures__/form.fixture.json similarity index 100% rename from packages/react-formio/src/components/__fixtures__/form.fixture.json rename to packages/react-formio/src/molecules/__fixtures__/form.fixture.json diff --git a/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts b/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts new file mode 100644 index 00000000..96443ad5 --- /dev/null +++ b/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts @@ -0,0 +1,14 @@ +import { useState } from "react"; + +export const useValue = (args: any) => { + const [value, setValue] = useState(args.value); + + return { + ...args, + value, + onChange(name: string, value: any) { + setValue(value); + args.onChange(name, value); + } + }; +}; diff --git a/packages/react-formio/src/components/alert/alert.component.spec.tsx b/packages/react-formio/src/molecules/alert/Alert.spec.tsx similarity index 82% rename from packages/react-formio/src/components/alert/alert.component.spec.tsx rename to packages/react-formio/src/molecules/alert/Alert.spec.tsx index a599439e..0011876f 100644 --- a/packages/react-formio/src/components/alert/alert.component.spec.tsx +++ b/packages/react-formio/src/molecules/alert/Alert.spec.tsx @@ -1,19 +1,16 @@ import { render, screen } from "@testing-library/react"; -import React from "react"; -import { Sandbox } from "./alert.stories"; +import { Alert } from "./Alert"; -describe("Alert component", () => { - it("should NOT display the alert component when no error is received.", () => { - const { container } = render(); - - expect(container).toBeEmptyDOMElement(); - }); +const args = { + error: "error placeholder" +}; +describe("Alert component", () => { it("should display an error when the error is in string format", () => { const error = "error in string format"; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -25,7 +22,7 @@ describe("Alert component", () => { it("should display error(s) when the error is an array", () => { const arrayOfErrors = ["first error", "second error", "third error"]; const joinedErrors = arrayOfErrors.map((error) => error).join(""); - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -42,7 +39,7 @@ describe("Alert component", () => { { name: "third error", path: "/path", message: "message" } ] }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -53,7 +50,7 @@ describe("Alert component", () => { it("should display an error message when the error is a standard error", () => { const standardError = { message: "first error" }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -64,7 +61,7 @@ describe("Alert component", () => { it("should display error(s) message(s) when the error is a joi validation error", () => { const joiValidationError = { name: "ValidationError", details: [{ message: "message 1" }, { message: "message 2" }] }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -77,7 +74,7 @@ describe("Alert component", () => { it("should display a custom error message that asks to reload the form when a conflict error occurs in a form", () => { const error = { _id: "some id", display: "some value" }; const messageReturned = "Another user has saved this form already. Please reload and re-apply your changes."; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -88,7 +85,7 @@ describe("Alert component", () => { it("should display an error message by default when the error format does not match any of the conditions of the formatError() handler", () => { const messageError: string = "An error occurred. See console logs for details."; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; diff --git a/packages/react-formio/src/molecules/alert/Alert.stories.tsx b/packages/react-formio/src/molecules/alert/Alert.stories.tsx new file mode 100644 index 00000000..515e0d6b --- /dev/null +++ b/packages/react-formio/src/molecules/alert/Alert.stories.tsx @@ -0,0 +1,39 @@ +import { Alert } from "./Alert"; + +/** + * Alerts display brief messages for the user without interrupting their use of the app. + * + * ```tsx + * import {Alert} from "@tsed/react-formio/molecules/alert/Alert"; + * + * + * Message + * + * ``` + */ +export default { + title: "Alert", + component: Alert, + argTypes: { + message: { + control: "text" + }, + type: { + control: "select", + options: ["primary", "secondary", "success", "danger", "warning", "info", "light", "dark"] + } + }, + parameters: { + docs: { + source: { language: "tsx" } + } + }, + tags: ["autodocs"] +}; + +export const Sandbox = { + args: { + type: "danger", + message: "error placeholder" + } +}; diff --git a/packages/react-formio/src/components/alert/alert.component.tsx b/packages/react-formio/src/molecules/alert/Alert.tsx similarity index 86% rename from packages/react-formio/src/components/alert/alert.component.tsx rename to packages/react-formio/src/molecules/alert/Alert.tsx index a7238eb3..edfc833e 100644 --- a/packages/react-formio/src/components/alert/alert.component.tsx +++ b/packages/react-formio/src/molecules/alert/Alert.tsx @@ -1,6 +1,10 @@ -import React from "react"; +import { PropsWithChildren } from "react"; function formatError(error: any): any { + if (!error || (Array.isArray(error) && !error.length)) { + return ""; + } + if (typeof error === "string") { return error; } @@ -44,18 +48,15 @@ function formatError(error: any): any { } export interface AlertProps { - error?: any | any[]; + message?: string | any | string[]; type?: string; } -export function Alert({ error, type = "danger" }: AlertProps) { - if (!error || (Array.isArray(error) && !error.length)) { - return null; - } - +export function Alert({ children, message, type = "danger" }: PropsWithChildren) { return (
- {formatError(error)} + {formatError(message)} + {children}
); } diff --git a/packages/react-formio/src/molecules/button/Button.stories.tsx b/packages/react-formio/src/molecules/button/Button.stories.tsx new file mode 100644 index 00000000..28164fac --- /dev/null +++ b/packages/react-formio/src/molecules/button/Button.stories.tsx @@ -0,0 +1,106 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { Icon } from "../../atoms/icon/Icon"; +import { Button, BUTTON_VARIANTS } from "./Button"; + +/** + * Button component with a label and an onClick handler. + * + * ```ts + * import {Button} from "@tsed/react-formio/molecules/button/Button"; + * ``` + * + * ## Override Button + * + * This component is registered with the name `Button` and can be overridden with the following code: + * + * ```ts + * registerComponent("Button", MyCustomButtonComponent); + * ``` + */ +export default { + title: "Button", + component: Button, + argTypes: { + onClick: { action: "clicked" }, + variant: { + control: "select", + options: BUTTON_VARIANTS + }, + disabled: { + control: "boolean" + } + }, + parameters: { + children: "Text", + variant: "primary" + } +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + children: "Text", + variant: "primary" + } +}; + +export const Variant: Story = { + args: { + children: "Text" + }, + render(args) { + return ( +
+ {BUTTON_VARIANTS.map((variant) => ( +
+ +
+ ))} +
+ ); + } +}; + +export const Disabled: Story = { + args: { + children: "Text", + disabled: true + }, + render(args) { + return ( +
+ {BUTTON_VARIANTS.map((variant) => ( +
+ +
+ ))} +
+ ); + } +}; + +export const WithIcon: Story = { + args: { + children: "Text" + }, + render(args) { + return ( +
+ {BUTTON_VARIANTS.map((variant) => ( +
+ +
+ ))} +
+ ); + } +}; diff --git a/packages/react-formio/src/molecules/button/Button.tsx b/packages/react-formio/src/molecules/button/Button.tsx new file mode 100644 index 00000000..dae2563e --- /dev/null +++ b/packages/react-formio/src/molecules/button/Button.tsx @@ -0,0 +1,54 @@ +import cx from "classnames"; +import { type ButtonHTMLAttributes, forwardRef, type LegacyRef, type PropsWithChildren } from "react"; + +import { registerComponent } from "../../registries/components"; + +export const BUTTON_VARIANTS = [ + "primary", + "secondary", + "success", + "danger", + "warning", + "info", + "light", + "dark", + "link", + "outline-primary", + "outline-secondary", + "outline-success", + "outline-danger", + "outline-warning", + "outline-info", + "outline-light", + "outline-dark", + "outline-link" +]; + +export interface ButtonProps extends ButtonHTMLAttributes { + variant?: (typeof BUTTON_VARIANTS)[keyof typeof BUTTON_VARIANTS] | string; +} + +export const Button = forwardRef( + ({ variant, className, children, ...props }: PropsWithChildren, ref: LegacyRef) => { + return ( + + ); + } +); + +registerComponent("Button", Button); diff --git a/packages/react-formio/src/components/card/card.component.spec.tsx b/packages/react-formio/src/molecules/card/Card.spec.tsx similarity index 74% rename from packages/react-formio/src/components/card/card.component.spec.tsx rename to packages/react-formio/src/molecules/card/Card.spec.tsx index 8f5bb17a..e8a7ad0a 100644 --- a/packages/react-formio/src/components/card/card.component.spec.tsx +++ b/packages/react-formio/src/molecules/card/Card.spec.tsx @@ -1,11 +1,11 @@ import { render, screen } from "@testing-library/react"; -import React from "react"; -import { Sandbox } from "./card.stories"; +import { Card } from "./Card"; +import { Sandbox } from "./Card.stories"; describe("Card", () => { it("should render the card component", () => { - render(); + render(); const title = screen.getByRole("heading"); const body = screen.getByRole("article"); diff --git a/packages/react-formio/src/components/card/card.stories.tsx b/packages/react-formio/src/molecules/card/Card.stories.tsx similarity index 52% rename from packages/react-formio/src/components/card/card.stories.tsx rename to packages/react-formio/src/molecules/card/Card.stories.tsx index f54ae243..30fdf516 100644 --- a/packages/react-formio/src/components/card/card.stories.tsx +++ b/packages/react-formio/src/molecules/card/Card.stories.tsx @@ -1,9 +1,14 @@ -import React from "react"; - -import { Card } from "./card.component"; +import { Card } from "./Card"; +/** + * Cards contain content and actions about a single subject. + * + * ```ts + * import {Card} from "@tsed/react-formio/molecules/card/Card"; + * ``` + */ export default { - title: "ReactFormio/Card", + title: "Card", component: Card, argTypes: {}, parameters: {} diff --git a/packages/react-formio/src/components/card/card.component.tsx b/packages/react-formio/src/molecules/card/Card.tsx similarity index 85% rename from packages/react-formio/src/components/card/card.component.tsx rename to packages/react-formio/src/molecules/card/Card.tsx index 66617741..0ee8fb3b 100644 --- a/packages/react-formio/src/components/card/card.component.tsx +++ b/packages/react-formio/src/molecules/card/Card.tsx @@ -1,8 +1,7 @@ import classnames from "classnames"; -import React, { PropsWithChildren } from "react"; +import { PropsWithChildren } from "react"; export interface CardProps { - children: React.ReactNode; label: string; className?: string; } diff --git a/packages/react-formio/src/components/form-control/formControl.component.spec.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx similarity index 81% rename from packages/react-formio/src/components/form-control/formControl.component.spec.tsx rename to packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx index 635f96c1..0b25abc4 100644 --- a/packages/react-formio/src/components/form-control/formControl.component.spec.tsx +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx @@ -1,12 +1,12 @@ import { render, screen } from "@testing-library/react"; -import React from "react"; -import { iconClass } from "../../utils/iconClass"; -import { Sandbox, WithDescription, WithPrefix, WithSuffix } from "./formControl.stories"; +import { iconClass } from "../../../utils/iconClass"; +import { FormControl } from "./FormControl"; +import { Sandbox } from "./FormControl.stories"; describe("form-control", () => { it("should display form control component", () => { - render(); + render(); const formGroup = screen.getByTestId("form-group-test") as HTMLFormElement; @@ -15,7 +15,7 @@ describe("form-control", () => { it("should NOT display form-control component without a name attribute defined", () => { const name = ""; - render(); + render(); const formGroup = screen.queryByTestId(`form-group-${name}`) as HTMLFormElement; @@ -23,7 +23,7 @@ describe("form-control", () => { }); it("should display form-control component with className 'field-required' when the props 'required' is set to true", () => { - render(); + render(); const formGroup = screen.getByTestId("form-group-test") as HTMLFormElement; const formControlLabel = screen.getByTestId(`form-control-label`) as HTMLLabelElement; @@ -36,7 +36,7 @@ describe("form-control", () => { it("should display prefix", () => { const fontAwsomeCalendarIcon = "fa fa-calendar"; const prefix = () as JSX.Element; - render(); + render(); const formGroup = screen.getByTestId("form-group-testPrefix") as HTMLFormElement; const formControlPrefix = screen.getByTestId("form-control-prefix") as HTMLSpanElement; @@ -50,7 +50,7 @@ describe("form-control", () => { it("should display suffix", () => { const fontAwsomeCalendarIcon = "fa fa-calendar"; const suffix = () as JSX.Element; - render(); + render(); const formGroup = screen.getByTestId("form-group-testSuffix") as HTMLFormElement; const formControlSuffix = screen.getByTestId("form-control-suffix") as HTMLSpanElement; @@ -63,7 +63,7 @@ describe("form-control", () => { it("should display description", () => { const description = "test description"; - render(); + render(); const formGroup = screen.getByTestId("form-group-testDescription") as HTMLFormElement; const formControlDescription = screen.getByTestId("form-control-description") as HTMLDivElement; diff --git a/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx new file mode 100644 index 00000000..33cb03e2 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx @@ -0,0 +1,58 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { iconClass } from "../../../utils/iconClass"; +import { FormControl } from "./FormControl"; +/** + * ```tsx + * import {FormControl} from "@tsed/react-formio/molecules/forms/form-control/FormControl"; + * ``` + */ +export default { + title: "forms/FormControl", + component: FormControl, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + children: { + control: "object" + } + }, + parameters: {}, + tags: ["autodocs"] +} satisfies Meta; + +type Story = StoryObj; + +export const Sandbox: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]" + } +}; + +export const Usage: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]", + before: + } +}; + +export const AppendAfter: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]", + after: + } +}; + +export const WithDescription: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]" + } +}; diff --git a/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx new file mode 100644 index 00000000..8ed3db24 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx @@ -0,0 +1,86 @@ +import classnames from "classnames"; +import omit from "lodash/omit"; +import { HTMLAttributes, InputHTMLAttributes, PropsWithChildren, ReactNode } from "react"; + +import { registerComponent } from "../../../registries/components"; + +export type BaseFormControlProps = { + label?: string; + description?: string | ReactNode; + before?: ReactNode | string; + after?: ReactNode | string; + shadow?: boolean; + value?: Value; + onChange?: (name: string | undefined, value: Value) => void; + /** + * The input size + */ + size?: "small" | string; +}; +export type FormControlProps< + Value = unknown, + Attributes extends HTMLAttributes = InputHTMLAttributes +> = BaseFormControlProps & Omit; + +export function cleanFormControlProps(props: FormControlProps, omitted: string[] = []): any { + return omit(props, ["label", "description", "prefix", "suffix", "size", "shadow", ...omitted]); +} + +export function FormControl({ + children, + name = "", + id = name, + required, + before, + after, + description, + label, + size, + className +}: PropsWithChildren>) { + return ( +
+ {label && ( + + )} +
+ {before && ( +
+ + {before} + +
+ )} + {children} + {after && ( +
+ + {after} + +
+ )} +
+ {description && ( +
+ {description} +
+ )} +
+ ); +} + +registerComponent("FormControl", FormControl); diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts b/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts new file mode 100644 index 00000000..22343aac --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.interface.ts @@ -0,0 +1,9 @@ +import type { InputHTMLAttributes } from "react"; + +import type { FormControlProps } from "../form-control/FormControl"; + +export interface InputTagsProps extends FormControlProps> { + layout?: "html5" | "react" | "choicesjs"; + delimiter?: string; + customProperties?: Record; +} diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx new file mode 100644 index 00000000..fcc118f0 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx @@ -0,0 +1,30 @@ +import { ComponentType } from "react"; + +import { getComponent, registerComponent } from "../../../registries/components"; +import { type FormControl as DefaultFormControl } from "../form-control/FormControl"; +import type { InputTagsProps } from "./InputTags.interface"; + +export function InputTags(props: InputTagsProps) { + const { name, id = name, label, required, description, before, after, size, className, layout = "choicesjs", ...otherProps } = props; + + const FormControl = getComponent("FormControl"); + const Component = getComponent>>([`InputTags.${layout}`, "Input"]); + console.log("VALUE", props.value); + return ( + + + + ); +} + +registerComponent("InputTags", InputTags); diff --git a/packages/react-formio/src/molecules/forms/input-tags/all.ts b/packages/react-formio/src/molecules/forms/input-tags/all.ts new file mode 100644 index 00000000..ccd3045d --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/all.ts @@ -0,0 +1,6 @@ +import "../form-control/FormControl"; +import "./components/ChoicesTags"; +import "./components/ReactTags"; +import "../input-text/InputText"; +export * from "./InputTags"; +export * from "./InputTags.interface"; diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx new file mode 100644 index 00000000..15de383d --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.stories.tsx @@ -0,0 +1,110 @@ +import "../all"; + +import type { Meta, StoryObj } from "@storybook/react"; + +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { InputTags } from "../InputTags"; + +/** + * The InputTags component enables users to create new options in the text field. + * + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/all"; + * + * or + * + * import "@tsed/react-formio/molecules/forms/input-tags/components/ChoicesTags"; + * import "@tsed/react-formio/molecules/forms/input-tags/components/ReactTags"; + * import "@tsed/react-formio/molecules/forms/input-text/InputText"; + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/InputTags"; + * + * ``` + */ +export default { + title: "forms/InputTags/ChoicesJs", + component: InputTags, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "object" + }, + size: { + control: "select", + options: ["small", "normal"] + }, + placeholder: { + control: "text" + }, + description: { + control: "text" + }, + layout: { + control: "select", + options: ["choicesjs", "react"] + }, + onChange: { + action: "onChange" + } + }, + parameters: {}, + args: { + layout: "choicesjs" + }, + tags: ["autodocs"] +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "", + placeholder: "Placeholder" + } +}; + +export const WithSizeOption: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "small", + placeholder: "Placeholder" + } +}; + +export const AppendBefore: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +export const AppendAfter: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx new file mode 100644 index 00000000..35dcdc27 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ChoicesTags.tsx @@ -0,0 +1,72 @@ +import Choices from "@formio/choices.js"; +import { useEffect, useRef } from "react"; +import { useDebouncedCallback } from "use-debounce"; + +import { registerComponent } from "../../../../registries/components"; +import { cleanFormControlProps } from "../../form-control/FormControl"; +import type { InputTagsProps } from "../InputTags.interface"; + +export function useChoiceTags(props: InputTagsProps) { + const { value, onChange, name = "", delimiter, customProperties, ...otherProps } = props; + const ref = useRef(null); + const instanceRef = useRef(null); + + const onAdd = useDebouncedCallback((add: Data) => { + const values = ((value || []) as Data[]).concat(add); + + onChange?.(name, [...values]); + }, 100); + + const onDelete = useDebouncedCallback((remove: Data) => { + const values = (value || []).filter((v) => v !== remove); + + onChange?.(name, [...values]); + }); + + useEffect(() => { + if (ref.current) { + const instance = new Choices(ref.current!, { + duplicateItemsAllowed: false, + ...customProperties, + delimiter, + editItems: true, + removeItemButton: true + }); + + instance.setValue((value || []) as string[]); + + instanceRef.current = instance; + + instance.passedElement.element.addEventListener("addItem", (event: { detail: { value: unknown } }) => { + onAdd(event.detail.value as Data); + }); + + instance.passedElement.element.addEventListener("removeItem", (event: { detail: { value: unknown } }) => { + onDelete(event.detail.value as Data); + }); + } + + return () => { + if (instanceRef.current) { + instanceRef.current.destroy(); + } + }; + }, [delimiter]); + + return { + otherProps: { + ...otherProps, + name + }, + ref, + instanceRef + }; +} + +export function ChoicesTags(props: InputTagsProps) { + const { ref, otherProps } = useChoiceTags(props); + + return ; +} + +registerComponent("InputTags.choicesjs", ChoicesTags); diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx new file mode 100644 index 00000000..2208ca3a --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.stories.tsx @@ -0,0 +1,140 @@ +import "../all"; + +import type { Meta, StoryObj } from "@storybook/react"; +import { type CreatableProps } from "react-select/creatable"; + +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { InputTags } from "../InputTags"; + +/** + * The InputTags component enables users to create new options in the text field. + * + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/all"; + * + * or + * + * import "@tsed/react-formio/molecules/forms/input-tags/components/ReactTags"; + * import "@tsed/react-formio/molecules/forms/input-text/InputText"; + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/InputTags"; + * + * ``` + */ +export default { + title: "forms/InputTags/React", + component: InputTags, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "object" + }, + size: { + control: "select", + options: ["small", "normal"] + }, + placeholder: { + control: "text" + }, + description: { + control: "text" + }, + layout: { + control: "select", + options: ["choicesjs", "react"] + }, + onChange: { + action: "onChange" + } + }, + parameters: {}, + args: { + layout: "react" + }, + tags: ["autodocs"], + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { value, onChange } = useValue(args); + + return ; + } +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "", + placeholder: "Placeholder" + } +}; + +export const WithSizeOption: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "small", + placeholder: "Placeholder" + } +}; + +export const AppendBefore: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +export const AppendAfter: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +/** + * InputTags using the [react-select](https://react-select.com/) library can + * be customized using the `customProperties` prop. + * + * For example, you can use the `customProperties` prop to add a list of options. + * + * See the [react-select documentation](https://react-select.com/creatable) for more information. + */ +export const CustomProperties: Story = { + args: { + value: [], + name: "name", + label: "Label", + placeholder: "Select or Create...", + customProperties: { + options: [ + { value: "chocolate", label: "Chocolate" }, + { value: "strawberry", label: "Strawberry" }, + { value: "vanilla", label: "Vanilla" } + ] + } satisfies CreatableProps + } +}; diff --git a/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx new file mode 100644 index 00000000..64542684 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/components/ReactTags.tsx @@ -0,0 +1,38 @@ +import makeAnimated from "react-select/animated"; +import CreatableSelect from "react-select/creatable"; + +import { registerComponent } from "../../../../registries/components"; +import { InputTagsProps } from "../InputTags.interface"; + +const animatedComponents = makeAnimated(); + +export function ReactTags(props: InputTagsProps) { + const { value = [], placeholder, customProperties = {} } = props; + + return ( + { + return { label: v, value: v }; + })} + onChange={(value) => { + props.onChange?.( + props.name, + value.map(({ value }) => { + return value; + }) + ); + }} + /> + ); +} + +registerComponent("InputTags.react", ReactTags); diff --git a/packages/react-formio/src/molecules/forms/input-text/InputText.interface.ts b/packages/react-formio/src/molecules/forms/input-text/InputText.interface.ts new file mode 100644 index 00000000..f857f397 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.interface.ts @@ -0,0 +1,5 @@ +import type { FormControlProps } from "../form-control/FormControl"; + +export interface InputTextProps extends FormControlProps { + debounceDelay?: number; +} diff --git a/packages/react-formio/src/components/input-text/inputText.component.spec.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx similarity index 79% rename from packages/react-formio/src/components/input-text/inputText.component.spec.tsx rename to packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx index a9612e69..f10c09d6 100644 --- a/packages/react-formio/src/components/input-text/inputText.component.spec.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx @@ -1,28 +1,28 @@ import { fireEvent, render, screen } from "@testing-library/react"; -import React from "react"; -import { Sandbox } from "./inputText.stories"; +import { InputText } from "./InputText"; +import { Usage } from "./InputText.stories"; describe("input-text", () => { it("should display the input-text component", () => { - render(); + render(); const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); }); it("should display the input-text component with a different size", () => { - render(); + render(); const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); - expect(input).toHaveClass("form-control-small"); + expect(screen.getByTestId("form-group-test")).toHaveClass("-size-small"); }); it("should display the input-text with placeholder", () => { const placeholderTest = "placeholder test"; - render(); + render(); const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); @@ -32,7 +32,7 @@ describe("input-text", () => { it("should change the value of the input-text", () => { const placeholderTest = "placeholder test"; - render(); + render(); const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); @@ -44,7 +44,7 @@ describe("input-text", () => { it("should NOT change the value of the input-text if the value is NOT of type number", () => { const placeholderTest = "placeholder test"; - render(); + render(); const input = screen.getByTestId("input_test") as HTMLInputElement; expect(input).toBeInTheDocument(); diff --git a/packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx new file mode 100644 index 00000000..9032e9fe --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx @@ -0,0 +1,179 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { expect, userEvent, within } from "@storybook/test"; + +import { iconClass } from "../../../utils/iconClass"; +import { useValue } from "../../__fixtures__/useValue.hook"; +import { InputText } from "./InputText"; + +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +/** + * Text Fields let users enter and edit text. + * + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-text/InputText"; + * ``` + */ +export default { + title: "forms/InputText", + component: InputText, + argTypes: { + label: { + control: "text" + }, + type: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "text" + }, + required: { + control: "boolean" + }, + size: { + control: "select", + options: ["small", "normal"] + }, + placeholder: { + control: "text" + }, + description: { + control: "text" + }, + onChange: { + action: "onChange" + }, + onBlur: { + action: "onBlur" + }, + onFocus: { + action: "onFocus" + } + }, + parameters: {}, + tags: ["autodocs"] +} satisfies Meta; + +type Story = StoryObj; +/** + * Basic usage of the InputText. + */ +export const Usage: Story = { + args: { + name: "name", + label: "Label", + value: "", + size: "", + placeholder: "Placeholder" + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const input = await canvas.getByPlaceholderText("Placeholder"); + await userEvent.type(input, "Test input", { delay: 100 }); + await expect(input).toHaveValue("Test input"); + } +}; +/** + * Debounce the value when the user types. + */ +export const Debounced: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const props = useValue(args); + return ( +
+ +
Value: {props.value}
+
+ ); + }, + args: { + name: "name", + label: "Label", + value: "", + size: "", + placeholder: "Placeholder" + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const input = await canvas.getByPlaceholderText("Placeholder"); + await userEvent.type(input, "Test input", { delay: 100 }); + + expect(canvas.getByTestId("debounced-value")).toHaveTextContent("Value:"); + + await delay(500); + + expect(canvas.getByTestId("debounced-value")).toHaveTextContent("Value: Test input"); + } +}; +/** + * Add a prefix to the input text. + */ +export const AppendBefore: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const props = useValue(args); + return } {...props} />; + }, + args: { + label: "Label", + value: "", + size: "", + placeholder: "Placeholder" + } +}; +/** + * Add a suffix to the input text. + */ +export const AppendAfter: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const props = useValue(args); + return } {...props} />; + }, + args: { + label: "Label", + value: "", + size: "", + placeholder: "Placeholder" + } +}; +/** + * Change the type of the input text. + */ +export const TypeNumber: Story = { + render(args: any) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const props = useValue(args); + return } {...props} />; + }, + args: { + label: "Label", + type: "number", + value: "", + size: "", + placeholder: "Placeholder", + description: "Use dollars!" + } +}; +/** + * Change the size of the input text. + */ +export const Sizing: Story = { + render(args: any) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const props = useValue(args); + + return } {...props} />; + }, + args: { + label: "Label", + type: "number", + value: "", + size: "small", + placeholder: "Placeholder", + description: "Use dollars!" + } +}; diff --git a/packages/react-formio/src/molecules/forms/input-text/InputText.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx new file mode 100644 index 00000000..16426bbb --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx @@ -0,0 +1,63 @@ +import { ComponentType, useEffect, useState } from "react"; +import { useDebouncedCallback } from "use-debounce"; + +import { getComponent, registerComponent } from "../../../registries/components"; +import { getEventValue } from "../../../utils/getEventValue"; +import { cleanFormControlProps, FormControl } from "../form-control/FormControl"; +import { InputTextProps } from "./InputText.interface"; + +function Input(props: InputTextProps) { + const { name, id = name, value, onChange, required, type, placeholder, debounceDelay = 300, ...otherProps } = props; + + const [localValue, setValue] = useState(value); + const change = useDebouncedCallback(onChange || (() => {}), debounceDelay); + + useEffect(() => { + setValue(value); + }, [value]); + + return ( + { + const value = getEventValue(event); + setValue(value); + + return change && change(name, value); + }} + /> + ); +} + +registerComponent("Input", Input); + +export function InputText(props: InputTextProps) { + const { name, id = name, label, required, size, before, after, description, className } = props; + const Input = getComponent>>("Input"); + + return ( + + + + ); +} + +registerComponent("InputText", InputText); diff --git a/packages/react-formio/src/molecules/forms/select/Select.interface.ts b/packages/react-formio/src/molecules/forms/select/Select.interface.ts new file mode 100644 index 00000000..494ec784 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/Select.interface.ts @@ -0,0 +1,42 @@ +import { SelectHTMLAttributes } from "react"; + +import { FormControlProps } from "../form-control/FormControl"; + +export interface SelectOptionBaseProps extends Record { + label: string | JSX.Element; + value: string; + id?: string; + disabled?: boolean; + note?: string | JSX.Element; + group?: string; + data?: Data; + template?: (item: SelectOptionProps) => JSX.Element; +} + +export interface SelectOptionProps extends SelectOptionBaseProps { + options?: SelectOptionProps[]; +} + +export interface SelectProps extends FormControlProps> { + layout?: "html5" | "react" | "choicesjs"; + /** + * Error message + */ + errorMessage?: string; + readonly?: boolean; + disableSearch?: boolean; + searchEnabled?: boolean; + customProperties?: Record; +} + +export interface SelectSingle extends SelectProps { + multiple?: false | undefined; + options: (SelectOptionBaseProps | Omit, "value">)[]; +} + +export interface SelectMultiple extends SelectProps { + multiple: true; + options: (SelectOptionBaseProps | Omit, "value">)[]; +} + +export type AllSelectProps = SelectSingle | SelectMultiple; diff --git a/packages/react-formio/src/molecules/forms/select/Select.tsx b/packages/react-formio/src/molecules/forms/select/Select.tsx new file mode 100644 index 00000000..e5e94d40 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/Select.tsx @@ -0,0 +1,28 @@ +import type { ComponentType } from "react"; + +import { getComponent, registerComponent } from "../../../registries/components"; +import type { FormControl as DefaultFormControl } from "../form-control/FormControl"; +import { useOptions } from "./hooks/useOptions"; +import { AllSelectProps } from "./Select.interface"; + +let uuid = 0; + +export function Select(props: AllSelectProps) { + const { className, name = "", id = `field-select-${++uuid}`, label, description = "" } = props; + + const options = useOptions({ + ...props, + value: (Array.isArray(props.value) ? props.value : [props.value]) as any + }); + + const FormControl = getComponent("FormControl"); + const Component = getComponent>>(["Select." + props.layout, "Select.html5"]); + + return ( + + + + ); +} + +registerComponent("Select", Select); diff --git a/packages/react-formio/src/molecules/forms/select/all.ts b/packages/react-formio/src/molecules/forms/select/all.ts new file mode 100644 index 00000000..695dd20a --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/all.ts @@ -0,0 +1,7 @@ +import "../form-control/FormControl"; +import "./components/ReactSelect"; +import "./components/HtmlSelect"; +import "./components/ChoicesSelect"; + +export * from "./Select"; +export * from "./Select.interface"; diff --git a/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx new file mode 100644 index 00000000..46ec8c0d --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/components/ChoicesSelect.stories.tsx @@ -0,0 +1,332 @@ +import "./ChoicesSelect"; + +import { Meta, StoryObj } from "@storybook/react"; +import { fn } from "@storybook/test"; + +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { Select } from "../Select"; + +const options = [ + { + label: "Option 1", + value: "option-1" + }, + { + label: "Option 2", + value: "option-2" + }, + { + label: "Option 3", + value: "option-3" + } +]; +/** + * ChoicesJS select component. + * + * ```tsx + * import {Select} from "@tsed/react-formio/molecules/forms/select/all"; // import HTML5, ChoicesJS and React components + * + * // or + * import {Select} from "@tsed/react-formio/molecules/forms/select/Select"; + * import "@tsed/react-formio/molecules/forms/select/components/ChoicesSelect"; // register only ChoicesJS component + * + * ``` + */ +export default { + title: "forms/Select/ChoiceJs", + component: Select, + parameters: { + layout: "centered", + backgrounds: { default: "pearl" } + }, + args: { + layout: "choicesjs" + }, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "text" + }, + size: { + control: "radio", + options: ["small", "normal"] + }, + layout: { + control: "radio", + options: ["html5", "choicesjs", "react"] + }, + placeholder: { + control: "text" + }, + options: { + control: "object" + }, + onChange: { + action: "onChange" + } + }, + tags: ["autodocs"], + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { value, onChange } = useValue(args); + + return ( +
+ + ); +} + +registerComponent("Select.choicesjs", ChoiceSelect); diff --git a/packages/react-formio/src/molecules/forms/select/components/HtmlSelect.stories.tsx b/packages/react-formio/src/molecules/forms/select/components/HtmlSelect.stories.tsx new file mode 100644 index 00000000..6a33ce2a --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/components/HtmlSelect.stories.tsx @@ -0,0 +1,305 @@ +import "./HtmlSelect"; + +import { Meta, StoryObj } from "@storybook/react"; +import { expect, fn, userEvent, within } from "@storybook/test"; + +import { iconClass } from "../../../../utils/iconClass"; +import { useValue } from "../../../__fixtures__/useValue.hook"; +import { Select } from "../Select"; + +const options = [ + { + label: "Option 1", + value: "option-1" + }, + { + label: "Option 2", + value: "option-2" + }, + { + label: "Option 3", + value: "option-3" + } +]; +/** + * HTML5 select component. + * + * ```tsx + * import {Select} from "@tsed/react-formio/molecules/forms/select/all"; // import HTML5, ChoicesJS and React components + * + * // or + * import {Select} from "@tsed/react-formio/molecules/forms/select/Select"; + * import "@tsed/react-formio/molecules/forms/select/components/HtmlSelect"; // register only HTML5 component + * + * ``` + */ +export default { + title: "forms/Select/Html5", + component: Select, + parameters: { + layout: "centered", + backgrounds: { default: "pearl" } + }, + args: {}, + argTypes: { + label: { + control: "text" + }, + name: { + control: "text" + }, + value: { + control: "select", + options: ["option-1", "option-2", "option-3"] + }, + size: { + control: "radio", + options: ["small", "normal"] + }, + layout: { + control: "select", + options: ["html5", "choicesjs", "react"] + }, + placeholder: { + control: "text" + }, + options: { + control: "object" + }, + onChange: { + action: "onChange" + } + }, + tags: ["autodocs"], + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { value, onChange } = useValue(args); + + return ( +
+ { + onChange && onChange(name, getEventValue(event)); + }} + > + {placeholder && !multiple && ( + + )} + {hasGroup + ? options.map(({ label, options }) => { + return ( + + {options.map((props: SelectOptionBaseProps) => { + return + ); + }) + : (options as SelectOptionBaseProps[]).map((props) => { + return