Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Code] Allow registration of other languages #1304

Open
maxijonson opened this issue May 21, 2024 · 1 comment
Open

[Code] Allow registration of other languages #1304

maxijonson opened this issue May 21, 2024 · 1 comment

Comments

@maxijonson
Copy link

Is your feature request related to a problem? Please describe.
Right now, there seem to be code highlighting for the <Code /> component only for javascript, json, jsx and typescript. I'm using it as a preview component for the Studio, and I pass in the selected language in parameter (for example, "tsx" or "sh") but I can't get highlighting to work, even if I try registerLanguage myself.

Describe the solution you'd like
It would be nice to be able to support other languages

Describe alternatives you've considered
This is a shortened version of what I'm trying, just to illustrate the problem, but it doesn't work:

import { Stack, Code } from "@sanity/ui";
import { registerLanguage } from "react-refractor";
import tsx from "refractor/lang/tsx";

registerLanguage(tsx);

const Preview = (props) => {
  return (
    <Stack>
      {props.renderDefault(props)}
      <Code language={props.language}>{props.code}</Code>
    </Stack>
  );
};

const schema = defineType({
  // ...
  preview: {
    select: {
      code: "code",
      language: "language",
    },
  },
  components: {
    preview: Preview,
  },
});

Additional context
This is what the editor looks like. I've logged the props and the "language" is correctly set to "tsx", but there's no highlight.
image

It might be worth noting that I have both refractor and react-refractor listed as dependencies because I use it differently in my frontend.

@maxijonson
Copy link
Author

maxijonson commented May 21, 2024

In case you want the actual, specific use-case I'm trying to work with, here it is:

// code-group.ts
import { CodeIcon } from "@sanity/icons";
import { defineArrayMember, defineField, defineType } from "sanity";
import CodeGroupPreview from "../../desk/components/code-group-preview/code-group-preview";

export default defineType({
  type: "object",
  name: "codeGroup",
  title: "Code Group",
  icon: CodeIcon,
  fields: [
    defineField({
      type: "array",
      name: "snippets",
      of: [
        defineArrayMember({
          type: "code",
          options: {
            language: "text",
            withFilename: true,
            languageAlternatives: [
              /**
               * If you add more languages, you'll need to:
               * 1. Add the language below
               * 2. Update the post-body-code.tsx to register the language
               */
              { title: "TypeScript", value: "typescript" },
              { title: "TSX", value: "tsx" },
              { title: "Shell", value: "sh" },
              { title: "JSON", value: "json" },
              { title: "Text", value: "text" },
            ],
          },
        }),
      ],
    }),
  ],
  preview: {
    select: {
      snippets: "snippets",
    },
  },
  components: {
    preview: CodeGroupPreview,
  },
});
// code-group-preview.tsx
"use client";
import {
  Button,
  Code,
  Container,
  Menu,
  MenuButton,
  MenuItem,
  Stack,
} from "@sanity/ui";
import { useEffect, useState } from "react";
import { registerLanguage } from "react-refractor";
import tsx from "refractor/lang/tsx";
import type { PreviewProps } from "sanity";
import type { CodeGroup } from "../../../sanity.types";

registerLanguage(tsx);

export type CodeGroupPreviewProps = PreviewProps & {
  snippets?: CodeGroup["snippets"];
};

const CodeGroupPreview = ({
  snippets = [],
  ...props
}: CodeGroupPreviewProps) => {
  const [activeTab, setActiveTab] = useState(0);
  const activeSnippet = snippets[activeTab];

  useEffect(() => {
    if (activeSnippet) return;
    setActiveTab(0);
  }, [activeSnippet]);

  if (!activeSnippet) return null;
  return (
    <Stack space={3}>
      {props.renderDefault({
        ...props,
        title: `Code Group | ${snippets.length} ${snippets.length === 1 ? "Snippet" : "Snippets"}`,
        layout: "block",
      })}
      <MenuButton
        button={
          <Button text={activeSnippet.filename || `Snippet ${activeTab}`} />
        }
        id="code-group-preview-menu"
        menu={
          <Menu>
            {snippets.map((snippet, index) => (
              <MenuItem
                key={index}
                onClick={() => setActiveTab(index)}
                padding={3}
                text={snippet.filename || `Snippet ${index}`}
              />
            ))}
          </Menu>
        }
        popover={{ portal: true }}
      />
      <Container padding={3} overflow="auto">
        <Code language="tsx">{activeSnippet.code}</Code>
      </Container>
    </Stack>
  );
};

export default CodeGroupPreview;

I'm using an array of the @sanity/code-input type. Weirdly enough, when opening my preview, which lists all code snippets from the code type, Syntax highlighting works there, but never on the preview component

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant