// Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import React, { ReactElement } from 'react'; export type TooltipPlacement = | 'top' | 'left' | 'right' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom'; export type PopoverProps = { children: ReactElement; content: ReactElement; arrowPointAtCenter?: boolean; overlayClassName?: string; placement?: TooltipPlacement; }; export const UIPopover: React.ComponentType = function UIPopover(props: PopoverProps) { return ( {(elements: Elements) => { return ; }} ); }; export type TooltipProps = { title: string | ReactElement; getPopupContainer?: (triggerNode: Element) => HTMLElement; overlayClassName?: string; children: ReactElement; placement?: TooltipPlacement; mouseLeaveDelay?: number; arrowPointAtCenter?: boolean; onVisibleChange?: (visible: boolean) => void; }; export const UITooltip: React.ComponentType = function UITooltip(props: TooltipProps) { return ( {(elements: Elements) => { return ; }} ); }; export type IconProps = { type: string; className?: string; onClick?: React.MouseEventHandler; }; export const UIIcon: React.ComponentType = function UIIcon(props: IconProps) { return ( {(elements: Elements) => { return ; }} ); }; export type DropdownProps = { overlay: React.ReactNode; placement?: 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight'; trigger?: Array<'click' | 'hover' | 'contextMenu'>; children?: React.ReactNode; }; export const UIDropdown = function UIDropdown(props: DropdownProps) { return ( {(elements: Elements) => { return ; }} ); }; export type MenuProps = { children?: React.ReactNode; }; export const UIMenu = function UIMenu(props: MenuProps) { return ( {(elements: Elements) => { return ; }} ); }; export type MenuItemProps = { children?: React.ReactNode; }; export const UIMenuItem = function UIMenuItem(props: MenuItemProps) { return ( {(elements: Elements) => { return ; }} ); }; export type ButtonHTMLType = 'submit' | 'button' | 'reset'; export type ButtonProps = { children?: React.ReactNode; className?: string; htmlType?: ButtonHTMLType; icon?: string; onClick?: React.MouseEventHandler; disabled?: boolean; }; export const UIButton = function UIButton(props: ButtonProps) { return ( {(elements: Elements) => { return ; }} ); }; export type DividerProps = { className?: string; type?: 'vertical' | 'horizontal'; }; export const UIDivider = function UIDivider(props: DividerProps) { return ( {(elements: Elements) => { return ; }} ); }; export type InputProps = { autosize?: boolean | null; placeholder?: string; onChange: (value: React.ChangeEvent) => void; suffix: React.ReactNode; value?: string; }; export const UIInput: React.FC = function UIInput(props: InputProps) { return ( {(elements: Elements) => { return ; }} ); }; export type InputGroupProps = { className?: string; compact?: boolean; style?: React.CSSProperties; children?: React.ReactNode; }; export const UIInputGroup = function UIInputGroup(props: InputGroupProps) { return ( {(elements: Elements) => { return ; }} ); }; export type Elements = { Popover: React.ComponentType; Tooltip: React.ComponentType; Icon: React.ComponentType; Dropdown: React.ComponentType; Menu: React.ComponentType; MenuItem: React.ComponentType; Button: React.ComponentType; Divider: React.ComponentType; Input: React.ComponentType; InputGroup: React.ComponentType; }; /** * Allows for injecting custom UI elements that will be used. Mainly for styling and removing dependency on * any specific UI library but can also inject specific behaviour. */ const UIElementsContext = React.createContext(undefined); UIElementsContext.displayName = 'UIElementsContext'; export default UIElementsContext; type GetElementsContextProps = { children: (elements: Elements) => React.ReactNode; }; /** * Convenience render prop style component to handle error state when elements are not defined. */ export function GetElementsContext(props: GetElementsContextProps) { return ( {(value: Elements | undefined) => { if (!value) { throw new Error('Elements context is required. You probably forget to use UIElementsContext.Provider'); } return props.children(value); }} ); }