@jetbrains/ring-ui 8.0.0-beta.3 → 8.0.0-beta.4
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/components/checkbox/checkbox.d.ts +1 -1
- package/components/collapsible-group/collapsible-group.css +138 -0
- package/components/collapsible-group/collapsible-group.d.ts +20 -0
- package/components/collapsible-group/collapsible-group.js +73 -0
- package/components/editable-heading/editable-heading.js +14 -14
- package/components/expand/collapsible-group.css +23 -89
- package/components/expand/collapsible-group.d.ts +8 -20
- package/components/expand/collapsible-group.js +14 -73
- package/components/global/compose-refs.d.ts +2 -1
- package/components/global/compose-refs.js +24 -8
- 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 +29 -9
- package/components/global/intersection-observer-context.js +43 -24
- 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/schedule-with-cleanup.d.ts +12 -0
- package/components/global/schedule-with-cleanup.js +34 -0
- package/components/global/table-selection.js +1 -1
- package/components/input/input.d.ts +1 -1
- package/components/legacy-table/row.d.ts +1 -1
- package/components/popup/popup.d.ts +2 -0
- package/components/popup/popup.js +2 -2
- package/components/select/select-popup.d.ts +1 -1
- package/components/select/select.d.ts +1 -1
- package/components/table/default-item-renderer.d.ts +23 -10
- package/components/table/default-item-renderer.js +40 -19
- package/components/table/internal/column-animation.d.ts +16 -0
- package/components/table/internal/column-animation.js +45 -0
- package/components/table/internal/table-header.d.ts +4 -0
- package/components/table/internal/table-header.js +357 -0
- package/components/table/internal/virtual-items.d.ts +34 -0
- package/components/table/{table-virtualize.js → internal/virtual-items.js} +68 -33
- package/components/table/item-virtualization.d.ts +35 -0
- package/components/table/item-virtualization.js +28 -0
- package/components/table/table-const.d.ts +40 -6
- package/components/table/table-const.js +14 -5
- package/components/table/table-primitives.d.ts +9 -16
- package/components/table/table-primitives.js +6 -60
- package/components/table/table-props.d.ts +280 -0
- package/components/table/table-props.js +1 -0
- package/components/table/table.css +171 -66
- package/components/table/table.d.ts +205 -209
- package/components/table/table.js +298 -2
- package/components/util-stories.d.ts +26 -0
- package/components/util-stories.js +61 -0
- package/package.json +29 -30
- package/components/date-picker/use-intersection-observer.d.ts +0 -6
- package/components/date-picker/use-intersection-observer.js +0 -48
- package/components/global/composeRefs.d.ts +0 -6
- package/components/global/composeRefs.js +0 -7
- package/components/table/table-component.d.ts +0 -80
- package/components/table/table-component.js +0 -130
- package/components/table/table-row-focus.d.ts +0 -4
- package/components/table/table-row-focus.js +0 -42
- package/components/table/table-virtualize.d.ts +0 -32
|
@@ -24,6 +24,6 @@ export default class Checkbox extends PureComponent<CheckboxProps> {
|
|
|
24
24
|
componentDidUpdate(prevProps: CheckboxProps): void;
|
|
25
25
|
input?: HTMLInputElement | null;
|
|
26
26
|
inputRef: (el: HTMLInputElement | null) => void;
|
|
27
|
-
composedInputRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T | null) => void>;
|
|
27
|
+
composedInputRef: import("memoize-one").MemoizedFn<(...refs: (Ref<HTMLInputElement> | undefined)[]) => (value: T | null) => () => void>;
|
|
28
28
|
render(): import("react").JSX.Element;
|
|
29
29
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
@import '../global/variables.css';
|
|
2
|
+
|
|
3
|
+
.expand .collapseRoot {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.expand {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
|
|
14
|
+
border: 1px solid var(--ring-line-color);
|
|
15
|
+
border-radius: var(--ring-border-radius-large);
|
|
16
|
+
outline: none;
|
|
17
|
+
background: var(--ring-content-background-color);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hovered {
|
|
21
|
+
box-shadow: var(--ring-popup-shadow);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.expanded {
|
|
25
|
+
box-shadow: var(--ring-popup-shadow);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.focused {
|
|
29
|
+
box-shadow: 0 0 0 2px var(--ring-border-hover-color), var(--ring-popup-shadow);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header {
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: calc(var(--ring-unit) * 1.5);
|
|
36
|
+
|
|
37
|
+
height: 28px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.headerButton {
|
|
41
|
+
display: block;
|
|
42
|
+
|
|
43
|
+
box-sizing: border-box;
|
|
44
|
+
width: 100%;
|
|
45
|
+
padding: calc(var(--ring-unit) * 1.5);
|
|
46
|
+
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
text-align: left;
|
|
49
|
+
|
|
50
|
+
color: inherit;
|
|
51
|
+
|
|
52
|
+
border: 0;
|
|
53
|
+
background: transparent;
|
|
54
|
+
|
|
55
|
+
font: inherit;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.headerButton:focus-visible {
|
|
59
|
+
outline: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.headerStatic {
|
|
63
|
+
display: block;
|
|
64
|
+
|
|
65
|
+
padding: calc(var(--ring-unit) * 1.5);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.headerContent {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: var(--ring-unit);
|
|
72
|
+
|
|
73
|
+
flex: 1;
|
|
74
|
+
|
|
75
|
+
min-width: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.avatarGroup {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: var(--ring-unit);
|
|
82
|
+
|
|
83
|
+
flex-shrink: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.title {
|
|
87
|
+
color: var(--ring-text-color);
|
|
88
|
+
|
|
89
|
+
font-size: var(--ring-font-size);
|
|
90
|
+
font-weight: var(--ring-font-weight-bold);
|
|
91
|
+
line-height: var(--ring-line-height);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.subtitleGroup {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: var(--ring-unit);
|
|
98
|
+
|
|
99
|
+
min-width: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.subtitle {
|
|
103
|
+
color: var(--ring-secondary-color);
|
|
104
|
+
|
|
105
|
+
font-size: var(--ring-font-size);
|
|
106
|
+
line-height: var(--ring-line-height);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.subtitleChevron {
|
|
110
|
+
color: var(--ring-secondary-color);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.toggle {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
|
|
117
|
+
flex-shrink: 0;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
|
|
120
|
+
width: calc(var(--ring-unit) * 3);
|
|
121
|
+
height: calc(var(--ring-unit) * 3);
|
|
122
|
+
|
|
123
|
+
border-radius: calc(var(--ring-unit) / 2);
|
|
124
|
+
background: var(--ring-secondary-background-color);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.toggleIcon {
|
|
128
|
+
color: var(--ring-secondary-color);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.body {
|
|
132
|
+
padding: 0 calc(var(--ring-unit) * 2) calc(var(--ring-unit) * 1.5);
|
|
133
|
+
|
|
134
|
+
color: var(--ring-text-color);
|
|
135
|
+
|
|
136
|
+
font-size: var(--ring-font-size);
|
|
137
|
+
line-height: var(--ring-line-height);
|
|
138
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface CollapsibleGroupProps {
|
|
3
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
4
|
+
avatar?: React.ReactNode;
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
subtitle?: React.ReactNode;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
className?: string | null | undefined;
|
|
9
|
+
defaultExpanded?: boolean;
|
|
10
|
+
expanded?: boolean | null | undefined;
|
|
11
|
+
onChange?: (expanded: boolean) => void;
|
|
12
|
+
disableAnimation?: boolean;
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
'data-test'?: string | null | undefined;
|
|
15
|
+
}
|
|
16
|
+
declare const CollapsibleGroup: {
|
|
17
|
+
({ ref, avatar, title, subtitle, children, className, defaultExpanded, expanded, onChange, disableAnimation, interactive, "data-test": dataTest, }: CollapsibleGroupProps): React.JSX.Element;
|
|
18
|
+
displayName: string;
|
|
19
|
+
};
|
|
20
|
+
export default CollapsibleGroup;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { use, useState } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import chevronRightIcon from '@jetbrains/icons/chevron-12px-right';
|
|
4
|
+
import chevronDownIcon from '@jetbrains/icons/chevron-12px-down';
|
|
5
|
+
import Icon from '../icon/icon';
|
|
6
|
+
import Collapse from '../collapse/collapse';
|
|
7
|
+
import CollapseContent from '../collapse/collapse-content';
|
|
8
|
+
import { CollapseContext } from '../collapse/collapse-context';
|
|
9
|
+
import styles from './collapsible-group.css';
|
|
10
|
+
function CollapsibleGroupHeaderContent({ avatar, titleContent, subtitle }) {
|
|
11
|
+
const { collapsed } = use(CollapseContext);
|
|
12
|
+
return (<span className={styles.header}>
|
|
13
|
+
<span className={styles.headerContent}>
|
|
14
|
+
<span className={styles.avatarGroup}>
|
|
15
|
+
{avatar}
|
|
16
|
+
<span className={styles.title}>{titleContent}</span>
|
|
17
|
+
</span>
|
|
18
|
+
{subtitle ? (<span className={styles.subtitleGroup}>
|
|
19
|
+
<Icon className={styles.subtitleChevron} glyph={chevronRightIcon} aria-hidden/>
|
|
20
|
+
<span className={styles.subtitle}>{subtitle}</span>
|
|
21
|
+
</span>) : null}
|
|
22
|
+
</span>
|
|
23
|
+
<span className={styles.toggle} aria-hidden>
|
|
24
|
+
<Icon className={styles.toggleIcon} glyph={collapsed ? chevronRightIcon : chevronDownIcon}/>
|
|
25
|
+
</span>
|
|
26
|
+
</span>);
|
|
27
|
+
}
|
|
28
|
+
function CollapsibleGroupHeader({ avatar, titleContent, subtitle, ...buttonProps }) {
|
|
29
|
+
const { setCollapsed, collapsed, id } = use(CollapseContext);
|
|
30
|
+
return (<button type='button' {...buttonProps} className={styles.headerButton} onClick={setCollapsed} aria-controls={`collapse-content-${id}`} aria-expanded={!collapsed}>
|
|
31
|
+
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
32
|
+
</button>);
|
|
33
|
+
}
|
|
34
|
+
function CollapsibleGroupHeaderStatic({ avatar, titleContent, subtitle }) {
|
|
35
|
+
return (<span className={styles.headerStatic}>
|
|
36
|
+
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
37
|
+
</span>);
|
|
38
|
+
}
|
|
39
|
+
const CollapsibleGroup = ({ ref, avatar, title, subtitle, children, className, defaultExpanded = false, expanded = null, onChange = () => { }, disableAnimation = false, interactive = true, 'data-test': dataTest, }) => {
|
|
40
|
+
const [innerExpanded, setInnerExpanded] = useState(defaultExpanded);
|
|
41
|
+
const [hovered, setHovered] = useState(false);
|
|
42
|
+
const [focused, setFocused] = useState(false);
|
|
43
|
+
const isExpanded = expanded ?? innerExpanded;
|
|
44
|
+
const handleChange = (collapsed) => {
|
|
45
|
+
const nextExpanded = !collapsed;
|
|
46
|
+
if (expanded == null) {
|
|
47
|
+
setInnerExpanded(nextExpanded);
|
|
48
|
+
}
|
|
49
|
+
onChange(nextExpanded);
|
|
50
|
+
};
|
|
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
|
+
const classes = classNames(styles.expand, className, {
|
|
59
|
+
[styles.hovered]: hovered,
|
|
60
|
+
[styles.expanded]: isExpanded,
|
|
61
|
+
[styles.focused]: focused,
|
|
62
|
+
});
|
|
63
|
+
return (<div ref={ref} className={classes} data-test={dataTest}>
|
|
64
|
+
<Collapse defaultCollapsed={!defaultExpanded} collapsed={expanded == null ? null : !expanded} onChange={handleChange} disableAnimation={disableAnimation} className={styles.collapseRoot}>
|
|
65
|
+
{interactive ? (<CollapsibleGroupHeader avatar={avatar} titleContent={title} subtitle={subtitle} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} onFocus={() => setFocused(true)} onBlur={onBlur}/>) : (<CollapsibleGroupHeaderStatic avatar={avatar} titleContent={title} subtitle={subtitle}/>)}
|
|
66
|
+
<CollapseContent>
|
|
67
|
+
<div className={styles.body}>{children}</div>
|
|
68
|
+
</CollapseContent>
|
|
69
|
+
</Collapse>
|
|
70
|
+
</div>);
|
|
71
|
+
};
|
|
72
|
+
CollapsibleGroup.displayName = 'CollapsibleGroup';
|
|
73
|
+
export default CollapsibleGroup;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useEffectEvent } 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';
|
|
@@ -45,26 +45,20 @@ export const EditableHeading = (props) => {
|
|
|
45
45
|
});
|
|
46
46
|
const headingClasses = classNames(styles.heading, headingClassName, size !== Size.AUTO && styles[`size${size}`]);
|
|
47
47
|
const inputClasses = classNames('ring-js-shortcuts', styles.input, styles.textarea, { [styles.textareaNotOverflow]: !isOverflow }, size !== Size.AUTO && inputStyles[`size${size}`], level !== Levels.H4 && styles[`level${level}`], inputClassName);
|
|
48
|
-
const
|
|
49
|
-
if (!el || !el.style) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
el.style.height = '0';
|
|
53
|
-
const { paddingTop, paddingBottom } = window.getComputedStyle(el);
|
|
54
|
-
el.style.height = `${el.scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom)}px`;
|
|
55
|
-
};
|
|
56
|
-
const checkValue = (el) => {
|
|
48
|
+
const checkValue = React.useCallback((el) => {
|
|
57
49
|
if (multiline && el && el.scrollHeight >= el.clientHeight) {
|
|
58
|
-
|
|
50
|
+
el.style.height = '0';
|
|
51
|
+
const { paddingTop, paddingBottom } = window.getComputedStyle(el);
|
|
52
|
+
el.style.height = `${el.scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom)}px`;
|
|
59
53
|
}
|
|
60
|
-
};
|
|
61
|
-
const checkOverflow = (el) => {
|
|
54
|
+
}, [multiline]);
|
|
55
|
+
const checkOverflow = React.useCallback((el) => {
|
|
62
56
|
const scrollHeight = el.scrollHeight || 0;
|
|
63
57
|
const clientHeight = el.clientHeight || 0;
|
|
64
58
|
const scrollTop = el.scrollTop || 0;
|
|
65
59
|
setIsScrolledToBottom(scrollHeight - clientHeight <= scrollTop);
|
|
66
60
|
setIsOverflow(scrollHeight > clientHeight);
|
|
67
|
-
};
|
|
61
|
+
}, []);
|
|
68
62
|
const onHeadingMouseDown = () => {
|
|
69
63
|
setIsMouseDown(true);
|
|
70
64
|
};
|
|
@@ -100,6 +94,12 @@ export const EditableHeading = (props) => {
|
|
|
100
94
|
setIsInFocus(false);
|
|
101
95
|
onBlur?.(e);
|
|
102
96
|
};
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
|
+
if (multiline && isEditing && textAreaRef.current) {
|
|
99
|
+
checkValue(textAreaRef.current);
|
|
100
|
+
checkOverflow(textAreaRef.current);
|
|
101
|
+
}
|
|
102
|
+
}, [checkOverflow, checkValue, isEditing, multiline]);
|
|
103
103
|
useEffect(() => {
|
|
104
104
|
window.addEventListener('mousemove', onMouseMove);
|
|
105
105
|
window.addEventListener('mouseup', onMouseUp);
|
|
@@ -1,138 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
flex-direction: column;
|
|
6
|
-
}
|
|
1
|
+
/* Deprecated alias of `../collapsible-group/collapsible-group.css` (removed in Ring UI 8.0).
|
|
2
|
+
Class names are forwarded via `composes` so the canonical stylesheet stays the single source of
|
|
3
|
+
the actual rules, while `import styles from '.../components/expand/collapsible-group.css'` keeps
|
|
4
|
+
returning the full token map. */
|
|
7
5
|
|
|
8
6
|
.expand {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
box-sizing: border-box;
|
|
7
|
+
composes: expand from '../collapsible-group/collapsible-group.css';
|
|
8
|
+
}
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
outline: none;
|
|
17
|
-
background: var(--ring-content-background-color);
|
|
10
|
+
.collapseRoot {
|
|
11
|
+
composes: collapseRoot from '../collapsible-group/collapsible-group.css';
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
.hovered {
|
|
21
|
-
|
|
15
|
+
composes: hovered from '../collapsible-group/collapsible-group.css';
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
.expanded {
|
|
25
|
-
|
|
19
|
+
composes: expanded from '../collapsible-group/collapsible-group.css';
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
.focused {
|
|
29
|
-
|
|
23
|
+
composes: focused from '../collapsible-group/collapsible-group.css';
|
|
30
24
|
}
|
|
31
25
|
|
|
32
26
|
.header {
|
|
33
|
-
|
|
34
|
-
align-items: center;
|
|
35
|
-
gap: calc(var(--ring-unit) * 1.5);
|
|
36
|
-
|
|
37
|
-
height: 28px;
|
|
27
|
+
composes: header from '../collapsible-group/collapsible-group.css';
|
|
38
28
|
}
|
|
39
29
|
|
|
40
30
|
.headerButton {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
box-sizing: border-box;
|
|
44
|
-
width: 100%;
|
|
45
|
-
padding: calc(var(--ring-unit) * 1.5);
|
|
46
|
-
|
|
47
|
-
cursor: pointer;
|
|
48
|
-
text-align: left;
|
|
49
|
-
|
|
50
|
-
color: inherit;
|
|
51
|
-
|
|
52
|
-
border: 0;
|
|
53
|
-
background: transparent;
|
|
54
|
-
|
|
55
|
-
font: inherit;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.headerButton:focus-visible {
|
|
59
|
-
outline: none;
|
|
31
|
+
composes: headerButton from '../collapsible-group/collapsible-group.css';
|
|
60
32
|
}
|
|
61
33
|
|
|
62
34
|
.headerStatic {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
padding: calc(var(--ring-unit) * 1.5);
|
|
35
|
+
composes: headerStatic from '../collapsible-group/collapsible-group.css';
|
|
66
36
|
}
|
|
67
37
|
|
|
68
38
|
.headerContent {
|
|
69
|
-
|
|
70
|
-
align-items: center;
|
|
71
|
-
gap: var(--ring-unit);
|
|
72
|
-
|
|
73
|
-
flex: 1;
|
|
74
|
-
|
|
75
|
-
min-width: 0;
|
|
39
|
+
composes: headerContent from '../collapsible-group/collapsible-group.css';
|
|
76
40
|
}
|
|
77
41
|
|
|
78
42
|
.avatarGroup {
|
|
79
|
-
|
|
80
|
-
align-items: center;
|
|
81
|
-
gap: var(--ring-unit);
|
|
82
|
-
|
|
83
|
-
flex-shrink: 0;
|
|
43
|
+
composes: avatarGroup from '../collapsible-group/collapsible-group.css';
|
|
84
44
|
}
|
|
85
45
|
|
|
86
46
|
.title {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
font-size: var(--ring-font-size);
|
|
90
|
-
font-weight: var(--ring-font-weight-bold);
|
|
91
|
-
line-height: var(--ring-line-height);
|
|
47
|
+
composes: title from '../collapsible-group/collapsible-group.css';
|
|
92
48
|
}
|
|
93
49
|
|
|
94
50
|
.subtitleGroup {
|
|
95
|
-
|
|
96
|
-
align-items: center;
|
|
97
|
-
gap: var(--ring-unit);
|
|
98
|
-
|
|
99
|
-
min-width: 0;
|
|
51
|
+
composes: subtitleGroup from '../collapsible-group/collapsible-group.css';
|
|
100
52
|
}
|
|
101
53
|
|
|
102
54
|
.subtitle {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
font-size: var(--ring-font-size);
|
|
106
|
-
line-height: var(--ring-line-height);
|
|
55
|
+
composes: subtitle from '../collapsible-group/collapsible-group.css';
|
|
107
56
|
}
|
|
108
57
|
|
|
109
58
|
.subtitleChevron {
|
|
110
|
-
|
|
59
|
+
composes: subtitleChevron from '../collapsible-group/collapsible-group.css';
|
|
111
60
|
}
|
|
112
61
|
|
|
113
62
|
.toggle {
|
|
114
|
-
|
|
115
|
-
align-items: center;
|
|
116
|
-
|
|
117
|
-
flex-shrink: 0;
|
|
118
|
-
justify-content: center;
|
|
119
|
-
|
|
120
|
-
width: calc(var(--ring-unit) * 3);
|
|
121
|
-
height: calc(var(--ring-unit) * 3);
|
|
122
|
-
|
|
123
|
-
border-radius: calc(var(--ring-unit) / 2);
|
|
124
|
-
background: var(--ring-secondary-background-color);
|
|
63
|
+
composes: toggle from '../collapsible-group/collapsible-group.css';
|
|
125
64
|
}
|
|
126
65
|
|
|
127
66
|
.toggleIcon {
|
|
128
|
-
|
|
67
|
+
composes: toggleIcon from '../collapsible-group/collapsible-group.css';
|
|
129
68
|
}
|
|
130
69
|
|
|
131
70
|
.body {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
color: var(--ring-text-color);
|
|
135
|
-
|
|
136
|
-
font-size: var(--ring-font-size);
|
|
137
|
-
line-height: var(--ring-line-height);
|
|
71
|
+
composes: body from '../collapsible-group/collapsible-group.css';
|
|
138
72
|
}
|
|
@@ -1,20 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
defaultExpanded?: boolean;
|
|
10
|
-
expanded?: boolean | null | undefined;
|
|
11
|
-
onChange?: (expanded: boolean) => void;
|
|
12
|
-
disableAnimation?: boolean;
|
|
13
|
-
interactive?: boolean;
|
|
14
|
-
'data-test'?: string | null | undefined;
|
|
15
|
-
}
|
|
16
|
-
declare const CollapsibleGroup: {
|
|
17
|
-
({ ref, avatar, title, subtitle, children, className, defaultExpanded, expanded, onChange, disableAnimation, interactive, "data-test": dataTest, }: CollapsibleGroupProps): React.JSX.Element;
|
|
18
|
-
displayName: string;
|
|
19
|
-
};
|
|
20
|
-
export default CollapsibleGroup;
|
|
1
|
+
import { type CollapsibleGroupProps } from '../collapsible-group/collapsible-group';
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated The `expand` module has been renamed to `collapsible-group`. This re-export will be removed in
|
|
4
|
+
* Ring UI 8.0. Use `CollapsibleGroup` from `@jetbrains/ring-ui/components/collapsible-group/collapsible-group` instead.
|
|
5
|
+
*/
|
|
6
|
+
declare const DeprecatedCollapsibleGroup: import("react").ForwardRefExoticComponent<Omit<CollapsibleGroupProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
7
|
+
export type { CollapsibleGroupProps };
|
|
8
|
+
export default DeprecatedCollapsibleGroup;
|
|
@@ -1,73 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{avatar}
|
|
16
|
-
<span className={styles.title}>{titleContent}</span>
|
|
17
|
-
</span>
|
|
18
|
-
{subtitle ? (<span className={styles.subtitleGroup}>
|
|
19
|
-
<Icon className={styles.subtitleChevron} glyph={chevronRightIcon} aria-hidden/>
|
|
20
|
-
<span className={styles.subtitle}>{subtitle}</span>
|
|
21
|
-
</span>) : null}
|
|
22
|
-
</span>
|
|
23
|
-
<span className={styles.toggle} aria-hidden>
|
|
24
|
-
<Icon className={styles.toggleIcon} glyph={collapsed ? chevronRightIcon : chevronDownIcon}/>
|
|
25
|
-
</span>
|
|
26
|
-
</span>);
|
|
27
|
-
}
|
|
28
|
-
function CollapsibleGroupHeader({ avatar, titleContent, subtitle, ...buttonProps }) {
|
|
29
|
-
const { setCollapsed, collapsed, id } = use(CollapseContext);
|
|
30
|
-
return (<button type='button' {...buttonProps} className={styles.headerButton} onClick={setCollapsed} aria-controls={`collapse-content-${id}`} aria-expanded={!collapsed}>
|
|
31
|
-
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
32
|
-
</button>);
|
|
33
|
-
}
|
|
34
|
-
function CollapsibleGroupHeaderStatic({ avatar, titleContent, subtitle }) {
|
|
35
|
-
return (<span className={styles.headerStatic}>
|
|
36
|
-
<CollapsibleGroupHeaderContent avatar={avatar} titleContent={titleContent} subtitle={subtitle}/>
|
|
37
|
-
</span>);
|
|
38
|
-
}
|
|
39
|
-
const CollapsibleGroup = ({ ref, avatar, title, subtitle, children, className, defaultExpanded = false, expanded = null, onChange = () => { }, disableAnimation = false, interactive = true, 'data-test': dataTest, }) => {
|
|
40
|
-
const [innerExpanded, setInnerExpanded] = useState(defaultExpanded);
|
|
41
|
-
const [hovered, setHovered] = useState(false);
|
|
42
|
-
const [focused, setFocused] = useState(false);
|
|
43
|
-
const isExpanded = expanded ?? innerExpanded;
|
|
44
|
-
const handleChange = (collapsed) => {
|
|
45
|
-
const nextExpanded = !collapsed;
|
|
46
|
-
if (expanded == null) {
|
|
47
|
-
setInnerExpanded(nextExpanded);
|
|
48
|
-
}
|
|
49
|
-
onChange(nextExpanded);
|
|
50
|
-
};
|
|
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
|
-
const classes = classNames(styles.expand, className, {
|
|
59
|
-
[styles.hovered]: hovered,
|
|
60
|
-
[styles.expanded]: isExpanded,
|
|
61
|
-
[styles.focused]: focused,
|
|
62
|
-
});
|
|
63
|
-
return (<div ref={ref} className={classes} data-test={dataTest}>
|
|
64
|
-
<Collapse defaultCollapsed={!defaultExpanded} collapsed={expanded == null ? null : !expanded} onChange={handleChange} disableAnimation={disableAnimation} className={styles.collapseRoot}>
|
|
65
|
-
{interactive ? (<CollapsibleGroupHeader avatar={avatar} titleContent={title} subtitle={subtitle} onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)} onFocus={() => setFocused(true)} onBlur={onBlur}/>) : (<CollapsibleGroupHeaderStatic avatar={avatar} titleContent={title} subtitle={subtitle}/>)}
|
|
66
|
-
<CollapseContent>
|
|
67
|
-
<div className={styles.body}>{children}</div>
|
|
68
|
-
</CollapseContent>
|
|
69
|
-
</Collapse>
|
|
70
|
-
</div>);
|
|
71
|
-
};
|
|
72
|
-
CollapsibleGroup.displayName = 'CollapsibleGroup';
|
|
73
|
-
export default CollapsibleGroup;
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import deprecate from 'util-deprecate';
|
|
3
|
+
import CollapsibleGroup from '../collapsible-group/collapsible-group';
|
|
4
|
+
const warnDeprecation = deprecate(() => { }, '`CollapsibleGroup` from `@jetbrains/ring-ui/components/expand/collapsible-group` is deprecated and will be removed in Ring UI 8.0. Import it from `@jetbrains/ring-ui/components/collapsible-group/collapsible-group` instead.');
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated The `expand` module has been renamed to `collapsible-group`. This re-export will be removed in
|
|
7
|
+
* Ring UI 8.0. Use `CollapsibleGroup` from `@jetbrains/ring-ui/components/collapsible-group/collapsible-group` instead.
|
|
8
|
+
*/
|
|
9
|
+
const DeprecatedCollapsibleGroup = forwardRef((props, ref) => {
|
|
10
|
+
warnDeprecation();
|
|
11
|
+
return <CollapsibleGroup ref={ref} {...props}/>;
|
|
12
|
+
});
|
|
13
|
+
DeprecatedCollapsibleGroup.displayName = 'CollapsibleGroup';
|
|
14
|
+
export default DeprecatedCollapsibleGroup;
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|