Skip to content

Commit

Permalink
chore(Portal): allow TypeScript in Examples.tsx files (#2648)
Browse files Browse the repository at this point in the history
The code changes of `react-live` to still support SSR are med
[here](tujoworker/react-live#1).
  • Loading branch information
tujoworker authored Sep 13, 2023
1 parent 82873c7 commit 98aaf3f
Show file tree
Hide file tree
Showing 11 changed files with 1,076 additions and 1,229 deletions.
6 changes: 3 additions & 3 deletions packages/dnb-design-system-portal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
"classnames": "2.3.1",
"history": "5.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-live-ssr": "workspace:*"
"react-dom": "18.2.0"
},
"devDependencies": {
"@babel/core": "7.22.5",
Expand Down Expand Up @@ -109,7 +108,8 @@
"process": "0.11.10",
"prop-types": "15.7.2",
"raw-loader": "4.0.2",
"react-live": "3.1.1",
"react-live": "4.1.3",
"react-live-ssr": "workspace:*",
"react-markdown": "8.0.7",
"remark-gfm": "1.0.0",
"repo-utils": "workspace:*",
Expand Down
45 changes: 45 additions & 0 deletions packages/dnb-design-system-portal/src/e2e/code-block.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test, expect } from '@playwright/test'

test.describe('CodeBlock', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/uilib/components/textarea/demos')

// Check if app is mounted
await page.waitForSelector('#dnb-drawer-list__portal', {
state: 'attached',
})
})

test('should tab to next element except when code change is made', async ({
page,
}) => {
const textareaList = page.locator('textarea')
const preList = page.locator('pre')

// Set our starting point
textareaList.nth(0).focus()

await expect(textareaList.nth(0)).toBeFocused()

await page.keyboard.down('Tab')

await expect(preList.nth(0)).toBeFocused()

await page.keyboard.down('Tab')

await expect(textareaList.nth(1)).toBeFocused()

await page.keyboard.down('Tab')

await expect(preList.nth(1)).toBeFocused()

// Make code change
await page.keyboard.down('Space')

// Try a new tab key down
await page.keyboard.down('Tab')

// Is still in same pre
await expect(preList.nth(1)).toBeFocused()
})
})
28 changes: 23 additions & 5 deletions packages/dnb-design-system-portal/src/shared/tags/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,10 @@ const CodeBlock = ({
)
} else {
return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
<Highlight
{...defaultProps}
code={String(exampleCode).trim()}
language={language}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
theme={prismTheme}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
Expand Down Expand Up @@ -99,6 +95,7 @@ export type LiveCodeProps = {
hideCode?: boolean
hidePreview?: boolean
language?: string
tabMode?: 'focus' | 'indentation'
'data-visual-test'?: string
}

Expand Down Expand Up @@ -126,6 +123,7 @@ class LiveCode extends React.PureComponent<
hideToolbar,
hideCode,
hidePreview,
tabMode: 'focus',
}

this._editorElementRef = React.createRef()
Expand Down Expand Up @@ -160,6 +158,10 @@ class LiveCode extends React.PureComponent<
return code
}

setIndentation(tabMode: LiveCodeProps['tabMode']) {
this.setState({ tabMode })
}

render() {
const {
scope = {},
Expand Down Expand Up @@ -188,7 +190,6 @@ class LiveCode extends React.PureComponent<
return (
<div className={liveCodeEditorStyle}>
<LiveProvider
Prism={Prism}
theme={prismTheme}
code={codeToUse}
scope={scope}
Expand Down Expand Up @@ -217,7 +218,9 @@ class LiveCode extends React.PureComponent<
>
<span className="dnb-sr-only">Code Editor</span>
<LiveEditor
prism={Prism}
id={this._id}
tabMode={this.state.tabMode}
className="dnb-live-editor__editable dnb-pre"
onChange={(code) => {
this.setState({ code })
Expand All @@ -236,6 +239,21 @@ class LiveCode extends React.PureComponent<
)
}
}}
onMouseDown={(e) => {
const focusMode =
document.documentElement.getAttribute('data-whatinput')
this.setIndentation(
focusMode === 'mouse' ? 'indentation' : 'focus',
)
}}
onBlurCapture={() => {
this.setIndentation('focus')
}}
onKeyDown={({ code }) => {
if (code !== 'Tab' && code !== 'ShiftLeft') {
this.setIndentation('indentation')
}
}}
/>
</div>
)}
Expand Down
121 changes: 121 additions & 0 deletions tools/react-live-ssr/dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { Prism, themes } from 'prism-react-renderer';
import * as React$1 from 'react';
import React__default, { CSSProperties, PropsWithChildren, ComponentType } from 'react';

type Props$3 = {
className?: string;
code: string;
disabled?: boolean;
language: string;
prism?: typeof Prism;
style?: CSSProperties;
tabMode?: "focus" | "indentation";
theme?: typeof themes.nightOwl;
onChange?(value: string): void;
editorRef?: React.RefObject<HTMLPreElement>;
} & Omit<React.HTMLAttributes<HTMLPreElement>, "onChange">;
declare const CodeEditor: {
(props: Props$3): JSX.Element;
defaultProps: Pick<Props$3, "tabMode">;
};

type Props$2 = {
code?: string;
disabled?: boolean;
enableTypeScript?: boolean;
language?: string;
noInline?: boolean;
skipInitialRender?: boolean;
scope?: Record<string, unknown>;
theme?: typeof themes.nightOwl;
transformCode?(code: string): string;
};
declare function LiveProvider({ children, code, language, theme, enableTypeScript, disabled, scope, transformCode, noInline, skipInitialRender, }: PropsWithChildren<Props$2>): JSX.Element;

declare function LiveEditor(props: Partial<Props$3>): JSX.Element;

declare function LiveError<T extends Record<string, unknown>>(props: T): JSX.Element | null;

type Props$1<T extends React__default.ElementType = React__default.ElementType> = {
Component?: T;
} & React__default.ComponentPropsWithoutRef<T>;
declare function LivePreview<T extends keyof JSX.IntrinsicElements>(props: Props$1<T>): JSX.Element;
declare function LivePreview<T extends React__default.ElementType>(props: Props$1<T>): JSX.Element;

type ContextValue = {
error?: string;
element?: ComponentType | null;
code: string;
disabled: boolean;
language: string;
theme?: typeof themes.nightOwl;
onError(error: Error): void;
onChange(value: string): void;
};
declare const LiveContext: React$1.Context<ContextValue>;

type Props = {
live: Record<string, unknown>;
};
declare function withLive<T>(WrappedComponent: ComponentType<T & Props>): {
(props: T): JSX.Element;
displayName: string;
};

type GenerateOptions = {
code: string;
scope?: Record<string, unknown>;
enableTypeScript: boolean;
};
declare const generateElement: ({ code, scope, enableTypeScript }: GenerateOptions, errorCallback: (error: Error) => void) => {
new (props: {} | Readonly<{}>): {
componentDidCatch(error: Error): void;
render(): JSX.Element | null;
context: unknown;
setState<K extends never>(state: {} | ((prevState: Readonly<{}>, props: Readonly<{}>) => {} | Pick<{}, K> | null) | Pick<{}, K> | null, callback?: (() => void) | undefined): void;
forceUpdate(callback?: (() => void) | undefined): void;
readonly props: Readonly<{}>;
state: Readonly<{}>;
refs: {
[key: string]: React__default.ReactInstance;
};
componentDidMount?(): void;
shouldComponentUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): boolean;
componentWillUnmount?(): void;
getSnapshotBeforeUpdate?(prevProps: Readonly<{}>, prevState: Readonly<{}>): any;
componentDidUpdate?(prevProps: Readonly<{}>, prevState: Readonly<{}>, snapshot?: any): void;
componentWillMount?(): void;
UNSAFE_componentWillMount?(): void;
componentWillReceiveProps?(nextProps: Readonly<{}>, nextContext: any): void;
UNSAFE_componentWillReceiveProps?(nextProps: Readonly<{}>, nextContext: any): void;
componentWillUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): void;
UNSAFE_componentWillUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): void;
};
new (props: {}, context: any): {
componentDidCatch(error: Error): void;
render(): JSX.Element | null;
context: unknown;
setState<K extends never>(state: {} | ((prevState: Readonly<{}>, props: Readonly<{}>) => {} | Pick<{}, K> | null) | Pick<{}, K> | null, callback?: (() => void) | undefined): void;
forceUpdate(callback?: (() => void) | undefined): void;
readonly props: Readonly<{}>;
state: Readonly<{}>;
refs: {
[key: string]: React__default.ReactInstance;
};
componentDidMount?(): void;
shouldComponentUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): boolean;
componentWillUnmount?(): void;
getSnapshotBeforeUpdate?(prevProps: Readonly<{}>, prevState: Readonly<{}>): any;
componentDidUpdate?(prevProps: Readonly<{}>, prevState: Readonly<{}>, snapshot?: any): void;
componentWillMount?(): void;
UNSAFE_componentWillMount?(): void;
componentWillReceiveProps?(nextProps: Readonly<{}>, nextContext: any): void;
UNSAFE_componentWillReceiveProps?(nextProps: Readonly<{}>, nextContext: any): void;
componentWillUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): void;
UNSAFE_componentWillUpdate?(nextProps: Readonly<{}>, nextState: Readonly<{}>, nextContext: any): void;
};
contextType?: React__default.Context<any> | undefined;
};
declare const renderElementAsync: ({ code, scope, enableTypeScript }: GenerateOptions, resultCallback: (sender: ComponentType) => void, errorCallback: (error: Error) => void) => void;

export { CodeEditor as Editor, LiveContext, LiveEditor, LiveError, LivePreview, LiveProvider, generateElement, renderElementAsync, withLive };
Loading

0 comments on commit 98aaf3f

Please sign in to comment.