From a9783d6cf7952342cc51b7f324b2536ddc854ab7 Mon Sep 17 00:00:00 2001 From: Mitsuru Ogawa Date: Tue, 25 Aug 2020 00:10:28 +0900 Subject: [PATCH] fix: Wrong union description with TypeScript #1621 (#1629) Fixes #1621 --- examples/sections/styleguide.config.js | 4 +- package-lock.json | 83 ++++++++++++------- package.json | 1 + .../ComplexType/ComplexType.spec.tsx | 20 +++++ .../ComplexType/ComplexTypeRenderder.tsx | 34 ++++++++ .../rsg-components/ComplexType/index.ts | 1 + .../rsg-components/Props/Props.spec.tsx | 42 +++++++--- .../rsg-components/Props/renderType.tsx | 28 ++----- .../rsg-components/Tooltip/Tooltip.spec.tsx | 66 +++++++++++++++ .../Tooltip/TooltipRenderer.tsx | 51 ++++++++++++ src/client/rsg-components/Tooltip/index.ts | 1 + src/typings/dependencies/react-docgen.ts | 1 - 12 files changed, 267 insertions(+), 65 deletions(-) create mode 100644 src/client/rsg-components/ComplexType/ComplexType.spec.tsx create mode 100644 src/client/rsg-components/ComplexType/ComplexTypeRenderder.tsx create mode 100644 src/client/rsg-components/ComplexType/index.ts create mode 100644 src/client/rsg-components/Tooltip/Tooltip.spec.tsx create mode 100644 src/client/rsg-components/Tooltip/TooltipRenderer.tsx create mode 100644 src/client/rsg-components/Tooltip/index.ts diff --git a/examples/sections/styleguide.config.js b/examples/sections/styleguide.config.js index b0deab5ad..3b50a2631 100644 --- a/examples/sections/styleguide.config.js +++ b/examples/sections/styleguide.config.js @@ -93,8 +93,8 @@ module.exports = { env === 'development' ? false : { - maxAssetSize: 1150000, // bytes - maxEntrypointSize: 1150000, // bytes + maxAssetSize: 1200000, // bytes + maxEntrypointSize: 1200000, // bytes hints: 'error', }, }), diff --git a/package-lock.json b/package-lock.json index 02ac41708..676b7c8e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2334,6 +2334,11 @@ } } }, + "@popperjs/core": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.4.tgz", + "integrity": "sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg==" + }, "@samverschueren/stream-to-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", @@ -2504,6 +2509,14 @@ } } }, + "@tippyjs/react": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.1.0.tgz", + "integrity": "sha512-g6Dpm46edr9T9z+BYxd/eJZa6QMFc4T4z5xrztxVlkti7AhNYf7OaE6b3Nh+boUZZ9wn8xkNq9VrQM5K4huwnQ==", + "requires": { + "tippy.js": "^6.2.0" + } + }, "@types/anymatch": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", @@ -3594,7 +3607,7 @@ }, "array-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, @@ -3707,7 +3720,7 @@ }, "util": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -3828,7 +3841,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -3845,7 +3858,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -4428,7 +4441,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -4465,7 +4478,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -4624,7 +4637,7 @@ "dependencies": { "callsites": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true } @@ -4874,7 +4887,7 @@ }, "slice-ansi": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "resolved": "http://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true }, @@ -4891,7 +4904,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -5005,7 +5018,7 @@ }, "colors": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "resolved": "http://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" }, "combined-stream": { @@ -5019,7 +5032,7 @@ }, "commander": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.1.0.tgz", "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" }, "common-dir": { @@ -5595,7 +5608,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -5608,7 +5621,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -5715,7 +5728,7 @@ }, "css-select": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { @@ -5981,7 +5994,7 @@ "dependencies": { "globby": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "requires": { "array-union": "^1.0.1", @@ -5993,7 +6006,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } @@ -6080,7 +6093,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -6208,7 +6221,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, "duplexify": { @@ -7004,7 +7017,7 @@ "dependencies": { "doctrine": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { @@ -9712,7 +9725,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-observable": { @@ -11898,7 +11911,7 @@ }, "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" }, "json-parse-better-errors": { @@ -12487,7 +12500,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -12525,7 +12538,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -13759,7 +13772,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "p-defer": { @@ -13925,7 +13938,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -14890,7 +14903,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -15442,7 +15455,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -15649,7 +15662,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -16568,7 +16581,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-final-newline": { @@ -17046,7 +17059,7 @@ }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -17094,6 +17107,14 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, + "tippy.js": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.2.6.tgz", + "integrity": "sha512-0tTL3WQNT0nWmpslhDryRahoBm6PT9fh1xXyDfOsvZpDzq52by2rF2nvsW0WX2j9nUZP/jSGDqfKJGjCtoGFKg==", + "requires": { + "@popperjs/core": "^2.4.4" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -17125,7 +17146,7 @@ "dependencies": { "ast-types": { "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", + "resolved": "http://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=" }, "esprima": { diff --git a/package.json b/package.json index 3618d025e..006feb8e0 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "node": ">=10" }, "dependencies": { + "@tippyjs/react": "4.1.0", "@vxna/mini-html-webpack-template": "^1.0.0", "acorn": "^6.4.1", "acorn-jsx": "^5.1.0", diff --git a/src/client/rsg-components/ComplexType/ComplexType.spec.tsx b/src/client/rsg-components/ComplexType/ComplexType.spec.tsx new file mode 100644 index 000000000..c51bf06a1 --- /dev/null +++ b/src/client/rsg-components/ComplexType/ComplexType.spec.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import ComplexType from './ComplexTypeRenderder'; + +function renderComponent(name = 'color', raw = 'red | blue') { + return render(); +} + +describe('ComplexType', () => { + test('should render name', () => { + const { getByRole } = renderComponent(); + expect(getByRole('button')).toHaveTextContent('color'); + }); + + test('should render raw text in the tooltip', () => { + const { container, getByRole } = renderComponent(); + fireEvent.focus(getByRole('button')); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('red | blue'); + }); +}); diff --git a/src/client/rsg-components/ComplexType/ComplexTypeRenderder.tsx b/src/client/rsg-components/ComplexType/ComplexTypeRenderder.tsx new file mode 100644 index 000000000..c6f931450 --- /dev/null +++ b/src/client/rsg-components/ComplexType/ComplexTypeRenderder.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import Styled, { JssInjectedProps } from 'rsg-components/Styled'; +import { MdInfoOutline } from 'react-icons/md'; +import Text from 'rsg-components/Text'; +import Tooltip from 'rsg-components/Tooltip'; +import * as Rsg from '../../../typings'; + +export const styles = ({ space }: Rsg.Theme) => ({ + complexType: { + alignItems: 'center', + display: 'inline-flex', + }, + icon: { + marginLeft: space[0], + }, +}); + +export interface ComplexTypeProps extends JssInjectedProps { + name: string; + raw: string; +} + +function ComplexTypeRenderer({ classes, name, raw }: ComplexTypeProps) { + return ( + + + {name} + + + + ); +} + +export default Styled(styles)(ComplexTypeRenderer); diff --git a/src/client/rsg-components/ComplexType/index.ts b/src/client/rsg-components/ComplexType/index.ts new file mode 100644 index 000000000..8710c1335 --- /dev/null +++ b/src/client/rsg-components/ComplexType/index.ts @@ -0,0 +1 @@ +export { default } from 'rsg-components/ComplexType/ComplexTypeRenderder'; diff --git a/src/client/rsg-components/Props/Props.spec.tsx b/src/client/rsg-components/Props/Props.spec.tsx index 83b9d80a9..71517f7b8 100644 --- a/src/client/rsg-components/Props/Props.spec.tsx +++ b/src/client/rsg-components/Props/Props.spec.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/prop-types */ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { parse } from 'react-docgen'; import PropsRenderer, { columns, getRowKey } from './PropsRenderer'; import { unquote, getType, showSpaces, PropDescriptor } from './util'; @@ -513,7 +513,7 @@ describe('props columns', () => { { name: 'Foo', description: 'Converts foo to bar', - type: {type: 'NameExpression', name: 'Array' }, + type: { type: 'NameExpression', name: 'Array' }, }, ], param: [ @@ -551,7 +551,7 @@ describe('props columns', () => { { title: 'Foo', description: 'Returns foo from bar', - type: {type: 'NameExpression', name: 'Array' }, + type: { type: 'NameExpression', name: 'Array' }, }, ], }, @@ -658,21 +658,27 @@ describe('props columns', () => { }); test('should render object type with body in tooltip', () => { - const { getByText } = renderFn(['foo: { bar: string }']); + const { container, getByRole } = renderFn(['foo: { bar: string }']); + fireEvent.focus(getByRole('button')); - expect(getByText('object').title).toMatchInlineSnapshot(`"{ bar: string }"`); + expect(getByRole('button')).toHaveTextContent('object'); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('{ bar: string }'); }); test('should render function type with body in tooltip', () => { - const { getByText } = renderFn(['foo: () => void']); + const { container, getByRole } = renderFn(['foo: () => void']); + fireEvent.focus(getByRole('button')); - expect(getByText('function').title).toMatchInlineSnapshot(`"() => void"`); + expect(getByRole('button')).toHaveTextContent('function'); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('() => void'); }); test('should render union type with body in tooltip', () => { - const { getByText } = renderFn(['foo: "bar" | number']); + const { container, getByRole } = renderFn(['foo: "bar" | number']); + fireEvent.focus(getByRole('button')); - expect(getByText('union').title).toMatchInlineSnapshot(`"\\"bar\\" | number"`); + expect(getByRole('button')).toHaveTextContent('union'); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('"bar" | number'); }); test('should render enum type', () => { @@ -696,9 +702,12 @@ describe('props columns', () => { }); test('should render tuple type with body in tooltip', () => { - const { getByText } = renderFn(['foo: ["bar", number]']); + const { container, getByRole } = renderFn(['foo: ["bar", number]']); - expect(getByText('tuple').title).toMatchInlineSnapshot(`"[\\"bar\\", number]"`); + fireEvent.focus(getByRole('button')); + + expect(getByRole('button')).toHaveTextContent('tuple'); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('["bar", number]'); }); test('should render custom class type', () => { @@ -722,6 +731,17 @@ describe('props columns', () => { Description:" `); }); + + test('should render literal type', () => { + const { container } = renderFn(['foo: 1']); + + expect(getText(container)).toMatchInlineSnapshot(` + "Prop name: foo + Type: 1 + Default: Required + Description:" + `); + }); }); }); diff --git a/src/client/rsg-components/Props/renderType.tsx b/src/client/rsg-components/Props/renderType.tsx index ba36c33e6..44e751545 100644 --- a/src/client/rsg-components/Props/renderType.tsx +++ b/src/client/rsg-components/Props/renderType.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { PropTypeDescriptor } from 'react-docgen'; import Type from 'rsg-components/Type'; -import Text from 'rsg-components/Text'; +import ComplexType from 'rsg-components/ComplexType'; import { getType, PropDescriptor, TypeDescriptor } from './util'; @@ -28,31 +28,19 @@ export function renderType(type: ExtendedPropTypeDescriptor): string { } } -function renderComplexType(name: string, title: string): React.ReactNode { - return ( - - {name} - - ); -} - -function renderAdvancedType(type: TypeDescriptor): React.ReactNode { - if (!type) { - return 'unknown'; - } - +function renderAdvancedType(type: PropTypeDescriptor | TypeDescriptor): React.ReactNode { switch (type.name) { case 'enum': - return type.name; + return {type.name}; case 'literal': - return type.value; + return {type.value}; case 'signature': - return renderComplexType(type.type, type.raw); + return ; case 'union': case 'tuple': - return renderComplexType(type.name, type.raw); + return ; default: - return (type as any).raw || (type as any).name; + return {(type as any).raw || (type as any).name}; } } @@ -62,7 +50,7 @@ export default function renderTypeColumn(prop: PropDescriptor): React.ReactNode return null; } if (prop.flowType || prop.tsType) { - return {renderAdvancedType(type as any)}; + return renderAdvancedType(type); } return {renderType(type)}; } diff --git a/src/client/rsg-components/Tooltip/Tooltip.spec.tsx b/src/client/rsg-components/Tooltip/Tooltip.spec.tsx new file mode 100644 index 000000000..2f92c0e23 --- /dev/null +++ b/src/client/rsg-components/Tooltip/Tooltip.spec.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { render, fireEvent, waitFor } from '@testing-library/react'; +import Tooltip, { TooltipPlacement } from './TooltipRenderer'; + +function renderComponent(content = 'tooltip', placement?: TooltipPlacement) { + return render( + +
+ + ); +} + +describe('Tooltip', () => { + test('should render child component as is', () => { + const { container, getByTestId } = renderComponent(); + expect(container).toContainElement(getByTestId('child')); + }); + + test('should render content in the tooltop body', () => { + const { container, getByRole } = renderComponent(); + fireEvent.focus(getByRole('button')); + expect(container.querySelector('[data-tippy-root]')).toHaveTextContent('tooltip'); + }); + + test('should show the tooltip by focus in', async () => { + const { container, getByRole } = renderComponent(); + fireEvent.focus(getByRole('button')); + await waitFor(() => + expect(container.querySelector('[data-state="visible"]')).toBeInTheDocument() + ); + }); + + test('should show the tooltip by click', async () => { + const { container, getByRole } = renderComponent(); + fireEvent.click(getByRole('button')); + await waitFor(() => + expect(container.querySelector('[data-state="visible"]')).toBeInTheDocument() + ); + }); + + test('should show the tooltip by mouse enter', async () => { + const { container, getByRole } = renderComponent(); + fireEvent.mouseEnter(getByRole('button')); + await waitFor(() => + expect(container.querySelector('[data-state="visible"]')).toBeInTheDocument() + ); + }); + + describe.each([['top'], ['right'], ['left'], ['bottom']])( + 'Test placement attribute', + placement => { + test(`should have ${placement} in data-placement attribute`, async () => { + // @ts-ignore + const { container, getByRole } = renderComponent(undefined, placement); + fireEvent.focus(getByRole('button')); + await waitFor(() => + expect(container.querySelector('[data-state="visible"]')).toBeInTheDocument() + ); + expect(container.querySelector('[data-placement]')).toHaveAttribute( + 'data-placement', + placement + ); + }); + } + ); +}); diff --git a/src/client/rsg-components/Tooltip/TooltipRenderer.tsx b/src/client/rsg-components/Tooltip/TooltipRenderer.tsx new file mode 100644 index 000000000..f7492c01e --- /dev/null +++ b/src/client/rsg-components/Tooltip/TooltipRenderer.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import Tippy from '@tippyjs/react'; +import Styled, { JssInjectedProps } from 'rsg-components/Styled'; +import * as Rsg from '../../../typings'; + +export const styles = ({ space, color, borderRadius, fontSize }: Rsg.Theme) => ({ + tooltip: { + '&.tippy-box': { + transitionProperty: [['opacity']], + '&[data-state="hidden"]': { + opacity: 0, + }, + }, + '& .tippy-content': { + padding: space[0], + border: `1px ${color.border} solid`, + borderRadius, + background: color.baseBackground, + boxShadow: [[0, 2, 4, 'rgba(0,0,0,.15)']], + fontSize: fontSize.small, + color: color.type, + }, + }, +}); + +export type TooltipPlacement = 'top' | 'right' | 'bottom' | 'left'; + +export interface TooltipProps extends JssInjectedProps { + children: React.ReactNode; + content: React.ReactNode; + placement?: TooltipPlacement; +} + +function TooltipRenderer({ classes, children, content, placement = 'top' }: TooltipProps) { + return ( + + + {children} + + + ); +} + +export default Styled(styles)(TooltipRenderer); diff --git a/src/client/rsg-components/Tooltip/index.ts b/src/client/rsg-components/Tooltip/index.ts new file mode 100644 index 000000000..7d61a1a47 --- /dev/null +++ b/src/client/rsg-components/Tooltip/index.ts @@ -0,0 +1 @@ +export { default } from 'rsg-components/Tooltip/TooltipRenderer'; diff --git a/src/typings/dependencies/react-docgen.ts b/src/typings/dependencies/react-docgen.ts index 0e01a0132..f9424b6eb 100644 --- a/src/typings/dependencies/react-docgen.ts +++ b/src/typings/dependencies/react-docgen.ts @@ -58,7 +58,6 @@ declare module 'react-docgen' { | 'objectOf' | 'shape' | 'exact' - | 'union' | 'instanceOf' | 'elementType'; value?: any;