Unverified Commit 52fcedb0 authored by Guilherme Gazzo's avatar Guilherme Gazzo Committed by GitHub
Browse files

fix: uikit using react components (#135)

parent 2b50517e
import React from 'react';
import {
Button,
} from '@rocket.chat/fuselage';
import { useBlockContext, getStyle } from './hooks';
export const UIKitButton = ({ element, context, parser }) => {
const [{ loading }, action] = useBlockContext(element, context);
return (
<Button
mod-mod-loading={loading}
{...getStyle(element.style)}
small
data-group={element.groupId}
key={element.actionId}
children={parser.plainText(element.text)}
onClick={action}
value={element.value}
/>
);
};
......@@ -2,22 +2,47 @@ import React from 'react';
import {
Field,
FieldGroup,
TextAreaInput,
TextInput,
} from '@rocket.chat/fuselage';
import {
BLOCK_CONTEXT,
} from '@rocket.chat/ui-kit';
import { Block } from './Block';
import { useBlockContext } from './hooks';
export const Input = ({ label, element, parser, index, error, hint }) => (
<Block>
<FieldGroup>
<Field>
{label && <Field.Label>{label}</Field.Label>}
{parser.renderInputs(element, BLOCK_CONTEXT.FORM, parser, index)}
{error && <Field.Error>{error}</Field.Error>}
{hint && <Field.Hint>{hint}</Field.Hint>}
</Field>
</FieldGroup>
</Block>
);
export const Input = ({ label, element, parser, index, hint, context }) => {
const [{ error }] = useBlockContext(element, context);
return (
<Block>
<FieldGroup>
<Field>
{label && <Field.Label>{label}</Field.Label>}
{parser.renderInputs(element, BLOCK_CONTEXT.FORM, parser, index)}
{error && <Field.Error>{error}</Field.Error>}
{hint && <Field.Hint>{hint}</Field.Hint>}
</Field>
</FieldGroup>
</Block>
);
};
export const PlainInput = ({ element, context, index, parser }) => {
const [{ loading, value, error }, action] = useBlockContext(element, context);
const { multiline, actionId, placeholder } = element;
const Component = multiline ? TextAreaInput : TextInput;
return (
<Component
key={index}
mod-loading={loading}
id={actionId}
name={actionId}
rows={6}
error={error}
value={value}
onInput={action}
placeholder={parser.plainText(placeholder)}
/>
);
};
import React from 'react';
import {
Button,
} from '@rocket.chat/fuselage';
import { useBlockContext, getStyle } from './hooks';
export const UIKitMultiSelect = ({ element, context, parser }) => {
const [{ loading }, action] = useBlockContext(element, context);
return (
<Button
mod-mod-loading={loading}
{...getStyle(element.style)}
small
data-group={element.groupId}
key={element.actionId}
children={parser.plainText(element.text)}
onClick={action}
value={element.value}
/>
);
};
......@@ -8,9 +8,14 @@ import {
useCursor,
} from '@rocket.chat/fuselage';
import { useBlockContext } from './hooks';
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 } });
export const Overflow = ({ context, options, parser, element }) => {
const [{ loading }, action] = useBlockContext(element, context);
const handleSelection = ([value]) => action({ target: { value } });
const convertedOptions = convertOptions(options, parser.text);
const [cursor, handleKeyDown, handleKeyUp, , [visible, hide, show]] = useCursor(-1, convertedOptions, (args, [, hide]) => {
handleSelection(args);
......@@ -26,6 +31,7 @@ export const Overflow = ({ options, parser, onChange = console.log }) => {
onBlur={hide}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
mod-loading={loading}
>
<Icon name='menu' size={20} />
</Button>
......
......@@ -4,25 +4,38 @@ import {
MultiSelect,
} from '@rocket.chat/fuselage';
import { useBlockContext } from './hooks';
export const StaticSelect = ({
options,
onChange,
parser,
placeholder = { text: 'select a option' },
}) => (
<Select
context,
...element
}) => {
const [{ loading, value }, action] = useBlockContext(element, context);
return <Select
value={value}
mod-loading={loading}
options={options.map((option) => [option.value, parser.text(option.text)])}
onChange={(value) => onChange({ target: { value } })}
placeholder={parser.text(placeholder)} />);
onChange={(value) => action({ target: { value } })}
placeholder={parser.text(placeholder)} />;
};
export const MultiStaticSelect = ({
context,
options,
onChange,
parser,
placeholder = { text: 'select a option' },
}) => (
<MultiSelect
...element
}) => {
const [{ loading, value }, action] = useBlockContext(element, context);
return <MultiSelect
value={value}
mod-loading={loading}
options={options.map((option) => [option.value, parser.text(option.text)])}
onChange={(value) => onChange({ target: { value } })}
placeholder={parser.text(placeholder)} />);
onChange={(value) => action({ target: { value } })}
placeholder={parser.text(placeholder)} />;
};
......@@ -21,6 +21,10 @@ import { withKnobs, text, boolean, number } from "@storybook/addon-knobs";
"element": {
"type": "plain_text_input",
"actionId": "input-test",
"placeholder": {
"text": "plain_text_input",
text: text('placeholder', 'asdas')
}
},
"label": {
"type": "plain_text",
......@@ -102,6 +106,59 @@ import { withKnobs, text, boolean, number } from "@storybook/addon-knobs";
</Story>
</Preview>
<Preview>
<Story name='confirm button'>
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal([
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": "Approve"
},
"confirm": {
"title": {
"type": "plain_text",
"text": "Are you sure?"
},
"text": {
"type": "mrkdwn",
"text": "Wouldn't you prefer a good game of _chess_?"
},
"confirm": {
"type": "plain_text",
"text": "Do it"
},
"deny": {
"type": "plain_text",
"text": "Stop, I've changed my mind!"
}
},
"style": "primary",
"value": "click_me_123"
},
{
"type": "button",
"text": {
"type": "plain_text",
"emoji": true,
"text": "Deny"
},
"style": "danger",
"value": "click_me_123"
}
]
}
])}
</Demo>
</Story>
</Preview>
<Preview>
<Story name='Poll'>
<Demo visible={boolean('visible', true) ? 1 : 0}>
......@@ -152,4 +209,16 @@ import { withKnobs, text, boolean, number } from "@storybook/addon-knobs";
</Story>
</Preview>
<Preview>
<Story name='live button'>
<Demo visible={boolean('visible', true) ? 1 : 0}>
{UiKitModal(JSON.parse(text('json', '[]')))}
</Demo>
</Story>
</Preview>
<Props of={UiKitModal}/>
import React, { useContext, useState } from 'react';
import {
BLOCK_CONTEXT,
} from '@rocket.chat/ui-kit';
export const defaultContext = {
action: (...args) => console.log(JSON.stringify(args)),
state: console.log,
appId: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
errors: {},
};
export const kitContext = React.createContext(defaultContext);
export const useBlockContext = ({ blockId, actionId, appId, initialValue }, context) => {
const [value, setValue] = useState(initialValue);
const [loading, setLoading] = useState(false);
const { action, appId: appIdFromContext, viewId, state, errors } = useContext(kitContext);
const error = errors && actionId && errors[actionId];
if ([BLOCK_CONTEXT.SECTION, BLOCK_CONTEXT.ACTION].includes(context)) {
return [{ loading, setLoading, error }, async ({ target: { value } }) => {
setLoading(true);
await action({ blockId, appId: appId || appIdFromContext, actionId, value, viewId });
setLoading(false);
}];
}
return [{ loading, setLoading, value, error }, async ({ target: { value } }) => {
setValue(value);
setLoading(true);
await state({ blockId, appId, actionId, value });
setLoading(false);
}];
};
export const getStyle = (style) => {
switch (style) {
case 'primary':
case 'danger':
return {
[style]: true,
};
}
};
import React, { useContext, useState } from 'react';
import React from 'react';
import {
Divider,
Button,
SelectInput,
Flex,
Margins,
TextAreaInput,
TextInput,
InputBox,
Box,
} from '@rocket.chat/fuselage';
......@@ -25,53 +21,15 @@ import {
import { Section as SectionLayoutBlock } from './Section';
import { Actions as ActionsLayoutBlock } from './Actions';
import { Input as InputLayoutBlock } from './Input';
import { Input as InputLayoutBlock, PlainInput } from './Input';
import { MessageImage, ModalImage } from './Image';
import { StaticSelect, MultiStaticSelect } from './StaticSelect';
import { Block } from './Block';
import { Overflow } from './Overflow';
import { UIKitButton } from './Button';
import { useBlockContext } from './hooks';
export const defaultContext = {
action: (...args) => console.log(JSON.stringify(args)),
state: console.log,
appId: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
errors: {},
};
export const kitContext = React.createContext(defaultContext);
export const useBlockContext = ({ blockId, actionId, appId, initialValue }, context) => {
const [value, setValue] = useState(initialValue);
const [loading, setLoading] = useState(false);
const { action, appId: appIdFromContext, state, errors } = useContext(kitContext);
const error = errors && actionId && errors[actionId];
if ([BLOCK_CONTEXT.SECTION, BLOCK_CONTEXT.ACTION].includes(context)) {
return [{ loading, setLoading, error }, async ({ target: { value } }) => {
setLoading(true);
await action({ blockId, appId: appId || appIdFromContext, actionId, value });
setLoading(false);
}];
}
return [{ loading, setLoading, value, error }, async ({ target: { value } }) => {
setValue(value);
setLoading(true);
await state({ blockId, appId, actionId, value });
setLoading(false);
}];
};
const getStyle = (style) => {
switch (style) {
case 'primary':
case 'danger':
return {
[style]: true,
};
}
};
export * from './hooks';
function mrkdwn({ text/* , type = 'plain_text'*/ } = { text: '' }) {
return text;
......@@ -95,20 +53,7 @@ class TextParser extends UiKitParserText {
class ButtonsParser extends UiKitParserButtons {
button(element, context, key) {
const [{ loading }, action] = useBlockContext(element, context);
return (
<Button
key={key}
mod-mod-loading={loading}
{...getStyle(element.style)}
small={context === BLOCK_CONTEXT.SECTION}
data-group={element.groupId}
key={element.actionId}
children={this.plainText(element.text)}
onClick={action}
value={element.value}
/>
);
return <UIKitButton element={element} context={context} key={key} parser={this}/>;
}
}
......@@ -121,25 +66,11 @@ class MessageParser extends UiKitParserMessage {
text(...args) { return text(...args); }
overflow(element, context) {
const [{ loading }, action] = useBlockContext(element, context);
return <Overflow loading={loading} {...element} onChange={action} parser={this}/>;
return <Overflow context={context} {...element} parser={this}/>;
}
button(element, context, key) {
const [{ loading }, action] = useBlockContext(element, context);
return (
<Button
key={key}
mod-mod-loading={loading}
{...getStyle(element.style)}
small
data-group={element.groupId}
key={element.actionId}
children={this.plainText(element.text)}
onClick={action}
value={element.value}
/>
);
return <UIKitButton element={element} context={context} key={key} parser={this}/>;
}
divider(_, __, key) {
......@@ -214,30 +145,26 @@ class MessageParser extends UiKitParserMessage {
}
multiStaticSelect(element, context, key) {
const [{ loading, value }, action] = useBlockContext(element, context);
return (
<MultiStaticSelect
{...element}
key={key}
value={value}
mod-loading={loading}
onChange={action}
parser={this}
context={context}
/>
);
}
staticSelect(element, context, key) {
const [{ loading, value }, action] = useBlockContext(element, context);
return <StaticSelect value={value} key={key} {...element} mod-loading={loading} onChange={action} parser={this} />;
return <StaticSelect key={key} {...element} parser={this} />;
}
selectInput(element, context, key) {
const [{ loading, value }, action] = useBlockContext(element, context);
return (
<SelectInput key={key} value={value} onChange={action} mod-loading={loading} placeholder={element.type} disabled />
);
}
// selectInput(element, context, key) {
// const [{ loading, value }, action] = useBlockContext(element, context);
// return (
// <SelectInput key={key} value={value} onChange={action} mod-loading={loading} placeholder={element.type} disabled />
// );
// }
}
class ModalParser extends UiKitParserModal {
......@@ -248,12 +175,9 @@ class ModalParser extends UiKitParserModal {
});
}
input({ element, label, blockId, appId, ...args }, context, index) {
const [{ loading, value, error }, action] = useBlockContext({ ...element, appId, blockId }, context);
input({ element, label, blockId, appId }, context, index) {
return (
<InputLayoutBlock
error={error}
key={index}
index={index}
parser={this}
......@@ -269,22 +193,7 @@ class ModalParser extends UiKitParserModal {
}
plainInput(element, context, index) {
const [{ loading, value, error }, action] = useBlockContext(element, context);
const { multiline, actionId, placeholder } = element;
const Component = multiline ? TextAreaInput : TextInput;
return (
<Component
key={index}
mod-loading={loading}
id={actionId}
name={actionId}
rows={6}
error={error}
value={value}
onInput={action}
placeholder={this.plainText(placeholder)}
/>
);
return <PlainInput parser={this} element={element} context={context} index={index}/>;
}
}
......@@ -298,4 +207,4 @@ export const UiKitText = uiKitText(textParser);
export const UiKitMessage = uiKitMessage(messageParser);
export const UiKitModal = uiKitModal(modalParser);
export const UiKitComponent = ({render, blocks}) => render(blocks);
export const UiKitComponent = ({ render, blocks }) => render(blocks);
......@@ -59,7 +59,7 @@ export abstract class UiKitParserMessage extends UiKitParserText {
datePicker: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
staticSelect: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
multiStaticSelect: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
selectInput: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
// selectInput: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
context: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
divider: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
actions: (element: UiKitElement, context: BLOCK_CONTEXT, index: Number) => Component;
......@@ -135,10 +135,10 @@ const renderElement = ({ type, ...element }: UiKitElement, context: BLOCK_CONTEX
return parser.datePicker(element as UiKitElement, context, index);
case ELEMENT_TYPES.PLAIN_TEXT_INPUT:
return parser.plainInput(element as UiKitElement, context, index);
case ELEMENT_TYPES.CONVERSATION_SELECT:
case ELEMENT_TYPES.CHANNEL_SELECT:
case ELEMENT_TYPES.USER_SELECT:
return parser.selectInput({ type, ...element }, context, index);
// case ELEMENT_TYPES.CONVERSATION_SELECT:
// case ELEMENT_TYPES.CHANNEL_SELECT:
// case ELEMENT_TYPES.USER_SELECT:
// return parser.selectInput({ type, ...element }, context, index);
}
};
......
Supports Markdown
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