mirror of https://github.com/laurent22/joplin.git
Desktop: Accessibility: Replacing library used for datetime with native input element (#11725)
parent
5a3d57e39a
commit
8611391d01
|
@ -9,7 +9,6 @@ import shim from '@joplin/lib/shim';
|
|||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||
import Dialog from './Dialog';
|
||||
const Datetime = require('react-datetime').default;
|
||||
const { clipboard } = require('electron');
|
||||
const formatcoords = require('formatcoords');
|
||||
|
||||
|
@ -48,6 +47,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
|||
private styleKey_: number;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
private styles_: any;
|
||||
private inputRef: React.RefObject<HTMLInputElement>;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
|
@ -55,6 +55,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
|||
this.revisionsLink_click = this.revisionsLink_click.bind(this);
|
||||
this.buttonRow_click = this.buttonRow_click.bind(this);
|
||||
this.okButton = React.createRef();
|
||||
this.inputRef = React.createRef();
|
||||
|
||||
this.state = {
|
||||
formNote: null,
|
||||
|
@ -224,13 +225,11 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
|||
});
|
||||
|
||||
shim.setTimeout(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
if ((this.refs.editField as any).openCalendar) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
(this.refs.editField as any).openCalendar();
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
focus('NotePropertiesDialog::editPropertyButtonClick', (this.refs.editField as any));
|
||||
// Opens datetime-local fields with calendar
|
||||
if (this.inputRef.current.showPicker) {
|
||||
this.inputRef.current.showPicker();
|
||||
} else if (this.inputRef.current) {
|
||||
focus('NotePropertiesDialog::editPropertyButtonClick', (this.inputRef.current));
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
@ -300,23 +299,14 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
|||
|
||||
if (this.state.editedKey === key) {
|
||||
if (key.indexOf('_time') >= 0) {
|
||||
controlComp = (
|
||||
<Datetime
|
||||
ref="editField"
|
||||
initialValue={value}
|
||||
dateFormat={time.dateFormat()}
|
||||
timeFormat={time.timeFormat()}
|
||||
inputProps={{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
onKeyDown: (event: any) => onKeyDown(event),
|
||||
style: styles.input,
|
||||
}}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
onChange={(momentObject: any) => {
|
||||
this.setState({ editedValue: momentObject });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
controlComp = <input
|
||||
type="datetime-local"
|
||||
defaultValue={value}
|
||||
ref={this.inputRef}
|
||||
onChange={event => this.setState({ editedValue: event.target.value })}
|
||||
onKeyDown={event => onKeyDown(event)}
|
||||
style={styles.input}
|
||||
/>;
|
||||
|
||||
editCompHandler = () => {
|
||||
void this.saveProperty();
|
||||
|
@ -328,7 +318,7 @@ class NotePropertiesDialog extends React.Component<Props, State> {
|
|||
<input
|
||||
defaultValue={value}
|
||||
type="text"
|
||||
ref="editField"
|
||||
ref={this.inputRef}
|
||||
onChange={event => {
|
||||
this.setState({ editedValue: event.target.value });
|
||||
}}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import * as React from 'react';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
import time from '@joplin/lib/time';
|
||||
const Datetime = require('react-datetime').default;
|
||||
import CreatableSelect from 'react-select/creatable';
|
||||
import Select from 'react-select';
|
||||
import makeAnimated from 'react-select/animated';
|
||||
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||
import Dialog from './Dialog';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { formatDateTimeLocalToMs, isValidDate } from '@joplin/utils/time';
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
|
@ -204,16 +204,14 @@ export default class PromptDialog extends React.Component<Props, any> {
|
|||
if (this.props.onClose) {
|
||||
let outputAnswer = this.state.answer;
|
||||
if (this.props.inputType === 'datetime') {
|
||||
// outputAnswer = anythingToDate(outputAnswer);
|
||||
outputAnswer = time.anythingToDateTime(outputAnswer);
|
||||
outputAnswer = isValidDate(outputAnswer) ? formatDateTimeLocalToMs(outputAnswer) : null;
|
||||
}
|
||||
this.props.onClose(accept ? outputAnswer : null, buttonType);
|
||||
}
|
||||
this.setState({ visible: false, answer: '' });
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onChange = (event: any) => {
|
||||
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ answer: event.target.value });
|
||||
};
|
||||
|
||||
|
@ -226,11 +224,6 @@ export default class PromptDialog extends React.Component<Props, any> {
|
|||
// return m.isValid() ? m.toDate() : null;
|
||||
// }
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onDateTimeChange = (momentObject: any) => {
|
||||
this.setState({ answer: momentObject });
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onSelectChange = (newValue: any) => {
|
||||
this.setState({ answer: newValue });
|
||||
|
@ -258,8 +251,13 @@ export default class PromptDialog extends React.Component<Props, any> {
|
|||
let inputComp = null;
|
||||
|
||||
if (this.props.inputType === 'datetime') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
inputComp = <Datetime className="datetime-picker" value={this.state.answer} inputProps={{ style: styles.input }} dateFormat={time.dateFormat()} timeFormat={time.timeFormat()} onChange={(momentObject: any) => onDateTimeChange(momentObject)} />;
|
||||
inputComp = <input
|
||||
defaultValue={this.state.answer}
|
||||
onChange={onChange}
|
||||
type="datetime-local"
|
||||
className='datetime-picker'
|
||||
style={styles.input}
|
||||
/>;
|
||||
} else if (this.props.inputType === 'tags') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
inputComp = <CreatableSelect className="tag-selector" onMenuOpen={this.select_menuOpen} onMenuClose={this.select_menuClose} styles={styles.select} theme={styles.selectTheme} ref={this.answerInput_} value={this.state.answer} placeholder="" components={makeAnimated()} isMulti={true} isClearable={false} backspaceRemovesValue={true} options={this.props.autocomplete} onChange={onSelectChange} onKeyDown={(event: any) => onKeyDown(event)} />;
|
||||
|
|
|
@ -4,6 +4,7 @@ import { _ } from '@joplin/lib/locale';
|
|||
import { stateUtils } from '@joplin/lib/reducer';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import time from '@joplin/lib/time';
|
||||
import { formatMsToDateTimeLocal } from '@joplin/utils/time';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
|
@ -29,7 +30,7 @@ export const runtime = (comp: any): CommandRuntime => {
|
|||
label: _('Set alarm:'),
|
||||
inputType: 'datetime',
|
||||
buttons: ['ok', 'cancel', 'clear'],
|
||||
value: note.todo_due ? new Date(note.todo_due) : defaultDate,
|
||||
value: note.todo_due ? formatMsToDateTimeLocal(note.todo_due) : formatMsToDateTimeLocal(defaultDate.getTime()),
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
onClose: async (answer: any, buttonType: string) => {
|
||||
let newNote: NoteEntity = null;
|
||||
|
@ -42,7 +43,7 @@ export const runtime = (comp: any): CommandRuntime => {
|
|||
} else if (answer !== null) {
|
||||
newNote = {
|
||||
id: note.id,
|
||||
todo_due: answer.getTime(),
|
||||
todo_due: answer,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,6 @@
|
|||
"pretty-bytes": "5.6.0",
|
||||
"re-resizable": "6.9.17",
|
||||
"react": "18.3.1",
|
||||
"react-datetime": "3.2.0",
|
||||
"react-dom": "18.3.1",
|
||||
"react-redux": "8.1.3",
|
||||
"react-select": "5.8.0",
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
// See https://sasscss.org/documentation/at-rules/import#plain-css-imports.
|
||||
@import url('style/icons/style.css');
|
||||
@import url('vendor/lib/@fortawesome/fontawesome-free/css/all.min.css');
|
||||
@import url('vendor/lib/react-datetime/css/react-datetime.css');
|
||||
@import url('vendor/lib/smalltalk/css/smalltalk.css');
|
||||
@import url('vendor/lib/roboto-fontface/css/roboto/roboto-fontface.css');
|
||||
@import url('vendor/lib/codemirror/lib/codemirror.css');
|
||||
|
|
|
@ -85,7 +85,6 @@ async function main() {
|
|||
'codemirror/addon/dialog/dialog.css',
|
||||
'codemirror/lib/codemirror.css',
|
||||
'mark.js/dist/mark.min.js',
|
||||
'react-datetime/css/react-datetime.css',
|
||||
'roboto-fontface/css/roboto/roboto-fontface.css',
|
||||
'smalltalk/css/smalltalk.css',
|
||||
'smalltalk/dist/smalltalk.min.js',
|
||||
|
|
|
@ -145,3 +145,15 @@ export const formatMsToLocal = (ms: number, format: string|null = null) => {
|
|||
if (format === null) format = dateTimeFormat();
|
||||
return dayjs(ms).format(format);
|
||||
};
|
||||
|
||||
export const formatMsToDateTimeLocal = (ms: number) => {
|
||||
return formatMsToLocal(ms, 'YYYY-MM-DDTHH:mm');
|
||||
};
|
||||
|
||||
export const isValidDate = (anything: string) => {
|
||||
return dayjs(anything).isValid();
|
||||
};
|
||||
|
||||
export const formatDateTimeLocalToMs = (anything: string) => {
|
||||
return dayjs(anything).unix() * 1000;
|
||||
};
|
||||
|
|
15
yarn.lock
15
yarn.lock
|
@ -8324,7 +8324,6 @@ __metadata:
|
|||
pretty-bytes: 5.6.0
|
||||
re-resizable: 6.9.17
|
||||
react: 18.3.1
|
||||
react-datetime: 3.2.0
|
||||
react-dom: 18.3.1
|
||||
react-redux: 8.1.3
|
||||
react-select: 5.8.0
|
||||
|
@ -39081,7 +39080,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
|
||||
"prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
|
||||
version: 15.7.2
|
||||
resolution: "prop-types@npm:15.7.2"
|
||||
dependencies:
|
||||
|
@ -39576,18 +39575,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-datetime@npm:3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "react-datetime@npm:3.2.0"
|
||||
dependencies:
|
||||
prop-types: ^15.5.7
|
||||
peerDependencies:
|
||||
moment: ^2.16.0
|
||||
react: ^16.5.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: c3407beb64f44cd5944252bee1c4565fc138e3f1e81d8e4fd00d2aeac564a18848ee9af5f51fbbb39bba588f8c2d659570384af1ce8378d4e0049a6bdb083655
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dev-utils@npm:^12.0.1":
|
||||
version: 12.0.1
|
||||
resolution: "react-dev-utils@npm:12.0.1"
|
||||
|
|
Loading…
Reference in New Issue