From 07508b4b02fadfaa89c0b41cb5a6bcba06f7b4ad Mon Sep 17 00:00:00 2001 From: checktheroads Date: Sat, 2 May 2020 16:09:03 -0700 Subject: [PATCH] accessibility improvements --- hyperglass/ui/components/ChakraSelect.js | 4 +- hyperglass/ui/components/Footer.js | 242 +- hyperglass/ui/components/FooterButton.js | 43 +- hyperglass/ui/components/FormField.js | 106 +- hyperglass/ui/components/HyperglassForm.js | 463 +-- hyperglass/ui/components/QueryLocation.js | 70 +- hyperglass/ui/components/QueryTarget.js | 117 +- hyperglass/ui/components/QueryType.js | 32 +- hyperglass/ui/components/QueryVrf.js | 22 +- hyperglass/ui/components/SubmitButton.js | 219 +- hyperglass/ui/components/Table/makeData.js | 35 - hyperglass/ui/next.config.js | 28 +- hyperglass/ui/package.json | 190 +- hyperglass/ui/pages/_document.js | 33 +- hyperglass/ui/pages/_error.js | 152 +- hyperglass/ui/yarn.lock | 3211 ++++++++++---------- 16 files changed, 2482 insertions(+), 2485 deletions(-) delete mode 100644 hyperglass/ui/components/Table/makeData.js diff --git a/hyperglass/ui/components/ChakraSelect.js b/hyperglass/ui/components/ChakraSelect.js index bb72701..b341b5b 100644 --- a/hyperglass/ui/components/ChakraSelect.js +++ b/hyperglass/ui/components/ChakraSelect.js @@ -58,8 +58,8 @@ const ChakraSelect = React.forwardRef( ); const selectedDisabled = theme.colors.whiteAlpha[400]; const placeholderColor = { - dark: theme.colors.whiteAlpha[400], - light: theme.colors.gray[400] + dark: theme.colors.whiteAlpha[700], + light: theme.colors.gray[600] }; const menuBg = { dark: theme.colors.black, light: theme.colors.white }; const menuColor = { diff --git a/hyperglass/ui/components/Footer.js b/hyperglass/ui/components/Footer.js index 3b6adda..e86d54b 100644 --- a/hyperglass/ui/components/Footer.js +++ b/hyperglass/ui/components/Footer.js @@ -10,119 +10,135 @@ import FooterContent from "~/components/FooterContent"; format.extend(String.prototype, {}); const Footer = () => { - const theme = useTheme(); - const config = useConfig(); - const { colorMode } = useColorMode(); - const footerBg = { light: theme.colors.blackAlpha[50], dark: theme.colors.whiteAlpha[100] }; - const footerColor = { light: theme.colors.black, dark: theme.colors.white }; - const contentBorder = { - light: theme.colors.blackAlpha[100], - dark: theme.colors.whiteAlpha[200] - }; - const [helpVisible, showHelp] = useState(false); - const [termsVisible, showTerms] = useState(false); - const [creditVisible, showCredit] = useState(false); - const extUrl = config.web.external_link.url.includes("{primary_asn}") - ? config.web.external_link.url.format({ primary_asn: config.primary_asn }) - : config.web.external_link.url || "/"; - const handleCollapse = i => { - if (i === "help") { - showTerms(false); - showCredit(false); - showHelp(!helpVisible); - } else if (i === "credit") { - showTerms(false); - showHelp(false); - showCredit(!creditVisible); - } else if (i === "terms") { - showHelp(false); - showCredit(false); - showTerms(!termsVisible); - } - }; - return ( - <> - {config.web.help_menu.enable && ( - - )} - {config.web.terms.enable && ( - - )} - {config.web.credit.enable && ( - - )} - - {config.web.terms.enable && ( - handleCollapse("terms")}> - {config.web.terms.title} - - )} - {config.web.help_menu.enable && ( - handleCollapse("help")}> - {config.web.help_menu.title} - - )} - - {config.web.credit.enable && ( - handleCollapse("credit")}> - - - )} - {config.web.external_link.enable && ( - - {config.web.external_link.title} - - )} - - - ); + const theme = useTheme(); + const config = useConfig(); + const { colorMode } = useColorMode(); + const footerBg = { + light: theme.colors.blackAlpha[50], + dark: theme.colors.whiteAlpha[100] + }; + const footerColor = { light: theme.colors.black, dark: theme.colors.white }; + const contentBorder = { + light: theme.colors.blackAlpha[100], + dark: theme.colors.whiteAlpha[200] + }; + const [helpVisible, showHelp] = useState(false); + const [termsVisible, showTerms] = useState(false); + const [creditVisible, showCredit] = useState(false); + const extUrl = config.web.external_link.url.includes("{primary_asn}") + ? config.web.external_link.url.format({ primary_asn: config.primary_asn }) + : config.web.external_link.url || "/"; + const handleCollapse = i => { + if (i === "help") { + showTerms(false); + showCredit(false); + showHelp(!helpVisible); + } else if (i === "credit") { + showTerms(false); + showHelp(false); + showCredit(!creditVisible); + } else if (i === "terms") { + showHelp(false); + showCredit(false); + showTerms(!termsVisible); + } + }; + return ( + <> + {config.web.help_menu.enable && ( + + )} + {config.web.terms.enable && ( + + )} + {config.web.credit.enable && ( + + )} + + {config.web.terms.enable && ( + handleCollapse("terms")} + aria-label={config.web.terms.title} + > + {config.web.terms.title} + + )} + {config.web.help_menu.enable && ( + handleCollapse("help")} + aria-label={config.web.help_menu.title} + > + {config.web.help_menu.title} + + )} + + {config.web.credit.enable && ( + handleCollapse("credit")} + aria-label="Powered by hyperglass" + > + + + )} + {config.web.external_link.enable && ( + + {config.web.external_link.title} + + )} + + + ); }; Footer.displayName = "Footer"; diff --git a/hyperglass/ui/components/FooterButton.js b/hyperglass/ui/components/FooterButton.js index 27cfe9e..51a410f 100644 --- a/hyperglass/ui/components/FooterButton.js +++ b/hyperglass/ui/components/FooterButton.js @@ -4,24 +4,29 @@ import { motion } from "framer-motion"; const AnimatedFlex = motion.custom(Flex); -export default React.forwardRef(({ onClick, side, children, ...props }, ref) => { +const FooterButton = React.forwardRef( + ({ onClick, side, children, ...props }, ref) => { return ( - - - + + + ); -}); + } +); + +FooterButton.displayName = "FooterButton"; +export default FooterButton; diff --git a/hyperglass/ui/components/FormField.js b/hyperglass/ui/components/FormField.js index e86c309..d5f3201 100644 --- a/hyperglass/ui/components/FormField.js +++ b/hyperglass/ui/components/FormField.js @@ -1,55 +1,61 @@ import React from "react"; -import { Flex, FormControl, FormLabel, FormErrorMessage, useColorMode } from "@chakra-ui/core"; +import { + Flex, + FormControl, + FormLabel, + FormErrorMessage, + useColorMode +} from "@chakra-ui/core"; export default ({ - label, - name, - error, - hiddenLabels, - helpIcon, - targetInfo, - setTarget, - labelAddOn, - fieldAddOn, - children, - ...props + label, + name, + error, + hiddenLabels, + helpIcon, + targetInfo, + setTarget, + labelAddOn, + fieldAddOn, + children, + ...props }) => { - const { colorMode } = useColorMode(); - const labelColor = { dark: "whiteAlpha.600", light: "blackAlpha.600" }; - return ( - - - {label} - {labelAddOn || null} - - {children} - {fieldAddOn && ( - - {fieldAddOn} - - )} - - {error && error.message} - - - ); + const { colorMode } = useColorMode(); + const labelColor = { dark: "whiteAlpha.700", light: "blackAlpha.700" }; + return ( + + + {label} + {labelAddOn || null} + + {children} + {fieldAddOn && ( + + {fieldAddOn} + + )} + + {error && error.message} + + + ); }; diff --git a/hyperglass/ui/components/HyperglassForm.js b/hyperglass/ui/components/HyperglassForm.js index 175509f..7ff6570 100644 --- a/hyperglass/ui/components/HyperglassForm.js +++ b/hyperglass/ui/components/HyperglassForm.js @@ -18,236 +18,265 @@ import useConfig from "~/components/HyperglassProvider"; format.extend(String.prototype, {}); -const formSchema = (config) => - yup.object().shape({ - query_location: yup - .array() - .of(yup.string()) - .required(config.messages.no_input.format({ field: config.web.text.query_location })), - query_type: yup - .string() - .required(config.messages.no_input.format({ field: config.web.text.query_type })), - query_vrf: yup.string(), - query_target: yup - .string() - .required(config.messages.no_input.format({ field: config.web.text.query_target })), - }); +const formSchema = config => + yup.object().shape({ + query_location: yup + .array() + .of(yup.string()) + .required( + config.messages.no_input.format({ + field: config.web.text.query_location + }) + ), + query_type: yup + .string() + .required( + config.messages.no_input.format({ field: config.web.text.query_type }) + ), + query_vrf: yup.string(), + query_target: yup + .string() + .required( + config.messages.no_input.format({ field: config.web.text.query_target }) + ) + }); const FormRow = ({ children, ...props }) => ( - - {children} - + + {children} + ); const HyperglassForm = React.forwardRef( - ({ isSubmitting, setSubmitting, setFormData, greetingAck, setGreetingAck, ...props }, ref) => { - const config = useConfig(); - const { handleSubmit, register, unregister, setValue, errors } = useForm({ - validationSchema: formSchema(config), - defaultValues: { query_vrf: "default", query_target: "" }, + ( + { + isSubmitting, + setSubmitting, + setFormData, + greetingAck, + setGreetingAck, + ...props + }, + ref + ) => { + const config = useConfig(); + const { handleSubmit, register, unregister, setValue, errors } = useForm({ + validationSchema: formSchema(config), + defaultValues: { query_vrf: "default", query_target: "" } + }); + + const [queryLocation, setQueryLocation] = useState([]); + const [queryType, setQueryType] = useState(""); + const [queryVrf, setQueryVrf] = useState(""); + const [queryTarget, setQueryTarget] = useState(""); + const [availVrfs, setAvailVrfs] = useState([]); + const [fqdnTarget, setFqdnTarget] = useState(""); + const [displayTarget, setDisplayTarget] = useState(""); + const [families, setFamilies] = useState([]); + const onSubmit = values => { + if (!greetingAck && config.web.greeting.required) { + window.location.reload(false); + setGreetingAck(false); + } else { + setFormData(values); + setSubmitting(true); + } + }; + + const handleLocChange = locObj => { + setQueryLocation(locObj.value); + const allVrfs = []; + const deviceVrfs = []; + locObj.value.map(loc => { + const locVrfs = []; + config.devices[loc].vrfs.map(vrf => { + locVrfs.push({ + label: vrf.display_name, + value: vrf.id + }); + deviceVrfs.push([{ id: vrf.id, ipv4: vrf.ipv4, ipv6: vrf.ipv6 }]); }); + allVrfs.push(locVrfs); + }); - const [queryLocation, setQueryLocation] = useState([]); - const [queryType, setQueryType] = useState(""); - const [queryVrf, setQueryVrf] = useState(""); - const [queryTarget, setQueryTarget] = useState(""); - const [availVrfs, setAvailVrfs] = useState([]); - const [fqdnTarget, setFqdnTarget] = useState(""); - const [displayTarget, setDisplayTarget] = useState(""); - const [families, setFamilies] = useState([]); - const onSubmit = (values) => { - if (!greetingAck && config.web.greeting.required) { - window.location.reload(false); - setGreetingAck(false); - } else { - setFormData(values); - setSubmitting(true); - } - }; + const intersecting = lodash.intersectionWith(...allVrfs, lodash.isEqual); + setAvailVrfs(intersecting); + !intersecting.includes(queryVrf) && + queryVrf !== "default" && + setQueryVrf("default"); - const handleLocChange = (locObj) => { - setQueryLocation(locObj.value); - const allVrfs = []; - const deviceVrfs = []; - locObj.value.map((loc) => { - const locVrfs = []; - config.devices[loc].vrfs.map((vrf) => { - locVrfs.push({ - label: vrf.display_name, - value: vrf.id, - }); - deviceVrfs.push([{ id: vrf.id, ipv4: vrf.ipv4, ipv6: vrf.ipv6 }]); - }); - allVrfs.push(locVrfs); - }); + let ipv4 = 0; + let ipv6 = 0; + deviceVrfs.length !== 0 && + intersecting.length !== 0 && + deviceVrfs + .filter(v => intersecting.every(i => i.id === v.id)) + .reduce((a, b) => a.concat(b)) + .filter(v => v.id === "default") + .map(v => { + v.ipv4 === true && ipv4++; + v.ipv6 === true && ipv6++; + }); + if (ipv4 !== 0 && ipv4 === ipv6) { + setFamilies([4, 6]); + } else if (ipv4 > ipv6) { + setFamilies([4]); + } else if (ipv4 < ipv6) { + setFamilies([6]); + } else { + setFamilies([]); + } + }; - const intersecting = lodash.intersectionWith(...allVrfs, lodash.isEqual); - setAvailVrfs(intersecting); - !intersecting.includes(queryVrf) && queryVrf !== "default" && setQueryVrf("default"); + const handleChange = e => { + setValue(e.field, e.value); + e.field === "query_location" + ? handleLocChange(e) + : e.field === "query_type" + ? setQueryType(e.value) + : e.field === "query_vrf" + ? setQueryVrf(e.value) + : e.field === "query_target" + ? setQueryTarget(e.value) + : null; + }; - let ipv4 = 0; - let ipv6 = 0; - deviceVrfs.length !== 0 && - intersecting.length !== 0 && - deviceVrfs - .filter((v) => intersecting.every((i) => i.id === v.id)) - .reduce((a, b) => a.concat(b)) - .filter((v) => v.id === "default") - .map((v) => { - v.ipv4 === true && ipv4++; - v.ipv6 === true && ipv6++; - }); - if (ipv4 !== 0 && ipv4 === ipv6) { - setFamilies([4, 6]); - } else if (ipv4 > ipv6) { - setFamilies([4]); - } else if (ipv4 < ipv6) { - setFamilies([6]); - } else { - setFamilies([]); - } - }; + const vrfContent = config.content.vrf[queryVrf]?.[queryType]; - const handleChange = (e) => { - setValue(e.field, e.value); - e.field === "query_location" - ? handleLocChange(e) - : e.field === "query_type" - ? setQueryType(e.value) - : e.field === "query_vrf" - ? setQueryVrf(e.value) - : e.field === "query_target" - ? setQueryTarget(e.value) - : null; - }; + const validFqdnQueryType = + ["ping", "traceroute", "bgp_route"].includes(queryType) && + fqdnTarget && + queryVrf === "default" + ? fqdnTarget + : null; - const vrfContent = config.content.vrf[queryVrf]?.[queryType]; - - const validFqdnQueryType = - ["ping", "traceroute", "bgp_route"].includes(queryType) && - fqdnTarget && - queryVrf === "default" - ? fqdnTarget - : null; - - useEffect(() => { - register({ name: "query_location" }); - register({ name: "query_type" }); - register({ name: "query_vrf" }); - }, [register]); - Object.keys(errors).length >= 1 && console.error(errors); - return ( - { + register({ name: "query_location" }); + register({ name: "query_type" }); + register({ name: "query_vrf" }); + }, [register]); + Object.keys(errors).length >= 1 && console.error(errors); + return ( + +
+ + - - - - - - - } - > - - - - - {availVrfs.length > 1 && ( - - - - )} - - ) - } - > - {queryType === "bgp_community" && - config.queries.bgp_community.mode === "select" ? ( - - ) : ( - - )} - - - - - - - - -
- ); - } + + + + } + > + + + + + {availVrfs.length > 1 && ( + + + + )} + + ) + } + > + {queryType === "bgp_community" && + config.queries.bgp_community.mode === "select" ? ( + + ) : ( + + )} + + + + + + + + +
+ ); + } ); HyperglassForm.displayName = "HyperglassForm"; diff --git a/hyperglass/ui/components/QueryLocation.js b/hyperglass/ui/components/QueryLocation.js index abf71b8..a2cc6d6 100644 --- a/hyperglass/ui/components/QueryLocation.js +++ b/hyperglass/ui/components/QueryLocation.js @@ -1,40 +1,44 @@ import React from "react"; import ChakraSelect from "~/components/ChakraSelect"; -const buildLocations = (networks) => { - const locations = []; - networks.map((net) => { - const netLocations = []; - net.locations.map((loc) => { - netLocations.push({ - label: loc.display_name, - value: loc.name, - group: net.display_name, - }); - }); - locations.push({ label: net.display_name, options: netLocations }); +const buildLocations = networks => { + const locations = []; + networks.map(net => { + const netLocations = []; + net.locations.map(loc => { + netLocations.push({ + label: loc.display_name, + value: loc.name, + group: net.display_name + }); }); - return locations; + locations.push({ label: net.display_name, options: netLocations }); + }); + return locations; }; -export default ({ locations, onChange }) => { - const options = buildLocations(locations); - const handleChange = (e) => { - const selected = []; - e && - e.map((sel) => { - selected.push(sel.value); - }); - onChange({ field: "query_location", value: selected }); - }; - return ( - - ); +const QueryLocation = ({ locations, onChange, label }) => { + const options = buildLocations(locations); + const handleChange = e => { + const selected = []; + e && + e.map(sel => { + selected.push(sel.value); + }); + onChange({ field: "query_location", value: selected }); + }; + return ( + + ); }; + +QueryLocation.displayName = "QueryLocation"; +export default QueryLocation; diff --git a/hyperglass/ui/components/QueryTarget.js b/hyperglass/ui/components/QueryTarget.js index c37dbdb..23ff607 100644 --- a/hyperglass/ui/components/QueryTarget.js +++ b/hyperglass/ui/components/QueryTarget.js @@ -1,74 +1,71 @@ -import React, { useEffect } from "react"; -import styled from "@emotion/styled"; +import * as React from "react"; +import { useEffect } from "react"; import { Input, useColorMode } from "@chakra-ui/core"; -const StyledInput = styled(Input)` - &::placeholder { - color: ${(props) => props.placeholderColor}; - } -`; - const fqdnPattern = /^(?!:\/\/)([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+\.[a-zA-Z]{2,6}?$/gim; const bg = { dark: "whiteAlpha.100", light: "white" }; const color = { dark: "whiteAlpha.800", light: "gray.400" }; const border = { dark: "whiteAlpha.50", light: "gray.100" }; -const placeholderColor = { dark: "whiteAlpha.400", light: "gray.400" }; +const placeholderColor = { dark: "whiteAlpha.700", light: "gray.600" }; const QueryTarget = ({ - placeholder, - register, - unregister, - setFqdn, - name, - value, - setTarget, - resolveTarget, - displayValue, - setDisplayValue, + placeholder, + register, + unregister, + setFqdn, + name, + value, + setTarget, + resolveTarget, + displayValue, + setDisplayValue }) => { - const { colorMode } = useColorMode(); + const { colorMode } = useColorMode(); - const handleBlur = () => { - if (resolveTarget && displayValue && fqdnPattern.test(displayValue)) { - setFqdn(displayValue); - } else if (resolveTarget && !displayValue) { - setFqdn(false); - } - }; - const handleChange = (e) => { - setDisplayValue(e.target.value); - setTarget({ field: name, value: e.target.value }); - }; - const handleKeyDown = (e) => { - if ([9, 13].includes(e.keyCode)) { - handleBlur(); - } - }; - useEffect(() => { - register({ name }); - return () => unregister(name); - }, [register, unregister, name]); - return ( - <> - - - - ); + const handleBlur = () => { + if (resolveTarget && displayValue && fqdnPattern.test(displayValue)) { + setFqdn(displayValue); + } else if (resolveTarget && !displayValue) { + setFqdn(false); + } + }; + const handleChange = e => { + setDisplayValue(e.target.value); + setTarget({ field: name, value: e.target.value }); + }; + const handleKeyDown = e => { + if ([9, 13].includes(e.keyCode)) { + handleBlur(); + } + }; + useEffect(() => { + register({ name }); + return () => unregister(name); + }, [register, unregister, name]); + return ( + <> + + + + ); }; QueryTarget.displayName = "QueryTarget"; diff --git a/hyperglass/ui/components/QueryType.js b/hyperglass/ui/components/QueryType.js index 8c9ee09..e5d6fbc 100644 --- a/hyperglass/ui/components/QueryType.js +++ b/hyperglass/ui/components/QueryType.js @@ -1,18 +1,22 @@ import React from "react"; import ChakraSelect from "~/components/ChakraSelect"; -export default ({ queryTypes, onChange }) => { - const queries = queryTypes - .filter(q => q.enable === true) - .map(q => { - return { value: q.name, label: q.display_name }; - }); - return ( - onChange({ field: "query_type", value: e.value })} - options={queries} - /> - ); +const QueryType = ({ queryTypes, onChange, label }) => { + const queries = queryTypes + .filter(q => q.enable === true) + .map(q => { + return { value: q.name, label: q.display_name }; + }); + return ( + onChange({ field: "query_type", value: e.value })} + options={queries} + aria-label={label} + /> + ); }; + +QueryType.displayName = "QueryType"; +export default QueryType; diff --git a/hyperglass/ui/components/QueryVrf.js b/hyperglass/ui/components/QueryVrf.js index 8df1421..10bebe8 100644 --- a/hyperglass/ui/components/QueryVrf.js +++ b/hyperglass/ui/components/QueryVrf.js @@ -1,13 +1,17 @@ import React from "react"; import ChakraSelect from "~/components/ChakraSelect"; -export default ({ vrfs, onChange }) => { - return ( - onChange({ field: "query_vrf", value: e.value })} - name="query_vrf" - options={vrfs} - /> - ); +const QueryVrf = ({ vrfs, onChange, label }) => { + return ( + onChange({ field: "query_vrf", value: e.value })} + name="query_vrf" + options={vrfs} + aria-label={label} + /> + ); }; + +QueryVrf.displayName = "QueryVrf"; +export default QueryVrf; diff --git a/hyperglass/ui/components/SubmitButton.js b/hyperglass/ui/components/SubmitButton.js index 4c78a32..c08265d 100644 --- a/hyperglass/ui/components/SubmitButton.js +++ b/hyperglass/ui/components/SubmitButton.js @@ -1,111 +1,130 @@ import React from "react"; -import { Box, PseudoBox, Spinner, useColorMode, useTheme } from "@chakra-ui/core"; +import { + Box, + PseudoBox, + Spinner, + useColorMode, + useTheme +} from "@chakra-ui/core"; import { FiSearch } from "react-icons/fi"; import { opposingColor } from "~/util"; const btnProps = { - display: "inline-flex", - appearance: "none", - alignItems: "center", - justifyContent: "center", - transition: "all 250ms", - userSelect: "none", - position: "relative", - whiteSpace: "nowrap", - verticalAlign: "middle", - lineHeight: "1.2", - outline: "none", - as: "button", - type: "submit", - borderRadius: "md", - fontWeight: "semibold" + display: "inline-flex", + appearance: "none", + alignItems: "center", + justifyContent: "center", + transition: "all 250ms", + userSelect: "none", + position: "relative", + whiteSpace: "nowrap", + verticalAlign: "middle", + lineHeight: "1.2", + outline: "none", + as: "button", + type: "submit", + borderRadius: "md", + fontWeight: "semibold" }; const btnSizeMap = { - lg: { - height: 12, - minWidth: 12, - fontSize: "lg", - px: 6 - }, - md: { - height: 10, - minWidth: 10, - fontSize: "md", - px: 4 - }, - sm: { - height: 8, - minWidth: 8, - fontSize: "sm", - px: 3 - }, - xs: { - height: 6, - minWidth: 6, - fontSize: "xs", - px: 2 - } + lg: { + height: 12, + minWidth: 12, + fontSize: "lg", + px: 6 + }, + md: { + height: 10, + minWidth: 10, + fontSize: "md", + px: 4 + }, + sm: { + height: 8, + minWidth: 8, + fontSize: "sm", + px: 3 + }, + xs: { + height: 6, + minWidth: 6, + fontSize: "xs", + px: 2 + } }; -export default React.forwardRef( - ( - { - isLoading = false, - isDisabled = false, - isActive = false, - isFullWidth = false, - size = "lg", - loadingText, - children, - ...props - }, - ref - ) => { - const _isDisabled = isDisabled || isLoading; - const { colorMode } = useColorMode(); - const theme = useTheme(); - const btnBg = { dark: theme.colors.primary[300], light: theme.colors.primary[500] }; - const btnBgActive = { dark: theme.colors.primary[400], light: theme.colors.primary[600] }; - const btnBgHover = { dark: theme.colors.primary[200], light: theme.colors.primary[400] }; - const btnColor = opposingColor(theme, btnBg[colorMode]); - const btnColorActive = opposingColor(theme, btnBgActive[colorMode]); - const btnColorHover = opposingColor(theme, btnBgHover[colorMode]); - const btnSize = btnSizeMap[size]; - return ( - - {isLoading ? ( - - ) : ( - - )} - {isLoading - ? loadingText || ( - - {children} - - ) - : children} - - ); - } +const SubmitButton = React.forwardRef( + ( + { + isLoading = false, + isDisabled = false, + isActive = false, + isFullWidth = false, + size = "lg", + loadingText, + children, + ...props + }, + ref + ) => { + const _isDisabled = isDisabled || isLoading; + const { colorMode } = useColorMode(); + const theme = useTheme(); + const btnBg = { + dark: theme.colors.primary[300], + light: theme.colors.primary[500] + }; + const btnBgActive = { + dark: theme.colors.primary[400], + light: theme.colors.primary[600] + }; + const btnBgHover = { + dark: theme.colors.primary[200], + light: theme.colors.primary[400] + }; + const btnColor = opposingColor(theme, btnBg[colorMode]); + const btnColorActive = opposingColor(theme, btnBgActive[colorMode]); + const btnColorHover = opposingColor(theme, btnBgHover[colorMode]); + const btnSize = btnSizeMap[size]; + return ( + + {isLoading ? ( + + ) : ( + + )} + {isLoading + ? loadingText || ( + + {children} + + ) + : children} + + ); + } ); + +SubmitButton.displayName = "SubmitButton"; +export default SubmitButton; diff --git a/hyperglass/ui/components/Table/makeData.js b/hyperglass/ui/components/Table/makeData.js deleted file mode 100644 index d45081f..0000000 --- a/hyperglass/ui/components/Table/makeData.js +++ /dev/null @@ -1,35 +0,0 @@ -import { generate } from "namor"; - -const range = (len) => { - const arr = []; - for (let i = 0; i < len; i++) { - arr.push(i); - } - return arr; -}; - -export const newPerson = () => { - const statusChance = Math.random(); - return { - name: generate({ words: 2, numbers: 0 }), - age: Math.floor(Math.random() * 30), - visits: Math.floor(Math.random() * 100), - progress: Math.floor(Math.random() * 100), - status: - statusChance > 0.66 ? "relationship" : statusChance > 0.33 ? "complicated" : "single", - }; -}; - -export default function makeData(...lens) { - const makeDataLevel = (depth = 0) => { - const len = lens[depth]; - return range(len).map((d) => { - return { - ...newPerson(), - subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined, - }; - }); - }; - - return makeDataLevel(); -} diff --git a/hyperglass/ui/next.config.js b/hyperglass/ui/next.config.js index 8348130..e06f6b0 100644 --- a/hyperglass/ui/next.config.js +++ b/hyperglass/ui/next.config.js @@ -4,18 +4,18 @@ const { configFile } = envVars; const config = require(String(configFile)); module.exports = { - webpack(config) { - const { alias } = config.resolve; - config.resolve.alias = { - ...alias, - ...aliases - }; - return config; - }, - poweredByHeader: false, - env: { - _NODE_ENV_: config.NODE_ENV, - _HYPERGLASS_URL_: config._HYPERGLASS_URL_, - _HYPERGLASS_CONFIG_: config._HYPERGLASS_CONFIG_ - } + webpack(config) { + const { alias } = config.resolve; + config.resolve.alias = { + ...alias, + ...aliases + }; + return config; + }, + poweredByHeader: false, + env: { + _NODE_ENV_: config.NODE_ENV, + _HYPERGLASS_URL_: config._HYPERGLASS_URL_, + _HYPERGLASS_CONFIG_: config._HYPERGLASS_CONFIG_ + } }; diff --git a/hyperglass/ui/package.json b/hyperglass/ui/package.json index 5a564ba..6d22bf4 100644 --- a/hyperglass/ui/package.json +++ b/hyperglass/ui/package.json @@ -1,99 +1,103 @@ { - "name": "ui", - "version": "1.0.0", - "description": "UI for hyperglass, the modern network looking glass", - "author": "Matt Love", - "license": "BSD-3-Clause-Clear", - "private": false, - "scripts": { - "dev": "node nextdev", - "build": "next build && next export -o ../hyperglass/static/ui", - "start": "next start" + "name": "ui", + "version": "1.0.0", + "description": "UI for hyperglass, the modern network looking glass", + "author": "Matt Love", + "license": "BSD-3-Clause-Clear", + "private": false, + "scripts": { + "dev": "node nextdev", + "build": "next build && next export -o ../hyperglass/static/ui", + "start": "next start", + "clean": "rimraf --no-glob ./.next ./out", + "check:es:build": "es-check es5 './.next/static/**/*.js' -v", + "check:es:export": "es-check es5 './out/**/*.js' -v" + }, + "browserslist": "> 0.25%, not dead", + "dependencies": { + "@chakra-ui/core": "^0.7.0", + "@emotion/core": "^10.0.28", + "@emotion/styled": "^10.0.27", + "@styled-system/should-forward-prop": "^5.1.5", + "axios": "^0.19.2", + "axios-hooks": "^1.9.0", + "chroma-js": "^2.1.0", + "dayjs": "^1.8.25", + "emotion-theming": "^10.0.27", + "framer-motion": "^1.10.0", + "lodash": "^4.17.15", + "next": "^9.3.1", + "react": "^16.13.1", + "react-countdown": "^2.2.1", + "react-dom": "^16.13.1", + "react-hook-form": "^5.1.1", + "react-icons": "^3.9.0", + "react-markdown": "^4.3.1", + "react-select": "^3.0.8", + "react-string-replace": "^0.4.4", + "react-table": "^7.0.4", + "react-textfit": "^1.1.0", + "string-format": "^2.0.0", + "styled-system": "^5.1.5", + "use-media": "^1.4.0", + "yup": "^0.28.3" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^2.24.0", + "@typescript-eslint/parser": "^2.24.0", + "babel-eslint": "^10.1.0", + "es-check": "^5.1.0", + "eslint": "^6.8.0", + "eslint-config-airbnb": "^18.1.0", + "eslint-config-prettier": "^6.10.0", + "eslint-config-react-app": "^5.2.0", + "eslint-import-resolver-webpack": "^0.12.1", + "eslint-plugin-flowtype": "^4.6.0", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-prettier": "^3.1.2", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^2.3.0", + "express": "^4.17.1", + "http-proxy-middleware": "0.20.0", + "prettier": "^1.19.1" + }, + "eslintConfig": { + "parser": "babel-eslint", + "rules": { + "max-len": [ + "error", + 100 + ], + "react/prop-types": 0, + "react/jsx-filename-extension": 0, + "react/jsx-props-no-spreading": 0, + "no-bitwise": 0, + "object-shorthand": 0, + "no-plusplus": 0, + "no-param-reassign": 0, + "no-unused-expressions": 0, + "no-nested-ternary": 0, + "no-underscore-dangle": 0, + "camelcase": 0 }, - "dependencies": { - "@chakra-ui/core": "^0.6.1", - "@emotion/core": "^10.0.28", - "@emotion/styled": "^10.0.27", - "@styled-system/should-forward-prop": "^5.1.5", - "axios": "^0.19.2", - "axios-hooks": "^1.9.0", - "chroma-js": "^2.1.0", - "dayjs": "^1.8.25", - "emotion-theming": "^10.0.27", - "framer-motion": "^1.10.0", - "lodash": "^4.17.15", - "namor": "^2.0.2", - "next": "^9.3.1", - "react": "^16.13.1", - "react-countdown": "^2.2.1", - "react-dom": "^16.13.1", - "react-hook-form": "^5.1.1", - "react-icons": "^3.9.0", - "react-markdown": "^4.3.1", - "react-select": "^3.0.8", - "react-string-replace": "^0.4.4", - "react-table": "^7.0.4", - "react-textfit": "^1.1.0", - "string-format": "^2.0.0", - "styled-system": "^5.1.5", - "use-media": "^1.4.0", - "yup": "^0.28.3" + "extends": [ + "airbnb", + "prettier", + "prettier/react" + ], + "env": { + "browser": true }, - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^2.24.0", - "@typescript-eslint/parser": "^2.24.0", - "babel-eslint": "^10.1.0", - "eslint": "^6.8.0", - "eslint-config-airbnb": "^18.1.0", - "eslint-config-prettier": "^6.10.0", - "eslint-config-react-app": "^5.2.0", - "eslint-import-resolver-webpack": "^0.12.1", - "eslint-plugin-flowtype": "^4.6.0", - "eslint-plugin-import": "^2.20.1", - "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-react": "^7.19.0", - "eslint-plugin-react-hooks": "^2.3.0", - "express": "^4.17.1", - "http-proxy-middleware": "0.20.0", - "prettier": "^1.19.1" - }, - "eslintConfig": { - "parser": "babel-eslint", - "rules": { - "max-len": [ - "error", - 100 - ], - "react/prop-types": 0, - "react/jsx-filename-extension": 0, - "react/jsx-props-no-spreading": 0, - "no-bitwise": 0, - "object-shorthand": 0, - "no-plusplus": 0, - "no-param-reassign": 0, - "no-unused-expressions": 0, - "no-nested-ternary": 0, - "no-underscore-dangle": 0, - "camelcase": 0 - }, - "extends": [ - "airbnb", - "prettier", - "prettier/react" - ], - "env": { - "browser": true - }, - "settings": { - "import/core-modules": [ - "styled-jsx/css" - ], - "import/resolver": { - "webpack": { - "config": "webpack.config.js" - } - } + "settings": { + "import/core-modules": [ + "styled-jsx/css" + ], + "import/resolver": { + "webpack": { + "config": "webpack.config.js" } + } } + } } diff --git a/hyperglass/ui/pages/_document.js b/hyperglass/ui/pages/_document.js index 4edf8bd..39d463e 100644 --- a/hyperglass/ui/pages/_document.js +++ b/hyperglass/ui/pages/_document.js @@ -2,23 +2,24 @@ import React from "react"; import Document, { Html, Head, Main, NextScript } from "next/document"; class MyDocument extends Document { - static async getInitialProps(ctx) { - const initialProps = await Document.getInitialProps(ctx); - return { ...initialProps }; - } + static async getInitialProps(ctx) { + const initialProps = await Document.getInitialProps(ctx); + return { ...initialProps }; + } - render() { - return ( - - - -