@react-spectrum/tree 3.0.0-nightly.5038 → 3.0.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.
package/src/TreeView.tsx CHANGED
@@ -10,21 +10,31 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {AriaTreeGridListProps} from '@react-aria/tree';
14
- import {ButtonContext, Collection, TreeItemContentRenderProps, TreeItemProps, TreeItemRenderProps, TreeRenderProps, UNSTABLE_Tree, UNSTABLE_TreeItem, UNSTABLE_TreeItemContent, useContextProps} from 'react-aria-components';
13
+ import {AriaTreeProps} from '@react-aria/tree';
14
+ import {
15
+ ButtonContext,
16
+ Tree,
17
+ TreeItem,
18
+ TreeItemContent,
19
+ TreeItemContentProps,
20
+ TreeItemContentRenderProps,
21
+ TreeItemProps,
22
+ TreeItemRenderProps,
23
+ TreeRenderProps,
24
+ useContextProps
25
+ } from 'react-aria-components';
15
26
  import {Checkbox} from '@react-spectrum/checkbox';
16
27
  import ChevronLeftMedium from '@spectrum-icons/ui/ChevronLeftMedium';
17
28
  import ChevronRightMedium from '@spectrum-icons/ui/ChevronRightMedium';
18
29
  import {DOMRef, Expandable, Key, SelectionBehavior, SpectrumSelectionProps, StyleProps} from '@react-types/shared';
30
+ import {focusRing, style} from '@react-spectrum/style-macro-s1' with {type: 'macro'};
19
31
  import {isAndroid} from '@react-aria/utils';
20
- import React, {createContext, isValidElement, JSX, JSXElementConstructor, ReactElement, ReactNode, useContext, useRef} from 'react';
32
+ import React, {createContext, JSX, JSXElementConstructor, ReactElement, ReactNode, useRef} from 'react';
21
33
  import {SlotProvider, useDOMRef, useStyleProps} from '@react-spectrum/utils';
22
- import {style} from '@react-spectrum/style-macro-s1' with {type: 'macro'};
23
- import {Text} from '@react-spectrum/text';
24
34
  import {useButton} from '@react-aria/button';
25
35
  import {useLocale} from '@react-aria/i18n';
26
36
 
27
- export interface SpectrumTreeViewProps<T> extends Omit<AriaTreeGridListProps<T>, 'children'>, StyleProps, SpectrumSelectionProps, Expandable {
37
+ export interface SpectrumTreeViewProps<T> extends Omit<AriaTreeProps<T>, 'children'>, StyleProps, SpectrumSelectionProps, Expandable {
28
38
  /** Provides content to display when there are no items in the tree. */
29
39
  renderEmptyState?: () => JSX.Element,
30
40
  /**
@@ -38,13 +48,9 @@ export interface SpectrumTreeViewProps<T> extends Omit<AriaTreeGridListProps<T>,
38
48
  children?: ReactNode | ((item: T) => ReactNode)
39
49
  }
40
50
 
41
- export interface SpectrumTreeViewItemProps<T extends object = object> extends Omit<TreeItemProps, 'className' | 'style' | 'value' | 'onHoverStart' | 'onHoverEnd' | 'onHoverChange'> {
51
+ export interface SpectrumTreeViewItemProps extends Omit<TreeItemProps, 'className' | 'style' | 'value' | 'onHoverStart' | 'onHoverEnd' | 'onHoverChange'> {
42
52
  /** Rendered contents of the tree item or child items. */
43
- children: ReactNode,
44
- /** Whether this item has children, even if not loaded yet. */
45
- hasChildItems?: boolean,
46
- /** A list of child tree item objects used when dynamically rendering the tree item children. */
47
- childItems?: Iterable<T>
53
+ children: ReactNode
48
54
  }
49
55
 
50
56
  interface TreeRendererContextValue {
@@ -52,16 +58,16 @@ interface TreeRendererContextValue {
52
58
  }
53
59
  const TreeRendererContext = createContext<TreeRendererContextValue>({});
54
60
 
55
- function useTreeRendererContext(): TreeRendererContextValue {
56
- return useContext(TreeRendererContext)!;
57
- }
58
-
59
61
  // TODO: add animations for rows appearing and disappearing
60
62
 
61
63
  // TODO: the below is needed so the borders of the top and bottom row isn't cut off if the TreeView is wrapped within a container by always reserving the 2px needed for the
62
64
  // keyboard focus ring. Perhaps find a different way of rendering the outlines since the top of the item doesn't
63
65
  // scroll into view due to how the ring is offset. Alternatively, have the tree render the top/bottom outline like it does in Listview
64
66
  const tree = style<Pick<TreeRenderProps, 'isEmpty'>>({
67
+ ...focusRing(),
68
+ outlineOffset: '[-2px]', // make certain we are visible inside overflow hidden containers
69
+ height: 'full',
70
+ width: 'full',
65
71
  borderWidth: 2,
66
72
  boxSizing: 'border-box',
67
73
  borderXWidth: 0,
@@ -76,19 +82,17 @@ const tree = style<Pick<TreeRenderProps, 'isEmpty'>>({
76
82
  alignItems: {
77
83
  isEmpty: 'center'
78
84
  },
79
- width: {
80
- isEmpty: 'full'
81
- },
82
- height: {
83
- isEmpty: 'full'
84
- },
85
85
  display: {
86
86
  isEmpty: 'flex'
87
- }
87
+ },
88
+ overflow: 'auto'
88
89
  });
89
90
 
90
- function TreeView<T extends object>(props: SpectrumTreeViewProps<T>, ref: DOMRef<HTMLDivElement>) {
91
- let {children, selectionStyle} = props;
91
+ /**
92
+ * A tree view provides users with a way to navigate nested hierarchical information.
93
+ */
94
+ export const TreeView = React.forwardRef(function TreeView<T extends object>(props: SpectrumTreeViewProps<T>, ref: DOMRef<HTMLDivElement>) {
95
+ let {children, selectionStyle, UNSAFE_className} = props;
92
96
 
93
97
  let renderer;
94
98
  if (typeof children === 'function') {
@@ -101,12 +105,12 @@ function TreeView<T extends object>(props: SpectrumTreeViewProps<T>, ref: DOMRef
101
105
 
102
106
  return (
103
107
  <TreeRendererContext.Provider value={{renderer}}>
104
- <UNSTABLE_Tree {...props} {...styleProps} className={({isEmpty}) => tree({isEmpty})} selectionBehavior={selectionBehavior as SelectionBehavior} ref={domRef}>
108
+ <Tree {...props} {...styleProps} className={renderProps => (UNSAFE_className ?? '') + tree(renderProps)} selectionBehavior={selectionBehavior as SelectionBehavior} ref={domRef}>
105
109
  {props.children}
106
- </UNSTABLE_Tree>
110
+ </Tree>
107
111
  </TreeRendererContext.Provider>
108
112
  );
109
- }
113
+ }) as <T>(props: SpectrumTreeViewProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
110
114
 
111
115
  interface TreeRowRenderProps extends TreeItemRenderProps {
112
116
  isLink?: boolean
@@ -140,7 +144,7 @@ const treeCellGrid = style({
140
144
  display: 'grid',
141
145
  width: 'full',
142
146
  alignItems: 'center',
143
- gridTemplateColumns: ['minmax(0, auto)', 'minmax(0, auto)', 'minmax(0, auto)', 'minmax(0, auto)', 'minmax(0, auto)', '1fr', 'minmax(0, auto)', 'auto'],
147
+ gridTemplateColumns: ['minmax(0, auto)', 'minmax(0, auto)', 'minmax(0, auto)', 10, 'minmax(0, auto)', '1fr', 'minmax(0, auto)', 'auto'],
144
148
  gridTemplateRows: '1fr',
145
149
  gridTemplateAreas: [
146
150
  'drag-handle checkbox level-padding expand-button icon content actions actionmenu'
@@ -199,7 +203,8 @@ const treeRowOutline = style({
199
203
  isSelected: {
200
204
  default: '[-1px]',
201
205
  isFocusVisible: '[-2px]'
202
- }
206
+ },
207
+ isFirst: 0
203
208
  },
204
209
  bottom: 0,
205
210
  pointerEvents: 'none',
@@ -221,52 +226,37 @@ const treeRowOutline = style({
221
226
  }
222
227
  });
223
228
 
224
- export const TreeViewItem = <T extends object>(props: SpectrumTreeViewItemProps<T>) => {
229
+ export const TreeViewItem = (props: SpectrumTreeViewItemProps) => {
225
230
  let {
226
- children,
227
- childItems,
228
- hasChildItems,
229
231
  href
230
232
  } = props;
231
233
 
232
- let content;
233
- let nestedRows;
234
- let {renderer} = useTreeRendererContext();
235
- // TODO alternative api is that we have a separate prop for the TreeItems contents and expect the child to then be
236
- // a nested tree item
237
-
238
- if (typeof children === 'string') {
239
- content = <Text>{children}</Text>;
240
- } else {
241
- content = [];
242
- nestedRows = [];
243
- React.Children.forEach(children, node => {
244
- if (isValidElement(node) && node.type === TreeViewItem) {
245
- nestedRows.push(node);
246
- } else {
247
- content.push(node);
248
- }
249
- });
250
- }
251
-
252
- if (childItems != null && renderer) {
253
- nestedRows = (
254
- <Collection items={childItems}>
255
- {renderer}
256
- </Collection>
257
- );
258
- }
259
-
260
234
  return (
261
- // TODO right now all the tree rows have the various data attributes applied on their dom nodes, should they? Doesn't feel very useful
262
- <UNSTABLE_TreeItem
235
+ <TreeItem
263
236
  {...props}
264
237
  className={renderProps => treeRow({
265
238
  ...renderProps,
266
239
  isLink: !!href
267
- })}>
268
- <UNSTABLE_TreeItemContent>
269
- {({isExpanded, hasChildRows, level, selectionMode, selectionBehavior, isDisabled, isSelected, isFocusVisible}) => (
240
+ })} />
241
+ );
242
+ };
243
+
244
+ export interface SpectrumTreeViewItemContentProps extends Omit<TreeItemContentProps, 'children'> {
245
+ /** Rendered contents of the tree item or child items. */
246
+ children: ReactNode
247
+ }
248
+
249
+
250
+ export const TreeViewItemContent = (props: SpectrumTreeViewItemContentProps) => {
251
+ let {
252
+ children
253
+ } = props;
254
+
255
+ return (
256
+ <TreeItemContent>
257
+ {({isExpanded, hasChildItems, level, selectionMode, selectionBehavior, isDisabled, isSelected, isFocusVisible, state, id}) => {
258
+ let isFirst = state.collection.getFirstKey() === id;
259
+ return (
270
260
  <div className={treeCellGrid({isDisabled})}>
271
261
  {selectionMode !== 'none' && selectionBehavior === 'toggle' && (
272
262
  // TODO: add transition?
@@ -275,15 +265,15 @@ export const TreeViewItem = <T extends object>(props: SpectrumTreeViewItemProps<
275
265
  UNSAFE_className={treeCheckbox()}
276
266
  UNSAFE_style={{paddingInlineEnd: '0px'}}
277
267
  slot="selection" />
278
- )}
268
+ )}
279
269
  <div style={{gridArea: 'level-padding', marginInlineEnd: `calc(${level - 1} * var(--spectrum-global-dimension-size-200))`}} />
280
270
  {/* TODO: revisit when we do async loading, at the moment hasChildItems will only cause the chevron to be rendered, no aria/data attributes indicating the row's expandability are added */}
281
- {(hasChildRows || hasChildItems) && <ExpandableRowChevron isDisabled={isDisabled} isExpanded={isExpanded} />}
271
+ {hasChildItems && <ExpandableRowChevron isDisabled={isDisabled} isExpanded={isExpanded} />}
282
272
  <SlotProvider
283
273
  slots={{
284
274
  text: {UNSAFE_className: treeContent({isDisabled})},
285
- // Note there is also an issue here where these icon props are making into the action menu's icon. Resolved by 8ab0ffb276ff437a65b365c9a3be0323a1b24656
286
- // but could crop up later for other components
275
+ // Note there is also an issue here where these icon props are making into the action menu's icon. Resolved by 8ab0ffb276ff437a65b365c9a3be0323a1b24656
276
+ // but could crop up later for other components
287
277
  icon: {UNSAFE_className: treeIcon(), size: 'S'},
288
278
  actionButton: {UNSAFE_className: treeActions(), isQuiet: true},
289
279
  actionGroup: {
@@ -296,14 +286,13 @@ export const TreeViewItem = <T extends object>(props: SpectrumTreeViewItemProps<
296
286
  },
297
287
  actionMenu: {UNSAFE_className: treeActionMenu(), UNSAFE_style: {marginInlineEnd: '.5rem'}, isQuiet: true}
298
288
  }}>
299
- {content}
289
+ {children}
300
290
  </SlotProvider>
301
- <div className={treeRowOutline({isFocusVisible, isSelected})} />
291
+ <div className={treeRowOutline({isFocusVisible, isSelected, isFirst})} />
302
292
  </div>
303
- )}
304
- </UNSTABLE_TreeItemContent>
305
- {nestedRows}
306
- </UNSTABLE_TreeItem>
293
+ );
294
+ }}
295
+ </TreeItemContent>
307
296
  );
308
297
  };
309
298
 
@@ -332,7 +321,7 @@ const expandButton = style<ExpandableRowChevronProps>({
332
321
  });
333
322
 
334
323
  function ExpandableRowChevron(props: ExpandableRowChevronProps) {
335
- let expandButtonRef = useRef<HTMLSpanElement>(null);
324
+ let expandButtonRef = useRef(null);
336
325
  let [fullProps, ref] = useContextProps({...props, slot: 'chevron'}, expandButtonRef, ButtonContext);
337
326
  let {isExpanded, isDisabled} = fullProps;
338
327
  let {direction} = useLocale();
@@ -354,9 +343,3 @@ function ExpandableRowChevron(props: ExpandableRowChevronProps) {
354
343
  </span>
355
344
  );
356
345
  }
357
-
358
- /**
359
- * A tree view provides users with a way to navigate nested hierarchical information.
360
- */
361
- const _TreeView = React.forwardRef(TreeView) as <T>(props: SpectrumTreeViewProps<T> & {ref?: DOMRef<HTMLDivElement>}) => ReactElement;
362
- export {_TreeView as TreeView};
package/src/index.ts CHANGED
@@ -12,5 +12,6 @@
12
12
 
13
13
  /// <reference types="css-module-types" />
14
14
 
15
- export {TreeViewItem, TreeView} from './TreeView';
16
- export type {SpectrumTreeViewProps, SpectrumTreeViewItemProps} from './TreeView';
15
+ export {TreeViewItem, TreeView, TreeViewItemContent} from './TreeView';
16
+ export {Collection} from 'react-aria-components';
17
+ export type {SpectrumTreeViewProps, SpectrumTreeViewItemProps, SpectrumTreeViewItemContentProps} from './TreeView';
@@ -1 +0,0 @@
1
- {"mappings":"ACAA;EAGE;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAYA;;;;EAMA;;;;EApCA;;;;EAYA;;;;EAYA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAYA;;;;EAMA;;;;EAMA;;;;;EAYA;;;;EAMA;;;;EA1FA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EApCA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAlBA;;;;EAMA;;;;EANA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAxBA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAxBA;;;;EAMA;;;;EANA;;;;EAMA;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAAA;;;;EAAA;;;;EAAA;;;;EAMA;;;;EAYA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAYA;;;;EAMA;;;;EA9EA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;EAMA;;;;;;;AA/DF;;AA4CA;EACE;IACE;;;;IAAA;;;;IA8CA;;;;IAIA","sources":["f54a9241b0b1bdd2","packages/@react-spectrum/tree/src/TreeView.tsx"],"sourcesContent":["@import \"43ede2ea230cbe77\";\n@import \"d6186a3bcdea23c0\";\n@import \"9b0163e48ed44108\";\n@import \"4145f5de7372e962\";\n@import \"5c8e7aff246c25c0\";\n@import \"e6e7b4c2a4a805d7\";\n@import \"ed226d1e6a9f6d5d\";\n@import \"af6efb89500ab023\";\n@import \"5458487886ba8cfe\";\n@import \"5be3595defba4bd4\";\n","@layer a, b;\n\n@layer a {\n .wc {\n border-top-width: var(--spectrum-alias-border-size-thick, var(--spectrum-global-dimension-static-size-25));\n }\n}\n\n@layer a {\n .xc {\n border-bottom-width: var(--spectrum-alias-border-size-thick, var(--spectrum-global-dimension-static-size-25));\n }\n}\n\n@layer a {\n .ua {\n border-inline-start-width: 0px;\n }\n}\n\n@layer a {\n .va {\n border-inline-end-width: 0px;\n }\n}\n\n@layer a {\n .__ka {\n box-sizing: border-box;\n }\n}\n\n@layer a {\n .Aa {\n border-style: solid;\n }\n}\n\n@layer a {\n .ca {\n border-color: transparent;\n }\n}\n\n@layer b.a {\n @media (forced-colors: active) {\n .ca___y {\n border-color: Background;\n }\n }\n}\n\n@layer a {\n ._Vd {\n justify-content: center;\n }\n}\n\n@layer a {\n ._Uc {\n align-items: center;\n }\n}\n\n@layer a {\n .oY {\n width: 100%;\n }\n}\n\n@layer a {\n .nY {\n height: 100%;\n }\n}\n\n@layer a {\n ._Sd {\n display: flex;\n }\n}\n\n"],"names":[],"version":3,"file":"TreeView.fdfdaa1c.css.map"}