@planningcenter/tapestry-react 2.1.2 → 2.3.0

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.
Files changed (88) hide show
  1. package/dist/cjs/Badge/Badge.js +5 -1
  2. package/dist/cjs/Button/Button.js +6 -3
  3. package/dist/cjs/Card/Card.js +5 -2
  4. package/dist/cjs/Combobox/Combobox.js +16 -43
  5. package/dist/cjs/Combobox/ComboboxInput.js +112 -146
  6. package/dist/cjs/Combobox/ComboboxItem.js +38 -53
  7. package/dist/cjs/Combobox/ComboboxItems.js +41 -58
  8. package/dist/cjs/Combobox/index.js +12 -0
  9. package/dist/cjs/DateField/DateField.js +109 -128
  10. package/dist/cjs/Field/Field.js +80 -106
  11. package/dist/cjs/Menu/Item.js +1 -0
  12. package/dist/cjs/Popover/utils.js +1 -0
  13. package/dist/cjs/SegmentedControl/SegmentedControl.js +89 -111
  14. package/dist/cjs/SegmentedTabs/SegmentedTabs.js +54 -84
  15. package/dist/cjs/Tabs/Tab.js +9 -6
  16. package/dist/cjs/Tabs/TabList.js +49 -64
  17. package/dist/cjs/Tabs/TabPanel.js +6 -2
  18. package/dist/cjs/Tabs/TabPanels.js +14 -27
  19. package/dist/cjs/Tabs/Tabs.js +72 -106
  20. package/dist/cjs/Tabs/index.js +12 -0
  21. package/dist/cjs/ThemeProvider/ThemeProvider.js +1 -1
  22. package/dist/cjs/Tooltip/Tooltip.js +158 -182
  23. package/dist/cjs/Wizard/Wizard.js +143 -193
  24. package/dist/cjs/Wizard/index.js +3 -0
  25. package/dist/esm/Badge/Badge.js +5 -1
  26. package/dist/esm/Button/Button.js +6 -3
  27. package/dist/esm/Card/Card.js +5 -2
  28. package/dist/esm/Combobox/Combobox.js +18 -43
  29. package/dist/esm/Combobox/ComboboxInput.js +111 -149
  30. package/dist/esm/Combobox/ComboboxItem.js +38 -52
  31. package/dist/esm/Combobox/ComboboxItems.js +38 -56
  32. package/dist/esm/Combobox/index.js +8 -0
  33. package/dist/esm/DateField/DateField.js +106 -133
  34. package/dist/esm/Field/Field.js +76 -103
  35. package/dist/esm/Menu/Item.js +1 -0
  36. package/dist/esm/Popover/utils.js +1 -0
  37. package/dist/esm/SegmentedControl/SegmentedControl.js +90 -114
  38. package/dist/esm/SegmentedTabs/SegmentedTabs.js +51 -83
  39. package/dist/esm/Tabs/Tab.js +8 -6
  40. package/dist/esm/Tabs/TabList.js +49 -66
  41. package/dist/esm/Tabs/TabPanel.js +4 -2
  42. package/dist/esm/Tabs/TabPanels.js +14 -28
  43. package/dist/esm/Tabs/Tabs.js +76 -120
  44. package/dist/esm/Tabs/index.js +8 -0
  45. package/dist/esm/ThemeProvider/ThemeProvider.js +1 -1
  46. package/dist/esm/Tooltip/Tooltip.js +154 -195
  47. package/dist/esm/Wizard/Wizard.js +144 -201
  48. package/dist/esm/Wizard/index.js +2 -0
  49. package/dist/types/Popover/utils.d.ts +3 -0
  50. package/package.json +1 -1
  51. package/src/.DS_Store +0 -0
  52. package/src/Badge/Badge.js +5 -0
  53. package/src/Button/Button.tsx +6 -3
  54. package/src/Card/Card.tsx +22 -1
  55. package/src/Combobox/Combobox.js +18 -32
  56. package/src/Combobox/Combobox.mdx +1 -0
  57. package/src/Combobox/Combobox.test.js +1 -1
  58. package/src/Combobox/ComboboxInput.js +111 -105
  59. package/src/Combobox/ComboboxItem.js +27 -27
  60. package/src/Combobox/ComboboxItems.js +38 -60
  61. package/src/Combobox/index.js +8 -0
  62. package/src/DateField/DateField.js +109 -105
  63. package/src/DateField/DateField.mdx +1 -0
  64. package/src/Field/Field.js +85 -93
  65. package/src/Field/Field.mdx +1 -0
  66. package/src/Menu/Heading.js +5 -1
  67. package/src/Menu/Heading.mdx +20 -0
  68. package/src/Menu/Item.js +13 -1
  69. package/src/Menu/Item.mdx +18 -0
  70. package/src/Menu/Menu.mdx +1 -0
  71. package/src/Popover/utils.ts +1 -0
  72. package/src/SegmentedControl/SegmentedControl.js +88 -92
  73. package/src/SegmentedControl/SegmentedControl.mdx +1 -0
  74. package/src/SegmentedTabs/SegmentedTabs.js +51 -71
  75. package/src/SegmentedTabs/SegmentedTabs.mdx +1 -0
  76. package/src/Tabs/Tab.js +3 -1
  77. package/src/Tabs/TabList.js +56 -62
  78. package/src/Tabs/TabPanel.js +2 -1
  79. package/src/Tabs/TabPanels.js +14 -15
  80. package/src/Tabs/Tabs.js +63 -84
  81. package/src/Tabs/Tabs.mdx +16 -17
  82. package/src/Tabs/index.js +8 -0
  83. package/src/ThemeProvider/ThemeProvider.tsx +1 -1
  84. package/src/Tooltip/Tooltip.js +142 -160
  85. package/src/Tooltip/Tooltip.mdx +1 -0
  86. package/src/Wizard/Wizard.js +141 -170
  87. package/src/Wizard/Wizard.mdx +3 -2
  88. package/src/Wizard/index.js +2 -0
@@ -2,6 +2,7 @@
2
2
  title: DateField
3
3
  category: Forms
4
4
  propsSummary: Accepts [Input](/input) props.
5
+ themeKey: dateField
5
6
  ---
6
7
 
7
8
  ```jsx live
@@ -1,5 +1,5 @@
1
1
  // @flow
2
- import React, { Component } from 'react'
2
+ import React from 'react'
3
3
 
4
4
  import Box from '../Box'
5
5
  import HelperDrawer from '../HelperDrawer'
@@ -7,6 +7,7 @@ import Input from '../Input'
7
7
  import Text from '../Text'
8
8
  import StackView from '../StackView'
9
9
  import { cloneChildren, generateId } from '../utils'
10
+ import { useThemeProps } from '../system'
10
11
 
11
12
  type Props = {
12
13
  /** Usually accepts form fields, such as `input` or `select`. */
@@ -52,106 +53,97 @@ type Props = {
52
53
  icon?: any,
53
54
  }
54
55
 
55
- class Field extends Component<Props> {
56
- static defaultProps = {
57
- distribution: 'fill',
58
- spacing: 1,
59
- }
60
-
61
- helperDrawerId = generateId('field-helper-drawer')
62
-
63
- fieldId = generateId('field')
64
-
65
- render() {
66
- const {
67
- children,
68
- compact,
69
- distribution,
70
- feedbackText,
71
- helpContent,
72
- icon,
73
- inline,
74
- innerRef,
75
- label,
76
- labelBasis,
77
- labelColor,
78
- labelGrow,
79
- spacing,
80
- state,
81
- ...restProps
82
- } = this.props
83
- return (
84
- <Box innerRef={innerRef} width="100%" {...restProps}>
85
- <StackView axis={inline ? 'horizontal' : 'vertical'} wrap>
86
- {label && (
87
- <StackView
88
- axis="horizontal"
89
- alignment="center"
90
- grow={labelGrow}
91
- basis={labelBasis}
92
- marginRight={inline ? 2 : undefined}
93
- >
94
- {icon}
95
-
96
- <Input.InputLabel
97
- controls={this.fieldId}
98
- fontSize={compact ? 4 : 3}
99
- color={labelColor}
100
- >
101
- {label}
102
- </Input.InputLabel>
103
-
104
- {helpContent && (
105
- <HelperDrawer.Toggle
106
- drawerId={this.helperDrawerId}
107
- marginLeft={0.25}
108
- marginRight={inline ? 1 : undefined}
109
- />
110
- )}
111
- </StackView>
112
- )}
113
-
114
- {helpContent && (
115
- <StackView axis="horizontal" order={inline ? 1 : 0} width="100%">
116
- <HelperDrawer
117
- id={this.helperDrawerId}
118
- marginTop={1}
119
- children={helpContent}
120
- />
121
- </StackView>
122
- )}
123
-
56
+ function Field({ ...props }: Props) {
57
+ const {
58
+ children,
59
+ compact,
60
+ distribution = 'fill',
61
+ feedbackText,
62
+ helpContent,
63
+ icon,
64
+ inline,
65
+ innerRef,
66
+ label,
67
+ labelBasis,
68
+ labelColor,
69
+ labelGrow,
70
+ spacing = 1,
71
+ state,
72
+ ...restProps
73
+ } = useThemeProps('field', props)
74
+ const helperDrawerId = generateId('field-helper-drawer')
75
+ const fieldId = generateId('field')
76
+ return (
77
+ <Box innerRef={innerRef} width="100%" {...restProps}>
78
+ <StackView axis={inline ? 'horizontal' : 'vertical'} wrap>
79
+ {label && (
124
80
  <StackView
125
81
  axis="horizontal"
126
82
  alignment="center"
127
- distribution={distribution}
128
- order={inline ? 0 : 1}
129
- grow={1}
130
- marginTop={inline || !label ? undefined : 1}
131
- maxWidth="100%"
132
- spacing={spacing}
83
+ grow={labelGrow}
84
+ basis={labelBasis}
85
+ marginRight={inline ? 2 : undefined}
133
86
  >
134
- {cloneChildren(children, (child, { firstChild }) =>
135
- firstChild
136
- ? {
137
- id: this.fieldId,
138
- size: child.props.size || (compact ? 'sm' : 'md'),
139
- }
140
- : {
141
- size: child.props.size || (compact ? 'sm' : 'md'),
142
- }
87
+ {icon}
88
+
89
+ <Input.InputLabel
90
+ controls={fieldId}
91
+ fontSize={compact ? 4 : 3}
92
+ color={labelColor}
93
+ >
94
+ {label}
95
+ </Input.InputLabel>
96
+
97
+ {helpContent && (
98
+ <HelperDrawer.Toggle
99
+ drawerId={helperDrawerId}
100
+ marginLeft={0.25}
101
+ marginRight={inline ? 1 : undefined}
102
+ />
143
103
  )}
144
104
  </StackView>
145
- </StackView>
105
+ )}
146
106
 
147
- {feedbackText && (
148
- <Text marginTop={1} color={state} align={inline ? 'right' : 'left'}>
149
- {feedbackText}
150
- </Text>
107
+ {helpContent && (
108
+ <StackView axis="horizontal" order={inline ? 1 : 0} width="100%">
109
+ <HelperDrawer
110
+ id={helperDrawerId}
111
+ marginTop={1}
112
+ children={helpContent}
113
+ />
114
+ </StackView>
151
115
  )}
152
- </Box>
153
- )
154
- }
116
+
117
+ <StackView
118
+ axis="horizontal"
119
+ alignment="center"
120
+ distribution={distribution}
121
+ order={inline ? 0 : 1}
122
+ grow={1}
123
+ marginTop={inline || !label ? undefined : 1}
124
+ maxWidth="100%"
125
+ spacing={spacing}
126
+ >
127
+ {cloneChildren(children, (child, { firstChild }) =>
128
+ firstChild
129
+ ? {
130
+ id: fieldId,
131
+ size: child.props.size || (compact ? 'sm' : 'md'),
132
+ }
133
+ : {
134
+ size: child.props.size || (compact ? 'sm' : 'md'),
135
+ }
136
+ )}
137
+ </StackView>
138
+ </StackView>
139
+
140
+ {feedbackText && (
141
+ <Text marginTop={1} color={state} align={inline ? 'right' : 'left'}>
142
+ {feedbackText}
143
+ </Text>
144
+ )}
145
+ </Box>
146
+ )
155
147
  }
156
148
 
157
149
  export default Field
@@ -3,6 +3,7 @@ title: Field
3
3
  category: Forms
4
4
  summary: Composes [InputLabel](/inputlabel) and passes an `id` to the first child to pair labels and controls automatically.
5
5
  propsSummary: Accepts [Box](/box) props.
6
+ themeKey: field
6
7
  ---
7
8
 
8
9
  ```jsx live
@@ -2,7 +2,11 @@ import React from 'react'
2
2
 
3
3
  import HeadingUppercase from '../HeadingUppercase'
4
4
 
5
- function Heading({ children, ...restProps }) {
5
+ export type Props = {
6
+ children?: any,
7
+ }
8
+
9
+ function Heading({ children, ...restProps }: Props) {
6
10
  return (
7
11
  <HeadingUppercase
8
12
  paddingBottom={0.5}
@@ -0,0 +1,20 @@
1
+ ---
2
+ title: Menu.Heading
3
+ category: General
4
+ propsSummary: Accepts [HeadingUppercase](/headinguppercase) props.
5
+ parent: Menu
6
+ ---
7
+
8
+ ```jsx live
9
+ render(
10
+ <Menu>
11
+ <Menu.Heading>Heading 1</Menu.Heading>
12
+ <Menu.Item>Item 1</Menu.Item>
13
+ <Menu.Item>Item 2</Menu.Item>
14
+ <Divider margin={0.5} />
15
+ <Menu.Heading>Heading 2</Menu.Heading>
16
+ <Menu.Item>Item 3</Menu.Item>
17
+ <Menu.Item>Item 4</Menu.Item>
18
+ </Menu>
19
+ )
20
+ ```
package/src/Menu/Item.js CHANGED
@@ -3,6 +3,16 @@ import React, { cloneElement } from 'react'
3
3
  import Box from '../Box'
4
4
  import StackView from '../StackView'
5
5
 
6
+ export type Props = {
7
+ children: any,
8
+ disabled: boolean,
9
+ backgroundColor: string,
10
+ highlightedColor: string,
11
+ isHighlighted: boolean,
12
+ renderLeft: Function | React.ReactNode,
13
+ renderRight: Function | React.ReactNode,
14
+ }
15
+
6
16
  function Item({
7
17
  backgroundColor = 'surface',
8
18
  children,
@@ -12,7 +22,7 @@ function Item({
12
22
  renderLeft,
13
23
  renderRight,
14
24
  ...props
15
- }) {
25
+ }: Props) {
16
26
  const css = {
17
27
  axis: 'horizontal',
18
28
  alignment: 'center',
@@ -96,4 +106,6 @@ function Item({
96
106
  )
97
107
  }
98
108
 
109
+ Item.displayName = 'Menu.Item'
110
+
99
111
  export default Item
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: Menu.Item
3
+ category: General
4
+ propsSummary: Accepts [StackView](/stackview) props.
5
+ parent: Menu
6
+ ---
7
+
8
+ ```jsx live
9
+ render(
10
+ <Menu>
11
+ <Menu.Item isHighlighted>Can be highlighted</Menu.Item>
12
+ <Menu.Item>Should be used as a child of Menu</Menu.Item>
13
+ <Menu.Item>
14
+ <Icon name="general.person" marginRight={1} /> Add icons and other things
15
+ </Menu.Item>
16
+ </Menu>
17
+ )
18
+ ```
package/src/Menu/Menu.mdx CHANGED
@@ -2,6 +2,7 @@
2
2
  title: Menu
3
3
  category: General
4
4
  propsSummary: Accepts [Card](/card) props.
5
+ isParent: true
5
6
  ---
6
7
 
7
8
  ```jsx live
@@ -19,6 +19,7 @@ export function getModifiers({ matchWidths, offset, keepInView, shouldFlip }) {
19
19
  enabled: Boolean(matchWidths),
20
20
  phase: 'write',
21
21
  requires: ['computeStyles'],
22
+ fn: () => {},
22
23
  effect: ({ state }) => {
23
24
  const { offsetWidth } = state.elements.reference
24
25
  if (matchWidths === 'minimum') {
@@ -1,9 +1,17 @@
1
1
  // @flow
2
- import React, { Component } from 'react'
2
+ import React, {
3
+ forwardRef,
4
+ useCallback,
5
+ useImperativeHandle,
6
+ useRef,
7
+ useState,
8
+ useEffect,
9
+ } from 'react'
3
10
 
4
11
  import Button from '../Button'
5
12
  import InputBox from '../Input/InputBox'
6
13
  import { navigateSize } from '../system'
14
+ import { useThemeProps } from '../system'
7
15
 
8
16
  type Props = {
9
17
  activeSegment?: string,
@@ -14,110 +22,98 @@ type Props = {
14
22
  size?: 'xs' | 'sm' | 'md' | 'lg',
15
23
  }
16
24
 
17
- class SegmentedControl extends Component<Props> {
18
- constructor(props: Props) {
19
- super(props)
20
- this.state = {
21
- activeIndex: this.getActiveIndex(props),
22
- }
23
- }
24
-
25
- componentDidUpdate(lastProps) {
26
- if (lastProps.activeSegment !== this.props.activeSegment) {
27
- this.setState({ activeIndex: this.getActiveIndex(this.props) })
28
- }
29
- }
30
-
31
- getActiveIndex = (props) => {
25
+ function SegmentedControl(props: Props, ref) {
26
+ const getActiveIndex = useCallback((props) => {
32
27
  return props.activeSegment === undefined
33
28
  ? 0
34
29
  : props.segments.indexOf(props.activeSegment)
35
- }
36
-
37
- setInputBox = (component) => {
38
- this.inputBox = component
39
- }
40
-
41
- focus(index) {
42
- this.inputBox.focus(index)
43
- }
30
+ })
31
+ const inputBoxRef = useRef(null)
32
+ const {
33
+ activeSegment,
34
+ color = 'primary',
35
+ disabled,
36
+ onChange,
37
+ segments,
38
+ segmentBasis = 'auto',
39
+ size = 'md',
40
+ ...restProps
41
+ } = useThemeProps('segmentedControl', props)
42
+ const [activeIndex, setActiveIndex] = useState(getActiveIndex(props))
44
43
 
45
- blur() {
46
- this.inputBox.blur()
47
- }
48
-
49
- handleKeyDown = (event) => {
50
- if (
51
- this.props.onChange &&
52
- (event.key === 'ArrowLeft' || event.key === 'ArrowRight')
53
- ) {
44
+ const handleKeyDown = useCallback((event) => {
45
+ if (onChange && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
54
46
  const amountToMove = event.key === 'ArrowLeft' ? -1 : 1
55
- const nextIndex = this.state.activeIndex + amountToMove
47
+ const nextIndex = activeIndex + amountToMove
56
48
  event.preventDefault()
57
- this.changeSegment(nextIndex)
49
+ changeSegment(nextIndex)
58
50
  }
59
- }
51
+ })
60
52
 
61
- changeSegment = (index) => {
62
- const nextSegment = this.props.segments[index]
53
+ const changeSegment = useCallback((index) => {
54
+ const nextSegment = segments[index]
63
55
  if (nextSegment) {
64
- if (this.props.activeSegment === undefined) {
65
- this.setState({ activeIndex: index })
56
+ if (activeSegment === undefined) {
57
+ setActiveIndex(index)
66
58
  }
67
- if (this.props.onChange) {
68
- this.props.onChange(nextSegment.title || nextSegment)
59
+ if (onChange) {
60
+ onChange(nextSegment.title || nextSegment)
69
61
  }
70
- this.focus(index)
62
+ focus(index)
63
+ }
64
+ })
65
+
66
+ const focus = useCallback((index) => inputBoxRef.current.focus(index))
67
+ const blur = useCallback(() => inputBoxRef.current.blur())
68
+
69
+ useImperativeHandle(ref, () => ({
70
+ focus,
71
+ blur,
72
+ }))
73
+
74
+ useEffect(() => {
75
+ const newActiveIndex = getActiveIndex(props)
76
+ if (activeIndex !== newActiveIndex) {
77
+ setActiveIndex(newActiveIndex)
71
78
  }
72
- }
79
+ }, [activeSegment])
73
80
 
74
- render() {
75
- const {
76
- activeSegment,
77
- color = 'primary',
78
- disabled,
79
- onChange,
80
- segments,
81
- segmentBasis = 'auto',
82
- size = 'md',
83
- ...restProps
84
- } = this.props
85
- const { activeIndex } = this.state
86
- return (
87
- <InputBox
88
- ref={this.setInputBox}
89
- size={size}
90
- includeSpacing
91
- evenPadding
92
- role="group"
93
- cursor="initial"
94
- disabled={disabled}
95
- {...restProps}
96
- >
97
- {segments.map((segment, segmentIndex) => {
98
- const { title, ...restSegmentProps } = segment
99
- const buttonProps = title ? restSegmentProps : {}
100
- return (
101
- <Button
102
- key={segmentIndex}
103
- grow={1}
104
- size={navigateSize(size, -1)}
105
- basis={segmentBasis}
106
- theme={segmentIndex === activeIndex ? color : undefined}
107
- variant={segmentIndex === activeIndex ? 'fill' : 'naked'}
108
- title={title || segment}
109
- disabled={disabled}
110
- onKeyDown={this.handleKeyDown}
111
- onClick={() =>
112
- segmentIndex !== activeIndex && this.changeSegment(segmentIndex)
113
- }
114
- {...buttonProps}
115
- />
116
- )
117
- })}
118
- </InputBox>
119
- )
120
- }
81
+ return (
82
+ <InputBox
83
+ ref={inputBoxRef}
84
+ size={size}
85
+ includeSpacing
86
+ evenPadding
87
+ role="group"
88
+ cursor="initial"
89
+ disabled={disabled}
90
+ {...restProps}
91
+ >
92
+ {segments.map((segment, segmentIndex) => {
93
+ const { title, ...restSegmentProps } = segment
94
+ const buttonProps = title ? restSegmentProps : {}
95
+ return (
96
+ <Button
97
+ key={segmentIndex}
98
+ grow={1}
99
+ size={navigateSize(size, -1)}
100
+ basis={segmentBasis}
101
+ theme={segmentIndex === activeIndex ? color : undefined}
102
+ variant={segmentIndex === activeIndex ? 'fill' : 'naked'}
103
+ title={title || segment}
104
+ disabled={disabled}
105
+ onKeyDown={handleKeyDown}
106
+ onClick={() =>
107
+ segmentIndex !== activeIndex && changeSegment(segmentIndex)
108
+ }
109
+ {...buttonProps}
110
+ />
111
+ )
112
+ })}
113
+ </InputBox>
114
+ )
121
115
  }
122
116
 
117
+ SegmentedControl = forwardRef(SegmentedControl)
118
+
123
119
  export default SegmentedControl
@@ -2,6 +2,7 @@
2
2
  title: SegmentedControl
3
3
  category: General
4
4
  propsSummary: Accepts [Input.Inputbox](/input.inputbox) props.
5
+ themeKey: segmentedControl
5
6
  ---
6
7
 
7
8
  ```jsx live