Junior Garcia b8e7b94586
🚀 (#4570)
* docs: optimize route higtlight (#4520)

* docs: optimize home display (#4519)

* docs: optimize home display and route highlight

* docs: optimize home display

* fix(alert): propagate className (#4535)

* fix(alert): propagate className

* chore(alert): remove className from alert theme

* fix(avatar): title type in Avatar (#4529)

* fix(avatar): title type in Avatar

* fix(alert): apply isEmpty check on title

* fix(alert): alert interface props type

* refactor: remove unnecessary props types (#4530)

* refactor(docs): remove string type as it is included in ReactNode

* refactor: remove unnecessary types

* feat(changeset): add changeset

* chore: remove changeset

* refactor: remove null since ReactNode unions it already

* fix(input): use onPress for wrapper click focus (#4483)

* fix(input): use onPress for wrapper click focus

* test(input): wrapper click focus test

* chore(changeset): input onPress for wrapper click focus

* chore(changeset): minor wording

* Refactor/rebrand (#4532)

* chore: rebrand in progress

* chore: update docs to use heroui

* chore: components renbranded

* chore: figma moved to the docs files

* fix: posthog config

* fix(docs): extra classname in form example (#4465)

* chore: clean git

* chore: make heroui private

* chore: new logo

* chore: node env var renamed

* chore: public robots txt deleted

* chore: wrangler installed

* chore: wrangler renamed

* chore: cloudlfare workers removed

* chore: force vercel deploy

* refactor: first migration and provider

* refactor: rename nextui plugin

* refactor: rename github site

* refactor: rename CONTRIBUTING

* refactor: rename package name

* refactor: nextjs image hostname

* refactor: mdx repo nextui-org rename frontio-ai

* refactor: nextui.org rename heroui.com

* refactor: add heroui to missing places

* fix: heroui plugin name

* fix: update docs

* docs: nextui to heroui add npmrc pnpm migratation

* chore: rename all packages with new org name

* chore: replace frontio-ai by frontioai

* chore: revert previous changes

* chore: small adjustment

* chore: doc updated

* feat: blog

* chore: avatar updated

* fix: url

* chore: add new ogimage

* fix: ogimage command

* fix: heroui name and storybook welcome page

* fix: og image url

* feat: favicon and icon changed

---------

Co-authored-by: աӄա <wingkwong.code@gmail.com>
Co-authored-by: winches <329487092@qq.com>

* fix: postbuild script

* chore: core package updates

* ci(changesets): version packages (#4569)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* feat: contributors added to the blog

---------

Co-authored-by: winches <329487092@qq.com>
Co-authored-by: աӄա <wingkwong.code@gmail.com>
Co-authored-by: Peterl561 <76144929+Peterl561@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-01-16 16:24:32 -03:00

166 lines
4.4 KiB
TypeScript

// Inspired by https://github.dev/modulz/stitches-site code demo
import React from "react";
import refractor from "refractor/core";
import js from "refractor/lang/javascript";
import jsx from "refractor/lang/jsx";
import bash from "refractor/lang/bash";
import css from "refractor/lang/css";
import diff from "refractor/lang/diff";
import {toHtml} from "hast-util-to-html";
import rangeParser from "parse-numeric-range";
import {clsx} from "@heroui/shared-utils";
import {Pre} from "./pre";
import {WindowActions} from "./window-actions";
import highlightLine from "@/libs/rehype-highlight-line";
import highlightWord from "@/libs/rehype-highlight-word";
refractor.register(js);
refractor.register(jsx);
refractor.register(bash);
refractor.register(css);
refractor.register(diff);
type PreProps = Omit<React.ComponentProps<typeof Pre>, "css">;
export type CodeBlockProps = PreProps & {
language: "js" | "jsx" | "bash" | "css" | "diff";
title?: string;
value?: string;
highlightLines?: string;
mode?: "static" | "typewriter";
showLineNumbers?: boolean;
showWindowIcons?: boolean;
className?: string;
};
/**
* recursively get all text nodes as an array for a given element
*/
function getTextNodes(node: any): any[] {
let childTextNodes: React.ReactNode[] = [];
if (!node.hasChildNodes()) return [];
const childNodes = node.childNodes;
for (let i = 0; i < childNodes.length; i++) {
if (childNodes[i].nodeType == Node.TEXT_NODE) {
childTextNodes.push(childNodes[i]);
} else if (childNodes[i].nodeType == Node.ELEMENT_NODE) {
Array.prototype.push.apply(childTextNodes, getTextNodes(childNodes[i]));
}
}
return childTextNodes;
}
/**
* given a text node, wrap each character in the
* given tag.
*/
function wrapEachCharacter(textNode: any, tag: string, count: number) {
const text = textNode.nodeValue;
const parent = textNode.parentNode;
const characters = text.split("");
characters.forEach(function (character: any, letterIndex: any) {
const delay = (count + letterIndex) * 50;
var element = document.createElement(tag);
var characterNode = document.createTextNode(character);
element.appendChild(characterNode);
element.style.opacity = "0";
element.style.transition = `all ease 0ms ${delay}ms`;
parent.insertBefore(element, textNode);
// skip a couple of frames to trigger transition
requestAnimationFrame(() => requestAnimationFrame(() => (element.style.opacity = "1")));
});
parent.removeChild(textNode);
}
function CodeTypewriter({value, className, css, ...props}: any) {
const wrapperRef = React.useRef(null);
React.useEffect(() => {
const wrapper = wrapperRef.current as any;
if (wrapper) {
var allTextNodes = getTextNodes(wrapper);
let count = 0;
allTextNodes?.forEach((textNode) => {
wrapEachCharacter(textNode, "span", count);
count = count + textNode.nodeValue.length;
});
wrapper.style.opacity = "1";
}
return () => (wrapper.innerHTML = value);
}, []);
return (
<Pre className={className} css={css} {...props}>
<code
dangerouslySetInnerHTML={{__html: value}}
ref={wrapperRef}
className={className}
style={{opacity: 0}}
/>
</Pre>
);
}
const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forwardedRef) => {
const {
language,
value,
title,
highlightLines = "0",
className = "",
mode,
showLineNumbers,
showWindowIcons,
...props
} = _props;
let result: any = refractor.highlight(value || "", language);
result = highlightLine(result, rangeParser(highlightLines));
result = highlightWord(result);
// convert to html
result = toHtml(result);
// TODO reset theme
const classes = `language-${language}`;
const codeClasses = clsx("absolute w-full px-4 pb-6", showWindowIcons ? "top-10" : "top-0");
if (mode === "typewriter") {
return <CodeTypewriter className={classes} css={css} value={result} {...props} />;
}
return (
<Pre
ref={forwardedRef}
className={clsx("code-block", classes, className)}
data-line-numbers={showLineNumbers}
{...props}
>
{showWindowIcons && <WindowActions title={title} />}
<code dangerouslySetInnerHTML={{__html: result}} className={clsx(classes, codeClasses)} />
</Pre>
);
});
CodeBlock.displayName = "HeroUI - CodeBlock";
export default CodeBlock;