-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
48 changed files
with
2,058 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export { angularOutputTarget } from './plugin' | ||
export type { OutputTargetAngular, ValueAccessorConfig } from './types' | ||
export { angularOutputTarget } from './lib/plugin' | ||
export type { OutputTargetAngular, ValueAccessorConfig } from './lib/types' |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
libs/output-target-react/react-component-lib/createComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* eslint-disable @typescript-eslint/ban-types */ | ||
import React, { createElement, Fragment } from 'react' | ||
|
||
import { attachProps, createForwardRef, dashToPascalCase, isCoveredByReact, mergeRefs } from './utils' | ||
|
||
export interface HTMLStencilElement extends HTMLElement { | ||
componentOnReady(): Promise<this> | ||
} | ||
|
||
interface StencilReactInternalProps<ElementType> extends React.HTMLAttributes<ElementType> { | ||
forwardedRef: React.RefObject<ElementType> | ||
ref?: React.Ref<any> | ||
} | ||
|
||
export const createReactComponent = < | ||
PropType, | ||
ElementType extends HTMLStencilElement, | ||
ContextStateType = {}, | ||
ExpandedPropsTypes = {}, | ||
>( | ||
tagName: string, | ||
ReactComponentContext?: React.Context<ContextStateType>, | ||
manipulatePropsFunction?: ( | ||
originalProps: StencilReactInternalProps<ElementType>, | ||
propsToPass: any, | ||
) => ExpandedPropsTypes, | ||
defineCustomElement?: () => void, | ||
) => { | ||
if (defineCustomElement !== undefined) { | ||
defineCustomElement() | ||
} | ||
|
||
const displayName = dashToPascalCase(tagName) | ||
const ReactComponent = class extends React.Component<StencilReactInternalProps<ElementType>> { | ||
componentEl!: ElementType | ||
|
||
setComponentElRef = (element: ElementType) => { | ||
this.componentEl = element | ||
} | ||
|
||
constructor(props: StencilReactInternalProps<ElementType>) { | ||
super(props) | ||
} | ||
|
||
componentDidMount() { | ||
this.componentDidUpdate(this.props) | ||
} | ||
|
||
componentDidUpdate(prevProps: StencilReactInternalProps<ElementType>) { | ||
attachProps(this.componentEl, this.props, prevProps) | ||
} | ||
|
||
render() { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars | ||
const { children, forwardedRef, style, className, ref, ...cProps } = this.props | ||
|
||
let propsToPass: any = Object.keys(cProps).reduce((acc, name) => { | ||
if (name.indexOf('on') === 0 && name[2] === name[2].toUpperCase()) { | ||
const eventName = name.substring(2).toLowerCase() | ||
if (typeof document !== 'undefined' && isCoveredByReact(eventName)) { | ||
(acc as any)[name] = (cProps as any)[name] | ||
} | ||
} else { | ||
(acc as any)[name] = (cProps as any)[name] | ||
} | ||
return acc | ||
}, {}) | ||
|
||
if (manipulatePropsFunction) { | ||
propsToPass = manipulatePropsFunction(this.props, propsToPass) | ||
} | ||
|
||
const newProps: Omit<StencilReactInternalProps<ElementType>, 'forwardedRef'> = { | ||
...propsToPass, | ||
ref: mergeRefs(forwardedRef, this.setComponentElRef), | ||
style, | ||
} | ||
|
||
/** | ||
* We use createElement here instead of | ||
* React.createElement to work around a | ||
* bug in Vite (https://github.com/vitejs/vite/issues/6104). | ||
* React.createElement causes all elements to be rendered | ||
* as <tagname> instead of the actual Web Component. | ||
*/ | ||
const areChildrenEmpty = children === '' || children === undefined || children === null | ||
const fragment = !areChildrenEmpty ? createElement(Fragment, {}, children) : createElement(Fragment, {}, ' ') | ||
const component = createElement(tagName, newProps, fragment) | ||
return component | ||
} | ||
|
||
static get displayName() { | ||
return displayName | ||
} | ||
} | ||
|
||
// If context was passed to createReactComponent then conditionally add it to the Component Class | ||
if (ReactComponentContext) { | ||
ReactComponent.contextType = ReactComponentContext | ||
} | ||
|
||
return createForwardRef<PropType, ElementType>(ReactComponent, displayName) | ||
} |
143 changes: 143 additions & 0 deletions
143
libs/output-target-react/react-component-lib/createOverlayComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import React from 'react' | ||
import ReactDOM from 'react-dom' | ||
|
||
import { OverlayEventDetail } from './interfaces' | ||
import { StencilReactForwardedRef, attachProps, dashToPascalCase, defineCustomElement, setRef } from './utils' | ||
|
||
interface OverlayElement extends HTMLElement { | ||
present: () => Promise<void> | ||
dismiss: (data?: any, role?: string | undefined) => Promise<boolean> | ||
} | ||
|
||
export interface ReactOverlayProps { | ||
children?: React.ReactNode | ||
isOpen: boolean | ||
onDidDismiss?: (event: CustomEvent<OverlayEventDetail>) => void | ||
onDidPresent?: (event: CustomEvent<OverlayEventDetail>) => void | ||
onWillDismiss?: (event: CustomEvent<OverlayEventDetail>) => void | ||
onWillPresent?: (event: CustomEvent<OverlayEventDetail>) => void | ||
} | ||
|
||
export const createOverlayComponent = <OverlayComponent extends object, OverlayType extends OverlayElement>( | ||
tagName: string, | ||
controller: { create: (options: any) => Promise<OverlayType> }, | ||
customElement?: any, | ||
) => { | ||
defineCustomElement(tagName, customElement) | ||
|
||
const displayName = dashToPascalCase(tagName) | ||
const didDismissEventName = `on${displayName}DidDismiss` | ||
const didPresentEventName = `on${displayName}DidPresent` | ||
const willDismissEventName = `on${displayName}WillDismiss` | ||
const willPresentEventName = `on${displayName}WillPresent` | ||
|
||
type Props = OverlayComponent & | ||
ReactOverlayProps & { | ||
forwardedRef?: StencilReactForwardedRef<OverlayType> | ||
} | ||
|
||
let isDismissing = false | ||
|
||
class Overlay extends React.Component<Props> { | ||
overlay?: OverlayType | ||
el!: HTMLDivElement | ||
|
||
constructor(props: Props) { | ||
super(props) | ||
if (typeof document !== 'undefined') { | ||
this.el = document.createElement('div') | ||
} | ||
this.handleDismiss = this.handleDismiss.bind(this) | ||
} | ||
|
||
static get displayName() { | ||
return displayName | ||
} | ||
|
||
componentDidMount() { | ||
if (this.props.isOpen) { | ||
this.present() | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
if (this.overlay) { | ||
this.overlay.dismiss() | ||
} | ||
} | ||
|
||
handleDismiss(event: CustomEvent<OverlayEventDetail<any>>) { | ||
if (this.props.onDidDismiss) { | ||
this.props.onDidDismiss(event) | ||
} | ||
setRef(this.props.forwardedRef, null) | ||
} | ||
|
||
shouldComponentUpdate(nextProps: Props) { | ||
// Check if the overlay component is about to dismiss | ||
if (this.overlay && nextProps.isOpen !== this.props.isOpen && nextProps.isOpen === false) { | ||
isDismissing = true | ||
} | ||
|
||
return true | ||
} | ||
|
||
async componentDidUpdate(prevProps: Props) { | ||
if (this.overlay) { | ||
attachProps(this.overlay, this.props, prevProps) | ||
} | ||
|
||
if (prevProps.isOpen !== this.props.isOpen && this.props.isOpen === true) { | ||
this.present(prevProps) | ||
} | ||
if (this.overlay && prevProps.isOpen !== this.props.isOpen && this.props.isOpen === false) { | ||
await this.overlay.dismiss() | ||
isDismissing = false | ||
|
||
/** | ||
* Now that the overlay is dismissed | ||
* we need to render again so that any | ||
* inner components will be unmounted | ||
*/ | ||
this.forceUpdate() | ||
} | ||
} | ||
|
||
async present(prevProps?: Props) { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars | ||
const { children, isOpen, onDidDismiss, onDidPresent, onWillDismiss, onWillPresent, ...cProps } = this.props | ||
const elementProps = { | ||
...cProps, | ||
ref: this.props.forwardedRef, | ||
[didDismissEventName]: this.handleDismiss, | ||
[didPresentEventName]: (e: CustomEvent) => this.props.onDidPresent && this.props.onDidPresent(e), | ||
[willDismissEventName]: (e: CustomEvent) => this.props.onWillDismiss && this.props.onWillDismiss(e), | ||
[willPresentEventName]: (e: CustomEvent) => this.props.onWillPresent && this.props.onWillPresent(e), | ||
} | ||
|
||
this.overlay = await controller.create({ | ||
...elementProps, | ||
component: this.el, | ||
componentProps: {}, | ||
}) | ||
|
||
setRef(this.props.forwardedRef, this.overlay) | ||
attachProps(this.overlay, elementProps, prevProps) | ||
|
||
await this.overlay.present() | ||
} | ||
|
||
render() { | ||
/** | ||
* Continue to render the component even when | ||
* overlay is dismissing otherwise component | ||
* will be hidden before animation is done. | ||
*/ | ||
return ReactDOM.createPortal(this.props.isOpen || isDismissing ? this.props.children : null, this.el) | ||
} | ||
} | ||
|
||
return React.forwardRef<OverlayType, Props>((props, ref) => { | ||
return <Overlay {...props} forwardedRef={ref} /> | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { createReactComponent } from './createComponent' | ||
export { createOverlayComponent } from './createOverlayComponent' |
34 changes: 34 additions & 0 deletions
34
libs/output-target-react/react-component-lib/interfaces.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// General types important to applications using stencil built components | ||
export interface EventEmitter<T = any> { | ||
emit: (data?: T) => CustomEvent<T> | ||
} | ||
|
||
export interface StyleReactProps { | ||
class?: string | ||
className?: string | ||
style?: { [key: string]: any } | ||
} | ||
|
||
export interface OverlayEventDetail<T = any> { | ||
data?: T | ||
role?: string | ||
} | ||
|
||
export interface OverlayInterface { | ||
el: HTMLElement | ||
animated: boolean | ||
keyboardClose: boolean | ||
overlayIndex: number | ||
presented: boolean | ||
|
||
enterAnimation?: any | ||
leaveAnimation?: any | ||
|
||
didPresent: EventEmitter<void> | ||
willPresent: EventEmitter<void> | ||
willDismiss: EventEmitter<OverlayEventDetail> | ||
didDismiss: EventEmitter<OverlayEventDetail> | ||
|
||
present(): Promise<void> | ||
dismiss(data?: any, role?: string): Promise<boolean> | ||
} |
Oops, something went wrong.