All files / src/comps KeyValues.tsx

97.95% Statements 48/49
81.25% Branches 39/48
100% Functions 9/9
97.95% Lines 48/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129                                      22x 121x 119x 119x 119x   119x 119x 119x             119x 2x     117x 1025x   117x 4x   2x   2x       117x         117x     1152x               22x     22x 1152x 1152x 1152x 1152x 1152x 1152x 1152x                       22x   22x 1154x 1152x 1152x 1152x 1152x 1152x 1152x 1152x 1152x 1152x 1152x 18x 18x                     1134x 11x 1x   1134x                 22x  
import { Fragment, useRef } from 'react';
import { useStore } from '../store';
import { useExpandsStore } from '../store/Expands';
import { useShowToolsDispatch } from '../store/ShowTools';
import { Value } from './Value';
import { KeyNameComp } from '../section/KeyName';
import { RowComp } from '../section/Row';
import { Container } from '../Container';
import { Quote, Colon } from '../symbol';
import { useHighlight } from '../utils/useHighlight';
import { type SectionElementResult } from '../store/Section';
import { Copied } from '../comps/Copied';
import { useIdCompat } from '../comps/useIdCompat';
 
interface KeyValuesProps<T extends object> extends SectionElementResult<T> {
  expandKey?: string;
  level: number;
}
 
export const KeyValues = <T extends object>(props: KeyValuesProps<T>) => {
  const { value, expandKey = '', level, keys = [] } = props;
  const expands = useExpandsStore();
  const { objectSortKeys, indentWidth, collapsed, shouldExpandNodeInitially } = useStore();
  const isMyArray = Array.isArray(value);
  const defaultExpanded =
    typeof collapsed === 'boolean' ? collapsed : typeof collapsed === 'number' ? level > collapsed : false;
  const isExpanded = expands[expandKey] ?? defaultExpanded;
  Iif (
    expands[expandKey] === undefined &&
    shouldExpandNodeInitially &&
    shouldExpandNodeInitially(isExpanded, { value, keys, level })
  ) {
    return null;
  }
  if (isExpanded) {
    return null;
  }
  // object
  let entries: [key: string | number, value: T][] = isMyArray
    ? Object.entries(value).map((m) => [Number(m[0]), m[1]])
    : Object.entries(value as T);
  if (objectSortKeys) {
    entries =
      objectSortKeys === true
        ? entries.sort(([a], [b]) => (typeof a === 'string' && typeof b === 'string' ? a.localeCompare(b) : 0))
        : entries.sort(([a, valA], [b, valB]) =>
            typeof a === 'string' && typeof b === 'string' ? objectSortKeys(a, b, valA, valB) : 0,
          );
  }
 
  const style = {
    borderLeft: 'var(--w-rjv-border-left-width, 1px) var(--w-rjv-line-style, solid) var(--w-rjv-line-color, #ebebeb)',
    paddingLeft: indentWidth,
    marginLeft: 6,
  };
  return (
    <div className="w-rjv-wrap" style={style}>
      {entries.map(([key, val], idx) => {
        return (
          <KeyValuesItem parentValue={value} keyName={key} keys={[...keys, key]} value={val} key={idx} level={level} />
        );
      })}
    </div>
  );
};
 
KeyValues.displayName = 'JVR.KeyValues';
 
interface KayNameProps<T extends object> extends Omit<KeyValuesProps<T>, 'level'> {}
export const KayName = <T extends object>(props: KayNameProps<T>) => {
  const { keyName, parentValue, keys, value } = props;
  const { highlightUpdates } = useStore();
  const isNumber = typeof keyName === 'number';
  const highlightContainer = useRef<HTMLSpanElement>(null);
  useHighlight({ value, highlightUpdates, highlightContainer });
  const compProps = { keyName, value, keys, parentValue };
  return (
    <Fragment>
      <span ref={highlightContainer}>
        <Quote isNumber={isNumber} data-placement="left" {...compProps} />
        <KeyNameComp {...compProps}>{keyName}</KeyNameComp>
        <Quote isNumber={isNumber} data-placement="right" {...compProps} />
      </span>
      <Colon {...compProps} />
    </Fragment>
  );
};
 
KayName.displayName = 'JVR.KayName';
 
export const KeyValuesItem = <T extends object>(props: KeyValuesProps<T>) => {
  const { keyName, value, parentValue, level = 0, keys = [] } = props;
  const dispatch = useShowToolsDispatch();
  const subkeyid = useIdCompat();
  const isMyArray = Array.isArray(value);
  const isMySet = value instanceof Set;
  const isMyMap = value instanceof Map;
  const isDate = value instanceof Date;
  const isUrl = value instanceof URL;
  const isMyObject = value && typeof value === 'object' && !isMyArray && !isMySet && !isMyMap && !isDate && !isUrl;
  const isNested = isMyObject || isMyArray || isMySet || isMyMap;
  if (isNested) {
    const myValue = isMySet ? Array.from(value as Set<any>) : isMyMap ? Object.fromEntries(value) : value;
    return (
      <Container
        keyName={keyName}
        value={myValue}
        parentValue={parentValue}
        initialValue={value}
        keys={keys}
        level={level + 1}
      />
    );
  }
  const reset: React.HTMLAttributes<HTMLDivElement> = {
    onMouseEnter: () => dispatch({ [subkeyid]: true }),
    onMouseLeave: () => dispatch({ [subkeyid]: false }),
  };
  return (
    <RowComp className="w-rjv-line" value={value} keyName={keyName} keys={keys} parentValue={parentValue} {...reset}>
      <KayName keyName={keyName} value={value} keys={keys} parentValue={parentValue} />
      <Value keyName={keyName!} value={value} />
      <Copied keyName={keyName} value={value as object} keys={keys} parentValue={parentValue} expandKey={subkeyid} />
    </RowComp>
  );
};
 
KeyValuesItem.displayName = 'JVR.KeyValuesItem';