@wordpress/dataviews 16.0.0 → 16.0.1

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 (47) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/build/components/dataviews-layouts/index.cjs +9 -0
  3. package/build/components/dataviews-layouts/index.cjs.map +3 -3
  4. package/build/components/dataviews-layouts/picker-activity/index.cjs +304 -0
  5. package/build/components/dataviews-layouts/picker-activity/index.cjs.map +7 -0
  6. package/build/components/dataviews-view-config/index.cjs +1 -0
  7. package/build/components/dataviews-view-config/index.cjs.map +2 -2
  8. package/build/constants.cjs +3 -0
  9. package/build/constants.cjs.map +2 -2
  10. package/build/types/dataviews.cjs.map +1 -1
  11. package/build-module/components/dataviews-layouts/index.mjs +11 -1
  12. package/build-module/components/dataviews-layouts/index.mjs.map +2 -2
  13. package/build-module/components/dataviews-layouts/picker-activity/index.mjs +273 -0
  14. package/build-module/components/dataviews-layouts/picker-activity/index.mjs.map +7 -0
  15. package/build-module/components/dataviews-view-config/index.mjs +1 -0
  16. package/build-module/components/dataviews-view-config/index.mjs.map +2 -2
  17. package/build-module/constants.mjs +2 -0
  18. package/build-module/constants.mjs.map +2 -2
  19. package/build-style/style-rtl.css +199 -13
  20. package/build-style/style.css +199 -13
  21. package/build-types/components/dataviews-layouts/index.d.ts +8 -0
  22. package/build-types/components/dataviews-layouts/index.d.ts.map +1 -1
  23. package/build-types/components/dataviews-layouts/picker-activity/index.d.ts +3 -0
  24. package/build-types/components/dataviews-layouts/picker-activity/index.d.ts.map +1 -0
  25. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  26. package/build-types/constants.d.ts +1 -0
  27. package/build-types/constants.d.ts.map +1 -1
  28. package/build-types/dataform/stories/index.story.d.ts +1 -0
  29. package/build-types/dataform/stories/index.story.d.ts.map +1 -1
  30. package/build-types/dataviews/stories/index.story.d.ts.map +1 -1
  31. package/build-types/dataviews-picker/stories/index.story.d.ts.map +1 -1
  32. package/build-types/types/dataviews.d.ts +16 -2
  33. package/build-types/types/dataviews.d.ts.map +1 -1
  34. package/build-wp/index.js +928 -648
  35. package/package.json +22 -19
  36. package/src/components/dataviews-layouts/index.ts +10 -0
  37. package/src/components/dataviews-layouts/picker-activity/index.tsx +359 -0
  38. package/src/components/dataviews-layouts/picker-activity/style.scss +227 -0
  39. package/src/components/dataviews-view-config/index.tsx +1 -0
  40. package/src/constants.ts +1 -0
  41. package/src/dataform/stories/content.story.tsx +1 -1
  42. package/src/dataform/stories/index.story.tsx +1 -0
  43. package/src/dataviews/stories/index.story.tsx +1 -0
  44. package/src/dataviews-picker/stories/index.story.tsx +6 -0
  45. package/src/dataviews-picker/test/dataviews-picker.tsx +5 -0
  46. package/src/style.scss +1 -0
  47. package/src/types/dataviews.ts +21 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "16.0.0",
3
+ "version": "16.0.1",
4
4
  "description": "DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -48,36 +48,39 @@
48
48
  },
49
49
  "./build-style/": "./build-style/"
50
50
  },
51
- "react-native": "src/index",
52
51
  "types": "build-types",
53
52
  "sideEffects": false,
54
53
  "dependencies": {
55
54
  "@ariakit/react": "^0.4.21",
56
- "@wordpress/base-styles": "^9.1.0",
57
- "@wordpress/components": "^35.0.0",
58
- "@wordpress/compose": "^8.1.0",
59
- "@wordpress/data": "^10.48.0",
60
- "@wordpress/date": "^5.48.0",
61
- "@wordpress/deprecated": "^4.48.0",
62
- "@wordpress/element": "^8.0.0",
63
- "@wordpress/i18n": "^6.21.0",
64
- "@wordpress/icons": "^13.3.0",
65
- "@wordpress/keycodes": "^4.48.0",
66
- "@wordpress/primitives": "^4.48.0",
67
- "@wordpress/private-apis": "^1.48.0",
68
- "@wordpress/ui": "^0.15.0",
69
- "@wordpress/warning": "^3.48.0",
55
+ "@types/react": "^18.3.27",
56
+ "@wordpress/base-styles": "^10.0.1",
57
+ "@wordpress/components": "^35.0.1",
58
+ "@wordpress/compose": "^8.1.1",
59
+ "@wordpress/data": "^10.48.1",
60
+ "@wordpress/date": "^5.48.1",
61
+ "@wordpress/deprecated": "^4.48.1",
62
+ "@wordpress/element": "^8.0.1",
63
+ "@wordpress/i18n": "^6.21.1",
64
+ "@wordpress/icons": "^14.0.1",
65
+ "@wordpress/keycodes": "^4.48.1",
66
+ "@wordpress/primitives": "^4.48.1",
67
+ "@wordpress/private-apis": "^1.48.1",
68
+ "@wordpress/ui": "^0.15.1",
69
+ "@wordpress/warning": "^3.48.1",
70
70
  "clsx": "^2.1.1",
71
- "colord": "^2.7.0",
71
+ "colord": "^2.9.3",
72
72
  "date-fns": "^4.1.0",
73
- "deepmerge": "4.3.1",
73
+ "deepmerge": "^4.3.1",
74
74
  "fast-deep-equal": "^3.1.3",
75
75
  "remove-accents": "^0.5.0"
76
76
  },
77
77
  "devDependencies": {
78
78
  "@storybook/addon-docs": "^10.2.8",
79
79
  "@storybook/react-vite": "^10.2.8",
80
+ "@testing-library/dom": "^10.4.1",
80
81
  "@testing-library/jest-dom": "^6.9.1",
82
+ "@testing-library/react": "^16.3.2",
83
+ "@testing-library/user-event": "^14.6.1",
81
84
  "@types/jest": "^29.5.14",
82
85
  "esbuild": "^0.27.2",
83
86
  "storybook": "^10.2.8"
@@ -92,5 +95,5 @@
92
95
  "scripts": {
93
96
  "build:wp": "node build.cjs"
94
97
  },
95
- "gitHead": "e7856693aeb4e2522d13608cd32c994e4a97cb9c"
98
+ "gitHead": "99df7432c5c7cb83ba41146fd1f57f3c19004305"
96
99
  }
@@ -19,6 +19,7 @@ import ViewList from './list';
19
19
  import ViewActivity from './activity';
20
20
  import ViewPickerGrid from './picker-grid';
21
21
  import ViewPickerTable from './picker-table';
22
+ import ViewPickerActivity from './picker-activity';
22
23
  import {
23
24
  LAYOUT_GRID,
24
25
  LAYOUT_LIST,
@@ -26,6 +27,7 @@ import {
26
27
  LAYOUT_ACTIVITY,
27
28
  LAYOUT_PICKER_GRID,
28
29
  LAYOUT_PICKER_TABLE,
30
+ LAYOUT_PICKER_ACTIVITY,
29
31
  } from '../../constants';
30
32
  import DensityPicker from './utils/density-picker';
31
33
  import GridConfigOptions from './utils/grid-config-options';
@@ -75,4 +77,12 @@ export const VIEW_LAYOUTS = [
75
77
  viewConfigOptions: DensityPicker,
76
78
  isPicker: true,
77
79
  },
80
+ {
81
+ type: LAYOUT_PICKER_ACTIVITY,
82
+ label: __( 'Activity' ),
83
+ component: ViewPickerActivity,
84
+ icon: scheduled,
85
+ viewConfigOptions: DensityPicker,
86
+ isPicker: true,
87
+ },
78
88
  ];
@@ -0,0 +1,359 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ReactNode } from 'react';
5
+ import clsx from 'clsx';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { Spinner, Composite } from '@wordpress/components';
11
+ import { useContext, useMemo, useRef } from '@wordpress/element';
12
+ import { useInstanceId } from '@wordpress/compose';
13
+ import { __, sprintf } from '@wordpress/i18n';
14
+ import { Stack, VisuallyHidden } from '@wordpress/ui';
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import DataViewsContext from '../../dataviews-context';
20
+ import { useIsMultiselectPicker } from '../../dataviews-picker-footer';
21
+ import getDataByGroup from '../utils/get-data-by-group';
22
+ import { useIntersectionObserver } from '../utils/use-infinite-scroll';
23
+ import type {
24
+ NormalizedField,
25
+ ViewPickerActivity as ViewPickerActivityType,
26
+ ViewPickerActivityProps,
27
+ } from '../../../types';
28
+ import type { SetSelection } from '../../../types/private';
29
+
30
+ function isDefined< T >( item: T | undefined ): item is T {
31
+ return !! item;
32
+ }
33
+
34
+ interface PickerActivityItemProps< Item > {
35
+ view: ViewPickerActivityType;
36
+ multiselect?: boolean;
37
+ selection: string[];
38
+ onChangeSelection: SetSelection;
39
+ getItemId: ( item: Item ) => string;
40
+ item: Item;
41
+ titleField?: NormalizedField< Item >;
42
+ mediaField?: NormalizedField< Item >;
43
+ descriptionField?: NormalizedField< Item >;
44
+ otherFields: NormalizedField< Item >[];
45
+ posinset?: number;
46
+ setsize?: number;
47
+ }
48
+
49
+ function PickerActivityItem< Item >( {
50
+ view,
51
+ multiselect,
52
+ selection,
53
+ onChangeSelection,
54
+ getItemId,
55
+ item,
56
+ titleField,
57
+ mediaField,
58
+ descriptionField,
59
+ otherFields,
60
+ posinset,
61
+ setsize,
62
+ }: PickerActivityItemProps< Item > ) {
63
+ const elementRef = useRef< HTMLButtonElement >( null );
64
+ useIntersectionObserver( elementRef, posinset );
65
+ const { showTitle = true, showMedia = true, showDescription = true } = view;
66
+ const id = getItemId( item );
67
+ const isSelected = selection.includes( id );
68
+ const density = view.layout?.density ?? 'balanced';
69
+
70
+ const mediaContent =
71
+ showMedia && density !== 'compact' && mediaField?.render ? (
72
+ <mediaField.render
73
+ item={ item }
74
+ field={ mediaField }
75
+ config={ {
76
+ sizes: density === 'comfortable' ? '32px' : '24px',
77
+ } }
78
+ />
79
+ ) : null;
80
+
81
+ const renderedMediaField = (
82
+ <div className="dataviews-view-picker-activity__item-type-icon">
83
+ { mediaContent || (
84
+ <span
85
+ className="dataviews-view-picker-activity__item-bullet"
86
+ aria-hidden="true"
87
+ />
88
+ ) }
89
+ </div>
90
+ );
91
+
92
+ const renderedTitleField =
93
+ showTitle && titleField?.render ? (
94
+ <titleField.render item={ item } field={ titleField } />
95
+ ) : null;
96
+
97
+ const renderedDescriptionField =
98
+ showDescription && descriptionField?.render ? (
99
+ <descriptionField.render item={ item } field={ descriptionField } />
100
+ ) : null;
101
+
102
+ const verticalGap = useMemo( () => {
103
+ switch ( density ) {
104
+ case 'comfortable':
105
+ return 'md';
106
+ default:
107
+ return 'sm';
108
+ }
109
+ }, [ density ] );
110
+
111
+ return (
112
+ <Composite.Item
113
+ ref={ elementRef }
114
+ role="option"
115
+ aria-label={
116
+ titleField
117
+ ? titleField.getValue( { item } ) || undefined
118
+ : undefined
119
+ }
120
+ aria-posinset={ posinset }
121
+ aria-setsize={ setsize }
122
+ aria-selected={ isSelected }
123
+ className={ clsx(
124
+ 'dataviews-view-picker-activity__item',
125
+ density === 'compact' && 'is-compact',
126
+ density === 'balanced' && 'is-balanced',
127
+ density === 'comfortable' && 'is-comfortable',
128
+ isSelected && 'is-selected'
129
+ ) }
130
+ onClick={ () => {
131
+ if ( isSelected ) {
132
+ onChangeSelection(
133
+ selection.filter( ( itemId ) => id !== itemId )
134
+ );
135
+ } else {
136
+ const newSelection = multiselect
137
+ ? [ ...selection, id ]
138
+ : [ id ];
139
+ onChangeSelection( newSelection );
140
+ }
141
+ } }
142
+ render={ <div /> }
143
+ >
144
+ <Stack direction="row" gap="lg" justify="start" align="flex-start">
145
+ <Stack
146
+ direction="column"
147
+ gap="xs"
148
+ align="center"
149
+ className="dataviews-view-picker-activity__item-type"
150
+ >
151
+ { renderedMediaField }
152
+ </Stack>
153
+ <Stack
154
+ direction="column"
155
+ gap={ verticalGap }
156
+ align="flex-start"
157
+ className="dataviews-view-picker-activity__item-content"
158
+ >
159
+ { renderedTitleField && (
160
+ <div className="dataviews-view-picker-activity__item-title">
161
+ { renderedTitleField }
162
+ </div>
163
+ ) }
164
+ { renderedDescriptionField && (
165
+ <div className="dataviews-view-picker-activity__item-description">
166
+ { renderedDescriptionField }
167
+ </div>
168
+ ) }
169
+ <div className="dataviews-view-picker-activity__item-fields">
170
+ { otherFields.map( ( field ) => (
171
+ <div
172
+ key={ field.id }
173
+ className="dataviews-view-picker-activity__item-field"
174
+ >
175
+ <VisuallyHidden
176
+ render={ <span /> }
177
+ className="dataviews-view-picker-activity__item-field-label"
178
+ >
179
+ { field.label }
180
+ </VisuallyHidden>
181
+ <span className="dataviews-view-picker-activity__item-field-value">
182
+ <field.render
183
+ item={ item }
184
+ field={ field }
185
+ />
186
+ </span>
187
+ </div>
188
+ ) ) }
189
+ </div>
190
+ </Stack>
191
+ </Stack>
192
+ </Composite.Item>
193
+ );
194
+ }
195
+
196
+ function PickerActivityGroup< Item >( {
197
+ groupName,
198
+ groupField,
199
+ showLabel = true,
200
+ children,
201
+ }: {
202
+ groupName: string;
203
+ groupField: NormalizedField< Item >;
204
+ showLabel?: boolean;
205
+ children: ReactNode;
206
+ } ) {
207
+ const headerId = useInstanceId(
208
+ PickerActivityGroup,
209
+ 'dataviews-view-picker-activity-group__header'
210
+ );
211
+ return (
212
+ <Stack
213
+ direction="column"
214
+ role="group"
215
+ aria-labelledby={ headerId }
216
+ className="dataviews-view-picker-activity-group"
217
+ >
218
+ <h3
219
+ className="dataviews-view-picker-activity-group__header"
220
+ id={ headerId }
221
+ >
222
+ { showLabel
223
+ ? sprintf(
224
+ // translators: 1: The label of the field e.g. "Date". 2: The value of the field, e.g.: "May 2022".
225
+ __( '%1$s: %2$s' ),
226
+ groupField.label,
227
+ groupName
228
+ )
229
+ : groupName }
230
+ </h3>
231
+ { children }
232
+ </Stack>
233
+ );
234
+ }
235
+
236
+ export default function ViewPickerActivity< Item >( {
237
+ data,
238
+ fields,
239
+ getItemId,
240
+ isLoading,
241
+ onChangeSelection,
242
+ selection,
243
+ view,
244
+ actions,
245
+ className,
246
+ empty,
247
+ }: ViewPickerActivityProps< Item > ) {
248
+ const { itemListLabel, paginationInfo } = useContext( DataViewsContext );
249
+ const isMultiselect = useIsMultiselectPicker( actions );
250
+
251
+ const titleField = fields.find(
252
+ ( field ) => field.id === view?.titleField
253
+ );
254
+ const mediaField = fields.find(
255
+ ( field ) => field.id === view?.mediaField
256
+ );
257
+ const descriptionField = fields.find(
258
+ ( field ) => field.id === view?.descriptionField
259
+ );
260
+ const otherFields = ( view?.fields ?? [] )
261
+ .map( ( fieldId ) => fields.find( ( f ) => fieldId === f.id ) )
262
+ .filter( isDefined );
263
+
264
+ const groupField = view.groupBy?.field
265
+ ? fields.find( ( f ) => f.id === view.groupBy?.field )
266
+ : null;
267
+ const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
268
+
269
+ const isInfiniteScroll =
270
+ ( view.infiniteScrollEnabled && ! dataByGroup ) ?? false;
271
+ const setsize = isInfiniteScroll ? paginationInfo?.totalItems : undefined;
272
+
273
+ const hasData = !! data?.length;
274
+ const isGrouped = !! ( groupField && dataByGroup );
275
+
276
+ const renderItem = ( item: Item ) => (
277
+ <PickerActivityItem
278
+ key={ getItemId( item ) }
279
+ view={ view }
280
+ multiselect={ isMultiselect }
281
+ selection={ selection }
282
+ onChangeSelection={ onChangeSelection }
283
+ getItemId={ getItemId }
284
+ item={ item }
285
+ titleField={ titleField }
286
+ mediaField={ mediaField }
287
+ descriptionField={ descriptionField }
288
+ otherFields={ otherFields }
289
+ posinset={ ( item as { position?: number } ).position }
290
+ setsize={ setsize }
291
+ />
292
+ );
293
+
294
+ if ( ! hasData ) {
295
+ return (
296
+ <div
297
+ className={ clsx( {
298
+ 'dataviews-loading': isLoading,
299
+ 'dataviews-no-results': ! isLoading,
300
+ } ) }
301
+ >
302
+ { isLoading ? (
303
+ <p>
304
+ <Spinner />
305
+ </p>
306
+ ) : (
307
+ empty
308
+ ) }
309
+ </div>
310
+ );
311
+ }
312
+
313
+ return (
314
+ <>
315
+ <Composite
316
+ virtualFocus
317
+ orientation="vertical"
318
+ role="listbox"
319
+ aria-multiselectable={ isMultiselect }
320
+ aria-label={ itemListLabel }
321
+ aria-busy={ isLoading }
322
+ render={
323
+ isGrouped ? (
324
+ <Stack direction="column" gap="sm" />
325
+ ) : undefined
326
+ }
327
+ className={ clsx(
328
+ 'dataviews-view-picker-activity',
329
+ className
330
+ ) }
331
+ >
332
+ { isGrouped && dataByGroup
333
+ ? Array.from( dataByGroup.entries() ).map(
334
+ ( [ groupName, groupItems ]: [
335
+ string,
336
+ Item[],
337
+ ] ) => (
338
+ <PickerActivityGroup< Item >
339
+ key={ groupName }
340
+ groupName={ groupName }
341
+ groupField={ groupField }
342
+ showLabel={
343
+ view.groupBy?.showLabel !== false
344
+ }
345
+ >
346
+ { groupItems.map( renderItem ) }
347
+ </PickerActivityGroup>
348
+ )
349
+ )
350
+ : data.map( renderItem ) }
351
+ </Composite>
352
+ { isLoading && (
353
+ <p className="dataviews-loading-more">
354
+ <Spinner />
355
+ </p>
356
+ ) }
357
+ </>
358
+ );
359
+ }
@@ -0,0 +1,227 @@
1
+ .dataviews-view-picker-activity {
2
+ margin: 0;
3
+ padding: 0;
4
+ // Fill the wrapper height so the footer sits at the bottom.
5
+ flex-grow: 1;
6
+
7
+ &:focus-visible {
8
+ &[aria-activedescendant] {
9
+ outline: none;
10
+ }
11
+
12
+ .dataviews-view-picker-activity__item[data-active-item="true"] {
13
+ outline: 2px solid var(--wpds-color-stroke-focus-brand);
14
+ outline-offset: -2px;
15
+ }
16
+ }
17
+
18
+ .dataviews-view-picker-activity__item {
19
+ cursor: var(--wpds-cursor-control);
20
+ border-radius: var(--wpds-border-radius-sm);
21
+ // Inset content to the toolbar/footer padding so the timeline aligns with the chrome.
22
+ padding-inline: var(--wpds-dimension-padding-2xl);
23
+ transition: background-color 0.1s ease;
24
+
25
+ // Selected and hovered rows share the same tint (like the table picker),
26
+ // keeping selection legible even for bullet-only items.
27
+ &.is-selected,
28
+ &:hover {
29
+ background-color: var(--wpds-color-bg-interactive-brand-weak-active);
30
+ }
31
+
32
+ // Selection outline only renders in Windows High Contrast mode.
33
+ &.is-selected {
34
+ outline: 3px solid transparent;
35
+ outline-offset: -2px;
36
+ }
37
+
38
+ &.is-compact {
39
+ .dataviews-view-picker-activity__item-type {
40
+ width: var(--wpds-dimension-padding-md);
41
+
42
+ &::before {
43
+ height: calc(var(--wpds-dimension-base) * 3);
44
+ }
45
+ }
46
+ .dataviews-view-picker-activity__item-type-icon {
47
+ width: calc(var(--wpds-dimension-base) * 3 - 1px);
48
+ height: calc(var(--wpds-dimension-base) * 3 - 1px);
49
+ }
50
+ .dataviews-view-picker-activity__item-content {
51
+ margin: var(--wpds-dimension-gap-md) 0;
52
+ }
53
+ }
54
+
55
+ &.is-balanced {
56
+ .dataviews-view-picker-activity__item-type {
57
+ width: calc(var(--wpds-dimension-base) * 6); // TODO: use size token when available
58
+
59
+ &::before {
60
+ height: calc(var(--wpds-dimension-base) * 3);
61
+ }
62
+ }
63
+ .dataviews-view-picker-activity__item-type-icon {
64
+ width: calc(var(--wpds-dimension-base) * 6 + 1px);
65
+ height: calc(var(--wpds-dimension-base) * 6 + 1px);
66
+ }
67
+ .dataviews-view-picker-activity__item-content {
68
+ margin: var(--wpds-dimension-gap-md) 0;
69
+ padding-top: var(--wpds-dimension-padding-sm);
70
+ }
71
+ }
72
+
73
+ &.is-comfortable {
74
+ .dataviews-view-picker-activity__item-type {
75
+ width: calc(var(--wpds-dimension-base) * 8); // TODO: use size token when available
76
+
77
+ &::before {
78
+ height: calc(var(--wpds-dimension-base) * 2);
79
+ }
80
+ }
81
+ .dataviews-view-picker-activity__item-type-icon {
82
+ width: calc(var(--wpds-dimension-base) * 8 + 1px);
83
+ height: calc(var(--wpds-dimension-base) * 8 + 1px);
84
+ }
85
+ .dataviews-view-picker-activity__item-content {
86
+ margin: var(--wpds-dimension-gap-sm) 0 var(--wpds-dimension-gap-lg);
87
+ padding-top: var(--wpds-dimension-padding-md);
88
+ }
89
+ }
90
+
91
+ &.is-comfortable,
92
+ &.is-balanced {
93
+ .dataviews-view-picker-activity__item-bullet {
94
+ width: calc(var(--wpds-dimension-base) * 2 + 1px);
95
+ height: calc(var(--wpds-dimension-base) * 2 + 1px);
96
+ position: relative;
97
+ top: 50%;
98
+ transform: translateY(-50%);
99
+ }
100
+ }
101
+ }
102
+
103
+ .dataviews-view-picker-activity__item-content {
104
+ flex-grow: 1;
105
+
106
+ .dataviews-view-picker-activity__item-title,
107
+ .dataviews-view-picker-activity__item-description,
108
+ .dataviews-view-picker-activity__item-fields {
109
+ min-height: calc(var(--wpds-dimension-base) * 4); // TODO: use size token when available
110
+ }
111
+
112
+ .dataviews-view-picker-activity__item-title {
113
+ position: relative;
114
+ display: flex;
115
+ align-items: center;
116
+ flex: 1;
117
+ overflow: hidden;
118
+ }
119
+
120
+ .dataviews-view-picker-activity__item-description {
121
+ &:empty {
122
+ display: none;
123
+ }
124
+ }
125
+
126
+ .dataviews-view-picker-activity__item-fields {
127
+ color: var(--wpds-color-fg-content-neutral-weak);
128
+ display: flex;
129
+ gap: var(--wpds-dimension-gap-md);
130
+ row-gap: var(--wpds-dimension-gap-xs);
131
+ flex-wrap: wrap;
132
+
133
+ &:empty {
134
+ display: none;
135
+ }
136
+
137
+ .dataviews-view-picker-activity__item-field {
138
+ &:has(.dataviews-view-picker-activity__item-field-value:empty) {
139
+ display: none;
140
+ }
141
+ }
142
+
143
+ .dataviews-view-picker-activity__item-field-value {
144
+ display: flex;
145
+ align-items: center;
146
+ }
147
+ }
148
+ }
149
+
150
+ // Timeline connector line
151
+ .dataviews-view-picker-activity__item-type {
152
+ align-self: stretch;
153
+ flex-shrink: 0;
154
+
155
+ &::after {
156
+ content: "";
157
+ flex: 1 1 auto;
158
+ width: 1px;
159
+ margin: 0 auto;
160
+ background-color: var(--wpds-color-stroke-surface-neutral);
161
+ }
162
+
163
+ &::before {
164
+ content: "";
165
+ flex: 0 0 auto;
166
+ width: 1px;
167
+ margin: 0 auto;
168
+ background-color: var(--wpds-color-stroke-surface-neutral);
169
+ }
170
+ }
171
+
172
+ // First and last item timeline lines
173
+ .dataviews-view-picker-activity__item:first-child {
174
+ .dataviews-view-picker-activity__item-type {
175
+ &::before {
176
+ visibility: hidden;
177
+ }
178
+ }
179
+ }
180
+
181
+ .dataviews-view-picker-activity-group:last-of-type > .dataviews-view-picker-activity__item:last-of-type,
182
+ & > .dataviews-view-picker-activity__item:last-child {
183
+ .dataviews-view-picker-activity__item-type {
184
+ &::after {
185
+ background: linear-gradient(to bottom, var(--wpds-color-stroke-surface-neutral) 0%, color-mix(in srgb, var(--wpds-color-stroke-surface-neutral) 20%, transparent) 60%, transparent 100%);
186
+ }
187
+ }
188
+ }
189
+
190
+ .dataviews-view-picker-activity-group__header {
191
+ font-size: var(--wpds-typography-font-size-lg);
192
+ font-weight: var(--wpds-typography-font-weight-medium);
193
+ color: var(--wpds-color-fg-content-neutral-weak);
194
+ margin: 0 0 var(--wpds-dimension-gap-sm) 0;
195
+ padding: 0;
196
+ padding-inline-start: var(--wpds-dimension-padding-2xl);
197
+ }
198
+
199
+ // Bullet/icon styling
200
+ .dataviews-view-picker-activity__item-type-icon {
201
+ overflow: hidden;
202
+ flex-shrink: 0;
203
+ // Transparent so the row tint shows through the corners around the round media.
204
+ background-color: transparent;
205
+
206
+ img,
207
+ svg,
208
+ .dataviews-view-picker-activity__item-bullet {
209
+ display: block;
210
+ width: 100%;
211
+ height: 100%;
212
+ margin: 0 auto;
213
+ object-fit: cover;
214
+ border-radius: 50%;
215
+ box-sizing: border-box;
216
+ box-shadow: inset 0 0 0 var(--wpds-border-width-xs) var(--wpds-color-stroke-surface-neutral);
217
+ }
218
+
219
+ svg {
220
+ padding: var(--wpds-dimension-padding-xs);
221
+ }
222
+
223
+ .dataviews-view-picker-activity__item-bullet {
224
+ background-color: var(--wpds-color-stroke-surface-neutral);
225
+ }
226
+ }
227
+ }
@@ -85,6 +85,7 @@ export function ViewTypeMenu() {
85
85
  case 'table':
86
86
  case 'pickerGrid':
87
87
  case 'pickerTable':
88
+ case 'pickerActivity':
88
89
  case 'activity':
89
90
  const viewWithoutLayout = { ...view };
90
91
  if ( 'layout' in viewWithoutLayout ) {
package/src/constants.ts CHANGED
@@ -54,5 +54,6 @@ export const LAYOUT_ACTIVITY = 'activity';
54
54
  // Picker view layouts.
55
55
  export const LAYOUT_PICKER_GRID = 'pickerGrid';
56
56
  export const LAYOUT_PICKER_TABLE = 'pickerTable';
57
+ export const LAYOUT_PICKER_ACTIVITY = 'pickerActivity';
57
58
 
58
59
  export const DAYS_OF_WEEK: DayNumber[] = [ 0, 1, 2, 3, 4, 5, 6 ];