@planningcenter/tapestry-react 2.6.0-rc.0 → 2.6.0-rc.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/dist/cjs/Button/Button.js +8 -1
- package/dist/cjs/Button/Button.test.js +51 -8
- package/dist/cjs/DataTable/components/BodyRow.js +2 -2
- package/dist/cjs/DataTable/components/CheckboxCell.js +1 -1
- package/dist/cjs/DataTable/hooks/useCollapsibleRows.js +2 -2
- package/dist/cjs/DragDrop/DragDrop.js +7 -0
- package/dist/cjs/Dropdown/Dropdown.js +5 -3
- package/dist/cjs/Dropdown/Link.js +2 -4
- package/dist/cjs/Input/InputLabel.js +40 -63
- package/dist/cjs/Modal/Modal.js +18 -8
- package/dist/cjs/Popover/Popover.js +10 -2
- package/dist/cjs/Portal/Portal.js +11 -1
- package/dist/cjs/Scrim/Scrim.js +16 -4
- package/dist/cjs/ThemeProvider/ThemeProvider.js +24 -6
- package/dist/cjs/ThemeProvider/styles.js +1 -4
- package/dist/cjs/TimeField/TimeField.js +1 -1
- package/dist/cjs/Tooltip/Tooltip.js +17 -17
- package/dist/cjs/index.d.js +70 -25
- package/dist/cjs/system/split-styles.js +2 -2
- package/dist/esm/Button/Button.js +8 -1
- package/dist/esm/Button/Button.test.js +67 -9
- package/dist/esm/DataTable/components/BodyRow.js +2 -2
- package/dist/esm/DataTable/components/CheckboxCell.js +1 -1
- package/dist/esm/DataTable/hooks/useCollapsibleRows.js +1 -1
- package/dist/esm/DragDrop/DragDrop.js +5 -0
- package/dist/esm/Dropdown/Dropdown.js +6 -4
- package/dist/esm/Dropdown/Link.js +1 -2
- package/dist/esm/Input/InputLabel.js +40 -63
- package/dist/esm/Modal/Modal.js +16 -8
- package/dist/esm/Popover/Popover.js +8 -2
- package/dist/esm/Portal/Portal.js +10 -0
- package/dist/esm/Scrim/Scrim.js +15 -4
- package/dist/esm/ThemeProvider/ThemeProvider.js +21 -6
- package/dist/esm/ThemeProvider/styles.js +1 -4
- package/dist/esm/TimeField/TimeField.js +1 -1
- package/dist/esm/Tooltip/Tooltip.js +18 -18
- package/dist/esm/index.d.js +39 -6
- package/dist/esm/system/split-styles.js +1 -1
- package/dist/types/Button/Button.d.ts +4 -0
- package/dist/types/Divider/Divider.d.ts +2 -2
- package/dist/types/Portal/Portal.d.ts +3 -0
- package/dist/types/Spinner/Spinner.d.ts +3 -1
- package/dist/types/ThemeProvider/ThemeProvider.d.ts +4 -2
- package/dist/types/index.d.ts +74 -5
- package/package.json +3 -3
- package/src/Button/Button.test.tsx +30 -0
- package/src/Button/Button.tsx +14 -1
- package/src/DataTable/DataTable.js +1 -1
- package/src/DataTable/components/BodyRow.js +1 -1
- package/src/DataTable/components/BodyRows.js +4 -1
- package/src/DataTable/components/CheckboxCell.js +1 -2
- package/src/DataTable/hooks/useCollapsibleRows.js +1 -1
- package/src/Divider/Divider.tsx +2 -2
- package/src/DragDrop/DragDrop.js +5 -0
- package/src/Dropdown/Dropdown.js +7 -4
- package/src/Dropdown/Dropdown.mdx +3 -3
- package/src/Dropdown/Link.js +1 -7
- package/src/Icon/Icon.mdx +45 -47
- package/src/Input/InputLabel.js +39 -36
- package/src/Input/InputLabel.mdx +1 -0
- package/src/Modal/Modal.js +16 -6
- package/src/Modal/Modal.mdx +2 -1
- package/src/Popover/Popover.mdx +1 -0
- package/src/Popover/Popover.tsx +8 -2
- package/src/Portal/Portal.tsx +14 -0
- package/src/RangeSlider/RangeSlider.mdx +10 -12
- package/src/Scrim/Scrim.mdx +1 -0
- package/src/Scrim/Scrim.tsx +11 -6
- package/src/Sidebar/Sidebar.mdx +0 -1
- package/src/Spinner/Spinner.tsx +2 -1
- package/src/ThemeProvider/ThemeProvider.tsx +22 -10
- package/src/ThemeProvider/styles.ts +23 -12
- package/src/TimeField/TimeField.js +1 -1
- package/src/Tooltip/Tooltip.js +20 -18
- package/src/index.d.ts +74 -5
- package/src/system/split-styles.js +4 -2
- package/src/.DS_Store +0 -0
|
@@ -2,12 +2,42 @@ import React from 'react'
|
|
|
2
2
|
import { render, fireEvent } from '@testing-library/react'
|
|
3
3
|
import { Button } from './Button'
|
|
4
4
|
|
|
5
|
+
it(`should render as <button> with type="button" by default`, () => {
|
|
6
|
+
const { container } = render(<Button />)
|
|
7
|
+
const button = container.querySelector('button')
|
|
8
|
+
expect(button.getAttribute('type')).toEqual('button')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it(`should render as <button> with type="submit"`, () => {
|
|
12
|
+
const { container } = render(<Button type='submit' />)
|
|
13
|
+
const button = container.querySelector('button')
|
|
14
|
+
expect(button.getAttribute('type')).toEqual('submit')
|
|
15
|
+
})
|
|
16
|
+
|
|
5
17
|
it(`should render title`, () => {
|
|
6
18
|
const title = 'Hello'
|
|
7
19
|
const { getByText } = render(<Button title={title} />)
|
|
8
20
|
getByText(title)
|
|
9
21
|
})
|
|
10
22
|
|
|
23
|
+
it(`should render <a> without a type if "to" is provided`, () => {
|
|
24
|
+
const { container } = render(<Button to='#' />)
|
|
25
|
+
const button = container.querySelector('a')
|
|
26
|
+
expect(button.getAttribute('type')).toBeNull()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it(`should render <a> without a type if "href" is provided`, () => {
|
|
30
|
+
const { container } = render(<Button href='#' />)
|
|
31
|
+
const button = container.querySelector('a')
|
|
32
|
+
expect(button.getAttribute('type')).toBeNull()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it(`should render <a> with "href" if "to" is specifed`, () => {
|
|
36
|
+
const { container } = render(<Button to='#' />)
|
|
37
|
+
const button = container.querySelector('a')
|
|
38
|
+
expect(button.getAttribute('href')).toEqual('#')
|
|
39
|
+
})
|
|
40
|
+
|
|
11
41
|
it(`should render href and external link values`, () => {
|
|
12
42
|
const title = 'Hello'
|
|
13
43
|
const { getByText } = render(
|
package/src/Button/Button.tsx
CHANGED
|
@@ -86,6 +86,11 @@ type ButtonProps = {
|
|
|
86
86
|
*/
|
|
87
87
|
to?: string
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Where the browser should navigate to when pressed. If you need any element here other than `<a>`, remember to use the `as` prop.
|
|
91
|
+
*/
|
|
92
|
+
href?: string
|
|
93
|
+
|
|
89
94
|
/**
|
|
90
95
|
* Wraps button in a [`<Tooltip />`](./tooltip). Accepts any valid Tooltip props.
|
|
91
96
|
*/
|
|
@@ -287,6 +292,14 @@ export function Button({
|
|
|
287
292
|
restProps['href'] = to
|
|
288
293
|
}
|
|
289
294
|
|
|
295
|
+
// remove `type` if either `to` or `href` is specified
|
|
296
|
+
if (to || (restProps as any).href) {
|
|
297
|
+
buttonProps = {
|
|
298
|
+
...buttonProps,
|
|
299
|
+
type: null,
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
290
303
|
// apply stroke defaults and higher z-index when hovering to show outline in group properly
|
|
291
304
|
if (variant === 'outline') {
|
|
292
305
|
buttonProps = {
|
|
@@ -342,7 +355,7 @@ export function Button({
|
|
|
342
355
|
}
|
|
343
356
|
|
|
344
357
|
if (
|
|
345
|
-
type &&
|
|
358
|
+
buttonProps.type &&
|
|
346
359
|
(restProps as any).as &&
|
|
347
360
|
(restProps as any).as !== "button"
|
|
348
361
|
) {
|
|
@@ -19,7 +19,7 @@ function BodyRow({
|
|
|
19
19
|
} = useKeyboardShortcuts(keyboardShortcuts, { rowData, rowIndex })
|
|
20
20
|
const props = {
|
|
21
21
|
ref: innerRef,
|
|
22
|
-
onClick:
|
|
22
|
+
onClick: (event) => onRowClick && onRowClick(rowData, rowIndex, event),
|
|
23
23
|
onMouseEnter: bindKeyboardShortcuts,
|
|
24
24
|
onMouseLeave: unbindKeyboardShortcuts,
|
|
25
25
|
style: {
|
|
@@ -38,7 +38,10 @@ function BodyRows({
|
|
|
38
38
|
key={columnIndex}
|
|
39
39
|
ref={getColumnRef(`${columnIndex}.${rowIndex + 1}`)} // offset by 1 to account for header row
|
|
40
40
|
role="cell"
|
|
41
|
-
className={`tapestry-react-reset ${css([
|
|
41
|
+
className={`tapestry-react-reset ${css([
|
|
42
|
+
...cellVariantStyles,
|
|
43
|
+
column.css,
|
|
44
|
+
])}`}
|
|
42
45
|
>
|
|
43
46
|
{getCell(column.cell, {
|
|
44
47
|
columnIndex,
|
|
@@ -2,7 +2,6 @@ import React, { useCallback } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import Icon from '../../Icon'
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
const iconPaths = {
|
|
7
6
|
fill: 'tapestry.checkbox0',
|
|
8
7
|
minus: 'tapestry.checkbox1',
|
|
@@ -99,7 +98,7 @@ function CheckboxCell({
|
|
|
99
98
|
/>
|
|
100
99
|
<Icon.Path
|
|
101
100
|
name={iconPaths.minus}
|
|
102
|
-
className="tapestry-react-reset tapestry-react-Checkbox-
|
|
101
|
+
className="tapestry-react-reset tapestry-react-Checkbox-Fill"
|
|
103
102
|
/>
|
|
104
103
|
<Icon.Path
|
|
105
104
|
name={iconPaths.checked}
|
package/src/Divider/Divider.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
3
|
import Box from '../Box'
|
|
4
|
-
import { BoxProps, ColorProp } from '../index'
|
|
4
|
+
import { BoxProps, ColorProp, StyleProps } from '../index'
|
|
5
5
|
|
|
6
6
|
export type DividerProps = {
|
|
7
7
|
/**
|
|
@@ -23,7 +23,7 @@ export type DividerProps = {
|
|
|
23
23
|
* The size of the line in pixels
|
|
24
24
|
*/
|
|
25
25
|
size?: number
|
|
26
|
-
}
|
|
26
|
+
} & StyleProps
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Used to break up content
|
package/src/DragDrop/DragDrop.js
CHANGED
|
@@ -9,6 +9,8 @@ import React, {
|
|
|
9
9
|
import { createPortal } from 'react-dom'
|
|
10
10
|
import * as RBDND from '@planningcenter/react-beautiful-dnd'
|
|
11
11
|
import mitt from 'mitt'
|
|
12
|
+
import { getThemeDataAttribute } from '../ThemeProvider/styles'
|
|
13
|
+
import { useThemeValue } from '../system'
|
|
12
14
|
|
|
13
15
|
import StackView from '../StackView'
|
|
14
16
|
|
|
@@ -33,9 +35,12 @@ function useDragDrop() {
|
|
|
33
35
|
|
|
34
36
|
function Provider({ onDragStart, onDragEnd, ...props }) {
|
|
35
37
|
const hasParentDragDrop = useDragDrop()
|
|
38
|
+
const themeId = useThemeValue('id')
|
|
36
39
|
if (typeof document !== 'undefined' && portalNode === null) {
|
|
37
40
|
portalNode = document.createElement('div')
|
|
38
41
|
portalNode.id = 'rbd-portal'
|
|
42
|
+
portalNode.className = 'tapestry-react-reset'
|
|
43
|
+
portalNode.setAttribute(getThemeDataAttribute(themeId), 'true')
|
|
39
44
|
document.body.appendChild(portalNode)
|
|
40
45
|
}
|
|
41
46
|
useEffect(() => {
|
package/src/Dropdown/Dropdown.js
CHANGED
|
@@ -9,7 +9,7 @@ import Popover from '../Popover'
|
|
|
9
9
|
import { cloneChildren, generateId } from '../utils'
|
|
10
10
|
|
|
11
11
|
import Item, { ITEM_DISPLAY_NAME } from './Item'
|
|
12
|
-
import Link, { LINK_DISPLAY_NAME
|
|
12
|
+
import Link, { LINK_DISPLAY_NAME } from './Link'
|
|
13
13
|
|
|
14
14
|
type Props = {
|
|
15
15
|
children?: React.ReactNode,
|
|
@@ -125,7 +125,7 @@ class Dropdown extends Component<Props> {
|
|
|
125
125
|
this.closePopover()
|
|
126
126
|
this.popover.focusAnchor()
|
|
127
127
|
}
|
|
128
|
-
if (
|
|
128
|
+
if (node.tagName === 'A' && event.type !== 'click') {
|
|
129
129
|
node.click()
|
|
130
130
|
} else if (this.props.onSelect) {
|
|
131
131
|
this.props.onSelect(data)
|
|
@@ -215,18 +215,21 @@ class Dropdown extends Component<Props> {
|
|
|
215
215
|
'aria-haspopup': true,
|
|
216
216
|
'aria-expanded': isPopoverOpen,
|
|
217
217
|
[arrowIconOnly ? 'icon' : 'iconRight']: {
|
|
218
|
-
name: isPopoverOpen
|
|
218
|
+
name: isPopoverOpen
|
|
219
|
+
? 'general.upCaret'
|
|
220
|
+
: 'general.downCaret',
|
|
219
221
|
size: 'sm',
|
|
220
222
|
},
|
|
221
223
|
title: arrowIconOnly ? 'arrow down' : restProps.title,
|
|
222
224
|
tabIndex: 0,
|
|
223
225
|
cursor: 'pointer',
|
|
224
226
|
onBlur: requestBlur,
|
|
225
|
-
onClick: () => {
|
|
227
|
+
onClick: (event) => {
|
|
226
228
|
this.togglePopover()
|
|
227
229
|
if (!isPopoverOpen) {
|
|
228
230
|
this.popover.focusAnchor()
|
|
229
231
|
}
|
|
232
|
+
onClick && onClick(event)
|
|
230
233
|
},
|
|
231
234
|
onKeyDown: (event) => {
|
|
232
235
|
anchorProps.onKeyDown(event)
|
|
@@ -26,10 +26,10 @@ render(
|
|
|
26
26
|
render(
|
|
27
27
|
<Dropdown title="Links" size="sm" variant="outline">
|
|
28
28
|
<Dropdown.Link to="http://planning.center" external>
|
|
29
|
-
Planning Center
|
|
29
|
+
Planning Center (external)
|
|
30
30
|
</Dropdown.Link>
|
|
31
|
-
<Dropdown.Link to="
|
|
32
|
-
React
|
|
31
|
+
<Dropdown.Link to="/button">
|
|
32
|
+
Tapestry React Button
|
|
33
33
|
</Dropdown.Link>
|
|
34
34
|
</Dropdown>
|
|
35
35
|
)
|
package/src/Dropdown/Link.js
CHANGED
|
@@ -4,7 +4,6 @@ import { ItemListItem } from '../ItemList'
|
|
|
4
4
|
import Menu from '../Menu'
|
|
5
5
|
|
|
6
6
|
export const LINK_DISPLAY_NAME = 'Dropdown.Link'
|
|
7
|
-
export const LINK_DATA = 'link'
|
|
8
7
|
|
|
9
8
|
class Link extends Component {
|
|
10
9
|
// Graphql wasn't picking up the correct displayName when this was
|
|
@@ -17,12 +16,7 @@ class Link extends Component {
|
|
|
17
16
|
restProps.target = '_blank'
|
|
18
17
|
}
|
|
19
18
|
return (
|
|
20
|
-
<ItemListItem
|
|
21
|
-
data={LINK_DATA}
|
|
22
|
-
text={text}
|
|
23
|
-
disabled={disabled}
|
|
24
|
-
index={index}
|
|
25
|
-
>
|
|
19
|
+
<ItemListItem data="link" text={text} disabled={disabled} index={index}>
|
|
26
20
|
{({ id, highlight, highlighted, clearHighlight, select }) => (
|
|
27
21
|
<Menu.Item
|
|
28
22
|
as="a"
|
package/src/Icon/Icon.mdx
CHANGED
|
@@ -29,35 +29,35 @@ An "icon set" groups product-specific icon paths together. By default, `tapestry
|
|
|
29
29
|
Additional icon sets can be imported from [libraries like `@planningcenter/icons`](https://github.com/planningcenter/icons) and exported through your app's [ThemeProvider](/theming#themeprovider). (You can import all exports [by using an asterisk](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_an_entire_modules_contents).)
|
|
30
30
|
|
|
31
31
|
```jsx
|
|
32
|
+
{/* import icon sets in local theme definition */}
|
|
32
33
|
import * as calendar from '@planningcenter/icons/paths/calendar'
|
|
33
34
|
import * as giving from '@planningcenter/icons/paths/giving'
|
|
34
35
|
import * as people from '@planningcenter/icons/paths/people'
|
|
35
36
|
|
|
36
37
|
const theme = {
|
|
38
|
+
...themeOptions,
|
|
37
39
|
icons: {
|
|
38
40
|
calendar,
|
|
39
41
|
giving,
|
|
40
|
-
people
|
|
42
|
+
people,
|
|
43
|
+
...designSystem.defaultTheme.icons
|
|
41
44
|
},
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
</ThemeProvider>
|
|
47
|
+
{/* prefix Icon instance in component */}
|
|
48
|
+
<Icon name="calendar.reservationBlock" />
|
|
49
|
+
<Icon name="giving.clockCircleO" />
|
|
50
|
+
<Icon name="people.photoOutline" />
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
```jsx live
|
|
52
54
|
render(() => {
|
|
53
55
|
return (
|
|
54
|
-
<
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
</StackView>
|
|
60
|
-
</ThemeProvider>
|
|
56
|
+
<StackView axis="horizontal" spacing={2}>
|
|
57
|
+
<Icon name="calendar.reservationBlock" size="xl" />
|
|
58
|
+
<Icon name="giving.clockCircleO" size="xl" />
|
|
59
|
+
<Icon name="people.photoOutline" size="xl" />
|
|
60
|
+
</StackView>
|
|
61
61
|
)
|
|
62
62
|
})
|
|
63
63
|
```
|
|
@@ -72,42 +72,40 @@ render(() => {
|
|
|
72
72
|
const [appName, setAppName] = React.useState('general')
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
|
-
<
|
|
76
|
-
<StackView
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</Select.Option>
|
|
88
|
-
))}
|
|
89
|
-
</Select>
|
|
90
|
-
<Input
|
|
91
|
-
grow={1}
|
|
92
|
-
autoFocus
|
|
93
|
-
renderLeft={<Icon name="general.search" />}
|
|
94
|
-
placeholder="Search by icon name"
|
|
95
|
-
value={value}
|
|
96
|
-
onChange={(e) => setValue(e.target.value)}
|
|
97
|
-
/>
|
|
98
|
-
</StackView>
|
|
99
|
-
<TileView minCellWidth={16} spacing={4} margin={4}>
|
|
100
|
-
{matchSorter(Object.keys(icons[appName]), value).map((iconName) => (
|
|
101
|
-
<StackView key={iconName} alignment="center" spacing={1}>
|
|
102
|
-
<Icon key={iconName} name={`${appName}.${iconName}`} size="xl" />
|
|
103
|
-
<Text fontSize={5} color="foregroundSecondary">
|
|
104
|
-
{iconName}
|
|
105
|
-
</Text>
|
|
106
|
-
</StackView>
|
|
75
|
+
<StackView grow={1}>
|
|
76
|
+
<StackView axis="horizontal" spacing={2}>
|
|
77
|
+
<Select
|
|
78
|
+
basis={26}
|
|
79
|
+
emptyValue="Choose icon set"
|
|
80
|
+
onChange={(event) => setAppName(event.value)}
|
|
81
|
+
defaultValue={appName}
|
|
82
|
+
>
|
|
83
|
+
{appNames.map((appName) => (
|
|
84
|
+
<Select.Option key={appName} value={appName}>
|
|
85
|
+
{appName}
|
|
86
|
+
</Select.Option>
|
|
107
87
|
))}
|
|
108
|
-
</
|
|
88
|
+
</Select>
|
|
89
|
+
<Input
|
|
90
|
+
grow={1}
|
|
91
|
+
autoFocus
|
|
92
|
+
renderLeft={<Icon name="general.search" />}
|
|
93
|
+
placeholder="Search by icon name"
|
|
94
|
+
value={value}
|
|
95
|
+
onChange={(e) => setValue(e.target.value)}
|
|
96
|
+
/>
|
|
109
97
|
</StackView>
|
|
110
|
-
|
|
98
|
+
<TileView minCellWidth={16} spacing={4} margin={4}>
|
|
99
|
+
{matchSorter(Object.keys(icons[appName]), value).map((iconName) => (
|
|
100
|
+
<StackView key={iconName} alignment="center" spacing={1}>
|
|
101
|
+
<Icon key={iconName} name={`${appName}.${iconName}`} size="xl" />
|
|
102
|
+
<Text fontSize={5} color="foregroundSecondary">
|
|
103
|
+
{iconName}
|
|
104
|
+
</Text>
|
|
105
|
+
</StackView>
|
|
106
|
+
))}
|
|
107
|
+
</TileView>
|
|
108
|
+
</StackView>
|
|
111
109
|
)
|
|
112
110
|
})
|
|
113
111
|
```
|
package/src/Input/InputLabel.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useCallback, useRef, useEffect } from 'react'
|
|
3
3
|
|
|
4
4
|
import { getColor } from '../system'
|
|
5
5
|
import Text from '../Text'
|
|
6
|
+
import { useThemeProps } from '../system'
|
|
6
7
|
|
|
7
8
|
import { inputs, inputLabels } from './utils'
|
|
8
9
|
|
|
@@ -10,54 +11,56 @@ export type InputLabelProps = {
|
|
|
10
11
|
/**
|
|
11
12
|
* The `id` of the input to control. Compatible with all Tapestry-React form components.
|
|
12
13
|
*/
|
|
13
|
-
controls
|
|
14
|
+
controls?: string,
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* The current state of the label. Should match corresponding `Input`'s state prop.
|
|
17
18
|
*/
|
|
18
|
-
state
|
|
19
|
+
state?: 'warning' | 'error' | 'success',
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.input = inputs[this.props.controls]
|
|
24
|
-
inputLabels[this.props.controls] = true
|
|
25
|
-
}
|
|
22
|
+
function InputLabel({ controls, state, ...restProps }: InputLabelProps) {
|
|
23
|
+
const { ...themeProps } = useThemeProps('inputLabel', restProps)
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
delete inputLabels[this.props.controls]
|
|
29
|
-
}
|
|
25
|
+
const input = useRef(null)
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
if (controls) {
|
|
28
|
+
themeProps.id = `${controls}-label`
|
|
33
29
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.input && this.input.setState({ isHovered: true })
|
|
30
|
+
if (state) {
|
|
31
|
+
themeProps.color = getColor(state)
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
input.current = inputs[controls]
|
|
36
|
+
inputLabels[controls] = true
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (controls) {
|
|
46
|
-
restProps.id = `${controls}-label`
|
|
47
|
-
}
|
|
48
|
-
if (state) {
|
|
49
|
-
restProps.color = getColor(state)
|
|
38
|
+
return () => {
|
|
39
|
+
delete inputLabels[controls]
|
|
50
40
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
const focusInput = useCallback(() => {
|
|
44
|
+
input.current && input.current.focus()
|
|
45
|
+
}, [input])
|
|
46
|
+
|
|
47
|
+
const handleMouseOver = useCallback(() => {
|
|
48
|
+
input.current && input.current.setState({ isHovered: true })
|
|
49
|
+
}, [input])
|
|
50
|
+
|
|
51
|
+
const handleMouseOut = useCallback(() => {
|
|
52
|
+
input.current && input.current.setState({ isHovered: false })
|
|
53
|
+
}, [input])
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Text
|
|
57
|
+
as="label"
|
|
58
|
+
onMouseOver={handleMouseOver}
|
|
59
|
+
onMouseOut={handleMouseOut}
|
|
60
|
+
onClick={focusInput}
|
|
61
|
+
{...themeProps}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
InputLabel.displayName = 'Input.InputLabel'
|
package/src/Input/InputLabel.mdx
CHANGED
|
@@ -4,6 +4,7 @@ category: Forms
|
|
|
4
4
|
summary: Provides accessibility as well as usability improvements for mouse users by allowing the user to click the <InputLabel/> component to focus the respective control. This mimics the browsers native label tag, but allows use with custom components like <Select/>.
|
|
5
5
|
propsSummary: Accepts [Text](/text) props.
|
|
6
6
|
parent: Input
|
|
7
|
+
themeKey: inputLabel
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
```jsx live
|
package/src/Modal/Modal.js
CHANGED
|
@@ -5,6 +5,7 @@ import Box from '../Box'
|
|
|
5
5
|
import Scrim from '../Scrim'
|
|
6
6
|
import { useDocumentEvent } from '../hooks'
|
|
7
7
|
import { trapFocus } from '../utils'
|
|
8
|
+
import { useThemeProps } from '../system'
|
|
8
9
|
|
|
9
10
|
export type ModalProps = {
|
|
10
11
|
children?: any,
|
|
@@ -23,6 +24,11 @@ export type ModalProps = {
|
|
|
23
24
|
* Determines whether the modal is open or not.
|
|
24
25
|
*/
|
|
25
26
|
open: boolean,
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Props passed to the internal [`<Scrim/>`](/scrim) component.
|
|
30
|
+
*/
|
|
31
|
+
scrimProps?: object,
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
function Modal({
|
|
@@ -32,6 +38,7 @@ function Modal({
|
|
|
32
38
|
open,
|
|
33
39
|
...restProps
|
|
34
40
|
}: ModalProps) {
|
|
41
|
+
const { scrimProps = {}, ...themeProps } = useThemeProps('modal', restProps)
|
|
35
42
|
const modalRef = useRef(null)
|
|
36
43
|
|
|
37
44
|
useLayoutEffect(() => {
|
|
@@ -58,16 +65,19 @@ function Modal({
|
|
|
58
65
|
onRequestClose()
|
|
59
66
|
}
|
|
60
67
|
}}
|
|
68
|
+
{...scrimProps}
|
|
61
69
|
>
|
|
62
70
|
<Box
|
|
71
|
+
backgroundColor="surface"
|
|
72
|
+
boxShadow="0 0 20px rgba(0, 0, 0, 0.15)"
|
|
63
73
|
innerRef={modalRef}
|
|
64
|
-
width="100%"
|
|
65
|
-
maxWidth={60}
|
|
66
|
-
padding={2}
|
|
67
74
|
margin={4}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
75
|
+
maxWidth={60}
|
|
76
|
+
padding={4}
|
|
77
|
+
paddingBottom={3}
|
|
78
|
+
radius={8}
|
|
79
|
+
width="100%"
|
|
80
|
+
{...themeProps}
|
|
71
81
|
>
|
|
72
82
|
{children}
|
|
73
83
|
</Box>
|
package/src/Modal/Modal.mdx
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
title: Modal
|
|
3
3
|
category: Overlays
|
|
4
4
|
propsSummary: Accepts [Box](/box) props.
|
|
5
|
+
themeKey: modal
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
```jsx live
|
|
@@ -16,7 +17,7 @@ function MyModal(props) {
|
|
|
16
17
|
return () => setLazyComponent(null)
|
|
17
18
|
}, [props.open])
|
|
18
19
|
return (
|
|
19
|
-
<Modal id="modal" closeOnOutsideClick height={
|
|
20
|
+
<Modal id="modal" closeOnOutsideClick height={25} {...props}>
|
|
20
21
|
<StackView spacing={2}>
|
|
21
22
|
{lazyComponent || <Text>Loading lazy component...</Text>}
|
|
22
23
|
<Select
|
package/src/Popover/Popover.mdx
CHANGED
package/src/Popover/Popover.tsx
CHANGED
|
@@ -7,6 +7,8 @@ import { lockScroll } from '../utils'
|
|
|
7
7
|
|
|
8
8
|
import rewireTabOrder from './rewireTabOrder'
|
|
9
9
|
import { getFixedParent, getModifiers } from './utils'
|
|
10
|
+
import { useThemeProps } from '../system'
|
|
11
|
+
import { useTheme } from '@emotion/react'
|
|
10
12
|
|
|
11
13
|
type anchorCallbackProps = {
|
|
12
14
|
innerRef(node: HTMLElement): void
|
|
@@ -116,6 +118,10 @@ export const Popover = React.forwardRef(
|
|
|
116
118
|
}: PopoverProps,
|
|
117
119
|
ref
|
|
118
120
|
) => {
|
|
121
|
+
const { zIndex = 10000, ...themeProps } = useThemeProps(
|
|
122
|
+
'popover',
|
|
123
|
+
restProps
|
|
124
|
+
)
|
|
119
125
|
const anchorRef = React.useRef(null)
|
|
120
126
|
const popperRef = React.useRef(null)
|
|
121
127
|
const unlockScroll = React.useRef(null)
|
|
@@ -253,8 +259,8 @@ export const Popover = React.forwardRef(
|
|
|
253
259
|
}
|
|
254
260
|
},
|
|
255
261
|
// ideally this should be pulled out to something like ThemeProvider for predictable z indices
|
|
256
|
-
style: { zIndex
|
|
257
|
-
...
|
|
262
|
+
style: { zIndex },
|
|
263
|
+
...themeProps,
|
|
258
264
|
})
|
|
259
265
|
: null}
|
|
260
266
|
</Portal>
|
package/src/Portal/Portal.tsx
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
|
+
import { getThemeDataAttribute } from '../ThemeProvider/styles'
|
|
4
|
+
import { ThemeContext } from '@emotion/react'
|
|
5
|
+
import { Theme } from '../index'
|
|
3
6
|
|
|
4
7
|
export type PortalProps = {
|
|
5
8
|
children: any
|
|
@@ -27,6 +30,9 @@ class Portal extends React.Component<PortalProps> {
|
|
|
27
30
|
renderTo: null,
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
static contextType = ThemeContext
|
|
34
|
+
context: React.ContextType<React.Context<Theme>>
|
|
35
|
+
|
|
30
36
|
_portalNode: HTMLElement = null
|
|
31
37
|
_needsUpdate = false
|
|
32
38
|
_updated = false
|
|
@@ -105,6 +111,14 @@ class Portal extends React.Component<PortalProps> {
|
|
|
105
111
|
Object.keys(restProps).forEach((key) => {
|
|
106
112
|
this._portalNode.setAttribute(key, restProps[key])
|
|
107
113
|
})
|
|
114
|
+
|
|
115
|
+
this._portalNode.classList.add('tapestry-react-reset')
|
|
116
|
+
|
|
117
|
+
this._portalNode.setAttribute(
|
|
118
|
+
getThemeDataAttribute(this.context.id),
|
|
119
|
+
'true'
|
|
120
|
+
)
|
|
121
|
+
|
|
108
122
|
if (style) {
|
|
109
123
|
Object.keys(style).forEach((key) => {
|
|
110
124
|
this._portalNode.style[key] = style[key]
|