Commit af1916a2 authored by Guilherme Gazzo's avatar Guilherme Gazzo Committed by Tasso Evangelista
Browse files

feat: Position, Modal, Options components (#116)



* first commit position

* option scroll auto

* fix options

* update loki

* Update packages/fuselage/src/components/Box/Position/index.js
Co-Authored-By: default avatarTasso Evangelista <tasso.evangelista@rocket.chat>

* Update index.js

* position

* wip modal

* Modal

* feat: Modal (#117)

* fix modal

* Modal, uikit overflow

* update loki

* test

* finish

* sad

* fix context component

* fiz text

* more parsers

* improve modal scrolling

* Update packages/fuselage-ui-kit/src/Actions.js
Co-Authored-By: default avatarTasso Evangelista <tasso.evangelista@rocket.chat>

* Update AutoComplete stories

* fix scroll by keyboard

* update references

* Add missing loki stories

* Refactor Modal

* Fix some Modal props and docs

* update references

* Refactor Modal.Stack

* Disable animations when running Loki

* Refactor AnimatedVisibility

* Refactor Flex

* Refactor Margins

* fix position

* fix margins

* Use classes on Flex

* Format JSX

* fix animated class

* loki update

* Add Scrollable stories

* Remove Position stories

* Remove unused Loki references
Co-authored-by: default avatarTasso Evangelista <tassoevan7@gmail.com>
parent 5a9aa820
This diff is collapsed.
import React, { useState } from 'react';
import {
Button,
Grid,
Margins,
Flex,
Box,
} from '@rocket.chat/fuselage';
......@@ -16,7 +16,7 @@ const getStyle = ({ type }) => {
case 'button':// ELEMENT_TYPES.BUTTON :
return 'auto';
default:
return '50%';
return '45%';
}
};
......@@ -27,7 +27,7 @@ export const Actions = ({ blockId, appId, elements, parser }) => {
const renderedElements = (showMoreVisible
? elements.slice(0, 5)
: elements
).map((element) => <Flex.Item basis={getStyle(element)}>{parser.renderActions({ blockId, appId, ...element }, BLOCK_CONTEXT.ACTION, parser)}</Flex.Item>);
).map((element, i) => <Margins key={i} all={8}><Flex.Item basis={getStyle(element)}>{parser.renderActions({ blockId, appId, ...element }, BLOCK_CONTEXT.ACTION, parser)}</Flex.Item></Margins>);
const handleShowMoreClick = () => {
setShowMoreVisible(false);
......@@ -35,12 +35,14 @@ export const Actions = ({ blockId, appId, elements, parser }) => {
return (
<Block>
<Flex.Container wrap='wrap'>
<Box>
{renderedElements}
{showMoreVisible && (<Flex.Item><Button onClick={handleShowMoreClick}>Show more...</Button></Flex.Item>)}
</Box>
</Flex.Container>
<Margins all='neg-x8'>
<Flex.Container wrap='wrap'>
<Box>
{renderedElements}
{showMoreVisible && (<Flex.Item><Button onClick={handleShowMoreClick}>Show more...</Button></Flex.Item>)}
</Box>
</Flex.Container>
</Margins>
</Block>
);
};
......@@ -4,5 +4,5 @@ import {
} from '@rocket.chat/fuselage';
export const Block = ({ children }) => (
<Margins blockEnd={4}>{children}</Margins>
<Margins blockEnd={16}>{children}</Margins>
);
import React from 'react';
import {
Modal,
ButtonGroup,
Button,
AnimatedVisibility,
} from '@rocket.chat/fuselage';
const thumb = 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==';
export const Demo = ({ children, visible }) => <AnimatedVisibility visibility={visible}><Modal open={visible}>
<Modal.Header><Modal.Thumb url={thumb}/> <Modal.Title>Modal Header</Modal.Title><Modal.Close/></Modal.Header>
<Modal.Content>{children}</Modal.Content>
<Modal.Footer>
<ButtonGroup align='end'>
<Button>Cancel</Button>
<Button primary>Submit</Button>
</ButtonGroup>
</Modal.Footer>
</Modal></AnimatedVisibility>;
......@@ -95,4 +95,4 @@ const genericImage = (element, context) => {
export const ModalImage = ({ element, context }) => genericImage(element, context) || <Block><Flex.Container justifyContent='center'><Box><Media element={element}/></Box></Flex.Container></Block>;
export const MessageImage = ({ element, context }) => genericImage(element, context) || <Block><Flex.Container justifyContent='flex-start'><Box><Media element={element}/></Box></Flex.Container></Block>;
export const MessageImage = ({ element, context }) => genericImage(element, context) || <Block><Flex.Container justifyContent='start'><Box><Media element={element}/></Box></Flex.Container></Block>;
import React from 'react';
import {
Label,
Field,
FieldGroup,
} from '@rocket.chat/fuselage';
......@@ -10,12 +9,14 @@ import {
import { Block } from './Block';
export const Input = ({ label, element, parser }) => (
export const Input = ({ label, element, parser, index }) => (
<Block>
<FieldGroup>
<Field>
{label && <Label text={label} />}
{parser.renderInputs(element, BLOCK_CONTEXT.FORM, parser)}
{label && <Field.Label>{label}</Field.Label>}
{
parser.renderInputs(element, BLOCK_CONTEXT.FORM, parser, index)
}
</Field>
</FieldGroup>
</Block>
......
import React, { useRef } from 'react';
import {
AnimatedVisibility,
Button,
PositionAnimated,
Options,
Icon,
useCursor,
} from '@rocket.chat/fuselage';
const convertOptions = (options, parser) => options.map(({ text, value }) => [value, parser(text)]);
export const Overflow = ({ options, parser, onChange = console.log }) => {
const handleSelection = ([value]) => onChange({ target: { value } });
const convertedOptions = convertOptions(options, parser.text);
const [cursor, handleKeyDown, handleKeyUp, , [visible, hide, show]] = useCursor(-1, convertedOptions, (args, [, hide]) => {
handleSelection(args);
hide();
});
const ref = useRef();
return (
<>
<Button
ref={ref}
small
ghost onClick={show}
onBlur={hide}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
>
<Icon name='menu' size={20} />
</Button>
<PositionAnimated
width='auto'
visible={visible ? AnimatedVisibility.VISIBLE : AnimatedVisibility.HIDDEN}
anchor={ref}
placement='bottom right'
>
<Options
onSelect={handleSelection}
options={convertOptions(options, parser.text)}
cursor={cursor}
/>
</PositionAnimated>
</>
);
};
......@@ -7,9 +7,111 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
# UI Kit Message
<Preview>
<Story name='Section Standard'>
{
UiKitMessage([{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "I am an item"
}
}])
}
}/>
</Story>
</Preview>
<Preview>
<Story name='Section Fields'>
{ UiKitMessage([
{
"type": "section",
"fields": [
{
"type": "plain_text",
"text": "field 1",
"emoji": true
},
{
"type": "plain_text",
"text": "field 2",
"emoji": true
},
{
"type": "plain_text",
"text": "field 3",
"emoji": true
},
{
"type": "plain_text",
"text": "field 4",
"emoji": true
},
{
"type": "plain_text",
"text": "field 5",
"emoji": true
}
]
}
])}
</Story>
</Preview>
<Preview>
<Story name='Divider'>
{
UiKitMessage([{
"type": "divider"
}])
}
}/>
</Story>
</Preview>
<Preview>
<Story name='Context Standard'>
{UiKitMessage([{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": "I am an item"
}
]
}])}
</Story>
</Preview>
<Preview>
<Story name='Context Standard + icon'>
{UiKitMessage([{
"type": "context",
"elements": [{
"type": "image",
"title": {
"type": "plain_text",
"text": "Example Image",
"emoji": true
},
"imageUrl": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png",
"altText": "Example Image"
},
{
"type": "mrkdwn",
"text": "I am an item"
}
]
}])}
</Story>
</Preview>
<Preview>
<Story name='Section + image'>
<UiKitMessage blocks={[{
{
UiKitMessage([{
"type": "section",
"text": {
"type": "mrkdwn",
......@@ -20,7 +122,8 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
"imageUrl": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png",
"altText": "plants"
}
}]
}])
}
}/>
</Story>
</Preview>
......@@ -28,57 +131,111 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
<Preview>
<Story name='Section + button'>
<UiKitMessage blocks={[{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Section + button"
},
"accessory": {
"type": "button",
"text": {
{
UiKitMessage([{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "button"
"text": "Section + button"
},
}
}]
}/>
"accessory": {
"type": "button",
"text": {
"type": "mrkdwn",
"text": "button"
},
}
}]
)}
</Story>
</Preview>
<Preview>
<Story name='Section + Select'>
<UiKitMessage blocks={[{
<Story name='Section + overflow'>
{UiKitMessage([
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Section + select"
"text": "This block has an overflow menu."
},
"accessory": {
"type": "static_select",
"options": [
{
value: 1,
"text": {
"type": "mrkdwn",
"text": "button"
}
},{
value: 2,
"text": {
"type": "mrkdwn",
"text": "second button"
}
}],
"type": "overflow",
"options": [
{
"text": {
"type": "plain_text",
"text": "Option 1",
"emoji": true
},
"value": "value-0"
},
{
"text": {
"type": "plain_text",
"text": "Option 2",
"emoji": true
},
"value": "value-1"
},
{
"text": {
"type": "plain_text",
"text": "Option 3",
"emoji": true
},
"value": "value-2"
},
{
"text": {
"type": "plain_text",
"text": "Option 4",
"emoji": true
},
"value": "value-3"
}
]
}
}]
}/>
}
])}
</Story>
</Preview>
<Preview>
<Story name='Section + Select'>
{
UiKitMessage([{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Section + select"
},
"accessory": {
"type": "static_select",
"options": [
{
value: 1,
"text": {
"type": "mrkdwn",
"text": "button"
}
},{
value: 2,
"text": {
"type": "mrkdwn",
"text": "second button"
}
}],
}
}]
)}
</Story>
</Preview>
<Preview>
<Story name='Section + Multi Select'>
<UiKitMessage blocks={[{
{UiKitMessage([{
"type": "section",
"text": {
"type": "mrkdwn",
......@@ -112,32 +269,13 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
value: 4
}],
}
}]
}/>
}])}
</Story>
</Preview>
<Preview>
<Story name='Image'>
<UiKitMessage blocks={[{
"type": "image",
"title": {
"type": "plain_text",
"text": "Example Image",
"emoji": true
},
"imageUrl": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png",
"altText": "Example Image"
}]
}/>
</Story>
</Preview>
<Preview>
<Story name='Context'>
<UiKitMessage blocks={[{
"type": "context",
"elements": [{
{UiKitMessage([{
"type": "image",
"title": {
"type": "plain_text",
......@@ -146,20 +284,13 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
},
"imageUrl": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png",
"altText": "Example Image"
},
{
"type": "mrkdwn",
"text": "context"
}
]
},]
}/>
}])}
</Story>
</Preview>
<Preview>
<Story name='Action - Buttons'>
<UiKitMessage blocks={[{
{UiKitMessage([{
"type": "actions",
"elements": [
{
......@@ -183,14 +314,14 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
"value": "click_me_123"
}
]
}]}/>
}])}
</Story>
</Preview>
<Preview>
<Story name='Fields'>
<UiKitMessage blocks={[
{ UiKitMessage([
{
"type": "section",
"fields": [
......@@ -221,14 +352,14 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
}
]
}
]}/>
])}
</Story>
</Preview>
<Preview>
<Story name='Action - Select'>
<UiKitMessage blocks={[{
{UiKitMessage([{
"type": "actions",
"elements": [
{
......@@ -298,7 +429,7 @@ import { UiKitModal, UiKitMessage, kitContext, defaultContext } from './';
]
}
]
}]}/>
}])}
</Story>
</Preview>
......
import { action } from '@storybook/addon-actions';
import { Meta, Preview, Props, Story } from '@storybook/addon-docs/blocks';
import {
Modal,
} from '@rocket.chat/fuselage';
import { UiKitModal, kitContext, defaultContext } from './';
import { Demo } from './Demo';
import { withKnobs, text, boolean, number } from "@storybook/addon-knobs";
<Meta title='UIKit|UiKitModal' parameters={{ jest: ['UiKitModal/spec'] }} />
<Meta title='UIKit|UiKitModal' parameters={{ jest: ['UiKitModal/spec'] }} decorators={[withKnobs]} />
# UI Kit Modal
<Preview>
<Story name='Input'>
<UiKitModal blocks={[{
"type": "input",
"element": {
"type": "plain_text_input"
},
"label": {
"type": "plain_text",
"text": "Label",
"emoji": true
}
}]
}/>
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal([{
"type": "input",
"element": {
"type": "plain_text_input"
},
"label": {
"type": "plain_text",
"text": "Label",
"emoji": true
}
}])}
</Demo>
</Story>
</Preview>
<Preview>
<Story name='Input Multiline'>
<UiKitModal blocks={[{
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal([{
"type": "input",
"element": {
"type": "plain_text_input",
......@@ -37,8 +44,8 @@ import { UiKitModal, kitContext, defaultContext } from './';
"text": "Label",
"emoji": true
}
}]
}/>
}])}
</Demo>
</Story>
</Preview>
......@@ -46,7 +53,8 @@ import { UiKitModal, kitContext, defaultContext } from './';
<Preview>
<Story name='Input Datepicker'>
<UiKitModal blocks={[{
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal([{
"type": "input",
"element": {
"type": "datepicker",
......@@ -62,14 +70,15 @@ import { UiKitModal, kitContext, defaultContext } from './';
"text": "Label",
"emoji": true
}
}]
}/>
}])}
</Demo>
</Story>
</Preview>
<Preview>
<Story name='Image'>
<UiKitModal blocks={[{
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal([{
"type": "image",
"title": {
"type": "plain_text",
......@@ -78,14 +87,15 @@ import { UiKitModal, kitContext, defaultContext } from './';
},
"imageUrl": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png",
"altText": "Example Image"
}]
}/>
}])}
</Demo>