@jetbrains/ring-ui 7.0.124 → 8.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/babel.config.js +1 -9
- package/components/auth-dialog-service/auth-dialog-service.js +2 -2
- package/components/avatar/avatar-info.js +0 -2
- package/components/avatar/avatar-size.d.ts +0 -4
- package/components/avatar/avatar-size.js +0 -4
- package/components/avatar/avatar.js +0 -6
- package/components/avatar/fallback-avatar.js +0 -28
- package/components/avatar-stack/avatar-stack.js +1 -1
- package/components/button/button.css +4 -4
- package/components/button/button.d.ts +0 -4
- package/components/button/button.js +2 -7
- package/components/button-group/button-group.css +23 -23
- package/components/button-toolbar/button-toolbar.css +2 -2
- package/components/checkbox/checkbox.d.ts +1 -1
- package/components/collapse/collapse-content.js +7 -16
- package/components/collapse/collapse-context.d.ts +1 -0
- package/components/collapse/collapse-context.js +1 -0
- package/components/collapse/collapse-control.js +2 -2
- package/components/collapse/collapse.css +8 -2
- package/components/collapse/collapse.js +10 -2
- package/components/collapsible-group/collapsible-group.css +1 -1
- package/components/collapsible-group/collapsible-group.d.ts +5 -1
- package/components/collapsible-group/collapsible-group.js +13 -22
- package/components/confirm-service/confirm-service.js +2 -2
- package/components/contenteditable/contenteditable.js +1 -2
- package/components/data-list/data-list.d.ts +4 -4
- package/components/data-list/data-list.js +2 -2
- package/components/data-list/data-list.mock.d.ts +1 -1
- package/components/data-list/item.d.ts +1 -1
- package/components/data-list/selection.d.ts +1 -1
- package/components/data-list/selection.js +1 -1
- package/components/date-picker/month.d.ts +0 -2
- package/components/date-picker/month.js +5 -5
- package/components/date-picker/months.js +8 -7
- package/components/date-picker/use-scroll-behavior.js +5 -6
- package/components/date-picker/years.js +11 -10
- package/components/dialog/dialog.d.ts +2 -2
- package/components/dialog/dialog.js +2 -2
- package/components/dropdown-menu/dropdown-menu.d.ts +4 -4
- package/components/dropdown-menu/dropdown-menu.js +4 -4
- package/components/editable-heading/editable-heading.d.ts +1 -2
- package/components/editable-heading/editable-heading.js +5 -6
- package/components/global/compose-refs.d.ts +2 -1
- package/components/global/compose-refs.js +24 -8
- package/components/global/configuration.d.ts +0 -5
- package/components/global/configuration.js +0 -7
- package/components/global/create-stateful-context.js +5 -5
- package/components/global/focus-with-temporary-tabindex.d.ts +11 -0
- package/components/global/focus-with-temporary-tabindex.js +21 -0
- package/components/global/intersection-observer-context.d.ts +46 -0
- package/components/global/intersection-observer-context.js +91 -0
- package/components/global/is-within-interactive-element.d.ts +6 -0
- package/components/global/is-within-interactive-element.js +26 -0
- package/components/global/is-within-navigable-element.d.ts +6 -0
- package/components/global/is-within-navigable-element.js +27 -0
- package/components/global/parse-css-duration.d.ts +5 -0
- package/components/global/parse-css-duration.js +13 -0
- package/components/global/rerender-hoc.d.ts +4 -2
- package/components/global/rerender-hoc.js +4 -4
- package/components/global/schedule-with-cleanup.d.ts +12 -0
- package/components/global/schedule-with-cleanup.js +34 -0
- package/components/{table/selection.d.ts → global/table-selection.d.ts} +15 -15
- package/components/{table/selection.js → global/table-selection.js} +3 -3
- package/components/global/theme.d.ts +4 -3
- package/components/global/theme.js +8 -8
- package/components/global/variables.css +0 -10
- package/components/global/variables.interface.d.ts +0 -4
- package/components/global/variables_dark.css +0 -7
- package/components/i18n/i18n-context.js +1 -1
- package/components/icon/icon-svg.js +2 -3
- package/components/icon/icon.css +0 -27
- package/components/icon/icon.d.ts +0 -1
- package/components/icon/icon.js +2 -4
- package/components/input/input.d.ts +1 -1
- package/components/island/adaptive-island-hoc.js +4 -4
- package/components/island/content.d.ts +7 -2
- package/components/island/content.js +5 -5
- package/components/{table → legacy-table}/cell.js +1 -1
- package/components/{table → legacy-table}/header-cell.js +1 -1
- package/components/{table → legacy-table}/header.js +1 -1
- package/components/legacy-table/legacy-table.css +260 -0
- package/components/{table → legacy-table}/multitable.d.ts +1 -1
- package/components/{table → legacy-table}/row.d.ts +1 -1
- package/components/{table → legacy-table}/row.js +1 -1
- package/components/legacy-table/selection-adapter.d.ts +6 -0
- package/components/{table → legacy-table}/selection-shortcuts-hoc.d.ts +5 -5
- package/components/{table → legacy-table}/simple-table.d.ts +2 -2
- package/components/{table → legacy-table}/simple-table.js +3 -3
- package/components/{table → legacy-table}/smart-table.d.ts +5 -5
- package/components/{table → legacy-table}/smart-table.js +3 -3
- package/components/legacy-table/table.d.ts +109 -0
- package/components/legacy-table/table.js +191 -0
- package/components/list/consts.d.ts +0 -1
- package/components/list/consts.js +0 -1
- package/components/list/list.d.ts +0 -4
- package/components/login-dialog/service.js +2 -2
- package/components/popup/popup.target.d.ts +3 -2
- package/components/popup/popup.target.js +4 -6
- package/components/query-assist/query-assist.d.ts +3 -1
- package/components/query-assist/query-assist.js +2 -2
- package/components/radio/radio-item.d.ts +3 -3
- package/components/radio/radio-item.js +3 -4
- package/components/radio/radio.d.ts +2 -2
- package/components/radio/radio.js +1 -1
- package/components/select/select-popup.d.ts +3 -2
- package/components/select/select-popup.js +3 -3
- package/components/select/select.d.ts +6 -2
- package/components/select/select.js +2 -4
- package/components/selection-toolbar/selection-toolbar.css +86 -0
- package/components/selection-toolbar/selection-toolbar.d.ts +11 -0
- package/components/selection-toolbar/selection-toolbar.js +23 -0
- package/components/slider/slider.js +4 -5
- package/components/tab-trap/tab-trap.d.ts +3 -3
- package/components/tab-trap/tab-trap.js +3 -5
- package/components/table/default-item-renderer.d.ts +55 -0
- package/components/table/default-item-renderer.js +77 -0
- package/components/table/internal/reorder-animation-context.d.ts +21 -0
- package/components/table/internal/reorder-animation-context.js +60 -0
- package/components/table/internal/reorder-handle.d.ts +9 -0
- package/components/table/internal/reorder-handle.js +334 -0
- package/components/table/internal/reorder-layout-context.d.ts +16 -0
- package/components/table/internal/reorder-layout-context.js +69 -0
- package/components/table/internal/table-header.d.ts +1 -0
- package/components/table/internal/table-header.js +143 -0
- package/components/table/internal/virtualization.d.ts +41 -0
- package/components/table/internal/virtualization.js +186 -0
- package/components/table/item-virtualization.d.ts +37 -0
- package/components/table/item-virtualization.js +26 -0
- package/components/table/reorder-animation.d.ts +37 -0
- package/components/table/reorder-animation.js +11 -0
- package/components/table/reorder-item-layout.d.ts +32 -0
- package/components/table/reorder-item-layout.js +23 -0
- package/components/table/table-const.d.ts +10 -0
- package/components/table/table-const.js +10 -0
- package/components/table/table-primitives.d.ts +64 -0
- package/components/table/table-primitives.js +34 -0
- package/components/table/table-props.d.ts +304 -0
- package/components/table/table-props.js +1 -0
- package/components/table/table.css +156 -167
- package/components/table/table.d.ts +231 -107
- package/components/table/table.js +319 -183
- package/components/tags-input/tags-input.d.ts +3 -1
- package/components/tooltip/tooltip.d.ts +2 -1
- package/components/tooltip/tooltip.js +6 -5
- package/components/upload/upload.d.ts +4 -3
- package/components/upload/upload.js +3 -7
- package/components/user-agreement/service.js +2 -2
- package/components/util-stories.d.ts +26 -0
- package/components/util-stories.js +61 -0
- package/package.json +45 -48
- package/components/content-layout/content-layout.css +0 -109
- package/components/content-layout/content-layout.d.ts +0 -20
- package/components/content-layout/content-layout.js +0 -40
- package/components/content-layout/sidebar.d.ts +0 -26
- package/components/content-layout/sidebar.js +0 -71
- package/components/date-picker/use-intersection-observer.d.ts +0 -6
- package/components/date-picker/use-intersection-observer.js +0 -48
- package/components/expand/collapsible-group.css +0 -76
- package/components/expand/collapsible-group.d.ts +0 -8
- package/components/expand/collapsible-group.js +0 -14
- package/components/global/composeRefs.d.ts +0 -6
- package/components/global/composeRefs.js +0 -7
- package/components/global/use-event-callback.d.ts +0 -4
- package/components/global/use-event-callback.js +0 -20
- package/components/grid/col.d.ts +0 -16
- package/components/grid/col.js +0 -35
- package/components/grid/grid.css +0 -920
- package/components/grid/grid.d.ts +0 -13
- package/components/grid/grid.js +0 -19
- package/components/grid/row.d.ts +0 -21
- package/components/grid/row.js +0 -41
- package/components/old-browsers-message/__mocks__/old-browsers-message.js +0 -1
- package/components/old-browsers-message/old-browsers-message-stop.d.ts +0 -1
- package/components/old-browsers-message/old-browsers-message-stop.js +0 -2
- package/components/old-browsers-message/old-browsers-message.css +0 -26
- package/components/old-browsers-message/old-browsers-message.d.ts +0 -5
- package/components/old-browsers-message/old-browsers-message.js +0 -86
- package/components/old-browsers-message/white-list.d.ts +0 -2
- package/components/old-browsers-message/white-list.js +0 -24
- package/components/table/selection-adapter.d.ts +0 -6
- /package/components/{table → legacy-table}/cell.d.ts +0 -0
- /package/components/{table → legacy-table}/disable-hover-hoc.d.ts +0 -0
- /package/components/{table → legacy-table}/disable-hover-hoc.js +0 -0
- /package/components/{table → legacy-table}/header-cell.d.ts +0 -0
- /package/components/{table → legacy-table}/header.d.ts +0 -0
- /package/components/{table → legacy-table}/multitable.js +0 -0
- /package/components/{table → legacy-table}/row-with-focus-sensor.d.ts +0 -0
- /package/components/{table → legacy-table}/row-with-focus-sensor.js +0 -0
- /package/components/{table → legacy-table}/selection-adapter.js +0 -0
- /package/components/{table → legacy-table}/selection-shortcuts-hoc.js +0 -0
- /package/components/{table → legacy-table}/table.examples2.json +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { use, useState } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import chevronRightIcon from '@jetbrains/icons/chevron-12px-right';
|
|
4
4
|
import chevronDownIcon from '@jetbrains/icons/chevron-12px-down';
|
|
@@ -8,7 +8,7 @@ import CollapseContent from '../collapse/collapse-content';
|
|
|
8
8
|
import { CollapseContext } from '../collapse/collapse-context';
|
|
9
9
|
import styles from './collapsible-group.css';
|
|
10
10
|
function CollapsibleGroupHeaderContent({ avatar, titleContent, subtitle }) {
|
|
11
|
-
const { collapsed } =
|
|
11
|
+
const { collapsed } = use(CollapseContext);
|
|
12
12
|
return (<span className={styles.header}>
|
|
13
13
|
<span className={styles.headerContent}>
|
|
14
14
|
<span className={styles.avatarGroup}>
|
|
@@ -26,7 +26,7 @@ function CollapsibleGroupHeaderContent({ avatar, titleContent, subtitle }) {
|
|
|
26
26
|
</span>);
|
|
27
27
|
}
|
|
28
28
|
function CollapsibleGroupHeader({ avatar, titleContent, subtitle, ...buttonProps }) {
|
|
29
|
-
const { setCollapsed, collapsed, id } =
|
|
29
|
+
const { setCollapsed, collapsed, id } = use(CollapseContext);
|
|
30
30
|
return (<button type='button' {...buttonProps} className={styles.headerButton} onClick={setCollapsed} aria-controls={`collapse-content-${id}`} aria-expanded={!collapsed}>
|
|
31
31
|
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
32
32
|
</button>);
|
|
@@ -36,10 +36,9 @@ function CollapsibleGroupHeaderStatic({ avatar, titleContent, subtitle }) {
|
|
|
36
36
|
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
37
37
|
</span>);
|
|
38
38
|
}
|
|
39
|
-
const CollapsibleGroup =
|
|
39
|
+
const CollapsibleGroup = ({ ref, avatar, title, subtitle, children, className, defaultExpanded = false, expanded = null, onChange = () => { }, disableAnimation = false, interactive = true, keepMounted = false, headingLevel, 'data-test': dataTest, }) => {
|
|
40
40
|
const [innerExpanded, setInnerExpanded] = useState(defaultExpanded);
|
|
41
41
|
const [hovered, setHovered] = useState(false);
|
|
42
|
-
const [focused, setFocused] = useState(false);
|
|
43
42
|
const isExpanded = expanded ?? innerExpanded;
|
|
44
43
|
const handleChange = (collapsed) => {
|
|
45
44
|
const nextExpanded = !collapsed;
|
|
@@ -48,27 +47,19 @@ const CollapsibleGroup = forwardRef(({ avatar, title, subtitle, children, classN
|
|
|
48
47
|
}
|
|
49
48
|
onChange(nextExpanded);
|
|
50
49
|
};
|
|
51
|
-
const onBlur = (event) => {
|
|
52
|
-
const nextTarget = event.relatedTarget;
|
|
53
|
-
if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
setFocused(false);
|
|
57
|
-
};
|
|
58
50
|
const classes = classNames(styles.expand, className, {
|
|
59
51
|
[styles.hovered]: hovered,
|
|
60
52
|
[styles.expanded]: isExpanded,
|
|
61
|
-
[styles.focused]: focused,
|
|
62
53
|
});
|
|
63
|
-
const header = interactive ? (<CollapsibleGroupHeader avatar={avatar} titleContent={title} subtitle={subtitle} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}
|
|
54
|
+
const header = interactive ? (<CollapsibleGroupHeader avatar={avatar} titleContent={title} subtitle={subtitle} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}/>) : (<CollapsibleGroupHeaderStatic avatar={avatar} titleContent={title} subtitle={subtitle}/>);
|
|
64
55
|
return (<div ref={ref} className={classes} data-test={dataTest}>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
56
|
+
<Collapse defaultCollapsed={!defaultExpanded} collapsed={expanded == null ? null : !expanded} onChange={handleChange} disableAnimation={disableAnimation} keepMounted={keepMounted} className={styles.collapseRoot}>
|
|
57
|
+
{headingLevel != null ? React.createElement(`h${headingLevel}`, { className: styles.heading }, header) : header}
|
|
58
|
+
<CollapseContent>
|
|
59
|
+
<div className={styles.body}>{children}</div>
|
|
60
|
+
</CollapseContent>
|
|
61
|
+
</Collapse>
|
|
62
|
+
</div>);
|
|
63
|
+
};
|
|
73
64
|
CollapsibleGroup.displayName = 'CollapsibleGroup';
|
|
74
65
|
export default CollapsibleGroup;
|
|
@@ -8,9 +8,9 @@ export const reactRoot = createRoot(containerElement);
|
|
|
8
8
|
*/
|
|
9
9
|
function renderConfirm(props) {
|
|
10
10
|
const { buttonsHeight = getGlobalControlsHeight(), ...restProps } = props;
|
|
11
|
-
reactRoot.render(<ControlsHeightContext
|
|
11
|
+
reactRoot.render(<ControlsHeightContext value={buttonsHeight}>
|
|
12
12
|
<Confirm {...restProps}/>
|
|
13
|
-
</ControlsHeightContext
|
|
13
|
+
</ControlsHeightContext>);
|
|
14
14
|
}
|
|
15
15
|
export default function confirm({ text, description, confirmLabel = 'OK', rejectLabel = 'Cancel', cancelIsDefault, onBeforeConfirm, buttonsHeight, }) {
|
|
16
16
|
return new Promise((resolve, reject) => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Component } from 'react';
|
|
2
2
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
3
|
-
import { getTrustedHTML } from '../global/configuration';
|
|
4
3
|
/**
|
|
5
4
|
* @name ContentEditable
|
|
6
5
|
*/
|
|
@@ -24,7 +23,7 @@ class ContentEditableBase extends Component {
|
|
|
24
23
|
return (<div {...props} ref={inputRef}
|
|
25
24
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
26
25
|
// @ts-ignore
|
|
27
|
-
disabled={disabled} role='textbox' tabIndex={disabled ? undefined : tabIndex} contentEditable={!this.props.disabled} dangerouslySetInnerHTML={{ __html
|
|
26
|
+
disabled={disabled} role='textbox' tabIndex={disabled ? undefined : tabIndex} contentEditable={!this.props.disabled} dangerouslySetInnerHTML={{ __html }}/>);
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
const ContentEditable = ({ children, ...props }) => (<ContentEditableBase {...props} __html={renderToStaticMarkup(children)}/>);
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { Component } from 'react';
|
|
5
5
|
import { type FocusSensorOuterProps } from '../global/focus-sensor-hoc';
|
|
6
|
-
import { type SelectionShortcutsAddProps, type SelectionShortcutsOuterProps } from '../table/selection-shortcuts-hoc';
|
|
7
|
-
import { type DisableHoverAddProps } from '../table/disable-hover-hoc';
|
|
8
|
-
import { type SelectionItem } from '../table
|
|
6
|
+
import { type SelectionShortcutsAddProps, type SelectionShortcutsOuterProps } from '../legacy-table/selection-shortcuts-hoc';
|
|
7
|
+
import { type DisableHoverAddProps } from '../legacy-table/disable-hover-hoc';
|
|
8
|
+
import { type SelectionItem } from '../global/table-selection';
|
|
9
9
|
import { type FormattedItem, moreLessButtonStates } from './item';
|
|
10
10
|
export interface DataListBaseProps<T extends SelectionItem> {
|
|
11
11
|
data: readonly T[];
|
|
@@ -20,7 +20,7 @@ export interface DataListBaseProps<T extends SelectionItem> {
|
|
|
20
20
|
type FocusableProps<T extends SelectionItem> = DataListBaseProps<T> & DisableHoverAddProps & FocusSensorOuterProps<HTMLDivElement> & SelectionShortcutsAddProps<T>;
|
|
21
21
|
export type DataListContainerProps<T extends SelectionItem> = DataListBaseProps<T> & FocusSensorOuterProps<HTMLDivElement> & SelectionShortcutsOuterProps<T>;
|
|
22
22
|
export default class DataListContainer<T extends SelectionItem> extends Component<DataListContainerProps<T>> {
|
|
23
|
-
DataList: import("react").ComponentClass<import("../table/disable-hover-hoc").DisableHoverProps<import("../table/selection-shortcuts-hoc").SelectionShortcutsProps<T, FocusableProps<T>>>, any>;
|
|
23
|
+
DataList: import("react").ComponentClass<import("../legacy-table/disable-hover-hoc").DisableHoverProps<import("../legacy-table/selection-shortcuts-hoc").SelectionShortcutsProps<T, FocusableProps<T>>>, any>;
|
|
24
24
|
render(): import("react").JSX.Element;
|
|
25
25
|
}
|
|
26
26
|
export {};
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { PureComponent, Component } from 'react';
|
|
5
5
|
import classNames from 'classnames';
|
|
6
6
|
import focusSensorHOC from '../global/focus-sensor-hoc';
|
|
7
|
-
import selectionShortcutsHOC from '../table/selection-shortcuts-hoc';
|
|
8
|
-
import disableHoverHOC from '../table/disable-hover-hoc';
|
|
7
|
+
import selectionShortcutsHOC from '../legacy-table/selection-shortcuts-hoc';
|
|
8
|
+
import disableHoverHOC from '../legacy-table/disable-hover-hoc';
|
|
9
9
|
import getUID from '../global/get-uid';
|
|
10
10
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
11
11
|
import Loader from '../loader/loader';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PureComponent, type ReactNode } from 'react';
|
|
2
|
-
import { type SelectionItem } from '../table
|
|
2
|
+
import { type SelectionItem } from '../global/table-selection';
|
|
3
3
|
import type Selection from './selection';
|
|
4
4
|
export declare enum moreLessButtonStates {
|
|
5
5
|
UNUSED = 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import TableSelection, { type CloneWithConfig, type SelectionItem, type TableSelectionConfig } from '../table
|
|
1
|
+
import TableSelection, { type CloneWithConfig, type SelectionItem, type TableSelectionConfig } from '../global/table-selection';
|
|
2
2
|
interface DataListSelectionConfig<T extends SelectionItem> extends TableSelectionConfig<T> {
|
|
3
3
|
partialSelected?: Set<T> | undefined;
|
|
4
4
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { type Locale } from 'date-fns';
|
|
2
2
|
import { type MonthsProps } from './consts';
|
|
3
|
-
import { type IntersectionObserverHandle } from './use-intersection-observer';
|
|
4
3
|
export interface MonthProps extends MonthsProps {
|
|
5
4
|
month: Date;
|
|
6
|
-
intersectionObserverHandle: IntersectionObserverHandle | null;
|
|
7
5
|
}
|
|
8
6
|
export default function Month(props: MonthProps): import("react").JSX.Element;
|
|
9
7
|
export declare function getMonthHeight(monthStart: Date | number, locale: Locale | undefined): number;
|
|
@@ -4,14 +4,14 @@ import { getDaysInMonth, setDate } from 'date-fns';
|
|
|
4
4
|
import { useRef } from 'react';
|
|
5
5
|
import Day from './day';
|
|
6
6
|
import units, { WEEK, getWeekStartsOn } from './consts';
|
|
7
|
-
import {
|
|
7
|
+
import { useIsIntersecting } from '../global/intersection-observer-context';
|
|
8
8
|
import styles from './date-picker.css';
|
|
9
9
|
export default function Month(props) {
|
|
10
|
-
const { month, locale
|
|
10
|
+
const { month, locale } = props;
|
|
11
11
|
const containerRef = useRef(null);
|
|
12
|
-
const
|
|
13
|
-
return (<div className={styles.month} ref={containerRef} style={
|
|
14
|
-
{
|
|
12
|
+
const isIntersecting = useIsIntersecting(containerRef);
|
|
13
|
+
return (<div className={styles.month} ref={containerRef} style={isIntersecting ? {} : { height: getMonthHeight(month, locale) }}>
|
|
14
|
+
{isIntersecting && (<>
|
|
15
15
|
<span className={styles.monthTitle}>{format(month, 'LLLL', { locale })}</span>
|
|
16
16
|
|
|
17
17
|
{Array.from({ length: getPaddingCellsNum(month, locale) }, (_, i) => (<Day {...props} day={new Date(0)} empty key={`e_${i}`}/>))}
|
|
@@ -5,7 +5,7 @@ import units from './consts';
|
|
|
5
5
|
import { ScrollArith } from './scroll-arith';
|
|
6
6
|
import { useScrollBehavior } from './use-scroll-behavior';
|
|
7
7
|
import scheduleRAF from '../global/schedule-raf';
|
|
8
|
-
import {
|
|
8
|
+
import { useIntersectionObserverHandle, IntersectionObserverContext } from '../global/intersection-observer-context';
|
|
9
9
|
import styles from './date-picker.css';
|
|
10
10
|
function getMonthHeightWithMargin(date, locale) {
|
|
11
11
|
return units.unit * 2 + getMonthHeight(date, locale);
|
|
@@ -23,14 +23,15 @@ const scheduleScroll = scheduleRAF();
|
|
|
23
23
|
*
|
|
24
24
|
* To avoid an unpainted gap at the viewport boundary, the next month must be reported
|
|
25
25
|
* as visible slightly before it actually enters the viewport. We achieve this by
|
|
26
|
-
* extending the IntersectionObserver
|
|
26
|
+
* extending the IntersectionObserver rootMargin.
|
|
27
27
|
*/
|
|
28
|
-
const
|
|
28
|
+
const intersectionObserverRootMargin = units.cellSize * 2;
|
|
29
29
|
export default function Months(props) {
|
|
30
30
|
const { scrollDate, setScrollDate, locale } = props;
|
|
31
31
|
const { containerRef, items } = useScrollBehavior(scrollDate, setScrollDate, locale, 'monthsScroll', scrollArith, scheduleScroll);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
return (<IntersectionObserverContext value={useIntersectionObserverHandle(containerRef, intersectionObserverRootMargin)}>
|
|
33
|
+
<div className={styles.months} ref={containerRef} data-test='ring-date-popup--months'>
|
|
34
|
+
{items.map(month => (<Month {...props} month={month} key={+month}/>))}
|
|
35
|
+
</div>
|
|
36
|
+
</IntersectionObserverContext>);
|
|
36
37
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useEffect, useEffectEvent, useLayoutEffect, useRef, useState } from 'react';
|
|
2
2
|
import units, { isSafariOnIPhone, scrollerReRenderDelayIPhone } from './consts';
|
|
3
|
-
import useEventCallback from '../global/use-event-callback';
|
|
4
3
|
export function useScrollBehavior(scrollDate, onContainerScroll, locale, selfScrollDateSource, arith, scheduleScroll) {
|
|
5
4
|
const [items, setItems] = useState(() => arith.getItems(scrollDate.date));
|
|
6
5
|
const [scrollTop, setScrollTop] = useState(() => arith.getScrollTop(items, scrollDate.date, locale));
|
|
7
6
|
const containerRef = useRef(null);
|
|
8
|
-
const syncSelfState =
|
|
7
|
+
const syncSelfState = useEffectEvent((newScrollDate) => {
|
|
9
8
|
const newScrollTopOnExistingItems = arith.getScrollTop(items, newScrollDate, locale);
|
|
10
9
|
if (isNearEdge(newScrollTopOnExistingItems, containerRef.current)) {
|
|
11
10
|
const { newItems, newScrollTop } = arith.getItemsAndScrollTop(newScrollDate, locale);
|
|
@@ -28,7 +27,7 @@ export function useScrollBehavior(scrollDate, onContainerScroll, locale, selfScr
|
|
|
28
27
|
if (scrollDate.source === selfScrollDateSource)
|
|
29
28
|
return;
|
|
30
29
|
syncSelfState(scrollDate.date);
|
|
31
|
-
}, [scrollDate, selfScrollDateSource
|
|
30
|
+
}, [scrollDate, selfScrollDateSource]);
|
|
32
31
|
const ignoreNextScrollEventRef = useRef(true);
|
|
33
32
|
useLayoutEffect(function setContainerScrollFromState() {
|
|
34
33
|
const container = containerRef.current;
|
|
@@ -38,7 +37,7 @@ export function useScrollBehavior(scrollDate, onContainerScroll, locale, selfScr
|
|
|
38
37
|
container.scrollTop = scrollTop;
|
|
39
38
|
}, [items, scrollTop]);
|
|
40
39
|
const updateStateTimerRef = useRef(null);
|
|
41
|
-
const handleScroll =
|
|
40
|
+
const handleScroll = useEffectEvent(() => {
|
|
42
41
|
scheduleScroll(() => {
|
|
43
42
|
if (updateStateTimerRef.current != null) {
|
|
44
43
|
window.clearTimeout(updateStateTimerRef.current);
|
|
@@ -83,7 +82,7 @@ export function useScrollBehavior(scrollDate, onContainerScroll, locale, selfScr
|
|
|
83
82
|
updateStateTimerRef.current = null;
|
|
84
83
|
}
|
|
85
84
|
};
|
|
86
|
-
}, [
|
|
85
|
+
}, []);
|
|
87
86
|
return { containerRef, items };
|
|
88
87
|
}
|
|
89
88
|
function isNearEdge(scrollTop, container) {
|
|
@@ -12,7 +12,7 @@ import { ScrollArith } from './scroll-arith';
|
|
|
12
12
|
import { useScrollBehavior } from './use-scroll-behavior';
|
|
13
13
|
import { animateDate } from './animate-date';
|
|
14
14
|
import scheduleRAF from '../global/schedule-raf';
|
|
15
|
-
import {
|
|
15
|
+
import { IntersectionObserverContext, useIntersectionObserverHandle, useIsIntersecting, } from '../global/intersection-observer-context';
|
|
16
16
|
import styles from './date-picker.css';
|
|
17
17
|
const { yearHeight } = units;
|
|
18
18
|
const scrollArith = new ScrollArith({
|
|
@@ -25,7 +25,7 @@ const scheduleScroll = scheduleRAF();
|
|
|
25
25
|
/**
|
|
26
26
|
* Reduces "empty" years during fast scrolling.
|
|
27
27
|
*/
|
|
28
|
-
const
|
|
28
|
+
const intersectionObserverRootMargin = units.calHeight / 2;
|
|
29
29
|
export default function Years({ scrollDate, setScrollDate }) {
|
|
30
30
|
const [localScrollDate, setLocalScrollDate] = useState(scrollDate);
|
|
31
31
|
const syncCleanupRef = useRef(null);
|
|
@@ -87,15 +87,16 @@ export default function Years({ scrollDate, setScrollDate }) {
|
|
|
87
87
|
}, yearsAnimationDuration);
|
|
88
88
|
}, [localScrollDate.date, setScrollDate]);
|
|
89
89
|
const { containerRef, items } = useScrollBehavior(localScrollDate, syncCalendarScrollDate, undefined, 'yearsScroll', scrollArith, scheduleScroll);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
return (<IntersectionObserverContext value={useIntersectionObserverHandle(containerRef, intersectionObserverRootMargin)}>
|
|
91
|
+
<div className={styles.years} ref={containerRef} data-test='ring-date-popup--years'>
|
|
92
|
+
{items.map(year => (<Year year={year} scrollDate={localScrollDate.date} handleYearClick={handleYearClick} key={+year}/>))}
|
|
93
|
+
</div>
|
|
94
|
+
</IntersectionObserverContext>);
|
|
94
95
|
}
|
|
95
|
-
function Year({ year, scrollDate, handleYearClick,
|
|
96
|
+
function Year({ year, scrollDate, handleYearClick, }) {
|
|
96
97
|
const buttonRef = useRef(null);
|
|
97
|
-
const
|
|
98
|
-
return (<button type='button' ref={buttonRef} key={+year} disabled={!
|
|
99
|
-
{
|
|
98
|
+
const isIntersecting = useIsIntersecting(buttonRef);
|
|
99
|
+
return (<button type='button' ref={buttonRef} key={+year} disabled={!isIntersecting} className={classNames(styles.year, isIntersecting && isSameYear(year, scrollDate) && styles.currentYear, isIntersecting && isThisYear(year) && styles.today)} onClick={isIntersecting ? () => handleYearClick(year) : undefined}>
|
|
100
|
+
{isIntersecting ? format(year, 'yyyy') : '\u00A0'}
|
|
100
101
|
</button>);
|
|
101
102
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PureComponent } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import
|
|
3
|
+
import { type TabTrapObject, type TabTrapProps } from '../tab-trap/tab-trap';
|
|
4
4
|
import type { ShortcutsScopeOptions } from '../shortcuts/core';
|
|
5
5
|
export interface DialogProps extends Partial<TabTrapProps> {
|
|
6
6
|
show: boolean;
|
|
@@ -43,7 +43,7 @@ export default class Dialog extends PureComponent<DialogProps> {
|
|
|
43
43
|
esc: (event: KeyboardEvent) => void;
|
|
44
44
|
};
|
|
45
45
|
dialog?: HTMLElement | null;
|
|
46
|
-
dialogRef: (
|
|
46
|
+
dialogRef: (tabTrapObj: TabTrapObject | null) => void;
|
|
47
47
|
nativeDialog: React.RefObject<HTMLDialogElement | null>;
|
|
48
48
|
render(): false | React.JSX.Element;
|
|
49
49
|
}
|
|
@@ -104,8 +104,8 @@ export default class Dialog extends PureComponent {
|
|
|
104
104
|
};
|
|
105
105
|
};
|
|
106
106
|
dialog;
|
|
107
|
-
dialogRef = (
|
|
108
|
-
this.dialog =
|
|
107
|
+
dialogRef = (tabTrapObj) => {
|
|
108
|
+
this.dialog = tabTrapObj && tabTrapObj.node;
|
|
109
109
|
};
|
|
110
110
|
nativeDialog = createRef();
|
|
111
111
|
render() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactElement, type HTMLAttributes, type SyntheticEvent, type
|
|
1
|
+
import { type ReactElement, type HTMLAttributes, type SyntheticEvent, type ReactNode } from 'react';
|
|
2
2
|
import { type SelectHandlerParams } from '../list/list';
|
|
3
3
|
import { type AnchorProps, type DropdownAttrs, type DropdownChildrenFunction } from '../dropdown/dropdown';
|
|
4
4
|
import PopupMenu, { type PopupMenuAttrs } from '../popup-menu/popup-menu';
|
|
@@ -10,6 +10,7 @@ export interface DropdownAnchorWrapperProps extends AnchorProps {
|
|
|
10
10
|
}
|
|
11
11
|
type OnSelectHandler<T> = ((item: ListDataItem<T>, event: Event | SyntheticEvent, params?: SelectHandlerParams) => void) | undefined;
|
|
12
12
|
export interface DropdownMenuProps<T = unknown> extends Omit<DropdownAttrs, 'anchor' | 'onSelect' | 'children'> {
|
|
13
|
+
ref?: React.Ref<PopupMenu<T> | null>;
|
|
13
14
|
anchor: ReactElement | ReactNode[] | string | ((props: AnchorProps, ariaProps: HTMLAttributes<HTMLElement>) => ReactElement | null);
|
|
14
15
|
data?: readonly ListDataItem<T>[] | undefined;
|
|
15
16
|
ariaLabel?: string | null | undefined;
|
|
@@ -17,9 +18,8 @@ export interface DropdownMenuProps<T = unknown> extends Omit<DropdownAttrs, 'anc
|
|
|
17
18
|
menuProps?: PopupMenuAttrs<T> | null | undefined;
|
|
18
19
|
children?: DropdownChildrenFunction;
|
|
19
20
|
}
|
|
20
|
-
declare
|
|
21
|
-
|
|
22
|
-
}) => ReactElement | null) & {
|
|
21
|
+
declare function DropdownMenu<T = unknown>({ ref, id, anchor, ariaLabel, data, onSelect, menuProps, children, ...restDropdownProps }: DropdownMenuProps<T>): import("react").JSX.Element;
|
|
22
|
+
declare const _default: typeof DropdownMenu & {
|
|
23
23
|
ListProps: {
|
|
24
24
|
Type: typeof import("../list/consts").Type;
|
|
25
25
|
Dimension: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cloneElement, useState, } from 'react';
|
|
2
2
|
import List, { ActiveItemContext } from '../list/list';
|
|
3
3
|
import Dropdown from '../dropdown/dropdown';
|
|
4
4
|
import PopupMenu from '../popup-menu/popup-menu';
|
|
@@ -31,11 +31,11 @@ function renderDropdownMenuChildren({ children, popupMenuProps }) {
|
|
|
31
31
|
}
|
|
32
32
|
return (popupProps) => children({ ...popupProps, ...popupMenuProps });
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
function DropdownMenu({ ref, id, anchor, ariaLabel, data, onSelect, menuProps, children, ...restDropdownProps }) {
|
|
35
35
|
const [uid] = useState(() => getUID('dropdown-menu-list'));
|
|
36
36
|
const listId = id || uid;
|
|
37
37
|
const popupMenuProps = {
|
|
38
|
-
ref
|
|
38
|
+
ref,
|
|
39
39
|
id: listId,
|
|
40
40
|
ariaLabel: ariaLabel || defaultAriaLabel,
|
|
41
41
|
closeOnSelect: true,
|
|
@@ -51,5 +51,5 @@ const DropdownMenu = forwardRef(function DropdownMenu({ id, anchor, ariaLabel, d
|
|
|
51
51
|
{renderDropdownMenuChildren({ children, popupMenuProps })}
|
|
52
52
|
</Dropdown>
|
|
53
53
|
</ActiveItemContext.Provider>);
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
55
|
export default Object.assign(DropdownMenu, { ListProps: List.ListProps });
|
|
@@ -29,5 +29,4 @@ export type EditableHeadingProps = Omit<InputHTMLAttributes<HTMLInputElement | H
|
|
|
29
29
|
translations?: EditableHeadingTranslations;
|
|
30
30
|
};
|
|
31
31
|
export declare const EditableHeading: (props: EditableHeadingProps) => React.JSX.Element;
|
|
32
|
-
|
|
33
|
-
export default _default;
|
|
32
|
+
export default EditableHeading;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect } from 'react';
|
|
1
|
+
import { useEffect, useEffectEvent, useLayoutEffect } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import Heading, { Levels } from '../heading/heading';
|
|
@@ -6,7 +6,6 @@ import Button from '../button/button';
|
|
|
6
6
|
import { Size } from '../input/input';
|
|
7
7
|
import getUID from '../global/get-uid';
|
|
8
8
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
9
|
-
import useEventCallback from '../global/use-event-callback';
|
|
10
9
|
import inputStyles from '../input/input.css';
|
|
11
10
|
import styles from './editable-heading.css';
|
|
12
11
|
export { Levels };
|
|
@@ -63,13 +62,13 @@ export const EditableHeading = (props) => {
|
|
|
63
62
|
const onHeadingMouseDown = () => {
|
|
64
63
|
setIsMouseDown(true);
|
|
65
64
|
};
|
|
66
|
-
const onMouseMove =
|
|
65
|
+
const onMouseMove = useEffectEvent(() => {
|
|
67
66
|
if (!isMouseDown) {
|
|
68
67
|
return;
|
|
69
68
|
}
|
|
70
69
|
setIsInSelectionMode(true);
|
|
71
70
|
});
|
|
72
|
-
const onMouseUp =
|
|
71
|
+
const onMouseUp = useEffectEvent(() => {
|
|
73
72
|
if (isMouseDown && !isInSelectionMode && !disabled) {
|
|
74
73
|
onEdit();
|
|
75
74
|
}
|
|
@@ -108,7 +107,7 @@ export const EditableHeading = (props) => {
|
|
|
108
107
|
window.removeEventListener('mousemove', onMouseMove);
|
|
109
108
|
window.removeEventListener('mouseup', onMouseUp);
|
|
110
109
|
};
|
|
111
|
-
}, [
|
|
110
|
+
}, []);
|
|
112
111
|
return (<>
|
|
113
112
|
<div className={classes}>
|
|
114
113
|
{!disabled && isEditing ? (<>
|
|
@@ -140,4 +139,4 @@ export const EditableHeading = (props) => {
|
|
|
140
139
|
{isEditing && error && (<div className={classNames(styles.errorText, size !== Size.AUTO && inputStyles[`size${size}`])}>{error}</div>)}
|
|
141
140
|
</>);
|
|
142
141
|
};
|
|
143
|
-
export default
|
|
142
|
+
export default EditableHeading;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { type Ref } from 'react';
|
|
2
|
-
export declare function createComposedRef<T>(): import("memoize-one").MemoizedFn<(...refs: (Ref<T> | undefined)[]) => (value: T | null) => void>;
|
|
2
|
+
export declare function createComposedRef<T>(): import("memoize-one").MemoizedFn<(...refs: (Ref<T> | undefined)[]) => (value: T | null) => () => void>;
|
|
3
|
+
export declare function useComposedRef<T>(...refs: (Ref<T> | undefined)[]): Ref<T>;
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
1
2
|
import memoizeOne from 'memoize-one';
|
|
2
3
|
function composeRefs(...refs) {
|
|
3
|
-
return (value) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
return (value) => {
|
|
5
|
+
const cleanups = [];
|
|
6
|
+
refs.forEach(ref => {
|
|
7
|
+
if (typeof ref === 'function') {
|
|
8
|
+
const cleanup = ref(value);
|
|
9
|
+
if (typeof cleanup === 'function') {
|
|
10
|
+
cleanups.push(cleanup);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
else if (ref) {
|
|
14
|
+
ref.current = value;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return () => cleanups.forEach(cleanup => cleanup());
|
|
18
|
+
};
|
|
11
19
|
}
|
|
12
20
|
export function createComposedRef() {
|
|
13
21
|
return memoizeOne((composeRefs));
|
|
14
22
|
}
|
|
23
|
+
export function useComposedRef(...refs) {
|
|
24
|
+
/**
|
|
25
|
+
* The React Compiler doesn't allow non-literal arrays in useMemo
|
|
26
|
+
* dependency lists, so we still use memoizeOne under the hood.
|
|
27
|
+
*/
|
|
28
|
+
const composer = useMemo(() => createComposedRef(), []);
|
|
29
|
+
return composer(...refs);
|
|
30
|
+
}
|
|
@@ -3,14 +3,9 @@ export declare enum ControlsHeight {
|
|
|
3
3
|
M = "M",
|
|
4
4
|
L = "L"
|
|
5
5
|
}
|
|
6
|
-
export interface RingUITrustedTypePolicy {
|
|
7
|
-
createHTML(html: string): TrustedHTML;
|
|
8
|
-
}
|
|
9
6
|
export interface RingUIConfiguration {
|
|
10
7
|
controlsHeight?: ControlsHeight;
|
|
11
8
|
popupsCssPositioning?: boolean;
|
|
12
|
-
trustedTypePolicy?: RingUITrustedTypePolicy | null;
|
|
13
9
|
}
|
|
14
10
|
export declare function configure(config: RingUIConfiguration): void;
|
|
15
11
|
export declare function getConfiguration(): Required<RingUIConfiguration>;
|
|
16
|
-
export declare function getTrustedHTML(html: string): string | TrustedHTML;
|
|
@@ -7,7 +7,6 @@ export var ControlsHeight;
|
|
|
7
7
|
const globalConfiguration = {
|
|
8
8
|
controlsHeight: ControlsHeight.M,
|
|
9
9
|
popupsCssPositioning: true,
|
|
10
|
-
trustedTypePolicy: null,
|
|
11
10
|
};
|
|
12
11
|
export function configure(config) {
|
|
13
12
|
if (config.controlsHeight !== undefined) {
|
|
@@ -16,13 +15,7 @@ export function configure(config) {
|
|
|
16
15
|
if (config.popupsCssPositioning !== undefined) {
|
|
17
16
|
globalConfiguration.popupsCssPositioning = config.popupsCssPositioning;
|
|
18
17
|
}
|
|
19
|
-
if (config.trustedTypePolicy !== undefined) {
|
|
20
|
-
globalConfiguration.trustedTypePolicy = config.trustedTypePolicy;
|
|
21
|
-
}
|
|
22
18
|
}
|
|
23
19
|
export function getConfiguration() {
|
|
24
20
|
return { ...globalConfiguration };
|
|
25
21
|
}
|
|
26
|
-
export function getTrustedHTML(html) {
|
|
27
|
-
return globalConfiguration.trustedTypePolicy?.createHTML(html) ?? html;
|
|
28
|
-
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { createContext, memo,
|
|
1
|
+
import { createContext, memo, use, useEffect, useState } from 'react';
|
|
2
2
|
export default function createStatefulContext(initialValue, name = '') {
|
|
3
3
|
const ValueContext = createContext(initialValue);
|
|
4
4
|
const UpdateContext = createContext(() => { });
|
|
5
5
|
function Provider({ children }) {
|
|
6
6
|
const [value, update] = useState(initialValue);
|
|
7
|
-
return (<ValueContext
|
|
8
|
-
<UpdateContext
|
|
9
|
-
</ValueContext
|
|
7
|
+
return (<ValueContext value={value}>
|
|
8
|
+
<UpdateContext value={update}>{children}</UpdateContext>
|
|
9
|
+
</ValueContext>);
|
|
10
10
|
}
|
|
11
11
|
Provider.displayName = `${name}Provider`;
|
|
12
12
|
function useUpdate(value, skipUpdate) {
|
|
13
|
-
const update =
|
|
13
|
+
const update = use(UpdateContext);
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
if (!skipUpdate) {
|
|
16
16
|
update(value);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focuses an element, temporarily adding `tabindex="0"` if necessary.
|
|
3
|
+
*
|
|
4
|
+
* If the element does not already have a `tabindex` attribute, one is
|
|
5
|
+
* added before focusing and automatically removed when the element loses
|
|
6
|
+
* focus.
|
|
7
|
+
*
|
|
8
|
+
* This is useful when implementing roving tabindex patterns on elements
|
|
9
|
+
* that are not normally focusable.
|
|
10
|
+
*/
|
|
11
|
+
export declare function focusWithTemporaryTabIndex(element: HTMLElement): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focuses an element, temporarily adding `tabindex="0"` if necessary.
|
|
3
|
+
*
|
|
4
|
+
* If the element does not already have a `tabindex` attribute, one is
|
|
5
|
+
* added before focusing and automatically removed when the element loses
|
|
6
|
+
* focus.
|
|
7
|
+
*
|
|
8
|
+
* This is useful when implementing roving tabindex patterns on elements
|
|
9
|
+
* that are not normally focusable.
|
|
10
|
+
*/
|
|
11
|
+
export function focusWithTemporaryTabIndex(element) {
|
|
12
|
+
if (!element.hasAttribute('tabindex')) {
|
|
13
|
+
element.tabIndex = 0;
|
|
14
|
+
function onBlur() {
|
|
15
|
+
element.removeAttribute('tabindex');
|
|
16
|
+
element.removeEventListener('blur', onBlur);
|
|
17
|
+
}
|
|
18
|
+
element.addEventListener('blur', onBlur);
|
|
19
|
+
}
|
|
20
|
+
element.focus();
|
|
21
|
+
}
|