Commit d4e707ac authored by Bernardo Sunderhus's avatar Bernardo Sunderhus

Starting the project

parents
/node_modules/
/dist/
*.log
registry=http://nexus.conexops.com.br/repository/npm/
scope=react-md-extensions
init.author.name = admin
init.author.email = suporte@evologica.com.br
# an email is required to publish npm packages
email=suporte@evologica.com.br
always-auth=true
_auth=YWRtaW46YWRtaW4xMjM=
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import { configure } from '@storybook/react';
// automatically import all files ending in *.stories.js
const req = require.context('../stories', true, /.stories.(js|jsx|ts|tsx)$/);
function loadStories() {
req.keys().forEach((filename) => req(filename));
}
configure(loadStories, module);
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Montserrat|Roboto" rel="stylesheet">
<link rel="stylesheet" href="https://unpkg.com/react-md@1.2.11/dist/react-md.indigo-pink.min.css">
module.exports = (config, configType) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: 'awesome-typescript-loader'
})
config.resolve.extensions.push('.tsx', '.ts')
return config
}
{
"name": "react-md-extensions",
"version": "0.0.1",
"description": "",
"main": "./index.js",
"publishConfig": {
"registry": "http://nexus.conexops.com.br/repository/npm-internal/"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"compile": "npm run clean && tsc -p .",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"clean": "rimraf ./dist",
"lint": "tslint 'src/**/*.ts'",
"release": "npm run lint && npm run compile && npm run copy-package && npm publish ./dist",
"copy-package": "cpy ./package.json ./dist"
},
"author": "Bernardo Sunderhus",
"license": "ISC",
"peerDependencies": {
"react": "^16.2.0",
"react-md": "^1.2.11"
},
"devDependencies": {
"@storybook/addon-actions": "^3.3.13",
"@storybook/addon-links": "^3.3.13",
"@storybook/addons": "^3.3.13",
"@storybook/react": "^3.3.13",
"@types/classnames": "^2.2.3",
"@types/react": "^16.0.38",
"@types/react-dom": "^16.0.4",
"@types/storybook__addon-actions": "^3.0.2",
"@types/storybook__addon-links": "^3.0.3",
"@types/storybook__react": "^3.0.7",
"awesome-typescript-loader": "^3.4.1",
"babel-core": "^6.26.0",
"classnames": "^2.2.5",
"cpy-cli": "^1.0.1",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-md": "^1.2.11",
"rimraf": "^2.6.2",
"tslint": "^5.8.0",
"tslint-config-standard": "^7.0.0",
"tslint-react": "^3.2.0",
"typescript": "^2.7.2"
}
}
import * as React from 'react'
import Checkbox from 'react-md/lib/SelectionControls/Checkbox'
import ListItemControl from 'react-md/lib/Lists/ListItemControl'
export interface CheckboxListItemProps {
id: string
label: string
checked: boolean
onToggleCheck (checked: boolean, event: Event): void
}
export let CheckboxListItem: React.SFC<CheckboxListItemProps> = function CheckboxListItem ({ id, label, checked, onToggleCheck }) {
const checkbox = <Checkbox
id={id}
name='list-item-control'
label={label}
onChange={onToggleCheck}
checked={checked || false}
/>
return <ListItemControl primaryAction={checkbox}/>
}
export * from './CheckboxListItem'
import * as React from 'react'
import { UP, DOWN, ESC, TAB, ZERO, NINE, KEYPAD_ZERO, KEYPAD_NINE } from '../constants/keyCodes'
import { CheckboxListItem } from '../CheckboxListItem'
/** React-md dependencies */
import DropdownMenu, { DropdownMenuProps } from 'react-md/lib/Menus/DropdownMenu'
import TextField, { TextFieldProps, TextFieldLineDirections, TextFieldTypes } from 'react-md/lib/TextFields/TextField'
import { HorizontalAnchors, VerticalAnchors, LayoverPositions, LayoverAnchor } from 'react-md/lib/Helpers/Layover'
export interface MultipleSelectFieldItem {
id: string
label: string
checked?: boolean
}
export interface MultipleSelectFieldState {
checked: {[props: string]: boolean}
inputValue: number | string
}
export interface MultipleSelectFieldWeakProps {
// TextField props
inputId?: string
inputValue?: number | string
inputDefaultValue?: number | string
inputStyle?: React.CSSProperties
inputClassName?: string
inputBlock?: boolean
inputPaddedBlock?: boolean
inputDisabled?: boolean
inputLabel?: React.ReactNode
inputPlaceholder?: string
inputType?: TextFieldTypes
inputActive?: boolean
inputError?: boolean
inputFloating?: boolean
inputRequired?: boolean
inputLineDirection?: TextFieldLineDirections
inputLeftIcon?: React.ReactElement<any>
inputLeftIconStateful?: boolean
inputRightIcon?: React.ReactElement<any>
inputRightIconStateful?: boolean
// inputPasswordIcon?: React.ReactElement<any>
// inputPasswordInitiallyVisible?: boolean
inputFullWidth?: boolean
// inputRows?: number
// inputMaxRows?: number
inputCustomSize?: string
inputErrorText?: React.ReactNode
inputHelpText?: React.ReactNode
inputHelpOnFocus?: boolean
inputMaxLength?: number
inputInlineIndicator?: React.ReactElement<any>
inputMin?: number
inputMax?: number
inputStep?: number
inputPattern?: string
inputResize?: { min: number, max: number, disableShrink?: boolean }
inputTabIndex?: number
// ----------------
// DropDownMenu props
menuId?: string
menuDefaultVisible?: boolean
menuVisible?: boolean
menuCascading?: boolean
menuCascadingAnchor?: { x: HorizontalAnchors, y: VerticalAnchors }
menuCascadingZDepth?: number
menuPosition?: LayoverPositions
menuSimplifiedMenu?: boolean
menuListId?: string
menuListProps?: {}
menuListStyle?: React.CSSProperties
menuListClassName?: string
menuListInline?: boolean
menuListZDepth?: number
menuListHeightRestricted?: boolean
menuStyle?: React.CSSProperties
menuClassName?: string
menuFixedTo?: {} | { x?: {}, y?: {} }
menuBlock?: boolean
menuCentered?: boolean
menuFullWidth?: boolean
menuSameWidth?: boolean
menuXThreshold?: number
menuYThreshold?: number
menuTransitionName?: string
menuTransitionEnterTimeout?: number
menuTransitionLeaveTimeout?: number
menuCloseOnOutsideClick?: boolean
menuAnchor?: LayoverAnchor
menuBelowAnchor?: LayoverAnchor
menuRepositionOnScroll?: boolean
menuRepositionOnResize?: boolean
menuMinLeft?: number | string
menuMinRight?: number | string
menuMinBottom?: number | string
menuFillViewportHeight?: boolean
menuFillViewportWidth?: boolean
// ------------------
menuItems?: MultipleSelectFieldItem[]
id?: string
block?: boolean
fullWidth?: boolean
className?: string
style?: React.CSSProperties
filter?: null | ((data: MultipleSelectFieldItem[], filterText: string | number) => MultipleSelectFieldItem[])
// TextField methods
onInputChange? (value: number | string, event: Event): void
onInputDoubleClick? (event: React.MouseEvent<HTMLElement>): void
onInputPaste? (event: React.ClipboardEvent<HTMLElement>): void
// ----------------
// DropwDownMenu methods
onMenuVisibilityChange? (visible: boolean, e: React.MouseEvent<HTMLElement>): void
// ---------------------
onToggleCheck? (checked: boolean, id: string): void
}
export interface MultipleSelectFieldProps extends MultipleSelectFieldWeakProps {
menutItems: MultipleSelectField[]
}
function getInputProps (props: MultipleSelectFieldWeakProps): TextFieldProps {
return {
id: props.inputId,
value: props.inputValue,
defaultValue: props.inputDefaultValue,
style: props.inputStyle,
inputClassName: props.inputClassName,
block: props.inputBlock,
paddedBlock: props.inputPaddedBlock,
disabled: props.inputDisabled,
label: props.inputLabel,
placeholder: props.inputPlaceholder,
type: props.inputType,
active: props.inputActive,
error: props.inputError,
floating: props.inputFloating,
required: props.inputRequired,
lineDirection: props.inputLineDirection,
leftIcon: props.inputLeftIcon,
leftIconStateful: props.inputLeftIconStateful,
rightIcon: props.inputRightIcon,
rightIconStateful: props.inputRightIconStateful,
// PasswordIcon: props.inputPasswordIcon,
// PasswordInitiallyVisible: props.inputPasswordInitiallyVisible,
fullWidth: props.inputFullWidth,
// Rows: props.inputRows,
// MaxRows: props.inputMaxRows,
customSize: props.inputCustomSize,
errorText: props.inputErrorText,
helpText: props.inputHelpText,
helpOnFocus: props.inputHelpOnFocus,
maxLength: props.inputMaxLength,
inlineIndicator: props.inputInlineIndicator,
min: props.inputMin,
max: props.inputMax,
step: props.inputStep,
pattern: props.inputPattern,
resize: props.inputResize,
tabIndex: props.inputTabIndex,
onChange: props.onInputChange,
onDoubleClick: props.onInputDoubleClick,
onPaste: props.onInputPaste
}
}
function getMenuProps (props: MultipleSelectFieldWeakProps): DropdownMenuProps {
return {
id: props.menuId,
defaultVisible: props.menuDefaultVisible,
visible: props.menuVisible,
cascading: props.menuCascading,
cascadingAnchor: props.menuCascadingAnchor,
cascadingZDepth: props.menuCascadingZDepth,
position: props.menuPosition,
simplifiedMenu: props.menuSimplifiedMenu,
listId: props.menuListId,
listProps: props.menuListProps,
listStyle: props.menuListStyle,
listClassName: props.menuListClassName,
listInline: props.menuListInline,
listZDepth: props.menuListZDepth,
listHeightRestricted: props.menuListHeightRestricted,
style: props.menuStyle,
className: props.menuClassName,
fixedTo: props.menuFixedTo,
block: props.menuBlock,
centered: props.menuCentered,
fullWidth: props.menuFullWidth,
sameWidth: props.menuSameWidth,
xThreshold: props.menuXThreshold,
yThreshold: props.menuYThreshold,
transitionName: props.menuTransitionName,
transitionEnterTimeout: props.menuTransitionEnterTimeout,
transitionLeaveTimeout: props.menuTransitionLeaveTimeout,
closeOnOutsideClick: props.menuCloseOnOutsideClick,
anchor: props.menuAnchor,
belowAnchor: props.menuBelowAnchor,
repositionOnScroll: props.menuRepositionOnScroll,
repositionOnResize: props.menuRepositionOnResize,
minLeft: props.menuMinLeft,
minRight: props.menuMinRight,
minBottom: props.menuMinBottom,
fillViewportHeight: props.menuFillViewportHeight,
fillViewportWidth: props.menuFillViewportWidth,
onVisibilityChange: props.onMenuVisibilityChange
}
}
let counter = 1
export class MultipleSelectField extends React.PureComponent<MultipleSelectFieldProps, MultipleSelectFieldState> {
static Positions = DropdownMenu.Positions
static VerticalAnchors = DropdownMenu.VerticalAnchors
static HorizontalAnchors = DropdownMenu.HorizontalAnchors
public state: MultipleSelectFieldState = { checked: {}, inputValue: this.props.inputValue || this.props.inputDefaultValue }
private _count: number
constructor (props: MultipleSelectFieldProps) {
super(props)
this._handleToggleCheck = this._handleToggleCheck.bind(this)
this._handleInputChange = this._handleInputChange.bind(this)
this._count = counter++
}
render () {
const menuProps = getMenuProps(this.props)
const inputProps = getInputProps(this.props)
const {
menuItems,
id,
block,
fullWidth,
className,
style,
filter
} = this.props
const { checked, inputValue } = this.state
const items = this._filter(menuItems, inputValue).map((item, index) => <CheckboxListItem
id={String(index)}
key={item.id}
label={item.label}
checked={item.checked || checked[index]}
onToggleCheck={this._handleToggleCheck}
/>)
return <DropdownMenu
{...menuProps}
id={this._menuId}
menuItems={items}
className={className}
style={style}
>
<TextField
{...inputProps}
onChange={this._handleInputChange}
id={this._inputId}
/>
</DropdownMenu>
}
private get _menuId () {
return this.props.menuId || this.props.id ? `${this.props.id}-menu` : `multiple-select-field-menu-${this._count}`
}
private get _inputId () {
return this.props.inputId || this.props.id ? `${this.props.id}-input` : `multiple-select-field-input-${this._count}`
}
private _filter (data: MultipleSelectFieldItem[], filterText: string | number) {
if (this.props.filter) return this.props.filter(data, filterText)
return data
}
private _handleInputChange (inputValue: string, e: Event) {
this.setState({ inputValue })
if (this.props.onInputChange) this.props.onInputChange(inputValue, e)
}
private _handleToggleCheck (checked: boolean, event: Event) {
const element = event.currentTarget as HTMLInputElement
if (this.props.menuItems[element.id].checked === undefined) {
this.setState(state => ({
checked: { ...state.checked, [element.id]: checked }
}))
}
this.props.onToggleCheck(checked, this.props.menuItems[element.id].id)
}
}
export * from './MultipleSelectField'
export { MultipleSelectField as default } from './MultipleSelectField'
export * from './keyCodes'
export const LEFT_MOUSE = 0
export const RIGHT_MOUSE = 2
export const TAB = 9
export const ENTER = 13
export const ESC = 27
export const SPACE = 32
export const PAGE_UP = 33
export const PAGE_DOWN = 34
export const END = 35
export const HOME = 36
export const LEFT = 37
export const UP = 38
export const RIGHT = 39
export const DOWN = 40
export const ZERO = 48
export const NINE = 57
export const KEYPAD_ZERO = 96
export const KEYPAD_NINE = 105
export * from './CheckboxListItem'
export * from './MultipleSelectField'
export * from './constants'
import * as React from 'react'
import * as cn from 'classnames'
import { storiesOf, StoryDecorator } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import { linkTo } from '@storybook/addon-links'
import { MultipleSelectField, MultipleSelectFieldWeakProps, MultipleSelectFieldItem } from '../src/MultipleSelectField'
const items = [
{ label: 'item 1', id: '1' },
{ label: 'item 2', id: '2' },
{ label: 'item 3', id: '3' },
{ label: 'item 4', id: '4' },
{ label: 'item 5', id: '5' },
{ label: 'item 6', id: '6' }
]
const CenterDecorator: StoryDecorator = (storyFn) => <div className='md-grid'>{storyFn()}</div>
const DefaultMultipleSelectField = (props: MultipleSelectFieldWeakProps) => <MultipleSelectField
{...props as any}
menuItems={items}
onToggleCheck={action('checkbox toggled')}
className={cn('md-cell', props.className)}
/>
storiesOf('MultipleSelectField', module)
.addDecorator(CenterDecorator)
.add('default', () => <DefaultMultipleSelectField/>)
.add('default visible', () => <DefaultMultipleSelectField menuDefaultVisible/>)
.add('default input', () => <DefaultMultipleSelectField inputDefaultValue='item 1'/>)
.add('menu positioned', () => <DefaultMultipleSelectField
className='md-cell--2'
menuDefaultVisible
menuAnchor={{
x: MultipleSelectField.HorizontalAnchors.INNER_LEFT,
y: MultipleSelectField.VerticalAnchors.BOTTOM
}}
menuPosition={MultipleSelectField.Positions.BELOW}
/>)
{
"compilerOptions": {
"outDir": "./dist",
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": true,
"declaration": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"suppressImplicitAnyIndexErrors": true,
"moduleResolution": "node",
"target": "es5",
"module": "commonjs",
"lib": ["es5", "es6", "dom"],
"jsx": "react"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
]
}
{
"extends": ["tslint-config-standard", "tslint-react"],
"rules": {
"await-promise": [true, "Thenable"],
"no-use-before-declare": true,
"return-undefined": true,
"no-floating-promises": true,
"no-unnecessary-qualifier": true,
"no-unnecessary-type-assertion": true,
"strict-type-predicates": true,
"jsx-wrap-multiline": false,
"jsx-no-lambda": false,
"jsx-boolean-value": false,
"jsx-no-multiline-js": false
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment