uiwjs / react-codemirror

CodeMirror 6 component for React. @codemirror https://uiwjs.github.io/react-codemirror/
https://uiwjs.github.io/react-codemirror/
MIT License
1.62k stars 128 forks source link

className not working in zebraStripes #676

Open ritik307 opened 1 month ago

ritik307 commented 1 month ago

I am trying to add zebraStripes on my codemirror and my goal here is to add zebraStripes to the line of code where the className = 'text-wrapper' but tehe feature isnt working. Can anyone help Following is the code:

     <CodeMirror
            value={jsonData}
            height="90vh"
            theme="dark"
            extensions={[langs.jsx(), zebraStripes({
              className: "text-wrapper"
            }),]}
            onDoubleClick={(event, value) => {
              handleDoubleClick(event, value);
            }}
            onChange={(value) => {
              handleOnJsChange(value);
            }}
        />

Screenshot:

Screenshot 2024-07-22 at 4 51 36 PM
jaywcjlove commented 1 month ago
image

@ritik307 I am unable to reproduce your error. After testing, it works correctly.

ritik307 commented 1 month ago

@jaywcjlove Its not working for me can you share you code snippet on your implementation. Maybe i am doing something wrong

jaywcjlove commented 1 month ago

@ritik307

https://github.com/uiwjs/react-codemirror/blob/3b02cab2cfed5b050eff54b0d063f2639fdd4d8c/www/src/pages/extensions/zebra-stripes/index.tsx#L46-L54

ritik307 commented 1 month ago

@jaywcjlove Still isnt working for me. Can you try the same zebraStripe code on the following jsx. My wild gues here is that it doesnt work for .jsx code

const StyledElementOurCompany = styled.div`
    background - color: #FFFFFF;
    display: flex;
    flex - direction: row;
    justify - content: center;
    width: 100 %;
     & .div {
     background - color: #FFFFFF;
     height: 1080px;
     overflow: hidden;
     position: relative;
     width: 1920px;
    }
     & .image - replace - here {
     height: 541px;
     left: 1379px;
     position: absolute;
     top: 0;
     width: 541px;
    }
     & .img {
     height: 539px;
     left: 838px;
     object - fit: cover;
     position: absolute;
     top: 541px;
     width: 541px;
    }
     & .data - text {
     height: 541px;
     left: 1379px;
     position: absolute;
     top: 541px;
     width: 545px;
    }
     & .overlap - group {
     background - color: #C1592E;
     height: 541px;
     position: relative;
     width: 541px;
    }
     & .text - wrapper {
     color: #FFFFFF;
     font - family: "Inter-Regular", Helvetica;
     font - size: 32px;
     font - weight: 400;
     left: 97px;
     letter - spacing: 0;
     line - height: normal;
     position: absolute;
     top: 288px;
     width: 348px;
    }
     & .text - wrapper - 2 {
     color: #FFFFFF;
     font - family: "Inter-Bold", Helvetica;
     font - size: 130px;
     font - weight: 700;
     left: 97px;
     letter - spacing: 0;
     line - height: normal;
     position: absolute;
     top: 110px;
    }
     & .company - text {
     align - items: flex - start;
     display: inline - flex;
     flex - direction: column;
     gap: 32px;
     left: 100px;
     position: absolute;
     top: 100px;
    }
     & .text - wrapper - 3 {
     color: #000000;
     font - family: "Red Hat Display-Bold", Helvetica;
     font - size: 96px;
     font - weight: 700;
     letter - spacing: 0;
     line - height: normal;
     margin - top: -1px;
     position: relative;
     width: fit - content;
    }
     & .lorem - ipsum - dolor {
     color: #19363A;
     font - family: "Inter-Regular", Helvetica;
     font - size: 42px;
     font - weight: 400;
     letter - spacing: 0;
     line - height: normal;
     position: relative;
     width: 658px;
    }
     `;
    export default ElementOurCompany = () => {
     return (
     <StyledElementOurCompany>
     <div className="div">
     <img className="image-replace-here" alt="Image replace here" src={image1} />
     <img className="img" alt="Image replace here" src={image2} />
     <div className="data-text">
     <div className="overlap-group">
     <p className="text-wrapper">{{abcdef}}</p>
     <div className="text-wrapper-2">{{abcd}}</div>
     </div>
     </div>
     <div className="company-text">
     <div className="text-wrapper-3">Our Company</div>
     <p className="cm-zebra-stripe">
     Lorem ipsum dolor sit amet, consectetur adipiscing elit dolor sit amet, consectetur adipiscing elit.Lorem
     ipsum dolor sit amet, consectetur adipiscing elit dolor sit amet, consectetur adipiscing elit. Irem ipsum
     dolor sit amet, <br />
     <br />
     Sectetur TEST elit dolor sit amet, consectetur adipiscing elit.
     </p>
     </div>
     </div>
     </StyledElementOurCompany>
     );
    };
jaywcjlove commented 1 month ago

@ritik307 Could you provide a reproducible example of the error? It looks like you might not be using the react-codemirror component.

ritik307 commented 1 month ago

@jaywcjlove Following is a reactjs codebase

Code Snippets

import React, { useEffect, useState, useCallback, useRef } from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { langs } from '@uiw/codemirror-extensions-langs';
import { View, VStack } from '@gluestack-ui/themed';
import Header from './Header';
import { zebraStripes } from '@uiw/codemirror-extensions-zebra-stripes';

const Editor = ({
  jsonData,
  setJsonData,
  setSelectedTagInfo,
  selectedKeyData,
  setSelectedKeyData,
  data,
  setData,
  setMappingData,
  mappingData,
  setIsDataTypesDisable,
  ...props
}) => {
  const [newJsxData, setNewJsxData] = useState('');

  const extractTagNameAndClass = htmlString => {
    let tagAndClass = [];
    let startIndex = htmlString.indexOf('<');
    let endIndex = htmlString.indexOf('>');

    if (startIndex === -1 || endIndex === -1) {
      return tagAndClass;
    }

    let tagWithAttributes = htmlString.substring(startIndex + 1, endIndex);
    let parts = tagWithAttributes.split(/\s+/);
    tagAndClass.push(parts[0]);

    for (let i = 1; i < parts.length; i++) {
      if (parts[i].startsWith('className="')) {
        let className = parts[i].substring(
          'className="'.length,
          parts[i].length - 1,
        );
        tagAndClass.push(className);
        break;
      } else if (parts[i].startsWith('class="')) {
        let className = parts[i].substring(
          'class="'.length,
          parts[i].length - 1,
        );
        tagAndClass.push(className);
        break;
      }
    }

    return tagAndClass;
  };

  const createDOMElement = jsxData => {
    try {
      const parser = new DOMParser();
      const doc = parser.parseFromString(jsxData, 'text/html');
      return doc.body;
    } catch (err) {
      console.log(err?.message);
    }
  };

  const extractKeyData = (input) => {
    const regex = /\{\{(.+?)\}\}/;
    const match = input?.match(regex);
    if (match) {
      return match[1];
    } else {
      return null;
    }
  }

  const extractTagInfo = (mainJsx, filterStr) => {
    try {
      const tagCheck = filterStr.includes('<') && filterStr.includes('>');
      const jsxData = mainJsx.replace(/className/g, 'class');
      const dom = createDOMElement(jsxData);
      if (tagCheck) {
        const tagClassData = extractTagNameAndClass(filterStr);
        const tagName = tagClassData[0];
        const className = tagClassData[1];
        const element = dom.querySelector(`${tagName}.${className}`);
        const keyData = extractKeyData(element?.textContent?.trim());
        return {
          tagName: element.tagName,
          textContent: element?.textContent?.trim() || '',
          keyData: keyData
        };
      } else {
        const textNodes = [];
        const walker = document.createTreeWalker(
          dom,
          NodeFilter.SHOW_TEXT,
          null,
          false,
        );

        let node;
        while ((node = walker.nextNode())) {
          if (node.nodeValue.includes(`{{${filterStr}}}`)) {
            textNodes.push(node.nodeValue.trim());
          }
        }
        if (textNodes.length > 0) {
          const textStr = textNodes.join(' ');
          const keyData = extractKeyData(textStr?.trim());
          return {
            textContent: textStr?.trim(),
            keyData: keyData
          };
        }
      }
      return { textContent: '' };
    } catch (err) {
      console.log(err);
      return { textContent: '' };
    }
  };

  const handleDoubleClick = useCallback((event, view) => {
    setSelectedTagInfo({ value: event?.target?.textContent });
    console.log("--info:", event?.target?.textContent)
    const tagData = extractTagInfo(
      jsonData,
      event?.target?.textContent?.trim(),
    );
    setSelectedKeyData({ ...tagData });
    console.log("--tagData: ", tagData);
    setIsDataTypesDisable(false)
  }, [jsonData, setSelectedTagInfo, setSelectedKeyData]);

  const handleOnJsChange = useCallback(changeData => {
    setJsonData(changeData); // Update the state with new JS data
    setNewJsxData(changeData); // Also keep the local state updated
  }, [setJsonData]);

  return (
    <View width={'50%'}>
      <VStack>
        <Header
          newJsxData={newJsxData}
          setJsonData={setJsonData}
          jsonData={jsonData}
          selectedKeyData={selectedKeyData}
          data={data}
          setData={setData}
          setMappingData={setMappingData}
          mappingData={mappingData}
          setIsDataTypesDisable={setIsDataTypesDisable}
        />
        <View flex={1} padding={10} height={'100%'}>
          <CodeMirror
            value={jsonData}
            height="90vh"
            theme="dark"

            extensions={[langs.jsx(), zebraStripes({
              lineNumber: [1, [3, 6], 10],
              lightColor: '#aca2ff33',
              darkColor: '#aca2ff40',
              className: 'xxx-text-wrapper',
            }),]}
            onDoubleClick={(event, value) => {
              handleDoubleClick(event, value);
            }}
            onChange={(value) => {
              handleOnJsChange(value);
            }}
          />
        </View>
      </VStack>
    </View>
  );
};

export default Editor;

jsonData value

const StyledElementOurCompany = styled.div`
    background - color: #FFFFFF;
    display: flex;
    flex - direction: row;
    justify - content: center;
    width: 100 %;
     & .div {
     background - color: #FFFFFF;
     height: 1080px;
     overflow: hidden;
     position: relative;
     width: 1920px;
    }
     & .image - replace - here {
     height: 541px;
     left: 1379px;
     position: absolute;
     top: 0;
     width: 541px;
    }
     & .img {
     height: 539px;
     left: 838px;
     object - fit: cover;
     position: absolute;
     top: 541px;
     width: 541px;
    }
     & .data - text {
     height: 541px;
     left: 1379px;
     position: absolute;
     top: 541px;
     width: 545px;
    }
     & .overlap - group {
     background - color: #C1592E;
     height: 541px;
     position: relative;
     width: 541px;
    }
     & .text - wrapper {
     color: #FFFFFF;
     font - family: "Inter-Regular", Helvetica;
     font - size: 32px;
     font - weight: 400;
     left: 97px;
     letter - spacing: 0;
     line - height: normal;
     position: absolute;
     top: 288px;
     width: 348px;
    }
     & .text - wrapper - 2 {
     color: #FFFFFF;
     font - family: "Inter-Bold", Helvetica;
     font - size: 130px;
     font - weight: 700;
     left: 97px;
     letter - spacing: 0;
     line - height: normal;
     position: absolute;
     top: 110px;
    }
     & .company - text {
     align - items: flex - start;
     display: inline - flex;
     flex - direction: column;
     gap: 32px;
     left: 100px;
     position: absolute;
     top: 100px;
    }
     & .text - wrapper - 3 {
     color: #000000;
     font - family: "Red Hat Display-Bold", Helvetica;
     font - size: 96px;
     font - weight: 700;
     letter - spacing: 0;
     line - height: normal;
     margin - top: -1px;
     position: relative;
     width: fit - content;
    }
     & .lorem - ipsum - dolor {
     color: #19363A;
     font - family: "Inter-Regular", Helvetica;
     font - size: 42px;
     font - weight: 400;
     letter - spacing: 0;
     line - height: normal;
     position: relative;
     width: 658px;
    }
     `;
    export default ElementOurCompany = () => {
     return (
     <StyledElementOurCompany>
     <div className="div">
     <img className="image-replace-here" alt="Image replace here" src={image1} />
     <img className="img" alt="Image replace here" src={image2} />
     <div className="data-text">
     <div className="overlap-group">
     <p className="text-wrapper">{{abcdef}}</p>
     <div className="text-wrapper-2">{{abcd}}</div>
     </div>
     </div>
     <div className="company-text">
     <div className="text-wrapper-3">Our Company</div>
     <p className="cm-zebra-stripe">
     Lorem ipsum dolor sit amet, consectetur adipiscing elit dolor sit amet, consectetur adipiscing elit.Lorem
     ipsum dolor sit amet, consectetur adipiscing elit dolor sit amet, consectetur adipiscing elit. Irem ipsum
     dolor sit amet, <br />
     <br />
     Sectetur TEST elit dolor sit amet, consectetur adipiscing elit.
     </p>
     </div>
     </div>
     </StyledElementOurCompany>
     );
    };
jaywcjlove commented 1 month ago

@ritik307 How do I run your example?

ritik307 commented 1 month ago

@jaywcjlove You don't have to, it is for reference so that you can check whether i have implemented the code right or not . To test the problem that I am facing just replace the value that you are providing with my above given jsonData value code in your example