@wordpress/dataviews 13.0.0 → 13.1.1-next.v.202603102151.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 (57) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/build/components/dataform-controls/date.cjs +11 -1
  3. package/build/components/dataform-controls/date.cjs.map +2 -2
  4. package/build/components/dataform-controls/datetime.cjs +23 -32
  5. package/build/components/dataform-controls/datetime.cjs.map +2 -2
  6. package/build/components/dataform-controls/utils/relative-date-control.cjs +2 -1
  7. package/build/components/dataform-controls/utils/relative-date-control.cjs.map +2 -2
  8. package/build/components/dataform-layouts/normalize-form.cjs +19 -1
  9. package/build/components/dataform-layouts/normalize-form.cjs.map +2 -2
  10. package/build/components/dataform-layouts/panel/index.cjs +1 -1
  11. package/build/components/dataform-layouts/panel/index.cjs.map +2 -2
  12. package/build/components/dataform-layouts/panel/modal.cjs +4 -3
  13. package/build/components/dataform-layouts/panel/modal.cjs.map +2 -2
  14. package/build/components/dataviews-layouts/table/index.cjs +1 -1
  15. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  16. package/build/types/dataform.cjs.map +1 -1
  17. package/build-module/components/dataform-controls/date.mjs +11 -1
  18. package/build-module/components/dataform-controls/date.mjs.map +2 -2
  19. package/build-module/components/dataform-controls/datetime.mjs +24 -33
  20. package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
  21. package/build-module/components/dataform-controls/utils/relative-date-control.mjs +2 -1
  22. package/build-module/components/dataform-controls/utils/relative-date-control.mjs.map +2 -2
  23. package/build-module/components/dataform-layouts/normalize-form.mjs +19 -1
  24. package/build-module/components/dataform-layouts/normalize-form.mjs.map +2 -2
  25. package/build-module/components/dataform-layouts/panel/index.mjs +1 -1
  26. package/build-module/components/dataform-layouts/panel/index.mjs.map +2 -2
  27. package/build-module/components/dataform-layouts/panel/modal.mjs +4 -3
  28. package/build-module/components/dataform-layouts/panel/modal.mjs.map +2 -2
  29. package/build-module/components/dataviews-layouts/table/index.mjs +1 -1
  30. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  31. package/build-style/style-rtl.css +1 -1
  32. package/build-style/style.css +1 -1
  33. package/build-types/components/dataform-controls/date.d.ts.map +1 -1
  34. package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
  35. package/build-types/components/dataform-controls/utils/relative-date-control.d.ts.map +1 -1
  36. package/build-types/components/dataform-layouts/normalize-form.d.ts.map +1 -1
  37. package/build-types/components/dataform-layouts/panel/modal.d.ts.map +1 -1
  38. package/build-types/dataform/stories/index.story.d.ts +26 -1
  39. package/build-types/dataform/stories/index.story.d.ts.map +1 -1
  40. package/build-types/dataform/stories/layout-panel.d.ts +3 -1
  41. package/build-types/dataform/stories/layout-panel.d.ts.map +1 -1
  42. package/build-types/types/dataform.d.ts +17 -2
  43. package/build-types/types/dataform.d.ts.map +1 -1
  44. package/build-wp/index.js +290 -318
  45. package/package.json +16 -16
  46. package/src/components/dataform-controls/date.tsx +11 -1
  47. package/src/components/dataform-controls/datetime.tsx +28 -44
  48. package/src/components/dataform-controls/utils/relative-date-control.tsx +2 -1
  49. package/src/components/dataform-layouts/normalize-form.ts +24 -1
  50. package/src/components/dataform-layouts/panel/index.tsx +1 -1
  51. package/src/components/dataform-layouts/panel/modal.tsx +7 -3
  52. package/src/components/dataform-layouts/panel/style.scss +1 -1
  53. package/src/components/dataform-layouts/test/normalize-form.ts +98 -5
  54. package/src/components/dataviews-layouts/table/index.tsx +1 -1
  55. package/src/dataform/stories/index.story.tsx +15 -0
  56. package/src/dataform/stories/layout-panel.tsx +19 -4
  57. package/src/types/dataform.ts +15 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "13.0.0",
3
+ "version": "13.1.1-next.v.202603102151.0+59e17f9ec",
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",
@@ -53,20 +53,20 @@
53
53
  "sideEffects": false,
54
54
  "dependencies": {
55
55
  "@ariakit/react": "^0.4.21",
56
- "@wordpress/base-styles": "^6.17.0",
57
- "@wordpress/components": "^32.3.0",
58
- "@wordpress/compose": "^7.41.0",
59
- "@wordpress/data": "^10.41.0",
60
- "@wordpress/date": "^5.41.0",
61
- "@wordpress/deprecated": "^4.41.0",
62
- "@wordpress/element": "^6.41.0",
63
- "@wordpress/i18n": "^6.14.0",
64
- "@wordpress/icons": "^11.8.0",
65
- "@wordpress/keycodes": "^4.41.0",
66
- "@wordpress/primitives": "^4.41.0",
67
- "@wordpress/private-apis": "^1.41.0",
68
- "@wordpress/ui": "^0.8.0",
69
- "@wordpress/warning": "^3.41.0",
56
+ "@wordpress/base-styles": "^6.17.1-next.v.202603102151.0+59e17f9ec",
57
+ "@wordpress/components": "^32.4.1-next.v.202603102151.0+59e17f9ec",
58
+ "@wordpress/compose": "^7.41.1-next.v.202603102151.0+59e17f9ec",
59
+ "@wordpress/data": "^10.41.1-next.v.202603102151.0+59e17f9ec",
60
+ "@wordpress/date": "^5.41.1-next.v.202603102151.0+59e17f9ec",
61
+ "@wordpress/deprecated": "^4.41.1-next.v.202603102151.0+59e17f9ec",
62
+ "@wordpress/element": "^6.41.1-next.v.202603102151.0+59e17f9ec",
63
+ "@wordpress/i18n": "^6.14.1-next.v.202603102151.0+59e17f9ec",
64
+ "@wordpress/icons": "^12.0.1-next.v.202603102151.0+59e17f9ec",
65
+ "@wordpress/keycodes": "^4.41.1-next.v.202603102151.0+59e17f9ec",
66
+ "@wordpress/primitives": "^4.41.1-next.v.202603102151.0+59e17f9ec",
67
+ "@wordpress/private-apis": "^1.41.1-next.v.202603102151.0+59e17f9ec",
68
+ "@wordpress/ui": "^0.9.1-next.v.202603102151.0+59e17f9ec",
69
+ "@wordpress/warning": "^3.41.1-next.v.202603102151.0+59e17f9ec",
70
70
  "clsx": "^2.1.1",
71
71
  "colord": "^2.7.0",
72
72
  "date-fns": "^4.1.0",
@@ -92,5 +92,5 @@
92
92
  "scripts": {
93
93
  "build:wp": "node build.cjs"
94
94
  },
95
- "gitHead": "8bfc179b9aed74c0a6dd6e8edf7a49e40e4f87cc"
95
+ "gitHead": "86db21e727d89e8f0dbba9300d2f97fd22b08693"
96
96
  }
@@ -293,6 +293,7 @@ function CalendarDateControl< Item >( {
293
293
  const {
294
294
  id,
295
295
  label,
296
+ description,
296
297
  setValue,
297
298
  getValue,
298
299
  isValid,
@@ -385,6 +386,7 @@ function CalendarDateControl< Item >( {
385
386
  id={ id }
386
387
  className="dataviews-controls__date"
387
388
  label={ displayLabel }
389
+ help={ description }
388
390
  hideLabelFromVision={ hideLabelFromVision }
389
391
  >
390
392
  <Stack direction="column" gap="lg">
@@ -462,7 +464,14 @@ function CalendarDateRangeControl< Item >( {
462
464
  markWhenOptional,
463
465
  validity,
464
466
  }: DataFormControlProps< Item > ) {
465
- const { id, label, getValue, setValue, format: fieldFormat } = field;
467
+ const {
468
+ id,
469
+ label,
470
+ description,
471
+ getValue,
472
+ setValue,
473
+ format: fieldFormat,
474
+ } = field;
466
475
  let value: DateRange;
467
476
  const fieldValue = getValue( { item: data } );
468
477
  if (
@@ -597,6 +606,7 @@ function CalendarDateRangeControl< Item >( {
597
606
  id={ id }
598
607
  className="dataviews-controls__date"
599
608
  label={ displayLabel }
609
+ help={ description }
600
610
  hideLabelFromVision={ hideLabelFromVision }
601
611
  >
602
612
  <Stack direction="column" gap="lg">
@@ -1,8 +1,3 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { format } from 'date-fns';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
@@ -12,7 +7,7 @@ import {
12
7
  } from '@wordpress/components';
13
8
  import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
14
9
  import { __ } from '@wordpress/i18n';
15
- import { getSettings } from '@wordpress/date';
10
+ import { dateI18n, getDate, getSettings } from '@wordpress/date';
16
11
  import { Stack } from '@wordpress/ui';
17
12
 
18
13
  /**
@@ -27,15 +22,12 @@ import { unlock } from '../../lock-unlock';
27
22
 
28
23
  const { DateCalendar, ValidatedInputControl } = unlock( componentsPrivateApis );
29
24
 
30
- const formatDateTime = ( date?: Date | string ): string => {
31
- if ( ! date ) {
25
+ const formatDateTime = ( value?: string ): string => {
26
+ if ( ! value ) {
32
27
  return '';
33
28
  }
34
- if ( typeof date === 'string' ) {
35
- return date;
36
- }
37
- // Format as datetime-local input expects: YYYY-MM-DDTHH:mm
38
- return format( date, "yyyy-MM-dd'T'HH:mm" );
29
+ // Format in WordPress timezone for datetime-local input: YYYY-MM-DDTHH:mm
30
+ return dateI18n( 'Y-m-d\\TH:i', getDate( value ) );
39
31
  };
40
32
 
41
33
  function CalendarDateTimeControl< Item >( {
@@ -79,21 +71,19 @@ function CalendarDateTimeControl< Item >( {
79
71
  ( newDate: Date | undefined | null ) => {
80
72
  let dateTimeValue: string | undefined;
81
73
  if ( newDate ) {
82
- // Preserve time if it exists in current value, otherwise use current time
83
- let finalDateTime = newDate;
74
+ // Extract the date part in WP timezone from the calendar selection
75
+ const wpDate = dateI18n( 'Y-m-d', newDate );
84
76
 
77
+ // Preserve time if it exists in current value, otherwise use current time
78
+ let wpTime: string;
85
79
  if ( value ) {
86
- const currentDateTime = parseDateTime( value );
87
- if ( currentDateTime ) {
88
- // Preserve the time part
89
- finalDateTime = new Date( newDate );
90
- finalDateTime.setHours( currentDateTime.getHours() );
91
- finalDateTime.setMinutes(
92
- currentDateTime.getMinutes()
93
- );
94
- }
80
+ wpTime = dateI18n( 'H:i', getDate( value ) );
81
+ } else {
82
+ wpTime = dateI18n( 'H:i', newDate );
95
83
  }
96
84
 
85
+ // Combine date and time in WP timezone and convert to ISO
86
+ const finalDateTime = getDate( `${ wpDate }T${ wpTime }` );
97
87
  dateTimeValue = finalDateTime.toISOString();
98
88
  onChangeCallback( dateTimeValue );
99
89
 
@@ -133,8 +123,8 @@ function CalendarDateTimeControl< Item >( {
133
123
  const handleManualDateTimeChange = useCallback(
134
124
  ( newValue?: string ) => {
135
125
  if ( newValue ) {
136
- // Convert from datetime-local format to ISO string
137
- const dateTime = new Date( newValue );
126
+ // Interpret the datetime-local value in WordPress timezone
127
+ const dateTime = getDate( newValue );
138
128
  onChangeCallback( dateTime.toISOString() );
139
129
 
140
130
  // Update calendar month to match
@@ -176,6 +166,18 @@ function CalendarDateTimeControl< Item >( {
176
166
  hideLabelFromVision={ hideLabelFromVision }
177
167
  >
178
168
  <Stack direction="column" gap="lg">
169
+ { /* Manual datetime input */ }
170
+ <ValidatedInputControl
171
+ ref={ inputControlRef }
172
+ __next40pxDefaultSize
173
+ required={ !! isValid?.required }
174
+ customValidity={ getCustomValidity( isValid, validity ) }
175
+ type="datetime-local"
176
+ label={ __( 'Date time' ) }
177
+ hideLabelFromVision
178
+ value={ formatDateTime( value ) }
179
+ onChange={ handleManualDateTimeChange }
180
+ />
179
181
  { /* Calendar widget */ }
180
182
  <DateCalendar
181
183
  style={ { width: '100%' } }
@@ -188,24 +190,6 @@ function CalendarDateTimeControl< Item >( {
188
190
  timeZone={ timezoneString || undefined }
189
191
  weekStartsOn={ weekStartsOn }
190
192
  />
191
- { /* Manual datetime input */ }
192
- <ValidatedInputControl
193
- ref={ inputControlRef }
194
- __next40pxDefaultSize
195
- required={ !! isValid?.required }
196
- customValidity={ getCustomValidity( isValid, validity ) }
197
- type="datetime-local"
198
- label={ __( 'Date time' ) }
199
- hideLabelFromVision
200
- value={
201
- value
202
- ? formatDateTime(
203
- parseDateTime( value ) || undefined
204
- )
205
- : ''
206
- }
207
- onChange={ handleManualDateTimeChange }
208
- />
209
193
  </Stack>
210
194
  </BaseControl>
211
195
  );
@@ -58,7 +58,7 @@ export default function RelativeDateControl< Item >( {
58
58
  operator === OPERATOR_IN_THE_PAST ? 'inThePast' : 'over'
59
59
  ];
60
60
 
61
- const { id, label, getValue, setValue } = field;
61
+ const { id, label, description, getValue, setValue } = field;
62
62
  const fieldValue = getValue( { item: data } );
63
63
  const { value: relValue = '', unit = options[ 0 ].value } =
64
64
  fieldValue && typeof fieldValue === 'object' ? fieldValue : {};
@@ -91,6 +91,7 @@ export default function RelativeDateControl< Item >( {
91
91
  className={ clsx( className, 'dataviews-controls__relative-date' ) }
92
92
  label={ label }
93
93
  hideLabelFromVision={ hideLabelFromVision }
94
+ help={ description }
94
95
  >
95
96
  <Stack direction="row" gap="sm">
96
97
  <NumberControl
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+
1
6
  /**
2
7
  * Internal dependencies
3
8
  */
@@ -55,10 +60,28 @@ function normalizeLayout( layout?: Layout ): NormalizedLayout {
55
60
  ? summary
56
61
  : [ summary ];
57
62
 
63
+ const openAs = layout?.openAs;
64
+ let normalizedOpenAs: NormalizedPanelLayout[ 'openAs' ];
65
+ if ( typeof openAs === 'object' && openAs.type === 'modal' ) {
66
+ normalizedOpenAs = {
67
+ type: 'modal',
68
+ applyLabel: openAs.applyLabel?.trim() || __( 'Apply' ),
69
+ cancelLabel: openAs.cancelLabel?.trim() || __( 'Cancel' ),
70
+ };
71
+ } else if ( openAs === 'modal' ) {
72
+ normalizedOpenAs = {
73
+ type: 'modal',
74
+ applyLabel: __( 'Apply' ),
75
+ cancelLabel: __( 'Cancel' ),
76
+ };
77
+ } else {
78
+ normalizedOpenAs = { type: 'dropdown' };
79
+ }
80
+
58
81
  normalizedLayout = {
59
82
  type: 'panel',
60
83
  labelPosition: layout?.labelPosition ?? 'side',
61
- openAs: layout?.openAs ?? 'dropdown',
84
+ openAs: normalizedOpenAs,
62
85
  summary: normalizedSummary,
63
86
  editVisibility: layout?.editVisibility ?? 'on-hover',
64
87
  } satisfies NormalizedPanelLayout;
@@ -13,7 +13,7 @@ export default function FormPanelField< Item >( {
13
13
  }: FieldLayoutProps< Item > ) {
14
14
  const layout = field.layout as NormalizedPanelLayout;
15
15
 
16
- if ( layout.openAs === 'modal' ) {
16
+ if ( layout.openAs.type === 'modal' ) {
17
17
  return (
18
18
  <PanelModal
19
19
  data={ data }
@@ -11,7 +11,7 @@ import {
11
11
  Button,
12
12
  Modal,
13
13
  } from '@wordpress/components';
14
- import { __ } from '@wordpress/i18n';
14
+
15
15
  import { useContext, useMemo, useRef, useState } from '@wordpress/element';
16
16
  import { useFocusOnMount, useMergeRefs } from '@wordpress/compose';
17
17
  import { Stack } from '@wordpress/ui';
@@ -23,6 +23,8 @@ import type {
23
23
  Field,
24
24
  NormalizedForm,
25
25
  NormalizedFormField,
26
+ NormalizedPanelLayout,
27
+ PanelOpenAsModal,
26
28
  FieldLayoutProps,
27
29
  } from '../../../types';
28
30
  import { DataFormLayout } from '../data-form-layout';
@@ -48,6 +50,8 @@ function ModalContent< Item >( {
48
50
  fieldLabel: string;
49
51
  touched: boolean;
50
52
  } ) {
53
+ const { openAs } = field.layout as NormalizedPanelLayout;
54
+ const { applyLabel, cancelLabel } = openAs as PanelOpenAsModal;
51
55
  const { fields } = useContext( DataFormContext );
52
56
  const [ changes, setChanges ] = useState< Partial< Item > >( {} );
53
57
  const modalData = useMemo( () => {
@@ -147,14 +151,14 @@ function ModalContent< Item >( {
147
151
  onClick={ onClose }
148
152
  __next40pxDefaultSize
149
153
  >
150
- { __( 'Cancel' ) }
154
+ { cancelLabel }
151
155
  </Button>
152
156
  <Button
153
157
  variant="primary"
154
158
  onClick={ onApply }
155
159
  __next40pxDefaultSize
156
160
  >
157
- { __( 'Apply' ) }
161
+ { applyLabel }
158
162
  </Button>
159
163
  </Stack>
160
164
  </Modal>
@@ -152,7 +152,7 @@
152
152
  }
153
153
 
154
154
  .dataforms-layouts-panel__field-dropdown .components-popover__content {
155
- min-width: 320px;
155
+ min-width: 256px;
156
156
  padding: $grid-unit-20;
157
157
  }
158
158
 
@@ -137,7 +137,7 @@ describe( 'normalizeFormFields', () => {
137
137
  layout: {
138
138
  labelPosition: 'side',
139
139
  type: 'panel',
140
- openAs: 'dropdown',
140
+ openAs: { type: 'dropdown' },
141
141
  summary: [],
142
142
  editVisibility: 'on-hover',
143
143
  },
@@ -147,7 +147,7 @@ describe( 'normalizeFormFields', () => {
147
147
  layout: {
148
148
  type: 'panel',
149
149
  labelPosition: 'side',
150
- openAs: 'dropdown',
150
+ openAs: { type: 'dropdown' },
151
151
  summary: [],
152
152
  editVisibility: 'on-hover',
153
153
  },
@@ -166,7 +166,7 @@ describe( 'normalizeFormFields', () => {
166
166
  layout: {
167
167
  labelPosition: 'top',
168
168
  type: 'panel',
169
- openAs: 'dropdown',
169
+ openAs: { type: 'dropdown' },
170
170
  summary: [],
171
171
  editVisibility: 'on-hover',
172
172
  },
@@ -176,7 +176,7 @@ describe( 'normalizeFormFields', () => {
176
176
  layout: {
177
177
  type: 'panel',
178
178
  labelPosition: 'top',
179
- openAs: 'dropdown',
179
+ openAs: { type: 'dropdown' },
180
180
  summary: [],
181
181
  editVisibility: 'on-hover',
182
182
  },
@@ -185,6 +185,99 @@ describe( 'normalizeFormFields', () => {
185
185
  } );
186
186
  } );
187
187
 
188
+ it( 'panel: openAs string "modal" normalizes to object with defaults', () => {
189
+ const form: Form = {
190
+ layout: { type: 'panel', openAs: 'modal' },
191
+ fields: [ 'field1' ],
192
+ };
193
+ const result = normalizeForm( form );
194
+ expect( result.layout ).toEqual( {
195
+ type: 'panel',
196
+ labelPosition: 'side',
197
+ openAs: {
198
+ type: 'modal',
199
+ applyLabel: 'Apply',
200
+ cancelLabel: 'Cancel',
201
+ },
202
+ summary: [],
203
+ editVisibility: 'on-hover',
204
+ } );
205
+ } );
206
+
207
+ it( 'panel: openAs object preserves labels', () => {
208
+ const form: Form = {
209
+ layout: {
210
+ type: 'panel',
211
+ openAs: {
212
+ type: 'modal',
213
+ applyLabel: 'Save',
214
+ cancelLabel: 'Dismiss',
215
+ },
216
+ },
217
+ fields: [ 'field1' ],
218
+ };
219
+ const result = normalizeForm( form );
220
+ expect( result.layout ).toEqual( {
221
+ type: 'panel',
222
+ labelPosition: 'side',
223
+ openAs: {
224
+ type: 'modal',
225
+ applyLabel: 'Save',
226
+ cancelLabel: 'Dismiss',
227
+ },
228
+ summary: [],
229
+ editVisibility: 'on-hover',
230
+ } );
231
+ } );
232
+
233
+ it( 'panel: openAs object without labels gets defaults', () => {
234
+ const form: Form = {
235
+ layout: {
236
+ type: 'panel',
237
+ openAs: { type: 'modal' },
238
+ },
239
+ fields: [ 'field1' ],
240
+ };
241
+ const result = normalizeForm( form );
242
+ expect( result.layout ).toEqual( {
243
+ type: 'panel',
244
+ labelPosition: 'side',
245
+ openAs: {
246
+ type: 'modal',
247
+ applyLabel: 'Apply',
248
+ cancelLabel: 'Cancel',
249
+ },
250
+ summary: [],
251
+ editVisibility: 'on-hover',
252
+ } );
253
+ } );
254
+
255
+ it( 'panel: openAs object trims whitespace and falls back to defaults', () => {
256
+ const form: Form = {
257
+ layout: {
258
+ type: 'panel',
259
+ openAs: {
260
+ type: 'modal',
261
+ applyLabel: ' ',
262
+ cancelLabel: '',
263
+ },
264
+ },
265
+ fields: [ 'field1' ],
266
+ };
267
+ const result = normalizeForm( form );
268
+ expect( result.layout ).toEqual( {
269
+ type: 'panel',
270
+ labelPosition: 'side',
271
+ openAs: {
272
+ type: 'modal',
273
+ applyLabel: 'Apply',
274
+ cancelLabel: 'Cancel',
275
+ },
276
+ summary: [],
277
+ editVisibility: 'on-hover',
278
+ } );
279
+ } );
280
+
188
281
  it( 'card: with default layout options', () => {
189
282
  const form: Form = {
190
283
  layout: { type: 'card' },
@@ -360,7 +453,7 @@ describe( 'normalizeFormFields', () => {
360
453
  layout: {
361
454
  type: 'panel',
362
455
  labelPosition: 'side',
363
- openAs: 'dropdown',
456
+ openAs: { type: 'dropdown' },
364
457
  summary: [],
365
458
  editVisibility: 'on-hover',
366
459
  },
@@ -444,7 +444,7 @@ function ViewTable< Item >( {
444
444
  className={ clsx(
445
445
  `dataviews-view-table__col-${ column }`,
446
446
  {
447
- 'dataviews-view-table__col-first-expand':
447
+ 'dataviews-view-table__col-expand':
448
448
  ! hasPrimaryColumn &&
449
449
  index === columns.length - 1,
450
450
  }
@@ -67,6 +67,21 @@ export const LayoutPanel = {
67
67
  description: 'Chooses when the edit icon is visible.',
68
68
  options: [ 'default', 'always', 'on-hover' ],
69
69
  },
70
+ applyLabel: {
71
+ control: { type: 'text' },
72
+ description:
73
+ 'Custom text for the modal apply button. Defaults to "Apply".',
74
+ if: { arg: 'openAs', eq: 'modal' },
75
+ },
76
+ cancelLabel: {
77
+ control: { type: 'text' },
78
+ description:
79
+ 'Custom text for the modal cancel button. Defaults to "Cancel".',
80
+ if: { arg: 'openAs', eq: 'modal' },
81
+ },
82
+ },
83
+ args: {
84
+ openAs: 'default',
70
85
  },
71
86
  };
72
87
 
@@ -275,7 +275,7 @@ const getPanelLayoutFromStoryArgs = ( {
275
275
  }: {
276
276
  summary?: string[];
277
277
  labelPosition?: 'default' | 'top' | 'side' | 'none';
278
- openAs?: 'default' | 'dropdown' | 'modal';
278
+ openAs?: PanelLayout[ 'openAs' ];
279
279
  editVisibility?: 'default' | EditVisibility;
280
280
  } ): Layout | undefined => {
281
281
  const panelLayout: PanelLayout = {
@@ -286,7 +286,7 @@ const getPanelLayoutFromStoryArgs = ( {
286
286
  panelLayout.labelPosition = labelPosition;
287
287
  }
288
288
 
289
- if ( openAs !== 'default' ) {
289
+ if ( openAs ) {
290
290
  panelLayout.openAs = openAs;
291
291
  }
292
292
 
@@ -303,13 +303,17 @@ const getPanelLayoutFromStoryArgs = ( {
303
303
 
304
304
  const LayoutPanelComponent = ( {
305
305
  labelPosition,
306
- openAs,
306
+ openAs: openAsArg,
307
307
  editVisibility,
308
+ applyLabel,
309
+ cancelLabel,
308
310
  }: {
309
311
  type: 'default' | 'regular' | 'panel' | 'card';
310
312
  labelPosition: 'default' | 'top' | 'side' | 'none';
311
313
  openAs: 'default' | 'dropdown' | 'modal';
312
314
  editVisibility: 'default' | EditVisibility;
315
+ applyLabel?: string;
316
+ cancelLabel?: string;
313
317
  } ) => {
314
318
  const [ post, setPost ] = useState< SamplePost >( {
315
319
  title: 'Hello, World!',
@@ -335,6 +339,17 @@ const LayoutPanelComponent = ( {
335
339
  } );
336
340
 
337
341
  const form: Form = useMemo( () => {
342
+ let openAs: PanelLayout[ 'openAs' ];
343
+ if ( openAsArg === 'modal' && ( applyLabel || cancelLabel ) ) {
344
+ openAs = {
345
+ type: 'modal',
346
+ applyLabel: applyLabel || undefined,
347
+ cancelLabel: cancelLabel || undefined,
348
+ };
349
+ } else if ( openAsArg !== 'default' ) {
350
+ openAs = openAsArg;
351
+ }
352
+
338
353
  return {
339
354
  layout: getPanelLayoutFromStoryArgs( {
340
355
  labelPosition,
@@ -392,7 +407,7 @@ const LayoutPanelComponent = ( {
392
407
  },
393
408
  ],
394
409
  };
395
- }, [ labelPosition, openAs, editVisibility ] );
410
+ }, [ labelPosition, openAsArg, applyLabel, cancelLabel, editVisibility ] );
396
411
 
397
412
  return (
398
413
  <DataForm< SamplePost >
@@ -23,17 +23,30 @@ export type NormalizedRegularLayout = {
23
23
 
24
24
  export type EditVisibility = 'always' | 'on-hover';
25
25
 
26
+ type PanelOpenAsDropdown = {
27
+ type: 'dropdown';
28
+ };
29
+ export type PanelOpenAsModal = {
30
+ type: 'modal';
31
+ applyLabel: string;
32
+ cancelLabel: string;
33
+ };
34
+
26
35
  export type PanelLayout = {
27
36
  type: 'panel';
28
37
  labelPosition?: LabelPosition;
29
- openAs?: 'dropdown' | 'modal';
38
+ openAs?:
39
+ | 'dropdown'
40
+ | 'modal'
41
+ | { type: 'dropdown' }
42
+ | { type: 'modal'; applyLabel?: string; cancelLabel?: string };
30
43
  summary?: PanelSummaryField;
31
44
  editVisibility?: EditVisibility;
32
45
  };
33
46
  export type NormalizedPanelLayout = {
34
47
  type: 'panel';
35
48
  labelPosition: LabelPosition;
36
- openAs: 'dropdown' | 'modal';
49
+ openAs: PanelOpenAsDropdown | PanelOpenAsModal;
37
50
  summary: NormalizedPanelSummaryField;
38
51
  editVisibility: EditVisibility;
39
52
  };