@wordpress/dataviews 9.0.1-next.6870dfe5b.0 → 9.0.1-next.a730c9c8c.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 (255) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/README.md +107 -12
  3. package/build/components/dataviews-filters/input-widget.js +48 -4
  4. package/build/components/dataviews-filters/input-widget.js.map +1 -1
  5. package/build/components/dataviews-layout/index.js +3 -1
  6. package/build/components/dataviews-layout/index.js.map +1 -1
  7. package/build/dataform-controls/array.js +9 -7
  8. package/build/dataform-controls/array.js.map +1 -1
  9. package/build/dataform-controls/checkbox.js +31 -20
  10. package/build/dataform-controls/checkbox.js.map +1 -1
  11. package/build/dataform-controls/color.js +29 -24
  12. package/build/dataform-controls/color.js.map +1 -1
  13. package/build/dataform-controls/date.js +32 -24
  14. package/build/dataform-controls/date.js.map +1 -1
  15. package/build/dataform-controls/datetime.js +133 -19
  16. package/build/dataform-controls/datetime.js.map +1 -1
  17. package/build/dataform-controls/email.js +9 -3
  18. package/build/dataform-controls/email.js.map +1 -1
  19. package/build/dataform-controls/index.js +27 -0
  20. package/build/dataform-controls/index.js.map +1 -1
  21. package/build/dataform-controls/integer.js +47 -34
  22. package/build/dataform-controls/integer.js.map +1 -1
  23. package/build/dataform-controls/password.js +47 -0
  24. package/build/dataform-controls/password.js.map +1 -0
  25. package/build/dataform-controls/radio.js +42 -9
  26. package/build/dataform-controls/radio.js.map +1 -1
  27. package/build/dataform-controls/relative-date-control.js +6 -10
  28. package/build/dataform-controls/relative-date-control.js.map +1 -1
  29. package/build/dataform-controls/select.js +41 -10
  30. package/build/dataform-controls/select.js.map +1 -1
  31. package/build/dataform-controls/telephone.js +9 -3
  32. package/build/dataform-controls/telephone.js.map +1 -1
  33. package/build/dataform-controls/text.js +16 -4
  34. package/build/dataform-controls/text.js.map +1 -1
  35. package/build/dataform-controls/textarea.js +81 -0
  36. package/build/dataform-controls/textarea.js.map +1 -0
  37. package/build/dataform-controls/toggle-group.js +36 -6
  38. package/build/dataform-controls/toggle-group.js.map +1 -1
  39. package/build/dataform-controls/toggle.js +33 -22
  40. package/build/dataform-controls/toggle.js.map +1 -1
  41. package/build/dataform-controls/url.js +9 -3
  42. package/build/dataform-controls/url.js.map +1 -1
  43. package/build/dataform-controls/utils/{validated-text.js → validated-input.js} +36 -29
  44. package/build/dataform-controls/utils/validated-input.js.map +1 -0
  45. package/build/dataforms-layouts/panel/dropdown.js +10 -14
  46. package/build/dataforms-layouts/panel/dropdown.js.map +1 -1
  47. package/build/dataforms-layouts/panel/index.js +24 -11
  48. package/build/dataforms-layouts/panel/index.js.map +1 -1
  49. package/build/dataforms-layouts/panel/modal.js +22 -27
  50. package/build/dataforms-layouts/panel/modal.js.map +1 -1
  51. package/build/dataforms-layouts/panel/summary-button.js +67 -0
  52. package/build/dataforms-layouts/panel/summary-button.js.map +1 -0
  53. package/build/dataforms-layouts/regular/index.js +7 -9
  54. package/build/dataforms-layouts/regular/index.js.map +1 -1
  55. package/build/dataviews-layouts/grid/index.js +5 -15
  56. package/build/dataviews-layouts/grid/index.js.map +1 -1
  57. package/build/dataviews-layouts/list/index.js +47 -2
  58. package/build/dataviews-layouts/list/index.js.map +1 -1
  59. package/build/dataviews-layouts/picker-grid/index.js +5 -15
  60. package/build/dataviews-layouts/picker-grid/index.js.map +1 -1
  61. package/build/dataviews-layouts/table/index.js +5 -17
  62. package/build/dataviews-layouts/table/index.js.map +1 -1
  63. package/build/dataviews-layouts/utils/get-data-by-group.js +23 -0
  64. package/build/dataviews-layouts/utils/get-data-by-group.js.map +1 -0
  65. package/build/field-types/index.js +4 -0
  66. package/build/field-types/index.js.map +1 -1
  67. package/build/field-types/password.js +51 -0
  68. package/build/field-types/password.js.map +1 -0
  69. package/build/normalize-fields.js +17 -0
  70. package/build/normalize-fields.js.map +1 -1
  71. package/build/types.js.map +1 -1
  72. package/build/validation.js +1 -1
  73. package/build/validation.js.map +1 -1
  74. package/build-module/components/dataviews-filters/input-widget.js +48 -4
  75. package/build-module/components/dataviews-filters/input-widget.js.map +1 -1
  76. package/build-module/components/dataviews-layout/index.js +3 -1
  77. package/build-module/components/dataviews-layout/index.js.map +1 -1
  78. package/build-module/dataform-controls/array.js +9 -7
  79. package/build-module/dataform-controls/array.js.map +1 -1
  80. package/build-module/dataform-controls/checkbox.js +31 -21
  81. package/build-module/dataform-controls/checkbox.js.map +1 -1
  82. package/build-module/dataform-controls/color.js +28 -24
  83. package/build-module/dataform-controls/color.js.map +1 -1
  84. package/build-module/dataform-controls/date.js +32 -24
  85. package/build-module/dataform-controls/date.js.map +1 -1
  86. package/build-module/dataform-controls/datetime.js +135 -21
  87. package/build-module/dataform-controls/datetime.js.map +1 -1
  88. package/build-module/dataform-controls/email.js +8 -2
  89. package/build-module/dataform-controls/email.js.map +1 -1
  90. package/build-module/dataform-controls/index.js +27 -0
  91. package/build-module/dataform-controls/index.js.map +1 -1
  92. package/build-module/dataform-controls/integer.js +46 -34
  93. package/build-module/dataform-controls/integer.js.map +1 -1
  94. package/build-module/dataform-controls/password.js +38 -0
  95. package/build-module/dataform-controls/password.js.map +1 -0
  96. package/build-module/dataform-controls/radio.js +44 -11
  97. package/build-module/dataform-controls/radio.js.map +1 -1
  98. package/build-module/dataform-controls/relative-date-control.js +6 -10
  99. package/build-module/dataform-controls/relative-date-control.js.map +1 -1
  100. package/build-module/dataform-controls/select.js +43 -12
  101. package/build-module/dataform-controls/select.js.map +1 -1
  102. package/build-module/dataform-controls/telephone.js +8 -2
  103. package/build-module/dataform-controls/telephone.js.map +1 -1
  104. package/build-module/dataform-controls/text.js +15 -3
  105. package/build-module/dataform-controls/text.js.map +1 -1
  106. package/build-module/dataform-controls/textarea.js +74 -0
  107. package/build-module/dataform-controls/textarea.js.map +1 -0
  108. package/build-module/dataform-controls/toggle-group.js +38 -8
  109. package/build-module/dataform-controls/toggle-group.js.map +1 -1
  110. package/build-module/dataform-controls/toggle.js +33 -23
  111. package/build-module/dataform-controls/toggle.js.map +1 -1
  112. package/build-module/dataform-controls/url.js +8 -2
  113. package/build-module/dataform-controls/url.js.map +1 -1
  114. package/build-module/dataform-controls/utils/validated-input.js +76 -0
  115. package/build-module/dataform-controls/utils/validated-input.js.map +1 -0
  116. package/build-module/dataforms-layouts/panel/dropdown.js +10 -15
  117. package/build-module/dataforms-layouts/panel/dropdown.js.map +1 -1
  118. package/build-module/dataforms-layouts/panel/index.js +24 -11
  119. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  120. package/build-module/dataforms-layouts/panel/modal.js +22 -28
  121. package/build-module/dataforms-layouts/panel/modal.js.map +1 -1
  122. package/build-module/dataforms-layouts/panel/summary-button.js +60 -0
  123. package/build-module/dataforms-layouts/panel/summary-button.js.map +1 -0
  124. package/build-module/dataforms-layouts/regular/index.js +8 -10
  125. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  126. package/build-module/dataviews-layouts/grid/index.js +6 -16
  127. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  128. package/build-module/dataviews-layouts/list/index.js +48 -3
  129. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  130. package/build-module/dataviews-layouts/picker-grid/index.js +6 -16
  131. package/build-module/dataviews-layouts/picker-grid/index.js.map +1 -1
  132. package/build-module/dataviews-layouts/table/index.js +5 -17
  133. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  134. package/build-module/dataviews-layouts/utils/get-data-by-group.js +17 -0
  135. package/build-module/dataviews-layouts/utils/get-data-by-group.js.map +1 -0
  136. package/build-module/field-types/index.js +4 -0
  137. package/build-module/field-types/index.js.map +1 -1
  138. package/build-module/field-types/password.js +46 -0
  139. package/build-module/field-types/password.js.map +1 -0
  140. package/build-module/normalize-fields.js +15 -0
  141. package/build-module/normalize-fields.js.map +1 -1
  142. package/build-module/types.js.map +1 -1
  143. package/build-module/validation.js +1 -1
  144. package/build-module/validation.js.map +1 -1
  145. package/build-style/style-rtl.css +9 -6
  146. package/build-style/style.css +9 -6
  147. package/build-types/components/dataform/stories/index.story.d.ts +3 -14
  148. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  149. package/build-types/components/dataviews/stories/fixtures.d.ts +4 -2
  150. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  151. package/build-types/components/dataviews-filters/input-widget.d.ts.map +1 -1
  152. package/build-types/dataform-controls/array.d.ts.map +1 -1
  153. package/build-types/dataform-controls/checkbox.d.ts.map +1 -1
  154. package/build-types/dataform-controls/color.d.ts.map +1 -1
  155. package/build-types/dataform-controls/date.d.ts.map +1 -1
  156. package/build-types/dataform-controls/datetime.d.ts.map +1 -1
  157. package/build-types/dataform-controls/email.d.ts.map +1 -1
  158. package/build-types/dataform-controls/index.d.ts +1 -1
  159. package/build-types/dataform-controls/index.d.ts.map +1 -1
  160. package/build-types/dataform-controls/integer.d.ts.map +1 -1
  161. package/build-types/dataform-controls/password.d.ts +3 -0
  162. package/build-types/dataform-controls/password.d.ts.map +1 -0
  163. package/build-types/dataform-controls/radio.d.ts.map +1 -1
  164. package/build-types/dataform-controls/relative-date-control.d.ts +6 -5
  165. package/build-types/dataform-controls/relative-date-control.d.ts.map +1 -1
  166. package/build-types/dataform-controls/select.d.ts.map +1 -1
  167. package/build-types/dataform-controls/telephone.d.ts.map +1 -1
  168. package/build-types/dataform-controls/text.d.ts +1 -1
  169. package/build-types/dataform-controls/text.d.ts.map +1 -1
  170. package/build-types/dataform-controls/textarea.d.ts +6 -0
  171. package/build-types/dataform-controls/textarea.d.ts.map +1 -0
  172. package/build-types/dataform-controls/toggle-group.d.ts.map +1 -1
  173. package/build-types/dataform-controls/toggle.d.ts.map +1 -1
  174. package/build-types/dataform-controls/url.d.ts.map +1 -1
  175. package/build-types/dataform-controls/utils/validated-input.d.ts +20 -0
  176. package/build-types/dataform-controls/utils/validated-input.d.ts.map +1 -0
  177. package/build-types/dataforms-layouts/panel/dropdown.d.ts +2 -1
  178. package/build-types/dataforms-layouts/panel/dropdown.d.ts.map +1 -1
  179. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  180. package/build-types/dataforms-layouts/panel/modal.d.ts +2 -1
  181. package/build-types/dataforms-layouts/panel/modal.d.ts.map +1 -1
  182. package/build-types/dataforms-layouts/panel/summary-button.d.ts +15 -0
  183. package/build-types/dataforms-layouts/panel/summary-button.d.ts.map +1 -0
  184. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
  185. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  186. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  187. package/build-types/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
  188. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  189. package/build-types/dataviews-layouts/utils/get-data-by-group.d.ts +6 -0
  190. package/build-types/dataviews-layouts/utils/get-data-by-group.d.ts.map +1 -0
  191. package/build-types/field-types/index.d.ts.map +1 -1
  192. package/build-types/field-types/password.d.ts +17 -0
  193. package/build-types/field-types/password.d.ts.map +1 -0
  194. package/build-types/field-types/stories/index.story.d.ts +5 -1
  195. package/build-types/field-types/stories/index.story.d.ts.map +1 -1
  196. package/build-types/normalize-fields.d.ts +3 -0
  197. package/build-types/normalize-fields.d.ts.map +1 -1
  198. package/build-types/types.d.ts +67 -4
  199. package/build-types/types.d.ts.map +1 -1
  200. package/build-types/validation.d.ts.map +1 -1
  201. package/build-wp/index.js +1670 -1350
  202. package/package.json +16 -15
  203. package/src/components/dataform/stories/index.story.tsx +489 -17
  204. package/src/components/dataviews/stories/fixtures.tsx +99 -41
  205. package/src/components/dataviews/stories/index.story.tsx +2 -2
  206. package/src/components/dataviews-filters/input-widget.tsx +44 -5
  207. package/src/components/dataviews-layout/index.tsx +1 -1
  208. package/src/components/dataviews-picker/stories/index.story.tsx +1 -1
  209. package/src/dataform-controls/array.tsx +4 -6
  210. package/src/dataform-controls/checkbox.tsx +41 -24
  211. package/src/dataform-controls/color.tsx +33 -24
  212. package/src/dataform-controls/date.tsx +47 -21
  213. package/src/dataform-controls/datetime.tsx +171 -23
  214. package/src/dataform-controls/email.tsx +10 -2
  215. package/src/dataform-controls/index.tsx +30 -0
  216. package/src/dataform-controls/integer.tsx +82 -49
  217. package/src/dataform-controls/password.tsx +50 -0
  218. package/src/dataform-controls/radio.tsx +53 -11
  219. package/src/dataform-controls/relative-date-control.tsx +11 -10
  220. package/src/dataform-controls/select.tsx +53 -10
  221. package/src/dataform-controls/telephone.tsx +10 -2
  222. package/src/dataform-controls/text.tsx +19 -2
  223. package/src/dataform-controls/textarea.tsx +85 -0
  224. package/src/dataform-controls/toggle-group.tsx +50 -10
  225. package/src/dataform-controls/toggle.tsx +41 -24
  226. package/src/dataform-controls/url.tsx +10 -2
  227. package/src/dataform-controls/utils/validated-input.tsx +109 -0
  228. package/src/dataforms-layouts/panel/dropdown.tsx +12 -23
  229. package/src/dataforms-layouts/panel/index.tsx +39 -16
  230. package/src/dataforms-layouts/panel/modal.tsx +24 -30
  231. package/src/dataforms-layouts/panel/summary-button.tsx +92 -0
  232. package/src/dataforms-layouts/regular/index.tsx +9 -7
  233. package/src/dataforms-layouts/regular/style.scss +0 -6
  234. package/src/dataviews-layouts/grid/index.tsx +9 -14
  235. package/src/dataviews-layouts/grid/style.scss +1 -0
  236. package/src/dataviews-layouts/list/index.tsx +74 -2
  237. package/src/dataviews-layouts/list/style.scss +8 -0
  238. package/src/dataviews-layouts/picker-grid/index.tsx +9 -13
  239. package/src/dataviews-layouts/table/index.tsx +10 -14
  240. package/src/dataviews-layouts/utils/get-data-by-group.ts +18 -0
  241. package/src/field-types/index.tsx +5 -0
  242. package/src/field-types/password.tsx +46 -0
  243. package/src/field-types/stories/index.story.tsx +138 -1
  244. package/src/normalize-fields.ts +18 -0
  245. package/src/test/filter-and-sort-data-view.js +148 -138
  246. package/src/test/normalize-fields.ts +114 -0
  247. package/src/types.ts +74 -3
  248. package/src/validation.ts +2 -0
  249. package/tsconfig.tsbuildinfo +1 -1
  250. package/build/dataform-controls/utils/validated-text.js.map +0 -1
  251. package/build-module/dataform-controls/utils/validated-text.js +0 -70
  252. package/build-module/dataform-controls/utils/validated-text.js.map +0 -1
  253. package/build-types/dataform-controls/utils/validated-text.d.ts +0 -16
  254. package/build-types/dataform-controls/utils/validated-text.d.ts.map +0 -1
  255. package/src/dataform-controls/utils/validated-text.tsx +0 -96
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "9.0.1-next.6870dfe5b.0",
3
+ "version": "9.0.1-next.a730c9c8c.0",
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",
@@ -46,22 +46,23 @@
46
46
  "dependencies": {
47
47
  "@ariakit/react": "^0.4.15",
48
48
  "@babel/runtime": "7.25.7",
49
- "@wordpress/base-styles": "^6.6.1-next.6870dfe5b.0",
50
- "@wordpress/components": "^30.3.2-next.6870dfe5b.0",
51
- "@wordpress/compose": "^7.30.1-next.6870dfe5b.0",
52
- "@wordpress/data": "^10.30.1-next.6870dfe5b.0",
53
- "@wordpress/date": "^5.30.1-next.6870dfe5b.0",
54
- "@wordpress/element": "^6.30.1-next.6870dfe5b.0",
55
- "@wordpress/i18n": "^6.3.1-next.6870dfe5b.0",
56
- "@wordpress/icons": "^10.30.1-next.6870dfe5b.0",
57
- "@wordpress/keycodes": "^4.30.1-next.6870dfe5b.0",
58
- "@wordpress/primitives": "^4.30.1-next.6870dfe5b.0",
59
- "@wordpress/private-apis": "^1.30.1-next.6870dfe5b.0",
60
- "@wordpress/url": "^4.30.1-next.6870dfe5b.0",
61
- "@wordpress/warning": "^3.30.1-next.6870dfe5b.0",
49
+ "@wordpress/base-styles": "^6.6.1-next.a730c9c8c.0",
50
+ "@wordpress/components": "^30.3.2-next.a730c9c8c.0",
51
+ "@wordpress/compose": "^7.30.1-next.a730c9c8c.0",
52
+ "@wordpress/data": "^10.30.1-next.a730c9c8c.0",
53
+ "@wordpress/date": "^5.30.1-next.a730c9c8c.0",
54
+ "@wordpress/element": "^6.30.1-next.a730c9c8c.0",
55
+ "@wordpress/i18n": "^6.3.1-next.a730c9c8c.0",
56
+ "@wordpress/icons": "^10.30.1-next.a730c9c8c.0",
57
+ "@wordpress/keycodes": "^4.30.1-next.a730c9c8c.0",
58
+ "@wordpress/primitives": "^4.30.1-next.a730c9c8c.0",
59
+ "@wordpress/private-apis": "^1.30.1-next.a730c9c8c.0",
60
+ "@wordpress/url": "^4.30.1-next.a730c9c8c.0",
61
+ "@wordpress/warning": "^3.30.1-next.a730c9c8c.0",
62
62
  "clsx": "^2.1.1",
63
63
  "colord": "^2.7.0",
64
64
  "date-fns": "^4.1.0",
65
+ "deepmerge": "4.3.1",
65
66
  "fast-deep-equal": "^3.1.3",
66
67
  "remove-accents": "^0.5.0"
67
68
  },
@@ -75,5 +76,5 @@
75
76
  "scripts": {
76
77
  "build:wp": "node build"
77
78
  },
78
- "gitHead": "c8637da9df499cd7b6b07c9fad918f6d45f4de3d"
79
+ "gitHead": "85a580bd2c55f811c8969b42dbb10209d19d514e"
79
80
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import deepMerge from 'deepmerge';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -41,6 +46,14 @@ type SamplePost = {
41
46
  address1?: string;
42
47
  address2?: string;
43
48
  city?: string;
49
+ comment_status?: string;
50
+ ping_status?: boolean;
51
+ longDescription?: string;
52
+ origin?: string;
53
+ destination?: string;
54
+ flight_status?: string;
55
+ gate?: string;
56
+ seat?: string;
44
57
  };
45
58
 
46
59
  const fields: Field< SamplePost >[] = [
@@ -79,6 +92,9 @@ const fields: Field< SamplePost >[] = [
79
92
  { value: 3, label: 'Alice' },
80
93
  { value: 4, label: 'Bob' },
81
94
  ],
95
+ setValue: ( { value } ) => ( {
96
+ author: Number( value ),
97
+ } ),
82
98
  },
83
99
  {
84
100
  id: 'reviewer',
@@ -168,6 +184,86 @@ const fields: Field< SamplePost >[] = [
168
184
  label: 'City',
169
185
  type: 'text',
170
186
  },
187
+ {
188
+ id: 'description',
189
+ label: 'Description',
190
+ type: 'text',
191
+ Edit: 'textarea',
192
+ },
193
+ {
194
+ id: 'longDescription',
195
+ label: 'Long Description',
196
+ type: 'text',
197
+ Edit: {
198
+ control: 'textarea',
199
+ rows: 5,
200
+ },
201
+ },
202
+ {
203
+ id: 'comment_status',
204
+ label: 'Comment Status',
205
+ type: 'text',
206
+ Edit: 'radio',
207
+ elements: [
208
+ { value: 'open', label: 'Allow comments' },
209
+ { value: 'closed', label: 'Comments closed' },
210
+ ],
211
+ },
212
+ {
213
+ id: 'ping_status',
214
+ label: 'Allow Pings/Trackbacks',
215
+ type: 'boolean',
216
+ },
217
+ {
218
+ id: 'discussion',
219
+ label: 'Discussion',
220
+ type: 'text',
221
+ render: ( { item } ) => {
222
+ const commentLabel =
223
+ item.comment_status === 'open'
224
+ ? 'Allow comments'
225
+ : 'Comments closed';
226
+ const pingLabel = item.ping_status
227
+ ? 'Pings enabled'
228
+ : 'Pings disabled';
229
+ return (
230
+ <span>
231
+ { commentLabel }, { pingLabel }
232
+ </span>
233
+ );
234
+ },
235
+ },
236
+ {
237
+ id: 'origin',
238
+ label: 'Origin',
239
+ type: 'text',
240
+ },
241
+ {
242
+ id: 'destination',
243
+ label: 'Destination',
244
+ type: 'text',
245
+ },
246
+ {
247
+ id: 'flight_status',
248
+ label: 'Flight Status',
249
+ type: 'text',
250
+ Edit: 'radio',
251
+ elements: [
252
+ { value: 'on-time', label: 'On Time' },
253
+ { value: 'delayed', label: 'Delayed' },
254
+ { value: 'cancelled', label: 'Cancelled' },
255
+ ],
256
+ },
257
+ {
258
+ id: 'gate',
259
+ label: 'Gate',
260
+ type: 'text',
261
+ },
262
+ {
263
+ id: 'seat',
264
+ label: 'Seat',
265
+ type: 'text',
266
+ },
171
267
  ];
172
268
 
173
269
  const LayoutRegularComponent = ( {
@@ -189,6 +285,7 @@ const LayoutRegularComponent = ( {
189
285
  filesize: 1024,
190
286
  dimensions: '1920x1080',
191
287
  tags: [ 'photography' ],
288
+ description: 'This is a sample description.',
192
289
  } );
193
290
 
194
291
  const form: Form = useMemo(
@@ -212,6 +309,8 @@ const LayoutRegularComponent = ( {
212
309
  'filesize',
213
310
  'dimensions',
214
311
  'tags',
312
+ 'description',
313
+ 'longDescription',
215
314
  ],
216
315
  } ),
217
316
  [ labelPosition ]
@@ -300,6 +399,13 @@ const LayoutPanelComponent = ( {
300
399
  address1: '123 Main St',
301
400
  address2: 'Apt 4B',
302
401
  city: 'New York',
402
+ comment_status: 'open',
403
+ ping_status: true,
404
+ origin: 'New York (JFK)',
405
+ destination: 'Los Angeles (LAX)',
406
+ flight_status: 'on-time',
407
+ gate: 'A12',
408
+ seat: '14F',
303
409
  } );
304
410
 
305
411
  const form: Form = useMemo( () => {
@@ -321,11 +427,34 @@ const LayoutPanelComponent = ( {
321
427
  'filesize',
322
428
  'dimensions',
323
429
  'tags',
430
+ {
431
+ id: 'discussion',
432
+ label: 'Discussion',
433
+ children: [ 'comment_status', 'ping_status' ],
434
+ summary: 'discussion',
435
+ },
324
436
  {
325
437
  id: 'address1',
326
438
  label: 'Combined Address',
327
439
  children: [ 'address1', 'address2', 'city' ],
328
440
  },
441
+ {
442
+ id: 'flight_info',
443
+ label: 'Flight Information',
444
+ children: [
445
+ 'origin',
446
+ 'destination',
447
+ 'flight_status',
448
+ 'gate',
449
+ ],
450
+ summary: [ 'origin', 'destination', 'flight_status' ],
451
+ },
452
+ {
453
+ id: 'passenger_details',
454
+ label: 'Passenger Details',
455
+ children: [ 'author', 'seat' ],
456
+ summary: [ 'author', 'seat' ],
457
+ },
329
458
  ],
330
459
  };
331
460
  }, [ labelPosition, openAs ] );
@@ -351,15 +480,13 @@ function CustomEditControl< Item >( {
351
480
  onChange,
352
481
  hideLabelFromVision,
353
482
  }: DataFormControlProps< Item > ) {
354
- const { id, label, placeholder, description } = field;
355
- const value = field.getValue( { item: data } );
483
+ const { label, placeholder, description, getValue, setValue } = field;
484
+ const value = getValue( { item: data } );
356
485
 
357
486
  const onChangeControl = useCallback(
358
487
  ( newValue: string ) =>
359
- onChange( {
360
- [ id ]: newValue,
361
- } ),
362
- [ id, onChange ]
488
+ onChange( setValue( { item: data, value: newValue } ) ),
489
+ [ data, onChange, setValue ]
363
490
  );
364
491
 
365
492
  return (
@@ -388,6 +515,9 @@ const ValidationComponent = ( {
388
515
  } ) => {
389
516
  type ValidatedItem = {
390
517
  text: string;
518
+ select?: string;
519
+ textWithRadio?: string;
520
+ textarea: string;
391
521
  email: string;
392
522
  telephone: string;
393
523
  url: string;
@@ -395,10 +525,16 @@ const ValidationComponent = ( {
395
525
  integer: number;
396
526
  boolean: boolean;
397
527
  customEdit: string;
528
+ password: string;
529
+ toggle?: boolean;
530
+ toggleGroup?: string;
398
531
  };
399
532
 
400
533
  const [ post, setPost ] = useState< ValidatedItem >( {
401
534
  text: 'Can have letters and spaces',
535
+ select: undefined,
536
+ textWithRadio: undefined,
537
+ textarea: 'Can have letters and spaces',
402
538
  email: 'hi@example.com',
403
539
  telephone: '+306978241796',
404
540
  url: 'https://example.com',
@@ -406,6 +542,9 @@ const ValidationComponent = ( {
406
542
  integer: 2,
407
543
  boolean: true,
408
544
  customEdit: 'custom control',
545
+ password: 'secretpassword123',
546
+ toggle: undefined,
547
+ toggleGroup: undefined,
409
548
  } );
410
549
 
411
550
  const customTextRule = ( value: ValidatedItem ) => {
@@ -415,6 +554,29 @@ const ValidationComponent = ( {
415
554
 
416
555
  return null;
417
556
  };
557
+
558
+ const customSelectRule = ( value: ValidatedItem ) => {
559
+ if ( value.select !== 'option1' ) {
560
+ return 'Value must be Option 1.';
561
+ }
562
+ return null;
563
+ };
564
+
565
+ const customTextRadioRule = ( value: ValidatedItem ) => {
566
+ if ( value.textWithRadio !== 'item1' ) {
567
+ return 'Value must be Item 1.';
568
+ }
569
+
570
+ return null;
571
+ };
572
+
573
+ const customTextareaRule = ( value: ValidatedItem ) => {
574
+ if ( ! /^[a-zA-Z ]+$/.test( value.textarea ) ) {
575
+ return 'Value must only contain letters and spaces.';
576
+ }
577
+
578
+ return null;
579
+ };
418
580
  const customEmailRule = ( value: ValidatedItem ) => {
419
581
  if ( ! /^[a-zA-Z0-9._%+-]+@example\.com$/.test( value.email ) ) {
420
582
  return 'Email address must be from @example.com domain.';
@@ -450,6 +612,41 @@ const ValidationComponent = ( {
450
612
 
451
613
  return null;
452
614
  };
615
+ const customBooleanRule = ( value: ValidatedItem ) => {
616
+ if ( value.boolean !== true ) {
617
+ return 'Boolean must be active.';
618
+ }
619
+
620
+ return null;
621
+ };
622
+ const customToggleRule = ( value: ValidatedItem ) => {
623
+ if ( value.toggle !== true ) {
624
+ return 'Toggle must be checked.';
625
+ }
626
+
627
+ return null;
628
+ };
629
+ const customToggleGroupRule = ( value: ValidatedItem ) => {
630
+ if ( value.toggleGroup !== 'option1' ) {
631
+ return 'Value must be Option 1.';
632
+ }
633
+
634
+ return null;
635
+ };
636
+
637
+ const customPasswordRule = ( value: ValidatedItem ) => {
638
+ if ( value.password.length < 8 ) {
639
+ return 'Password must be at least 8 characters long.';
640
+ }
641
+ if ( ! /[A-Z]/.test( value.password ) ) {
642
+ return 'Password must contain at least one uppercase letter.';
643
+ }
644
+ if ( ! /[0-9]/.test( value.password ) ) {
645
+ return 'Password must contain at least one number.';
646
+ }
647
+
648
+ return null;
649
+ };
453
650
 
454
651
  const maybeCustomRule = (
455
652
  rule: ( item: ValidatedItem ) => null | string
@@ -467,6 +664,43 @@ const ValidationComponent = ( {
467
664
  custom: maybeCustomRule( customTextRule ),
468
665
  },
469
666
  },
667
+ {
668
+ id: 'select',
669
+ type: 'text',
670
+ label: 'Select',
671
+ elements: [
672
+ { value: 'option1', label: 'Option 1' },
673
+ { value: 'option2', label: 'Option 2' },
674
+ ],
675
+ isValid: {
676
+ required,
677
+ custom: maybeCustomRule( customSelectRule ),
678
+ },
679
+ },
680
+ {
681
+ id: 'textWithRadio',
682
+ type: 'text',
683
+ Edit: 'radio',
684
+ label: 'Text with radio',
685
+ elements: [
686
+ { value: 'item1', label: 'Item 1' },
687
+ { value: 'item2', label: 'Item 2' },
688
+ ],
689
+ isValid: {
690
+ required,
691
+ custom: maybeCustomRule( customTextRadioRule ),
692
+ },
693
+ },
694
+ {
695
+ id: 'textarea',
696
+ type: 'text',
697
+ Edit: 'textarea',
698
+ label: 'Textarea',
699
+ isValid: {
700
+ required,
701
+ custom: maybeCustomRule( customTextareaRule ),
702
+ },
703
+ },
470
704
  {
471
705
  id: 'email',
472
706
  type: 'email',
@@ -518,6 +752,7 @@ const ValidationComponent = ( {
518
752
  label: 'Boolean',
519
753
  isValid: {
520
754
  required,
755
+ custom: maybeCustomRule( customBooleanRule ),
521
756
  },
522
757
  },
523
758
  {
@@ -528,18 +763,58 @@ const ValidationComponent = ( {
528
763
  required,
529
764
  },
530
765
  },
766
+ {
767
+ id: 'password',
768
+ type: 'password',
769
+ label: 'Password',
770
+ isValid: {
771
+ required,
772
+ custom: maybeCustomRule( customPasswordRule ),
773
+ },
774
+ },
775
+ {
776
+ id: 'toggle',
777
+ type: 'boolean',
778
+ label: 'Toggle',
779
+ Edit: 'toggle',
780
+ isValid: {
781
+ required,
782
+ custom: maybeCustomRule( customToggleRule ),
783
+ },
784
+ },
785
+ {
786
+ id: 'toggleGroup',
787
+ type: 'text',
788
+ label: 'Toggle Group',
789
+ Edit: 'toggleGroup',
790
+ elements: [
791
+ { value: 'option1', label: 'Option 1' },
792
+ { value: 'option2', label: 'Option 2' },
793
+ { value: 'option3', label: 'Option 3' },
794
+ ],
795
+ isValid: {
796
+ required,
797
+ custom: maybeCustomRule( customToggleGroupRule ),
798
+ },
799
+ },
531
800
  ];
532
801
 
533
802
  const form = {
534
803
  layout: { type },
535
804
  fields: [
536
805
  'text',
806
+ 'select',
807
+ 'textWithRadio',
808
+ 'textarea',
537
809
  'email',
538
810
  'telephone',
539
811
  'url',
540
812
  'color',
541
813
  'integer',
542
814
  'boolean',
815
+ 'toggle',
816
+ 'toggleGroup',
817
+ 'password',
543
818
  'customEdit',
544
819
  ],
545
820
  };
@@ -1122,17 +1397,6 @@ const meta = {
1122
1397
  };
1123
1398
  export default meta;
1124
1399
 
1125
- export const Default = {
1126
- render: LayoutRegularComponent,
1127
- argTypes: {
1128
- type: {
1129
- control: { type: 'select' },
1130
- description: 'Chooses the layout type.',
1131
- options: [ 'default', 'card', 'panel', 'regular' ],
1132
- },
1133
- },
1134
- };
1135
-
1136
1400
  export const LayoutCard = {
1137
1401
  render: LayoutCardComponent,
1138
1402
  argTypes: {
@@ -1218,3 +1482,211 @@ export const Validation = {
1218
1482
  export const Visibility = {
1219
1483
  render: VisibilityComponent,
1220
1484
  };
1485
+
1486
+ const DataAdapterComponent = () => {
1487
+ type DataAdapterItem = {
1488
+ user: {
1489
+ profile: {
1490
+ name: string;
1491
+ email: string;
1492
+ };
1493
+ preferences: {
1494
+ notifications: boolean;
1495
+ };
1496
+ };
1497
+ revenue: {
1498
+ total: number;
1499
+ units: number;
1500
+ pricePerUnit: number;
1501
+ };
1502
+ };
1503
+
1504
+ const [ data, setData ] = useState< DataAdapterItem >( {
1505
+ user: {
1506
+ profile: {
1507
+ name: 'John Doe',
1508
+ email: 'john@example.com',
1509
+ },
1510
+ preferences: {
1511
+ notifications: true,
1512
+ },
1513
+ },
1514
+ revenue: {
1515
+ total: 30,
1516
+ units: 10,
1517
+ pricePerUnit: 3,
1518
+ },
1519
+ } );
1520
+
1521
+ const nestedFields: Field< DataAdapterItem >[] = [
1522
+ // Examples of autogenerated getValue/setValue methods
1523
+ // for nested data based on the field id.
1524
+ {
1525
+ id: 'user.profile.name',
1526
+ label: 'User Name',
1527
+ type: 'text',
1528
+ },
1529
+ {
1530
+ id: 'user.profile.email',
1531
+ label: 'User Email',
1532
+ type: 'email',
1533
+ },
1534
+ // Example of adapting a data value to a control value
1535
+ // by providing getValue/setValue methods.
1536
+ {
1537
+ id: 'user.preferences.notifications',
1538
+ label: 'Notifications',
1539
+ type: 'boolean',
1540
+ Edit: 'radio',
1541
+ elements: [
1542
+ { label: 'Enabled', value: 'enabled' },
1543
+ { label: 'Disabled', value: 'disabled' },
1544
+ ],
1545
+ getValue: ( { item } ) =>
1546
+ item.user.preferences.notifications === true
1547
+ ? 'enabled'
1548
+ : 'disabled',
1549
+ setValue: ( { value } ) => ( {
1550
+ user: {
1551
+ preferences: { notifications: value === 'enabled' },
1552
+ },
1553
+ } ),
1554
+ },
1555
+ // Example of deriving data by leveraging setValue method.
1556
+ {
1557
+ id: 'revenue.total',
1558
+ label: 'Total Revenue',
1559
+ type: 'integer',
1560
+ readOnly: true,
1561
+ },
1562
+ {
1563
+ id: 'revenue.pricePerUnit',
1564
+ label: 'Price Per Unit',
1565
+ type: 'integer',
1566
+ setValue: ( { item, value } ) => ( {
1567
+ revenue: {
1568
+ total: value * item.revenue.units,
1569
+ pricePerUnit: value,
1570
+ },
1571
+ } ),
1572
+ },
1573
+ {
1574
+ id: 'revenue.units',
1575
+ label: 'Units',
1576
+ type: 'integer',
1577
+ setValue: ( { item, value } ) => ( {
1578
+ revenue: {
1579
+ total: item.revenue.pricePerUnit * value,
1580
+ units: value,
1581
+ },
1582
+ } ),
1583
+ },
1584
+ ];
1585
+
1586
+ const handleChange = useCallback( ( edits: any ) => {
1587
+ // Edits will respect the shape of the data
1588
+ // because fields provide the proper information
1589
+ // (via field.id or via field.setValue).
1590
+ setData( ( prev ) => deepMerge( prev, edits ) );
1591
+ }, [] );
1592
+
1593
+ return (
1594
+ <>
1595
+ <h1>Data adapter</h1>
1596
+ <p>
1597
+ This story is best looked at with the code on the side. It aims
1598
+ to highlight how DataForm can wrangle data in scenarios such as
1599
+ nested data, bridge data to/from UI controls, and derived data.
1600
+ </p>
1601
+ <p>
1602
+ <b>Current data snapshot:</b>
1603
+ </p>
1604
+ <pre>{ JSON.stringify( data, null, 2 ) }</pre>
1605
+ <h2>Nested data</h2>
1606
+ <p>
1607
+ The first example demonstrates how to signal nested data via{ ' ' }
1608
+ <code>field.id</code>.
1609
+ </p>
1610
+ <p>
1611
+ By using <code>{ `{ id: 'user.profile.name' }` }</code> as field
1612
+ id, when users edit the name, the edits will come in this shape:
1613
+ <code>{ `{ user: { profile: { name: 'John Doe' } } }` }</code>
1614
+ </p>
1615
+ <DataForm< DataAdapterItem >
1616
+ data={ data }
1617
+ fields={ nestedFields }
1618
+ form={ {
1619
+ layout: {
1620
+ type: 'panel',
1621
+ labelPosition: 'top',
1622
+ openAs: 'modal',
1623
+ },
1624
+ fields: [
1625
+ {
1626
+ id: 'userProfile',
1627
+ label: 'User Profile',
1628
+ children: [
1629
+ 'user.profile.name',
1630
+ 'user.profile.email',
1631
+ ],
1632
+ },
1633
+ ],
1634
+ } }
1635
+ onChange={ handleChange }
1636
+ />
1637
+ <h2>Adapt data and UI control</h2>
1638
+ <p>
1639
+ Sometimes, we need to adapt the data type to and from the UI
1640
+ control response. This example demonstrates how to adapt a
1641
+ boolean to a text string (Enabled/Disabled).
1642
+ </p>
1643
+ <DataForm< DataAdapterItem >
1644
+ data={ data }
1645
+ fields={ nestedFields }
1646
+ form={ {
1647
+ layout: {
1648
+ type: 'panel',
1649
+ labelPosition: 'top',
1650
+ openAs: 'modal',
1651
+ },
1652
+ fields: [ 'user.preferences.notifications' ],
1653
+ } }
1654
+ onChange={ handleChange }
1655
+ />
1656
+ <h2>Derived data</h2>
1657
+ <p>
1658
+ Last, but not least, this example showcases how to work with
1659
+ derived data by providing a custom setValue function. Note how,
1660
+ changing UNITS or PRICE PER UNIT, updates the TOTAL value as
1661
+ well.
1662
+ </p>
1663
+ <DataForm< DataAdapterItem >
1664
+ data={ data }
1665
+ fields={ nestedFields }
1666
+ form={ {
1667
+ layout: {
1668
+ type: 'panel',
1669
+ labelPosition: 'top',
1670
+ openAs: 'modal',
1671
+ },
1672
+ fields: [
1673
+ {
1674
+ id: 'revenue',
1675
+ label: 'Revenue',
1676
+ children: [
1677
+ 'revenue.pricePerUnit',
1678
+ 'revenue.units',
1679
+ 'revenue.total',
1680
+ ],
1681
+ },
1682
+ ],
1683
+ } }
1684
+ onChange={ handleChange }
1685
+ />
1686
+ </>
1687
+ );
1688
+ };
1689
+
1690
+ export const DataAdapter = {
1691
+ render: DataAdapterComponent,
1692
+ };