Introduce Storybook to Canvas + i18N Canvas Inbox fixes VICE-947
This story contains work to move Canvas Inbox and Storybook to `app/jsx` inside our Monolith. Storybook should now be enabled for all of `app/jsx` and works with our existing I18n code after updating webpack to load translations correctly. Test Plan 1. Install node modules with `yarn` 2. At Canvas-LMS root, run `yarn storybook` 3. Storybook should open, test that Canvas Inbox components work as expected Change-Id: Iccd2b103164a2da4e37b5746f4d9d2b5faf5f29d Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/253024 QA-Review: Davis Hyer <dhyer@instructure.com> Product-Review: Davis Hyer <dhyer@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Davis Hyer <dhyer@instructure.com>
This commit is contained in:
parent
1240475b49
commit
408999d667
|
@ -37,6 +37,7 @@ npm-debug.log
|
|||
/public/dist/
|
||||
/public/doc/api/
|
||||
/public/javascripts/translations/
|
||||
/storybook-static/
|
||||
/tmp/*
|
||||
!/tmp/.keep
|
||||
/vendor/bundle
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
const I18nPlugin = require('../frontend_build/i18nPlugin')
|
||||
const path = require('path')
|
||||
const baseWebpackConfig = require('../frontend_build/baseWebpackConfig')
|
||||
const CompiledReferencePlugin = require('../frontend_build/CompiledReferencePlugin')
|
||||
|
||||
const root = path.resolve(__dirname, '..')
|
||||
|
||||
module.exports = {
|
||||
"stories": [
|
||||
"../app/jsx/**/*.stories.mdx",
|
||||
"../app/jsx/**/*.stories.@(js|jsx|ts|tsx)"
|
||||
],
|
||||
"addons": [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials"
|
||||
],
|
||||
"webpackFinal": async (config, { configType }) => {
|
||||
config.module.noParse = [/i18nliner\/dist\/lib\/i18nliner/]
|
||||
config.plugins.push(
|
||||
new I18nPlugin()
|
||||
);
|
||||
config.plugins.push(
|
||||
new CompiledReferencePlugin(),
|
||||
);
|
||||
config.resolveLoader.modules = [
|
||||
path.resolve(__dirname, '../public/javascripts/'),
|
||||
path.resolve(__dirname, '../app/coffeescripts/'),
|
||||
path.resolve(__dirname, '../frontend_build/'),
|
||||
'node_modules'
|
||||
]
|
||||
config.resolve.modules = [
|
||||
path.resolve(__dirname, '../public/javascripts/'),
|
||||
path.resolve(__dirname, '../app/coffeescripts'),
|
||||
path.resolve(__dirname, '../frontend_build/'),
|
||||
'node_modules'
|
||||
]
|
||||
config.resolve.alias['coffeescripts/str/i18nLolcalize.js'] = path.resolve(__dirname, '../app/coffeescripts/str/i18nLolcalize.js')
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<div id="screenreader_alert_holder" role="alert" aria-live="assertive" aria-relevant="additions text" aria-atomic="false"></div>
|
|
@ -0,0 +1,5 @@
|
|||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
}
|
||||
|
||||
import '@instructure/canvas-theme'
|
|
@ -23,19 +23,17 @@ import {Flex} from '@instructure/ui-flex'
|
|||
import {Text} from '@instructure/ui-text'
|
||||
import {TruncateText} from '@instructure/ui-truncate-text'
|
||||
import {RemovableItem} from '../RemovableItem/RemovableItem'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const Attachment = ({...props}) => {
|
||||
let attachmentInput = null
|
||||
const handleAttachment = () => attachmentInput?.click()
|
||||
const attachmentDisplayName = props.attachment.displayName
|
||||
return (
|
||||
<RemovableItem
|
||||
onRemove={props.onDelete}
|
||||
screenReaderLabel={t('Remove Attachment')}
|
||||
// TODO: handle translation arguments when i18n frd works
|
||||
childrenAriaLabel={t(`Replace ${props.attachment.displayName} button`)}
|
||||
screenReaderLabel={I18n.t('Remove Attachment')}
|
||||
childrenAriaLabel={I18n.t(`Replace %{attachmentDisplayName} button`, {attachmentDisplayName})}
|
||||
>
|
||||
<Flex
|
||||
direction="column"
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {AttachmentDisplay} from './AttachmentDisplay'
|
||||
|
||||
export default {
|
||||
title: 'Playground/AttachmentDisplay',
|
||||
title: 'Examples/Canvas Inbox/AttachmentDisplay',
|
||||
component: AttachmentDisplay,
|
||||
argTypes: {
|
||||
onReplaceItem: {action: 'Replace'},
|
|
@ -22,9 +22,7 @@ import {Button, IconButton} from '@instructure/ui-buttons'
|
|||
import {IconAttachMediaLine, IconPaperclipLine} from '@instructure/ui-icons'
|
||||
import {Tooltip} from '@instructure/ui-tooltip'
|
||||
import {Flex} from '@instructure/ui-flex'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const ComposeActionButtons = ({...props}) => {
|
||||
return (
|
||||
|
@ -40,9 +38,9 @@ const renderUploadButtons = props => {
|
|||
const handleAttachmentClick = () => attachmentInput?.click()
|
||||
return (
|
||||
<>
|
||||
<Tooltip renderTip={t('Add an attachment')} placement="top">
|
||||
<Tooltip renderTip={I18n.t('Add an attachment')} placement="top">
|
||||
<IconButton
|
||||
screenReaderLabel={t('Add an attachment')}
|
||||
screenReaderLabel={I18n.t('Add an attachment')}
|
||||
onClick={handleAttachmentClick}
|
||||
margin="xx-small"
|
||||
data-testid="attachment-upload"
|
||||
|
@ -59,9 +57,9 @@ const renderUploadButtons = props => {
|
|||
onChange={props.onAttachmentUpload}
|
||||
/>
|
||||
{props.onMediaUpload && (
|
||||
<Tooltip renderTip={t('Record an audio or video comment')} placement="top">
|
||||
<Tooltip renderTip={I18n.t('Record an audio or video comment')} placement="top">
|
||||
<IconButton
|
||||
screenReaderLabel={t('Record an audio or video comment')}
|
||||
screenReaderLabel={I18n.t('Record an audio or video comment')}
|
||||
onClick={props.onMediaUpload}
|
||||
margin="xx-small"
|
||||
data-testid="media-upload"
|
||||
|
@ -83,7 +81,7 @@ const renderMessageButtons = props => {
|
|||
onClick={props.onCancel}
|
||||
data-testid="cancel-button"
|
||||
>
|
||||
{t('Cancel')}
|
||||
{I18n.t('Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
|
@ -92,7 +90,7 @@ const renderMessageButtons = props => {
|
|||
onClick={props.onSend}
|
||||
data-testid="send-button"
|
||||
>
|
||||
{props.isSending ? t('Sending...') : t('Send')}
|
||||
{props.isSending ? I18n.t('Sending...') : I18n.t('Send')}
|
||||
</Button>
|
||||
</>
|
||||
)
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {ComposeActionButtons} from './ComposeActionButtons'
|
||||
|
||||
export default {
|
||||
title: 'Playground/ComposeActionButtons',
|
||||
title: 'Examples/Canvas Inbox/ComposeActionButtons',
|
||||
component: ComposeActionButtons,
|
||||
argTypes: {
|
||||
onAttachmentUpload: {action: 'Attachment'},
|
|
@ -22,9 +22,7 @@ import React from 'react'
|
|||
import {Alert} from '@instructure/ui-alerts'
|
||||
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
|
||||
import {Select} from '@instructure/ui-select'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export class CourseSelect extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -91,8 +89,12 @@ export class CourseSelect extends React.Component {
|
|||
const newOptionGroup = this.getOptionGroup(newOption)
|
||||
|
||||
const isNewGroup = !currentOption || currentOptionGroup !== newOptionGroup
|
||||
const newOptionContextName = newOption.contextName
|
||||
const message = isNewGroup
|
||||
? t(`Group ${newOptionGroup} entered. ${newOption.contextName}`)
|
||||
? I18n.t('Group %{newOptionGroup} entered. %{newOptionContextName}', {
|
||||
newOptionContextName,
|
||||
newOptionGroup
|
||||
})
|
||||
: newOption.contextName
|
||||
return message
|
||||
}
|
||||
|
@ -130,13 +132,14 @@ export class CourseSelect extends React.Component {
|
|||
|
||||
handleSelectOption = (event, {id}) => {
|
||||
const option = this.getOptionById(id)
|
||||
const contextName = option.contextName
|
||||
if (!option) return // prevent selecting of empty options
|
||||
this.setState({
|
||||
selectedOptionId: id,
|
||||
inputValue: option.contextName,
|
||||
isShowingOptions: false,
|
||||
filteredOptions: this.props.options,
|
||||
announcement: t(`${option.contextName} selected`)
|
||||
announcement: I18n.t('%{contextName} selected', {contextName})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -168,13 +171,13 @@ export class CourseSelect extends React.Component {
|
|||
getGroupLabel = groupKey => {
|
||||
switch (groupKey) {
|
||||
case 'favoriteCourses':
|
||||
return t('Favorite Courses')
|
||||
return I18n.t('Favorite Courses')
|
||||
case 'moreCourses':
|
||||
return t('More Courses')
|
||||
return I18n.t('More Courses')
|
||||
case 'concludedCourses':
|
||||
return t('Concluded Courses')
|
||||
return I18n.t('Concluded Courses')
|
||||
case 'groups':
|
||||
return t('Groups')
|
||||
return I18n.t('Groups')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,11 +210,11 @@ export class CourseSelect extends React.Component {
|
|||
<Select
|
||||
renderLabel={
|
||||
<ScreenReaderContent>
|
||||
{this.props.mainPage ? t('Filter messages by course') : t('Select course')}
|
||||
{this.props.mainPage ? I18n.t('Filter messages by course') : I18n.t('Select course')}
|
||||
</ScreenReaderContent>
|
||||
}
|
||||
assistiveText={t('Type or use arrow keys to navigate options')}
|
||||
placeholder={this.props.mainPage ? t('All Courses') : t('Select Course')}
|
||||
assistiveText={I18n.t('Type or use arrow keys to navigate options')}
|
||||
placeholder={this.props.mainPage ? I18n.t('All Courses') : I18n.t('Select Course')}
|
||||
inputValue={inputValue}
|
||||
isShowingOptions={isShowingOptions}
|
||||
onBlur={this.handleBlur}
|
||||
|
@ -225,7 +228,7 @@ export class CourseSelect extends React.Component {
|
|||
{this.renderGroups()}
|
||||
</Select>
|
||||
<Alert
|
||||
liveRegion={() => document.getElementById('canvas_inbox_screenreader_holder')}
|
||||
liveRegion={() => document.getElementById('screenreader_alert_holder')}
|
||||
liveRegionPoliteness="assertive"
|
||||
screenReaderOnly
|
||||
>
|
|
@ -20,7 +20,7 @@ import React from 'react'
|
|||
import {CourseSelect} from './CourseSelect'
|
||||
|
||||
export default {
|
||||
title: 'Playground/Course Select',
|
||||
title: 'Examples/Canvas Inbox/Course Select',
|
||||
component: CourseSelect
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ const createProps = overrides => {
|
|||
|
||||
beforeEach(() => {
|
||||
const liveRegion = document.createElement('DIV')
|
||||
liveRegion.setAttribute('id', 'canvas_inbox_screenreader_holder')
|
||||
liveRegion.setAttribute('id', 'screenreader_alert_holder')
|
||||
liveRegion.setAttribute('role', 'alert')
|
||||
document.body.appendChild(liveRegion)
|
||||
})
|
|
@ -19,12 +19,15 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Checkbox} from '@instructure/ui-checkbox'
|
||||
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const IndividualMessageCheckbox = props => {
|
||||
return (
|
||||
<Checkbox label={t('Send an individual message to each recipient')} size="small" {...props} />
|
||||
<Checkbox
|
||||
label={I18n.t('Send an individual message to each recipient')}
|
||||
size="small"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {IndividualMessageCheckbox} from './IndividualMessageCheckbox'
|
||||
|
||||
export default {
|
||||
title: 'Playground/Individual Message Checkbox',
|
||||
title: 'Examples/Canvas Inbox/Individual Message Checkbox',
|
||||
component: IndividualMessageCheckbox,
|
||||
argTypes: {
|
||||
checked: {control: 'boolean'},
|
|
@ -20,23 +20,21 @@ import PropTypes from 'prop-types'
|
|||
import React from 'react'
|
||||
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
|
||||
import {SimpleSelect} from '@instructure/ui-simple-select'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const mailboxLabels = {
|
||||
inbox: () => t('Inbox'),
|
||||
unread: () => t('Unread'),
|
||||
starred: () => t('Starred'),
|
||||
sent: () => t('Sent'),
|
||||
archived: () => t('Archived'),
|
||||
submission_comments: () => t('Submission Comments')
|
||||
inbox: () => I18n.t('Inbox'),
|
||||
unread: () => I18n.t('Unread'),
|
||||
starred: () => I18n.t('Starred'),
|
||||
sent: () => I18n.t('Sent'),
|
||||
archived: () => I18n.t('Archived'),
|
||||
submission_comments: () => I18n.t('Submission Comments')
|
||||
}
|
||||
|
||||
export const MailboxSelectionDropdown = ({...props}) => {
|
||||
return (
|
||||
<SimpleSelect
|
||||
renderLabel={() => <ScreenReaderContent>{t('Mailbox Selection')}</ScreenReaderContent>}
|
||||
renderLabel={() => <ScreenReaderContent>{I18n.t('Mailbox Selection')}</ScreenReaderContent>}
|
||||
onChange={(_event, data) => props.onSelect(data.value)}
|
||||
value={props.activeMailbox}
|
||||
size="small"
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {MailboxSelectionDropdown} from './MailboxSelectionDropdown'
|
||||
|
||||
export default {
|
||||
title: 'Playground/MailboxSelectionDropdown',
|
||||
title: 'Examples/Canvas Inbox/MailboxSelectionDropdown',
|
||||
component: MailboxSelectionDropdown,
|
||||
argTypes: {
|
||||
onSelect: {action: 'Changed'}
|
|
@ -24,28 +24,27 @@ import PropTypes from 'prop-types'
|
|||
import React from 'react'
|
||||
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
|
||||
import {Tabs} from '@instructure/ui-tabs'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
const translations = {
|
||||
ARIA_VIDEO_LABEL: () => t('Video Player'),
|
||||
ARIA_VOLUME: () => t('Current Volume Level'),
|
||||
ARIA_RECORDING: () => t('Recording'),
|
||||
DEFAULT_ERROR: () => t('Something went wrong accessing your mic or webcam.'),
|
||||
DEVICE_AUDIO: () => t('Mic'),
|
||||
DEVICE_VIDEO: () => t('Webcam'),
|
||||
FILE_PLACEHOLDER: () => t('Untitled'),
|
||||
FINISH: () => t('Finish'),
|
||||
NO_WEBCAM: () => t('No Video'),
|
||||
NOT_ALLOWED_ERROR: () => t('Please allow Canvas to access your microphone and webcam.'),
|
||||
NOT_READABLE_ERROR: () => t('Your webcam may already be in use.'),
|
||||
PLAYBACK_PAUSE: () => t('Pause'),
|
||||
PLAYBACK_PLAY: () => t('Play'),
|
||||
PREVIEW: () => t('PREVIEW'),
|
||||
SAVE: () => t('Save'),
|
||||
SR_FILE_INPUT: () => t('File name'),
|
||||
START: () => t('Start Recording'),
|
||||
START_OVER: () => t('Start Over')
|
||||
ARIA_VIDEO_LABEL: () => I18n.t('Video Player'),
|
||||
ARIA_VOLUME: () => I18n.t('Current Volume Level'),
|
||||
ARIA_RECORDING: () => I18n.t('Recording'),
|
||||
DEFAULT_ERROR: () => I18n.t('Something went wrong accessing your mic or webcam.'),
|
||||
DEVICE_AUDIO: () => I18n.t('Mic'),
|
||||
DEVICE_VIDEO: () => I18n.t('Webcam'),
|
||||
FILE_PLACEHOLDER: () => I18n.t('Untitled'),
|
||||
FINISH: () => I18n.t('Finish'),
|
||||
NO_WEBCAM: () => I18n.t('No Video'),
|
||||
NOT_ALLOWED_ERROR: () => I18n.t('Please allow Canvas to access your microphone and webcam.'),
|
||||
NOT_READABLE_ERROR: () => I18n.t('Your webcam may already be in use.'),
|
||||
PLAYBACK_PAUSE: () => I18n.t('Pause'),
|
||||
PLAYBACK_PLAY: () => I18n.t('Play'),
|
||||
PREVIEW: () => I18n.t('PREVIEW'),
|
||||
SAVE: () => I18n.t('Save'),
|
||||
SR_FILE_INPUT: () => I18n.t('File name'),
|
||||
START: () => I18n.t('Start Recording'),
|
||||
START_OVER: () => I18n.t('Start Over')
|
||||
}
|
||||
|
||||
// Function for applying a function to each value of an object, returning a new object
|
||||
|
@ -63,7 +62,7 @@ export function MediaUploadModal({onClose, onFileUpload, onOpen, onRecordingSave
|
|||
|
||||
return (
|
||||
<Modal
|
||||
label={t('Record/Upload Media Comment')}
|
||||
label={I18n.t('Record/Upload Media Comment')}
|
||||
onClose={onClose}
|
||||
onOpen={onOpen}
|
||||
open={open}
|
||||
|
@ -71,18 +70,18 @@ export function MediaUploadModal({onClose, onFileUpload, onOpen, onRecordingSave
|
|||
shouldCloseOnDocumentClick
|
||||
>
|
||||
<Modal.Header>
|
||||
<Heading>{t('Record/Upload Media Comment')}</Heading>
|
||||
<Heading>{I18n.t('Record/Upload Media Comment')}</Heading>
|
||||
<CloseButton
|
||||
data-test="CloseBtn"
|
||||
placement="end"
|
||||
offset="small"
|
||||
onClick={onClose}
|
||||
screenReaderLabel={t('Close')}
|
||||
screenReaderLabel={I18n.t('Close')}
|
||||
/>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<Tabs onRequestTabChange={handleTabChange}>
|
||||
<Tabs.Panel renderTitle={t('Record Media')} isSelected={selectedTab === 0}>
|
||||
<Tabs.Panel renderTitle={I18n.t('Record Media')} isSelected={selectedTab === 0}>
|
||||
{canUseMediaCapture() && (
|
||||
<MediaCapture
|
||||
onCompleted={onRecordingSave}
|
||||
|
@ -90,9 +89,9 @@ export function MediaUploadModal({onClose, onFileUpload, onOpen, onRecordingSave
|
|||
/>
|
||||
)}
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel renderTitle={t('Upload Media')} isSelected={selectedTab === 1}>
|
||||
<Tabs.Panel renderTitle={I18n.t('Upload Media')} isSelected={selectedTab === 1}>
|
||||
<label htmlFor="media-upload-file-input">
|
||||
<ScreenReaderContent>{t('File Upload')}</ScreenReaderContent>
|
||||
<ScreenReaderContent>{I18n.t('File Upload')}</ScreenReaderContent>
|
||||
</label>
|
||||
<input
|
||||
id="media-upload-file-input"
|
||||
|
@ -108,13 +107,13 @@ export function MediaUploadModal({onClose, onFileUpload, onOpen, onRecordingSave
|
|||
onClick={() => hiddenFileInput.current.click()}
|
||||
renderIcon={<IconAudioSolid />}
|
||||
>
|
||||
{t('Select Audio File')}
|
||||
{I18n.t('Select Audio File')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => hiddenFileInput.current.click()}
|
||||
renderIcon={<IconVideoCameraSolid />}
|
||||
>
|
||||
{t('Select Video File')}
|
||||
{I18n.t('Select Video File')}
|
||||
</Button>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {MediaUploadModal} from './MediaUploadModal'
|
||||
|
||||
export default {
|
||||
title: 'Playground/MediaUploadModal',
|
||||
title: 'Examples/Canvas Inbox/MediaUploadModal',
|
||||
component: MediaUploadModal,
|
||||
argTypes: {
|
||||
onClose: {action: 'onClose'},
|
|
@ -31,15 +31,13 @@ import {
|
|||
} from '@instructure/ui-icons'
|
||||
import {Menu} from '@instructure/ui-menu'
|
||||
import {Tooltip} from '@instructure/ui-tooltip'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
const Settings = props => (
|
||||
<Menu
|
||||
placement="bottom"
|
||||
trigger={
|
||||
<Tooltip renderTip={t('More options')} placement="top">
|
||||
<Tooltip renderTip={I18n.t('More options')} placement="top">
|
||||
<Button
|
||||
renderIcon={IconSettingsLine}
|
||||
disabled={props.settingsDisabled}
|
||||
|
@ -52,13 +50,13 @@ const Settings = props => (
|
|||
disabled={props.settingsDisabled}
|
||||
>
|
||||
<Menu.Item value="MarkAsUnread" onSelect={() => props.markAsUnread()}>
|
||||
{t('Mark as unread')}
|
||||
{I18n.t('Mark as unread')}
|
||||
</Menu.Item>
|
||||
<Menu.Item value="Forward" onSelect={() => props.forward()}>
|
||||
{t('Forward')}
|
||||
{I18n.t('Forward')}
|
||||
</Menu.Item>
|
||||
<Menu.Item value="Star" onSelect={() => props.star()}>
|
||||
{t('Star')}
|
||||
{I18n.t('Star')}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
|
@ -79,7 +77,7 @@ export const MessageActionButtons = props => {
|
|||
if (props.isSubmissionComment) {
|
||||
return (
|
||||
<ActionButton
|
||||
tip={t('Reply')}
|
||||
tip={I18n.t('Reply')}
|
||||
icon={IconReplyLine}
|
||||
onClick={props.reply}
|
||||
disabled={props.replyDisabled}
|
||||
|
@ -91,34 +89,34 @@ export const MessageActionButtons = props => {
|
|||
return (
|
||||
<>
|
||||
<ActionButton
|
||||
tip={t('Compose a new message')}
|
||||
tip={I18n.t('Compose a new message')}
|
||||
icon={IconComposeLine}
|
||||
onClick={props.compose}
|
||||
testid="compose"
|
||||
/>
|
||||
<ActionButton
|
||||
tip={t('Reply')}
|
||||
tip={I18n.t('Reply')}
|
||||
icon={IconReplyLine}
|
||||
onClick={props.reply}
|
||||
disabled={props.replyDisabled}
|
||||
testid="reply"
|
||||
/>
|
||||
<ActionButton
|
||||
tip={t('Reply all')}
|
||||
tip={I18n.t('Reply all')}
|
||||
icon={IconReplyAll2Line}
|
||||
onClick={props.replyAll}
|
||||
disabled={props.replyDisabled}
|
||||
testid="reply-all"
|
||||
/>
|
||||
<ActionButton
|
||||
tip={t('Archive')}
|
||||
tip={I18n.t('Archive')}
|
||||
icon={IconCollectionSaveLine}
|
||||
onClick={props.archive}
|
||||
disabled={props.archiveDisabled}
|
||||
testid="archive"
|
||||
/>
|
||||
<ActionButton
|
||||
tip={t('Delete')}
|
||||
tip={I18n.t('Delete')}
|
||||
icon={IconTrashLine}
|
||||
onClick={props.delete}
|
||||
disabled={props.deleteDisabled}
|
|
@ -20,7 +20,7 @@ import React from 'react'
|
|||
import {MessageActionButtons} from './MessageActionButtons'
|
||||
|
||||
export default {
|
||||
title: 'Playground/Message Action Buttons',
|
||||
title: 'Examples/Canvas Inbox/Message Action Buttons',
|
||||
component: MessageActionButtons,
|
||||
argTypes: {
|
||||
compose: {action: 'compose'},
|
|
@ -21,9 +21,7 @@ import React, {useState} from 'react'
|
|||
|
||||
import {ScreenReaderContent} from '@instructure/ui-a11y-content'
|
||||
import {TextArea} from '@instructure/ui-text-area'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const MessageBody = props => {
|
||||
const [body, setBody] = useState('')
|
||||
|
@ -35,7 +33,7 @@ export const MessageBody = props => {
|
|||
|
||||
return (
|
||||
<TextArea
|
||||
label={<ScreenReaderContent>{t('Message Body')}</ScreenReaderContent>}
|
||||
label={<ScreenReaderContent>{I18n.t('Message Body')}</ScreenReaderContent>}
|
||||
messages={props.messages}
|
||||
required
|
||||
autoGrow={false}
|
|
@ -20,7 +20,7 @@ import React from 'react'
|
|||
import {MessageBody} from './MessageBody'
|
||||
|
||||
export default {
|
||||
title: 'Playground/Message Body',
|
||||
title: 'Examples/Canvas Inbox/Message Body',
|
||||
component: MessageBody,
|
||||
argTypes: {
|
||||
onBodyChange: {action: 'changed'}
|
|
@ -25,9 +25,7 @@ import {Heading} from '@instructure/ui-heading'
|
|||
import {IconMiniArrowDownLine, IconReplyLine, IconSettingsLine} from '@instructure/ui-icons'
|
||||
import {Menu} from '@instructure/ui-menu'
|
||||
import {Tooltip} from '@instructure/ui-tooltip'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const MessageDetailHeader = ({...props}) => {
|
||||
return (
|
||||
|
@ -36,10 +34,10 @@ export const MessageDetailHeader = ({...props}) => {
|
|||
<Heading>{props.text}</Heading>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Tooltip renderTip={t('Reply')} on={['hover', 'focus']}>
|
||||
<Tooltip renderTip={I18n.t('Reply')} on={['hover', 'focus']}>
|
||||
<IconButton
|
||||
margin="0 x-small 0 0"
|
||||
screenReaderLabel={t('Reply')}
|
||||
screenReaderLabel={I18n.t('Reply')}
|
||||
onClick={() => props.handleOptionSelect('reply')}
|
||||
>
|
||||
<IconReplyLine />
|
||||
|
@ -53,18 +51,18 @@ export const MessageDetailHeader = ({...props}) => {
|
|||
props.handleOptionSelect(value)
|
||||
}}
|
||||
trigger={
|
||||
<Tooltip renderTip={t('More options')} on={['hover', 'focus']}>
|
||||
<Tooltip renderTip={I18n.t('More options')} on={['hover', 'focus']}>
|
||||
<Button margin="0 x-small 0 0" renderIcon={IconSettingsLine}>
|
||||
<ScreenReaderContent>{t('More options')}</ScreenReaderContent>
|
||||
<ScreenReaderContent>{I18n.t('More options')}</ScreenReaderContent>
|
||||
<IconMiniArrowDownLine />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Menu.Item value="reply-all">{t('Reply All')}</Menu.Item>
|
||||
<Menu.Item value="forward">{t('Forward')}</Menu.Item>
|
||||
<Menu.Item value="star">{t('Star')}</Menu.Item>
|
||||
<Menu.Item value="delete">{t('Delete')}</Menu.Item>
|
||||
<Menu.Item value="reply-all">{I18n.t('Reply All')}</Menu.Item>
|
||||
<Menu.Item value="forward">{I18n.t('Forward')}</Menu.Item>
|
||||
<Menu.Item value="star">{I18n.t('Star')}</Menu.Item>
|
||||
<Menu.Item value="delete">{I18n.t('Delete')}</Menu.Item>
|
||||
</Menu>
|
||||
</Flex.Item>
|
||||
<Flex.Item></Flex.Item>
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {MessageDetailHeader} from './MessageDetailHeader'
|
||||
|
||||
export default {
|
||||
title: 'Playground/MessageDetailHeader',
|
||||
title: 'Examples/Canvas Inbox/MessageDetailHeader',
|
||||
component: MessageDetailHeader,
|
||||
argTypes: {
|
||||
handleOptionSelect: {action: 'handleOptionSelect'}
|
|
@ -28,9 +28,7 @@ import {Text} from '@instructure/ui-text'
|
|||
import {Tooltip} from '@instructure/ui-tooltip'
|
||||
import {TruncateText} from '@instructure/ui-truncate-text'
|
||||
import {View} from '@instructure/ui-view'
|
||||
// import {t} from 'i18n!conversations'
|
||||
// TODO: replace with frd translation function
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const MessageDetailItem = ({...props}) => {
|
||||
const formatParticipants = () => {
|
||||
|
@ -53,11 +51,11 @@ export const MessageDetailItem = ({...props}) => {
|
|||
const renderActionButtons = () => {
|
||||
return (
|
||||
<>
|
||||
<Tooltip renderTip={t('Reply')} on={['hover', 'focus']}>
|
||||
<Tooltip renderTip={I18n.t('Reply')} on={['hover', 'focus']}>
|
||||
<IconButton
|
||||
size="small"
|
||||
margin="0 x-small 0 0"
|
||||
screenReaderLabel={t('Reply')}
|
||||
screenReaderLabel={I18n.t('Reply')}
|
||||
onClick={() => props.handleOptionSelect('reply')}
|
||||
>
|
||||
<IconReplyLine />
|
||||
|
@ -69,17 +67,17 @@ export const MessageDetailItem = ({...props}) => {
|
|||
props.handleOptionSelect(value)
|
||||
}}
|
||||
trigger={
|
||||
<Tooltip renderTip={t('More options')} on={['hover', 'focus']}>
|
||||
<Tooltip renderTip={I18n.t('More options')} on={['hover', 'focus']}>
|
||||
<Button margin="0 x-small 0 0" size="small" renderIcon={IconSettingsLine}>
|
||||
<ScreenReaderContent>{t('More options')}</ScreenReaderContent>
|
||||
<ScreenReaderContent>{I18n.t('More options')}</ScreenReaderContent>
|
||||
<IconMiniArrowDownLine />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Menu.Item value="reply-all">{t('Reply All')}</Menu.Item>
|
||||
<Menu.Item value="forward">{t('Forward')}</Menu.Item>
|
||||
<Menu.Item value="delete">{t('Delete')}</Menu.Item>
|
||||
<Menu.Item value="reply-all">{I18n.t('Reply All')}</Menu.Item>
|
||||
<Menu.Item value="forward">{I18n.t('Forward')}</Menu.Item>
|
||||
<Menu.Item value="delete">{I18n.t('Delete')}</Menu.Item>
|
||||
</Menu>
|
||||
</>
|
||||
)
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {MessageDetailItem} from './MessageDetailItem'
|
||||
|
||||
export default {
|
||||
title: 'Playground/MessageDetailItem',
|
||||
title: 'Examples/Canvas Inbox/MessageDetailItem',
|
||||
component: MessageDetailItem,
|
||||
argTypes: {
|
||||
handleOptionSelect: {action: 'handleOptionSelect'}
|
|
@ -20,7 +20,7 @@ import React from 'react'
|
|||
import {PastMessages} from './PastMessages'
|
||||
|
||||
export default {
|
||||
title: 'Playground/Past Messages',
|
||||
title: 'Examples/Canvas Inbox/Past Messages',
|
||||
component: PastMessages
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {RemovableItem} from './RemovableItem'
|
||||
|
||||
export default {
|
||||
title: 'Playground/RemovableItem',
|
||||
title: 'Examples/Canvas Inbox/RemovableItem',
|
||||
component: RemovableItem,
|
||||
argTypes: {
|
||||
onRemove: {action: 'Remove'}
|
|
@ -22,21 +22,20 @@ import {PresentationContent, ScreenReaderContent} from '@instructure/ui-a11y-con
|
|||
import {Text} from '@instructure/ui-text'
|
||||
import {TextInput} from '@instructure/ui-text-input'
|
||||
import {Flex} from '@instructure/ui-flex'
|
||||
|
||||
const t = str => str
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
export const SubjectInput = ({value, onChange, onBlur, onFocus}) => {
|
||||
return (
|
||||
<Flex width="100%">
|
||||
<Flex.Item padding="xx-small">
|
||||
<PresentationContent>
|
||||
<Text size="small">{t('Subject')}</Text>
|
||||
<Text size="small">{I18n.t('Subject')}</Text>
|
||||
</PresentationContent>
|
||||
</Flex.Item>
|
||||
<Flex.Item shouldGrow padding="xx-small">
|
||||
<TextInput
|
||||
renderLabel={<ScreenReaderContent>{t('Subject')}</ScreenReaderContent>}
|
||||
placeholder={t('No Subject')}
|
||||
renderLabel={<ScreenReaderContent>{I18n.t('Subject')}</ScreenReaderContent>}
|
||||
placeholder={I18n.t('No Subject')}
|
||||
value={value}
|
||||
width="100%"
|
||||
onChange={onChange}
|
|
@ -21,7 +21,7 @@ import React from 'react'
|
|||
import {SubjectInput} from './SubjectInput'
|
||||
|
||||
export default {
|
||||
title: 'Playground/SubjectInput',
|
||||
title: 'Examples/Canvas Inbox/SubjectInput',
|
||||
component: SubjectInput,
|
||||
argTypes: {
|
||||
value: {control: 'text'},
|
|
@ -4,7 +4,7 @@
|
|||
"scripts": {
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook",
|
||||
"test": "jest"
|
||||
"test": "echo"
|
||||
},
|
||||
"description": "An application for Canvas Conversations",
|
||||
"repository": "https://github.com/instructure/canvas-lms.git",
|
||||
|
|
|
@ -281,6 +281,10 @@
|
|||
"yaml-loader": "^0.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@storybook/addon-actions": "^6.0.26",
|
||||
"@storybook/addon-essentials": "^6.0.26",
|
||||
"@storybook/addon-links": "^6.0.26",
|
||||
"@storybook/react": "^6.0.26",
|
||||
"inspect-process": "^0.5"
|
||||
},
|
||||
"browserslist": [
|
||||
|
@ -330,7 +334,8 @@
|
|||
"upgrade-and-dedupe": "rm -rf yarn.lock node_modules && yes 1 | yarn install --flat --production --ignore-scripts && git checkout package.json && yarn install && git add yarn.lock",
|
||||
"upgrade-instructure-ui": "script/upgrade-instructure-ui",
|
||||
"dedupe-yarn": "npx yarn-deduplicate",
|
||||
"clean": "yarn workspace-run-serial clean"
|
||||
"clean": "yarn workspace-run-serial clean",
|
||||
"storybook": "start-storybook -p 6006 --no-dll =s ../public/javascripts"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "https://github.com/instructure/jquery.git#1.7.2-with-AMD-and-CommonJS",
|
||||
|
|
Loading…
Reference in New Issue