;
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 |
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 | }
--------------------------------------------------------------------------------