├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .np-config.json ├── .npmignore ├── .vscode ├── launch.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docker-compose.yml ├── notes.txt ├── package.json ├── rollup.config.js ├── src ├── docs │ ├── config │ │ └── config.js │ └── vx │ │ ├── Area.txt │ │ ├── Bar.txt │ │ ├── BarGroup.txt │ │ ├── BarGroupMultiDim.txt │ │ ├── Combo.txt │ │ ├── Line.txt │ │ ├── Multi.txt │ │ ├── MultiDin.txt │ │ ├── Scatter.mdx │ │ └── XYChart.mdx └── lib │ ├── components │ ├── Area │ │ ├── Area.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Bar │ │ ├── Bar.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Box │ │ ├── Box.jsx │ │ ├── StyledBox.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Button │ │ ├── Button.jsx │ │ ├── ButtonTheme.jsx │ │ ├── StyledButton.jsx │ │ ├── __tests__ │ │ │ └── Button.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Combo │ │ ├── Combo.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── CurrentSelections │ │ ├── CurrentSelections.jsx │ │ ├── SelectionsTheme.jsx │ │ ├── StyledSelections.jsx │ │ ├── __tests__ │ │ │ ├── CurrentSelections.test.jsx │ │ │ └── MultipleSelections.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Filter │ │ ├── DropdownList.jsx │ │ ├── Filter.jsx │ │ ├── FilterListItem.jsx │ │ ├── FilterTheme.jsx │ │ ├── StyledFilter.jsx │ │ ├── __tests__ │ │ │ ├── Dropdown.test.jsx │ │ │ └── Filter.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Grid │ │ ├── Grid.jsx │ │ ├── StyledGrid.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── KPI │ │ ├── KPI.jsx │ │ ├── KPITheme.jsx │ │ ├── StyledKPI.jsx │ │ ├── __tests__ │ │ │ └── KPI.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Line │ │ ├── Line.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Login │ │ ├── Login.jsx │ │ ├── LoginTheme.jsx │ │ ├── StyledLogin.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Menu │ │ ├── Menu.jsx │ │ ├── MenuTheme.jsx │ │ └── index.js │ ├── Modal │ │ ├── Modal.jsx │ │ ├── ModalTheme.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Motor │ │ ├── Motor.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── NavItem │ │ ├── NavItem.jsx │ │ ├── NavItemTheme.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── NotConnected │ │ ├── NotConnected.jsx │ │ ├── NotConnectedTheme.jsx │ │ ├── StyledNotConnected.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── QlikObject │ │ ├── QlikObject.jsx │ │ ├── QlikObjectTheme.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── QlikSelections │ │ ├── QlikSelections.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Scatter │ │ ├── Scatter.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Search │ │ ├── SearchBar.jsx │ │ ├── SearchTheme.jsx │ │ ├── StyledSearch.jsx │ │ ├── Suggestions.jsx │ │ ├── __tests__ │ │ │ └── SearchBar.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── SelectionModal │ │ ├── SelectionModal.jsx │ │ ├── SelectionModalTheme.jsx │ │ ├── StyledSelectionModal.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Sidebar │ │ ├── SideBarTheme.jsx │ │ ├── Sidebar.jsx │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── menuFactory.js │ │ ├── menus │ │ │ ├── bubble.js │ │ │ ├── elastic.js │ │ │ ├── fallDown.js │ │ │ ├── index.js │ │ │ ├── push.js │ │ │ ├── pushRotate.js │ │ │ ├── reveal.js │ │ │ ├── scaleDown.js │ │ │ ├── scaleRotate.js │ │ │ ├── slide.js │ │ │ └── stack.js │ │ ├── snapsvgImporter.js │ │ ├── styles.css │ │ └── utils.js │ ├── SidebarLegacy │ │ ├── SidebarLegacy.jsx │ │ ├── StyledSidebarLegacy.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── SidebarNext │ │ ├── SideBarTheme.jsx │ │ ├── SidebarNext.jsx │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── menuFactory.js │ │ ├── menus │ │ │ ├── bubble.js │ │ │ ├── elastic.js │ │ │ ├── fallDown.js │ │ │ ├── index.js │ │ │ ├── push.js │ │ │ ├── pushRotate.js │ │ │ ├── reveal.js │ │ │ ├── scaleDown.js │ │ │ ├── scaleRotate.js │ │ │ ├── slide.js │ │ │ └── stack.js │ │ ├── snapsvgImporter.js │ │ ├── styles.css │ │ └── utils.js │ ├── SmartHeading │ │ ├── HeadingTheme.jsx │ │ ├── SmartHeading.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Spinner │ │ ├── Spinner.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── Table │ │ ├── StyledTable.jsx │ │ ├── Table.jsx │ │ ├── TableBody.jsx │ │ ├── TableHeader.jsx │ │ ├── TableTheme.jsx │ │ ├── __tests__ │ │ │ └── Table.test.jsx │ │ ├── index.d.ts │ │ └── index.js │ ├── XYChart │ │ ├── CreateXYChart.jsx │ │ ├── CustomChartBackground.jsx │ │ ├── CustomChartPattern.jsx │ │ ├── StyledXYChart.jsx │ │ ├── XYChart.jsx │ │ ├── XYChartTheme.jsx │ │ ├── index.d.ts │ │ └── index.js │ └── visx │ │ ├── classes │ │ └── DataRegistry.ts │ │ ├── components │ │ ├── XYChart.tsx │ │ ├── axis │ │ │ ├── AnimatedAxis.tsx │ │ │ ├── Axis.tsx │ │ │ └── BaseAxis.tsx │ │ ├── brush │ │ │ ├── BaseBrush.tsx │ │ │ ├── Brush.tsx │ │ │ ├── BrushCorner.tsx │ │ │ ├── BrushHandle.tsx │ │ │ ├── BrushSelection.tsx │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── grid │ │ │ ├── AnimatedGrid.tsx │ │ │ ├── BaseGrid.tsx │ │ │ └── Grid.tsx │ │ ├── legend │ │ │ └── Legend.tsx │ │ ├── series │ │ │ ├── AnimatedAreaSeries.tsx │ │ │ ├── AnimatedBarGroup.tsx │ │ │ ├── AnimatedBarSeries.tsx │ │ │ ├── AnimatedBarStack.tsx │ │ │ ├── AnimatedGlyphSeries.tsx │ │ │ ├── AnimatedLineSeries.tsx │ │ │ ├── AreaSeries.tsx │ │ │ ├── BarGroup.tsx │ │ │ ├── BarSeries.tsx │ │ │ ├── BarStack.tsx │ │ │ ├── GlyphSeries.tsx │ │ │ ├── LineSeries.tsx │ │ │ └── private │ │ │ │ ├── AnimatedBars.tsx │ │ │ │ ├── AnimatedGlyphs.tsx │ │ │ │ ├── AnimatedPath.tsx │ │ │ │ ├── Bars.tsx │ │ │ │ ├── BaseAreaSeries.tsx │ │ │ │ ├── BaseBarGroup.tsx │ │ │ │ ├── BaseBarSeries.tsx │ │ │ │ ├── BaseBarStack.tsx │ │ │ │ ├── BaseGlyphSeries.tsx │ │ │ │ ├── BaseLineSeries.tsx │ │ │ │ └── defaultRenderGlyph.tsx │ │ ├── titles │ │ │ ├── Title.tsx │ │ │ └── TitleTheme.tsx │ │ └── tooltip │ │ │ └── Tooltip.tsx │ │ ├── context │ │ ├── DataContext.tsx │ │ ├── EventEmitterContext.tsx │ │ └── TooltipContext.tsx │ │ ├── enhancers │ │ └── withRegisteredData.tsx │ │ ├── hooks │ │ ├── useDataRegistry.ts │ │ ├── useDimensions.ts │ │ ├── useEventEmitter.ts │ │ └── useScales.ts │ │ ├── index.ts │ │ ├── providers │ │ ├── DataProvider.tsx │ │ ├── EventEmitterProvider.tsx │ │ └── TooltipProvider.tsx │ │ ├── theme │ │ ├── buildChartTheme.ts │ │ ├── createColorArray.ts │ │ └── themes │ │ │ └── theme.ts │ │ ├── typeguards │ │ ├── isChildWithProps.ts │ │ ├── isDefined.ts │ │ └── isValidNumber.ts │ │ ├── types │ │ ├── data.ts │ │ ├── event.ts │ │ ├── index.ts │ │ ├── series.ts │ │ ├── theme.ts │ │ └── tooltip.ts │ │ └── utils │ │ ├── combineBarStackData.ts │ │ ├── findNearestDatumSingleDimension.ts │ │ ├── findNearestDatumX.ts │ │ ├── findNearestDatumXY.ts │ │ ├── findNearestDatumY.ts │ │ ├── findNearestStackDatum.ts │ │ ├── getBarStackRegistryData.ts │ │ ├── getScaleBandwidth.ts │ │ ├── getScaleBaseline.ts │ │ └── getScaledValueFactory.ts │ ├── contexts │ ├── ConfigProvider.jsx │ ├── EngineProvider.d.ts │ ├── EngineProvider.jsx │ └── ThemeProvider.jsx │ ├── default-props.d.ts │ ├── default-props.js │ ├── hooks │ ├── _useDataRegistry.js │ ├── _useRegisteredData.js │ ├── useCapability.d.ts │ ├── useCapability.jsx │ ├── useContextMenu.jsx │ ├── useEffectDebugger.jsx │ ├── useEngine.d.ts │ ├── useEngine.jsx │ ├── useHyperCube.d.ts │ ├── useHyperCube.jsx │ ├── useListObject.d.ts │ ├── useListObject.jsx │ ├── useMediaQuery.jsx │ ├── useModal.d.ts │ ├── useModal.jsx │ ├── useOutsideClick.jsx │ ├── useScreenSize.d.ts │ ├── useScreenSize.jsx │ ├── useSearch.d.ts │ ├── useSearch.jsx │ ├── useSelectionObject.d.ts │ ├── useSelectionObject.jsx │ ├── useSidebar.d.ts │ └── useSidebar.jsx │ ├── index.ts │ ├── themes │ ├── base.d.ts │ ├── base.jsx │ ├── colors │ │ ├── material-ui.css │ │ └── open-color.css │ ├── defaultTheme.jsx │ ├── index.ts │ ├── night.d.ts │ ├── night.jsx │ └── under development │ │ ├── archibald.jsx │ │ ├── classic.jsx │ │ ├── google.jsx │ │ ├── material-ui.jsx │ │ ├── nowalls.jsx │ │ ├── oldColors.jsx │ │ ├── powerbi.jsx │ │ ├── qlik.jsx │ │ └── tableau.jsx │ └── utils │ ├── CapApiUtils │ ├── ConnectCapAPI.js │ ├── Preloader.jsx │ ├── Tooltip.js │ ├── Uid.js │ └── index.js │ ├── RoundNum.js │ ├── calcDisplayOption.js │ ├── colorByExpression.js │ ├── colors.js │ ├── componentWidth.js │ ├── exportData.js │ ├── hexToRgb.js │ ├── hyperCubeUtilities.js │ ├── index.d.ts │ ├── index.js │ ├── isDefined.js │ ├── legendPosition.js │ ├── lodash │ ├── .internal │ │ ├── freeGlobal.js │ │ ├── getTag.js │ │ ├── isPrototype.js │ │ ├── nodeTypes.js │ │ └── root.js │ ├── index.js │ ├── isArguments.js │ ├── isArrayLike.js │ ├── isBuffer.js │ ├── isEmpty.js │ ├── isLength.js │ ├── isNull.js │ ├── isObjectLike.js │ ├── isString.js │ └── isTypedArray.js │ ├── object.js │ ├── selectDrag │ ├── createSelectable.js │ ├── doObjectsCollide.js │ ├── getBoundsForNode.js │ ├── index.js │ ├── isNodeIn.js │ ├── nodeInRoot.js │ └── selectable-group.js │ ├── styles.js │ └── valueIfUndefined.js ├── static ├── m_icon.png ├── motor.png └── motor_red.png └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | .git 2 | .npmrc 3 | .yarnrc 4 | build 5 | dist 6 | node_modules 7 | coverage 8 | config 9 | styleguide 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | # coverage 10 | dist 11 | .rpt2_cache 12 | 13 | # misc 14 | .DS_Store 15 | .env 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # coverage 26 | package-lock.json 27 | 28 | # docz 29 | .docz 30 | .docz/.cache 31 | 32 | 33 | -------------------------------------------------------------------------------- /.np-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests": false 3 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | ._* 3 | .DS_Store 4 | .git 5 | .gitlab-ci* 6 | .hg 7 | .npmrc 8 | .lock-wscript 9 | .svn 10 | .wafpickle-* 11 | .travis.yml 12 | .editorconfig 13 | .eslint* 14 | .yarnrc 15 | 16 | config.gypi 17 | CVS 18 | npm-debug.log 19 | 20 | yarn-debug.log* 21 | yarn-error.log* 22 | default.config 23 | rollup.config.js 24 | 25 | 26 | docker* 27 | Docker* 28 | 29 | coverage 30 | config 31 | demo 32 | public 33 | src 34 | scripts 35 | styleguide* 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[typescriptreact]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Motor Logo](./static/motor.png) 2 | 3 | # Note, we are no longer supporting this package, please use @motor-js/engine & @motor-js/nebula. 4 | 5 | # The React Framework for Qlik Sense Mashups 6 | 7 | Motor JS consists of charts, components and utilities for the 8 | rapid creation of custom dashboards off the Qlik engine. 9 | 10 | - Official website: www.motor.so 11 | - Docs: https://docs.motor.so 12 | - Community: https://discord.gg/jmjx78N59b 13 | - Starter Template: https://github.com/motor-js/motor-starter 14 | 15 | ## Quick Start 16 | 17 | ### Get Started via NPM 18 | 19 | npm install @motor-js/core 20 | 21 | ## Feature Overview 22 | 23 | - Charts, Components and Utilities for Qlik Sense Mashups 24 | - Easy theming 25 | - Reusable hooks 26 | - Support for TypeScript and React 27 | - Built using Qlik's Engine API 28 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | engine: 5 | image: qlikcore/engine:12.725.0 6 | restart: always 7 | command: -S AcceptEULA=${ACCEPT_EULA} 8 | ports: 9 | - "19077:9076" 10 | volumes: 11 | - ./data:/data 12 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | && NODE_ENV=production BABEL_ENV=production rollup -c 2 | 3 | pre-release old: npm run lint:fix && npm run test:coverage 4 | 5 | 6 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from "rollup-plugin-babel"; 2 | import commonjs from "rollup-plugin-commonjs"; 3 | import external from "rollup-plugin-peer-deps-external"; 4 | import postcss from "rollup-plugin-postcss"; 5 | import resolve from "@rollup/plugin-node-resolve"; 6 | import url from "@rollup/plugin-url"; 7 | import svgr from "@svgr/rollup"; 8 | import { terser } from "rollup-plugin-terser"; 9 | import typescript from "rollup-plugin-typescript2"; 10 | 11 | export default [ 12 | { 13 | input: "src/lib/index.ts", 14 | output: [ 15 | { 16 | file: "dist/index.js", 17 | format: "cjs", 18 | sourcemap: true, 19 | }, 20 | { 21 | file: "dist/index.es.js", 22 | format: "es", 23 | sourcemap: true, 24 | }, 25 | ], 26 | plugins: [ 27 | typescript({ 28 | typescript: require("typescript"), 29 | }), 30 | postcss({ 31 | plugins: [], 32 | minimize: false, 33 | sourceMap: "inline", 34 | }), 35 | external({ 36 | includeDependencies: true, 37 | }), 38 | url(), 39 | svgr(), 40 | resolve({ extensions: [".jsx", ".js", ".ts"] }), 41 | babel({ 42 | presets: ["react-app"], 43 | plugins: [ 44 | "@babel/plugin-proposal-object-rest-spread", 45 | "@babel/plugin-proposal-optional-chaining", 46 | "@babel/plugin-syntax-dynamic-import", 47 | "@babel/plugin-proposal-class-properties", 48 | "transform-react-remove-prop-types", 49 | ], 50 | exclude: "node_modules/**", 51 | runtimeHelpers: true, 52 | }), 53 | commonjs(), 54 | terser(), 55 | ], 56 | }, 57 | ]; 58 | -------------------------------------------------------------------------------- /src/docs/config/config.js: -------------------------------------------------------------------------------- 1 | export const config = { 2 | host: 'juno-ui.eu.qlikcloud.com', 3 | secure: true, 4 | port: null, 5 | prefix: '', 6 | appId: 'f29964d4-0e59-48a2-8525-34dab9cd41e7', 7 | qcs: true, 8 | webIntId: '4Tx-ydWxSQEM_q1ajlYBVzGgVUVJUo-i', 9 | } 10 | 11 | /* 12 | export const config = { 13 | host: "localhost", 14 | secure: false, 15 | port: 19077, 16 | prefix: "", 17 | appId: "fd74489e-81c4-47ae-93b3-06ad49175b4e", 18 | // appId: "ac09dd54-6bc5-45fe-bb95-ad6f329737be", 19 | }; 20 | 21 | /* 22 | 23 | export const config = { 24 | host: 'sense-demo.qlik.com', 25 | secure: true, 26 | port: 443, 27 | prefix: '', 28 | appId:'372cbc85-f7fb-4db6-a620-9a5367845dce', 29 | } 30 | 31 | */ 32 | 33 | /* 34 | export const config = { 35 | host: "localhost", 36 | secure: false, 37 | port: 19077, 38 | prefix: "", 39 | appId: "a21862bc-0e9a-4a16-938c-fe3d03209f4a", 40 | }; 41 | */ 42 | 43 | // export const config = { 44 | // host: 'localhost', 45 | // secure: false, 46 | // port: 19077, 47 | // prefix: '', 48 | // appId: '02e868df-bbb3-4733-9786-b69edccf4218', 49 | // }; 50 | -------------------------------------------------------------------------------- /src/docs/vx/Area.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: Area 3 | route: /area 4 | menu: visx 5 | --- 6 | 7 |

Area Chart

8 | 9 |
10 | 11 | Here is a bar chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Area from '../../lib/components/Area/Area.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/docs/vx/Bar.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bar 3 | route: /bar 4 | menu: visx 5 | --- 6 | 7 |

Bar Chart

8 | 9 |
10 | 11 | Here is a bar chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Bar from '../../lib/components/Bar/Bar.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/docs/vx/BarGroup.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: BarGroup 3 | route: /bargroup 4 | menu: visx 5 | --- 6 | 7 |

Bar Chart

8 | 9 |
10 | 11 | Here is a bar chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Bar from '../../lib/components/Bar/Bar.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/docs/vx/BarGroupMultiDim.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: BarGroupMultiDim 3 | route: /bargroupmultidim 4 | menu: visx 5 | --- 6 | 7 |

Bar Chart

8 | 9 |
10 | 11 | Here is a bar chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Bar from '../../lib/components/Bar/Bar.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/docs/vx/Combo.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: Combo 3 | route: /combo 4 | menu: visx 5 | --- 6 | 7 |

Combo Chart

8 | 9 |
10 | 11 | Here is a bar chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Combo from '../../lib/components/Combo/Combo.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/docs/vx/Line.txt: -------------------------------------------------------------------------------- 1 | --- 2 | name: Line 3 | route: /line 4 | menu: visx 5 | --- 6 | 7 |

LineChart

8 | 9 |
10 | 11 | Here is a line chart. 12 | Check out the props and example usage below 💡 13 | 14 | import { Props } from 'docz' 15 | import { Playground } from 'docz' 16 | import Line from '../../lib/components/Line/Line.jsx' 17 | import Motor from '../../lib/components/Motor/Motor.jsx' 18 | import Filter from '../../lib/components/Filter/Filter.jsx' 19 | import Button from '../../lib/components/Button/Button.jsx' 20 | import { config } from '../config/config.js' 21 | 22 | 23 | 25 | 26 | 27 | 28 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/docs/vx/XYChart.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | name: XYChart 3 | route: /xychart 4 | menu: visx 5 | --- 6 | 7 |

XYChart

8 | 9 |
10 | 11 | import { Props } from 'docz' 12 | import { Playground } from 'docz' 13 | import Bar from '../../lib/components/Bar/Bar.jsx' 14 | import Line from '../../lib/components/Line/Line.jsx' 15 | import Motor from '../../lib/components/Motor/Motor.jsx' 16 | import Filter from '../../lib/components/Filter/Filter.jsx' 17 | import CurrentSelections from '../../lib/components/CurrentSelections/CurrentSelections.jsx' 18 | import Button from '../../lib/components/Button/Button.jsx' 19 | import { config } from '../config/config.js' 20 | 21 | 22 | 32 | 33 | 34 | 35 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/lib/components/Area/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface AreaProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | showAxis?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const Area: React.FC; 56 | 57 | export type AreaType = AreaProps; 58 | 59 | export default Area; 60 | -------------------------------------------------------------------------------- /src/lib/components/Area/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Area"; 2 | -------------------------------------------------------------------------------- /src/lib/components/Bar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface BarProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | showAxis?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const Bar: React.FC; 56 | 57 | export type BarType = BarProps; 58 | 59 | export default Bar; 60 | -------------------------------------------------------------------------------- /src/lib/components/Bar/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Bar' 2 | -------------------------------------------------------------------------------- /src/lib/components/Box/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | borderType, 4 | } from '../../../utils' 5 | 6 | export interface BoxProps { 7 | height?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string | {max?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string,min?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string}; 8 | width?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string | {max?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string,min?: "xxsmall" | "xsmall" | "small" | "medium" | "large" | "xlarge" | "xxlarge" | string}; 9 | margin?: string 10 | overflow?: "auto" | "hidden" | "scroll" | "visible" | {horizontal?: "auto" | "hidden" | "scroll" | "visible",vertical?: "auto" | "hidden" | "scroll" | "visible"} | string; 11 | backgroundColor?: string 12 | border?: borderType 13 | padding?: string 14 | align?: 'start' | 'center' | 'end'| 'baseline'| 'stretch' 15 | alignContent?: 'start' | 'center' | 'end' | 'between' | 'around' | 'stretch' 16 | justify?: 'around' | 'between' | 'center' | 'end' | 'evenly' | 'start' | 'stretch' 17 | justifyContent?: 'around' | 'between' | 'center' | 'end' | 'start' | 'stretch' 18 | direction?: 'row' | 'column' | 'row-responsive' | 'row-reverse' | 'column-reverse' 19 | flex?: boolean | 'grow' | 'shrink' | { grow: number, shrink: number } 20 | focusable?: boolean 21 | basis?: string 22 | wrapProp?: boolean | 'reverse' 23 | elevation?: string, 24 | onClick?: () => {} 25 | gridArea?: string, 26 | } 27 | 28 | declare const Box: React.FC; 29 | 30 | export type BoxType = BoxProps 31 | 32 | export default Box 33 | -------------------------------------------------------------------------------- /src/lib/components/Box/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Box' -------------------------------------------------------------------------------- /src/lib/components/Button/__tests__/Button.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | fireEvent, 5 | cleanup, 6 | waitForElement, 7 | waitForDomChange, 8 | } from '@testing-library/react' 9 | import '@testing-library/jest-dom' 10 | // import { renderHook, act } from '@testing-library/react-hooks' 11 | import Button from '../Button' 12 | 13 | afterEach(cleanup) 14 | 15 | describe('Button test', () => { 16 | it('renders with title', () => { 17 | const { getByRole } = render() 18 | expect(getByRole('button')).toHaveTextContent('Test') 19 | }) 20 | 21 | it('captures clicks', done => { 22 | function handleClick() { 23 | done() 24 | } 25 | const { getByText } = render( 26 | , 27 | ) 28 | const node = getByText('Test') 29 | fireEvent.click(node) 30 | }) 31 | }) 32 | 33 | -------------------------------------------------------------------------------- /src/lib/components/Button/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface ButtonProps { 8 | config?: configType, 9 | type: 'clearSelections' | 'back' | 'forward' | 'default'; 10 | block?: boolean, 11 | onClick?: () => void, 12 | size?: sizeType, 13 | color?: string, 14 | margin?: string, 15 | width?: string, 16 | fontColor?: string, 17 | borderRadius?: string, 18 | border?: string, 19 | outline?: string, 20 | activeTransform?: string, 21 | activeBackgroundColor?: string, 22 | activeBackgroundSize?: string, 23 | activeTransition?: string, 24 | transition?: string, 25 | hoverBoxShadow?: string, 26 | hoverBorder?: string, 27 | hoverBackground?: string 28 | } 29 | 30 | declare const Button: React.FC; 31 | 32 | export type ButtonType = ButtonProps 33 | 34 | export default Button 35 | -------------------------------------------------------------------------------- /src/lib/components/Button/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Button' -------------------------------------------------------------------------------- /src/lib/components/Combo/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface ComboProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | showAxis?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const Combo: React.FC; 56 | 57 | export type ComboType = ComboProps; 58 | 59 | export default Combo; 60 | -------------------------------------------------------------------------------- /src/lib/components/Combo/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Combo' 2 | -------------------------------------------------------------------------------- /src/lib/components/CurrentSelections/CurrentSelections.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/rules-of-hooks */ 2 | import React, { useContext } from "react"; 3 | import PropTypes from "prop-types"; 4 | import StyledSelections from "./StyledSelections"; 5 | import { EngineContext } from "../../contexts/EngineProvider"; 6 | 7 | function CurrentSelections({ ...rest }) { 8 | const { engine } = useContext(EngineContext); 9 | 10 | return ; 11 | } 12 | 13 | // toggleList(item.field)}> {} 14 | CurrentSelections.propTypes = { 15 | /** Size of the selections box */ 16 | size: PropTypes.oneOf(["tiny", "small", "medium", "large", "xlarge"]), 17 | /** Width of the selections box */ 18 | width: PropTypes.string, 19 | /** Max width of the selections box */ 20 | maxWidth: PropTypes.string, 21 | /** Set margin */ 22 | margin: PropTypes.string, 23 | /** Set max height */ 24 | maxHeight: PropTypes.string, 25 | /** Set min height */ 26 | minHeight: PropTypes.string, 27 | /** Number of selections the object will 28 | * display per dimension, 29 | * before values are grouped */ 30 | selectionsLimit: PropTypes.oneOf([1, 2, 3, 4, 5]), 31 | /* set overflow properties on the x-axis or y-axis */ 32 | overflow: PropTypes.oneOf(["x-axis", "y-axis"]), 33 | flex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 34 | /** Name of the parent grid area to place the box */ 35 | gridArea: PropTypes.string, 36 | }; 37 | 38 | CurrentSelections.defaultProps = { 39 | size: "medium", 40 | width: "100%", 41 | maxWidth: null, 42 | margin: null, 43 | maxHeight: "80px", 44 | minHeight: "80px", 45 | selectionsLimit: 3, 46 | overflow: "x-axis", 47 | flex: null, 48 | gridArea: null, 49 | }; 50 | 51 | export default CurrentSelections; 52 | -------------------------------------------------------------------------------- /src/lib/components/CurrentSelections/__tests__/CurrentSelections.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | cleanup, 5 | fireEvent, 6 | } from '@testing-library/react' 7 | import '@testing-library/jest-dom' 8 | import CurrentSelections from '../CurrentSelections' 9 | import SelectionObject from '../../../../hooks/useSelectionObject' 10 | 11 | jest.mock('../../../../hooks/useSelectionObject') 12 | 13 | afterEach(cleanup) 14 | 15 | describe('Current Selections test', () => { 16 | it('renders with default text', () => { 17 | SelectionObject.mockReturnValue({ 18 | qLayout: { 19 | qSelectionInfo: {}, 20 | qSelectionObject: { 21 | qBackCount: 0, 22 | qForwardCount: 0, 23 | qSelections: [], 24 | }, 25 | }, 26 | }) 27 | 28 | const { getByTestId } = render() 29 | expect(getByTestId('selections')).toHaveTextContent('No current selections') 30 | }) 31 | 32 | it('renders with one selection', async () => { 33 | const clearSelections = jest.fn() 34 | SelectionObject.mockReturnValue({ 35 | qLayout: { 36 | qSelectionInfo: {}, 37 | qSelectionObject: { 38 | qBackCount: 0, 39 | qForwardCount: 0, 40 | qSelections: [{ 41 | qField: 'Dim', 42 | qSelected: 'Value', 43 | qSelectedFieldSelectionInfo: [{ 44 | qName: 'Value', 45 | }], 46 | qSelectedCount: 1, 47 | qTotal: 457, 48 | }], 49 | }, 50 | }, 51 | }) 52 | 53 | const { getByTestId } = render() 54 | expect(getByTestId('selectTitle')).toHaveTextContent('Dim:') 55 | expect(getByTestId('selectValue')).toHaveTextContent('Value') 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /src/lib/components/CurrentSelections/__tests__/MultipleSelections.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | cleanup, 5 | fireEvent, 6 | } from '@testing-library/react' 7 | import '@testing-library/jest-dom' 8 | import CurrentSelections from '../CurrentSelections' 9 | import SelectionObject from '../../../../hooks/useSelectionObject' 10 | 11 | jest.mock('../../../../hooks/useSelectionObject') 12 | 13 | afterEach(cleanup) 14 | 15 | describe('Multiple Selections', () => { 16 | it('renders multiple selections', () => { 17 | SelectionObject.mockReturnValue({ 18 | qLayout: { 19 | qSelectionInfo: {}, 20 | qSelectionObject: { 21 | qBackCount: 0, 22 | qForwardCount: 0, 23 | qSelections: [{ 24 | qField: 'Dim', 25 | qSelected: 'Value1, Value2, Value3', 26 | qSelectedFieldSelectionInfo: [{ 27 | qName: 'Value1', 28 | }, 29 | { 30 | qName: 'Value2', 31 | }, 32 | { 33 | qName: 'Value3', 34 | }], 35 | qSelectedCount: 3, 36 | qTotal: 457, 37 | }], 38 | }, 39 | }, 40 | }) 41 | 42 | const { getByTestId } = render() 43 | expect(getByTestId('selectValue')).toHaveTextContent('3 of 457') 44 | }) 45 | }) 46 | 47 | /* 48 | it('debug',() => { 49 | const { debug } = render( 50 | 55 | ) 56 | 57 | debug() 58 | }) 59 | */ 60 | 61 | -------------------------------------------------------------------------------- /src/lib/components/CurrentSelections/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface CurrentSelectionsProps { 8 | config?: configType 9 | size?: sizeType 10 | width?: string 11 | margin?: string 12 | maxHeight?: string 13 | minHeight?: string 14 | selectionsLimit?: 1 | 2 | 3 | 4 | 5 15 | overflow?: 'x-axis' | 'y-axis' 16 | } 17 | 18 | declare const CurrentSelections: React.FC; 19 | 20 | export type CurrentSelectionsType = CurrentSelectionsProps 21 | 22 | export default CurrentSelections 23 | -------------------------------------------------------------------------------- /src/lib/components/CurrentSelections/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './CurrentSelections' 2 | -------------------------------------------------------------------------------- /src/lib/components/Filter/Filter.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-template */ 2 | import React, { useContext } from "react"; 3 | import PropTypes from "prop-types"; 4 | import { ThemeContext } from "styled-components"; 5 | import StyledFilter from "./StyledFilter"; 6 | import defaultTheme from "../../themes/defaultTheme"; 7 | import { EngineContext } from "../../contexts/EngineProvider"; 8 | 9 | function Filter({ ...rest }) { 10 | const myTheme = useContext(ThemeContext) || defaultTheme; 11 | const { engine, engineError } = useContext(EngineContext); 12 | 13 | return ( 14 | 20 | ); 21 | } 22 | 23 | Filter.propTypes = { 24 | /** Filter label */ 25 | label: PropTypes.string.isRequired, 26 | /** Dimension from Qlik Data Model to render in the Filter */ 27 | dimension: PropTypes.array.isRequired, 28 | /** Size of the filter */ 29 | size: PropTypes.oneOf(["tiny", "small", "medium", "large", "xlarge"]), 30 | /** Filter width */ 31 | width: PropTypes.string, 32 | /** The height of the Filter drop down box */ 33 | dropHeight: PropTypes.string, 34 | /** The amount of margin around the component */ 35 | margin: PropTypes.string, 36 | /** Event handler fired when a selection is changed */ 37 | onSelectionChange: PropTypes.func, 38 | /** Event handler fired when the list box is searched */ 39 | onSearch: PropTypes.func, 40 | /** Option to enable only single selections in the Filter list */ 41 | single: PropTypes.bool, 42 | /** Option that sorts our Filter by selection state */ 43 | sortByState: PropTypes.bool, 44 | /** Add the Filter selections to the title */ 45 | selectionsTitle: PropTypes.bool, 46 | }; 47 | 48 | Filter.defaultProps = { 49 | config: null, 50 | width: "200px", 51 | size: "medium", 52 | dropHeight: "250px", 53 | margin: "5px", 54 | onSelectionChange: () => {}, 55 | onSearch: () => {}, 56 | single: false, 57 | sortByState: true, 58 | selectionsTitle: true, 59 | }; 60 | 61 | export default Filter; 62 | -------------------------------------------------------------------------------- /src/lib/components/Filter/FilterListItem.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StyledFilterListItem } from './FilterTheme' 3 | 4 | const FilterListItem = React.forwardRef(({ 5 | data, 6 | selectMultipleCallback, 7 | selectableKey, 8 | rowHeight, 9 | i, 10 | size, 11 | itemHeight, 12 | }, ref) => ( 13 | (selectMultipleCallback(data[0]))} 18 | rowHeight={rowHeight} 19 | i={i} 20 | size={size} 21 | itemHeight={itemHeight} 22 | selected={data[0].qState} 23 | > 24 | {data[0].qText} 25 | 26 | )) 27 | 28 | export default FilterListItem 29 | -------------------------------------------------------------------------------- /src/lib/components/Filter/__tests__/Dropdown.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | cleanup, 5 | fireEvent, 6 | } from '@testing-library/react' 7 | import '@testing-library/jest-dom' 8 | import Filter from '../Filter' 9 | import useListObject from '../../../../hooks/useListObject' 10 | 11 | jest.mock('../../../../hooks/useListObject') 12 | const { listobject } = require('qix-faker') 13 | 14 | // No testing currently for search box or select & drag 15 | 16 | afterEach(cleanup) 17 | 18 | const lo = listobject({ 19 | numRows: 10, 20 | dimension: d => d.name.firstName(), 21 | }) 22 | 23 | describe('Dropdown test', () => { 24 | useListObject.mockReturnValue({ 25 | qLayout: { qListObject: lo }, 26 | qData: lo.qDataPages[0], 27 | selections: [], 28 | beginSelections: jest.fn(), 29 | select: jest.fn(), 30 | searchListObjectFor: jest.fn(), 31 | acceptListObjectSearch: jest.fn(), 32 | endSelections: jest.fn(), 33 | changePage: jest.fn(), 34 | }) 35 | 36 | it('renders dropdown & handles selections', async () => { 37 | const { 38 | debug, 39 | container, 40 | getByText, 41 | getByTestId, 42 | findAllByTestId, 43 | } = render( 44 | , 50 | ) 51 | 52 | // dropdown toggle 53 | fireEvent.click(getByText('Province')) 54 | const items = await findAllByTestId('items') 55 | expect(items).toHaveLength(10) 56 | 57 | // selections 58 | const dropdown = await getByTestId('dropdown') 59 | const selectable = await container.querySelector('#selectableItem-0') 60 | fireEvent.click(dropdown) 61 | fireEvent.click(selectable) 62 | 63 | // search 64 | const search = getByTestId('dd-search') 65 | expect(search.value).toBe('') 66 | 67 | // close listbox & end selections 68 | fireEvent.click(document) 69 | // const noItems = findAllByTestId('items') 70 | // expect(noItems).toBe({}) 71 | }) 72 | }) 73 | 74 | -------------------------------------------------------------------------------- /src/lib/components/Filter/__tests__/Filter.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | cleanup, 5 | fireEvent, 6 | } from '@testing-library/react' 7 | import '@testing-library/jest-dom' 8 | import Filter from '../Filter' 9 | import useListObject from '../../../../hooks/useListObject' 10 | 11 | jest.mock('../../../../hooks/useListObject') 12 | const { listobject } = require('qix-faker') 13 | 14 | afterEach(cleanup) 15 | 16 | const lo = listobject({ 17 | numRows: 10, 18 | dimension: d => d.name.firstName(), 19 | }) 20 | 21 | // console.log(lo.qDataPages[0].qMatrix) 22 | describe('Filter test', () => { 23 | useListObject.mockReturnValue({ 24 | qLayout: { qListObject: lo }, 25 | qData: lo.qDataPages[0], 26 | selections: [], 27 | beginSelections: jest.fn(), 28 | }) 29 | 30 | const label = 'Province' 31 | const dimension = 'province' 32 | 33 | it('renders with a label', () => { 34 | const { getByTestId } = render( 35 | , 39 | ) 40 | expect(getByTestId('filterTitle')).toHaveTextContent('Province') 41 | }) 42 | 43 | it('renders with a label when selectionsTitle={false}', () => { 44 | const { getByTestId } = render( 45 | , 50 | ) 51 | expect(getByTestId('filterTitleNoSel')).toHaveTextContent('Province') 52 | }) 53 | }) 54 | 55 | /* 56 | it('debug',() => { 57 | const { debug } = render( 58 | 63 | ) 64 | 65 | debug() 66 | }) 67 | */ 68 | 69 | -------------------------------------------------------------------------------- /src/lib/components/Filter/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface FilterProps { 8 | config?: configType 9 | label: string 10 | dimension?: Array 11 | size?: sizeType 12 | width?: string 13 | dropHeight?: string 14 | margin?: string 15 | onSelectionChange?: () => {} 16 | onSearch?: () => {} 17 | single?: boolean 18 | sortByState?: boolean 19 | selectionsTitle?: boolean 20 | } 21 | 22 | declare const Filter: React.FC; 23 | 24 | export type FilterType = FilterProps 25 | 26 | export default Filter 27 | -------------------------------------------------------------------------------- /src/lib/components/Filter/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Filter' 2 | -------------------------------------------------------------------------------- /src/lib/components/Grid/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface GridProps { 4 | areas?: {name?: string,start?: number[],end?: number[]}[] | string[][]; 5 | rows: Array 6 | columns: Array 7 | fill: boolean | 'horizontal' | 'vertical' 8 | overflow?: "auto" | "hidden" | "scroll" | "visible" | {horizontal?: "auto" | "hidden" | "scroll" | "visible",vertical?: "auto" | "hidden" | "scroll" | "visible"} | string; 9 | gap?: string 10 | backgroundColor?: string 11 | justify?: 'start' | 'center' | 'end' | 'stretch' 12 | justifyContent?: 'start'| 'center' | 'end' | 'between' | 'around' | 'stretch' 13 | align?: 'start' | 'center' | 'end' | 'stretch' 14 | alignContent?: 'start'| 'center'| 'end'| 'between'| 'around'| 'stretch' 15 | } 16 | 17 | declare const Grid: React.FC; 18 | 19 | export type GridType = GridProps 20 | 21 | export default Grid -------------------------------------------------------------------------------- /src/lib/components/Grid/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Grid' 2 | -------------------------------------------------------------------------------- /src/lib/components/KPI/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { 4 | configType, 5 | sizeType, 6 | calcCondType, 7 | borderType, 8 | } from '../../../utils' 9 | 10 | export interface KPIProps { 11 | config?: configType 12 | calcCondition?: calcCondType 13 | label?: string 14 | cols: Array 15 | margin?: string 16 | width?: string 17 | border?: borderType 18 | justifyContent?: 'flex-start' | 'center' | 'flex-end' 19 | textAlign?:'left' | 'center' | 'right' 20 | size?: sizeType 21 | roundNum?: boolean 22 | color?: string 23 | precision?: boolean 24 | labelColor?: string 25 | alignSelf?: 'flex-start' | 'center' | 'flex-end' 26 | padding?: string 27 | backgroundColor?: string 28 | maxWidth?: string 29 | responsive?: boolean 30 | onClick?: () => {} 31 | cursor?: string 32 | autoSizeValue?: boolean 33 | } 34 | 35 | declare const KPI: React.FC; 36 | 37 | export type KPIType = KPIProps 38 | 39 | export default KPI -------------------------------------------------------------------------------- /src/lib/components/KPI/index.js: -------------------------------------------------------------------------------- 1 | export { 2 | default, 3 | } 4 | from './KPI' 5 | -------------------------------------------------------------------------------- /src/lib/components/Line/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface LineProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | showAxis?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const Line: React.FC; 56 | 57 | export type LineType = LineProps; 58 | 59 | export default Line; 60 | -------------------------------------------------------------------------------- /src/lib/components/Line/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Line' 2 | -------------------------------------------------------------------------------- /src/lib/components/Login/Login.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { ThemeContext } from "styled-components"; 4 | import { ConfigContext } from "../../contexts/ConfigProvider"; 5 | import defaultTheme from "../../themes/defaultTheme"; 6 | import StyledLogin from "./StyledLogin"; 7 | import { EngineContext } from "../../contexts/EngineProvider"; 8 | import { LoginWrapper } from "./LoginTheme"; 9 | 10 | const Login = ({ config, ...rest }) => { 11 | const myConfig = config || useContext(ConfigContext); 12 | const myTheme = useContext(ThemeContext) || defaultTheme; 13 | const { errorCode } = useContext(EngineContext); 14 | 15 | return ( 16 | 17 | {myConfig && errorCode && ( 18 | 19 | )} 20 | 21 | ); 22 | }; 23 | 24 | Login.propTypes = { 25 | config: PropTypes.object, 26 | header: PropTypes.string, 27 | body: PropTypes.string, 28 | size: PropTypes.oneOf(["tiny", "small", "medium", "large", "xlarge"]), 29 | buttonText: PropTypes.string, 30 | backgroundColor: PropTypes.string, 31 | buttonFontColor: PropTypes.string, 32 | buttonColor: PropTypes.string, 33 | logo: PropTypes.string, 34 | logoHeight: PropTypes.string, 35 | logoWidth: PropTypes.string, 36 | }; 37 | 38 | Login.defaultProps = { 39 | config: null, 40 | logo: null, 41 | logoHeight: null, 42 | logoWidth: null, 43 | // header: 'Welcome to your motor js mashup', 44 | // body: 'Please log on to access your application', 45 | // size: 'medium', 46 | // buttonText: 'Login', 47 | // backgroundColor: 'white', 48 | // buttonFontColor: 'white', 49 | // buttonColor: 'brand', 50 | }; 51 | 52 | export default Login; 53 | -------------------------------------------------------------------------------- /src/lib/components/Login/LoginTheme.jsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import { globalStyle } from '../../utils/styles' 3 | import { defaultProps } from '../../default-props' 4 | 5 | const LoginOverlay = styled.div` 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | z-index: 1040; 10 | width: 100vw; 11 | height: 100vh; 12 | background-color: rgba(105,105,105,0.8); 13 | display: flex; 14 | ` 15 | 16 | const LoginBox = styled.div` 17 | display: flex; 18 | justify-content: center; 19 | flex-direction: column; 20 | position: relative; 21 | margin: 0.2; 22 | padding: 5px; 23 | background-color: ${props => props.color}; 24 | border: 1px solid gray; 25 | border-radius: 8px; 26 | width: 30%; 27 | min-width: 350px; 28 | top: 30%; 29 | left: 35%; 30 | align-self: flex-start; 31 | ` 32 | 33 | const LoginWrapper = styled.div` 34 | display: ${props => (props.errorCode === -1 ? '' : 'none')} 35 | ` 36 | 37 | const LoginHeader = styled.div` 38 | ${globalStyle}; 39 | padding: 0.6rem; 40 | font-size: ${props => props.theme.global.size.title[props.size]} 41 | ` 42 | 43 | const LoginText = styled.div` 44 | ${globalStyle}; 45 | padding: 0.6rem; 46 | ` 47 | 48 | LoginOverlay.defaultProps = {} 49 | Object.setPrototypeOf(LoginOverlay.defaultProps, defaultProps) 50 | 51 | LoginBox.defaultProps = {} 52 | Object.setPrototypeOf(LoginBox.defaultProps, defaultProps) 53 | 54 | LoginWrapper.defaultProps = {} 55 | Object.setPrototypeOf(LoginWrapper.defaultProps, defaultProps) 56 | 57 | LoginText.defaultProps = {} 58 | Object.setPrototypeOf(LoginText.defaultProps, defaultProps) 59 | 60 | LoginHeader.defaultProps = {} 61 | Object.setPrototypeOf(LoginHeader.defaultProps, defaultProps) 62 | 63 | export { 64 | LoginOverlay, 65 | LoginBox, 66 | LoginWrapper, 67 | LoginText, 68 | LoginHeader, 69 | } 70 | -------------------------------------------------------------------------------- /src/lib/components/Login/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface LoginProps { 8 | config?: configType 9 | header: React.ReactNode 10 | body: React.ReactNode 11 | size: sizeType 12 | buttonText: string 13 | backgroundColor: string 14 | buttonFontColor: string 15 | buttonColor: string 16 | } 17 | 18 | declare const Login: React.FC; 19 | 20 | export type LoginType = LoginProps 21 | 22 | export default Login 23 | -------------------------------------------------------------------------------- /src/lib/components/Login/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Login.jsx' 2 | -------------------------------------------------------------------------------- /src/lib/components/Menu/Menu.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import useContextMenu from '../../hooks/useContextMenu' 3 | import { 4 | StyledMenu, StyledListItem, StyledDownload, StyledFileDownload, 5 | } from './MenuTheme' 6 | 7 | const Menu = ({ outerRef, exportDataCallback, exportImageCallback, open }) => { 8 | const { xPos, yPos, menu } = useContextMenu(outerRef, open) 9 | 10 | if (menu) { 11 | return ( 12 | 18 | { exportDataCallback() }}> 19 | 20 | Export Data 21 | 22 | {/* } 23 | { exportImageCallback() }}> 24 | 25 | Export Image 26 | 27 | Export PDF\ 28 | */} 29 | 30 | ) 31 | } 32 | 33 | return <> 34 | } 35 | 36 | export default Menu 37 | 38 | Menu.propTypes = { 39 | 40 | } 41 | 42 | Menu.defaultProps = { 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/lib/components/Menu/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Menu.jsx' 2 | -------------------------------------------------------------------------------- /src/lib/components/Modal/ModalTheme.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { globalStyle } from "../../utils/styles"; 3 | import { defaultProps } from "../../default-props"; 4 | 5 | const ModalOverlay = styled.div` 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | z-index: 1040; 10 | width: 100vw; 11 | height: 100vh; 12 | background-color: rgba(105, 105, 105, 0.8); 13 | `; 14 | const ModalWrapper = styled.div` 15 | ${globalStyle}; 16 | position: fixed; 17 | z-index: ${(props) => props.zIndex}; 18 | background-color: white; 19 | width: ${(props) => props.width}; 20 | border-radius: 8px; 21 | box-shadow: 1px 1px 1px var(--oc-grey-6); 22 | left: ${(props) => (100 - props.numWidth) / 2}%; 23 | top: ${(props) => props.top}; 24 | box-sizing: border-box; 25 | `; 26 | 27 | const ModalMain = styled.div` 28 | position: relative; 29 | margin: 0.2; 30 | opacity: 1; 31 | padding: 24px; 32 | `; 33 | 34 | ModalOverlay.defaultProps = {}; 35 | Object.setPrototypeOf(ModalOverlay.defaultProps, defaultProps); 36 | 37 | ModalWrapper.defaultProps = {}; 38 | Object.setPrototypeOf(ModalWrapper.defaultProps, defaultProps); 39 | 40 | ModalMain.defaultProps = {}; 41 | Object.setPrototypeOf(ModalMain.defaultProps, defaultProps); 42 | 43 | /* 44 | const ModalHeader = styled.div` 45 | width: 100%; 46 | height: 60px; 47 | border-bottom: 1px solid var(--oc-gray-4); 48 | ` 49 | 50 | const ModalBody = styled.div` 51 | width: 100%; 52 | height: 100%; 53 | background-color: 'red'; 54 | ` 55 | 56 | const ModalFooter = styled.div` 57 | width: 100%; 58 | height: 40px; 59 | background-color: 'blue'; 60 | ` 61 | */ 62 | export { 63 | ModalWrapper, 64 | ModalOverlay, 65 | ModalMain, 66 | // ModalHeader, 67 | // ModalBody, 68 | // ModalFooter, 69 | }; 70 | -------------------------------------------------------------------------------- /src/lib/components/Modal/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface ModalProps { 4 | children: React.ReactNode 5 | footer: React.ReactNode 6 | header: React.ReactNode 7 | width: '10%' | '20%' | '30%' | '40%' | '50%' | '60%' | '70%' | '80%' | '90%' | '100%' | 8 | '10vw' | '20vw' | '30vw' | '40vw' | '50vw' | '60vw' | '70vw' | '80vw' | '90vw' | '10vw' 9 | zIndex: string 10 | } 11 | 12 | declare const Modal: React.FC; 13 | 14 | export type ModalType = ModalProps 15 | 16 | export default Modal -------------------------------------------------------------------------------- /src/lib/components/Modal/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Modal' -------------------------------------------------------------------------------- /src/lib/components/Motor/Motor.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { ThemeContext } from '../../contexts/ThemeProvider' 3 | import { EngineContext } from '../../contexts/EngineProvider' 4 | import { ConfigContext } from '../../contexts/ConfigProvider' 5 | import { deepMerge } from '../../utils/object' 6 | import defaultTheme from '../../themes/defaultTheme' 7 | import Login from '../Login' 8 | import NotConnected from '../NotConnected' 9 | import useEngine from '../../hooks/useEngine' 10 | 11 | function Motor({ 12 | children, theme, config, logo, logoWidth, logoHeight, capabilityAPI, 13 | }) { 14 | const [myTheme, setMyTheme] = useState(defaultTheme) 15 | const [myConfig, setMyConfig] = useState(config) 16 | const nextTheme = deepMerge(myTheme, theme) 17 | 18 | const engine = useEngine(myConfig, capabilityAPI) 19 | 20 | // eslint-disable-next-line react/react-in-jsx-scope 21 | return ( 22 | 23 | 24 | 25 | {} 26 | {} 27 | {children} 28 | 29 | 30 | 31 | ) 32 | } 33 | 34 | export default Motor 35 | -------------------------------------------------------------------------------- /src/lib/components/Motor/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | } from '../../../utils' 5 | 6 | export interface MotorProps { 7 | config: configType, 8 | children: React.ReactNode 9 | engine: Object, 10 | theme: Object, 11 | } 12 | 13 | declare const Motor: React.FC; 14 | 15 | export type MotorType = MotorProps 16 | 17 | export default Motor 18 | -------------------------------------------------------------------------------- /src/lib/components/Motor/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Motor'; 2 | -------------------------------------------------------------------------------- /src/lib/components/NavItem/NavItemTheme.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { globalStyle, borderStyle } from "../../utils/styles"; 3 | import { defaultProps } from "../../default-props"; 4 | import { selectColor } from "../../utils/colors"; 5 | 6 | // size to be added 7 | // bordre to be added 8 | const StyledNavItem = styled.div` 9 | ${globalStyle}; 10 | ${(props) => 11 | props.border && 12 | props.border !== "none" && 13 | (Array.isArray(props.border, props.theme) 14 | ? props.border.map((border) => 15 | borderStyle(border, props.theme, "navitem") 16 | ) 17 | : borderStyle(props.border, props.theme, "navitem"))}; 18 | text-align: ${(props) => props.textAlign || props.theme.navItem.textAlign}; 19 | margin-bottom: 0; /* Puts space between NavItems */ 20 | :hover { 21 | ${(props) => 22 | props.border ? props.border.hover : props.theme.navItem.border.hover}; 23 | 24 | background-color: ${(props) => 25 | selectColor( 26 | props.background 27 | ? props.background.color.hover 28 | : props.theme.navItem.background.color.hover, 29 | props.theme 30 | )}; 31 | color: white; 32 | } 33 | :focus { 34 | color: red; 35 | } 36 | a { 37 | color: ${(props) => 38 | props.active 39 | ? selectColor( 40 | props.color ? props.color.active : props.theme.navItem.color.active, 41 | props.theme 42 | ) 43 | : selectColor( 44 | props.color 45 | ? props.color.inactive 46 | : props.theme.navItem.color.inactive, 47 | props.theme 48 | )}; 49 | text-decoration: none; /* Gets rid of underlining of text */ 50 | :hover { 51 | opacity: 0.7; 52 | } 53 | } 54 | `; 55 | 56 | StyledNavItem.defaultProps = {}; 57 | Object.setPrototypeOf(StyledNavItem.defaultProps, defaultProps); 58 | 59 | export { StyledNavItem }; 60 | -------------------------------------------------------------------------------- /src/lib/components/NavItem/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | sizeType, 4 | borderType 5 | } from '../../../utils' 6 | 7 | export interface NavItemProps { 8 | children?: React.ReactNode 9 | size?: sizeType 10 | responsive?: boolean 11 | color?: object 12 | background?: object 13 | textAlign?: string 14 | /** Border of the Pie Chart, need desc */ 15 | border?: borderType 16 | } 17 | 18 | declare const NavItem: React.FC; 19 | 20 | export type NavItemType = NavItemProps 21 | 22 | export default NavItem 23 | -------------------------------------------------------------------------------- /src/lib/components/NavItem/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./NavItem"; 2 | -------------------------------------------------------------------------------- /src/lib/components/NotConnected/NotConnected.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { ThemeContext } from "styled-components"; 4 | import { ConfigContext } from "../../contexts/ConfigProvider"; 5 | import defaultTheme from "../../themes/defaultTheme"; 6 | import StyledNotConnected from "./StyledNotConnected"; 7 | import { EngineContext } from "../../contexts/EngineProvider"; 8 | import useEngine from "../../hooks/useEngine"; 9 | import { NotConnectedWrapper } from "./NotConnectedTheme"; 10 | 11 | const NotConnected = ({ config, ...rest }) => { 12 | const myConfig = config || useContext(ConfigContext); 13 | const myTheme = useContext(ThemeContext) || defaultTheme; 14 | const { errorCode } = useContext(EngineContext) || useEngine(myConfig); 15 | 16 | return ( 17 | 18 | {myConfig && errorCode && ( 19 | 20 | )} 21 | 22 | ); 23 | }; 24 | 25 | NotConnected.propTypes = { 26 | header: PropTypes.string, 27 | body: PropTypes.string, 28 | size: PropTypes.oneOf(["tiny", "small", "medium", "large", "xlarge"]), 29 | buttonText: PropTypes.string, 30 | backgroundColor: PropTypes.string, 31 | buttonFontColor: PropTypes.string, 32 | buttonColor: PropTypes.string, 33 | }; 34 | 35 | export default NotConnected; 36 | -------------------------------------------------------------------------------- /src/lib/components/NotConnected/NotConnectedTheme.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { globalStyle } from "../../utils/styles"; 3 | import { defaultProps } from "../../default-props"; 4 | 5 | const NotConnectedOverlay = styled.div` 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | z-index: 1040; 10 | width: 100vw; 11 | height: 100vh; 12 | background-color: rgba(105, 105, 105, 0.8); 13 | display: flex; 14 | `; 15 | 16 | const NotConnectedBox = styled.div` 17 | display: flex; 18 | justify-content: center; 19 | flex-direction: column; 20 | position: relative; 21 | margin: 0.2; 22 | padding: 5px; 23 | background-color: ${(props) => props.color}; 24 | border: 1px solid gray; 25 | border-radius: 8px; 26 | width: 30%; 27 | min-width: 350px; 28 | top: 30%; 29 | left: 35%; 30 | align-self: flex-start; 31 | `; 32 | 33 | const NotConnectedWrapper = styled.div` 34 | display: ${(props) => (props.errorCode === -3 ? "" : "none")}; 35 | `; 36 | 37 | const NotConnectedHeader = styled.div` 38 | ${globalStyle}; 39 | padding: 0.8rem; 40 | font-size: ${(props) => props.theme.global.size.title[props.size]}; 41 | `; 42 | 43 | const NotConnectedText = styled.div` 44 | ${globalStyle}; 45 | padding: 0.6rem; 46 | `; 47 | 48 | NotConnectedOverlay.defaultProps = {}; 49 | Object.setPrototypeOf(NotConnectedOverlay.defaultProps, defaultProps); 50 | 51 | NotConnectedBox.defaultProps = {}; 52 | Object.setPrototypeOf(NotConnectedBox.defaultProps, defaultProps); 53 | 54 | NotConnectedWrapper.defaultProps = {}; 55 | Object.setPrototypeOf(NotConnectedWrapper.defaultProps, defaultProps); 56 | 57 | NotConnectedText.defaultProps = {}; 58 | Object.setPrototypeOf(NotConnectedText.defaultProps, defaultProps); 59 | 60 | NotConnectedHeader.defaultProps = {}; 61 | Object.setPrototypeOf(NotConnectedHeader.defaultProps, defaultProps); 62 | 63 | export { 64 | NotConnectedOverlay, 65 | NotConnectedBox, 66 | NotConnectedWrapper, 67 | NotConnectedText, 68 | NotConnectedHeader, 69 | }; 70 | -------------------------------------------------------------------------------- /src/lib/components/NotConnected/StyledNotConnected.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Button from "../Button"; 3 | import Box from "../Box"; 4 | 5 | import { 6 | NotConnectedOverlay, 7 | NotConnectedBox, 8 | NotConnectedHeader, 9 | NotConnectedText, 10 | } from "./NotConnectedTheme"; 11 | 12 | const StyledNotConnected = ({ 13 | header, 14 | body, 15 | size, 16 | buttonText, 17 | backgroundColor, 18 | buttonFontColor, 19 | buttonColor, 20 | theme, 21 | }) => { 22 | const { 23 | global: { notConnected }, 24 | } = theme; 25 | 26 | return ( 27 | 28 | 29 | 35 | 36 | {header || notConnected.header} 37 | 38 | 39 | 47 | 48 | {body || notConnected.body} 49 | 50 | 58 | 59 | 60 | 61 | ); 62 | }; 63 | 64 | export default StyledNotConnected; 65 | -------------------------------------------------------------------------------- /src/lib/components/NotConnected/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface LoginProps { 8 | config?: configType 9 | header: React.ReactNode 10 | body: React.ReactNode 11 | size: sizeType 12 | buttonText: string 13 | backgroundColor: string 14 | buttonFontColor: string 15 | buttonColor: string 16 | } 17 | 18 | declare const Login: React.FC; 19 | 20 | export type LoginType = LoginProps 21 | 22 | export default Login 23 | -------------------------------------------------------------------------------- /src/lib/components/NotConnected/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./NotConnected"; 2 | -------------------------------------------------------------------------------- /src/lib/components/QlikObject/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface QlikObjectProps { 4 | id?: string; 5 | type: string; 6 | cols: string; 7 | options: string; 8 | noSelections: string; 9 | noInteraction: string; 10 | width?: string; 11 | height?: string; 12 | border?: string 13 | minWidth: string; 14 | minHeight: string; 15 | exportData: string; 16 | exportDataTitle: string; 17 | exportDataOptions: string; 18 | exportImg: string; 19 | exportImgTitle: string; 20 | exportImgOptions: string; 21 | exportPdf: string; 22 | exportPdfTitle: string; 23 | exportPdfOptions: string; 24 | } 25 | 26 | declare const QlikObject: React.FC; 27 | 28 | export type QlikObjectType = QlikObjectProps; 29 | 30 | export default QlikObject; -------------------------------------------------------------------------------- /src/lib/components/QlikObject/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './QlikObject.jsx' 2 | -------------------------------------------------------------------------------- /src/lib/components/QlikSelections/QlikSelections.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect, useContext } from 'react' 2 | import PropTypes from "prop-types" 3 | import Spinner from '../Spinner' 4 | import { EngineContext } from "../../contexts/EngineProvider"; 5 | 6 | const QlikSelections = ({ 7 | height, 8 | width, 9 | border, 10 | }) => { 11 | const node = useRef(null) 12 | const { app } = useContext(EngineContext) 13 | 14 | useEffect(() => { 15 | if(app) { 16 | try { 17 | (async () => { 18 | app.getObject(node.current, 'CurrentSelections') 19 | })(); 20 | } catch (_error) { 21 | console.warn(_error); 22 | } 23 | } 24 | },[app]) 25 | 26 | return ( 27 |
28 | { app ? (
) : ()} 29 |
30 | ) 31 | 32 | } 33 | 34 | export default QlikSelections 35 | 36 | QlikSelections.propTypes = { 37 | height: PropTypes.string, 38 | width: PropTypes.string, 39 | border: PropTypes.string, 40 | } 41 | 42 | QlikSelections.defaultProps = { 43 | height: '38px', 44 | width: '100%', 45 | border: null, 46 | } -------------------------------------------------------------------------------- /src/lib/components/QlikSelections/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface QlikSelectionsProps { 4 | width?: string; 5 | height?: string; 6 | border?: string 7 | } 8 | 9 | declare const QlikSelections: React.FC; 10 | 11 | export type QlikSelectionsType = QlikSelectionsProps; 12 | 13 | export default QlikSelections; -------------------------------------------------------------------------------- /src/lib/components/QlikSelections/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './QlikSelections.jsx' 2 | -------------------------------------------------------------------------------- /src/lib/components/Scatter/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface BarProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | showAxis?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const Bar: React.FC; 56 | 57 | export type BarType = BarProps; 58 | 59 | export default Bar; 60 | -------------------------------------------------------------------------------- /src/lib/components/Scatter/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Bar' 2 | -------------------------------------------------------------------------------- /src/lib/components/Search/SearchBar.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { ThemeContext } from "styled-components"; 4 | import StyledSearch from "./StyledSearch"; 5 | import defaultTheme from "../../themes/defaultTheme"; 6 | import { EngineContext } from "../../contexts/EngineProvider"; 7 | 8 | const SearchBar = ({ ...rest }) => { 9 | const myTheme = useContext(ThemeContext) || defaultTheme; 10 | const { engine, engineError } = useContext(EngineContext); 11 | 12 | return ( 13 | 19 | ); 20 | }; 21 | 22 | SearchBar.propTypes = { 23 | /* list of dimensions to search for in the app, if left empty, all fields in the app are searched through */ 24 | dimensions: PropTypes.array, 25 | /* Size of the search bar */ 26 | size: PropTypes.oneOf(["tiny", "small", "medium", "large", "xlarge"]), 27 | /* Width of the search bar */ 28 | width: PropTypes.string, 29 | /* Margin around the search bar */ 30 | margin: PropTypes.string, 31 | /* Drop height of the search bar */ 32 | dropHeight: PropTypes.string, 33 | }; 34 | 35 | SearchBar.defaultProps = { 36 | dimensions: [], 37 | size: "medium", 38 | width: "100%", 39 | margin: "5px", 40 | dropHeight: "400px", 41 | }; 42 | 43 | export default SearchBar; 44 | -------------------------------------------------------------------------------- /src/lib/components/Search/__tests__/SearchBar.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | render, 4 | cleanup, 5 | fireEvent, 6 | } from '@testing-library/react' 7 | import '@testing-library/jest-dom' 8 | import StyledSearch from '../StyledSearch' 9 | import useSearch from '../../../../hooks/useSearch' 10 | import SearchTheme from '../SearchTheme' 11 | 12 | jest.mock('../../../../hooks/useSearch') 13 | 14 | describe('SearchBar test', () => { 15 | useSearch.mockReturnValue({ 16 | searchResults: { 17 | qSearchGroupArray: [{ 18 | qGroupType: 'DatasetType', 19 | qId: 0, 20 | qItems: [{ 21 | qIdentifier: 'Dim', 22 | qItemMatches: [{ qText: 'A' }], 23 | qItemType: 'Field', 24 | qSearchTermsMatched: [0], 25 | qTotalNumberOfMatches: 1, 26 | }], 27 | }], 28 | qSearchTerms: ['A'], 29 | qTotalNumberOfGroups: 0, 30 | }, 31 | select: jest.fn(), 32 | }) 33 | 34 | const { debug, getByTestId } = render() 35 | const search = getByTestId('search-bar') 36 | 37 | it('renders', () => { 38 | expect(search).toHaveTextContent('') 39 | fireEvent.change(search, { target: { value: 'search' } }) 40 | expect(search.value).toBe('search') 41 | }) 42 | 43 | it('accepts text input, returns suggestions and is selectabe', async () => { 44 | fireEvent.change(search, { target: { value: 'bor' } }) 45 | expect(search.value).toBe('bor') 46 | const selectable = await getByTestId('value-0') 47 | fireEvent.click(selectable) 48 | }) 49 | }) 50 | -------------------------------------------------------------------------------- /src/lib/components/Search/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | } from '../../../utils' 6 | 7 | export interface SearchProps { 8 | config?: configType 9 | dimensions: Array 10 | size: sizeType 11 | width: string 12 | margin: string 13 | dropHeight: string 14 | } 15 | 16 | declare const Search: React.FC; 17 | 18 | export type SearchType = SearchProps 19 | 20 | export default Search 21 | -------------------------------------------------------------------------------- /src/lib/components/Search/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SearchBar.jsx' 2 | -------------------------------------------------------------------------------- /src/lib/components/SelectionModal/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface SelectionModalProps { 4 | confirmCallback: () => {}; 5 | cancelCallback: () => {}; 6 | isOpen: boolean; 7 | margin: string; 8 | offset: number; 9 | width: string; 10 | buttonType: "icon" | "text"; 11 | hoverOpacityConfirm: string; 12 | bckgColorCancel: string; 13 | bckgColorConfirm: string; 14 | hoverOpacityCancel: string; 15 | borderColorConfirm: string; 16 | borderColorCancel: string; 17 | borderSizeConfirm: string; 18 | borderSizeCancel: string; 19 | borderStyleConfirm: string; 20 | borderStyleCancel: string; 21 | borderRadiusConfirm: string; 22 | borderRadiusCancel: string; 23 | colorConfirm: string; 24 | colorCancel: string; 25 | } 26 | 27 | declare const SelectionModal: React.FC; 28 | 29 | export type SelectionModalType = SelectionModalProps; 30 | 31 | export default SelectionModal; 32 | -------------------------------------------------------------------------------- /src/lib/components/SelectionModal/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SelectionModal' 2 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { ThemeContext } from "styled-components"; 3 | import defaultTheme from "../../themes/defaultTheme"; 4 | 5 | import { slide as SlideMenu } from "./menus"; 6 | import { stack as StackMenu } from "./menus"; 7 | // import { elastic as ElasticMenu } from "./menus"; // requires snapsvg-cjs in package,json : "snapsvg-cjs": "0.0.6" 8 | // import { bubble as BubbleMenu } from "./menus"; // requires snapsvg-cjs in package,json : "snapsvg-cjs": "0.0.6" 9 | import { push as PushMenu } from "./menus"; 10 | import { pushRotate as PushRotateMenu } from "./menus"; 11 | import { scaleDown as ScaleDownMenu } from "./menus"; 12 | import { scaleRotate as ScaleRotateMenu } from "./menus"; 13 | import { fallDown as FallDownMenu } from "./menus"; 14 | import { reveal as RevealMenu } from "./menus"; 15 | 16 | const Sidebar = (props) => { 17 | const theme = useContext(ThemeContext) || defaultTheme; 18 | 19 | return ( 20 | <> 21 | { 22 | { 23 | slide: {props.children}, 24 | stack: {props.children}, 25 | // elastic: {props.children}, 26 | // bubble: {props.children}, 27 | push: {props.children}, 28 | pushRotate: ( 29 | {props.children} 30 | ), 31 | scaleDown: {props.children}, 32 | scaleRotate: ( 33 | {props.children} 34 | ), 35 | fallDown: {props.children}, 36 | reveal: {props.children}, 37 | }[props.type || "slide"] 38 | } 39 | 40 | ); 41 | }; 42 | 43 | export default Sidebar; 44 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { borderType } from "../../utils"; 3 | 4 | export interface SidebarProps { 5 | backgroundColor?: string; 6 | border?: borderType; 7 | padding?: string; 8 | } 9 | 10 | declare const Sidebar: React.FC; 11 | 12 | export type SidebarType = SidebarProps; 13 | 14 | export default Sidebar; 15 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Sidebar"; 2 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/fallDown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | menuWrap(isOpen) { 7 | return { 8 | MozTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 9 | MsTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 10 | OTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 11 | WebkitTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 12 | transform: isOpen ? '' : 'translate3d(0, -100%, 0)', 13 | transition: 'all 0.5s ease-in-out' 14 | }; 15 | }, 16 | 17 | pageWrap(isOpen, width, right) { 18 | return { 19 | MozTransform: isOpen 20 | ? '' 21 | : right 22 | ? `translate3d(-${width}, 0, 0)` 23 | : `translate3d(${width}, 0, 0)`, 24 | MsTransform: isOpen 25 | ? '' 26 | : right 27 | ? `translate3d(-${width}, 0, 0)` 28 | : `translate3d(${width}, 0, 0)`, 29 | OTransform: isOpen 30 | ? '' 31 | : right 32 | ? `translate3d(-${width}, 0, 0)` 33 | : `translate3d(${width}, 0, 0)`, 34 | WebkitTransform: isOpen 35 | ? '' 36 | : right 37 | ? `translate3d(-${width}, 0, 0)` 38 | : `translate3d(${width}, 0, 0)`, 39 | transform: isOpen 40 | ? '' 41 | : right 42 | ? `translate3d(-${width}, 0, 0)` 43 | : `translate3d(${width}, 0, 0)`, 44 | transition: 'all 0.5s' 45 | }; 46 | }, 47 | 48 | outerContainer(isOpen) { 49 | return { 50 | perspective: '1500px', 51 | perspectiveOrigin: '0% 50%', 52 | overflow: isOpen ? '' : 'hidden' 53 | }; 54 | } 55 | }; 56 | 57 | export default menuFactory(styles); 58 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/index.js: -------------------------------------------------------------------------------- 1 | export { default as slide } from "./slide"; 2 | export { default as stack } from "./stack"; 3 | export { default as elastic } from "./elastic"; 4 | export { default as bubble } from "./bubble"; 5 | export { default as push } from "./push"; 6 | export { default as pushRotate } from "./pushRotate"; 7 | export { default as scaleDown } from "./scaleDown"; 8 | export { default as scaleRotate } from "./scaleRotate"; 9 | export { default as fallDown } from "./fallDown"; 10 | export { default as reveal } from "./reveal"; 11 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/push.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(-${width}, 0, 0)` 12 | : `translate3d(${width}, 0, 0)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(-${width}, 0, 0)` 17 | : `translate3d(${width}, 0, 0)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(-${width}, 0, 0)` 22 | : `translate3d(${width}, 0, 0)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(-${width}, 0, 0)` 27 | : `translate3d(${width}, 0, 0)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(-${width}, 0, 0)` 32 | : `translate3d(${width}, 0, 0)`, 33 | transition: 'all 0.5s' 34 | }; 35 | }, 36 | 37 | outerContainer(isOpen) { 38 | return { 39 | overflow: isOpen ? '' : 'hidden' 40 | }; 41 | } 42 | }; 43 | 44 | export default menuFactory(styles); 45 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/pushRotate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 12 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 17 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 22 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 27 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 32 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 33 | transformOrigin: right ? '100% 50%' : '0% 50%', 34 | transformStyle: 'preserve-3d', 35 | transition: 'all 0.5s' 36 | }; 37 | }, 38 | 39 | outerContainer(isOpen) { 40 | return { 41 | perspective: '1500px', 42 | overflow: isOpen ? '' : 'hidden' 43 | }; 44 | } 45 | }; 46 | 47 | export default menuFactory(styles); 48 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/scaleDown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width) { 7 | return { 8 | MozTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 9 | MsTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 10 | OTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 11 | WebkitTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 12 | transform: isOpen ? '' : `translate3d(0, 0, -${width})`, 13 | transformOrigin: '100%', 14 | transformStyle: 'preserve-3d', 15 | transition: 'all 0.5s' 16 | }; 17 | }, 18 | 19 | outerContainer() { 20 | return { 21 | perspective: '1500px' 22 | }; 23 | } 24 | }; 25 | 26 | export default menuFactory(styles); 27 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/scaleRotate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 12 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 17 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 22 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 27 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 32 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 33 | transformStyle: 'preserve-3d', 34 | transition: 'all 0.5s', 35 | overflow: isOpen ? '' : 'hidden' 36 | }; 37 | }, 38 | 39 | outerContainer(isOpen) { 40 | return { 41 | perspective: '1500px', 42 | overflow: isOpen ? '' : 'hidden' 43 | }; 44 | } 45 | }; 46 | 47 | export default menuFactory(styles); 48 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/slide.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = {}; 6 | 7 | export default menuFactory(styles); 8 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/menus/stack.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | menuWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(${width}, 0, 0)` 12 | : `translate3d(-${width}, 0, 0)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(${width}, 0, 0)` 17 | : `translate3d(-${width}, 0, 0)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(${width}, 0, 0)` 22 | : `translate3d(-${width}, 0, 0)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(${width}, 0, 0)` 27 | : `translate3d(-${width}, 0, 0)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(${width}, 0, 0)` 32 | : `translate3d(-${width}, 0, 0)`, 33 | transition: isOpen 34 | ? 'transform 0.8s cubic-bezier(0.7, 0, 0.3, 1)' 35 | : 'transform 0.4s cubic-bezier(0.7, 0, 0.3, 1)' 36 | }; 37 | }, 38 | 39 | item(isOpen, width, right, nthChild) { 40 | return { 41 | MozTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 42 | MsTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 43 | OTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 44 | WebkitTransform: isOpen 45 | ? '' 46 | : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 47 | transform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 48 | transition: isOpen 49 | ? 'transform 0.8s cubic-bezier(0.7, 0, 0.3, 1)' 50 | : 'transform 0s 0.2s cubic-bezier(0.7, 0, 0.3, 1)' 51 | }; 52 | } 53 | }; 54 | 55 | export default menuFactory(styles); 56 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/snapsvgImporter.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | let Snap; 3 | try { 4 | // Snap = require('snapsvg-cjs'); 5 | } finally { 6 | return Snap; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/styles.css: -------------------------------------------------------------------------------- 1 | #anchor { 2 | /* Give app full page to work with */ 3 | height: 100vh; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/lib/components/Sidebar/utils.js: -------------------------------------------------------------------------------- 1 | export const pxToNum = val => parseInt(val.slice(0, -2), 10); 2 | -------------------------------------------------------------------------------- /src/lib/components/SidebarLegacy/SidebarLegacy.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { 4 | StyledSidebarLegacy, 5 | SidebarLegacyOverlay, 6 | } from "./StyledSidebarLegacy"; 7 | import useOutsideClick from "../../hooks/useOutsideClick"; 8 | 9 | const SidebarLegacy = ({ 10 | children, 11 | isOpen, 12 | showOverlay, 13 | collapsable, 14 | width, 15 | onOutsideClick, 16 | ...rest 17 | }) => { 18 | const ref = useRef(); 19 | 20 | useOutsideClick(ref, () => { 21 | if (isOpen) { 22 | const outsideClick = !ref.current.contains(event.target); 23 | if (outsideClick) onOutsideClick(); 24 | } 25 | }); 26 | 27 | return ( 28 | <> 29 | 30 |
31 | 38 | {children} 39 | 40 |
41 | 42 | ); 43 | }; 44 | 45 | export default SidebarLegacy; 46 | 47 | SidebarLegacy.propTypes = { 48 | /** contents of the SidebarLegacy */ 49 | children: PropTypes.node, 50 | /** whether the SidebarLegacy is collapsable */ 51 | collapsable: PropTypes.bool, 52 | pullRight: PropTypes.bool, 53 | showOverlay: PropTypes.bool, 54 | width: PropTypes.string, 55 | }; 56 | 57 | SidebarLegacy.defaultProps = { 58 | children: undefined, 59 | collapsable: false, 60 | pullRight: false, 61 | showOverlay: true, 62 | width: "100%", 63 | }; 64 | -------------------------------------------------------------------------------- /src/lib/components/SidebarLegacy/StyledSidebarLegacy.jsx: -------------------------------------------------------------------------------- 1 | import styled, { css } from "styled-components"; 2 | import { defaultProps } from "../../default-props"; 3 | import Box from "../Box"; 4 | 5 | const collapsableStyle = css` 6 | position: absolute; 7 | top: 0; 8 | bottom: 0; 9 | left: ${({ pullRight }) => (pullRight ? null : 0)}; 10 | right: ${({ pullRight }) => (pullRight ? 0 : null)}; 11 | z-index: 999; 12 | width: ${(props) => props.width} 13 | transition: transform 0.3s ease-in-out; 14 | transform: ${({ open }) => (open ? "translateX(0)" : "translateX(-100%)")}; 15 | display: ${({ open }) => (open ? "flex" : "none")}; 16 | `; 17 | 18 | const StyledSidebarLegacy = styled(Box)` 19 | ${(props) => props.collapsable && collapsableStyle} 20 | `; 21 | 22 | const SidebarLegacyOverlay = styled.div` 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | z-index: 998; 27 | width: 100%; 28 | height: 100%; 29 | background-color: ${({ overlay }) => 30 | `rgba(105,105,105, ${overlay ? 0.3 : 0.0})`}; 31 | display: ${({ open }) => (open ? "block" : "none")}; 32 | `; 33 | 34 | // const SidebarLegacyOverlay = styled.div` 35 | // ${(props) => props.collapsable && overlayStyle} 36 | // `; 37 | 38 | StyledSidebarLegacy.defaultProps = {}; 39 | Object.setPrototypeOf(StyledSidebarLegacy.defaultProps, defaultProps); 40 | 41 | SidebarLegacyOverlay.defaultProps = {}; 42 | Object.setPrototypeOf(SidebarLegacyOverlay.defaultProps, defaultProps); 43 | 44 | export { StyledSidebarLegacy, SidebarLegacyOverlay }; 45 | -------------------------------------------------------------------------------- /src/lib/components/SidebarLegacy/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface SidebarLegacyProps { 4 | children: React.ReactNode 5 | collapsable: boolean 6 | } 7 | 8 | declare const SidebarLegacy: React.FC; 9 | 10 | export type SidebarLegacyType = SidebarLegacyProps 11 | 12 | export default SidebarLegacy 13 | -------------------------------------------------------------------------------- /src/lib/components/SidebarLegacy/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SidebarLegacy' 2 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/SidebarNext.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { ThemeContext } from "styled-components"; 3 | import defaultTheme from "../../themes/defaultTheme"; 4 | 5 | import { slide as SlideMenu } from "./menus"; 6 | import { stack as StackMenu } from "./menus"; 7 | // import { elastic as ElasticMenu } from "./menus"; // requires snapsvg-cjs in package,json : "snapsvg-cjs": "0.0.6" 8 | // import { bubble as BubbleMenu } from "./menus"; // requires snapsvg-cjs in package,json : "snapsvg-cjs": "0.0.6" 9 | import { push as PushMenu } from "./menus"; 10 | import { pushRotate as PushRotateMenu } from "./menus"; 11 | import { scaleDown as ScaleDownMenu } from "./menus"; 12 | import { scaleRotate as ScaleRotateMenu } from "./menus"; 13 | import { fallDown as FallDownMenu } from "./menus"; 14 | import { reveal as RevealMenu } from "./menus"; 15 | 16 | const SidebarNext = (props) => { 17 | const theme = useContext(ThemeContext) || defaultTheme; 18 | 19 | return ( 20 | <> 21 | { 22 | { 23 | slide: {props.children}, 24 | stack: {props.children}, 25 | // elastic: {props.children}, 26 | // bubble: {props.children}, 27 | push: {props.children}, 28 | pushRotate: ( 29 | {props.children} 30 | ), 31 | scaleDown: {props.children}, 32 | scaleRotate: ( 33 | {props.children} 34 | ), 35 | fallDown: {props.children}, 36 | reveal: {props.children}, 37 | }[props.type || "slide"] 38 | } 39 | 40 | ); 41 | }; 42 | 43 | export default SidebarNext; 44 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { borderType } from "../../utils"; 3 | 4 | export interface SidebarNextProps { 5 | backgroundColor?: string; 6 | border?: borderType; 7 | padding?: string; 8 | } 9 | 10 | declare const SidebarNext: React.FC; 11 | 12 | export type SidebarNextType = SidebarNextProps; 13 | 14 | export default SidebarNext; 15 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./SidebarNext"; 2 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/fallDown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | menuWrap(isOpen) { 7 | return { 8 | MozTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 9 | MsTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 10 | OTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 11 | WebkitTransform: isOpen ? '' : 'translate3d(0, -100%, 0)', 12 | transform: isOpen ? '' : 'translate3d(0, -100%, 0)', 13 | transition: 'all 0.5s ease-in-out' 14 | }; 15 | }, 16 | 17 | pageWrap(isOpen, width, right) { 18 | return { 19 | MozTransform: isOpen 20 | ? '' 21 | : right 22 | ? `translate3d(-${width}, 0, 0)` 23 | : `translate3d(${width}, 0, 0)`, 24 | MsTransform: isOpen 25 | ? '' 26 | : right 27 | ? `translate3d(-${width}, 0, 0)` 28 | : `translate3d(${width}, 0, 0)`, 29 | OTransform: isOpen 30 | ? '' 31 | : right 32 | ? `translate3d(-${width}, 0, 0)` 33 | : `translate3d(${width}, 0, 0)`, 34 | WebkitTransform: isOpen 35 | ? '' 36 | : right 37 | ? `translate3d(-${width}, 0, 0)` 38 | : `translate3d(${width}, 0, 0)`, 39 | transform: isOpen 40 | ? '' 41 | : right 42 | ? `translate3d(-${width}, 0, 0)` 43 | : `translate3d(${width}, 0, 0)`, 44 | transition: 'all 0.5s' 45 | }; 46 | }, 47 | 48 | outerContainer(isOpen) { 49 | return { 50 | perspective: '1500px', 51 | perspectiveOrigin: '0% 50%', 52 | overflow: isOpen ? '' : 'hidden' 53 | }; 54 | } 55 | }; 56 | 57 | export default menuFactory(styles); 58 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/index.js: -------------------------------------------------------------------------------- 1 | export { default as slide } from "./slide"; 2 | export { default as stack } from "./stack"; 3 | export { default as elastic } from "./elastic"; 4 | export { default as bubble } from "./bubble"; 5 | export { default as push } from "./push"; 6 | export { default as pushRotate } from "./pushRotate"; 7 | export { default as scaleDown } from "./scaleDown"; 8 | export { default as scaleRotate } from "./scaleRotate"; 9 | export { default as fallDown } from "./fallDown"; 10 | export { default as reveal } from "./reveal"; 11 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/push.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(-${width}, 0, 0)` 12 | : `translate3d(${width}, 0, 0)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(-${width}, 0, 0)` 17 | : `translate3d(${width}, 0, 0)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(-${width}, 0, 0)` 22 | : `translate3d(${width}, 0, 0)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(-${width}, 0, 0)` 27 | : `translate3d(${width}, 0, 0)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(-${width}, 0, 0)` 32 | : `translate3d(${width}, 0, 0)`, 33 | transition: 'all 0.5s' 34 | }; 35 | }, 36 | 37 | outerContainer(isOpen) { 38 | return { 39 | overflow: isOpen ? '' : 'hidden' 40 | }; 41 | } 42 | }; 43 | 44 | export default menuFactory(styles); 45 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/pushRotate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 12 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 17 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 22 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 27 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(-${width}, 0, 0) rotateY(15deg)` 32 | : `translate3d(${width}, 0, 0) rotateY(-15deg)`, 33 | transformOrigin: right ? '100% 50%' : '0% 50%', 34 | transformStyle: 'preserve-3d', 35 | transition: 'all 0.5s' 36 | }; 37 | }, 38 | 39 | outerContainer(isOpen) { 40 | return { 41 | perspective: '1500px', 42 | overflow: isOpen ? '' : 'hidden' 43 | }; 44 | } 45 | }; 46 | 47 | export default menuFactory(styles); 48 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/scaleDown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width) { 7 | return { 8 | MozTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 9 | MsTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 10 | OTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 11 | WebkitTransform: isOpen ? '' : `translate3d(0, 0, -${width})`, 12 | transform: isOpen ? '' : `translate3d(0, 0, -${width})`, 13 | transformOrigin: '100%', 14 | transformStyle: 'preserve-3d', 15 | transition: 'all 0.5s' 16 | }; 17 | }, 18 | 19 | outerContainer() { 20 | return { 21 | perspective: '1500px' 22 | }; 23 | } 24 | }; 25 | 26 | export default menuFactory(styles); 27 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/scaleRotate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | pageWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 12 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 17 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 22 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 27 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? 'translate3d(-100px, 0, -600px) rotateY(20deg)' 32 | : 'translate3d(100px, 0, -600px) rotateY(-20deg)', 33 | transformStyle: 'preserve-3d', 34 | transition: 'all 0.5s', 35 | overflow: isOpen ? '' : 'hidden' 36 | }; 37 | }, 38 | 39 | outerContainer(isOpen) { 40 | return { 41 | perspective: '1500px', 42 | overflow: isOpen ? '' : 'hidden' 43 | }; 44 | } 45 | }; 46 | 47 | export default menuFactory(styles); 48 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/slide.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = {}; 6 | 7 | export default menuFactory(styles); 8 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/menus/stack.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import menuFactory from '../menuFactory'; 4 | 5 | const styles = { 6 | menuWrap(isOpen, width, right) { 7 | return { 8 | MozTransform: isOpen 9 | ? '' 10 | : right 11 | ? `translate3d(${width}, 0, 0)` 12 | : `translate3d(-${width}, 0, 0)`, 13 | MsTransform: isOpen 14 | ? '' 15 | : right 16 | ? `translate3d(${width}, 0, 0)` 17 | : `translate3d(-${width}, 0, 0)`, 18 | OTransform: isOpen 19 | ? '' 20 | : right 21 | ? `translate3d(${width}, 0, 0)` 22 | : `translate3d(-${width}, 0, 0)`, 23 | WebkitTransform: isOpen 24 | ? '' 25 | : right 26 | ? `translate3d(${width}, 0, 0)` 27 | : `translate3d(-${width}, 0, 0)`, 28 | transform: isOpen 29 | ? '' 30 | : right 31 | ? `translate3d(${width}, 0, 0)` 32 | : `translate3d(-${width}, 0, 0)`, 33 | transition: isOpen 34 | ? 'transform 0.8s cubic-bezier(0.7, 0, 0.3, 1)' 35 | : 'transform 0.4s cubic-bezier(0.7, 0, 0.3, 1)' 36 | }; 37 | }, 38 | 39 | item(isOpen, width, right, nthChild) { 40 | return { 41 | MozTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 42 | MsTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 43 | OTransform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 44 | WebkitTransform: isOpen 45 | ? '' 46 | : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 47 | transform: isOpen ? '' : 'translate3d(0, ' + nthChild * 500 + 'px, 0)', 48 | transition: isOpen 49 | ? 'transform 0.8s cubic-bezier(0.7, 0, 0.3, 1)' 50 | : 'transform 0s 0.2s cubic-bezier(0.7, 0, 0.3, 1)' 51 | }; 52 | } 53 | }; 54 | 55 | export default menuFactory(styles); 56 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/snapsvgImporter.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | let Snap; 3 | try { 4 | // Snap = require('snapsvg-cjs'); 5 | } finally { 6 | return Snap; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/styles.css: -------------------------------------------------------------------------------- 1 | #App { 2 | /* Give app full page to work with */ 3 | height: 100vh; 4 | } 5 | 6 | #page-wrap { 7 | text-align: center; 8 | /* Prevent sidebar from showing a scrollbar on page */ 9 | overflow: auto; 10 | } 11 | 12 | /* Morph shape necessary with bubble or elastic */ 13 | .bm-morph-shape { 14 | fill: #373a47; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/components/SidebarNext/utils.js: -------------------------------------------------------------------------------- 1 | export const pxToNum = val => parseInt(val.slice(0, -2), 10); 2 | -------------------------------------------------------------------------------- /src/lib/components/SmartHeading/HeadingTheme.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { globalStyle } from "../../utils/styles"; 3 | import { defaultProps } from "../../default-props"; 4 | import { selectColor } from "../../utils/colors"; 5 | 6 | const StyledHeading = styled.h1` 7 | ${globalStyle}; 8 | color: ${(props) => 9 | selectColor(props.color || props.theme.smartHeading.color, props.theme)}; 10 | font-size: ${(props) => props.size}; 11 | font-weight: ${(props) => props.fontWeight}; 12 | margin: ${(props) => props.margin}; 13 | `; 14 | 15 | StyledHeading.defaultProps = {}; 16 | Object.setPrototypeOf(StyledHeading.defaultProps, defaultProps); 17 | 18 | export { StyledHeading }; 19 | -------------------------------------------------------------------------------- /src/lib/components/SmartHeading/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType 5 | } from '../../../utils' 6 | 7 | export interface SmartHeadingProps { 8 | children: React.ReactNode, 9 | config: configType, 10 | size: sizeType, 11 | type: 'free' | 'lastReload' | 'appName', 12 | level: '1 | 2 | 3 | 4 | 5 | 6', 13 | margin: string, 14 | } 15 | 16 | declare const SmartHeading: React.FC; 17 | 18 | export type SmartHeadingType = SmartHeadingProps 19 | 20 | export default SmartHeading 21 | -------------------------------------------------------------------------------- /src/lib/components/SmartHeading/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SmartHeading' -------------------------------------------------------------------------------- /src/lib/components/Spinner/Spinner.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import Loader from "react-loader-spinner"; 3 | import { ThemeContext } from "styled-components"; 4 | import PropTypes from "prop-types"; 5 | import defaultTheme from "../../themes/defaultTheme"; 6 | import { selectColor } from "../../utils/colors"; 7 | 8 | function Spinner({ type, size, color, timeout }) { 9 | const theme = useContext(ThemeContext) || defaultTheme; 10 | const { spinner } = theme; 11 | 12 | const colorTmp = color || spinner.color; 13 | 14 | const spinnerColor = selectColor(colorTmp, theme); 15 | 16 | return ( 17 | 26 | 35 | 36 | ); 37 | } 38 | 39 | Spinner.propTypes = { 40 | type: PropTypes.oneOf([ 41 | "Audio", 42 | "BallTriangle", 43 | "Bars", 44 | "Circles", 45 | "Grid", 46 | "Hearts", 47 | "Oval", 48 | "Puff", 49 | "Rings", 50 | "TailSpin", 51 | "ThreeDots", 52 | ]), 53 | size: PropTypes.number, 54 | color: PropTypes.string, 55 | timeout: PropTypes.number, 56 | }; 57 | 58 | export default Spinner; 59 | -------------------------------------------------------------------------------- /src/lib/components/Spinner/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface SpinnerProps { 4 | type: 5 | 'Audio' | 6 | 'BallTriangle' | 7 | 'Bars' | 8 | 'Circles' | 9 | 'Grid' | 10 | 'Hearts' | 11 | 'Oval' | 12 | 'Puff' | 13 | 'Rings' | 14 | 'TailSpin' | 15 | 'ThreeDots', 16 | size: number, 17 | color: string, 18 | timeout: number, 19 | } 20 | 21 | declare const Spinner: React.FC; 22 | 23 | export type SpinnerType = SpinnerProps 24 | 25 | export default Spinner 26 | -------------------------------------------------------------------------------- /src/lib/components/Spinner/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Spinner' 2 | -------------------------------------------------------------------------------- /src/lib/components/Table/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | } from '../../../utils' 7 | 8 | export interface TableProps { 9 | config: configType 10 | columns: Array 11 | columnOrder: Array 12 | calcCondition: calcCondType 13 | columnSortOrder:Array 14 | grandTotalsFlag: boolean 15 | margin: string 16 | height: string 17 | wrapperWidth: string 18 | tableWidth: string 19 | size: sizeType 20 | pageHeight: number 21 | tableLayout: 'fixed'| 'auto' 22 | headerAlignment: 'left' | 'middle'| 'right' 23 | headerBackgroundColor: string 24 | headerFontColor: string 25 | interactiveSort: boolean 26 | grid: boolean 27 | bandedRows: boolean 28 | highlightOnSelection: boolean 29 | allowSelections: boolean 30 | } 31 | 32 | declare const Table: React.FC; 33 | 34 | export type TableType = TableProps 35 | 36 | export default Table 37 | -------------------------------------------------------------------------------- /src/lib/components/Table/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Table' 2 | -------------------------------------------------------------------------------- /src/lib/components/XYChart/CustomChartPattern.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { 3 | PatternCircles, 4 | PatternHexagons, 5 | PatternLines, 6 | PatternWaves, 7 | } from "@visx/pattern"; 8 | import { DataContext } from "../visx"; 9 | import { selectColor } from "../../utils"; 10 | 11 | const patternId = "xy-chart-pattern"; 12 | 13 | export default function CustomChartBackground({ backgroundPattern }) { 14 | const { theme, margin, width, height, innerWidth, innerHeight } = useContext( 15 | DataContext 16 | ); 17 | 18 | // early return values not available in context 19 | if ( 20 | width == null || 21 | height == null || 22 | margin == null || 23 | theme == null || 24 | backgroundPattern == null 25 | ) 26 | return null; 27 | 28 | let Pattern; 29 | 30 | switch (backgroundPattern) { 31 | case "Circles": 32 | Pattern = PatternCircles; 33 | break; 34 | case "Hexagons": 35 | Pattern = PatternHexagons; 36 | break; 37 | case "Lines": 38 | Pattern = PatternLines; 39 | break; 40 | case "Waves": 41 | Pattern = PatternWaves; 42 | break; 43 | default: 44 | Pattern = PatternLines; 45 | break; 46 | } 47 | 48 | return ( 49 | <> 50 | 58 | 65 | 73 | 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /src/lib/components/XYChart/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType, 4 | sizeType, 5 | calcCondType, 6 | showLabelsType, 7 | textOnAxisType, 8 | tickSpacingType, 9 | showAxisType, 10 | showGridlinesType, 11 | borderType, 12 | colorThemeType, 13 | showLegendType, 14 | otherTotalSpecType, 15 | } from "../../utils"; 16 | 17 | export interface XYChartProps { 18 | config?: configType; 19 | label?: string; 20 | cols?: Array; 21 | calcCondition?: calcCondType; 22 | suppressZero?: boolean; 23 | columnSortOrder?: Array; 24 | sortDirection?: string; 25 | width?: string; 26 | height?: string; 27 | margin?: string; 28 | size?: sizeType; 29 | showLabels?: showLabelsType; 30 | textOnAxis?: textOnAxisType; 31 | tickSpacing?: tickSpacingType; 32 | hideAxisLine?: showAxisType; 33 | maxAxisLength?: number; 34 | allowSlantedYAxis?: boolean; 35 | showGridlines?: showGridlinesType; 36 | fontColor?: string; 37 | border?: borderType; 38 | backgroundColor?: string; 39 | colorTheme?: colorThemeType; 40 | stacked?: boolean; 41 | percentStacked?: boolean; 42 | roundNum?: boolean; 43 | title?: string; 44 | subTitle?: string; 45 | showLegend?: showLegendType; 46 | allowSelections?: boolean; 47 | maxWidth?: number; 48 | suppressScroll?: boolean; 49 | barPadding?: number; 50 | dimensionErrMsg?: string; 51 | measureErrMsg?: string; 52 | otherTotalSpec?: otherTotalSpecType; 53 | } 54 | 55 | declare const XYChart: React.FC; 56 | 57 | export type XYChartType = XYChartProps; 58 | 59 | export default XYChart; 60 | -------------------------------------------------------------------------------- /src/lib/components/XYChart/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./XYChart"; 2 | -------------------------------------------------------------------------------- /src/lib/components/visx/classes/DataRegistry.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import { DataRegistryEntry } from '../types/data'; 3 | 4 | /** A class for holding data entries */ 5 | export default class DataRegistry< 6 | XScale extends AxisScale, 7 | YScale extends AxisScale, 8 | Datum extends object 9 | > { 10 | private registry: { [key: string]: DataRegistryEntry } = {}; 11 | 12 | private registryKeys: string[] = []; 13 | 14 | /** Add one or more entries to the registry. */ 15 | public registerData( 16 | entryOrEntries: 17 | | DataRegistryEntry 18 | | DataRegistryEntry[], 19 | ) { 20 | const entries = Array.isArray(entryOrEntries) ? entryOrEntries : [entryOrEntries]; 21 | entries.forEach(currEntry => { 22 | if (currEntry.key in this.registry && this.registry[currEntry.key] != null) { 23 | console.debug('Overriding data registry key', currEntry.key); 24 | } 25 | this.registry[currEntry.key] = currEntry; 26 | this.registryKeys = Object.keys(this.registry); 27 | }); 28 | } 29 | 30 | /** Remove one or more entries to the registry. */ 31 | public unregisterData(keyOrKeys: string | string[]) { 32 | const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys]; 33 | keys.forEach(currKey => { 34 | delete this.registry[currKey]; 35 | this.registryKeys = Object.keys(this.registry); 36 | }); 37 | } 38 | 39 | /** Returns all data registry entries. This value is not constant between calls. */ 40 | public entries() { 41 | return Object.values(this.registry); 42 | } 43 | 44 | /** Returns a specific entity from the registry, if it exists. */ 45 | public get(key: string) { 46 | return this.registry[key]; 47 | } 48 | 49 | /** 50 | * Returns the current registry keys. 51 | * This value is constant between calls if the keys themselves have not changed. 52 | */ 53 | public keys() { 54 | return this.registryKeys; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/axis/AnimatedAxis.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { AxisScale } from '@visx/axis/lib/types'; 3 | import VxAnimatedAxis from '@visx/react-spring/lib/axis/AnimatedAxis'; 4 | import { AnimationTrajectory } from '@visx/react-spring/lib/types'; 5 | import BaseAxis, { BaseAxisProps } from './BaseAxis'; 6 | 7 | export type AnimatedAxisProps = Omit< 8 | BaseAxisProps, 9 | 'AxisComponent' 10 | > & { 11 | /** Animation trjectory of axis ticks. */ 12 | animationTrajectory?: AnimationTrajectory; 13 | }; 14 | 15 | export default function AnimatedAxis(props: AnimatedAxisProps) { 16 | return AxisComponent={VxAnimatedAxis} {...props} />; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/axis/Axis.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Axis as VisxAxis, AxisScale } from '@visx/axis'; 3 | import BaseAxis, { BaseAxisProps } from './BaseAxis'; 4 | 5 | export type AxisProps = Omit, 'AxisComponent'>; 6 | 7 | export default function Axis(props: AxisProps) { 8 | return AxisComponent={VisxAxis} {...props} />; 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/brush/types.ts: -------------------------------------------------------------------------------- 1 | export type Point = { 2 | x: number; 3 | y: number; 4 | }; 5 | 6 | export type Bounds = { 7 | x0: number; 8 | x1: number; 9 | xValues?: any[]; 10 | y0: number; 11 | y1: number; 12 | yValues?: any[]; 13 | }; 14 | 15 | export interface MarginShape { 16 | top?: number; 17 | left?: number; 18 | right?: number; 19 | bottom?: number; 20 | } 21 | 22 | export interface BrushShape extends BrushStartEnd { 23 | extent: Bounds; 24 | bounds: Bounds; 25 | } 26 | 27 | export interface BrushStartEnd { 28 | start: Point; 29 | end: Point; 30 | } 31 | 32 | export interface PartialBrushStartEnd { 33 | start: Partial; 34 | end: Partial; 35 | } 36 | 37 | export type ResizeTriggerAreas = 38 | | "left" 39 | | "right" 40 | | "top" 41 | | "bottom" 42 | | "topLeft" 43 | | "topRight" 44 | | "bottomLeft" 45 | | "bottomRight"; 46 | 47 | export interface Scale { 48 | (value: Input): Output; 49 | ticks?: (count: number) => Input[]; 50 | domain(input: Input[]): this; 51 | domain(): Input[]; 52 | range(): Output[]; 53 | range(output: Output[]): this; 54 | invert?: (output: Output) => Input; 55 | step?: () => number; 56 | } 57 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/brush/utils.ts: -------------------------------------------------------------------------------- 1 | import { Scale } from "./types"; 2 | 3 | export function scaleInvert(scale: Scale, value: number) { 4 | // Test if the scale is an ordinalScale or not, 5 | // Since an ordinalScale doesn't support invert function. 6 | if (!scale.invert) { 7 | const [start, end] = scale.range(); 8 | let i = 0; 9 | // ordinal should have step 10 | const width = (scale.step!() * (end - start)) / Math.abs(end - start); 11 | if (width > 0) { 12 | while (value > start + width * (i + 1)) { 13 | i += 1; 14 | } 15 | } else { 16 | while (value < start + width * (i + 1)) { 17 | i += 1; 18 | } 19 | } 20 | 21 | return i; 22 | } 23 | 24 | return scale.invert(value); 25 | } 26 | 27 | export function getDomainFromExtent( 28 | scale: Scale, 29 | start: number, 30 | end: number, 31 | tolerentDelta: number 32 | ) { 33 | let domain; 34 | const invertedStart = scaleInvert( 35 | scale, 36 | start + (start < end ? -tolerentDelta : tolerentDelta) 37 | ); 38 | const invertedEnd = scaleInvert( 39 | scale, 40 | end + (end < start ? -tolerentDelta : tolerentDelta) 41 | ); 42 | const minValue = Math.min(invertedStart, invertedEnd); 43 | const maxValue = Math.max(invertedStart, invertedEnd); 44 | if (scale.invert) { 45 | domain = { 46 | start: minValue, 47 | end: maxValue, 48 | }; 49 | } else { 50 | const values = []; 51 | const scaleDomain = scale.domain(); 52 | for (let i = minValue; i <= maxValue; i += 1) { 53 | values.push(scaleDomain[i]); 54 | } 55 | domain = { 56 | values, 57 | }; 58 | } 59 | 60 | return domain; 61 | } 62 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/grid/AnimatedGrid.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from "react"; 2 | import AnimatedGridRows from "@visx/react-spring/lib/grid/AnimatedGridRows"; 3 | import AnimatedGridColumns from "@visx/react-spring/lib/grid/AnimatedGridColumns"; 4 | import { AnimationTrajectory } from "@visx/react-spring"; 5 | import { GridRowsProps } from "@visx/grid/lib/grids/GridRows"; 6 | import { AxisScale } from "@visx/axis"; 7 | import { GridColumnsProps } from "@visx/grid/lib/grids/GridColumns"; 8 | import BaseGrid, { BaseGridProps } from "./BaseGrid"; 9 | 10 | export type AnimatedGridProps = Omit< 11 | BaseGridProps, 12 | "GridRowsComponent" | "GridColumnsComponent" 13 | > & { 14 | /** Animation trjectory of grid lines. */ 15 | animationTrajectory?: AnimationTrajectory; 16 | /** Number of Grid Rows. */ 17 | numGridRows?: number; 18 | /** Number of Grid Columns. */ 19 | numGridColumns?: number; 20 | }; 21 | 22 | export default function AnimatedGrid({ 23 | animationTrajectory, 24 | numGridRows, 25 | numGridColumns, 26 | ...props 27 | }: AnimatedGridProps) { 28 | const RowsComponent = useMemo( 29 | () => (rowProps: GridRowsProps) => ( 30 | 35 | ), 36 | [animationTrajectory] 37 | ); 38 | const ColumnsComponent = useMemo( 39 | () => (rowProps: GridColumnsProps) => ( 40 | 45 | ), 46 | [animationTrajectory] 47 | ); 48 | return ( 49 | 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/grid/Grid.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import GridRows from "@visx/grid/lib/grids/GridRows"; 3 | import GridColumns from "@visx/grid/lib/grids/GridColumns"; 4 | import BaseGrid, { BaseGridProps } from "./BaseGrid"; 5 | import { AnimationTrajectory } from "@visx/react-spring"; 6 | 7 | export type GridProps = Omit< 8 | BaseGridProps, 9 | "GridRowsComponent" | "GridColumnsComponent" 10 | > & { 11 | /** Animation trjectory of grid lines. */ 12 | animationTrajectory?: AnimationTrajectory /** Number of Grid Rows. */; 13 | numGridRows?: number; 14 | /** Number of Grid Columns. */ 15 | numGridColumns?: number; 16 | }; 17 | 18 | export default function Grid({ 19 | animationTrajectory = null, 20 | numGridRows, 21 | numGridColumns, 22 | ...props 23 | }: GridProps) { 24 | return ( 25 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedAreaSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import AnimatedPath from './private/AnimatedPath'; 4 | import BaseAreaSeries, { BaseAreaSeriesProps } from './private/BaseAreaSeries'; 5 | 6 | export default function AnimatedAreaSeries< 7 | XScale extends AxisScale, 8 | YScale extends AxisScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'PathComponent'>) { 11 | return {...props} PathComponent={AnimatedPath} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedBarGroup.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PositionScale } from '@visx/shape/lib/types'; 3 | import BaseBarGroup, { BaseBarGroupProps } from './private/BaseBarGroup'; 4 | import AnimatedBars from './private/AnimatedBars'; 5 | 6 | export default function AnimatedBarGroup< 7 | XScale extends PositionScale, 8 | YScale extends PositionScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'BarsComponent'>) { 11 | return {...props} BarsComponent={AnimatedBars} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedBarSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import BaseBarSeries, { BaseBarSeriesProps } from './private/BaseBarSeries'; 4 | import AnimatedBars from './private/AnimatedBars'; 5 | 6 | export default function AnimatedBarSeries< 7 | XScale extends AxisScale, 8 | YScale extends AxisScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'BarsComponent'>) { 11 | return {...props} BarsComponent={AnimatedBars} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedBarStack.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PositionScale } from '@visx/shape/lib/types'; 3 | import BaseBarStack, { BaseBarStackProps } from './private/BaseBarStack'; 4 | import AnimatedBars from './private/AnimatedBars'; 5 | 6 | export default function AnimatedBarStack< 7 | XScale extends PositionScale, 8 | YScale extends PositionScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'BarsComponent'>) { 11 | return {...props} BarsComponent={AnimatedBars} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedGlyphSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React, { useCallback } from 'react'; 3 | import { GlyphProps, GlyphsProps } from '../../types'; 4 | import AnimatedGlyphs from './private/AnimatedGlyphs'; 5 | import BaseGlyphSeries, { BaseGlyphSeriesProps } from './private/BaseGlyphSeries'; 6 | import defaultRenderGlyph from './private/defaultRenderGlyph'; 7 | 8 | export default function AnimatedGlyphSeries< 9 | XScale extends AxisScale, 10 | YScale extends AxisScale, 11 | Datum extends object 12 | >({ 13 | renderGlyph = defaultRenderGlyph, 14 | ...props 15 | }: Omit, 'renderGlyphs'> & { 16 | renderGlyph?: React.FC>; 17 | }) { 18 | const renderGlyphs = useCallback( 19 | ({ glyphs, xScale, yScale, horizontal }: GlyphsProps) => ( 20 | 27 | ), 28 | [renderGlyph], 29 | ); 30 | 31 | return ( 32 | 33 | {...props} 34 | // @TODO currently generics for non-SeriesProps are not passed correctly in 35 | // withRegisteredData HOC 36 | // @ts-ignore 37 | renderGlyphs={renderGlyphs} 38 | /> 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AnimatedLineSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import BaseLineSeries, { BaseLineSeriesProps } from './private/BaseLineSeries'; 4 | import AnimatedPath from './private/AnimatedPath'; 5 | 6 | export default function AnimatedLineSeries< 7 | XScale extends AxisScale, 8 | YScale extends AxisScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'PathComponent'>) { 11 | return {...props} PathComponent={AnimatedPath} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/AreaSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import BaseAreaSeries, { BaseAreaSeriesProps } from './private/BaseAreaSeries'; 4 | 5 | export default function AreaSeries< 6 | XScale extends AxisScale, 7 | YScale extends AxisScale, 8 | Datum extends object 9 | >({ ...props }: Omit, 'PathComponent'>) { 10 | return {...props} />; 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/BarGroup.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PositionScale } from '@visx/shape/lib/types'; 3 | import BaseBarGroup, { BaseBarGroupProps } from './private/BaseBarGroup'; 4 | import Bars from './private/Bars'; 5 | 6 | export default function BarGroup< 7 | XScale extends PositionScale, 8 | YScale extends PositionScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'BarsComponent'>) { 11 | return {...props} BarsComponent={Bars} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/BarSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import BaseBarSeries, { BaseBarSeriesProps } from './private/BaseBarSeries'; 4 | import Bars from './private/Bars'; 5 | 6 | function BarSeries({ 7 | ...props 8 | }: Omit, 'BarsComponent'>) { 9 | return {...props} BarsComponent={Bars} />; 10 | } 11 | 12 | export default BarSeries; 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/BarStack.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PositionScale } from '@visx/shape/lib/types'; 3 | import BaseBarStack, { BaseBarStackProps } from './private/BaseBarStack'; 4 | import Bars from './private/Bars'; 5 | 6 | export default function BarStack< 7 | XScale extends PositionScale, 8 | YScale extends PositionScale, 9 | Datum extends object 10 | >({ ...props }: Omit, 'BarsComponent'>) { 11 | return {...props} BarsComponent={Bars} />; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/GlyphSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from "@visx/axis"; 2 | import React, { useCallback } from "react"; 3 | import { GlyphProps, GlyphsProps } from "../../types"; 4 | import BaseGlyphSeries, { 5 | BaseGlyphSeriesProps, 6 | } from "./private/BaseGlyphSeries"; 7 | import defaultRenderGlyph from "./private/defaultRenderGlyph"; 8 | 9 | export default function GlyphSeries< 10 | XScale extends AxisScale, 11 | YScale extends AxisScale, 12 | Datum extends object 13 | >({ 14 | renderGlyph = defaultRenderGlyph, 15 | ...props 16 | }: Omit, "renderGlyphs"> & { 17 | renderGlyph?: React.FC>; 18 | }) { 19 | const renderGlyphs = useCallback( 20 | ({ glyphs }: GlyphsProps) => 21 | glyphs.map((glyph) => ( 22 | {renderGlyph(glyph)} 23 | )), 24 | [renderGlyph] 25 | ); 26 | return ( 27 | 28 | {...props} 29 | // @TODO currently generics for non-SeriesProps are not passed correctly in 30 | // withRegisteredData HOC 31 | // @ts-ignore 32 | renderGlyphs={renderGlyphs} 33 | /> 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/LineSeries.tsx: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import React from 'react'; 3 | import BaseLineSeries, { BaseLineSeriesProps } from './private/BaseLineSeries'; 4 | 5 | export default function LineSeries< 6 | XScale extends AxisScale, 7 | YScale extends AxisScale, 8 | Datum extends object 9 | >({ ...props }: Omit, 'PathComponent'>) { 10 | return {...props} />; 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/private/AnimatedPath.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { animated, useSpring } from 'react-spring'; 3 | 4 | export default function AnimatedPath({ 5 | d, 6 | stroke, 7 | fill, 8 | ...lineProps 9 | }: Omit, 'ref'>) { 10 | const tweened = useSpring({ d, stroke, fill }); 11 | return ; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/private/Bars.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import React from 'react'; 3 | import { BarsProps } from '../../../types'; 4 | 5 | export default function Bars({ 6 | bars, 7 | horizontal, 8 | xScale, 9 | yScale,id, 10 | ...rectProps 11 | }: BarsProps) { 12 | return ( 13 | // eslint-disable-next-line react/jsx-no-useless-fragment 14 | <> 15 | {bars.map(({ key, id, ...barProps }) => ( 16 | 17 | ))} 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/series/private/defaultRenderGlyph.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { GlyphProps } from '../../../types'; 3 | 4 | export default function defaultRenderGlyph({ 5 | key, 6 | color, 7 | x, 8 | y, 9 | size, 10 | }: GlyphProps) { 11 | return ; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/components/visx/components/titles/Title.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { TitleWrapper, Title as TitleText, SubTitle } from "./TitleTheme"; 3 | // import SmartHeading from "../../../../SmartHeading"; 4 | 5 | type Props = { 6 | title?: string; 7 | subTitle?: string; 8 | size?: string; 9 | }; 10 | 11 | function Title(props: Props) { 12 | const { title, subTitle, size } = props; 13 | const titleText = title; 14 | const subTitleText = subTitle; 15 | 16 | return ( 17 | 18 | {titleText} 19 | {subTitleText} 20 | 21 | ); 22 | } 23 | 24 | TitleText.defaultProps = { 25 | margin: "0px", 26 | }; 27 | 28 | SubTitle.defaultProps = { 29 | margin: "0px", 30 | }; 31 | 32 | export default Title; 33 | -------------------------------------------------------------------------------- /src/lib/components/visx/context/DataContext.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import React from 'react'; 3 | import { AxisScale } from '@visx/axis'; 4 | import { DataContextType } from '../types'; 5 | 6 | type AnyDataContext = DataContextType; 7 | 8 | /** Utilities for infering context generics */ 9 | export type InferXScaleConfig = X extends DataContextType< 10 | infer T, 11 | any, 12 | any 13 | > 14 | ? T 15 | : AxisScale; 16 | 17 | export type InferYScaleConfig = X extends DataContextType< 18 | any, 19 | infer T, 20 | any 21 | > 22 | ? T 23 | : AxisScale; 24 | 25 | export type InferDatum = X extends DataContextType 26 | ? T 27 | : any; 28 | 29 | export type InferDataContext = DataContextType< 30 | InferXScaleConfig, 31 | InferYScaleConfig, 32 | InferDatum 33 | >; 34 | 35 | const DataContext = React.createContext>({}); 36 | 37 | export default DataContext; 38 | -------------------------------------------------------------------------------- /src/lib/components/visx/context/EventEmitterContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { EventEmitterContextType } from '../types'; 3 | 4 | const EventEmitterContext = createContext(null); 5 | 6 | export default EventEmitterContext; 7 | -------------------------------------------------------------------------------- /src/lib/components/visx/context/TooltipContext.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { createContext } from 'react'; 3 | import { TooltipContextType } from '../types'; 4 | 5 | type InferTooltipContext = D extends TooltipContextType ? D : any; 6 | 7 | const TooltipContext = createContext(null); 8 | 9 | export default TooltipContext; 10 | -------------------------------------------------------------------------------- /src/lib/components/visx/hooks/useDataRegistry.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from "@visx/axis"; 2 | import { useMemo, useState } from "react"; 3 | import DataRegistry from "../classes/DataRegistry"; 4 | import { DataContextType } from "../types"; 5 | 6 | /** Hook that returns an API equivalent to DataRegistry but which updates as needed for use as a hook. */ 7 | export default function useDataRegistry< 8 | XScale extends AxisScale, 9 | YScale extends AxisScale, 10 | Datum extends object 11 | >(): DataContextType["dataRegistry"] { 12 | const [, forceUpdate] = useState(Math.random()); 13 | const privateRegistry = useMemo( 14 | () => new DataRegistry(), 15 | [] 16 | ); 17 | 18 | return useMemo( 19 | () => ({ 20 | registerData: ( 21 | ...params: Parameters< 22 | DataContextType["dataRegistry"]["registerData"] 23 | > 24 | ) => { 25 | privateRegistry.registerData(...params); 26 | forceUpdate(Math.random()); 27 | }, 28 | unregisterData: ( 29 | ...params: Parameters< 30 | DataContextType< 31 | XScale, 32 | YScale, 33 | Datum 34 | >["dataRegistry"]["unregisterData"] 35 | > 36 | ) => { 37 | privateRegistry.unregisterData(...params); 38 | forceUpdate(Math.random()); 39 | }, 40 | entries: () => privateRegistry.entries(), 41 | get: (key: string) => privateRegistry.get(key), 42 | keys: () => privateRegistry.keys(), 43 | }), 44 | [privateRegistry] 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /src/lib/components/visx/hooks/useDimensions.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from 'react'; 2 | 3 | const INITIAL_DIMENSIONS = { 4 | width: 0, 5 | height: 0, 6 | margin: { top: 0, right: 0, bottom: 0, left: 0 }, 7 | }; 8 | 9 | export type Dimensions = typeof INITIAL_DIMENSIONS; 10 | 11 | /** A hook for accessing and setting memoized width, height, and margin chart dimensions. */ 12 | export default function useDimensions( 13 | initialDimensions?: Partial, 14 | ): [Dimensions, (dims: Dimensions) => void] { 15 | const [dimensions, privateSetDimensions] = useState({ 16 | ...INITIAL_DIMENSIONS, 17 | ...initialDimensions, 18 | }); 19 | 20 | // expose a setter with better memoization logic 21 | const publicSetDimensions = useCallback( 22 | (dims: Dimensions) => { 23 | if ( 24 | dims.width !== dimensions.width || 25 | dims.height !== dimensions.height || 26 | dims.margin.left !== dimensions.margin.left || 27 | dims.margin.right !== dimensions.margin.right || 28 | dims.margin.top !== dimensions.margin.top || 29 | dims.margin.bottom !== dimensions.margin.bottom 30 | ) { 31 | privateSetDimensions(dims); 32 | } 33 | }, 34 | [ 35 | dimensions.width, 36 | dimensions.height, 37 | dimensions.margin.left, 38 | dimensions.margin.right, 39 | dimensions.margin.bottom, 40 | dimensions.margin.top, 41 | ], 42 | ); 43 | 44 | return [dimensions, publicSetDimensions]; 45 | } 46 | -------------------------------------------------------------------------------- /src/lib/components/visx/hooks/useEventEmitter.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useContext, useEffect } from "react"; 2 | import { localPoint } from "@visx/event"; 3 | import EventEmitterContext from "../context/EventEmitterContext"; 4 | 5 | export type EventType = 6 | | "mousemove" 7 | | "mouseout" 8 | | "touchmove" 9 | | "touchend" 10 | | "click"; 11 | export type HandlerParams = { 12 | event: React.MouseEvent | React.TouchEvent; 13 | svgPoint: ReturnType; 14 | }; 15 | export type Handler = (params?: HandlerParams) => void; 16 | 17 | /** 18 | * Hook for optionally subscribing to a specified EventType, 19 | * and returns emitter for emitting events. 20 | */ 21 | export default function useEventEmitter( 22 | eventType?: EventType, 23 | handler?: Handler 24 | ) { 25 | const emitter = useContext(EventEmitterContext); 26 | 27 | /** wrap emitter.emit so we can enforce stricter type signature */ 28 | const emit = useCallback( 29 | (type: EventType, event: HandlerParams["event"]) => 30 | emitter?.emit(type, { 31 | event, 32 | svgPoint: localPoint(event), 33 | }), 34 | [emitter] 35 | ); 36 | 37 | useEffect(() => { 38 | if (emitter && eventType && handler) { 39 | emitter.on(eventType, handler); 40 | return () => emitter?.off(eventType, handler); 41 | } 42 | return undefined; 43 | }, [emitter, eventType, handler]); 44 | 45 | return emitter ? emit : null; 46 | } 47 | -------------------------------------------------------------------------------- /src/lib/components/visx/providers/EventEmitterProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import mitt from 'mitt'; 3 | import EventEmitterContext from '../context/EventEmitterContext'; 4 | 5 | /** Provider for EventEmitterContext. */ 6 | export default function EventEmitterProvider({ children }: { children: React.ReactNode }) { 7 | const emitter = useMemo(() => mitt(), []); 8 | return {children}; 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/components/visx/theme/createColorArray.ts: -------------------------------------------------------------------------------- 1 | export const createColorArray = (color: any, theme: any) => { 2 | // if array 3 | if (Array.isArray(color)) { 4 | return color; 5 | } 6 | if (theme.global.chart[`${theme}Theme`] !== undefined) { 7 | // if string and string matches a theme name 8 | 9 | return theme.global.chart[`${theme}Theme`].color; 10 | } 11 | if (theme.global.color[color] !== undefined) { 12 | // if string and string matches a theme name 13 | 14 | return theme.global.color[color]; 15 | } 16 | // if string and doesn't match a theme name, it is an open color array 17 | return [ 18 | `var(--oc-${color}-0)`, 19 | `var(--oc-${color}-1)`, 20 | `var(--oc-${color}-2)`, 21 | `var(--oc-${color}-3)`, 22 | `var(--oc-${color}-4)`, 23 | `var(--oc-${color}-5)`, 24 | `var(--oc-${color}-6)`, 25 | `var(--oc-${color}-7)`, 26 | `var(--oc-${color}-8)`, 27 | `var(--oc-${color}-9)`, 28 | ]; 29 | }; 30 | -------------------------------------------------------------------------------- /src/lib/components/visx/theme/themes/theme.ts: -------------------------------------------------------------------------------- 1 | import buildChartTheme from "../buildChartTheme"; 2 | 3 | import { createColorArray } from "../createColorArray"; 4 | 5 | export const chartTheme = (theme: any, colorTheme: string, size: string) => { 6 | const colorPalette = createColorArray(colorTheme, theme); 7 | 8 | const { 9 | global: { chart }, 10 | } = theme; 11 | 12 | return buildChartTheme({ 13 | size, 14 | backgroundColor: 15 | chart[`${colorTheme}Theme`] !== undefined 16 | ? chart[`${colorTheme}Theme`].backgroundColor 17 | : theme.backgroundColor, 18 | colors: colorPalette, 19 | tickLabelStyles: { 20 | fill: 21 | chart[`${colorTheme}Theme`] !== undefined 22 | ? chart[`${colorTheme}Theme`].tickLabelStyles 23 | : theme.tickLabelStyles, 24 | }, 25 | labelStyles: { 26 | fill: 27 | chart[`${colorTheme}Theme`] !== undefined 28 | ? chart[`${colorTheme}Theme`].labelStyles 29 | : theme.labelStyles, 30 | }, 31 | gridColor: { 32 | stroke: 33 | chart[`${colorTheme}Theme`] !== undefined 34 | ? chart[`${colorTheme}Theme`].gridColor 35 | : theme.gridColor, 36 | }, 37 | chart: theme.global.chart, 38 | tooltiplLabelStyles: chart.tooltip.tooltiplLabelStyles, 39 | gridStyles: chart.gridStyles, 40 | xAxisStyles: chart.xAxisStyles, 41 | yAxisStyles: chart.yAxisStyles, 42 | scatter: theme.scatter, 43 | bar: theme.bar, 44 | points: theme.points, 45 | stackedArea: theme.stackedArea, 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/lib/components/visx/typeguards/isChildWithProps.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** Returns whether the React.ReactNode has props (and therefore is an `Element` versus primative type) */ 4 | export default function isChildWithProps

( 5 | child: React.ReactNode, 6 | ): child is React.ComponentType

{ 7 | return !!child && typeof child === 'object' && 'props' in child && child.props != null; 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/components/visx/typeguards/isDefined.ts: -------------------------------------------------------------------------------- 1 | export default function isDefined(_: unknown): _ is number { 2 | return typeof _ !== "undefined" && _ !== null; 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/components/visx/typeguards/isValidNumber.ts: -------------------------------------------------------------------------------- 1 | export default function isValidNumber(_: unknown): _ is number { 2 | return _ != null && typeof _ === 'number' && !Number.isNaN(_) && Number.isFinite(_); 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/components/visx/types/event.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import { ScaleInput } from '@visx/scale'; 3 | import { Emitter } from 'mitt'; 4 | 5 | export type EventEmitterContextType = Emitter; 6 | 7 | /** Arguments for findNearestDatum* functions. */ 8 | export type NearestDatumArgs< 9 | XScale extends AxisScale, 10 | YScale extends AxisScale, 11 | Datum extends object 12 | > = { 13 | point: { x: number; y: number } | null; 14 | xAccessor: (d: Datum) => ScaleInput; 15 | yAccessor: (d: Datum) => ScaleInput; 16 | data: Datum[]; 17 | width: number; 18 | height: number; 19 | xScale: XScale; 20 | yScale: YScale; 21 | }; 22 | -------------------------------------------------------------------------------- /src/lib/components/visx/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data'; 2 | export * from './event'; 3 | export * from './series'; 4 | export * from './theme'; 5 | export * from './tooltip'; 6 | -------------------------------------------------------------------------------- /src/lib/components/visx/types/tooltip.ts: -------------------------------------------------------------------------------- 1 | import { UseTooltipParams } from '@visx/tooltip/lib/hooks/useTooltip'; 2 | 3 | export type TooltipDatum = { 4 | /** Series key that datum belongs to. */ 5 | key: string; 6 | /** Index of datum in series data array. */ 7 | index: number; 8 | /** Datum. */ 9 | datum: Datum; 10 | }; 11 | 12 | /** Call signature of `TooltipContext.showTooltip` */ 13 | export type ShowTooltipParams = { 14 | /** Series key that datum belongs to. */ 15 | key: string; 16 | /** Index of datum in series data array. */ 17 | index: number; 18 | /** Datum. */ 19 | datum: Datum; 20 | /** Optional distance of datum x value to event x value. Used to determine closest datum. */ 21 | distanceX?: number; 22 | /** Optional distance of datum y value to event y value. Used to determine closest datum. */ 23 | distanceY?: number; 24 | /** Coordinates of the event in svg space. */ 25 | svgPoint?: { x: number; y: number }; 26 | }; 27 | 28 | export type TooltipData = { 29 | /** Nearest Datum to event across all Series. */ 30 | nearestDatum?: TooltipDatum & { distance: number }; 31 | /** Nearest Datum to event across for each Series. */ 32 | datumByKey: { 33 | [key: string]: TooltipDatum; 34 | }; 35 | }; 36 | 37 | export type TooltipContextType = UseTooltipParams> & { 38 | showTooltip: (params: ShowTooltipParams) => void; 39 | }; 40 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/findNearestDatumX.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import findNearestDatumSingleDimension from './findNearestDatumSingleDimension'; 3 | import { NearestDatumArgs } from '../types'; 4 | 5 | export default function findNearestDatumX< 6 | XScale extends AxisScale, 7 | YScale extends AxisScale, 8 | Datum extends object 9 | >({ 10 | xScale: scale, 11 | xAccessor: accessor, 12 | yScale, 13 | yAccessor, 14 | point, 15 | data, 16 | }: NearestDatumArgs): { 17 | datum: Datum; 18 | index: number; 19 | distanceX: number; 20 | distanceY: number; 21 | } | null { 22 | if (!point) return null; 23 | 24 | const nearestDatum = findNearestDatumSingleDimension({ 25 | scale, 26 | accessor, 27 | scaledValue: point.x, 28 | data, 29 | }); 30 | 31 | return nearestDatum 32 | ? { 33 | datum: nearestDatum.datum, 34 | index: nearestDatum.index, 35 | distanceX: nearestDatum.distance, 36 | distanceY: Math.abs(Number(yScale(yAccessor(nearestDatum.datum))) - point.y), 37 | } 38 | : null; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/findNearestDatumXY.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import { voronoi } from '@visx/voronoi'; 3 | import { NearestDatumArgs } from '../types'; 4 | 5 | /* finds the datum nearest to svgMouseX/Y using a voronoi */ 6 | export default function findNearestDatumXY< 7 | XScale extends AxisScale, 8 | YScale extends AxisScale, 9 | Datum extends object 10 | >({ 11 | width, 12 | height, 13 | xScale, 14 | yScale, 15 | xAccessor, 16 | yAccessor, 17 | point, 18 | data, 19 | }: NearestDatumArgs) { 20 | if (!point) return null; 21 | 22 | const scaledX = (d: Datum) => Number(xScale(xAccessor(d))); 23 | const scaledY = (d: Datum) => Number(yScale(yAccessor(d))); 24 | 25 | // Create a voronoi for each datum's x,y coordinate 26 | const voronoiInstance = voronoi({ 27 | x: scaledX, 28 | y: scaledY, 29 | width, 30 | height, 31 | }); 32 | 33 | const nearestDatum = voronoiInstance(data).find(point.x, point.y); 34 | 35 | if (!nearestDatum) return null; 36 | 37 | const { data: datum, index } = nearestDatum; 38 | const distanceX = Math.abs(scaledX(datum) - point.x); 39 | const distanceY = Math.abs(scaledY(datum) - point.y); 40 | 41 | return { datum, index, distanceX, distanceY }; 42 | } 43 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/findNearestDatumY.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import findNearestDatumSingleDimension from './findNearestDatumSingleDimension'; 3 | import { NearestDatumArgs } from '../types'; 4 | 5 | export default function findNearestDatumY< 6 | XScale extends AxisScale, 7 | YScale extends AxisScale, 8 | Datum extends object 9 | >({ 10 | yScale: scale, 11 | yAccessor: accessor, 12 | xScale, 13 | xAccessor, 14 | point, 15 | data, 16 | }: NearestDatumArgs): { 17 | datum: Datum; 18 | index: number; 19 | distanceX: number; 20 | distanceY: number; 21 | } | null { 22 | if (!point) return null; 23 | 24 | const nearestDatum = findNearestDatumSingleDimension({ 25 | scale, 26 | accessor, 27 | scaledValue: point.y, 28 | data, 29 | }); 30 | 31 | return nearestDatum 32 | ? { 33 | datum: nearestDatum.datum, 34 | index: nearestDatum.index, 35 | distanceY: nearestDatum.distance, 36 | distanceX: Math.abs(Number(xScale(xAccessor(nearestDatum.datum))) - point.x), 37 | } 38 | : null; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/findNearestStackDatum.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import { getFirstItem, getSecondItem } from '@visx/shape/lib/util/accessors'; 3 | import findNearestDatumY from './findNearestDatumY'; 4 | import findNearestDatumX from './findNearestDatumX'; 5 | import { BarStackDatum, NearestDatumArgs } from '../types'; 6 | 7 | /** 8 | * This is a wrapper around findNearestDatumX/Y for BarStack, accounting for a 9 | * Bar's d0 and d1, not just d1 (which findNearestDatum uses). Additionally, 10 | * returns the BarSeries original `Datum`, not the `BarStackDatum` so 11 | * Tooltip typing is correct. 12 | */ 13 | export default function findNearestStackDatum< 14 | XScale extends AxisScale, 15 | YScale extends AxisScale, 16 | Datum extends object 17 | >( 18 | nearestDatumArgs: NearestDatumArgs>, 19 | barSeriesData: Datum[], 20 | horizontal?: boolean, 21 | ) { 22 | const { xScale, yScale, point } = nearestDatumArgs; 23 | const datum = (horizontal ? findNearestDatumY : findNearestDatumX)(nearestDatumArgs); 24 | const barSeriesDatum = datum?.index == null ? null : barSeriesData[datum.index]; 25 | 26 | return datum && barSeriesDatum && point 27 | ? { 28 | index: datum.index, 29 | datum: barSeriesDatum, 30 | distanceX: horizontal // if mouse is ON the bar, set 0 distance 31 | ? point.x >= (xScale(getFirstItem(datum.datum)) ?? Infinity) && 32 | point.x <= (xScale(getSecondItem(datum.datum)) ?? -Infinity) 33 | ? 0 34 | : datum.distanceX 35 | : datum.distanceX, 36 | distanceY: horizontal 37 | ? datum.distanceY // if mouse is ON the bar, set 0 distance 38 | : point.y <= (yScale(getFirstItem(datum.datum)) ?? -Infinity) && 39 | point.y >= (yScale(getSecondItem(datum.datum)) ?? Infinity) 40 | ? 0 41 | : datum.distanceY, 42 | } 43 | : null; 44 | } 45 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/getScaleBandwidth.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | 3 | export default function getScaleBandwidth(scale: Scale) { 4 | // Broaden type before using 'xxx' in s as typeguard. 5 | const s = scale as AxisScale; 6 | return 'bandwidth' in s ? s?.bandwidth() ?? 0 : 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/getScaleBaseline.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from '@visx/axis'; 2 | import { coerceNumber } from '@visx/scale'; 3 | import isValidNumber from '../typeguards/isValidNumber'; 4 | 5 | /** 6 | * Returns the output value of a scale's baseline value, which is either zero 7 | * or the minimum scale value if its domain doesn't include zero. 8 | */ 9 | export default function getScaleBaseline(scale: Scale) { 10 | const [a, b] = scale.range().map(rangeBoundary => coerceNumber(rangeBoundary) ?? 0); 11 | const isDescending = a != null && b != null && b < a; 12 | const maybeScaleZero = scale(0); 13 | const [minOutput, maxOutput] = isDescending ? [b, a] : [a, b]; 14 | 15 | // if maybeScaleZero _is_ a number, but the scale is not clamped and it's outside the domain 16 | // fallback to the scale's minimum 17 | return isDescending 18 | ? isValidNumber(maybeScaleZero) 19 | ? Math.min(Math.max(minOutput, maybeScaleZero), maxOutput) 20 | : maxOutput 21 | : isValidNumber(maybeScaleZero) 22 | ? Math.max(maybeScaleZero, minOutput) 23 | : minOutput; 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/components/visx/utils/getScaledValueFactory.ts: -------------------------------------------------------------------------------- 1 | import { AxisScale } from "@visx/axis"; 2 | import { ScaleInput } from "@visx/scale"; 3 | import isValidNumber from "../typeguards/isValidNumber"; 4 | import getScaleBandwidth from "./getScaleBandwidth"; 5 | 6 | /** Returns a function that takes a Datum as input and returns a scaled value, correcting for the scale's bandwidth if applicable. */ 7 | export default function getScaledValueFactory< 8 | Scale extends AxisScale, 9 | Datum, 10 | Number 11 | >( 12 | scale: Scale, 13 | accessor: (d: Datum, n?: Number) => ScaleInput, 14 | index?: Number, 15 | align: "start" | "center" | "end" = "center" 16 | ) { 17 | return (d: Datum, n?: Number) => { 18 | const scaledValue = scale(accessor(d, index)); 19 | if (isValidNumber(scaledValue)) { 20 | const bandwidthOffset = 21 | (align === "start" ? 0 : getScaleBandwidth(scale)) / 22 | (align === "center" ? 2 : 1); 23 | return scaledValue + bandwidthOffset; 24 | } 25 | // @TODO: NaNs cause react-spring to throw, but the return value of this must be number 26 | // this currently causes issues in vertical <> horizontal transitions because 27 | // x/yAccessors from context are out of sync with props.horizontal 28 | // horizontal should be moved to context 29 | return NaN; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/lib/contexts/ConfigProvider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const ConfigContext = React.createContext({ 4 | host: null, 5 | secure: null, 6 | port: null, 7 | prefix: null, 8 | app: null, 9 | }) 10 | 11 | -------------------------------------------------------------------------------- /src/lib/contexts/EngineProvider.d.ts: -------------------------------------------------------------------------------- 1 | export declare const EngineContext: Object; 2 | 3 | export default EngineContext; 4 | -------------------------------------------------------------------------------- /src/lib/contexts/EngineProvider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const EngineContext = React.createContext(/* {engine: { }} */) 4 | -------------------------------------------------------------------------------- /src/lib/contexts/ThemeProvider.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { ThemeContext } from 'styled-components' 4 | import { deepMerge } from '../utils/object' 5 | 6 | ThemeContext.Extend = ({ children, value }) => ( 7 | 8 | {theme => ( 9 | 10 | {children} 11 | 12 | )} 13 | 14 | ) 15 | 16 | ThemeContext.Extend.propTypes = { 17 | children: PropTypes.node.isRequired, 18 | value: PropTypes.shape({}).isRequired, 19 | } 20 | 21 | export { ThemeContext } 22 | -------------------------------------------------------------------------------- /src/lib/default-props.d.ts: -------------------------------------------------------------------------------- 1 | import { base } from "./themes/base"; 2 | 3 | export namespace defaultProps { 4 | export { base as theme }; 5 | } 6 | 7 | export function extendDefaultTheme(theme: Object): void; 8 | -------------------------------------------------------------------------------- /src/lib/default-props.js: -------------------------------------------------------------------------------- 1 | import { deepMerge } from './utils/object' 2 | import base from './themes/base' 3 | 4 | export const defaultProps = { 5 | theme: base, 6 | } 7 | 8 | export const extendDefaultTheme = theme => { 9 | defaultProps.theme = deepMerge(base, theme) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/hooks/_useDataRegistry.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useContext } from "react"; 2 | import ChartContext from "../components/visx/context/ChartContext"; 3 | 4 | export default function useDataRegistry({ 5 | data, 6 | key, 7 | xAccessor, 8 | yAccessor, 9 | elAccessor, 10 | mouseEvents, 11 | legendShape, 12 | findNearestDatum, 13 | }) { 14 | const { registerData, unregisterData } = useContext(ChartContext); 15 | 16 | // register data on mount 17 | useEffect(() => { 18 | registerData({ 19 | [key]: { 20 | key, 21 | data, 22 | xAccessor, 23 | yAccessor, 24 | elAccessor, 25 | mouseEvents, 26 | legendShape, 27 | findNearestDatum, 28 | }, 29 | }); 30 | return () => unregisterData(key); 31 | }, [ 32 | registerData, 33 | unregisterData, 34 | key, 35 | data, 36 | xAccessor, 37 | yAccessor, 38 | elAccessor, 39 | mouseEvents, 40 | legendShape, 41 | findNearestDatum, 42 | ]); 43 | } 44 | -------------------------------------------------------------------------------- /src/lib/hooks/_useRegisteredData.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import ChartContext from "../components/visx/context/ChartContext"; 3 | 4 | export default function useRegisteredData(dataKey) { 5 | const { dataRegistry } = useContext(ChartContext); 6 | 7 | return dataRegistry[dataKey] || null; 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/hooks/useCapability.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType 4 | } from '../../../utils' 5 | 6 | export interface useCapabilityProps { 7 | config: configType 8 | } 9 | 10 | declare const useCapability: React.FC; 11 | 12 | export type useCapabilityType = useCapabilityProps 13 | 14 | export default useCapability 15 | -------------------------------------------------------------------------------- /src/lib/hooks/useContextMenu.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useCallback, useState } from "react"; 2 | 3 | const useContextMenu = (outerRef, open) => { 4 | 5 | const [xPos, setXPos] = useState("0px"); 6 | const [yPos, setYPos] = useState("0px"); 7 | const [menu, showMenu] = useState(false); 8 | 9 | const handleContextMenu = useCallback( 10 | event => { 11 | event.preventDefault(); 12 | if (open) { 13 | showMenu(true); 14 | } else { 15 | showMenu(false); 16 | } 17 | 18 | if (outerRef && outerRef.current.contains(event.target)) { 19 | console.log('called 1') 20 | setXPos(`${event.pageX}px`); 21 | setYPos(`${event.pageY}px`); 22 | showMenu(true); 23 | } else { 24 | showMenu(false); 25 | } 26 | }, 27 | [showMenu, outerRef, setXPos, setYPos] 28 | ); 29 | 30 | const handleClick = useCallback(() => { 31 | showMenu(false); 32 | }, [showMenu]); 33 | 34 | useEffect(() => { 35 | document.addEventListener("click", handleClick); 36 | document.addEventListener("contextmenu", handleContextMenu); 37 | return () => { 38 | document.addEventListener("click", handleClick); 39 | document.removeEventListener("contextmenu", handleContextMenu); 40 | }; 41 | }); 42 | return { xPos, yPos, menu }; 43 | }; 44 | 45 | export default useContextMenu; -------------------------------------------------------------------------------- /src/lib/hooks/useEffectDebugger.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react"; 2 | 3 | const usePrevious = (value, initialValue) => { 4 | const ref = useRef(initialValue); 5 | useEffect(() => { 6 | ref.current = value; 7 | }); 8 | return ref.current; 9 | }; 10 | 11 | const useEffectDebugger = (effectHook, dependencies, dependencyNames = []) => { 12 | const previousDeps = usePrevious(dependencies, []); 13 | 14 | const changedDeps = dependencies.reduce((accum, dependency, index) => { 15 | if (dependency !== previousDeps[index]) { 16 | const keyName = dependencyNames[index] || index; 17 | return { 18 | ...accum, 19 | [keyName]: { 20 | before: previousDeps[index], 21 | after: dependency, 22 | }, 23 | }; 24 | } 25 | 26 | return accum; 27 | }, {}); 28 | 29 | if (Object.keys(changedDeps).length) { 30 | console.log("[use-effect-debugger] ", changedDeps); 31 | } 32 | 33 | useEffect(effectHook, dependencies); 34 | }; 35 | 36 | export default useEffectDebugger; 37 | -------------------------------------------------------------------------------- /src/lib/hooks/useEngine.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | configType 4 | } from '../../../utils' 5 | 6 | export interface useEngineProps { 7 | config: configType 8 | } 9 | 10 | declare const useEngine: React.FC; 11 | 12 | export type useEngineType = useEngineProps 13 | 14 | export default useEngine 15 | -------------------------------------------------------------------------------- /src/lib/hooks/useHyperCube.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { calcCondType, otherTotalSpecType } from "../utils"; 3 | 4 | export interface useHyperCubeProps { 5 | engine: object; 6 | cols: Array; 7 | qColumnOrder: Array; 8 | qCalcCondition: calcCondType; 9 | qPage: object; 10 | qInterColumnSortOrder: Array; 11 | qSupressMissing: boolean; 12 | qSuppressZero: boolean; 13 | qSortByNumeric: number; 14 | qSortByAscii: number; 15 | qInterLineSortOrder: Array; 16 | qOtherTotalSpec: otherTotalSpecType; 17 | } 18 | 19 | declare const useHyperCube: React.FC; 20 | 21 | export type useHyperCubeType = useHyperCubeProps; 22 | 23 | export default useHyperCube; 24 | -------------------------------------------------------------------------------- /src/lib/hooks/useListObject.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useListObjectProps { 4 | qPage: { qTop: number, qLeft: number, qWidth: number, qHeight: number }, 5 | engine: object, 6 | dimension: Array 7 | label: string 8 | } 9 | 10 | declare const useListObject: React.FC; 11 | 12 | export type useListObjectType = useListObjectProps 13 | 14 | export default useListObject 15 | -------------------------------------------------------------------------------- /src/lib/hooks/useMediaQuery.jsx: -------------------------------------------------------------------------------- 1 | import { useLayoutEffect, useState } from 'react' 2 | 3 | export default function useMediaQuery(mediaQuery) { 4 | const [matches, setMatches] = useState( 5 | () => window.matchMedia(mediaQuery).matches, 6 | ) 7 | useLayoutEffect(() => { 8 | const mediaQueryList = window.matchMedia(mediaQuery) 9 | const listener = e => setMatches(e.matches) 10 | mediaQueryList.addListener(listener) 11 | 12 | return () => mediaQueryList.removeListener(listener) 13 | }, [mediaQuery]) 14 | 15 | return matches 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/hooks/useModal.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useModalProps { 4 | } 5 | 6 | declare const useModal: React.FC; 7 | 8 | export type useModalType = useModalProps 9 | 10 | export default useModal 11 | -------------------------------------------------------------------------------- /src/lib/hooks/useModal.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | const useModal = () => { 4 | const [isShowing, setIsShowing] = useState(false) 5 | 6 | function toggle() { 7 | setIsShowing(!isShowing) 8 | } 9 | 10 | return { 11 | isShowing, 12 | toggle, 13 | } 14 | } 15 | 16 | export default useModal 17 | -------------------------------------------------------------------------------- /src/lib/hooks/useOutsideClick.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | const useOutsideClick = (ref, callback) => { 4 | 5 | const handleClick = (e) => { 6 | if (ref.current && !ref.current.contains(e.target)) { 7 | callback(); 8 | } 9 | }; 10 | 11 | useEffect(() => { 12 | document.addEventListener('click', handleClick); 13 | 14 | return () => { 15 | document.removeEventListener('click', handleClick); 16 | }; 17 | }); 18 | }; 19 | 20 | export default useOutsideClick; 21 | -------------------------------------------------------------------------------- /src/lib/hooks/useScreenSize.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useScreenSizeProps { 4 | } 5 | 6 | declare const useScreenSize: React.FC; 7 | 8 | export type useScreenSizeType = useScreenSizeProps 9 | 10 | export default useScreenSize 11 | -------------------------------------------------------------------------------- /src/lib/hooks/useScreenSize.jsx: -------------------------------------------------------------------------------- 1 | // Media Queries 2 | import useMediaQuery from './useMediaQuery' 3 | import base from '../themes/base' 4 | 5 | const useScreenSize = () => { 6 | 7 | const { mobile, tablet, desktop } = base.global.responsiveBreakpoints 8 | 9 | const mobNum = parseInt(mobile, 10) + 1 10 | const tabNum = parseInt(tablet, 10) + 1 11 | const deskNum = parseInt(desktop, 10) + 1 12 | 13 | const mobPlus1 = mobNum + 'px' 14 | const tabPlus1 = tabNum + 'px' 15 | const deskPlus1 = deskNum + 'px' 16 | 17 | const isMobile = useMediaQuery(`(max-width: ${mobile})`) 18 | const isTablet = useMediaQuery(`(min-width: ${mobPlus1}) and (max-width: ${tabPlus1})`) 19 | const isDesktop = useMediaQuery(`(min-width: ${tabPlus1}) and (max-width: ${deskPlus1})`) 20 | const isLargeDesktop = useMediaQuery(`(min-width: ${deskPlus1})`) 21 | 22 | if (isMobile) { return { screen: 'mobile' } } 23 | if 24 | (isTablet) { return { screen: 'tablet' } } 25 | if 26 | (isDesktop) { return { screen: 'desktop' } } 27 | if 28 | (isLargeDesktop) { return { screen: 'largeDesktop' } } 29 | 30 | return { screen: 'desktop' } 31 | } 32 | 33 | export default useScreenSize 34 | -------------------------------------------------------------------------------- /src/lib/hooks/useSearch.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useSearchProps { 4 | engine: object, 5 | searchValue: string, 6 | dimensions: Array, 7 | qCount: number, 8 | qGroupItemCount: number, 9 | } 10 | 11 | declare const useSearch: React.FC; 12 | 13 | export type useSearchType = useSearchProps 14 | 15 | export default useSearch 16 | -------------------------------------------------------------------------------- /src/lib/hooks/useSelectionObject.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useSelectionObjectProps { 4 | engine: object, 5 | } 6 | 7 | declare const useSelectionObject: React.FC; 8 | 9 | export type useSelectionObjectType = useSelectionObjectProps 10 | 11 | export default useSelectionObject 12 | -------------------------------------------------------------------------------- /src/lib/hooks/useSelectionObject.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useRef } from 'react' 2 | 3 | let qDoc = null 4 | let qObject = null 5 | 6 | const useSelectionObject = ({ engine }) => { 7 | const _isMounted = useRef(true) 8 | const [qLayout, setQLatout] = useState(null) 9 | // const { qLayout } = state 10 | // const [qLayout, setQLayout] = useState(null) 11 | 12 | const update = async () => { 13 | const _qLayout = await qObject.getLayout() 14 | if (_isMounted.current) { 15 | setQLatout(_qLayout) 16 | } 17 | } 18 | 19 | const clearSelections = async (field, value) => { 20 | 21 | if (field) { 22 | const qField = await qDoc.getField(field) 23 | if (value) { 24 | await qField.toggleSelect(value) 25 | } else { 26 | await qField.clear() 27 | } 28 | } else { 29 | qDoc.clearAll() 30 | } 31 | } 32 | 33 | useEffect(() => { 34 | // eslint-disable-next-line no-empty 35 | if (engine === undefined) { } else { 36 | (async () => { 37 | const qProp = { qInfo: { qType: 'SelectionObject' }, qSelectionObjectDef: {} } 38 | qDoc = await engine 39 | qObject = await qDoc.createSessionObject(qProp) 40 | qObject.on('changed', () => { update() }) 41 | update() 42 | })() 43 | } 44 | }, [engine]) 45 | 46 | useEffect(() => (() => _isMounted.current = false), []) 47 | 48 | return { qLayout, clearSelections } 49 | } 50 | 51 | export default useSelectionObject 52 | -------------------------------------------------------------------------------- /src/lib/hooks/useSidebar.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface useSidebarProps { 4 | } 5 | 6 | declare const useSidebar: React.FC; 7 | 8 | export type useSidebarType = useSidebarProps 9 | 10 | export default useSidebar 11 | -------------------------------------------------------------------------------- /src/lib/hooks/useSidebar.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | const useSidebar = () => { 4 | const [isOpen, setIsOpen] = useState(false) 5 | 6 | function toggle() { 7 | setIsOpen(!isOpen) 8 | } 9 | 10 | return { 11 | isOpen, 12 | toggle, 13 | } 14 | } 15 | 16 | export default useSidebar 17 | -------------------------------------------------------------------------------- /src/lib/themes/base.d.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | 3 | export interface Theme { 4 | name: string; 5 | global: { 6 | chart: { 7 | hover?: CSSProperties; 8 | selection?: CSSProperties; 9 | nonSelection?: CSSProperties; 10 | noSelections?: CSSProperties; 11 | }; 12 | }; 13 | points?: CSSProperties; 14 | scatter?: CSSProperties; 15 | bar?: CSSProperties; 16 | stackedArea?: CSSProperties; 17 | } 18 | 19 | export declare const base: Theme; 20 | 21 | export default base; 22 | -------------------------------------------------------------------------------- /src/lib/themes/defaultTheme.jsx: -------------------------------------------------------------------------------- 1 | export { default } from './base' 2 | -------------------------------------------------------------------------------- /src/lib/themes/index.ts: -------------------------------------------------------------------------------- 1 | export { default as base } from "./base"; 2 | export { default as night} from "./night" 3 | -------------------------------------------------------------------------------- /src/lib/themes/night.d.ts: -------------------------------------------------------------------------------- 1 | export declare const night: Object; 2 | 3 | export default night; 4 | -------------------------------------------------------------------------------- /src/lib/themes/under development/archibald.jsx: -------------------------------------------------------------------------------- 1 | import defaultTheme from './base'; 2 | import { deepMerge } from '../../utils/object'; 3 | 4 | const base = [ 5 | '#D81C23', 6 | '#4FA8C2', 7 | '#D97441', 8 | '#D29849', 9 | 'var(--oc-pink-3)', 10 | 'var(--oc-pink-5)', 11 | 'var(--oc-pink-6)', 12 | 'var(--oc-pink-7)', 13 | 'var(--oc-pink-8)', 14 | ]; 15 | 16 | const color = { 17 | brand: '#D81C23', 18 | brandPrimary: '#D81C23', 19 | brandSecondary: '#4FA8C2', 20 | gauge: '#D81C23', 21 | colorTheme: base, 22 | }; 23 | 24 | const theme = { 25 | global: { color }, 26 | column: { 27 | colorTheme: base, 28 | }, 29 | bar: { 30 | colorTheme: base, 31 | }, 32 | line: { 33 | lines: { 34 | stroke: '#D81C23', 35 | }, 36 | color: { 37 | selectionBackground: '#D81C23', 38 | }, 39 | colorTheme: base, 40 | }, 41 | scatter: { 42 | scatters: { 43 | stroke: '#D81C23', 44 | }, 45 | colorTheme: base, 46 | }, 47 | pie: { 48 | colorTheme: base, 49 | }, 50 | barplot: { 51 | colorTheme: base, 52 | }, 53 | wordcloud: { 54 | colorTheme: base, 55 | }, 56 | tooltip: { 57 | color: '#D81C23', 58 | }, 59 | title: { 60 | mainTitle: { 61 | fontColor: '#D81C23', 62 | }, 63 | subTitle: { 64 | fontColor: 'var(--oc-gray-7)', 65 | }, 66 | }, 67 | legend: { 68 | arrowStyle: { 69 | fill: 'var(--oc-pink-5)', 70 | stroke: 'var(--oc-pink-5)', 71 | }, 72 | arrowDisabledStyle: { 73 | fill: 'var(--oc-pink-1)', 74 | stroke: 'var(--oc-pink-1)', 75 | }, 76 | }, 77 | }; 78 | 79 | export default deepMerge(defaultTheme, theme); 80 | -------------------------------------------------------------------------------- /src/lib/themes/under development/classic.jsx: -------------------------------------------------------------------------------- 1 | import defaultTheme from './base'; 2 | import { deepMerge } from '../../utils/object'; 3 | 4 | const base = [ 5 | 'var(--oc-blue-4)', 6 | 'var(--oc-blue-9)', 7 | 'var(--oc-blue-0)', 8 | 'var(--oc-blue-2)', 9 | 'var(--oc-blue-3)', 10 | 'var(--oc-blue-5)', 11 | 'var(--oc-blue-6)', 12 | 'var(--oc-blue-7)', 13 | 'var(--oc-blue-8)', 14 | ]; 15 | 16 | const color = { 17 | brand: 'var(--oc-blue-4)', 18 | brandPrimary: '#4dabf7', 19 | brandSecondary: '#1864ab', 20 | fontLight: 'var(--oc-blue-1)', 21 | gauge: 'var(--oc-blue-4)', 22 | base, 23 | }; 24 | 25 | const theme = { 26 | global: { 27 | color, 28 | }, 29 | column: { 30 | colorTheme: base, 31 | }, 32 | bar: { 33 | colorTheme: base, 34 | }, 35 | line: { 36 | lines: { 37 | stroke: 'var(--oc-blue-4)', 38 | }, 39 | color: { 40 | selectionBackground: 'var(--oc-blue-4)', 41 | }, 42 | colorTheme: base, 43 | }, 44 | scatter: { 45 | scatters: { 46 | stroke: 'var(--oc-blue-4)', 47 | }, 48 | colorTheme: base, 49 | }, 50 | pie: { 51 | colorTheme: base, 52 | }, 53 | barplot: { 54 | colorTheme: base, 55 | }, 56 | wordcloud: { 57 | colorTheme: base, 58 | }, 59 | tooltip: { 60 | color: 'var(--oc-blue-6)', 61 | }, 62 | title: { 63 | mainTitle: { 64 | fontColor: 'var(--oc-blue-4)', 65 | }, 66 | subTitle: { 67 | fontColor: 'var(--oc-gray-7)', 68 | }, 69 | }, 70 | legend: { 71 | arrowStyle: { 72 | fill: 'var(--oc-blue-5)', 73 | stroke: 'var(--oc-blue-5)', 74 | }, 75 | arrowDisabledStyle: { 76 | fill: 'var(--oc-blue-1)', 77 | stroke: 'var(--oc-blue-1)', 78 | }, 79 | }, 80 | }; 81 | 82 | export default deepMerge(defaultTheme, theme); 83 | -------------------------------------------------------------------------------- /src/lib/themes/under development/nowalls.jsx: -------------------------------------------------------------------------------- 1 | import defaultTheme from './base'; 2 | import { deepMerge } from '../../utils/object'; 3 | 4 | const base = [ 5 | '#99ca3b', 6 | '#999999', 7 | '#454545', 8 | '#B3B3B3', 9 | '#CCCCCC', 10 | '#8AD4EB', 11 | '#FE9666', 12 | '#A66999', 13 | '#3599B8', 14 | '#DFBFBF', 15 | '#4AC5BB', 16 | '#454545', 17 | '#FB8280', 18 | ]; 19 | 20 | const color = { 21 | brand: '#99ca3b', 22 | brandPrimary: '#99ca3b', 23 | brandSecondary: '#999999', 24 | gauge: '#99ca3b', 25 | base, 26 | }; 27 | const theme = { 28 | global: { color }, 29 | column: { 30 | colorTheme: base, 31 | }, 32 | bar: { 33 | colorTheme: base, 34 | }, 35 | line: { 36 | lines: { 37 | stroke: '#99ca3b', 38 | }, 39 | color: { 40 | selectionBackground: '#99ca3b', 41 | }, 42 | colorTheme: base, 43 | }, 44 | scatter: { 45 | scatters: { 46 | stroke: '#99ca3b', 47 | }, 48 | colorTheme: base, 49 | }, 50 | pie: { 51 | colorTheme: base, 52 | }, 53 | barplot: { 54 | colorTheme: base, 55 | }, 56 | wordcloud: { 57 | colorTheme: base, 58 | }, 59 | tooltip: { 60 | color: '#99ca3b', 61 | }, 62 | title: { 63 | mainTitle: { 64 | fontColor: '#99ca3b', 65 | }, 66 | subTitle: { 67 | fontColor: 'var(--oc-gray-7)', 68 | }, 69 | }, 70 | legend: { 71 | arrowStyle: { 72 | fill: '#8AD4EB', 73 | stroke: '#8AD4EB', 74 | }, 75 | arrowDisabledStyle: { 76 | fill: 'var(--oc-pink-1)', 77 | stroke: 'var(--oc-pink-1)', 78 | }, 79 | }, 80 | }; 81 | 82 | export default deepMerge(defaultTheme, theme); 83 | -------------------------------------------------------------------------------- /src/lib/themes/under development/powerbi.jsx: -------------------------------------------------------------------------------- 1 | import defaultTheme from './base'; 2 | import { deepMerge } from '../../utils/object'; 3 | 4 | const base = [ 5 | '#03B8AA', 6 | '#374649', 7 | '#FD625E', 8 | '#F2C80F', 9 | '#5F6B6D', 10 | '#8ad4eb', 11 | '#fe9666', 12 | '#a66999', 13 | '#3599b8', 14 | '#dfbfbf', 15 | '#4ac5bb', 16 | '#5f6b6d', 17 | '#fb8281', 18 | '#f4d25a', 19 | '#7f898a', 20 | '#a4ddee', 21 | '#fdab89', 22 | '#b687ac', 23 | '#28738a', 24 | '#a78f8f', 25 | '#168980', 26 | '#293537', 27 | '#bb4a4a', 28 | '#b59525', 29 | '#475052', 30 | ]; 31 | 32 | const color = { 33 | brand: '#03B8AA', 34 | brandPrimary: '#03B8AA', 35 | brandSecondary: '#374649', 36 | gauge: '#03B8AA', 37 | base, 38 | }; 39 | 40 | const theme = { 41 | global: { color }, 42 | column: { 43 | colorTheme: base, 44 | }, 45 | bar: { 46 | colorTheme: base, 47 | }, 48 | line: { 49 | lines: { 50 | stroke: '#03B8AA', 51 | }, 52 | color: { 53 | selectionBackground: '#03B8AA', 54 | }, 55 | colorTheme: base, 56 | }, 57 | scatter: { 58 | scatters: { 59 | stroke: '#03B8AA', 60 | }, 61 | colorTheme: base, 62 | }, 63 | pie: { 64 | colorTheme: base, 65 | }, 66 | barplot: { 67 | colorTheme: base, 68 | }, 69 | wordcloud: { 70 | colorTheme: base, 71 | }, 72 | tooltip: { 73 | color: '#03B8AA', 74 | }, 75 | title: { 76 | mainTitle: { 77 | fontColor: '#03B8AA', 78 | }, 79 | subTitle: { 80 | fontColor: 'var(--oc-gray-7)', 81 | }, 82 | }, 83 | legend: { 84 | arrowStyle: { 85 | fill: '#8ad4eb', 86 | stroke: '#8ad4eb', 87 | }, 88 | arrowDisabledStyle: { 89 | fill: 'var(--oc-pink-1)', 90 | stroke: 'var(--oc-pink-1)', 91 | }, 92 | }, 93 | }; 94 | 95 | export default deepMerge(defaultTheme, theme); 96 | -------------------------------------------------------------------------------- /src/lib/themes/under development/tableau.jsx: -------------------------------------------------------------------------------- 1 | import defaultTheme from './base'; 2 | import { deepMerge } from '../../utils/object'; 3 | 4 | const base = [ 5 | '#4E79A8', 6 | '#A0CBE8', 7 | '#F28E2B', 8 | '#FFBE7D', 9 | '#59A14F', 10 | '#8CD17D', 11 | '#B6992D', 12 | '#F1CE63', 13 | '#499894', 14 | '#86BCB6', 15 | '#E15759', 16 | '#FF9D9A', 17 | '#79706E', 18 | '#BAB0AD', 19 | '#D47295', 20 | '#FABFD2', 21 | '#B07AA2', 22 | '#D4A6C9', 23 | '#946B51', 24 | '#D7B5A6', 25 | ]; 26 | 27 | const color = { 28 | brand: '#4E79A8', 29 | brandPrimary: '#4E79A8', 30 | brandSecondary: '#A0CBE8', 31 | gauge: '#4E79A8', 32 | colorTheme: base, 33 | }; 34 | 35 | const theme = { 36 | global: { 37 | color, 38 | }, 39 | column: { 40 | colorTheme: base, 41 | }, 42 | bar: { 43 | colorTheme: base, 44 | }, 45 | line: { 46 | lines: { 47 | stroke: '#4E79A8', 48 | }, 49 | color: { 50 | selectionBackground: '#4E79A8', 51 | }, 52 | colorTheme: base, 53 | }, 54 | scatter: { 55 | scatters: { 56 | stroke: '#4E79A8', 57 | }, 58 | colorTheme: base, 59 | }, 60 | pie: { 61 | colorTheme: base, 62 | }, 63 | barplot: { 64 | colorTheme: base, 65 | }, 66 | wordcloud: { 67 | colorTheme: base, 68 | }, 69 | tooltip: { 70 | color: '#4E79A8', 71 | }, 72 | title: { 73 | mainTitle: { 74 | fontColor: '#4E79A8', 75 | }, 76 | subTitle: { 77 | fontColor: 'var(--oc-gray-7)', 78 | }, 79 | }, 80 | legend: { 81 | arrowStyle: { 82 | fill: '#8CD17D', 83 | stroke: '#8CD17D', 84 | }, 85 | arrowDisabledStyle: { 86 | fill: 'var(--oc-pink-1)', 87 | stroke: 'var(--oc-pink-1)', 88 | }, 89 | }, 90 | }; 91 | 92 | export default deepMerge(defaultTheme, theme); 93 | -------------------------------------------------------------------------------- /src/lib/utils/CapApiUtils/Preloader.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import '../styles/index.scss'; 4 | 5 | const Preloader = (props) => { 6 | const { 7 | width, height, paddingTop, type, 8 | } = props; 9 | if (type === 'dots') { 10 | return '...'; 11 | } if (type === 'bgColor') { 12 | return ( 13 |

14 | ); 15 | } 16 | return ( 17 |
18 |
19 |
20 |
21 | ); 22 | }; 23 | Preloader.propTypes = { 24 | width: PropTypes.string, 25 | height: PropTypes.string, 26 | paddingTop: PropTypes.string, 27 | type: PropTypes.string, 28 | }; 29 | Preloader.defaultProps = { 30 | width: '100%', 31 | height: '100%', 32 | paddingTop: 0, 33 | type: 'balls', 34 | }; 35 | export default Preloader; 36 | -------------------------------------------------------------------------------- /src/lib/utils/CapApiUtils/Tooltip.js: -------------------------------------------------------------------------------- 1 | const Tooltip = class { 2 | constructor() { 3 | this.div = { 4 | x: 0, 5 | y: 0, 6 | w: 0, 7 | h: 0, 8 | show: false, 9 | element: document.getElementsByClassName('qdt-tooltip'), 10 | }; 11 | } 12 | create() { 13 | try { 14 | if (!this.div.element[0]) { 15 | const div = document.createElement('div'); 16 | div.setAttribute('class', 'qdt-tooltip'); 17 | document.body.appendChild(div); 18 | } 19 | } catch (error) { 20 | console.log(error); 21 | } 22 | } 23 | show(data) { 24 | try { 25 | const { div } = this; 26 | div.element[0].style.display = 'inline-block'; 27 | if (data) { 28 | const text = `${data[0].values[0].qText}: ${data[1].values[0]}`; 29 | div.element[0].innerHTML = text; 30 | const rect = div.element[0].getBoundingClientRect(); 31 | div.w = rect.width; 32 | div.h = rect.height; 33 | } 34 | div.element[0].style.position = 'absolute'; 35 | div.element[0].style.top = `${div.y - div.h - 10}px`; 36 | div.element[0].style.left = `${(div.x - (div.w / 2))}px`; 37 | } catch (error) { 38 | console.log(error); 39 | } 40 | } 41 | hide() { 42 | try { 43 | const { div } = this; 44 | if (div.element[0]) { 45 | div.element[0].style.display = 'none'; 46 | } 47 | } catch (error) { 48 | console.log(error); 49 | } 50 | } 51 | }; 52 | 53 | export default Tooltip; -------------------------------------------------------------------------------- /src/lib/utils/CapApiUtils/Uid.js: -------------------------------------------------------------------------------- 1 | function uid(length) { 2 | const ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 3 | const ID_LENGTH = (length) || 8; 4 | let rtn = ''; 5 | for (let i = 0; i < ID_LENGTH; i += 1) { 6 | rtn += ALPHABET.charAt(Math.floor(Math.random() * ALPHABET.length)); 7 | } 8 | return rtn; 9 | } 10 | 11 | export default uid; -------------------------------------------------------------------------------- /src/lib/utils/CapApiUtils/index.js: -------------------------------------------------------------------------------- 1 | import Uid from './Uid'; 2 | 3 | const globals = { 4 | qlik: null, 5 | resize: null, 6 | }; 7 | 8 | export default { Uid, globals }; -------------------------------------------------------------------------------- /src/lib/utils/RoundNum.js: -------------------------------------------------------------------------------- 1 | // import { isBoolean } from "../components/visx/utils/chartUtils"; 2 | export function isBoolean(val) { 3 | return typeof val === "boolean"; 4 | } 5 | 6 | export function roundNumber(numb, precision) { 7 | let num = numb; 8 | let decimals = isBoolean(precision) 9 | ? precision === true 10 | ? 2 11 | : 0 12 | : precision; 13 | 14 | // check if the string passed is number or contains formatting like 13% 15 | if (/^[0-9.]+$/.test(num)) { 16 | num = 17 | // precision && num > 1000 ? parseFloat(num).toFixed(decimals) : Math.round(num); 18 | precision ? parseFloat(num).toFixed(decimals) : Math.round(num); 19 | if (num >= 1000 && num < 1000000) { 20 | num = precision 21 | ? parseFloat(num / 1000).toFixed(decimals) 22 | : Math.round(num / 1000); 23 | if (/\.00$/.test(num)) { 24 | num = num.replace(/\.00$/, ""); // Remove .00 25 | } 26 | num += "K"; // Add the abbreviation 27 | } else if (num >= 1000000 && num < 1000000000) { 28 | num = precision 29 | ? parseFloat(num / 1000000).toFixed(decimals) 30 | : Math.round(num / 1000000); 31 | if (/\.00$/.test(num)) { 32 | num = num.replace(/\.00$/, ""); // Remove .00 33 | } 34 | num += "M"; // Add the abbreviation 35 | } else if (num >= 1000000000 && num < 1000000000000) { 36 | num = precision 37 | ? parseFloat(num / 1000000000).toFixed(decimals) 38 | : Math.round(num / 1000000000); 39 | if (/\.00$/.test(num)) { 40 | num = num.replace(/\.00$/, ""); // Remove .00 41 | } 42 | num += "G"; // Add the abbreviation 43 | } else if (num >= 1000000000000) { 44 | num = precision 45 | ? parseFloat(num / 1000000000000).toFixed(decimals) 46 | : Math.round(num / 1000000000000); 47 | if (/\.00$/.test(num)) { 48 | num = num.replace(/\.00$/, ""); // Remove .00 49 | } 50 | num += "T"; // Add the abbreviation 51 | // Change to B and add T 52 | } 53 | } 54 | 55 | return num; 56 | } 57 | 58 | export default roundNumber; 59 | -------------------------------------------------------------------------------- /src/lib/utils/calcDisplayOption.js: -------------------------------------------------------------------------------- 1 | export const calcDisplayOption = (value, useDDefaultValue = false) => { 2 | if (typeof value !== 'boolean') return value; 3 | 4 | if (value) { 5 | return useDDefaultValue ? 'default' : 'both'; 6 | } else { 7 | return 'none'; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /src/lib/utils/colors.js: -------------------------------------------------------------------------------- 1 | export const selectColor = (color, theme) => { 2 | const colors = theme.global !== undefined ? theme.global.color : theme.color; // added for xyChart 3 | const result = colors[color] !== undefined ? colors[color] : color; 4 | // theme.global.color[color] !== undefined ? theme.global.color[color] : color; 5 | 6 | return result; 7 | }; 8 | 9 | export const openColorArray = (color) => [ 10 | `var(--oc-${color}-0)`, 11 | `var(--oc-${color}-1)`, 12 | `var(--oc-${color}-2)`, 13 | `var(--oc-${color}-3)`, 14 | `var(--oc-${color}-4)`, 15 | `var(--oc-${color}-5)`, 16 | `var(--oc-${color}-6)`, 17 | `var(--oc-${color}-7)`, 18 | `var(--oc-${color}-8)`, 19 | `var(--oc-${color}-9)`, 20 | ]; 21 | 22 | export const createColorArray = (color, theme) => { 23 | // if array 24 | if (Array.isArray(color)) { 25 | return color; 26 | } 27 | if (theme.global.chart[`${theme}Theme`] !== undefined) { 28 | // if string and string matches a theme name 29 | 30 | return theme.global.chart[`${theme}Theme`].color; 31 | } 32 | if (theme.global.color[color] !== undefined) { 33 | // if string and string matches a theme name 34 | 35 | return theme.global.color[color]; 36 | } 37 | // if string and doesn't match a theme name, it is an open color array 38 | return [ 39 | `var(--oc-${color}-0)`, 40 | `var(--oc-${color}-1)`, 41 | `var(--oc-${color}-2)`, 42 | `var(--oc-${color}-3)`, 43 | `var(--oc-${color}-4)`, 44 | `var(--oc-${color}-5)`, 45 | `var(--oc-${color}-6)`, 46 | `var(--oc-${color}-7)`, 47 | `var(--oc-${color}-8)`, 48 | `var(--oc-${color}-9)`, 49 | ]; 50 | }; 51 | -------------------------------------------------------------------------------- /src/lib/utils/componentWidth.js: -------------------------------------------------------------------------------- 1 | export const componentWidth = ({ width, margin }) => { 2 | return /^\d+(\.\d+)?%$/.test(width) 3 | ? `calc(${width} - ${+parseInt(margin, 10) * 2}px)` 4 | : `${+parseInt(width, 10)}px`; 5 | }; 6 | -------------------------------------------------------------------------------- /src/lib/utils/exportData.js: -------------------------------------------------------------------------------- 1 | const exportData = (engine, config, id, filename) => { 2 | const { 3 | host, secure, port, prefix, 4 | } = config 5 | 6 | const _secure = secure ? 'https://' : 'http://' 7 | const _port = port ? `:${port}` : '' 8 | const server = _secure + host + _port + prefix 9 | engine.getObject(id).then(model => { 10 | model.exportData('CSV_C', '/qHyperCubeDef', filename, 'P').then(url => { 11 | window.open(server + url.qUrl, '_blank') 12 | }) 13 | }) 14 | } 15 | 16 | export default exportData 17 | -------------------------------------------------------------------------------- /src/lib/utils/hexToRgb.js: -------------------------------------------------------------------------------- 1 | export const hexToRgb = (bkgColor, opacity = 1) => { 2 | if (bkgColor.substr(0, 4) === "rgba") return bkgColor; 3 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(bkgColor); 4 | return result 5 | ? `rgba(${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt( 6 | result[3], 7 | 16 8 | )},${opacity})` 9 | : `rgba(${bkgColor}, ${opacity})`; 10 | }; 11 | -------------------------------------------------------------------------------- /src/lib/utils/index.js: -------------------------------------------------------------------------------- 1 | export { roundNumber } from "./RoundNum"; 2 | export { hyperCubeTransform } from "./hyperCubeUtilities"; 3 | export { groupHyperCubeData } from "./hyperCubeUtilities"; 4 | export { stackHyperCubeData } from "./hyperCubeUtilities"; 5 | export { getMeasureNames } from "./hyperCubeUtilities"; 6 | export { getDimensionNames } from "./hyperCubeUtilities"; 7 | export { getDimensionCategories } from "./hyperCubeUtilities"; 8 | export { numericSortDirection } from "./hyperCubeUtilities"; 9 | export { validData } from "./hyperCubeUtilities"; 10 | export { colorByExpression } from "./colorByExpression"; 11 | export { calcDisplayOption } from "./calcDisplayOption"; 12 | export { isNull, isEmpty, isString } from "./lodash"; 13 | export { legendPosition } from "./legendPosition"; 14 | export { componentWidth } from "./componentWidth"; 15 | export { isDefined } from "./isDefined"; 16 | export { valueIfUndefined } from "./valueIfUndefined"; 17 | export { default as exportData } from "./exportData"; 18 | export { selectColor, createColorArray } from "./colors"; 19 | export { globalStyle, borderStyle } from "./styles"; 20 | -------------------------------------------------------------------------------- /src/lib/utils/isDefined.js: -------------------------------------------------------------------------------- 1 | export function isDefined(val) { 2 | return typeof val !== "undefined" && val !== null; 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/utils/legendPosition.js: -------------------------------------------------------------------------------- 1 | export const legendPosition = (showLegend, defaultLegend) => { 2 | switch (showLegend) { 3 | case null: 4 | case undefined: 5 | return defaultLegend ? "right" : "none"; 6 | case true: 7 | case "right": 8 | return "right"; 9 | case false: 10 | case "none": 11 | return "none"; 12 | case "bottom": 13 | return "bottom"; 14 | default: 15 | return "right"; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/.internal/freeGlobal.js: -------------------------------------------------------------------------------- 1 | /** Detect free variable `global` from Node.js. */ 2 | const freeGlobal = 3 | typeof global === "object" && 4 | global !== null && 5 | global.Object === Object && 6 | global; 7 | 8 | export default freeGlobal; 9 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/.internal/getTag.js: -------------------------------------------------------------------------------- 1 | const toString = Object.prototype.toString; 2 | 3 | /** 4 | * Gets the `toStringTag` of `value`. 5 | * 6 | * @private 7 | * @param {*} value The value to query. 8 | * @returns {string} Returns the `toStringTag`. 9 | */ 10 | function getTag(value) { 11 | if (value == null) { 12 | return value === undefined ? "[object Undefined]" : "[object Null]"; 13 | } 14 | return toString.call(value); 15 | } 16 | 17 | export default getTag; 18 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/.internal/isPrototype.js: -------------------------------------------------------------------------------- 1 | /** Used for built-in method references. */ 2 | const objectProto = Object.prototype; 3 | 4 | /** 5 | * Checks if `value` is likely a prototype object. 6 | * 7 | * @private 8 | * @param {*} value The value to check. 9 | * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. 10 | */ 11 | function isPrototype(value) { 12 | const Ctor = value && value.constructor; 13 | const proto = (typeof Ctor === "function" && Ctor.prototype) || objectProto; 14 | 15 | return value === proto; 16 | } 17 | 18 | export default isPrototype; 19 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/.internal/nodeTypes.js: -------------------------------------------------------------------------------- 1 | import freeGlobal from "./freeGlobal.js"; 2 | 3 | /** Detect free variable `exports`. */ 4 | const freeExports = 5 | typeof exports === "object" && 6 | exports !== null && 7 | !exports.nodeType && 8 | exports; 9 | 10 | /** Detect free variable `module`. */ 11 | const freeModule = 12 | freeExports && 13 | typeof module === "object" && 14 | module !== null && 15 | !module.nodeType && 16 | module; 17 | 18 | /** Detect the popular CommonJS extension `module.exports`. */ 19 | const moduleExports = freeModule && freeModule.exports === freeExports; 20 | 21 | /** Detect free variable `process` from Node.js. */ 22 | const freeProcess = moduleExports && freeGlobal.process; 23 | 24 | /** Used to access faster Node.js helpers. */ 25 | const nodeTypes = (() => { 26 | try { 27 | /* Detect public `util.types` helpers for Node.js v10+. */ 28 | /* Node.js deprecation code: DEP0103. */ 29 | const typesHelper = 30 | freeModule && freeModule.require && freeModule.require("util").types; 31 | return typesHelper 32 | ? typesHelper 33 | : /* Legacy process.binding('util') for Node.js earlier than v10. */ 34 | freeProcess && freeProcess.binding && freeProcess.binding("util"); 35 | } catch (e) {} 36 | })(); 37 | 38 | export default nodeTypes; 39 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/.internal/root.js: -------------------------------------------------------------------------------- 1 | /* global globalThis, self */ 2 | import freeGlobal from "./freeGlobal.js"; 3 | 4 | /** Detect free variable `globalThis` */ 5 | const freeGlobalThis = 6 | typeof globalThis === "object" && 7 | globalThis !== null && 8 | globalThis.Object == Object && 9 | globalThis; 10 | 11 | /** Detect free variable `self`. */ 12 | const freeSelf = 13 | typeof self === "object" && self !== null && self.Object === Object && self; 14 | 15 | /** Used as a reference to the global object. */ 16 | const root = 17 | freeGlobalThis || freeGlobal || freeSelf || Function("return this")(); 18 | 19 | export default root; 20 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/index.js: -------------------------------------------------------------------------------- 1 | export { default as isNull } from "./isNull"; 2 | export { default as isEmpty } from "./isEmpty"; 3 | export { default as isString } from "./isString"; 4 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isArguments.js: -------------------------------------------------------------------------------- 1 | import getTag from "./.internal/getTag.js"; 2 | import isObjectLike from "./isObjectLike.js"; 3 | 4 | /** 5 | * Checks if `value` is likely an `arguments` object. 6 | * 7 | * @since 0.1.0 8 | * @category Lang 9 | * @param {*} value The value to check. 10 | * @returns {boolean} Returns `true` if `value` is an `arguments` object, else `false`. 11 | * @example 12 | * 13 | * isArguments(function() { return arguments }()) 14 | * // => true 15 | * 16 | * isArguments([1, 2, 3]) 17 | * // => false 18 | */ 19 | function isArguments(value) { 20 | return isObjectLike(value) && getTag(value) == "[object Arguments]"; 21 | } 22 | 23 | export default isArguments; 24 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isArrayLike.js: -------------------------------------------------------------------------------- 1 | import isLength from "./isLength.js"; 2 | 3 | /** 4 | * Checks if `value` is array-like. A value is considered array-like if it's 5 | * not a function and has a `value.length` that's an integer greater than or 6 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. 7 | * 8 | * @since 4.0.0 9 | * @category Lang 10 | * @param {*} value The value to check. 11 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 12 | * @example 13 | * 14 | * isArrayLike([1, 2, 3]) 15 | * // => true 16 | * 17 | * isArrayLike(document.body.children) 18 | * // => true 19 | * 20 | * isArrayLike('abc') 21 | * // => true 22 | * 23 | * isArrayLike(Function) 24 | * // => false 25 | */ 26 | function isArrayLike(value) { 27 | return value != null && typeof value !== "function" && isLength(value.length); 28 | } 29 | 30 | export default isArrayLike; 31 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isBuffer.js: -------------------------------------------------------------------------------- 1 | import root from "./.internal/root.js"; 2 | 3 | /** Detect free variable `exports`. */ 4 | const freeExports = 5 | typeof exports === "object" && 6 | exports !== null && 7 | !exports.nodeType && 8 | exports; 9 | 10 | /** Detect free variable `module`. */ 11 | const freeModule = 12 | freeExports && 13 | typeof module === "object" && 14 | module !== null && 15 | !module.nodeType && 16 | module; 17 | 18 | /** Detect the popular CommonJS extension `module.exports`. */ 19 | const moduleExports = freeModule && freeModule.exports === freeExports; 20 | 21 | /** Built-in value references. */ 22 | const Buffer = moduleExports ? root.Buffer : undefined; 23 | 24 | /* Built-in method references for those with the same name as other `lodash` methods. */ 25 | const nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; 26 | 27 | /** 28 | * Checks if `value` is a buffer. 29 | * 30 | * @since 4.3.0 31 | * @category Lang 32 | * @param {*} value The value to check. 33 | * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. 34 | * @example 35 | * 36 | * isBuffer(new Buffer(2)) 37 | * // => true 38 | * 39 | * isBuffer(new Uint8Array(2)) 40 | * // => false 41 | */ 42 | const isBuffer = nativeIsBuffer || (() => false); 43 | 44 | export default isBuffer; 45 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isEmpty.js: -------------------------------------------------------------------------------- 1 | import getTag from "./.internal/getTag.js"; 2 | import isArguments from "./isArguments.js"; 3 | import isArrayLike from "./isArrayLike.js"; 4 | import isBuffer from "./isBuffer.js"; 5 | import isPrototype from "./.internal/isPrototype.js"; 6 | import isTypedArray from "./isTypedArray.js"; 7 | 8 | /** Used to check objects for own properties. */ 9 | const hasOwnProperty = Object.prototype.hasOwnProperty; 10 | 11 | /** 12 | * Checks if `value` is an empty object, collection, map, or set. 13 | * 14 | * Objects are considered empty if they have no own enumerable string keyed 15 | * properties. 16 | * 17 | * Array-like values such as `arguments` objects, arrays, buffers, strings, or 18 | * jQuery-like collections are considered empty if they have a `length` of `0`. 19 | * Similarly, maps and sets are considered empty if they have a `size` of `0`. 20 | * 21 | * @since 0.1.0 22 | * @category Lang 23 | * @param {*} value The value to check. 24 | * @returns {boolean} Returns `true` if `value` is empty, else `false`. 25 | * @example 26 | * 27 | * isEmpty(null) 28 | * // => true 29 | * 30 | * isEmpty(true) 31 | * // => true 32 | * 33 | * isEmpty(1) 34 | * // => true 35 | * 36 | * isEmpty([1, 2, 3]) 37 | * // => false 38 | * 39 | * isEmpty('abc') 40 | * // => false 41 | * 42 | * isEmpty({ 'a': 1 }) 43 | * // => false 44 | */ 45 | function isEmpty(value) { 46 | if (value == null) { 47 | return true; 48 | } 49 | if ( 50 | isArrayLike(value) && 51 | (Array.isArray(value) || 52 | typeof value === "string" || 53 | typeof value.splice === "function" || 54 | isBuffer(value) || 55 | isTypedArray(value) || 56 | isArguments(value)) 57 | ) { 58 | return !value.length; 59 | } 60 | const tag = getTag(value); 61 | if (tag == "[object Map]" || tag == "[object Set]") { 62 | return !value.size; 63 | } 64 | if (isPrototype(value)) { 65 | return !Object.keys(value).length; 66 | } 67 | for (const key in value) { 68 | if (hasOwnProperty.call(value, key)) { 69 | return false; 70 | } 71 | } 72 | return true; 73 | } 74 | 75 | export default isEmpty; 76 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isLength.js: -------------------------------------------------------------------------------- 1 | /** Used as references for various `Number` constants. */ 2 | const MAX_SAFE_INTEGER = 9007199254740991; 3 | 4 | /** 5 | * Checks if `value` is a valid array-like length. 6 | * 7 | * **Note:** This method is loosely based on 8 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). 9 | * 10 | * @since 4.0.0 11 | * @category Lang 12 | * @param {*} value The value to check. 13 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 14 | * @example 15 | * 16 | * isLength(3) 17 | * // => true 18 | * 19 | * isLength(Number.MIN_VALUE) 20 | * // => false 21 | * 22 | * isLength(Infinity) 23 | * // => false 24 | * 25 | * isLength('3') 26 | * // => false 27 | */ 28 | function isLength(value) { 29 | return ( 30 | typeof value === "number" && 31 | value > -1 && 32 | value % 1 == 0 && 33 | value <= MAX_SAFE_INTEGER 34 | ); 35 | } 36 | 37 | export default isLength; 38 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isNull.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks if `value` is `null`. 3 | * 4 | * @since 0.1.0 5 | * @category Lang 6 | * @param {*} value The value to check. 7 | * @returns {boolean} Returns `true` if `value` is `null`, else `false`. 8 | * @example 9 | * 10 | * isNull(null) 11 | * // => true 12 | * 13 | * isNull(void 0) 14 | * // => false 15 | */ 16 | function isNull(value) { 17 | return value === null; 18 | } 19 | 20 | export default isNull; 21 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isObjectLike.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks if `value` is object-like. A value is object-like if it's not `null` 3 | * and has a `typeof` result of "object". 4 | * 5 | * @since 4.0.0 6 | * @category Lang 7 | * @param {*} value The value to check. 8 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 9 | * @example 10 | * 11 | * isObjectLike({}) 12 | * // => true 13 | * 14 | * isObjectLike([1, 2, 3]) 15 | * // => true 16 | * 17 | * isObjectLike(Function) 18 | * // => false 19 | * 20 | * isObjectLike(null) 21 | * // => false 22 | */ 23 | function isObjectLike(value) { 24 | return typeof value === "object" && value !== null; 25 | } 26 | 27 | export default isObjectLike; 28 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isString.js: -------------------------------------------------------------------------------- 1 | import getTag from "./.internal/getTag.js"; 2 | 3 | /** 4 | * Checks if `value` is classified as a `String` primitive or object. 5 | * 6 | * @since 0.1.0 7 | * @category Lang 8 | * @param {*} value The value to check. 9 | * @returns {boolean} Returns `true` if `value` is a string, else `false`. 10 | * @example 11 | * 12 | * isString('abc') 13 | * // => true 14 | * 15 | * isString(1) 16 | * // => false 17 | */ 18 | function isString(value) { 19 | const type = typeof value; 20 | return ( 21 | type === "string" || 22 | (type === "object" && 23 | value != null && 24 | !Array.isArray(value) && 25 | getTag(value) == "[object String]") 26 | ); 27 | } 28 | 29 | export default isString; 30 | -------------------------------------------------------------------------------- /src/lib/utils/lodash/isTypedArray.js: -------------------------------------------------------------------------------- 1 | import getTag from "./.internal/getTag.js"; 2 | import nodeTypes from "./.internal/nodeTypes.js"; 3 | import isObjectLike from "./isObjectLike.js"; 4 | 5 | /** Used to match `toStringTag` values of typed arrays. */ 6 | const reTypedTag = /^\[object (?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)Array\]$/; 7 | 8 | /* Node.js helper references. */ 9 | const nodeIsTypedArray = nodeTypes && nodeTypes.isTypedArray; 10 | 11 | /** 12 | * Checks if `value` is classified as a typed array. 13 | * 14 | * @since 3.0.0 15 | * @category Lang 16 | * @param {*} value The value to check. 17 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 18 | * @example 19 | * 20 | * isTypedArray(new Uint8Array) 21 | * // => true 22 | * 23 | * isTypedArray([]) 24 | * // => false 25 | */ 26 | const isTypedArray = nodeIsTypedArray 27 | ? (value) => nodeIsTypedArray(value) 28 | : (value) => isObjectLike(value) && reTypedTag.test(getTag(value)); 29 | 30 | export default isTypedArray; 31 | -------------------------------------------------------------------------------- /src/lib/utils/object.js: -------------------------------------------------------------------------------- 1 | export const isObject = (item) => 2 | item && typeof item === "object" && !Array.isArray(item); 3 | 4 | export const deepFreeze = (obj) => { 5 | Object.keys(obj).forEach( 6 | (key) => key && isObject(obj[key]) && Object.freeze(obj[key]) 7 | ); 8 | 9 | return Object.freeze(obj); 10 | }; 11 | 12 | export const deepMerge = (target, ...sources) => { 13 | if (!sources.length) { 14 | return target; 15 | } 16 | // making sure to not change target (immutable) 17 | const output = { ...target }; 18 | sources.forEach((source) => { 19 | if (isObject(source)) { 20 | Object.keys(source).forEach((key) => { 21 | if (isObject(source[key])) { 22 | if (!output[key]) { 23 | output[key] = { ...source[key] }; 24 | } else { 25 | output[key] = deepMerge(output[key], source[key]); 26 | } 27 | } else { 28 | output[key] = source[key]; 29 | } 30 | }); 31 | } 32 | }); 33 | 34 | return output; 35 | }; 36 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/createSelectable.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const createSelectable = WrappedComponent => { 5 | class SelectableItem extends React.Component { 6 | 7 | childRef = React.createRef(); 8 | 9 | componentDidMount() { 10 | //const element = ReactDOM.findDOMNode(this) 11 | const element = this.childRef.current; 12 | this.context.selectable.register(this.props.selectableKey, element) 13 | } 14 | 15 | componentWillUnmount() { 16 | this.context.selectable.unregister(this.props.selectableKey) 17 | } 18 | 19 | render() { 20 | return ( 21 | 22 | {this.props.children} 23 | 24 | ) 25 | } 26 | } 27 | 28 | SelectableItem.contextTypes = { 29 | selectable: PropTypes.object, 30 | } 31 | 32 | SelectableItem.propTypes = { 33 | selectableKey: PropTypes.any.isRequired, 34 | } 35 | 36 | return SelectableItem 37 | } 38 | 39 | export default createSelectable 40 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/doObjectsCollide.js: -------------------------------------------------------------------------------- 1 | import getBoundsForNode from './getBoundsForNode' 2 | 3 | /** 4 | * Given offsets, widths, and heights of two objects, determine if they collide (overlap). 5 | * @param {int} aTop The top position of the first object 6 | * @param {int} aLeft The left position of the first object 7 | * @param {int} bTop The top position of the second object 8 | * @param {int} bLeft The left position of the second object 9 | * @param {int} aWidth The width of the first object 10 | * @param {int} aHeight The height of the first object 11 | * @param {int} bWidth The width of the second object 12 | * @param {int} bHeight The height of the second object 13 | * @return {bool} 14 | */ 15 | const coordsCollide = (aTop, aLeft, bTop, bLeft, aWidth, aHeight, bWidth, bHeight, tolerance) => { 16 | if (typeof tolerance === 'undefined') { 17 | tolerance = 0 18 | } 19 | 20 | return !( 21 | // 'a' bottom doesn't touch 'b' top 22 | ((aTop + aHeight - tolerance) < bTop) 23 | // 'a' top doesn't touch 'b' bottom 24 | || ((aTop + tolerance) > (bTop + bHeight)) 25 | // 'a' right doesn't touch 'b' left 26 | || ((aLeft + aWidth - tolerance) < bLeft) 27 | // 'a' left doesn't touch 'b' right 28 | || ((aLeft + tolerance) > (bLeft + bWidth)) 29 | ) 30 | } 31 | 32 | /** 33 | * Given two objects containing "top", "left", "offsetWidth" and "offsetHeight" 34 | * properties, determine if they collide. 35 | * @param {Object|HTMLElement} a 36 | * @param {Object|HTMLElement} b 37 | * @return {bool} 38 | */ 39 | export default (a, b, tolerance) => { 40 | const aObj = (a instanceof HTMLElement) ? getBoundsForNode(a) : a 41 | const bObj = (b instanceof HTMLElement) ? getBoundsForNode(b) : b 42 | 43 | return coordsCollide( 44 | aObj.top, 45 | aObj.left, 46 | bObj.top, 47 | bObj.left, 48 | aObj.offsetWidth, 49 | aObj.offsetHeight, 50 | bObj.offsetWidth, 51 | bObj.offsetHeight, 52 | tolerance, 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/getBoundsForNode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given a node, get everything needed to calculate its boundaries 3 | * @param {HTMLElement} node 4 | * @return {Object} 5 | */ 6 | export default node => { 7 | const rect = node.getBoundingClientRect() 8 | 9 | return { 10 | top: rect.top + document.body.scrollTop, 11 | left: rect.left + document.body.scrollLeft, 12 | offsetWidth: node.offsetWidth, 13 | offsetHeight: node.offsetHeight, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/index.js: -------------------------------------------------------------------------------- 1 | import SelectableGroup from './selectable-group' 2 | import createSelectable from './createSelectable' 3 | import isNodeIn from './isNodeIn' 4 | import nodeInRoot from './nodeInRoot' 5 | 6 | export { 7 | SelectableGroup, 8 | createSelectable, 9 | isNodeIn, 10 | nodeInRoot, 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/isNodeIn.js: -------------------------------------------------------------------------------- 1 | const isNodeIn = (node, predicate) => { 2 | if (typeof predicate !== 'function') { 3 | throw new Error('isNodeIn second parameter must be a function') 4 | } 5 | 6 | let currentNode = node 7 | while (currentNode) { 8 | if (predicate(currentNode)) { 9 | return true 10 | } 11 | currentNode = currentNode.parentNode 12 | } 13 | 14 | return false 15 | } 16 | 17 | export default isNodeIn 18 | -------------------------------------------------------------------------------- /src/lib/utils/selectDrag/nodeInRoot.js: -------------------------------------------------------------------------------- 1 | import isNodeIn from './isNodeIn' 2 | 3 | const isNodeInRoot = (node, root) => ( 4 | isNodeIn(node, currentNode => currentNode === root) 5 | ) 6 | 7 | export default isNodeInRoot 8 | -------------------------------------------------------------------------------- /src/lib/utils/valueIfUndefined.js: -------------------------------------------------------------------------------- 1 | export function valueIfUndefined(val, alternative) { 2 | return typeof val !== "undefined" && val !== null ? val : alternative; 3 | } 4 | -------------------------------------------------------------------------------- /static/m_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motor-js/motor-ui/12c0d90e1b762be72ce153e964439e52b821586f/static/m_icon.png -------------------------------------------------------------------------------- /static/motor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motor-js/motor-ui/12c0d90e1b762be72ce153e964439e52b821586f/static/motor.png -------------------------------------------------------------------------------- /static/motor_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motor-js/motor-ui/12c0d90e1b762be72ce153e964439e52b821586f/static/motor_red.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "./dist", 5 | "allowSyntheticDefaultImports": true, 6 | "module": "es6", 7 | "noImplicitAny": false, 8 | "outDir": "./dist", 9 | "target": "es6", 10 | "lib": [ 11 | "es2019" 12 | ], 13 | "moduleResolution": "node", 14 | "jsx": "react", 15 | }, 16 | "include": [ 17 | "src/**/*" 18 | ], 19 | "exclude": ["node_modules"] 20 | } --------------------------------------------------------------------------------