diff --git a/remix/.eslintrc.js b/remix/.eslintrc.js index a2f2fae..d5a4569 100644 --- a/remix/.eslintrc.js +++ b/remix/.eslintrc.js @@ -17,7 +17,14 @@ module.exports = { version: "detect", }, }, - plugins: ["@typescript-eslint", "react", "prettier", "unused-imports", "simple-import-sort", "chakra-ui"], + plugins: [ + "@typescript-eslint", + "react", + // "unused-imports", + "prettier", + "simple-import-sort", + "chakra-ui", + ], extends: [ "@remix-run/eslint-config", "eslint:recommended", @@ -26,7 +33,10 @@ module.exports = { "plugin:@typescript-eslint/recommended", ], rules: { - "react/jsx-curly-brace-presence": ["error", { props: "never", children: "never" }], + "react/jsx-curly-brace-presence": [ + "error", + { props: "never", children: "never" }, + ], "no-async-promise-executor": "off", "react/prop-types": "off", "react/display-name": "off", @@ -35,8 +45,8 @@ module.exports = { "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-unused-vars": "off", - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": "error", + // "unused-imports/no-unused-imports": "error", + // "unused-imports/no-unused-vars": "error", "react/react-in-jsx-scope": "off", "chakra-ui/props-order": "error", "chakra-ui/props-shorthand": [ diff --git a/remix/app/Providers/ThingtimeProvider.tsx b/remix/app/Providers/ThingtimeProvider.tsx index c0f4afe..650ba1c 100644 --- a/remix/app/Providers/ThingtimeProvider.tsx +++ b/remix/app/Providers/ThingtimeProvider.tsx @@ -20,7 +20,14 @@ try { // nothing } -const forceable = { +const force = { + settings: { + commanderActive: true, + }, + version: 22, +} + +const newVersionData = { Content: { hidden1: "Edit this to your heart's desire.", "How?": "Just search for Content and edit the value to whatever you want.", @@ -30,26 +37,25 @@ const forceable = { }, } -const initialThingtime = { - nav: {}, - version: 22, - ...forceable, -} - -const userData = { +const initialValues = { settings: { - showCommander: true, + commanderActive: true, clearCommanderOnToggle: true, clearCommanderContextOnToggle: true, }, - ...forceable, + Content: { + hidden1: "Edit this to your heart's desire.", + "How?": "Just search for Content and edit the value to whatever you want.", + "Example:": `Content = New Content! + Content.Nested Content = New Nested Content! + `, + }, } +const initialThingtime = smarts.merge(initialValues, force) + export const ThingtimeProvider = (props: any): JSX.Element => { - const [thingtime, set] = React.useState({ - ...initialThingtime, - ...userData, - }) + const [thingtime, set] = React.useState(smarts.merge(initialValues, force)) const thingtimeRef = React.useRef(thingtime) @@ -61,15 +67,15 @@ export const ThingtimeProvider = (props: any): JSX.Element => { if (thingtimeFromLocalStorage) { const parsed = JSON.parse(thingtimeFromLocalStorage) if (parsed) { - const invalidLocalStorage = - !parsed.version || parsed.version < initialThingtime.version - if (!invalidLocalStorage) { - set(parsed) + const localIsValid = + !parsed.version || parsed.version >= force.version + if (localIsValid) { + const newThingtime = smarts.merge(force, parsed) + console.log("nik comm newThingtime", newThingtime) + set(newThingtime) } else { - const newThingtime = { - ...parsed, - ...initialThingtime, - } + const withVersionUpdates = smarts.merge(newVersionData, parsed) + const newThingtime = smarts.merge(force, withVersionUpdates) set(newThingtime) } } @@ -144,6 +150,7 @@ export const ThingtimeProvider = (props: any): JSX.Element => { try { window.setThingtime = setThingtime window.thingtime = thingtime + window.tt = thingtime } catch { // nothing } diff --git a/remix/app/components/Commander/Commander.tsx b/remix/app/components/Commander/Commander.tsx index a06ec01..1c67f2f 100644 --- a/remix/app/components/Commander/Commander.tsx +++ b/remix/app/components/Commander/Commander.tsx @@ -2,6 +2,7 @@ import React from "react" import ClickAwayListener from "react-click-away-listener" import { Center, Flex, Input } from "@chakra-ui/react" +import { Rainbow } from "../Rainbow/Rainbow" import { Thingtime } from "../Thingtime/Thingtime" import { useThingtime } from "../Thingtime/useThingtime" @@ -14,7 +15,7 @@ export const Commander = (props) => { const inputRef = React.useRef() const [value, setValue] = React.useState("") - + const [active, setActive] = React.useState(false) const [contextPath, setContextPath] = React.useState() const [showContext, setShowContextState] = React.useState(false) @@ -33,23 +34,25 @@ export const Commander = (props) => { return ret }, [contextPath, getThingtime]) - const showCommander = React.useMemo(() => { - return thingtime?.settings?.showCommander - }, [thingtime?.settings?.showCommander]) + const commanderActive = React.useMemo(() => { + return thingtime?.settings?.commanderActive + }, [thingtime?.settings?.commanderActive]) - // showCommander useEffect + console.log("nik commanderActive", commanderActive) + + // commanderActive useEffect React.useEffect(() => { - if (showCommander) { + if (commanderActive) { inputRef?.current?.focus?.() } else { if (thingtimeRef?.current?.settings?.clearCommanderOnToggle) { setValue("") } if (thingtimeRef?.current?.settings?.clearCommanderContextOnToggle) { - setShowContext(false, "showCommander useEffect") + setShowContext(false, "commanderActive useEffect") } } - }, [showCommander, thingtimeRef, setShowContext]) + }, [commanderActive, thingtimeRef, setShowContext]) const onChange = React.useCallback((e) => { setValue(e.target.value) @@ -165,7 +168,7 @@ export const Commander = (props) => { // setShowContext(true, 'Thingtime changes update suggestions') // } } - }, [value, thingtime, commandPath, setShowContext]) + }, [value, thingtime, commandPath]) const onEnter = React.useCallback( (props) => { @@ -202,6 +205,7 @@ export const Commander = (props) => { setShowContext, escapedCommandValue, setThingtime, + getThingtime, commandIsAction, commandPath, commandContainsPath, @@ -216,8 +220,8 @@ export const Commander = (props) => { e.stopPropagation() onEnter({ e }) // setThingtime( - // 'settings.showCommander', - // !thingtime?.settings?.showCommander + // 'settings.commanderActive', + // !thingtime?.settings?.commanderActive // ) } }, @@ -225,13 +229,18 @@ export const Commander = (props) => { ) const openCommander = React.useCallback(() => { - setThingtime("settings.showCommander", true) + console.log("nik commander opening commander") + setThingtime("settings.commanderActive", true) }, [setThingtime]) const closeCommander = React.useCallback(() => { - if (thingtime?.settings?.showCommander) { - setThingtime("settings.showCommander", false) + if (thingtime?.settings?.commanderActive) { + console.log("nik commander closing commander") + setThingtime("settings.commanderActive", false) } + + document.activeElement.blur() + if (value !== "") { setValue("") } @@ -241,15 +250,22 @@ export const Commander = (props) => { if (showContext !== false) { setShowContext(false) } - }, [setThingtime, setShowContext, value, contextPath, showContext]) + }, [ + setThingtime, + setShowContext, + value, + contextPath, + showContext, + thingtime?.settings?.commanderActive, + ]) const toggleCommander = React.useCallback(() => { - if (thingtime?.settings?.showCommander) { + if (thingtime?.settings?.commanderActive) { closeCommander() } else { openCommander() } - }, [thingtime?.settings?.showCommander, closeCommander, openCommander]) + }, [thingtime?.settings?.commanderActive, closeCommander, openCommander]) React.useEffect(() => { const keyListener = (e: any) => { @@ -295,11 +311,13 @@ export const Commander = (props) => { return "calc(100vw - 45px)" }, []) + const rainbowRepeats = 1 + return ( { -
- -
+ > + + + +
) diff --git a/remix/app/components/Rainbow/Rainbow.tsx b/remix/app/components/Rainbow/Rainbow.tsx index 1846589..c3e1327 100644 --- a/remix/app/components/Rainbow/Rainbow.tsx +++ b/remix/app/components/Rainbow/Rainbow.tsx @@ -1,14 +1,239 @@ import React from "react" -import { Box } from "@chakra-ui/react" +import { Box, Center } from "@chakra-ui/react" -export const Rainbow = (props: any): JSX.Element => { +import { GradientPath } from "~/gp/GradientPath" +import { useProps } from "~/hooks/useProps" +import { useTrace } from "~/hooks/useTrace" +import { useUuid } from "~/hooks/useUuid" + +export const Rainbow = (allProps: any): JSX.Element => { const rainbow = ["#f34a4a", "#ffbc48", "#58ca70", "#47b5e6", "#a555e8"] + const props = useProps(allProps) + + const uuid = useUuid() + + const [hidden, setHidden] = React.useState(true) + const repeats = props?.repeats || 1 + const [filter, setFilter] = React.useState(props?.filter) + const opacity = props?.opacity !== undefined ? props?.opacity : 1 const [colors, setColors] = React.useState(props?.colors || rainbow) + const [pathWidth, setPathWidth] = React.useState(props?.thickness || 1) + const [overflow, setOverflow] = React.useState(props?.overflow || "hidden") + const [opacityTransition, setOpacityTransition] = React.useState( + props?.opacityTransition || "all 10000ms ease" + ) + + const parentRef = React.useRef(null) + + const repeatedColours = React.useMemo(() => { + const ret = [] + + for (let i = 0; i < repeats; i++) { + ret.push(...colors) + } + + ret.push(colors[0]) + + return ret + }, [colors, repeats]) + + // make SVG that takes makes path in the shape of a box + // which adjusts to the parent containers size + + const [state, setState] = React.useState({ + width: 100, + height: 100, + }) + + const [strokeWidth, setStrokeWidth] = React.useState(1) + + const [extraStroke, setExtraStroke] = React.useState(0) + + const [width, setWidth] = React.useState(props?.width || "100%") + const [height, setHeight] = React.useState(props?.height || "100%") + + const pathString = React.useMemo(() => { + const startPoint = 0 + strokeWidth / 2 + const endPoint = 100 - strokeWidth / 2 + + return `M -${4} ${startPoint} H ${endPoint} V ${endPoint} H ${startPoint} V ${startPoint}` + }, [strokeWidth]) + + const svgRef = React.useRef(null) + + const colourKeyframes = React.useMemo(() => { + const ret = {} + + repeatedColours.map((colour, i) => { + const keyframe = `${(i / (repeatedColours.length - 1)) * 100}%` + ret[keyframe] = { + fill: colour, + stroke: colour, + } + }) + + return ret + }, [repeatedColours]) + + React.useEffect(() => { + const updateChildSize = () => { + const { width, height } = parentRef?.current?.getBoundingClientRect() + console.log("nik width height", width, height) + setState({ width, height }) + } + + updateChildSize() + + new ResizeObserver(updateChildSize).observe(parentRef?.current) + }, []) + + const rect = React.useMemo(() => { + return ( + + ) + }, [state?.width, state?.height]) + + const svg = React.useMemo(() => { + const id = Math.random().toString(36).substring(2, 15) + + return ( + + + {rect} + {/* */} + + + ) + }, [state, rect]) + + React.useEffect(() => { + if (uuid) { + const svg = svgRef?.current?.querySelector("svg") + + // path is rect or insert new rect if empty svg + const rectSource = parentRef?.current?.querySelector(".svg-source rect") + const path = + svg?.querySelector?.("rect") || + svg?.appendChild?.(rectSource?.cloneNode?.()) + + if (path) { + console.log("nik re-rendering rainbow") + const gp = new GradientPath({ + path, + segments: props?.segments || 1000, + samples: props?.samples || 1, + precision: props?.precision || 5, + }) + + gp.render({ + type: "path", + width: pathWidth || 1, + animation: { + name: `rainbow-${uuid}`, + duration: 5, + }, + }) + + setTimeout(() => { + setHidden(false) + }, 500) + + return () => { + // setHidden(true) + gp.remove() + } + } + } + }, [ + uuid, + props?.segments, + props?.samples, + props?.precision, + pathWidth, + repeatedColours, + parentRef, + svgRef, + rect, + ]) + + const render = true + + useTrace("Rainbow", { + props, + }) return ( - - {props?.children} - + <> +
+
+ {/* debug svg */} + + {svg} + + + {svg} + +
+ {allProps?.children} +
+ ) } diff --git a/remix/app/gp/GradientPath.js b/remix/app/gp/GradientPath.js new file mode 100644 index 0000000..1ba1198 --- /dev/null +++ b/remix/app/gp/GradientPath.js @@ -0,0 +1,105 @@ +import { DEFAULT_PRECISION } from "./_constants" +import { getData, strokeToFill } from "./_data" +import { convertPathToNode, segmentToD, styleAttrs, svgElem } from "./_utils" + +export const GradientPath = class { + constructor({ path, segments, samples, precision = DEFAULT_PRECISION }) { + // If the path being passed isn't a DOM node already, make it one + this.path = convertPathToNode(path) + + this.segments = segments + this.samples = samples + this.precision = precision + + // Check if nodeName is path and that the path is closed, otherwise it's closed by default + this.pathClosed = + this.path.nodeName == "path" + ? this.path.getAttribute("d").match(/z/gi) + : true + + // Store the render cycles that the user creates + this.renders = [] + + // Append a group to the SVG to capture everything we render and ensure our paths and circles are properly encapsulated + this.svg = path.closest("svg") + this.group = svgElem("g", { + class: "gradient-path", + }) + + // Get the data + this.data = getData({ path, segments, samples, precision }) + + // Append the main group to the SVG + this.svg.appendChild(this.group) + + // Remove the main path once we have the data values + this.path.parentNode.removeChild(this.path) + } + + remove() { + this.group.parentNode.removeChild(this.group) + } + + render({ + type, + stroke = ["white", "black", "white"], + strokeWidth = 1, + fill = ["white", "black", "white"], + width, + animation = {}, + }) { + // Store information from this render cycle + const renderCycle = {} + + // Create a group for each element + const elemGroup = svgElem("g", { class: `element-${type}` }) + + this.group.appendChild(elemGroup) + renderCycle.group = elemGroup + + if (type === "path") { + // If we specify a width and fill, then we need to outline the path and then average the join points of the segments + // If we do not specify a width and fill, then we will be stroking and can leave the data "as is" + renderCycle.data = + width && fill + ? strokeToFill(this.data, width, this.precision, this.pathClosed) + : this.data + + for (let j = 0; j < renderCycle.data.length; j++) { + const { samples, progress } = renderCycle.data[j] + + // Create a path for each segment and append it to its elemGroup + elemGroup.appendChild( + svgElem("path", { + class: "path-segment", + d: segmentToD(samples), + ...styleAttrs(fill, stroke, strokeWidth, progress, animation), + }) + ) + } + } else if (type === "circle") { + renderCycle.data = this.data.flatMap(({ samples }) => samples) + + for (let j = 0; j < renderCycle.data.length; j++) { + const { x, y, progress } = renderCycle.data[j] + + // Create a circle for each sample and append it to its elemGroup + elemGroup.appendChild( + svgElem("circle", { + class: "circle-sample", + cx: x, + cy: y, + r: width / 2, + ...styleAttrs(fill, stroke, strokeWidth, progress, animation), + }) + ) + } + } + + // Save the information in the current renderCycle and pop it onto the renders array + this.renders.push(renderCycle) + + // Return this for method chaining + return this + } +} diff --git a/remix/app/gp/Sample.js b/remix/app/gp/Sample.js new file mode 100644 index 0000000..76432d3 --- /dev/null +++ b/remix/app/gp/Sample.js @@ -0,0 +1,8 @@ +export default class Sample { + constructor({ x, y, progress, segment }) { + this.x = x; + this.y = y; + this.progress = progress; + this.segment = segment; + } +} diff --git a/remix/app/gp/Segment.js b/remix/app/gp/Segment.js new file mode 100644 index 0000000..310902c --- /dev/null +++ b/remix/app/gp/Segment.js @@ -0,0 +1,8 @@ +import { getMiddleSample } from './_utils'; + +export default class Segment { + constructor({ samples }) { + this.samples = samples; + this.progress = getMiddleSample(samples).progress; + } +} diff --git a/remix/app/gp/_constants.js b/remix/app/gp/_constants.js new file mode 100644 index 0000000..ed3a507 --- /dev/null +++ b/remix/app/gp/_constants.js @@ -0,0 +1 @@ +export const DEFAULT_PRECISION = 2; diff --git a/remix/app/gp/_data.js b/remix/app/gp/_data.js new file mode 100644 index 0000000..e0256d6 --- /dev/null +++ b/remix/app/gp/_data.js @@ -0,0 +1,219 @@ +import Sample from './Sample'; +import Segment from './Segment'; +import { convertPathToNode } from './_utils'; +import { DEFAULT_PRECISION } from './_constants'; + +// The main function responsible for getting data +// This will take a path, number of samples, number of samples, and a precision value +// It will return an array of Segments, which in turn contains an array of Samples +// This can later be used to generate a stroked path, converted to outlines for a filled path, or flattened for plotting SVG circles +export const getData = ({ + path, + segments, + samples, + precision = DEFAULT_PRECISION +}) => { + // Convert the given path to a DOM node if it isn't already one + path = convertPathToNode(path); + + // We decrement the number of samples per segment because when we group them later we will add on the first sample of the following segment + if (samples > 1) samples--; + + // Get total length of path, total number of samples we will be generating, and two blank arrays to hold samples and segments + const pathLength = path.getTotalLength(), + totalSamples = segments * samples, + allSamples = [], + allSegments = []; + + // For the number of total samples, get the x, y, and progress values for each sample along the path + for (let sample = 0; sample <= totalSamples; sample++) { + const progress = sample / totalSamples; + + let { x, y } = path.getPointAtLength(progress * pathLength); + + // If the user asks to round our x and y values, do so + if (precision) { + x = +x.toFixed(precision); + y = +y.toFixed(precision); + } + + // Create a new Sample and push it onto the allSamples array + allSamples.push(new Sample({ x, y, progress })); + } + + // Out of all the samples gathered previously, sort them into groups of segments + // Each group includes the samples of the current segment, with the last sample being first sample from the next segment + for (let segment = 0; segment < segments; segment++) { + const currentStart = segment * samples, + nextStart = currentStart + samples, + segmentSamples = []; + + // Push all current samples onto segmentSamples + for (let samInSeg = 0; samInSeg < samples; samInSeg++) { + segmentSamples.push(allSamples[currentStart + samInSeg]); + } + + // Push the first sample from the next segment onto segmentSamples + segmentSamples.push(allSamples[nextStart]); + + // Create a new Segment with the samples from segmentSamples + allSegments.push(new Segment({ samples: segmentSamples })); + } + + // Return our group of segments + return allSegments; +}; + +// The function responsible for converting strokable data (from getData()) into fillable data +// This allows any SVG path to be filled instead of just stroked, allowing for the user to fill and stroke paths simultaneously +// We start by outlining the stroked data given a specified width and the we average together the edges where adjacent segments touch +export const strokeToFill = (data, width, precision, pathClosed) => { + const outlinedStrokes = outlineStrokes(data, width, precision), + averagedSegmentJoins = averageSegmentJoins( + outlinedStrokes, + precision, + pathClosed + ); + + return averagedSegmentJoins; +}; + +// An internal function for outlining stroked data +const outlineStrokes = (data, width, precision) => { + // We need to get the points perpendicular to a startPoint, given an angle, radius, and precision + const getPerpSamples = (angle, radius, precision, startPoint) => { + const p0 = new Sample({ + ...startPoint, + x: Math.sin(angle) * radius + startPoint.x, + y: -Math.cos(angle) * radius + startPoint.y + }), + p1 = new Sample({ + ...startPoint, + x: -Math.sin(angle) * radius + startPoint.x, + y: Math.cos(angle) * radius + startPoint.y + }); + + // If the user asks to round our x and y values, do so + if (precision) { + p0.x = +p0.x.toFixed(precision); + p0.y = +p0.y.toFixed(precision); + p1.x = +p1.x.toFixed(precision); + p1.y = +p1.y.toFixed(precision); + } + + return [p0, p1]; + }; + + // We need to set the radius (half of the width) and have a holding array for outlined Segments + const radius = width / 2, + outlinedData = []; + + for (let i = 0; i < data.length; i++) { + const samples = data[i].samples, + segmentSamples = []; + + // For each sample point and the following sample point (if there is one) compute the angle + // Also compute the sample's various perpendicular points (with a distance of radius away from the sample point) + for (let j = 0; j < samples.length; j++) { + // If we're at the end of the segment and there are no further points, get outta here! + if (samples[j + 1] === undefined) break; + + const p0 = samples[j], // First point + p1 = samples[j + 1], // Second point + angle = Math.atan2(p1.y - p0.y, p1.x - p0.x), // Perpendicular angle to p0 and p1 + p0Perps = getPerpSamples(angle, radius, precision, p0), // Get perpedicular points with a distance of radius away from p0 + p1Perps = getPerpSamples(angle, radius, precision, p1); // Get perpedicular points with a distance of radius away from p1 + + // We only need the p0 perpendenciular points for the first sample + // The p0 for j > 0 will always be the same as p1 anyhow, so let's not add redundant points + if (j === 0) { + segmentSamples.push(...p0Perps); + } + + // Always push the second sample point's perpendicular points + segmentSamples.push(...p1Perps); + } + + // segmentSamples is out of order... + // Given a segmentSamples length of 8, the points need to be rearranged from: 0, 2, 4, 6, 7, 5, 3, 1 + outlinedData.push( + new Segment({ + samples: [ + ...segmentSamples.filter((s, i) => i % 2 === 0), + ...segmentSamples.filter((s, i) => i % 2 === 1).reverse() + ] + }) + ); + } + + return outlinedData; +}; + +// An internal function taking outlinedData (from outlineStrokes()) and averaging adjacent edges +// If we didn't do this, our data would be fillable, but it would look stroked +// This function fixes where segments overlap and underlap each other +const averageSegmentJoins = (outlinedData, precision, pathClosed) => { + // Find the average x and y between two points (p0 and p1) + const avg = (p0, p1) => ({ + x: (p0.x + p1.x) / 2, + y: (p0.y + p1.y) / 2 + }); + + // Recombine the new x and y positions with all the other keys in the object + const combine = (segment, pos, avg) => ({ + ...segment[pos], + x: avg.x, + y: avg.y + }); + + const init_outlinedData = JSON.parse(JSON.stringify(outlinedData)); //clone initial outlinedData Object + + for (let i = 0; i < outlinedData.length; i++) { + // If path is closed: the current segment's samples; + // If path is open: the current segments' samples, as long as it's not the last segment; Otherwise, the current segments' sample of the initial outlinedData object + const currentSamples = pathClosed + ? outlinedData[i].samples + : outlinedData[i + 1] + ? outlinedData[i].samples + : init_outlinedData[i].samples, + // If path is closed: the next segment's samples, otherwise, the first segment's samples + // If path is open: the next segment's samples, otherwise, the first segment's samples of the initial outlinedData object + nextSamples = pathClosed + ? outlinedData[i + 1] + ? outlinedData[i + 1].samples + : outlinedData[0].samples + : outlinedData[i + 1] + ? outlinedData[i + 1].samples + : init_outlinedData[0].samples, + currentMiddle = currentSamples.length / 2, // The "middle" sample in the current segment's samples + nextEnd = nextSamples.length - 1; // The last sample in the next segment's samples + + // Average two sets of outlined samples to create p0Average and p1Average + const p0Average = avg(currentSamples[currentMiddle - 1], nextSamples[0]), + p1Average = avg(currentSamples[currentMiddle], nextSamples[nextEnd]); + + // If the user asks to round our x and y values, do so + if (precision) { + p0Average.x = +p0Average.x.toFixed(precision); + p0Average.y = +p0Average.y.toFixed(precision); + p1Average.x = +p1Average.x.toFixed(precision); + p1Average.y = +p1Average.y.toFixed(precision); + } + + // Replace the previous values with new Samples + currentSamples[currentMiddle - 1] = new Sample({ + ...combine(currentSamples, currentMiddle - 1, p0Average) + }); + currentSamples[currentMiddle] = new Sample({ + ...combine(currentSamples, currentMiddle, p1Average) + }); + nextSamples[0] = new Sample({ + ...combine(nextSamples, 0, p0Average) + }); + nextSamples[nextEnd] = new Sample({ + ...combine(nextSamples, nextEnd, p1Average) + }); + } + + return outlinedData; +}; diff --git a/remix/app/gp/_utils.js b/remix/app/gp/_utils.js new file mode 100644 index 0000000..e9069d7 --- /dev/null +++ b/remix/app/gp/_utils.js @@ -0,0 +1,90 @@ +import tinygradient from "tinygradient" + +// An internal function to help with easily creating SVG elements with an object of attributes +export const svgElem = (type, attrs) => { + const elem = document.createElementNS("http://www.w3.org/2000/svg", type), + attributes = Object.keys(attrs) + + for (let i = 0; i < attributes.length; i++) { + const attr = attributes[i] + + elem.setAttribute(attr, attrs[attr]) + } + + return elem +} + +// An internal function to help with the repetition of adding fill, stroke, and stroke-width attributes +export const styleAttrs = ( + fill, + stroke, + strokeWidth, + progress, + animation +) => { + const determineColor = (type, progress) => + typeof type === "string" ? type : tinygradient(type).rgbAt(progress) + + const attrs = {} + + if (stroke) { + attrs["stroke"] = determineColor(stroke, progress) + attrs["stroke-width"] = strokeWidth + } + + if (fill) { + attrs["fill"] = determineColor(fill, progress) + } + + if (animation?.name) { + // TODO: add animation-direction support + + const duration = animation.duration || 5 + + attrs["style"] = ` + animation-name: ${animation?.name}; + animation-delay: ${progress * duration - duration}s; + animation-duration: ${duration}s; + animation-iteration-count: infinite; + animation-timing-function: linear;` + } + + return attrs +} + +// An internal function to convert any array of samples into a "d" attribute to be passed to an SVG path +export const segmentToD = (samples) => { + let d = "" + + for (let i = 0; i < samples.length; i++) { + const { x, y } = samples[i], + prevSample = i === 0 ? null : samples[i - 1] + + if (i === 0 && i !== samples.length - 1) { + d += `M${x},${y}` + } else if (x !== prevSample.x && y !== prevSample.y) { + d += `L${x},${y}` + } else if (x !== prevSample.x) { + d += `H${x}` + } else if (y !== prevSample.y) { + d += `V${y}` + } + + if (i === samples.length - 1) { + d += "Z" + } + } + + return d +} + +// An internal function for getting the colors of a segment, we need to get middle most sample (sorted by progress along the path) +export const getMiddleSample = (samples) => { + const sortedSamples = [...samples].sort((a, b) => a.progress - b.progress) + + return sortedSamples[(sortedSamples.length / 2) | 0] +} + +// An internal function for converting any D3 selection or DOM-like element into a DOM node +export const convertPathToNode = (path) => + path instanceof Element || path instanceof HTMLDocument ? path : path.node() diff --git a/remix/app/gp/index.js b/remix/app/gp/index.js new file mode 100644 index 0000000..6d907e1 --- /dev/null +++ b/remix/app/gp/index.js @@ -0,0 +1,2 @@ +export { default as GradientPath } from './GradientPath'; +export { getData, strokeToFill } from './_data'; diff --git a/remix/app/hooks/useProps.tsx b/remix/app/hooks/useProps.tsx new file mode 100644 index 0000000..a5c6576 --- /dev/null +++ b/remix/app/hooks/useProps.tsx @@ -0,0 +1,10 @@ +import React from "react" + +export const useProps = (allProps) => { + const deps = Object.values(allProps).filter((v) => v !== allProps.children) + + return React.useMemo(() => { + const { children, ...other } = allProps + return other + }, deps) +} diff --git a/remix/app/hooks/useTrace.tsx b/remix/app/hooks/useTrace.tsx new file mode 100644 index 0000000..74f6591 --- /dev/null +++ b/remix/app/hooks/useTrace.tsx @@ -0,0 +1,25 @@ +import React from "react" + +export const useTrace = (name, props) => { + const prev = React.useRef(props) + React.useEffect(() => { + const changedProps = Object.entries(props).reduce( + (changedValues, [key, newValue]) => { + window.trace = window.trace || {} + window.trace[key] = newValue + if (prev.current[key] !== newValue) { + changedValues[key] = { + old: prev.current[key], + new: newValue, + } + } + return changedValues + }, + {} + ) + if (Object.keys(changedProps)?.length) { + console.table({ TT: { name }, ...changedProps }) + } + prev.current = props + }) +} diff --git a/remix/app/hooks/useUuid.tsx b/remix/app/hooks/useUuid.tsx new file mode 100644 index 0000000..02497db --- /dev/null +++ b/remix/app/hooks/useUuid.tsx @@ -0,0 +1,11 @@ +import React from "react" + +export const useUuid = () => { + const [uuid, setUuid] = React.useState() + + React.useEffect(() => { + setUuid(Math.random().toString(36).substring(7)) + }, []) + + return uuid +} diff --git a/remix/app/routes/index.tsx b/remix/app/routes/index.tsx index aba5941..3bcd08b 100644 --- a/remix/app/routes/index.tsx +++ b/remix/app/routes/index.tsx @@ -1,11 +1,11 @@ import { Box, Flex } from "@chakra-ui/react" import { ProfileDrawer } from "~/components/Nav/ProfileDrawer" -import { Rainbow } from "~/components/Rainbow/Rainbow" import { Splash } from "~/components/Splash/Splash" import { Thingtime } from "~/components/Thingtime/Thingtime" import { ThingtimeDemo } from "~/components/Thingtime/ThingtimeDemo" import { useThingtime } from "~/components/Thingtime/useThingtime" +import { GradientPath } from "~/gp/GradientPath" export default function Index() { const { thingtime } = useThingtime() @@ -17,10 +17,7 @@ export default function Index() { flexDirection="column" maxWidth="100%" > - - - - + {/* */} {} // window.Buffer = Buffer @@ -56,46 +56,46 @@ export const save = (value, opts) => { // extract parent path from dot delimitted path -export const getParentPath = path => { - const parts = path.split('.') +export const getParentPath = (path) => { + const parts = path.split(".") parts.pop() - return parts.join('.') + return parts.join(".") } export const toJavascript = (value, opts = {}) => { - let defaultOpts = { + const defaultOpts = { wrapInFunction: true, declarations: [], - identifier: 'obj', + identifier: "obj", keys: { - obj: 1 + obj: 1, }, dependancies: {}, mappings: [], seen: [], - db: [] + db: [], } Object.assign(defaultOpts, opts) opts = defaultOpts toJavascriptAux(value, opts) // sort declarations by dependancies - for (let declaration of opts.declarations) { - if (declaration.type === 'ExpressionStatement') { + for (const declaration of opts.declarations) { + if (declaration.type === "ExpressionStatement") { // nothing } else { - let key = declaration.declarations[0].id.name - let dependancies = opts.dependancies[key] - let dependancyCheck = {} - for (let dependancy of dependancies) { + const key = declaration.declarations[0].id.name + const dependancies = opts.dependancies[key] + const dependancyCheck = {} + for (const dependancy of dependancies) { dependancyCheck[dependancy] = false } let sortableDeclarationIndex = 0 let insertionIndex = 0 - for (let sortableDeclaration of opts.declarations) { - if (sortableDeclaration.type === 'ExpressionStatement') { + for (const sortableDeclaration of opts.declarations) { + if (sortableDeclaration.type === "ExpressionStatement") { // nothing } else { - let sortableDeclarationKey = + const sortableDeclarationKey = sortableDeclaration.declarations[0].id.name if (dependancyCheck[sortableDeclarationKey] === false) { insertionIndex = sortableDeclarationIndex + 1 @@ -105,15 +105,15 @@ export const toJavascript = (value, opts = {}) => { // increment iterator index sortableDeclarationIndex++ } - let declarationIndex = opts.declarations.indexOf(declaration) + const declarationIndex = opts.declarations.indexOf(declaration) opts.declarations.splice(declarationIndex, 1) opts.declarations.splice(insertionIndex, 0, declaration) } } let program if (opts.wrapInFunction && !opts.moduleExport) { - opts.declarations.push(t.returnStatement(t.identifier('obj'))) - let expression = t.expressionStatement( + opts.declarations.push(t.returnStatement(t.identifier("obj"))) + const expression = t.expressionStatement( t.callExpression( t.functionExpression(null, [], t.blockStatement(opts.declarations)), [] @@ -125,65 +125,65 @@ export const toJavascript = (value, opts = {}) => { opts.declarations.push( t.expressionStatement( t.assignmentExpression( - '=', - t.memberExpression(t.identifier('module'), t.identifier('exports')), - t.identifier('obj') + "=", + t.memberExpression(t.identifier("module"), t.identifier("exports")), + t.identifier("obj") ) ) ) } program = t.program(opts.declarations) } - let stringifiedProgram = getBabel().generator(program).code + const stringifiedProgram = getBabel().generator(program).code return getBabel().prettier.format(stringifiedProgram, { semi: false, - parser: 'babel', - useTabs: true + parser: "babel", + useTabs: true, }) } export const toJavascriptAux = (value, opts) => { - if (typeof value === 'object') { + if (typeof value === "object") { if (!opts.seen.includes(value)) { // update map and seen opts.seen.push(value) - let properties = createObjectProperties(value, opts) - let declaration = t.variableDeclaration('let', [ + const properties = createObjectProperties(value, opts) + const declaration = t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(opts.identifier), t.objectExpression(properties) - ) + ), ]) opts.declarations.unshift(declaration) - for (let key of Object.keys(value)) { - let property = properties.find(v => { + for (const key of Object.keys(value)) { + const property = properties.find((v) => { return v.value.name === key }) if (property) { - let identifier = property.value.name + const identifier = property.value.name toJavascriptAux(value[key], { ...opts, identifier }) } } } - } else if (typeof value === 'string') { - let declaration = t.variableDeclaration('let', [ + } else if (typeof value === "string") { + const declaration = t.variableDeclaration("let", [ t.variableDeclarator( t.identifier(opts.identifier), t.stringLiteral(value) - ) + ), ]) opts.declarations.unshift(declaration) } } export const createObjectProperties = (value, opts) => { - let properties = [] + const properties = [] let dependancies = opts.dependancies[opts.identifier] if (!dependancies) dependancies = opts.dependancies[opts.identifier] = [] - for (let key of Object.keys(value)) { + for (const key of Object.keys(value)) { if (value[key] === value) { opts.declarations.push( t.expressionStatement( t.assignmentExpression( - '=', + "=", t.memberExpression( t.identifier(opts.identifier), t.identifier(key) @@ -198,7 +198,7 @@ export const createObjectProperties = (value, opts) => { if (opts.keys[key] === undefined) { opts.keys[key] = 1 } - let keyIncrement = opts.keys[key] + const keyIncrement = opts.keys[key] if (keyIncrement == 1) { opts.mappings.push(key) } else { @@ -206,7 +206,7 @@ export const createObjectProperties = (value, opts) => { } opts.keys[key]++ } - let identifier = opts.mappings[opts.db.indexOf(value[key])] + const identifier = opts.mappings[opts.db.indexOf(value[key])] dependancies.push(identifier) properties.push( t.objectProperty( @@ -226,23 +226,23 @@ export const serialize = (value, opts = {}) => { return stringify(value, opts) } export const stringify = (value, opts = {}) => { - let schema = { + const schema = { stringifier: stringifier, - replace (key, value) { + replace(key, value) { if (opts.firstRun) { opts.firstRun = !opts.firstRun return value } - var after = opts.stringifier(key, value, opts) + const after = opts.stringifier(key, value, opts) const type = typeof after.value - if (type === 'object') { + if (type === "object") { if (after === null || after.value === null) { const ret = after.value return ret } - } else if (type === 'string') { + } else if (type === "string") { const ret = opts.known.get(after.key) || setKnown(opts.known, opts.input, after) return ret @@ -254,16 +254,16 @@ export const stringify = (value, opts = {}) => { firstRun: undefined, known: new Map(), input: [], - output: [] + output: [], } - Object.keys(schema).forEach(key => { + Object.keys(schema).forEach((key) => { if (getsmart(opts, epp(key), { undefined: true }, true).undefined == true) { opts[key] = schema[key] } }) - opts.virtual = opts.stringifier('', value, opts) + opts.virtual = opts.stringifier("", value, opts) for ( let i = parseInt(setKnown(opts.known, opts.input, opts.virtual)); i < opts.input.length; @@ -276,7 +276,7 @@ export const stringify = (value, opts = {}) => { console.error(err) } } - return '[' + opts.output.join(',') + ']' + return "[" + opts.output.join(",") + "]" } export const replacer = (key, value) => { const opts = opts || {} @@ -285,17 +285,17 @@ export const replacer = (key, value) => { opts.firstRun = !opts.firstRun return value } - var after = opts.stringifier(key, value, opts) + const after = opts.stringifier(key, value, opts) // replace with if statements const type = typeof after.value - if (type === 'object') { + if (type === "object") { if (after === null) { const ret = after.value return ret } - } else if (type === 'string') { + } else if (type === "string") { const ret = opts.known.get(after.key) || setKnown(opts.known, opts.input, after) return ret @@ -303,7 +303,7 @@ export const replacer = (key, value) => { return after.value } export const setKnown = (known, input, virtual) => { - var index = String(input.push(virtual.value) - 1) + const index = String(input.push(virtual.value) - 1) known.set(virtual.key, index) return index } @@ -311,63 +311,63 @@ export const stringifier = (key, val, opts) => { let ret = { value: val, key: val } if ( val instanceof Function && - typeof val.toString === 'function' && - (!opts.strictFunctions || typeof val.$scopes != 'undefined') + typeof val.toString === "function" && + (!opts.strictFunctions || typeof val.$scopes != "undefined") ) { - let known = opts.known.get(ret.key) + const known = opts.known.get(ret.key) ret = { value: known || { - type: 'function', + type: "function", js: val.toString(), $scopes: val.$scopes, $context: val.$context, - ...val + ...val, }, - key: val + key: val, } - if (ret.value.js == 'function () { [native code] }') return - if (typeof known == 'undefined') setKnown(opts.known, opts.input, ret) - } else if (ret.value === Infinity && typeof ret.value != 'string') { - let known = opts.known.get(ret.key) + if (ret.value.js == "function () { [native code] }") return + if (typeof known == "undefined") setKnown(opts.known, opts.input, ret) + } else if (ret.value === Infinity && typeof ret.value != "string") { + const known = opts.known.get(ret.key) ret = { value: known || { - type: 'number', - js: 'Infinity', + type: "number", + js: "Infinity", $scopes: [], - $context: {} + $context: {}, }, - key: val + key: val, } - if (typeof known == 'undefined') setKnown(opts.known, opts.input, ret) - } else if (typeof ret.value === 'undefined') { + if (typeof known == "undefined") setKnown(opts.known, opts.input, ret) + } else if (typeof ret.value === "undefined") { ret = { value: { - type: 'undefined', - js: 'undefined' + type: "undefined", + js: "undefined", }, - key: val + key: val, } } else if (ret.value instanceof Array && opts.serializeArrayProps) { - let known = opts.known.get(ret.key) + const known = opts.known.get(ret.key) ret = { value: known ? ret.value : { - type: 'Array', + type: "Array", js: ret.value, - uuid: ret.value.uuid + uuid: ret.value.uuid, }, - key: val + key: val, } setKnown(opts.known, opts.input, ret) } return ret } -export const primitives = value => { +export const primitives = (value) => { return value instanceof String ? String(value) : value } export const Primitives = (key, value) => { - return typeof value === 'string' ? new String(value) : value + return typeof value === "string" ? new String(value) : value } export const play = (text, opts) => { return parse(text, opts) @@ -377,17 +377,17 @@ export const load = (text, opts = {}) => { return parse(text, opts) } export const parse = (text, opts = {}) => { - let schema = { + const schema = { // parser: eval('(function '+parser+')'), parser: parser(opts), value: {}, strictFunctions: true, noFunctions: false, firstPass: true, - output: new Map() + output: new Map(), } - Object.keys(schema).forEach(key => { + Object.keys(schema).forEach((key) => { if (getsmart(opts, epp(key), { undefined: true }, true).undefined == true) { opts[key] = schema[key] } @@ -398,52 +398,52 @@ export const parse = (text, opts = {}) => { opts.firstPass = false opts.input = opts.input.map(primitives) opts.value = opts.input[0] - let isObject = typeof opts.value === 'object' && opts.value - var tmp = isObject + const isObject = typeof opts.value === "object" && opts.value + const tmp = isObject ? revive(opts.input, opts.output, opts.value, opts.parser, opts) : opts.value opts.replaceMode = true let ret = revive(opts.input, new Map(), tmp, opts.parser, opts) - ret = opts.parser('', tmp, opts) + ret = opts.parser("", tmp, opts) return ret } -export const parser = opts => { +export const parser = (opts) => { return function (key, val) { - if (val.js && val.type === 'Array') { + if (val.js && val.type === "Array") { const ret = opts.input[opts.output.get(val)].js ret.uuid = opts.input[opts.output.get(val)].uuid return ret } else if ( val.js && - val.type === 'function' && + val.type === "function" && opts.replaceMode && !opts.noFunctions ) { let ret = opts.input[opts.output.get(val)] if (typeof ret == val.type) return ret - let uuid = jsUUID() - var fn - var scopedEval - if (val.$scopedEval && typeof val.$scopedEval == 'function') { + const uuid = jsUUID() + let fn + let scopedEval + if (val.$scopedEval && typeof val.$scopedEval == "function") { scopedEval = val.$scopedEval } else { - var fns = createScopedEval(uuid) + const fns = createScopedEval(uuid) try { fn = eval(`(${fns})`) - var input = { val, smarts } + const input = { val, smarts } scopedEval = fn(input) } catch (err) { - console.log('Caught error evaling createScopedEval', err) + console.log("Caught error evaling createScopedEval", err) } } ret = scopedEval({ val }) try { - Object.defineProperty(ret, '$scopes', { + Object.defineProperty(ret, "$scopes", { value: val.$scopes, - enumerable: true + enumerable: true, }) if (val.uuid) { ret.uuid = val.uuid @@ -452,17 +452,17 @@ export const parser = opts => { if (opts.verbose) console.error(err) } try { - Object.defineProperty(ret, '$context', { + Object.defineProperty(ret, "$context", { value: val.$context, - enumerable: true + enumerable: true, }) } catch (err) { if (opts.verbose) console.error(err) } try { - Object.defineProperty(ret, '$scopedEval', { + Object.defineProperty(ret, "$scopedEval", { value: scopedEval, - enumerable: true + enumerable: true, }) } catch (err) { if (opts.verbose) console.error(err) @@ -477,11 +477,11 @@ export const parser = opts => { } export const revive = (input, parsed, output, parser, opts) => { return Object.keys(output).reduce((output, key) => { - var value = output[key] + let value = output[key] // if the value hasn't been revived yet if (value instanceof String) { - var tmp = input[value] - if (typeof tmp === 'object' && !parsed.get(tmp)) { + const tmp = input[value] + if (typeof tmp === "object" && !parsed.get(tmp)) { parsed.set(tmp, value) output[key] = primitives( parser(key, revive(input, parsed, tmp, parser, opts)) @@ -498,7 +498,7 @@ export const revive = (input, parsed, output, parser, opts) => { if (opts.replaceMode) { // output[key] = primitives(parser(key, revive(input, parsed, value, parser, opts))) value = parser(key, value) - if (typeof value === 'object' && !parsed.get(value)) { + if (typeof value === "object" && !parsed.get(value)) { parsed.set(value, value) output[key] = primitives( parser(key, revive(input, parsed, value, parser, opts)) @@ -520,8 +520,8 @@ export const revive = (input, parsed, output, parser, opts) => { return output }, output) } -export const createScopedEval = uuid => { - let ret = /*javascript*/ ` +export const createScopedEval = (uuid) => { + const ret = /*javascript*/ ` function createScopedEval(${uuid}){ // scopeCode @@ -633,7 +633,7 @@ export const createScopedEval = uuid => { ` return ret } -export const defineVariable = uuid => { +export const defineVariable = (uuid) => { return /*javascript*/ ` ${uuid.variableType} ${uuid.variableKey} = ${uuid}.$scope[${uuid}.variableKey] Object.defineProperty( @@ -651,8 +651,8 @@ export const defineVariable = uuid => { ) ` } -export const scopedEval = uuid => { - let ret = /*javascript*/ `function scopedEval(${uuid}){ +export const scopedEval = (uuid) => { + const ret = /*javascript*/ `function scopedEval(${uuid}){ if(typeof ${uuid} == 'string'){ ${uuid} = { val: { @@ -688,11 +688,11 @@ export const scopedEval = uuid => { ` return ret } -export const jsUUID = (prefix = 'uuid') => { - return prefix + uuid().replace(/-/g, '') +export const jsUUID = (prefix = "uuid") => { + return prefix + uuid().replace(/-/g, "") } -export const context = opts => { - let uuid = gosmart.bind(this)(opts, 'path.context.scope.uuid', jsUUID()) +export const context = (opts) => { + const uuid = gosmart.bind(this)(opts, "path.context.scope.uuid", jsUUID()) return eval(/*javascript*/ ` ( function(){ @@ -702,7 +702,7 @@ export const context = opts => { )() `) } -export const contextObject = uuid => { +export const contextObject = (uuid) => { return /*javascript*/ ` let ${uuid} = { $$uuid: '${uuid}', @@ -752,7 +752,7 @@ export const contextObject = uuid => { $parentContexts: [], $contextStatus: "var", $mode: (eval("var ${uuid}1 = null"), (typeof ${ - uuid + '1' + uuid + "1" } === "undefined")) ? "strict" : "non-strict", } ${uuid}.$functionScoper = ${uuid}.$functionScoper(${uuid}.$functionScoper) @@ -795,43 +795,43 @@ export const contextObject = uuid => { } ` } -export const createContext = opts => { +export const createContext = (opts) => { schema(opts, { - wrapBody: true + wrapBody: true, }) - let node = opts.aster(/*javascript*/ ` + const node = opts.aster(/*javascript*/ ` ${contextObject(opts.uuid)} `) node[0].declarations[0].contextDeclaration = true // so the $functionScoper function doesn't get wrapped or have $context inserted - let property3 = node[0].declarations[0].init.properties[3] + const property3 = node[0].declarations[0].init.properties[3] property3.value.scoperWrapped = true property3.value.body.scopeInitialized = true - let property3ScopesValue = + const property3ScopesValue = property3.value.body.body[0].expression.arguments[2].properties[0].value property3ScopesValue.callee.scoperWrapped = true property3ScopesValue.callee.body.scopeInitialized = true - let property3ForStatement = property3ScopesValue.callee.body.body[0] + const property3ForStatement = property3ScopesValue.callee.body.body[0] property3ForStatement.body.scopeInitialized = true property3ForStatement.init.declarations[0].inScope = true property3ForStatement.init.declarations[1].inScope = true // so the $add function doesn't get wrapped or have $context inserted - let property4 = node[0].declarations[0].init.properties[4] + const property4 = node[0].declarations[0].init.properties[4] property4.value.scoperWrapped = true property4.value.body.scopeInitialized = true // so the $scopes self-invoking function doesn't get wrapped or have $context inserted - let property5 = node[0].declarations[0].init.properties[5] + const property5 = node[0].declarations[0].init.properties[5] property5.value.callee.scoperWrapped = true property5.value.callee.body.scopeInitialized = true - let property5ForStatement = property5.value.callee.body.body[0] + const property5ForStatement = property5.value.callee.body.body[0] property5ForStatement.body.scopeInitialized = true property5ForStatement.init.declarations[0].inScope = true property5ForStatement.init.declarations[1].inScope = true // so the $variableMaps self-invoking function doesn't get wrapped or have $context inserted - let property6 = node[0].declarations[0].init.properties[6] + const property6 = node[0].declarations[0].init.properties[6] property6.value.callee.scoperWrapped = true property6.value.callee.body.scopeInitialized = true - let property6ForStatement = property6.value.callee.body.body[0] + const property6ForStatement = property6.value.callee.body.body[0] property6ForStatement.body.scopeInitialized = true property6ForStatement.init.declarations[0].inScope = true property6ForStatement.init.declarations[1].inScope = true @@ -853,7 +853,7 @@ export const createContext = opts => { node10.inheritScope = true node[node.length - 1].lastContextNode = true if (opts.wrapBody) { - let bodyWrapper = node[node.length - 1] + const bodyWrapper = node[node.length - 1] bodyWrapper.body.push(...opts.path.node.body) } addBindingsToContext({ ...opts, node }) @@ -866,34 +866,34 @@ export const createContext = opts => { // wrapper.body.splice(1,0,addContextToScopeNode) return node } -export const createInlineContext = opts => { - let wrapperString = /*javascript*/ ` +export const createInlineContext = (opts) => { + const wrapperString = /*javascript*/ ` for(let ${opts.uuid} = function(){ // node goes here return ${opts.uuid} }() ; a<1;a++){} ` - let inlineContextNode = opts.aster(wrapperString).init.declarations[0] - let contextBody = createContext({ ...opts, wrapBody: false }) + const inlineContextNode = opts.aster(wrapperString).init.declarations[0] + const contextBody = createContext({ ...opts, wrapBody: false }) inlineContextNode.init.callee.body.body.splice(0, 0, ...contextBody) inlineContextNode.contextDeclaration = true return inlineContextNode } -export const addBindingsToContext = opts => { - for (let key in opts.path.scope.bindings) { - let binding = opts.path.scope.bindings[key] - if (binding.kind == 'var') { - let newNode = scopeVar({ +export const addBindingsToContext = (opts) => { + for (const key in opts.path.scope.bindings) { + const binding = opts.path.scope.bindings[key] + if (binding.kind == "var") { + const newNode = scopeVar({ ...opts, key, - type: binding.kind + type: binding.kind, }) opts.node.splice(opts.node.length - 1, 0, newNode) } } } -export const scopeVarCode = opts => { - let ret = /*javascript*/ ` +export const scopeVarCode = (opts) => { + const ret = /*javascript*/ ` Object.defineProperty( ${opts.uuid}.$closure, ${stringify(opts.key)}, @@ -911,8 +911,8 @@ export const scopeVarCode = opts => { ` return ret } -export const scopeVarInlineCode = opts => { - let ret = /*javascript*/ ` +export const scopeVarInlineCode = (opts) => { + const ret = /*javascript*/ ` let ${jsUUID()} = ( ${scopeVarCode(opts)} ) @@ -934,8 +934,8 @@ export const scopeVar = (opts = {}) => { thirdArg = node.expression.left.arguments[2] } - let getter = thirdArg.properties[0] - let setter = thirdArg.properties[1] + const getter = thirdArg.properties[0] + const setter = thirdArg.properties[1] getter.body.scopeInitialized = true setter.body.scopeInitialized = true getter.body.scoperWrapped = true @@ -946,7 +946,7 @@ export const scopeVar = (opts = {}) => { return node } export const functionWrapper = (uuid, path, aster) => { - let wrapper = aster(/*javascript*/ ` + const wrapper = aster(/*javascript*/ ` ${uuid}.$functionScoper() `) wrapper.expression.arguments.push(path.node) @@ -959,24 +959,24 @@ export const bodyInsert = (index, body, aster, ...things) => { export const initBlock = (path, aster) => { if (!path.node.scopeInitialized) { path.node.scopeInitialized = true - let uuid = getPathUUID({ path }) - let contextNode = createContext({ uuid, aster, path }) + const uuid = getPathUUID({ path }) + const contextNode = createContext({ uuid, aster, path }) path.node.body = contextNode } } -export const getNodeUUID = opts => { +export const getNodeUUID = (opts) => { if ( opts.node && - opts.node.type != 'BlockStatement' && - opts.node.type != 'Program' + opts.node.type != "BlockStatement" && + opts.node.type != "Program" ) return getNodeUUID({ ...opts, - node: opts.node.body || opts.node.block + node: opts.node.body || opts.node.block, }) - return gosmart.bind(this)(opts.node, 'uuid', jsUUID()) + return gosmart.bind(this)(opts.node, "uuid", jsUUID()) } -export const getPathUUID = opts => { +export const getPathUUID = (opts) => { if ( opts.path.context.scope.path.node.inheritScope || opts.path.scope.path.node.inheritScope @@ -984,27 +984,27 @@ export const getPathUUID = opts => { return getPathUUID({ ...opts, path: opts.path.parentPath }) return getNodeUUID({ ...opts, - node: opts.path.context.scope.path.node + node: opts.path.context.scope.path.node, }) } -export const babelPlugin = babel => { +export const babelPlugin = (babel) => { const aster = babel.template.ast - let metaVisitor = { - Program (path) { + const metaVisitor = { + Program(path) { initBlock(path, aster) }, - BlockStatement (path) { + BlockStatement(path) { initBlock(path, aster) }, - ForInStatement () { + ForInStatement() { // nothing }, // ForInStatement (path) { // path = path // }, - ObjectMethod (path) { - let name = path.node.key.name + ObjectMethod(path) { + const name = path.node.key.name let replacement = aster(/*javascript*/ ` let a = { ${name}: function ${name}(){} @@ -1015,32 +1015,32 @@ export const babelPlugin = babel => { replacement.value.params = path.node.params path.replaceWith(replacement) }, - Function (path) { + Function(path) { if ( - path.type != 'FunctionDeclaration' && + path.type != "FunctionDeclaration" && !path.node.scoperWrapped && !path.node.body.scoperWrapped ) { path.node.scoperWrapped = true path.node.body.scoperWrapped = true - let uuid = getPathUUID({ path }) - let replacement = functionWrapper(uuid, path, aster) + const uuid = getPathUUID({ path }) + const replacement = functionWrapper(uuid, path, aster) path.replaceWith(replacement) } }, - FunctionDeclaration (path) { + FunctionDeclaration(path) { if (!path.node.scoped) { path.node.scoped = true const parentBlock = path.scope.parent try { - parentBlock.block.body.forEach(node => { + parentBlock.block.body.forEach((node) => { if (node.lastContextNode) { - let uuid = getPathUUID({ path }) - let newNode = aster(/*javascript*/ ` + const uuid = getPathUUID({ path }) + const newNode = aster(/*javascript*/ ` ${uuid}.$functionScoper(${path.node.id.name}) `) node.body.splice(1, 0, newNode) - throw new Error('break foreach') + throw new Error("break foreach") } }) } catch (err) { @@ -1048,32 +1048,34 @@ export const babelPlugin = babel => { } } }, - VariableDeclarator (path) { + VariableDeclarator(path) { if (!path.node.inScope) { path.node.inScope = true - let parentPath = getsmart.bind(this)(path, 'parentPath', undefined) + const parentPath = getsmart.bind(this)(path, "parentPath", undefined) if ( // this is for inline let and const declarations in normal // js blocks - (parentPath.node.kind == 'let' || parentPath.node.kind == 'const') && + (parentPath.node.kind == "let" || parentPath.node.kind == "const") && // we check the length of declarations because we only have to do inline replacement // if there's a chance another declaration might use a former one parentPath.node.declarations.length > 1 && !( - parentPath.parentPath.node.type == 'ForInStatement' || - parentPath.parentPath.node.type == 'ForOfStatement' || - parentPath.parentPath.node.type == 'ForStatement' + parentPath.parentPath.node.type == "ForInStatement" || + parentPath.parentPath.node.type == "ForOfStatement" || + parentPath.parentPath.node.type == "ForStatement" ) ) { - let uuid = getPathUUID({ path }) + const uuid = getPathUUID({ path }) if (uuid) { - let indexInParent = parentPath.node.declarations.indexOf(path.node) - let newDeclaration = scopeVar({ + const indexInParent = parentPath.node.declarations.indexOf( + path.node + ) + const newDeclaration = scopeVar({ aster, inline: true, uuid, key: parentPath.node.declarations[indexInParent].id.name, - type: parentPath.node.kind + type: parentPath.node.kind, }) parentPath.node.declarations.splice( indexInParent + 1, @@ -1083,53 +1085,57 @@ export const babelPlugin = babel => { } } else if ( // - (parentPath.node.kind == 'let' || - parentPath.node.kind == 'var' || - parentPath.node.kind == 'const') && + (parentPath.node.kind == "let" || + parentPath.node.kind == "var" || + parentPath.node.kind == "const") && // only do this for singular declarations parentPath.node.declarations.length < 2 && // and check if variable is declared inside a ForX statement - (parentPath.parentPath.node.type == 'ForInStatement' || - parentPath.parentPath.node.type == 'ForOfStatement' || - parentPath.parentPath.node.type == 'ForStatement') + (parentPath.parentPath.node.type == "ForInStatement" || + parentPath.parentPath.node.type == "ForOfStatement" || + parentPath.parentPath.node.type == "ForStatement") ) { - let uuid = getPathUUID({ path }) + const uuid = getPathUUID({ path }) if (uuid) { - let indexInParent = parentPath.node.declarations.indexOf(path.node) - let newNode = scopeVar({ + const indexInParent = parentPath.node.declarations.indexOf( + path.node + ) + const newNode = scopeVar({ aster, uuid, key: parentPath.node.declarations[indexInParent].id.name, - type: parentPath.node.kind + type: parentPath.node.kind, }) parentPath.parentPath.node.body.body.splice(0, 0, newNode) } } else if ( // this is a special case for when ForStatements get their own scope - (parentPath.node.kind == 'let' || parentPath.node.kind == 'const') && + (parentPath.node.kind == "let" || parentPath.node.kind == "const") && // we check the length of declarations because we only have to do inline replacement // if there's a chance another declaration might use a former one parentPath.node.declarations.length > 1 && - parentPath.parentPath.node.type == 'ForStatement' + parentPath.parentPath.node.type == "ForStatement" ) { // if the first declaration isn't our context declaration, insert one - let uuid = gosmart.bind(this)(path, 'scope.uuid', jsUUID()) + const uuid = gosmart.bind(this)(path, "scope.uuid", jsUUID()) if (!parentPath.node.declarations[0].contextDeclaration) { - let inlineContextDeclaration = createInlineContext({ + const inlineContextDeclaration = createInlineContext({ path, uuid, - aster + aster, }) parentPath.node.declarations.splice(0, 0, inlineContextDeclaration) } if (uuid) { - let indexInParent = parentPath.node.declarations.indexOf(path.node) - let newDeclaration = scopeVar({ + const indexInParent = parentPath.node.declarations.indexOf( + path.node + ) + const newDeclaration = scopeVar({ aster, inline: true, uuid, key: parentPath.node.declarations[indexInParent].id.name, - type: parentPath.node.kind + type: parentPath.node.kind, }) parentPath.node.declarations.splice( indexInParent + 1, @@ -1138,17 +1144,19 @@ export const babelPlugin = babel => { ) } } else if ( - parentPath.node.kind == 'let' || - parentPath.node.kind == 'const' + parentPath.node.kind == "let" || + parentPath.node.kind == "const" ) { - let uuid = getPathUUID({ path }) + const uuid = getPathUUID({ path }) if (uuid) { - let indexInParent = parentPath.node.declarations.indexOf(path.node) - let newNode = scopeVar({ + const indexInParent = parentPath.node.declarations.indexOf( + path.node + ) + const newNode = scopeVar({ aster, uuid, key: parentPath.node.declarations[indexInParent].id.name, - type: parentPath.node.kind + type: parentPath.node.kind, }) parentPath.insertAfter(newNode) } @@ -1166,10 +1174,10 @@ export const babelPlugin = babel => { // } } } - } + }, } - let ret = { - visitor: metaVisitor + const ret = { + visitor: metaVisitor, // visitor: { // Program(path){ // path.traverse(metaVisitor) @@ -1181,7 +1189,7 @@ export const babelPlugin = babel => { export const transform = (src, opts = {}) => { return getBabel().transform(src, { plugins: [babelPlugin], - ...opts + ...opts, }) } /** non-parser stuff */ @@ -1191,7 +1199,7 @@ export const stripUuids = (thing, seen = []) => { } catch { // nothing } - if (typeof thing === 'object') { + if (typeof thing === "object") { const keys = Object.keys(thing) for (const key of keys) { const val = thing[key] @@ -1213,13 +1221,13 @@ export const schema = (obj1, obj2, opts = {}) => { obj2 = clone(obj2, opts) } return merge(obj1, obj2, { - ...opts + ...opts, }) } export const create = (obj1, obj2, opts) => { - let ret = merge(obj1, obj2, { + const ret = merge(obj1, obj2, { clone: true, - ...opts + ...opts, }) return ret @@ -1249,14 +1257,14 @@ export const merge = (value1, value2, opts = {}, seen = new Map()) => { value2 = clone(value2) } - let props = Object.keys(value2) + const props = Object.keys(value2) - props.forEach(prop => { - let propertyValue1 = value1[prop] + props.forEach((prop) => { + const propertyValue1 = value1[prop] if (prop in value1 && basic(propertyValue1) && !opts.overwrite) { return } - let propertyValue2 = value2[prop] + const propertyValue2 = value2[prop] seen.set(value1, value1) let newVal = propertyValue2 if (prop in value1) { @@ -1268,43 +1276,43 @@ export const merge = (value1, value2, opts = {}, seen = new Map()) => { ) } if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && value1 ) { const setToUse = this.$set || local.vue.Vue.set setToUse?.(value1, prop, newVal) if ( - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { value1[prop] = newVal if ( - getsmart.bind(this)(local.vue, 'store', false) && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + getsmart.bind(this)(local.vue, "store", false) && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } }) return value1 } -export const basic = value => { - let valueType = typeof value - let ret = +export const basic = (value) => { + const valueType = typeof value + const ret = !( - valueType == 'object' || - valueType == 'array' || - valueType == 'function' + valueType == "object" || + valueType == "array" || + valueType == "function" ) || value === null return ret } @@ -1322,27 +1330,27 @@ export const deepForEach = ( seens = { originals: [], clones: [] }, first = true ) => { - path = path || '' + path = path || "" if (first) { - value = { '': value } + value = { "": value } } // if(!(typeof value == 'string' || typeof value == 'boolean' || typeof value == 'number')){ // seens.originals.push(value) // } if (Array.isArray(value)) { forEachArray(value, fn, path, ret, seens) - } else if (typeof value == 'object') { + } else if (typeof value == "object") { forEachObject(value, fn, path, ret, seens) } - return ret[''] + return ret[""] } export const forEachObject = (obj, fn, path, ret, seens) => { for (const key in obj) { const deepPath = path ? `${path}.${key}` : key - let primitive = - typeof obj[key] == 'string' || - typeof obj[key] == 'boolean' || - typeof obj[key] == 'number' + const primitive = + typeof obj[key] == "string" || + typeof obj[key] == "boolean" || + typeof obj[key] == "number" if (primitive || seens.originals.indexOf(obj[key]) < 0) { if (!primitive) { seens.originals.push(obj[key]) @@ -1356,10 +1364,10 @@ export const forEachObject = (obj, fn, path, ret, seens) => { } export const forEachArray = (array, fn, path, ret = {}, seens) => { array.forEach((value, index, arr) => { - let primitive = - typeof value == 'string' || - typeof value == 'boolean' || - typeof value == 'number' + const primitive = + typeof value == "string" || + typeof value == "boolean" || + typeof value == "number" if (primitive || seens.originals.indexOf(value) < 0) { if (!primitive) { seens.originals.push(value) @@ -1377,11 +1385,11 @@ export const setThing = ({ option, list = getsmart.bind(this)(objList), obj = true, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, push, strings, - targets + targets, } = {}) => { let index = thingIndex({ option, @@ -1389,18 +1397,18 @@ export const setThing = ({ obj, keys, keymatchtype, - strings + strings, }) - if (obj == 'debug') { - console.log('index') + if (obj == "debug") { + console.log("index") console.log(index) - console.log('list') + console.log("list") console.log(list) } if (index >= 0 && list) { - if (targets && targets.length && typeof targets.length == 'number') { - for (var i = 0; i < targets.length; i++) { - let value = getsmart.bind(this)(option, targets[i], undefined) + if (targets && targets.length && typeof targets.length == "number") { + for (let i = 0; i < targets.length; i++) { + const value = getsmart.bind(this)(option, targets[i], undefined) if (value) { setsmart.bind(this)(list[index], targets[i], value) } @@ -1408,42 +1416,42 @@ export const setThing = ({ } else { list.splice(index, 1, option) if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) ) { if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else if ( - getsmart.bind(this)(local.vue, 'store', false) && - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + getsmart.bind(this)(local.vue, "store", false) && + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } // list[index] = option } else if (push && list) { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { list.splice(list.length, 0, option) if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { list.push(option) @@ -1456,13 +1464,13 @@ export const setThings = ({ options, list = getsmart.bind(this)(objList), obj = true, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, push, - async + async, } = {}) => { if (options && options instanceof Array && list) { - for (let option of options) { + for (const option of options) { if (async) { new Promise(() => { setThing({ @@ -1471,7 +1479,7 @@ export const setThings = ({ obj, keys, keymatchtype, - push + push, }) }) } else { @@ -1481,7 +1489,7 @@ export const setThings = ({ obj, keys, keymatchtype, - push + push, }) } } @@ -1492,20 +1500,20 @@ export const optIn = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, index ) => { - if (typeof option === 'object') { + if (typeof option === "object") { obj = true } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { return index ? list.indexOf(option) : true - } else if (obj && list && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { - if (!(keys && typeof keys.length == 'number')) return - for (var indKey = 0; indKey < keys.length; indKey++) { - if (keymatchtype == 'broad') { + } else if (obj && list && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { + if (!(keys && typeof keys.length == "number")) return + for (let indKey = 0; indKey < keys.length; indKey++) { + if (keymatchtype == "broad") { if ( list[i] && getsmart.bind(this)(list[i], keys[indKey], undefined) == @@ -1515,7 +1523,7 @@ export const optIn = ( return index ? i : true } else if ( list[i] && - typeof list[i] == 'string' && + typeof list[i] == "string" && list[i] == getsmart.bind(this)(option, keys[indKey], undefined) && getsmart.bind(this)(option, keys[indKey], undefined) !== undefined ) { @@ -1533,7 +1541,7 @@ export const optIn = ( } } else if ( list[i] && - typeof list[i] == 'string' && + typeof list[i] == "string" && list[i] == getsmart.bind(this)(option, keys[indKey], undefined) && getsmart.bind(this)(option, keys[indKey], undefined) !== undefined ) { @@ -1551,12 +1559,12 @@ export const thingIn = ({ option, list = getsmart.bind(this)(objList), obj = true, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, - retIndex + retIndex, // vue = local.vue } = {}) => { - if (typeof option === 'object') { + if (typeof option === "object") { obj = true } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { @@ -1565,11 +1573,11 @@ export const thingIn = ({ } else { return true } - } else if (obj && list && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { - if (!(keys && typeof keys.length == 'number')) return - for (var indKey = 0; indKey < keys.length; indKey++) { - if (keymatchtype == 'broad') { + } else if (obj && list && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { + if (!(keys && typeof keys.length == "number")) return + for (let indKey = 0; indKey < keys.length; indKey++) { + if (keymatchtype == "broad") { if ( list[i] && getsmart.bind(this)(list[i], keys[indKey], undefined) == @@ -1583,7 +1591,7 @@ export const thingIn = ({ } } else if ( list[i] && - typeof list[i] == 'string' && + typeof list[i] == "string" && list[i] == getsmart.bind(this)(option, keys[indKey], undefined) && getsmart.bind(this)(option, keys[indKey], undefined) !== undefined ) { @@ -1609,7 +1617,7 @@ export const thingIn = ({ } } else if ( list[i] && - typeof list[i] == 'string' && + typeof list[i] == "string" && list[i] == getsmart.bind(this)(option, keys[indKey], undefined) && getsmart.bind(this)(option, keys[indKey], undefined) !== undefined ) { @@ -1635,18 +1643,18 @@ export const optsIn = ( options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (!(options instanceof Array)) return true - for (let option of options) { + for (const option of options) { // if(typeof option === 'object'){ // obj = true // } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { // return true } else if (obj && list) { - for (var i = 0; i < list.length; i++) { + for (let i = 0; i < list.length; i++) { if (!optIn(option, list[i], obj, keys, keymatchtype)) { return false } @@ -1661,18 +1669,18 @@ export const thingsIn = ({ options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (!(options instanceof Array)) return true - for (let option of options) { + for (const option of options) { // if(typeof option === 'object'){ // obj = true // } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { // return true - } else if (obj && list && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { + } else if (obj && list && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { if (!optIn(option, list[i], obj, keys, keymatchtype)) { return false } @@ -1687,18 +1695,18 @@ export const anyOptsIn = ( options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (!(options instanceof Array)) return false - for (let option of options) { + for (const option of options) { // if(typeof option === 'object'){ // obj = true // } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { return true - } else if (obj && list && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { + } else if (obj && list && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { if (optIn(option, list[i], obj, keys, keymatchtype)) { return true } @@ -1711,18 +1719,18 @@ export const anyThingsIn = ({ options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (!(options instanceof Array)) return false - for (let option of options) { + for (const option of options) { // if(typeof option === 'object'){ // obj = true // } if (!obj && list && list.indexOf && list.indexOf(option) >= 0) { return true - } else if (obj && list && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { + } else if (obj && list && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { if (optIn(option, list[i], obj, keys, keymatchtype)) { return true } @@ -1735,14 +1743,14 @@ export const optIndex = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { - if (typeof option === 'object') { + if (typeof option === "object") { obj = true } - if (obj && list && keys && typeof list.length == 'number') { - for (var i = 0; i < list.length; i++) { + if (obj && list && keys && typeof list.length == "number") { + for (let i = 0; i < list.length; i++) { if (optIn(option, list, obj, keys, keymatchtype)) { return i } @@ -1756,22 +1764,22 @@ export const thingIndex = ({ option, list, obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, - strings + strings, } = {}) => { - if (typeof option === 'object') { + if (typeof option === "object") { obj = true } if (obj && list && keys) { - let index = thingIn({ + const index = thingIn({ option, list, obj, keys, keymatchtype, strings, - retIndex: true + retIndex: true, }) return index } else if (list) { @@ -1783,25 +1791,25 @@ export const pushOpt = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, index ) => { if ( - typeof list == 'object' && + typeof list == "object" && !optIn(option, list, obj, keys, keymatchtype) ) { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { list.splice(list.length, 0, option) if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { list.push(option) @@ -1815,22 +1823,22 @@ export const addOpt = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype, index ) => { - if (typeof list == 'object') { + if (typeof list == "object") { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { list.splice(list.length, 0, option) if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { list.push(option) @@ -1844,24 +1852,24 @@ export const pushThing = ({ option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if ( - typeof list == 'object' && + typeof list == "object" && !thingIn({ option, list, obj, keys, keymatchtype }) ) { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { list.splice(list.length, 0, option) if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { list.push(option) @@ -1872,11 +1880,11 @@ export const pushOpts = ( options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (!(options instanceof Array)) return - for (let option of options) { + for (const option of options) { pushOpt(option, list, obj, keys, keymatchtype) } } @@ -1884,11 +1892,11 @@ export const pushThings = ({ options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (!(options instanceof Array)) return - for (let option of options) { + for (const option of options) { pushThing({ option, list, obj, keys, keymatchtype }) } } @@ -1896,21 +1904,21 @@ export const popOpt = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { - if (typeof list == 'object' && optIn(option, list, obj, keys, keymatchtype)) { + if (typeof list == "object" && optIn(option, list, obj, keys, keymatchtype)) { list.splice(optIndex(option, list, obj, keys, keymatchtype), 1) if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } } @@ -1919,17 +1927,17 @@ export const popThing = ({ option, list = getsmart.bind(this)(stringList), obj = true, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if ( - typeof list == 'object' && + typeof list == "object" && thingIn({ option, list, obj, keys, - keymatchtype + keymatchtype, }) ) { list.splice( @@ -1938,20 +1946,20 @@ export const popThing = ({ list, obj, keys, - keymatchtype + keymatchtype, }), 1 ) if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) || - getsmart.bind(this)(local.vue, 'store', false) + getsmart.bind(this)(local.vue, "reactiveSetter", false) || + getsmart.bind(this)(local.vue, "store", false) ) { if ( - !localStorage.getItem('vuexWriteLock') && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + !localStorage.getItem("vuexWriteLock") && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } } @@ -1960,11 +1968,11 @@ export const popOpts = ( options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (!(options instanceof Array)) return - for (let option of options) { + for (const option of options) { popOpt(option, list, obj, keys, keymatchtype) } } @@ -1972,11 +1980,11 @@ export const popThings = ({ options, list = getsmart.bind(this)(stringList), obj = true, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (!(options instanceof Array)) return - for (let option of options) { + for (const option of options) { popOpt(option, list, obj, keys, keymatchtype) } } @@ -1984,7 +1992,7 @@ export const toggleOpt = ( option, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (optIn(option, list, obj, keys, keymatchtype)) { @@ -1997,8 +2005,8 @@ export const toggleThing = ({ option, list = getsmart.bind(this)(stringList), obj = true, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (optIn(option, list, obj, keys, keymatchtype)) { popOpt(option, list, obj, keys, keymatchtype) @@ -2010,11 +2018,11 @@ export const toggleOpts = ( options, list = getsmart.bind(this)(stringList), obj, - keys = ['uuid', '_id', 'id'], + keys = ["uuid", "_id", "id"], keymatchtype ) => { if (!(options instanceof Array)) return - for (let option in options) { + for (const option in options) { toggleOpt(option, list, obj, keys, keymatchtype) } } @@ -2022,11 +2030,11 @@ export const toggleThings = ({ options, list = getsmart.bind(this)(stringList), obj = true, - keys = ['uuid', '_id', 'id'], - keymatchtype + keys = ["uuid", "_id", "id"], + keymatchtype, } = {}) => { if (!(options instanceof Array)) return - for (let option in options) { + for (const option in options) { if (optIn(option, list, obj, keys, keymatchtype)) { popOpt(option, list, obj, keys, keymatchtype) } else { @@ -2057,8 +2065,8 @@ export const getsmart = ( context?: any, schema?: any ) => { - if (!property && obj && typeof obj == 'string') { - property = obj.split('.') + if (!property && obj && typeof obj == "string") { + property = obj.split(".") try { obj = eval(property[0]) } catch (err) { @@ -2072,46 +2080,46 @@ export const getsmart = ( if (context) { return { value: defaultValue, - undefined: true + undefined: true, } } else { return defaultValue } } // If the property list is in dot notation, convert to array - if (typeof property == 'string') { + if (typeof property == "string") { property = parsePropertyPath(property) - } else if (getsmart.bind(this)(property, 'constructor', false) !== Array) { + } else if (getsmart.bind(this)(property, "constructor", false) !== Array) { if (context) { return { value: defaultValue, undefined: true, - err: 'properties path @property argument was not passed properly' + err: "properties path @property argument was not passed properly", } } else { return defaultValue } } - let deepGetByArray = deepGetByArrayUnbound.bind(this) + const deepGetByArray = deepGetByArrayUnbound.bind(this) return deepGetByArray(obj, property, defaultValue) // In order to avoid constantly checking the type of the property // we separate the real logic out into an inner function. - function deepGetByArrayUnbound (obj, propsArray, defaultValue) { + function deepGetByArrayUnbound(obj, propsArray, defaultValue) { // This case getting to the last property but it not being ultimately defined // Not just having a value of undefined if ( propsArray.length > 0 && context && - typeof obj == 'object' && + typeof obj == "object" && obj !== null && !(ee(propsArray[0]) in obj) ) { return { value: defaultValue, - undefined: true + undefined: true, } } @@ -2119,7 +2127,7 @@ export const getsmart = ( // then stop executing and return the default value. // If no default was provided it will be undefined. if ( - typeof obj == 'undefined' || + typeof obj == "undefined" || obj == null || (schema && obj.constructor.name !== schema) ) { @@ -2131,7 +2139,7 @@ export const getsmart = ( return { value: defaultValue, undefined: undef, - schema: schema && obj.constructor.name === schema + schema: schema && obj.constructor.name === schema, } } else { return defaultValue @@ -2143,41 +2151,41 @@ export const getsmart = ( if (context) { return { value: obj, - undefined: false + undefined: false, } } else { return obj } } // Prepare our found property and path array for recursion - var nextObj = obj[ee(propsArray[0])] - var remainingProps = propsArray.slice(1) + const nextObj = obj[ee(propsArray[0])] + const remainingProps = propsArray.slice(1) return deepGetByArray(nextObj, remainingProps, defaultValue) } } -export const escapePropertyPath = (path = '') => { - let newPath = escapeEscapes(path) +export const escapePropertyPath = (path = "") => { + const newPath = escapeEscapes(path) return '["' + newPath + '"]' } -export const epp = (path = '') => { +export const epp = (path = "") => { return escapePropertyPath(path) } -export const escapeEscapes = (path = '') => { - let newPath = '' +export const escapeEscapes = (path = "") => { + let newPath = "" for (let i in path) { i = +i - let char = path[i] + const char = path[i] if (i > 0 && i < path.length - 1) { - let prevChar = path[i - 1] - let nextChar = path[i + 1] - let openingArrayPath = char === '"' && prevChar === '[' + const prevChar = path[i - 1] + const nextChar = path[i + 1] + const openingArrayPath = char === '"' && prevChar === "[" // && (nextChar !== "\\" || i === path.length-1) - let closingArrayPath = - char === '"' && nextChar === ']' && prevChar !== '\\' + const closingArrayPath = + char === '"' && nextChar === "]" && prevChar !== "\\" // let offset = 0 // if(openingArrayPath) offset = 1 if (openingArrayPath || closingArrayPath) { - newPath += '\\' + newPath += "\\" // path = path.slice(0,i+offset)+"\\"+path.slice(i+offset,path.length) } } @@ -2185,27 +2193,27 @@ export const escapeEscapes = (path = '') => { } return newPath } -export const ee = (path = '') => { +export const ee = (path = "") => { return escapeEscapes(path) } // TODO // Make parsing use \" or \' // Currently only uses \" -export const parsePropertyPath = (path = '') => { - let array = [] +export const parsePropertyPath = (path = "") => { + const array = [] let readingArrayBasedPath = false let i = 0 let push = false let pushed = false while (i < path.length) { - let arrayPathStart = path[i] == '[' && path[i + 1] == '"' - let escapedStart = !(path[i + 1] !== '\\' || i === 0) + const arrayPathStart = path[i] == "[" && path[i + 1] == '"' + const escapedStart = !(path[i + 1] !== "\\" || i === 0) if (readingArrayBasedPath) { // we found the end of an array delimited path - let arrayPathEnd = path[i] == '"' && path[i + 1] == ']' - let escapedEnd = !(path[i - 1] !== '\\' || i == 0) + const arrayPathEnd = path[i] == '"' && path[i + 1] == "]" + const escapedEnd = !(path[i - 1] !== "\\" || i == 0) if (arrayPathEnd && !escapedEnd) { i += 1 readingArrayBasedPath = false @@ -2214,15 +2222,15 @@ export const parsePropertyPath = (path = '') => { // if the path includes an "escaped" array based path begin or end value // do not push the escape character if ( - (path[i] == '\\' && path[i + 1] == '"' && path[i + 2] == ']') || - (path[i - 1] == '[' && path[i] == '\\' && path[i + 1] == '"') + (path[i] == "\\" && path[i + 1] == '"' && path[i + 2] == "]") || + (path[i - 1] == "[" && path[i] == "\\" && path[i + 1] == '"') ) { // nothing } else { array[array.length - 1] += path[i] } } - } else if (path[i] == '.') { + } else if (path[i] == ".") { if (!pushed) push = true } // we found the start of an array delimited path @@ -2231,14 +2239,14 @@ export const parsePropertyPath = (path = '') => { if (!pushed) push = true i += 1 } else { - if (i == 0) array.push('') + if (i == 0) array.push("") array[array.length - 1] += path[i] } i++ if (push && i < path.length) { pushed = true - array.push('') + array.push("") push = false } else { pushed = false @@ -2247,45 +2255,45 @@ export const parsePropertyPath = (path = '') => { return array } -export const ppp = (path = '') => { +export const ppp = (path = "") => { return this.parsePropertyPath(path) } -export const parsePropertyArray = pathArray => { - let path = '' +export const parsePropertyArray = (pathArray) => { + let path = "" if (pathArray instanceof Array) { - pathArray.forEach(subPath => { + pathArray.forEach((subPath) => { path += epp(subPath) }) - } else if (typeof pathArray === 'string') { + } else if (typeof pathArray === "string") { return path } return path } -export const ppa = pathArray => { +export const ppa = (pathArray) => { return this.parsePropertyArray(pathArray) } -export const pathToArray = path => { - if (typeof path == 'string') { +export const pathToArray = (path) => { + if (typeof path == "string") { return parsePropertyPath(path) } else { return path } } -export const pathToString = path => { - if (typeof path == 'string') { +export const pathToString = (path) => { + if (typeof path == "string") { let ret = parsePropertyPath(path) ret = parsePropertyArray(ret) return ret } else { - let ret = parsePropertyArray(path) + const ret = parsePropertyArray(path) return ret } } export const setsmart = (obj, property, value, context?: any) => { - if (!property && typeof obj == 'string') { - property = obj.split('.') + if (!property && typeof obj == "string") { + property = obj.split(".") try { obj = eval(property[0]) } catch (err) { @@ -2294,14 +2302,14 @@ export const setsmart = (obj, property, value, context?: any) => { property = property.slice(1, property.length) } // If the property list is in dot notation, convert to array - if (typeof property == 'string') { + if (typeof property == "string") { property = parsePropertyPath(property) - } else if (getsmart.bind(this)(property, 'constructor', false) !== Array) { + } else if (getsmart.bind(this)(property, "constructor", false) !== Array) { if (context) { return { value: value, undefined: true, - err: 'properties path @property argument was not passed properly' + err: "properties path @property argument was not passed properly", } } else { return value @@ -2309,45 +2317,45 @@ export const setsmart = (obj, property, value, context?: any) => { } // if no obj make obj - if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) obj = {} + if (!obj || (typeof obj !== "object" && typeof obj !== "function")) obj = {} - let deepSetByArray = deepSetByArrayUnbound.bind(this) + const deepSetByArray = deepSetByArrayUnbound.bind(this) if (property) { return deepSetByArray(obj, property, value) } else { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && obj ) { const setToUse = this.$set || local.vue.Vue.set setToUse(obj, undefined, value) if ( - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { obj = value if ( - getsmart.bind(this)(local.vue, 'store', false) && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + getsmart.bind(this)(local.vue, "store", false) && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } if (context) { return { value: obj, undefined: false, - err: 'there were no properties passed' + err: "there were no properties passed", } } else { return obj @@ -2356,77 +2364,77 @@ export const setsmart = (obj, property, value, context?: any) => { // In order to avoid constantly checking the type of the property // we separate the real logic out into an inner function. - function deepSetByArrayUnbound (obj, propsArray, value) { + function deepSetByArrayUnbound(obj, propsArray, value) { // If the path array has only 1 more element, we've reached // the intended property and set its value if (propsArray.length == 1) { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && obj ) { const setToUse = this.$set || local.vue.Vue.set setToUse(obj, ee(propsArray[0]), value) if ( - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { // TODO: make parent object new object so that react can see the change obj[ee(propsArray[0])] = value if ( - getsmart.bind(this)(local.vue, 'store', false) && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + getsmart.bind(this)(local.vue, "store", false) && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } if (context) { return { value: obj[ee(propsArray[0])], - undefined: false + undefined: false, } } else { return obj[ee(propsArray[0])] } } // Prepare our path array for recursion - var remainingProps = propsArray.slice(1) + const remainingProps = propsArray.slice(1) // check if next prop is object - if (typeof obj[ee(propsArray[0])] !== 'object') { + if (typeof obj[ee(propsArray[0])] !== "object") { // If we have reached an undefined/null property if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && obj ) { const setToUse = this.$set || local.vue.Vue.set setToUse(obj, ee(propsArray[0]), {}) if ( - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { obj[ee(propsArray[0])] = {} if ( - getsmart.bind(this)(local.vue, 'store', false) && - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + getsmart.bind(this)(local.vue, "store", false) && + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } } @@ -2434,8 +2442,8 @@ export const setsmart = (obj, property, value, context?: any) => { } } export const deletesmart = (obj, property) => { - if (!property && typeof obj == 'string') { - property = obj.split('.') + if (!property && typeof obj == "string") { + property = obj.split(".") try { obj = eval(property[0]) } catch (err) { @@ -2445,19 +2453,19 @@ export const deletesmart = (obj, property) => { property = property.slice(1, property.length) } // If the property list is in dot notation, convert to array - if (typeof property == 'string') { + if (typeof property == "string") { property = parsePropertyPath(property) } - let parentPathArray = property.slice(0, property.length - 1) - let path = property[property.length - 1] - let parentObj = getsmart(obj, parentPathArray, {}) + const parentPathArray = property.slice(0, property.length - 1) + const path = property[property.length - 1] + const parentObj = getsmart(obj, parentPathArray, {}) if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && obj ) { @@ -2468,20 +2476,20 @@ export const deletesmart = (obj, property) => { } export const pushSmart = (array, value) => { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && array ) { array.push(value) if ( - typeof getsmart.bind(this)(window, '$store.commit', undefined) == - 'function' + typeof getsmart.bind(this)(window, "$store.commit", undefined) == + "function" ) { - window.$store.commit(local.vue.basePath || 'graph/thing') + window.$store.commit(local.vue.basePath || "graph/thing") } } else { array.push(value) @@ -2489,7 +2497,7 @@ export const pushSmart = (array, value) => { } export const gosmart = (obj, property, value, context, schema) => { // stands for get or set smart - var get = getsmart.bind(this)( + let get = getsmart.bind(this)( obj, property, value, @@ -2510,13 +2518,13 @@ export const gosmart = (obj, property, value, context, schema) => { export const gosmarter = (obj, property, value, context, schema = true) => { return gosmart.bind(this)(obj, property, value, context, schema) } -export const absoluteType = value => { +export const absoluteType = (value) => { let type try { type = value.constructor.name } catch (e) { - if (typeof value === 'undefined') type = 'undefined' - if (value === null) type = 'null' + if (typeof value === "undefined") type = "undefined" + if (value === null) type = "null" } return type } @@ -2525,24 +2533,24 @@ export const vgosmart = (obj, property, value, context) => { // return value from property path, either gotten or smartly set return { get: () => { - var get = getsmart.bind(this)(obj, property, value, true) + let get = getsmart.bind(this)(obj, property, value, true) if (get.undefined) { get = setsmart.bind(this)(obj, property, get.value, context) } if (context) { return get } else { - return getsmart.bind(this)(get, 'value', get) + return getsmart.bind(this)(get, "value", get) } }, - set: val => { + set: (val) => { setsmart.bind(this)(obj, property, val) - } + }, } } export const getsmartval = (obj, property, defaultValue) => { // get the value of a property path based off its type - let target = getsmart.bind(this)(obj, property, defaultValue) + const target = getsmart.bind(this)(obj, property, defaultValue) if (target && target.type) { if (target[target.type]) { return target[target.type] @@ -2554,16 +2562,16 @@ export const getsmartval = (obj, property, defaultValue) => { } return defaultValue } -export const safestring = something => { - return smarts.stringify(something || '') +export const safestring = (something) => { + return smarts.stringify(something || "") } -export const safeparse = something => { - return smarts.parse(something || '') +export const safeparse = (something) => { + return smarts.parse(something || "") } -export const flatten = (arrays, func = i => i) => { +export const flatten = (arrays, func = (i) => i) => { const flat = [] - arrays.forEach(array => { + arrays.forEach((array) => { if (Array.isArray(array)) { flat.push(...flatten(array)) } else { @@ -2573,15 +2581,15 @@ export const flatten = (arrays, func = i => i) => { return flat } -export const mapsmart = (list, keyProperty = 'title', returnExistant) => { +export const mapsmart = (list, keyProperty = "title", returnExistant) => { return new Promise((resolve, reject) => { if (!keyProperty) { reject() - } else if (list && typeof list.length == 'number') { + } else if (list && typeof list.length == "number") { if (list.length == 0) { if ( (returnExistant && - getsmart.bind(this)(list, 'mapped.' + returnExistant, false)) || + getsmart.bind(this)(list, "mapped." + returnExistant, false)) || !returnExistant ) { resolve(true) @@ -2591,42 +2599,42 @@ export const mapsmart = (list, keyProperty = 'title', returnExistant) => { resolve() } } - if (!list.mapped || typeof list.mapped === 'boolean') { + if (!list.mapped || typeof list.mapped === "boolean") { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && list ) { const setToUse = this.$set || local.vue.Vue.set - setToUse(list, 'mapped', {}) + setToUse(list, "mapped", {}) } else { - list['mapped'] = {} + list["mapped"] = {} } } - for (var i = 0; i < list.length; i++) { - if (typeof list[i] !== 'string') { + for (let i = 0; i < list.length; i++) { + if (typeof list[i] !== "string") { if ( - getsmart.bind(this)(local.vue, 'reactiveSetter', false) && + getsmart.bind(this)(local.vue, "reactiveSetter", false) && getsmart.bind(this)( this, - '$set', - getsmart.bind(this)(local.vue, 'Vue.set', false) + "$set", + getsmart.bind(this)(local.vue, "Vue.set", false) ) && list.mapped ) { const setToUse = this.$set || local.vue.Vue.set setToUse(list.mapped, list[i][keyProperty], list[i]) } else { - list['mapped'][list[i][keyProperty]] = list[i] + list["mapped"][list[i][keyProperty]] = list[i] } if (i == list.length - 1) { if ( (returnExistant && - getsmart.bind(this)(list, 'mapped.' + returnExistant, false)) || + getsmart.bind(this)(list, "mapped." + returnExistant, false)) || !returnExistant ) { resolve(true) @@ -2664,7 +2672,7 @@ export const mapsmart = (list, keyProperty = 'title', returnExistant) => { else if (i == list.length - 1) { if ( (returnExistant && - getsmart.bind(this)(list, 'mapped.' + returnExistant, false)) || + getsmart.bind(this)(list, "mapped." + returnExistant, false)) || !returnExistant ) { resolve(true) @@ -2681,17 +2689,17 @@ export const mapsmart = (list, keyProperty = 'title', returnExistant) => { } }) } -export const domval = thing => { - return getsmart.bind(this)(thing, 'properties.description', '') +export const domval = (thing) => { + return getsmart.bind(this)(thing, "properties.description", "") } export const getParent = (levels = Infinity) => { - if (typeof levels == 'string') levels = (levels.match(/\.\./g) || []).length + if (typeof levels == "string") levels = (levels.match(/\.\./g) || []).length if (levels >= this.pathAsArray.length - 1) { return this.pathAsArray[0] } - let level = this.pathAsArray.length - 1 - levels + const level = this.pathAsArray.length - 1 - levels return this.pathAsArray[level] } @@ -2699,9 +2707,9 @@ export const getThing = (props = {}) => { const { list = getsmart.bind(this)(objList), defaultValue = undefined } = props - var index = thingIn({ + const index = thingIn({ ...props, - retIndex: true + retIndex: true, }) if (index >= 0) { return list[index] @@ -2710,14 +2718,14 @@ export const getThing = (props = {}) => { } } export const equal = (obj1, obj2, seen = []) => { - if (obj1 && obj2 && typeof obj1 == 'object' && typeof obj2 == 'object') { + if (obj1 && obj2 && typeof obj1 == "object" && typeof obj2 == "object") { seen.push(obj1, obj2) //Loop through properties in object 1 for (const p in obj1) { //Check property exists on both objects if ( - typeof obj1.hasOwnProperty == 'function' && - typeof obj2.hasOwnProperty == 'function' && + typeof obj1.hasOwnProperty == "function" && + typeof obj2.hasOwnProperty == "function" && Object.prototype.hasOwnProperty.call(obj1, p) !== Object.prototype.hasOwnProperty.call(obj2, p) ) @@ -2725,14 +2733,14 @@ export const equal = (obj1, obj2, seen = []) => { switch (typeof obj1[p]) { //Deep compare objects - case 'object': + case "object": if (seen.indexOf(obj1[p]) < 0 && !equal(obj1[p], obj2[p], seen)) return false break //Compare function code - case 'function': + case "function": if ( - typeof obj2[p] == 'undefined' || + typeof obj2[p] == "undefined" || obj1[p].toString() != obj2[p].toString() ) return false @@ -2752,7 +2760,7 @@ export const equal = (obj1, obj2, seen = []) => { } export const mergeall = (array, options) => { if (!Array.isArray(array)) { - throw new Error('first argument should be an array') + throw new Error("first argument should be an array") } return array.reduce(function (prev, next) { @@ -2864,5 +2872,5 @@ export const smarts = { getParent, getThing, equal, - mergeall + mergeall, } diff --git a/remix/package.json b/remix/package.json index 9c39a39..2bcca82 100644 --- a/remix/package.json +++ b/remix/package.json @@ -20,6 +20,7 @@ "react": "^18.2.0", "react-click-away-listener": "^2.2.3", "react-dom": "^18.2.0", + "tinygradient": "^1.1.5", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/remix/pnpm-lock.yaml b/remix/pnpm-lock.yaml index 3627028..7ff7889 100644 --- a/remix/pnpm-lock.yaml +++ b/remix/pnpm-lock.yaml @@ -41,6 +41,9 @@ dependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + tinygradient: + specifier: ^1.1.5 + version: 1.1.5 uuid: specifier: ^9.0.0 version: 9.0.0