feat: Adding new UIKit components (#29566)
Co-authored-by: Tiago Evangelista Pinto <17487063+tiagoevanp@users.noreply.github.com>pull/29893/head
parent
5f7f27547f
commit
f9a748526d
@ -0,0 +1,6 @@ |
||||
--- |
||||
"@rocket.chat/fuselage-ui-kit": minor |
||||
"@rocket.chat/uikit-playground": minor |
||||
--- |
||||
|
||||
feat: Adding new UIKit components: Callout, Checkbox, Radio Button, Time Picker, Toast Bar, Toggle Switch, Tab Navigation |
||||
@ -0,0 +1,20 @@ |
||||
import { Callout } from '@rocket.chat/fuselage'; |
||||
import * as UiKit from '@rocket.chat/ui-kit'; |
||||
import type { ReactElement } from 'react'; |
||||
|
||||
import type { BlockProps } from '../utils/BlockProps'; |
||||
|
||||
type CalloutBlockProps = BlockProps<UiKit.CalloutBlock>; |
||||
|
||||
const CalloutBlock = ({ |
||||
block, |
||||
surfaceRenderer, |
||||
}: CalloutBlockProps): ReactElement => { |
||||
return ( |
||||
<Callout type={block.variant} icon={block.icon} title={block.title?.text}> |
||||
{surfaceRenderer.renderTextObject(block.text, 0, UiKit.BlockContext.NONE)} |
||||
</Callout> |
||||
); |
||||
}; |
||||
|
||||
export default CalloutBlock; |
||||
@ -0,0 +1,45 @@ |
||||
import { CheckBox, Box } from '@rocket.chat/fuselage'; |
||||
import * as UiKit from '@rocket.chat/ui-kit'; |
||||
import type { ReactElement } from 'react'; |
||||
|
||||
import { useUiKitState } from '../hooks/useUiKitState'; |
||||
import type { BlockProps } from '../utils/BlockProps'; |
||||
|
||||
type CheckboxElementProps = BlockProps<UiKit.CheckboxElement>; |
||||
|
||||
const CheckboxElement = ({ |
||||
block, |
||||
context, |
||||
surfaceRenderer, |
||||
}: CheckboxElementProps): ReactElement => { |
||||
const [{ loading, value }, action] = useUiKitState(block, context); |
||||
const { options } = block; |
||||
|
||||
return ( |
||||
<Box> |
||||
{options.map((option: UiKit.Option) => { |
||||
const isChecked = value?.includes(option.value); |
||||
|
||||
return ( |
||||
<Box key={option.value} pb='x4'> |
||||
<CheckBox |
||||
disabled={loading} |
||||
value={option.value} |
||||
checked={isChecked} |
||||
onChange={action} |
||||
/> |
||||
<Box is='label' pis='x8'> |
||||
{surfaceRenderer.renderTextObject( |
||||
option.text, |
||||
0, |
||||
UiKit.BlockContext.NONE |
||||
)} |
||||
</Box> |
||||
</Box> |
||||
); |
||||
})} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default CheckboxElement; |
||||
@ -0,0 +1,43 @@ |
||||
import { Box, RadioButton } from '@rocket.chat/fuselage'; |
||||
import * as UiKit from '@rocket.chat/ui-kit'; |
||||
import type { ReactElement } from 'react'; |
||||
|
||||
import { useUiKitState } from '../hooks/useUiKitState'; |
||||
import type { BlockProps } from '../utils/BlockProps'; |
||||
|
||||
type RadioButtonElementProps = BlockProps<UiKit.RadioButtonElement>; |
||||
|
||||
const RadioButtonElement = ({ |
||||
block, |
||||
context, |
||||
surfaceRenderer, |
||||
}: RadioButtonElementProps): ReactElement => { |
||||
const [{ loading, value }, action] = useUiKitState(block, context); |
||||
const { options } = block; |
||||
|
||||
return ( |
||||
<Box> |
||||
{options.map((option: UiKit.Option) => { |
||||
return ( |
||||
<Box key={option.value} pb='x4'> |
||||
<RadioButton |
||||
disabled={loading} |
||||
checked={value === option.value} |
||||
value={option.value} |
||||
onChange={action} |
||||
/> |
||||
<Box is='label' pis='x8'> |
||||
{surfaceRenderer.renderTextObject( |
||||
option.text, |
||||
0, |
||||
UiKit.BlockContext.NONE |
||||
)} |
||||
</Box> |
||||
</Box> |
||||
); |
||||
})} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default RadioButtonElement; |
||||
@ -0,0 +1,38 @@ |
||||
import { InputBox } from '@rocket.chat/fuselage'; |
||||
import type * as UiKit from '@rocket.chat/ui-kit'; |
||||
import type { ReactElement } from 'react'; |
||||
|
||||
import { useUiKitState } from '../hooks/useUiKitState'; |
||||
import type { BlockProps } from '../utils/BlockProps'; |
||||
import { fromTextObjectToString } from '../utils/fromTextObjectToString'; |
||||
|
||||
type TimePickerElementProps = BlockProps<UiKit.TimePickerElement>; |
||||
|
||||
const TimePickerElement = ({ |
||||
block, |
||||
context, |
||||
surfaceRenderer, |
||||
}: TimePickerElementProps): ReactElement => { |
||||
const [{ loading, value, error }, action] = useUiKitState(block, context); |
||||
const { actionId, placeholder } = block; |
||||
|
||||
return ( |
||||
<InputBox |
||||
type='time' |
||||
error={error} |
||||
value={value} |
||||
disabled={loading} |
||||
id={actionId} |
||||
name={actionId} |
||||
rows={6} |
||||
placeholder={ |
||||
placeholder |
||||
? fromTextObjectToString(surfaceRenderer, placeholder, 0) |
||||
: undefined |
||||
} |
||||
onInput={action} |
||||
/> |
||||
); |
||||
}; |
||||
|
||||
export default TimePickerElement; |
||||
@ -0,0 +1,45 @@ |
||||
import { Box, ToggleSwitch } from '@rocket.chat/fuselage'; |
||||
import * as UiKit from '@rocket.chat/ui-kit'; |
||||
import { type ReactElement } from 'react'; |
||||
|
||||
import { useUiKitState } from '../hooks/useUiKitState'; |
||||
import type { BlockProps } from '../utils/BlockProps'; |
||||
|
||||
type ToggleSwitchElementProps = BlockProps<UiKit.ToggleSwitchElement>; |
||||
|
||||
const ToggleSwitchElement = ({ |
||||
block, |
||||
context, |
||||
surfaceRenderer, |
||||
}: ToggleSwitchElementProps): ReactElement => { |
||||
const [{ value, loading }, action] = useUiKitState(block, context); |
||||
const { options } = block; |
||||
|
||||
return ( |
||||
<Box> |
||||
{options.map((option: UiKit.Option) => { |
||||
const isChecked = value.includes(option.value); |
||||
|
||||
return ( |
||||
<Box key={option.value} pb='x4'> |
||||
<ToggleSwitch |
||||
disabled={loading} |
||||
value={option.value} |
||||
checked={isChecked} |
||||
onChange={action} |
||||
/> |
||||
<Box is='label' pis='x8'> |
||||
{surfaceRenderer.renderTextObject( |
||||
option.text, |
||||
0, |
||||
UiKit.BlockContext.NONE |
||||
)} |
||||
</Box> |
||||
</Box> |
||||
); |
||||
})} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default ToggleSwitchElement; |
||||
@ -1,8 +1,16 @@ |
||||
import type { FuselageSurfaceRendererProps } from './FuselageSurfaceRenderer'; |
||||
import { FuselageSurfaceRenderer } from './FuselageSurfaceRenderer'; |
||||
|
||||
export class FuselageModalSurfaceRenderer extends FuselageSurfaceRenderer { |
||||
public constructor(allowedBlocks?: FuselageSurfaceRendererProps) { |
||||
super(allowedBlocks); |
||||
public constructor() { |
||||
super([ |
||||
'actions', |
||||
'context', |
||||
'divider', |
||||
'image', |
||||
'input', |
||||
'section', |
||||
'preview', |
||||
'callout', |
||||
]); |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,40 @@ |
||||
import type { LayoutBlock } from '@rocket.chat/ui-kit'; |
||||
|
||||
export const actionWithCheckbox: readonly LayoutBlock[] = [ |
||||
{ |
||||
type: 'actions', |
||||
elements: [ |
||||
{ |
||||
type: 'checkbox', |
||||
appId: 'app-id', |
||||
blockId: 'block-id', |
||||
actionId: 'action-id', |
||||
options: [ |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option 1', |
||||
}, |
||||
value: 'value-1', |
||||
}, |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option initial', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
], |
||||
initialOptions: [ |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option initial', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
]; |
||||
@ -0,0 +1,38 @@ |
||||
import type { LayoutBlock } from '@rocket.chat/ui-kit'; |
||||
|
||||
export const actionWithRadioButton: readonly LayoutBlock[] = [ |
||||
{ |
||||
type: 'actions', |
||||
elements: [ |
||||
{ |
||||
type: 'radio_button', |
||||
appId: 'app-id', |
||||
blockId: 'block-id', |
||||
actionId: 'action-id', |
||||
options: [ |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option 1', |
||||
}, |
||||
value: 'value-1', |
||||
}, |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option initial', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
], |
||||
initialOption: { |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Option initial', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
]; |
||||
@ -0,0 +1,21 @@ |
||||
import type { LayoutBlock } from '@rocket.chat/ui-kit'; |
||||
|
||||
export const actionWithTimePicker: readonly LayoutBlock[] = [ |
||||
{ |
||||
type: 'actions', |
||||
elements: [ |
||||
{ |
||||
type: 'time_picker', |
||||
initialTime: '10:30', |
||||
appId: 'app-id', |
||||
blockId: 'block-id', |
||||
actionId: 'action-id', |
||||
placeholder: { |
||||
type: 'plain_text', |
||||
text: 'Select a time', |
||||
emoji: true, |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
]; |
||||
@ -0,0 +1,40 @@ |
||||
import type { LayoutBlock } from '@rocket.chat/ui-kit'; |
||||
|
||||
export const actionWithToggleSwitch: readonly LayoutBlock[] = [ |
||||
{ |
||||
type: 'actions', |
||||
elements: [ |
||||
{ |
||||
type: 'toggle_switch', |
||||
appId: 'app-id', |
||||
blockId: 'block-id', |
||||
actionId: 'action-id', |
||||
options: [ |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Toggle 1', |
||||
}, |
||||
value: 'value-1', |
||||
}, |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Toggle initial option', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
], |
||||
initialOptions: [ |
||||
{ |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Toggle initial option', |
||||
}, |
||||
value: 'value-2', |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
]; |
||||
@ -0,0 +1,16 @@ |
||||
import type { LayoutBlock } from '@rocket.chat/ui-kit'; |
||||
|
||||
export const callout: readonly LayoutBlock[] = [ |
||||
{ |
||||
type: 'callout', |
||||
title: { |
||||
type: 'plain_text', |
||||
text: 'Callout Title', |
||||
}, |
||||
text: { |
||||
type: 'plain_text', |
||||
text: 'Callout Text', |
||||
}, |
||||
icon: 'rocket', |
||||
}, |
||||
]; |
||||
Loading…
Reference in new issue