From edebd04fe147c449a271606148aebc974811e17a Mon Sep 17 00:00:00 2001 From: Nikita Barsukov Date: Mon, 11 Sep 2023 15:36:06 +0300 Subject: [PATCH] chore(react): improve demo example about `elementPredicate` + Cypress tests --- .github/workflows/e2e.yml | 2 +- .../tests/react/element-predicate.cy.ts | 29 +++++++++++++++++++ .../example.component.tsx | 0 .../use-maskito-basic-usage.tsx | 0 .../2-element-predicate/awesome-input.tsx | 19 ++++++++++++ .../2-element-predicate/example.component.tsx | 20 +++++++++++++ .../examples/2-element-predicate/index.tsx | 23 +++++++++++++++ .../react/examples/query-nested-input.md | 18 ------------ .../frameworks/react/react-doc.component.ts | 17 +++++++++-- .../frameworks/react/react-doc.module.ts | 5 ++-- .../frameworks/react/react-doc.template.html | 9 ++++-- 11 files changed, 117 insertions(+), 25 deletions(-) create mode 100644 projects/demo-integrations/cypress/tests/react/element-predicate.cy.ts rename projects/demo/src/pages/frameworks/react/examples/{use-maskito-basic-usage => 1-use-maskito-basic-usage}/example.component.tsx (100%) rename projects/demo/src/pages/frameworks/react/examples/{use-maskito-basic-usage => 1-use-maskito-basic-usage}/use-maskito-basic-usage.tsx (100%) create mode 100644 projects/demo/src/pages/frameworks/react/examples/2-element-predicate/awesome-input.tsx create mode 100644 projects/demo/src/pages/frameworks/react/examples/2-element-predicate/example.component.tsx create mode 100644 projects/demo/src/pages/frameworks/react/examples/2-element-predicate/index.tsx delete mode 100644 projects/demo/src/pages/frameworks/react/examples/query-nested-input.md diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 102bf6d73..de7d0c176 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -112,7 +112,7 @@ jobs: # Replace with npm run cy:run -- --spec "**/!(kit|recipes)/*.cy.ts" --config baseUrl="${{ env.UNIVERSAL_SERVER }}" # After this issue fix: https://github.com/cypress-io/cypress/issues/22407 run: - npm run cy:run -- --spec "**/(angular|ssr|addons|others)/**/*.cy.ts" --config baseUrl="${{ + npm run cy:run -- --spec "**/(angular|react|ssr|addons|others)/**/*.cy.ts" --config baseUrl="${{ env.UNIVERSAL_SERVER }}" concurrency: group: e2e-${{ github.workflow }}-${{ github.ref }} diff --git a/projects/demo-integrations/cypress/tests/react/element-predicate.cy.ts b/projects/demo-integrations/cypress/tests/react/element-predicate.cy.ts new file mode 100644 index 000000000..8b5395fc1 --- /dev/null +++ b/projects/demo-integrations/cypress/tests/react/element-predicate.cy.ts @@ -0,0 +1,29 @@ +import {DemoPath} from '@demo/constants'; + +describe('@maskito/react | Element Predicate', () => { + describe('Sync predicate works', () => { + beforeEach(() => { + cy.visit(DemoPath.React); + cy.get('#awesome-input-wrapper input.real-input') + .scrollIntoView() + .should('be.visible') + .as('input'); + }); + + it('rejects invalid characters', () => { + cy.get('@input').type('abc12def').should('have.value', '12'); + }); + + it('accepts valid input', () => { + cy.get('@input').type('12.09.2023').should('have.value', '12.09.2023'); + }); + + it('automatically adds fixed characters', () => { + cy.get('@input').type('12092023').should('have.value', '12.09.2023'); + }); + + it('automatically pads day / month segments with zeroes for large digits', () => { + cy.get('@input').type('992023').should('have.value', '09.09.2023'); + }); + }); +}); diff --git a/projects/demo/src/pages/frameworks/react/examples/use-maskito-basic-usage/example.component.tsx b/projects/demo/src/pages/frameworks/react/examples/1-use-maskito-basic-usage/example.component.tsx similarity index 100% rename from projects/demo/src/pages/frameworks/react/examples/use-maskito-basic-usage/example.component.tsx rename to projects/demo/src/pages/frameworks/react/examples/1-use-maskito-basic-usage/example.component.tsx diff --git a/projects/demo/src/pages/frameworks/react/examples/use-maskito-basic-usage/use-maskito-basic-usage.tsx b/projects/demo/src/pages/frameworks/react/examples/1-use-maskito-basic-usage/use-maskito-basic-usage.tsx similarity index 100% rename from projects/demo/src/pages/frameworks/react/examples/use-maskito-basic-usage/use-maskito-basic-usage.tsx rename to projects/demo/src/pages/frameworks/react/examples/1-use-maskito-basic-usage/use-maskito-basic-usage.tsx diff --git a/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/awesome-input.tsx b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/awesome-input.tsx new file mode 100644 index 000000000..d7af6fc9b --- /dev/null +++ b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/awesome-input.tsx @@ -0,0 +1,19 @@ +import {forwardRef} from 'react'; + +const hiddenInputStyles = { + display: 'none', +}; + +export const AwesomeInput = forwardRef((props, ref) => ( +
+ + + +
+)); diff --git a/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/example.component.tsx b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/example.component.tsx new file mode 100644 index 000000000..b7a4b2fe4 --- /dev/null +++ b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/example.component.tsx @@ -0,0 +1,20 @@ +import {isPlatformBrowser} from '@angular/common'; +import {Component, ElementRef, Inject, PLATFORM_ID} from '@angular/core'; +import {createRoot} from 'react-dom/client'; + +import {App} from './index'; + +@Component({ + selector: 'react-example-2', + template: '', + host: { + 'comment-for-devtools': 'Everything inside this tag is really rendered by `react-dom` library', + }, +}) +export class ReactExample2 { + constructor(elementRef: ElementRef, @Inject(PLATFORM_ID) platformId: Record) { + if (isPlatformBrowser(platformId)) { + createRoot(elementRef.nativeElement).render(); + } + } +} diff --git a/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/index.tsx b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/index.tsx new file mode 100644 index 000000000..98f6a55a4 --- /dev/null +++ b/projects/demo/src/pages/frameworks/react/examples/2-element-predicate/index.tsx @@ -0,0 +1,23 @@ +// @ts-nocheck React & Vue Global JSX Types Conflicts +import type {MaskitoElementPredicate} from '@maskito/core'; +import {maskitoDateOptionsGenerator} from '@maskito/kit'; +import {useMaskito} from '@maskito/react'; + +import {AwesomeInput} from './awesome-input'; + +const options = maskitoDateOptionsGenerator({ + mode: 'dd/mm/yyyy', +}); + +const elementPredicate: MaskitoElementPredicate = host => host.querySelector('input.real-input')!; + +export const App = () => { + const inputRef = useMaskito({options, elementPredicate}); + + return ( + + ); +}; diff --git a/projects/demo/src/pages/frameworks/react/examples/query-nested-input.md b/projects/demo/src/pages/frameworks/react/examples/query-nested-input.md deleted file mode 100644 index 90b37592f..000000000 --- a/projects/demo/src/pages/frameworks/react/examples/query-nested-input.md +++ /dev/null @@ -1,18 +0,0 @@ -```tsx -import type {MaskitoElementPredicate} from '@maskito/core'; -import {maskitoDateOptionsGenerator} from '@maskito/kit'; -import {useMaskito} from '@maskito/react'; -import {AwesomeInput} from '@awesome-ui-kit/input'; - -const options = maskitoDateOptionsGenerator({ - mode: 'dd/mm/yyyy', -}); - -const predicate: MaskitoElementPredicate = host => host.querySelector('input[id="my-input"]')!; - -const App = () => { - const inputRef = useMaskito({options, predicate}); - - return ; -}; -``` diff --git a/projects/demo/src/pages/frameworks/react/react-doc.component.ts b/projects/demo/src/pages/frameworks/react/react-doc.component.ts index d10f42335..216a57cee 100644 --- a/projects/demo/src/pages/frameworks/react/react-doc.component.ts +++ b/projects/demo/src/pages/frameworks/react/react-doc.component.ts @@ -1,5 +1,8 @@ import {ChangeDetectionStrategy, Component} from '@angular/core'; import {DemoPath} from '@demo/constants'; +import {RawLoaderContent} from '@taiga-ui/addon-doc'; + +const DROP_TS_NO_CHECK_REG = /\/\/\s@ts-nocheck[^\n]+\n/; @Component({ selector: 'react-doc-page', @@ -9,10 +12,20 @@ import {DemoPath} from '@demo/constants'; export class ReactDocPageComponent { readonly coreConceptsOverviewDocPage = `/${DemoPath.CoreConceptsOverview}`; readonly useMaskitoBasicUsage = import( - './examples/use-maskito-basic-usage/use-maskito-basic-usage.tsx?raw' + './examples/1-use-maskito-basic-usage/use-maskito-basic-usage.tsx?raw' ); - readonly queryNestedInputDemo = import('./examples/query-nested-input.md?raw'); + readonly elementPredicateExample: Record = { + 'index.tsx': import('./examples/2-element-predicate/index.tsx?raw').then(m => ({ + // See: https://github.com/vuejs/core/issues/1033#issuecomment-1340309622 + // TODO: Check if it still required after upgrade Vue to 3.4 (https://github.com/vuejs/core/pull/7958) + default: m.default.replace(DROP_TS_NO_CHECK_REG, ''), + })), + 'awesome-input.tsx': import( + './examples/2-element-predicate/awesome-input.tsx?raw' + ), + }; + readonly controlledInputDemo = import('./examples/controlled-input.md?raw'); readonly bestBadPractice = import('./examples/best-bad-practice.md?raw'); } diff --git a/projects/demo/src/pages/frameworks/react/react-doc.module.ts b/projects/demo/src/pages/frameworks/react/react-doc.module.ts index 0e7d07506..7366fb683 100644 --- a/projects/demo/src/pages/frameworks/react/react-doc.module.ts +++ b/projects/demo/src/pages/frameworks/react/react-doc.module.ts @@ -6,7 +6,8 @@ import {MaskitoModule} from '@maskito/angular'; import {TuiAddonDocModule, tuiGenerateRoutes} from '@taiga-ui/addon-doc'; import {TuiLinkModule, TuiNotificationModule} from '@taiga-ui/core'; -import {ReactExample1} from './examples/use-maskito-basic-usage/example.component'; +import {ReactExample1} from './examples/1-use-maskito-basic-usage/example.component'; +import {ReactExample2} from './examples/2-element-predicate/example.component'; import {ReactDocPageComponent} from './react-doc.component'; @NgModule({ @@ -20,7 +21,7 @@ import {ReactDocPageComponent} from './react-doc.component'; TuiNotificationModule, RouterModule.forChild(tuiGenerateRoutes(ReactDocPageComponent)), ], - declarations: [ReactDocPageComponent, ReactExample1], + declarations: [ReactDocPageComponent, ReactExample1, ReactExample2], exports: [ReactDocPageComponent], }) export class ReactDocPageModule {} diff --git a/projects/demo/src/pages/frameworks/react/react-doc.template.html b/projects/demo/src/pages/frameworks/react/react-doc.template.html index 4714ca67b..ed90fc515 100644 --- a/projects/demo/src/pages/frameworks/react/react-doc.template.html +++ b/projects/demo/src/pages/frameworks/react/react-doc.template.html @@ -52,7 +52,7 @@

Query nested input element

Pass a predicate to - elementPredicate + elementPredicate to find input element for you, if you do not have a direct access to it. For example, you use component from some UI Kit library.

@@ -65,7 +65,12 @@

Query nested input element

so that might be sufficient. Use custom predicate if you need custom logic. - + + +