Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,15 @@
"files": [
"lib",
"styles",
"images"
"images",
"src/tailwind-config.css"
],
"type": "module",
"main": "./lib/index.js",
"exports": {
".": "./lib/index.js",
"./tailwind-config.css": "./src/tailwind-config.css"
},
"browserslist": "chrome 70, firefox 70, safari 11.1",
"dependencies": {
"highlight.js": "^11.6.0",
Expand Down
12 changes: 9 additions & 3 deletions src/pattern-library/components/Library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Scroll,
ScrollContainer,
} from '../../';
import type { CodeLanguage } from '../util/jsx-to-string';
import { highlightCode, jsxToHTML } from '../util/jsx-to-string';

/**
Expand Down Expand Up @@ -464,13 +465,18 @@ type CodeContentProps =
| {
/** Code content (to be rendered with syntax highlighting) */
content: ComponentChildren;

/** Programming language. */
lang?: CodeLanguage;
}
| {
/**
* Example file to read and use as content (to be rendered with syntax
* highlighting)
* highlighting).
*/
exampleFile: string;

// Example files are currently assumed to always be TypeScript.
};

export type LibraryCodeProps = {
Expand All @@ -495,7 +501,7 @@ function useCodeContent(
): [string | undefined, Error | undefined] {
const hasStaticContent = isCodeWithContent(props);
const [codeMarkup, setCodeMarkup] = useState<string | undefined>(
hasStaticContent ? jsxToHTML(props.content) : undefined,
hasStaticContent ? jsxToHTML(props.content, props.lang) : undefined,
);
const [error, setError] = useState<Error>();

Expand All @@ -506,7 +512,7 @@ function useCodeContent(

const controller = new AbortController();
fetchCodeExample(`/examples/${props.exampleFile}.tsx`, controller.signal)
.then(code => setCodeMarkup(highlightCode(code)))
.then(code => setCodeMarkup(highlightCode(code, 'typescript')))
.catch(setError);

return () => controller.abort();
Expand Down
68 changes: 43 additions & 25 deletions src/pattern-library/components/patterns/GettingStartedPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,58 @@ export default function GettingStartedPage() {
<Library.Section>
<Library.SectionL2 title="Installation">
<p>
Your application needs to install{' '}
Add{' '}
<Link href="https://tailwindcss.com/" underline="always">
tailwindcss
</Link>{' '}
to use this {"package's"} updated components.
to your application&apos;s dependencies.
</p>
<Library.Code
content={`$ yarn add tailwindcss @hypothesis/frontend-shared`}
content={`$ yarn add tailwindcss @tailwindcss/postcss @hypothesis/frontend-shared`}
/>
<p>
Then, in your project&apos;s gulp configuration, pass{' '}
<code>
{'{'} tailwind: true {'}'}
</code>{' '}
to the <code>buildCSS</code> function:
</p>
<Library.Code
content={`import { buildCSS } from '@hypothesis/frontend-build';

gulp.task('build-tailwind-css', () =>
buildCSS(['app.css'], {
tailwind: true,
}),
);`}
/>
</Library.SectionL2>
<Library.SectionL2 title="Configuration">
<Library.SectionL3 title="Configure tailwindcss">
<p>Configure your {"project's"} tailwind configuration object:</p>
<ul>
<li>Use this {"package's"} tailwind preset</li>
<li>
Add this {"package's"} source to the {"configuration's"}{' '}
<code>content</code> globs
</li>
</ul>
<Library.Code
size="sm"
title="Your project's tailwind config"
content={`import tailwindConfig from '@hypothesis/frontend-shared/lib/tailwind.preset.js';
<p>
In your project&apos;s CSS entry point, import the Tailwind theme
from this package:
</p>
<Library.Code
size="sm"
title="Your project's tailwind config"
lang="css"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several changes in other files to support specifying the language, as auto-detection did not work properly.

content={`@import 'tailwindcss' @source(none);

/* Scan the frontend-shared package for used classes. The path is relative to
the location of the CSS file. */
@source 'node_modules/@hypothesis/frontend-shared/lib/**/*.js';

export default {
presets: [tailwindConfig],
content: [
'./node_modules/@hypothesis/frontend-shared/lib/**/*.{js,ts,tsx}',
// ...
],
// ...`}
/>
</Library.SectionL3>
/* Enable the Tailwind theme and additional utilities. */
@import '@hypothesis/frontend-shared/tailwind-config.css';
`}
/>
<p>
See the{' '}
<a href="https://tailwindcss.com/docs/functions-and-directives">
Tailwind documentation
</a>{' '}
for more details on configuration at-rules.
</p>
</Library.SectionL2>
<Library.SectionL2 title="Usage">
<Library.Usage componentName="Card, Link" />
Expand Down
19 changes: 14 additions & 5 deletions src/pattern-library/util/jsx-to-string.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import hljs from 'highlight.js/lib/core';
import hljsCSSLang from 'highlight.js/lib/languages/css';
import hljsTypeScriptLang from 'highlight.js/lib/languages/typescript';
import hljsXMLLang from 'highlight.js/lib/languages/xml';
import { Fragment } from 'preact';
Expand Down Expand Up @@ -155,6 +156,8 @@ export function jsxToString(vnode: ComponentChildren): string {
}
}

export type CodeLanguage = 'css' | 'typescript';

/**
* Render a code snippet as syntax-highlighted HTML markup.
*
Expand All @@ -164,7 +167,7 @@ export function jsxToString(vnode: ComponentChildren): string {
* The content returned by this function is sanitized and safe to use as
* `dangerouslySetInnerHTML` prop.
*/
export function highlightCode(code: string): string {
export function highlightCode(code: string, lang?: CodeLanguage): string {
// JSX support in Highlight.js involves a combination of the TS and XML
// languages, so we need to load both.
if (!hljs.getLanguage('typescript')) {
Expand All @@ -173,8 +176,11 @@ export function highlightCode(code: string): string {
if (!hljs.getLanguage('xml')) {
hljs.registerLanguage('xml', hljsXMLLang);
}

return hljs.highlightAuto(code).value;
if (!hljs.getLanguage('css')) {
hljs.registerLanguage('css', hljsCSSLang);
}
const languages = lang !== undefined ? [lang] : undefined;
return hljs.highlightAuto(code, languages).value;
}

/**
Expand All @@ -183,7 +189,10 @@ export function highlightCode(code: string): string {
* The content returned by this function is sanitized and safe to use as
* `dangerouslySetInnerHTML` prop.
*/
export function jsxToHTML(vnode: ComponentChildren): string {
export function jsxToHTML(
vnode: ComponentChildren,
lang?: CodeLanguage,
): string {
const code = jsxToString(vnode);
return highlightCode(code);
return highlightCode(code, lang);
}
Loading