@react-spectrum/card 3.0.0-alpha.33 → 3.0.0-alpha.35

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/CardView.tsx CHANGED
@@ -47,7 +47,6 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
47
47
  let cardViewLayout = useMemo(() => typeof layout === 'function' ? new layout({collator, cardOrientation, scale}) : layout, [layout, collator, cardOrientation, scale]);
48
48
  let layoutType = cardViewLayout.layoutType;
49
49
 
50
- let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/card');
51
50
  let {direction} = useLocale();
52
51
  let {collection} = useListState(props);
53
52
 
@@ -79,8 +78,6 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
79
78
 
80
79
  cardViewLayout.collection = gridCollection;
81
80
  cardViewLayout.disabledKeys = state.disabledKeys;
82
- cardViewLayout.isLoading = isLoading;
83
- cardViewLayout.direction = direction;
84
81
 
85
82
  let {gridProps} = useGrid({
86
83
  ...props,
@@ -89,7 +86,7 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
89
86
  }, state, domRef);
90
87
 
91
88
  type View = ReusableView<Node<T>, ReactNode>;
92
- let renderWrapper = (parent: View, reusableView: View) => (
89
+ let renderWrapper = useCallback((parent: View, reusableView: View) => (
93
90
  <VirtualizerItem
94
91
  key={reusableView.key}
95
92
  layoutInfo={reusableView.layoutInfo}
@@ -97,7 +94,7 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
97
94
  parent={parent?.layoutInfo}>
98
95
  {reusableView.rendered}
99
96
  </VirtualizerItem>
100
- );
97
+ ), []);
101
98
 
102
99
  let focusedKey = state.selectionManager.focusedKey;
103
100
  let focusedItem = gridCollection.getItem(state.selectionManager.focusedKey);
@@ -105,64 +102,71 @@ function CardView<T extends object>(props: SpectrumCardViewProps<T>, ref: DOMRef
105
102
  focusedKey = focusedItem.parentKey;
106
103
  }
107
104
 
108
- let margin = cardViewLayout.margin || 0;
109
- let virtualizer = cardViewLayout.virtualizer;
110
- let scrollToItem = useCallback((key) => {
111
- virtualizer && virtualizer.scrollToItem(key, {
112
- duration: 0,
113
- offsetY: margin
114
- });
115
- }, [margin, virtualizer]);
105
+ let persistedKeys = useMemo(() => focusedKey != null ? new Set([focusedKey]) : null, [focusedKey]);
116
106
 
117
107
  // TODO: does aria-row count and aria-col count need to be modified? Perhaps aria-col count needs to be omitted
118
108
  return (
119
- <CardViewContext.Provider value={{state, isQuiet, layout: cardViewLayout, cardOrientation}}>
109
+ <CardViewContext.Provider value={{state, isQuiet, layout: cardViewLayout, cardOrientation, renderEmptyState}}>
120
110
  <Virtualizer
121
111
  {...gridProps}
122
112
  {...styleProps}
123
113
  className={classNames(styles, 'spectrum-CardView')}
124
114
  ref={domRef}
125
- focusedKey={focusedKey}
115
+ persistedKeys={persistedKeys}
126
116
  scrollDirection="vertical"
127
117
  layout={cardViewLayout}
128
118
  collection={gridCollection}
129
119
  isLoading={isLoading}
130
120
  onLoadMore={onLoadMore}
121
+ layoutOptions={useMemo(() => ({isLoading, direction}), [isLoading, direction])}
131
122
  renderWrapper={renderWrapper}
132
- transitionDuration={isLoading ? 160 : 220}
133
- scrollToItem={scrollToItem}>
134
- {(type, item) => {
123
+ style={{
124
+ ...styleProps.style,
125
+ scrollPaddingTop: cardViewLayout.margin || 0
126
+ }}>
127
+ {useCallback((type, item) => {
135
128
  if (type === 'item') {
136
129
  return (
137
130
  <InternalCard item={item} />
138
131
  );
139
132
  } else if (type === 'loader') {
140
- return (
141
- <CenteredWrapper>
142
- <ProgressCircle
143
- isIndeterminate
144
- aria-label={state.collection.size > 0 ? stringFormatter.format('loadingMore') : stringFormatter.format('loading')} />
145
- </CenteredWrapper>
146
- );
133
+ return <LoadingState />;
147
134
  } else if (type === 'placeholder') {
148
- let emptyState = renderEmptyState ? renderEmptyState() : null;
149
- if (emptyState == null) {
150
- return null;
151
- }
152
-
153
- return (
154
- <CenteredWrapper>
155
- {emptyState}
156
- </CenteredWrapper>
157
- );
135
+ return <EmptyState />;
158
136
  }
159
- }}
137
+ }, [])}
160
138
  </Virtualizer>
161
139
  </CardViewContext.Provider>
162
140
 
163
141
  );
164
142
  }
165
143
 
144
+ function LoadingState() {
145
+ let {state} = useCardViewContext();
146
+ let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/card');
147
+ return (
148
+ <CenteredWrapper>
149
+ <ProgressCircle
150
+ isIndeterminate
151
+ aria-label={state.collection.size > 0 ? stringFormatter.format('loadingMore') : stringFormatter.format('loading')} />
152
+ </CenteredWrapper>
153
+ );
154
+ }
155
+
156
+ function EmptyState() {
157
+ let {renderEmptyState} = useCardViewContext();
158
+ let emptyState = renderEmptyState ? renderEmptyState() : null;
159
+ if (emptyState == null) {
160
+ return null;
161
+ }
162
+
163
+ return (
164
+ <CenteredWrapper>
165
+ {emptyState}
166
+ </CenteredWrapper>
167
+ );
168
+ }
169
+
166
170
  function CenteredWrapper({children}) {
167
171
  let {state} = useCardViewContext();
168
172
  return (
@@ -185,8 +189,8 @@ function InternalCard(props) {
185
189
  let {state, cardOrientation, isQuiet, layout} = useCardViewContext();
186
190
 
187
191
  let layoutType = layout.layoutType;
188
- let rowRef = useRef();
189
- let cellRef = useRef<DOMRefValue<HTMLDivElement>>();
192
+ let rowRef = useRef(undefined);
193
+ let cellRef = useRef<DOMRefValue<HTMLDivElement>>(undefined);
190
194
  let unwrappedRef = useUnwrapDOMRef(cellRef);
191
195
 
192
196
  let {rowProps: gridRowProps} = useGridRow({
@@ -130,41 +130,6 @@ export class GridLayout<T> extends BaseLayout<T> {
130
130
  );
131
131
  }
132
132
 
133
- getVisibleLayoutInfos(rect) {
134
- let res: LayoutInfo[] = [];
135
- let numItems = this.collection.size;
136
- if (numItems <= 0 || !this.itemSize) {
137
- // If there aren't any items in the collection, we are in a loader/placeholder state. Return those layoutInfos as
138
- // the currently visible items
139
- if (this.layoutInfos.size > 0) {
140
- for (let layoutInfo of this.layoutInfos.values()) {
141
- if (this.isVisible(layoutInfo, rect)) {
142
- res.push(layoutInfo);
143
- }
144
- }
145
- }
146
- } else {
147
- // The approach from v2 uses indexes where other v3 layouts iterate through every node/root node. This feels more efficient
148
- let firstVisibleItem = this.getIndexAtPoint(rect.x, rect.y);
149
- let lastVisibleItem = this.getIndexAtPoint(rect.maxX, rect.maxY);
150
- for (let index = firstVisibleItem; index <= lastVisibleItem; index++) {
151
- let keyFromIndex = this.collection.rows[index].key;
152
- let layoutInfo = this.layoutInfos.get(keyFromIndex);
153
- if (layoutInfo && this.isVisible(layoutInfo, rect)) {
154
- res.push(layoutInfo);
155
- }
156
- }
157
-
158
- // Check if loader is in view and add to res if so
159
- let loader = this.layoutInfos.get('loader');
160
- if (loader && this.isVisible(loader, rect)) {
161
- res.push(loader);
162
- }
163
- }
164
-
165
- return res;
166
- }
167
-
168
133
  buildCollection() {
169
134
  let visibleWidth = this.virtualizer.visibleRect.width;
170
135
  let visibleHeight = this.virtualizer.visibleRect.height;
@@ -13,7 +13,7 @@
13
13
  import {BaseLayout, BaseLayoutOptions} from './BaseLayout';
14
14
  import {getChildNodes, getFirstItem} from '@react-stately/collections';
15
15
  import {InvalidationContext, LayoutInfo, Rect, Size} from '@react-stately/virtualizer';
16
- import {Key, KeyboardDelegate, Node} from '@react-types/shared';
16
+ import {Key, KeyboardDelegate} from '@react-types/shared';
17
17
 
18
18
  export interface WaterfallLayoutOptions extends BaseLayoutOptions {
19
19
  /**
@@ -69,7 +69,7 @@ export class WaterfallLayout<T> extends BaseLayout<T> implements KeyboardDelegat
69
69
  return 'waterfall';
70
70
  }
71
71
 
72
- buildCollection(invalidationContext: InvalidationContext<Node<T>, unknown>) {
72
+ buildCollection(invalidationContext: InvalidationContext) {
73
73
  // Compute the number of columns needed to display the content
74
74
  let visibleWidth = this.virtualizer.visibleRect.width;
75
75
  let availableWidth = visibleWidth - this.margin * 2;