Browse Source

Review fixes

pull/652/head
philon- 1 year ago
parent
commit
05de7a4f95
  1. 24
      src/components/UI/Input.tsx
  2. 68
      src/core/utils/deepCompareConfig.ts
  3. 3
      src/core/utils/eventBus.ts
  4. 2
      src/i18n/locales/en/common.json

24
src/components/UI/Input.tsx

@ -6,16 +6,17 @@ import { useCopyToClipboard } from "@core/hooks/useCopyToClipboard.ts";
import { usePasswordVisibilityToggle } from "@core/hooks/usePasswordVisibilityToggle.ts";
import { useTranslation } from "react-i18next";
const cnInvalidBase = "border-2 border-red-500 dark:border-red-500";
const cnDirtyBase = "border-2 border-sky-500 dark:border-sky-500";
const inputVariants = cva(
"flex h-10 w-full rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-1 focus:ring-slate-400 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-500 dark:bg-transparet dark:text-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-600",
{
variants: {
variant: {
default: "border-slate-300 dark:border-slate-500",
invalid:
"border-2 border-red-500 dark:border-red-500 focus:ring-red-500 dark:focus:ring-red-500",
dirty:
"border-2 border-sky-500 dark:border-sky-500 focus:ring-sky-500 dark:focus:ring-sky-500",
invalid: `${cnInvalidBase} focus:ring-red-500 dark:focus:ring-red-500`,
dirty: `${cnDirtyBase} focus:ring-sky-500 dark:focus:ring-sky-500`,
},
},
defaultVariants: {
@ -140,6 +141,11 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
className,
);
const extrasClassName = cn([
variant === "invalid" && `${cnInvalidBase} border-l-0`,
variant === "dirty" && `${cnDirtyBase} border-l-0`,
]);
return (
<div
className={cn("relative flex w-full items-stretch", containerClassName)}
@ -165,10 +171,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<span
className={cn(
"inline-flex items-center border border-l-0 border-slate-300 bg-slate-100/80 px-3 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300",
variant === "invalid" &&
"border-2 border-l-0 border-red-500 dark:border-red-500",
variant === "dirty" &&
"border-2 border-l-0 border-sky-500 dark:border-sky-500",
extrasClassName,
!hasActions && "rounded-r-md",
)}
>
@ -180,10 +183,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<div
className={cn(
"flex items-center divide-x divide-slate-300 border border-l-0 border-slate-300 dark:divide-slate-700 dark:border-slate-500",
variant === "invalid" &&
"border-2 border-l-0 border-red-500 dark:border-red-500",
variant === "dirty" &&
"border-2 border-l-0 border-sky-500 dark:border-sky-500",
extrasClassName,
disabled &&
"border-slate-200 dark:border-slate-700 divide-slate-200",
!hasSuffix && "rounded-r-md",

68
src/core/utils/deepCompareConfig.ts

@ -1,66 +1,56 @@
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
export function deepCompareConfig(
existing: unknown,
working: unknown,
a: unknown,
b: unknown,
allowUndefined = false,
): boolean {
if (existing === working) return true;
if (
allowUndefined &&
(typeof existing === "undefined" || typeof working === "undefined")
) return true;
if (a === b) {
return true;
}
if (typeof existing !== typeof working) {
return false;
// If allowUndefined is true, and one is undefined, they are considered equal. // This check is placed early to simplify subsequent logic.
if (allowUndefined && (a === undefined || b === undefined)) {
return true;
}
if (existing === null || working === null) {
if (existing !== working) {
if (typeof a !== typeof b || a === null || b === null) {
return false;
}
return true;
}
if (Array.isArray(existing) && Array.isArray(working)) {
if (existing.length !== working.length && !allowUndefined) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length && !allowUndefined) {
return false;
}
for (let i = 0; i < existing.length; i++) {
if (
!deepCompareConfig(existing[i], working[i], allowUndefined)
) {
const longestLength = Math.max(a.length, b.length);
for (let i = 0; i < longestLength; i++) {
if (!deepCompareConfig(a[i], b[i], allowUndefined)) {
return false;
}
}
return true;
}
if (typeof existing === "object" && typeof working === "object") {
const exObj = existing as Record<string, unknown>;
const woObj = working as Record<string, unknown>;
const keys = new Set<string>([
...Object.keys(exObj),
...Object.keys(woObj),
]);
if (isObject(a) && isObject(b)) {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
const allKeys = new Set([...aKeys, ...bKeys]);
for (const key of keys) {
if (key === "$typeName") continue;
const hasExisting = Object.prototype.hasOwnProperty.call(exObj, key);
const hasWorking = Object.prototype.hasOwnProperty.call(woObj, key);
const valExisting = exObj[key];
const valWorking = woObj[key];
if (!hasWorking && allowUndefined && hasExisting) {
for (const key of allKeys) {
if (key === "$typeName") {
continue;
}
if (
!deepCompareConfig(valExisting, valWorking, allowUndefined)
) {
const aValue = a[key];
const bValue = b[key];
if (!deepCompareConfig(aValue, bValue, allowUndefined)) {
return false;
}
}
return true;
}

3
src/core/utils/eventBus.ts

@ -2,9 +2,6 @@ export type EventMap = {
"dialog:unsafeRoles": {
action: "confirm" | "dismiss";
};
"dialog:managedMode": {
action: "confirm" | "dismiss";
};
};
export type EventName = keyof EventMap;

2
src/i18n/locales/en/common.json

@ -71,7 +71,7 @@
"unset": "UNSET",
"fallbackName": "Meshtastic {{last4}}",
"formValidation": {
"unsavedChanges": "There are unsaved changes",
"unsavedChanges": "Unsaved changes",
"tooBig": {
"string": "Too long, expected less than or equal to {{maximum}} characters.",
"number": "Too big, expected a number smaller than or equal to {{maximum}}.",

Loading…
Cancel
Save