blixify-ui-web-mcp 0.1.3 → 0.1.19

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 (168) hide show
  1. package/lib/components/action/button/README.md +12 -11
  2. package/lib/components/action/button/button.stories.tsx +38 -27
  3. package/lib/components/action/buttonGroup/buttonGroup.stories.tsx +82 -16
  4. package/lib/components/action/iconButton/README.md +1 -0
  5. package/lib/components/action/iconButton/iconButton.stories.tsx +6 -12
  6. package/lib/components/action/radioList/radioList.stories.tsx +10 -16
  7. package/lib/components/action/slider/slider.stories.tsx +9 -15
  8. package/lib/components/action/textButton/textButton.stories.tsx +6 -12
  9. package/lib/components/action/toggle/toggle.stories.tsx +6 -12
  10. package/lib/components/advanced/collapse/collapse.stories.tsx +240 -24
  11. package/lib/components/advanced/infoWindow/infoWindow.stories.tsx +10 -16
  12. package/lib/components/advanced/popUp/README.md +33 -7
  13. package/lib/components/advanced/popUp/popUp.stories.tsx +9 -15
  14. package/lib/components/auth/bareSignIn/bareSignIn.stories.tsx +36 -16
  15. package/lib/components/auth/bareSignUp/bareSignUp.stories.tsx +7 -13
  16. package/lib/components/auth/signIn/signIn.stories.tsx +4 -10
  17. package/lib/components/auth/signUp/signUp.stories.tsx +4 -10
  18. package/lib/components/chart/areaChart/areaChart.stories.tsx +12 -18
  19. package/lib/components/chart/barChart/barChart.stories.tsx +12 -18
  20. package/lib/components/chart/boxPlotChart/boxPlotChart.stories.tsx +11 -17
  21. package/lib/components/chart/bubbleChart/bubbleChart.stories.tsx +11 -17
  22. package/lib/components/chart/card/card.stories.tsx +172 -38
  23. package/lib/components/chart/ganttChart/ganttChart.stories.tsx +10 -16
  24. package/lib/components/chart/heatmapChart/heatmapChart.stories.tsx +11 -17
  25. package/lib/components/chart/lineChart/lineChart.stories.tsx +8 -14
  26. package/lib/components/chart/pieChart/pieChart.stories.tsx +11 -17
  27. package/lib/components/chart/polarAreaChart/polarAreaChart.stories.tsx +11 -17
  28. package/lib/components/chart/radarChart/radarChart.stories.tsx +6 -12
  29. package/lib/components/chart/radialBar/radialChart.stories.tsx +4 -10
  30. package/lib/components/chart/rangeBarChart/rangeBarChart.stories.tsx +8 -14
  31. package/lib/components/chart/statsCard/statsCard.stories.tsx +12 -18
  32. package/lib/components/chart/treemapChart/treemapChart.stories.tsx +11 -17
  33. package/lib/components/chat/chatAnchor/README.md +7 -0
  34. package/lib/components/chat/chatAnchor/chatAnchor.stories.tsx +15 -21
  35. package/lib/components/chat/chatBase/README.md +103 -22
  36. package/lib/components/chat/chatBase/chatBase.stories.tsx +657 -57
  37. package/lib/components/chat/chatDashboard/README.md +17 -15
  38. package/lib/components/chat/chatDashboard/chatDashboard.stories.tsx +358 -46
  39. package/lib/components/data/dataGraph/dataGraph.stories.tsx +8 -14
  40. package/lib/components/data/dataReference/dataReference.stories.tsx +9 -15
  41. package/lib/components/data/dataTemplate/README.md +443 -129
  42. package/lib/components/data/dataTemplate/dataModule.stories.tsx +10 -15
  43. package/lib/components/data/dataTemplate/dataTemplate.stories.tsx +20 -34
  44. package/lib/components/data/dataWrapper/README.md +207 -84
  45. package/lib/components/data/dataWrapper/dataWrapper.consumer.stories.tsx +2125 -0
  46. package/lib/components/data/dataWrapper/dataWrapper.edit.stories.tsx +607 -0
  47. package/lib/components/data/dataWrapper/dataWrapper.utils.stories.tsx +576 -0
  48. package/lib/components/data/dataWrapper/dataWrapper.view.stories.tsx +1273 -0
  49. package/lib/components/data/flexFilter/flexFilter.stories.tsx +171 -0
  50. package/lib/components/data/queryForm/queryForm.stories.tsx +6 -12
  51. package/lib/components/data/readQuery/readQuery.stories.tsx +6 -11
  52. package/lib/components/data/readQueryHoc/readQueryHoc.stories.tsx +6 -12
  53. package/lib/components/data/writeQuery/README.md +21 -10
  54. package/lib/components/data/writeQuery/writeQuery.stories.tsx +6 -10
  55. package/lib/components/design/actionSection/actionSection.stories.tsx +10 -14
  56. package/lib/components/design/banner/banner.stories.tsx +6 -12
  57. package/lib/components/design/bannerAction/bannerAction.stories.tsx +100 -21
  58. package/lib/components/design/blogSection/blogSection.stories.tsx +6 -12
  59. package/lib/components/design/carouselSection/carouselSection.stories.tsx +6 -12
  60. package/lib/components/design/designList/designList.stories.tsx +6 -12
  61. package/lib/components/design/faq/faq.stories.tsx +53 -31
  62. package/lib/components/design/fileGrid/fileGrid.stories.tsx +10 -16
  63. package/lib/components/design/fileViewer/fileViewer.stories.tsx +6 -12
  64. package/lib/components/design/footerSection/footerSection.stories.tsx +6 -12
  65. package/lib/components/design/googleReview/googleReview.stories.tsx +6 -12
  66. package/lib/components/design/heroSection/heroSection.stories.tsx +10 -16
  67. package/lib/components/design/iconList/iconList.stories.tsx +6 -12
  68. package/lib/components/design/imageGallery/imageGallery.stories.tsx +6 -12
  69. package/lib/components/design/imageZoom/imageZoom.stories.tsx +6 -12
  70. package/lib/components/design/leftContent/leftContent.stories.tsx +6 -12
  71. package/lib/components/design/logoCloud/logoCloud.stories.tsx +6 -12
  72. package/lib/components/design/onboarding/onboarding.stories.tsx +8 -14
  73. package/lib/components/design/pricing/pricing.stories.tsx +6 -12
  74. package/lib/components/design/rightContent/rightContent.stories.tsx +6 -12
  75. package/lib/components/design/sectionList/sectionList.stories.tsx +6 -12
  76. package/lib/components/design/teams/teams.stories.tsx +6 -12
  77. package/lib/components/display/alert/alert.stories.tsx +8 -14
  78. package/lib/components/display/calendar/README.md +49 -0
  79. package/lib/components/display/calendar/calendar.stories.tsx +78 -35
  80. package/lib/components/display/clipboard/clipboard.stories.tsx +6 -12
  81. package/lib/components/display/detailList/detailList.stories.tsx +172 -48
  82. package/lib/components/display/drawer/README.md +44 -11
  83. package/lib/components/display/drawer/drawer.stories.tsx +71 -16
  84. package/lib/components/display/emptyState/emptyState.stories.tsx +47 -15
  85. package/lib/components/display/feeds/feeds.stories.tsx +6 -12
  86. package/lib/components/display/flexTable/README.md +11 -7
  87. package/lib/components/display/flexTable/flexTable.stories.tsx +318 -20
  88. package/lib/components/display/grid/README.md +29 -30
  89. package/lib/components/display/grid/grid.stories.tsx +16 -23
  90. package/lib/components/display/kanban/kanban.stories.tsx +17 -23
  91. package/lib/components/display/list/README.md +30 -29
  92. package/lib/components/display/list/list.stories.tsx +11 -17
  93. package/lib/components/display/loading/loading.stories.tsx +7 -12
  94. package/lib/components/display/mapView/mapView.stories.tsx +9 -15
  95. package/lib/components/display/modal/modal.stories.tsx +6 -13
  96. package/lib/components/display/newCalendar/README.md +163 -0
  97. package/lib/components/display/newCalendar/newCalendar.stories.tsx +292 -0
  98. package/lib/components/display/newFeeds/README.md +53 -0
  99. package/lib/components/display/newFeeds/newFeeds.stories.tsx +104 -0
  100. package/lib/components/display/newKanban/README.md +25 -0
  101. package/lib/components/display/newKanban/newKanban.stories.tsx +131 -0
  102. package/lib/components/display/newList/README.md +30 -0
  103. package/lib/components/display/newList/newList.stories.tsx +231 -0
  104. package/lib/components/display/newPagination/README.md +15 -0
  105. package/lib/components/display/newTable/README.md +121 -0
  106. package/lib/components/display/newTable/newTable.stories.tsx +551 -0
  107. package/lib/components/display/notification/notification.stories.tsx +6 -12
  108. package/lib/components/display/progress/progress.stories.tsx +7 -12
  109. package/lib/components/display/stepper/README.md +4 -0
  110. package/lib/components/display/stepper/stepper.stories.tsx +70 -23
  111. package/lib/components/display/table/README.md +38 -37
  112. package/lib/components/display/table/table.stories.tsx +34 -36
  113. package/lib/components/display/tag/tag.stories.tsx +34 -40
  114. package/lib/components/input/address/address.stories.tsx +12 -18
  115. package/lib/components/input/canvas/canvas.stories.tsx +12 -18
  116. package/lib/components/input/checkbox/checkbox.stories.tsx +7 -13
  117. package/lib/components/input/datePicker/datePicker.stories.tsx +41 -11
  118. package/lib/components/input/form/form.stories.tsx +11 -17
  119. package/lib/components/input/markdown/README.md +80 -2
  120. package/lib/components/input/markdown/markdown.stories.tsx +83 -32
  121. package/lib/components/input/monthYearPicker/monthYearPicker.stories.tsx +52 -24
  122. package/lib/components/input/netPromoterScore/netPromoterScore.stories.tsx +6 -12
  123. package/lib/components/input/rating/rating.stories.tsx +6 -12
  124. package/lib/components/input/select/README.md +31 -29
  125. package/lib/components/input/select/select.stories.tsx +33 -39
  126. package/lib/components/input/signature/signature.stories.tsx +12 -18
  127. package/lib/components/input/textArea/textArea.stories.tsx +6 -12
  128. package/lib/components/input/textInput/textinput.stories.tsx +14 -20
  129. package/lib/components/input/uploadInput/uploadInput.stories.tsx +143 -19
  130. package/lib/components/navigation/bars/README.md +27 -0
  131. package/lib/components/navigation/bars/bars.stories.tsx +56 -19
  132. package/lib/components/navigation/bottomTab/bottomTab.stories.tsx +7 -12
  133. package/lib/components/navigation/breadcrumb/breadcrumb.stories.tsx +8 -14
  134. package/lib/components/navigation/header/header.stories.tsx +33 -21
  135. package/lib/components/navigation/leftNav/leftNav.stories.tsx +10 -16
  136. package/lib/components/navigation/tabs/tabs.stories.tsx +10 -16
  137. package/lib/components/structure/column/column.stories.tsx +10 -15
  138. package/lib/components/structure/container/container.stories.tsx +8 -13
  139. package/lib/components/structure/link/link.stories.tsx +11 -17
  140. package/lib/components/structure/text/text.stories.tsx +12 -17
  141. package/lib/components/template/authPage/authPage.stories.tsx +6 -5
  142. package/lib/components/template/calendarView/calendarView.stories.tsx +726 -0
  143. package/lib/components/template/chatDashboard/chatDashboard.stories.tsx +497 -0
  144. package/lib/components/template/landingPage/landingPage.stories.tsx +10 -7
  145. package/lib/components/template/mapLayout/mapLayout.stories.tsx +519 -0
  146. package/lib/components/template/productListing/productListing.stories.tsx +7 -13
  147. package/lib/components/template/productOverview/productOverview.stories.tsx +5 -11
  148. package/lib/components/template/shoppingCart/shoppingCart.stories.tsx +6 -12
  149. package/lib/components/template/userHomePage/userHomePage.stories.tsx +384 -524
  150. package/lib/components/template/userRankingDashboard/userRankingDashboard.stories.tsx +145 -75
  151. package/lib/mcp/tools/componentsRoot.d.ts +2 -0
  152. package/lib/mcp/tools/componentsRoot.d.ts.map +1 -0
  153. package/lib/mcp/tools/componentsRoot.js +59 -0
  154. package/lib/mcp/tools/componentsRoot.js.map +1 -0
  155. package/lib/mcp/tools/getBackendComponent.d.ts.map +1 -1
  156. package/lib/mcp/tools/getBackendComponent.js +2 -5
  157. package/lib/mcp/tools/getBackendComponent.js.map +1 -1
  158. package/lib/mcp/tools/getComponent.d.ts.map +1 -1
  159. package/lib/mcp/tools/getComponent.js +2 -5
  160. package/lib/mcp/tools/getComponent.js.map +1 -1
  161. package/lib/mcp/tools/listComponents.d.ts.map +1 -1
  162. package/lib/mcp/tools/listComponents.js +15 -10
  163. package/lib/mcp/tools/listComponents.js.map +1 -1
  164. package/lib/mcp/tools/suggestTemplate.d.ts.map +1 -1
  165. package/lib/mcp/tools/suggestTemplate.js +107 -21
  166. package/lib/mcp/tools/suggestTemplate.js.map +1 -1
  167. package/package.json +1 -1
  168. package/lib/components/data/dataWrapper/dataWrapper.stories.tsx +0 -831
@@ -40,6 +40,177 @@ The `model` prop defines the columns/fields. You can build it manually as a `Dat
40
40
 
41
41
  ---
42
42
 
43
+ ### Layout: tabs, sections and extended tabs
44
+
45
+ Three schema-level settings shape how a record is laid out. They nest in one fixed order:
46
+
47
+ ```
48
+ Tab (DataStructure.tabId) ← tab bar across the top of the read + update views
49
+ └─ Section (DataStructure.groupId) ← titled card inside the tab; collapsible in the form
50
+ └─ fields ← an object / listObject field renders as a nested
51
+ block or table INSIDE its section — it is a field,
52
+ not a further structural level
53
+ ```
54
+
55
+ - Columns with a `tabId` but no `groupId` sit directly under the tab; columns with
56
+ neither land in an automatic **Others** tab. Order follows the schema.
57
+ - `extendedTabs` is a different thing: extra **list** views (grid / calendar / kanban /
58
+ map / report / iframe) rendered as tabs next to the main list — see Extended Tab below.
59
+ It never appears on a single record.
60
+ - `organise.groupBy` is different again: it splits the **list** into one table per value
61
+ of a column ("Group By X"), and has nothing to do with `groupId`.
62
+
63
+ **How a tabbed form is dressed** (`tabAlign: "left"`):
64
+
65
+ - The rail is a numbered `Stepper` (`variant="checklist"`) — the active step is a filled primary block, and a
66
+ step whose required fields are all filled shows a tick instead of its number.
67
+ - Each tab's fields open with the tab name and, when `organise.tabDescriptions[tabId]`
68
+ is set, a one-line description. A horizontal stepper (`tabAlign: "stepper"`) shows
69
+ `organise.tabShortLabels[tabId]` under each dot on a phone (the tab id itself stays the
70
+ only key); without short labels only the active step keeps its name there. Each section is a white card with its title and, when
71
+ `organise.groupDescriptions[groupId]` is set, its own description. The library never
72
+ paints the page background — the host does (Space uses grey), the cards sit on it.
73
+ - **Every update form and every read view** ends in a sticky, single-row floating bar
74
+ carrying its actions — Save · Submit on the form, Update (or the app's own component),
75
+ Export PDF and Log on the read view; a tabbed form adds the navigation cluster to it.
76
+ The bar's left is reserved for the step navigation; the actions group on the right,
77
+ Delete first (an icon on phones), then Save · Submit / Export PDF · Log · Update. The
78
+ header keeps only the title. Success toasts clear themselves after 4 s and, on phones,
79
+ appear at the bottom lifted above the bar. It is the form's only action bar —
80
+ a floating pill (rounded, shadow, lifted off the bottom edge, stretched into the page
81
+ margin on phones), 60 px tall on desktop and phone. Left cluster is navigation —
82
+ `‹ Previous · Step x of y · Next ›` (icons and `x/y` on a phone); Next moves to the
83
+ next tab, saving a draft silently first when `bareSaveOnTabChange` is on, and is
84
+ disabled on the last tab. Right cluster is actions — `Save · Submit`; Submit is
85
+ reachable on every step and is the one filled (primary) button. The header row keeps only Delete. `bareUpdateActionComponent`, when
86
+ set, takes the place of Save / Submit (navigation stays); return an empty fragment to
87
+ hide the library's buttons — the bar is then dropped on a plain form and keeps only its
88
+ navigation on a tabbed one. `bareUpdateActionBottom` swaps the pill for a plain
89
+ right-aligned row (same buttons, no border / shadow / sticky) — use it for short forms
90
+ inside a `Modal`, where the pill would be a card inside a card. Inside a `Modal` without
91
+ `overflowScroll` the panel is `overflow-hidden`, so the pill sits at the end of the form
92
+ instead of floating.
93
+ - `listObject` tables inside the form render their inputs in cell mode (16 px text,
94
+ low padding) so a checklist row is ~44 px, the same as an editable list row.
95
+
96
+ **Saving: create, update, drafts, auto-save**
97
+
98
+ - `id="new"` (or no id) → **create**; any other id → **update** of that record. The toast says
99
+ "Created Successfully" / "Updated Successfully"; with `enableUpdateDraft` a draft save
100
+ says "Draft Saved" instead.
101
+ - `edit.enableUpdateDraft: true` adds **Save** (draft, `baseDraft: true`) next to Submit.
102
+ - `bareSettings.bareSaveOnTabChange: true` is the **auto-save**: Next / Previous write a draft
103
+ before moving, silently. Only an explicit Save or Submit shows a toast.
104
+ - `bareSettings.bareUpsertPartialUpdate: true` turns the update into an upsert by id that sends
105
+ only the changed fields, and **skips the write when nothing changed** — so a Next on an
106
+ untouched tab costs no request. Without it every save writes the full record and toasts,
107
+ changed or not.
108
+ The API behind the collection must accept a partial document (an upsert by id that
109
+ `$set`s only the sent fields) — Verdant's `mongoData` route does; check before turning it
110
+ on elsewhere.
111
+
112
+ **Offline mode** (`bareOffline`, the Meraque work-order checklist pattern)
113
+
114
+ ```
115
+ mount (online) ─▶ prefetch latest N docs + bareOfflineReferences ─▶ IndexedDB store "local"
116
+ key = collectionId
117
+ save ─▶ online → server (with bareOfflineNetworkListener)
118
+ ─▶ offline → IndexedDB, stamped { baseOnline:false, syncStatus:"pending", dirtySections }
119
+ ref.handleUploadOfflineData() ─▶ every pending doc → server (diffed against the baseline it was
120
+ loaded with, 300 ms apart) ─▶ marked synced
121
+ ```
122
+
123
+ - The DTW does the prefetch, the local reads, the local writes and the upload; the app owns the
124
+ _policy_: when to go offline, when to sync, what to tell the user. Meraque keeps an `offline`
125
+ state, shows a banner ("Going offline? Sync data required…" / "You're in offline mode." /
126
+ "Data synced. Ready for offline."), passes `bareOffline: offline`, and calls
127
+ `dtwRef.current.handleUploadOfflineData()` when the connection is back.
128
+ - Prefetch never overwrites pending local edits — pending docs win over the server copy of the
129
+ same id. Reference collections listed in `bareOfflineReferences` are what make reference
130
+ fields (team, pilot, robot…) selectable with no network.
131
+ - Story: `Data / Data Wrapper / Consumer Fixtures / Meraque · Work Order (Offline)` — prefetch,
132
+ an offline toggle, an offline save and Sync now, all mocked in the page.
133
+ - This is a feature, not a test harness — stories fake the server with `axios-mock-adapter`
134
+ instead (see the Consumer Fixtures file).
135
+
136
+ **Dark mode** — `organise.darkMode: true` darkens everything DataTemplate renders: list
137
+ chrome, tables and lists, the update form's section cards and **every input's field** (not
138
+ just its label — text, textarea, select and its dropdown, date, checkbox and radio boxes),
139
+ the read view's cards, modals, the drawer, toasts and the floating action bar. Pass
140
+ `organise.darkModeBg` with the class your page already uses (`"bg-neutral-900"`) and those
141
+ surfaces adopt it; without it they fall back to `bg-gray-900`. Story: `Consumer Fixtures /
142
+ Dark Mode` (Sales Leads list + KPJ form on a Meraque-style page).
143
+
144
+ **Wide tables** — every table scrolls inside a `ScrollShadow`: a soft fade on the edge
145
+ that still hides columns, gone at the end of the scroll, over a thin always-visible
146
+ scrollbar. `listObject` tables inside a form also pin their first column
147
+ (`FlexTable pinColumns`, the same `{ left, right }` shape as `NewTable`) so the row label stays put.
148
+
149
+ **Sheet habits in `NewTable`** (`bareNewDTW`):
150
+
151
+ - A `list` column with `listSelectionColour` paints the whole cell in the value's
152
+ colour with contrasting text; in an editable table one tap on it enters the row's inline
153
+ edit and opens that cell's ordinary `Select`, its options in the same colours — picking one
154
+ commits a single update. Colour keys are the Tag palette (`red`, `blue`, `green`, `yellow`, `indigo`,
155
+ `dark`, `default`).
156
+ In a read-only table (`listEditable` off — the wrapper default) that cell is the same
157
+ filled `Select` an editable table shows, just disabled, so it looks identical in both modes
158
+ and the row click still opens the record.
159
+ - `organise.groupBy` keeps rows in **one** table: each group is a tinted, collapsible band
160
+ (chevron, title, count) in the grouping column's colour, and its rows carry the same
161
+ colour as a bar down their left edge. Legacy `Table` keeps the separate-tables layout.
162
+ - Row selection gains **Shift-click** (extend from the last clicked row), **drag** down
163
+ the checkbox column (paint a range), **Esc** (clear), and a **Copy** action on the
164
+ floating bar that writes the selected rows' visible columns as TSV to the clipboard
165
+ (`enableCopy={false}` hides it).
166
+
167
+ **Field polish** — a `list` shown as radios (`listView: "radioview"`) with more than six
168
+ options lays out in two columns; a `boolean` with `enableRadioButtons` renders as
169
+ Yes / No pills; `TextInput` / `TextArea` show a character counter whenever `maxLength`
170
+ is set.
171
+
172
+ None of these carry a colour of their own. Everything coloured follows the theme's
173
+ primary: the active tab's underline (`border-primary-500 text-primary-600`) and, in the
174
+ update form only, the light `bg-primary-50` tint behind a collapsible section. Read-view
175
+ section cards are plain white. Per-value colour exists only on `list` / `multipleList`
176
+ columns via `listSelectionColour`.
177
+
178
+ A worked example is Blixify Space's KPJ **Projects** space: every column carries a lettered
179
+ `tabId` (`A. Research Identification` … `P. Applicant Endorsement`) plus a `groupId`
180
+ (`Research Details`, `Application Details`, …), and its `kpjuResearchers` listObject shows
181
+ as a nested table inside the _Applicants' Details_ section.
182
+
183
+ ## View Settings
184
+
185
+ One panel behind the sliders icon carries every list-view setting — it replaces the old
186
+ Slice Data, Model Overview and Sort modals and the desktop-only header drag.
187
+
188
+ | Section | What it does |
189
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
190
+ | Columns | search the column list, drag a handle to reorder, eye / eye-slash to hide. The last visible column stays locked so the table always has a header |
191
+ | Sort | pick the column and the direction — the only sort UI on a phone, where the table renders cards with no headers |
192
+ | Rows per page | 10 / 25 / 50 / 100, persisted with the rest of the view state |
193
+
194
+ The column list is the only scrolling region (capped height with a `ScrollShadow`), so Sort
195
+ and Rows per page stay in view on a collection with dozens of fields. Desktop opens a
196
+ popover; a phone opens a modal, since the popover cannot fit the panel inside the viewport.
197
+
198
+ The panel is standard under `bareNewDTW`; `bareSettings.bareViewSettings` opts a legacy or bare
199
+ DTW into it. There are no separate sort / filter / drag flags — the feature carries all three,
200
+ and per-column filtering comes from `bareFlexFilters`.
201
+
202
+ The table header carries the same actions for the column you are pointing at: sort, and a hide
203
+ button revealed on hover so a wide header stays clean (the sort icon stays visible because it
204
+ also reports the current sort). Reordering has no icon — the header shows a grab cursor and
205
+ the panel carries an explicit handle. Both run the same
206
+ reorder and hide as the panel, so the result persists identically whichever one is used. The
207
+ panel remains the only surface on a phone, where the card view has no headers.
208
+
209
+ Hide and reorder are **per user** by default, kept in `persistViewState`. Wire
210
+ `organise.onChangeHide` / `organise.onChangeDrag` and the panel switches to **schema mode**:
211
+ the change is written to the model and handed to the consumer to persist for everyone — which
212
+ is what a Space-backed DTW wants.
213
+
43
214
  ## Step-by-Step Setup
44
215
 
45
216
  **1. Install peer dependencies**
@@ -98,7 +269,7 @@ Or derive it from a Workspace object:
98
269
  import { parseWorkspaceSettings } from "blixify-ui-web/data/utils";
99
270
  const devSettings = parseWorkspaceSettings(
100
271
  { dbEndpoint, imageEndpoint, uploadEndpoint },
101
- workspaceObject
272
+ workspaceObject,
102
273
  );
103
274
  ```
104
275
 
@@ -108,7 +279,7 @@ const devSettings = parseWorkspaceSettings(
108
279
  const handleNavigate = (
109
280
  nextType: string,
110
281
  selectedId?: string,
111
- nextViewId?: string
282
+ nextViewId?: string,
112
283
  ) => {
113
284
  setType(nextType);
114
285
  if (selectedId !== undefined) setId(selectedId);
@@ -241,6 +412,8 @@ Set `organise.viewId="calendar"` and add an `extendedTabs` entry with `calendarS
241
412
 
242
413
  ### Grid view
243
414
 
415
+ Under `bareNewDTW` the grid hides `Grid`'s own page buttons and renders the same `NewPagination` footer as the table and list views.
416
+
244
417
  Set `organise.viewId="grid"` (or add an `extendedTabs` entry with `viewType="grid"`) to render records as image cards. Use `bareSettings.bareListGridComponent` to fully customise each card, or use the built-in grid with `viewImage` pointing to an image column.
245
418
 
246
419
  ```tsx
@@ -335,6 +508,8 @@ Set `organise.viewId="list"` to render records as a vertical list instead of a t
335
508
 
336
509
  ### Kanban view
337
510
 
511
+ On phones (`bareListMobileView`) the columns become a tab rail with one column visible; the first column is selected as soon as data arrives, and cards move by long-press onto another tab. Cards, rail and columns follow `organise.darkMode`.
512
+
338
513
  Set `viewType="kanban"` on an `extendedTabs` entry and configure `kanbanSettings` to define which column drives the board columns. `title` is the column ID shown on each card; `groupCluster` maps column names to the list-selection values that belong in that column.
339
514
 
340
515
  ```tsx
@@ -536,6 +711,27 @@ Enable `organise.exportSettings.enableExportReadPDF` to add a PDF export button
536
711
 
537
712
  ---
538
713
 
714
+ ## Stacking (z-index) Layers
715
+
716
+ The layers every DataTemplate surface stacks in, lowest to highest. Anything that floats
717
+ must sit above the sticky action bar (`z-20`) and below overlays/modals.
718
+
719
+ | Layer | Components |
720
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
721
+ | `z-0` – `z-10` | In-flow accents: sticky table headers / pinned columns (`z-10`–`z-20` in FlexTable), stepper rail, grid/list image overlays, modal sticky title (`z-10`) |
722
+ | `z-20` | **DataTemplate sticky action bar** (form + read view), stepper connectors, date-picker mobile overlay |
723
+ | `z-30` | Floating pieces that must clear the action bar: **Select option list**, `PopUp` panels (filters, ⋮ menu, select-all), drawer root, page `Header` / `BottomTab` / `LeftNav`, legacy list/table popovers |
724
+ | `z-[35]` | Drawer sticky header (above its own content, below a Modal) |
725
+ | `z-40` | **Modal** (overlay + panel) — deliberately above the drawer (`z-30`) so a modal opened from a drawer wins |
726
+ | `z-50` | Toasts (**Notification**), calendar day popup, kanban drag ghost, row hover tooltips, markdown editor menus, onboarding |
727
+ | `z-[51]` | Stepper description popover (above toasts so it stays readable) |
728
+ | `z-[100]` | DataTemplate fixed utilities: offline sync badge, scroll-to-top |
729
+ | `z-[9999]` | App-level attention layers: `Bars` celebration overlay, `InfoWindow` |
730
+
731
+ Rules of thumb: a dropdown or popover opened from inside the form → `z-30`; anything modal →
732
+ `z-40`; transient feedback (toast, drag ghost, tooltip) → `z-50`; never introduce a new value
733
+ without placing it in this table.
734
+
539
735
  ## Utility Functions
540
736
 
541
737
  ### `parseSpaceToDataStructure(space: Space): DataStructure[]`
@@ -562,7 +758,7 @@ const devSettings = parseWorkspaceSettings(
562
758
  imageEndpoint: process.env.IMAGE_ENDPOINT,
563
759
  uploadEndpoint: process.env.UPLOAD_ENDPOINT,
564
760
  },
565
- workspaceObject // optional — overrides defaults when provided
761
+ workspaceObject, // optional — overrides defaults when provided
566
762
  );
567
763
  ```
568
764
 
@@ -572,7 +768,8 @@ const devSettings = parseWorkspaceSettings(
572
768
 
573
769
  | Method | Description |
574
770
  | ---------------------------------- | ----------------------------------------------------------------- |
575
- | `handleRefresh()` | Re-fetches the current list data |
771
+ | `handleRefresh()` | Re-fetches the current list data, resetting pagination to page 1 |
772
+ | `handleRefreshCurrentPage()` | Re-fetches in place, keeping page index, cursor, and filters |
576
773
  | `handleFormSubmit()` | Programmatically submits the update/create form |
577
774
  | `handleFormCheck()` | Validates the form without submitting |
578
775
  | `handlePopUpModal()` | Opens the create/update modal |
@@ -595,26 +792,27 @@ const devSettings = parseWorkspaceSettings(
595
792
 
596
793
  ### Optional props
597
794
 
598
- | Name | Type | Default | Description |
599
- | ---------------- | --------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------- |
600
- | `id` | `string` | `""` | Selected record ID. Pass `"new"` to open a blank create form |
601
- | `limit` | `number` | `10` | Records per page in list view |
602
- | `space` | `Space` | — | Full Space object from Blixify Space — enables extended features like tabs, sort, and additional queries |
603
- | `edit` | `Edit` | — | Controls create/update/delete permissions — see Edit below |
604
- | `organise` | `Organise` | — | Controls view, sort, filter, tabs, export, and navigation — see Organise below |
605
- | `bareSettings` | `BareSettings` | — | Injects custom React components and callbacks into list/read/update views — see BareSettings below |
606
- | `renderSettings` | `RenderSettings` | — | Overrides the entire list UI or loading UI with custom renderers |
607
- | `roles` | `string[]` | — | Role strings (reserved for future permission checks) |
608
- | `darkMode` | `boolean` | — | Applies dark colour scheme |
609
- | `uniqueLabel` | `string` | — | Unique label appended to internal query keys to avoid collisions |
610
- | `groupId` | `string` | — | Groups list results by this field. Grouped items are returned with a `children` array |
611
- | `defaultTab` | `any` | — | Pre-selects a tab on mount |
612
- | `workspaceId` | `string` | — | Workspace ID (used for workspace-scoped operations) |
613
- | `newTabUrl` | `{ default?: string; addons?: string }` | — | URL config for row links. `default` is the base URL; `addons` is appended after the record id |
614
- | `lib` | `LibSettings` | — | External library instances — see lib below |
615
- | `linkProps` | `LinkProps` | — | Refer to Link component documentation |
616
- | `onComplete` | `(id: string) => void` | — | Called after a create/update operation completes |
617
- | `onLoadIframe` | `() => void` | — | Called when an iframe tab finishes loading |
795
+ | Name | Type | Default | Description |
796
+ | ---------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
797
+ | `id` | `string` | `""` | Selected record ID. Pass `"new"` to open a blank create form |
798
+ | `limit` | `number` | `10` | Records per page in list view |
799
+ | `space` | `Space` | — | Full Space object from Blixify Space — enables extended features like tabs, sort, and additional queries |
800
+ | `edit` | `Edit` | — | Controls create/update/delete permissions — see Edit below |
801
+ | `organise` | `Organise` | — | Controls view, sort, filter, tabs, export, and navigation — see Organise below |
802
+ | `bareSettings` | `BareSettings` | — | Injects custom React components and callbacks into list/read/update views — see BareSettings below |
803
+ | `renderSettings` | `RenderSettings` | — | Overrides the entire list UI or loading UI with custom renderers |
804
+ | `roles` | `string[]` | — | Role strings (reserved for future permission checks) |
805
+ | `darkMode` | `boolean` | — | Applies dark colour scheme |
806
+ | `darkModeBg` | `string` | The app's own dark surface class (e.g. `"bg-neutral-900"`). With `darkMode`, every panel DataTemplate paints — modals, tables, lists, section cards, read-view cards, the drawer, the floating action bar — uses it instead of the default `bg-gray-900`, so nothing comes out navy on a black page |
807
+ | `uniqueLabel` | `string` | — | Unique label appended to internal query keys to avoid collisions |
808
+ | `groupId` | `string` | — | Groups list results by this field. Grouped items are returned with a `children` array |
809
+ | `defaultTab` | `any` | — | Pre-selects a tab on mount |
810
+ | `workspaceId` | `string` | — | Workspace ID (used for workspace-scoped operations) |
811
+ | `newTabUrl` | `{ default?: string; addons?: string }` | — | URL config for row links. `default` is the base URL; `addons` is appended after the record id |
812
+ | `lib` | `LibSettings` | — | External library instances — see lib below |
813
+ | `linkProps` | `LinkProps` | — | Refer to Link component documentation |
814
+ | `onComplete` | `(id: string) => void` | — | Called after a create/update operation completes |
815
+ | `onLoadIframe` | `() => void` | — | Called when an iframe tab finishes loading |
618
816
 
619
817
  ### lib
620
818
 
@@ -668,6 +866,36 @@ const devSettings = parseWorkspaceSettings(
668
866
  | `disabledTabsDeleteBtn` | `boolean` | Disables the delete button inside extended tabs |
669
867
  | `activityLog` | `ActivityLog` | See ActivityLog below |
670
868
 
869
+ #### Inline editability matrix (`listEditable`)
870
+
871
+ Which field types can be edited from the list table, and how. Types not listed under
872
+ "Never rendered" appear as read-only cells when they are not editable.
873
+
874
+ | Edited **in the cell** | Edited **in a modal** (cell click opens it) | Read-only in list | Never rendered as a list column |
875
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ------------------------------- |
876
+ | `string`, `contact`, `email`, `textArea`, `number`, `boolean` (checkbox and radio commit on select), `date`, `list`, `multipleList`, `person`, `listPerson`, `roles`, `reference`, `listReference`, `referenceSelection` | `image`, `multipleImage`, `address`, `object`, `listObject`, `markdown`, `signature`, `file`, `multipleFile`, `listAddress` | `math` (computed), `password` | `canvas`, `ganttchart` |
877
+
878
+ - **Why some types edit in a modal:** their editor is bigger than one line. An
879
+ `address` is a Places autocomplete plus a map with a draggable pin plus
880
+ country/state/district fields; `image` / `multipleImage` are an upload area
881
+ with previews; `object` / `listObject` are a nested form. None of that fits a
882
+ table cell, so the cell shows the value (or `Add`) and a click opens the same
883
+ editor the update view uses. Keep them there — an inline variant would have to
884
+ drop the map / previews / nested fields to fit.
885
+ - Inline commits fire **one single-column update on blur**, and only when the value
886
+ actually changed — an untouched blur fires nothing.
887
+ - `reference` / `listReference` options load with **one call per cell focus** (the
888
+ select's own fetch — the table adds none of its own); typing searches
889
+ server-side, debounced.
890
+ - Reference labels — top-level **and** nested inside `object` / `listObject` —
891
+ are resolved once at list load, one query per referenced collection, and seed
892
+ both the inline cell and the object editor; nothing is fetched on open.
893
+ - An `object` cell prints every readable field joined with `·`
894
+ (`Blixify Sdn Bhd · Admin`), with nested reference ids already swapped for labels.
895
+ - Modal saves go through the same single-column update; Cancel and no-change saves
896
+ fire nothing.
897
+ - See the `DTW Inline Edit Matrix` story for a live fixture with every type.
898
+
671
899
  ### ActivityLog
672
900
 
673
901
  | Name | Type | Description |
@@ -683,57 +911,55 @@ const devSettings = parseWorkspaceSettings(
683
911
 
684
912
  ### Organise
685
913
 
686
- | Name | Type | Description |
687
- | ----------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
688
- | `sort` | `Sort` | Default sort applied to list queries |
689
- | `pageIndex` | `number` | Initial page index |
690
- | `viewId` | `string` | Active view type: `"general"`, `"calendar"`, `"grid"`, `"list"`, `"feeds"`, `"kanban"`, etc. |
691
- | `idField` | `string` | DataStructure column ID whose value becomes the new record's ID on creation |
692
- | `extendedTabs` | `ExtendedTabs[]` | Additional tabs rendered alongside the main view — see Extended Tab below |
693
- | `additionalQuery` | `AdditionalQuery[]` | Filter/search controls rendered above the list — see Additional Query below |
694
- | `darkMode` | `boolean` | Applies dark colour scheme to the organise bar |
695
- | `hideSearch` | `boolean` | Hides the search input |
696
- | `hidePagination` | `boolean` | Hides pagination on Table, List, Grid, and Feeds views |
697
- | `hideNewTabs` | `boolean` | Hides the new-tab creation button |
698
- | `splitView` | `boolean` | Renders a split list/detail layout in read mode |
699
- | `listObjectTableView` | `boolean` | Shows list objects in table view during read and update |
700
- | `disableMulti` | `boolean` | Disables multi-row selection |
701
- | `disableSelectFullData` | `{ table?: boolean; list?: boolean }` | Disables "select all pages" for table and/or list views |
702
- | `disabledOnEnter` | `boolean` | Prevents Enter key from submitting forms |
703
- | `breadcrumbType` | `"button" \| "hidden"` | `"button"` shows a back button; `"hidden"` hides the breadcrumb entirely |
704
- | `breadcrumbAttributeId` | `string` | Column ID whose value is used as the breadcrumb label in read view |
705
- | `tabAlign` | `"top" \| "left" \| "stepper"` | Tab layout direction |
706
- | `groupRead` | `"groupId"` | Groups and separates read view sections by DataStructure `groupId` |
707
- | `showCollapsibleTab` | `boolean` | Renders tabs as collapsible sections |
708
- | `showBaseUpdatedAt` | `boolean` | Shows the `baseUpdatedAt` timestamp in Table, Grid, List, and Kanban views |
709
- | `showGroupByFeature` | `boolean` | Shows the group-by selector in the toolbar |
710
- | `showReadFloatingNav` | `boolean` | Shows a floating section navigator in read view |
711
- | `showExport` | `boolean` | Shows import/export options (default `true`) |
712
- | `disableEllipsisOnLongWord` | `boolean` | Wraps long text instead of truncating with ellipsis |
713
- | `fixedPagination` | `boolean` | Fixes the pagination bar to the bottom of the viewport |
714
- | `filterComponentNewRow` | `boolean` | Renders each filter component on its own row |
715
- | `addColumnEnabled` | `boolean` | Shows an add-column button in the table header |
716
- | `advSortEnabled` | `boolean` | Shows advanced sort controls |
717
- | `advFilterEnabled` | `boolean` | Shows advanced filter controls |
718
- | `advDragEnabled` | `boolean` | Enables drag-to-reorder columns |
719
- | `groupBy` | `string` | Column ID to group list results by |
720
- | `groupIdCollapsible` | `{ [key: string]: boolean }` | Initial collapsed/expanded state per group ID |
721
- | `sortGroupByAlphabetically` | `boolean` | Sorts group-by values alphabetically |
722
- | `unionCollections` | `any[]` | Additional collections to union-query alongside the main collection |
723
- | `moreSettings` | `{ text: string; onClick: () => void }[]` | Extra items appended to the "more" dropdown menu |
724
- | `exportSettings` | `ExportSettings` | See Export Settings below |
725
- | `onChangeSort` | `(value: Sort) => void` | Called when the user changes the sort |
726
- | `onChangeFilter` | `(value: AdditionalQuery[]) => void` | Called when the user changes filters |
727
- | `onChangeHide` | `(value: DataStructure[]) => void` | Called when the user hides/shows columns |
728
- | `onChangeDrag` | `(dragId: string, dropId: string, newHeader: TableHeader[]) => void` | Called after a column is reordered |
729
- | `onChangeTabs` | `(value: ExtendedTabs[]) => void` | Called when tabs are added/removed/reordered |
730
- | `onChangePagination` | `(page: number) => void` | Called when the page changes |
731
- | `onAddColumns` | `(model: DataStructure[]) => void` | Called when a new column is added |
732
- | `handleNavigate` | `(type: string, selectedId?: string, viewId?: string) => void` | Called when the component needs to navigate (e.g. row click → read view) |
733
- | `handleCustomDownloadFile` | `(url: string, fileName?: string) => void` | Overrides the default file download behaviour |
734
- | `renderReferenceLabelOptions` | `(spaceId?: string, includeReference?: boolean, type?: string) => Option[]` | Returns column options for reference label selectors |
735
- | `renderReferenceSpaceOptions` | `() => Option[]` | Returns space options for reference space selectors |
736
- | `renderGroupByOptions` | `() => Option[]` | Returns custom options for the group-by selector |
914
+ | Name | Type | Description |
915
+ | ----------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
916
+ | `sort` | `Sort` | Default sort applied to list queries |
917
+ | `pageIndex` | `number` | Initial page index |
918
+ | `viewId` | `string` | Active view type: `"general"`, `"calendar"`, `"grid"`, `"list"`, `"feeds"`, `"kanban"`, etc. |
919
+ | `idField` | `string` | DataStructure column ID whose value becomes the new record's ID on creation |
920
+ | `extendedTabs` | `ExtendedTabs[]` | Additional tabs rendered alongside the main view — see Extended Tab below |
921
+ | `additionalQuery` | `AdditionalQuery[]` | Filter/search controls rendered above the list — see Additional Query below |
922
+ | `darkMode` | `boolean` | Applies dark colour scheme to the organise bar |
923
+ | `hideSearch` | `boolean` | Hides the search input |
924
+ | `hidePagination` | `boolean` | Hides pagination on Table, List, Grid, and Feeds views |
925
+ | `hideNewTabs` | `boolean` | Hides the new-tab creation button |
926
+ | `splitView` | `boolean` | Renders a split list/detail layout in read mode |
927
+ | `listObjectTableView` | `boolean` | Shows list objects in table view during read and update |
928
+ | `disableMulti` | `boolean` | Disables multi-row selection |
929
+ | `disableSelectFullData` | `{ table?: boolean; list?: boolean }` | Disables "select all pages" for table and/or list views |
930
+ | `disabledOnEnter` | `boolean` | Prevents Enter key from submitting forms |
931
+ | `breadcrumbType` | `"button" \| "hidden"` | `"button"` shows a back button; `"hidden"` hides the breadcrumb entirely |
932
+ | `breadcrumbAttributeId` | `string` | Column ID whose value is used as the breadcrumb label in read view |
933
+ | `tabAlign` | `"top" \| "left" \| "stepper"` | Tab layout direction |
934
+ | `groupRead` | `"groupId"` | Groups and separates read view sections by DataStructure `groupId` |
935
+ | `showCollapsibleTab` | `boolean` | Renders tabs as collapsible sections |
936
+ | `showBaseUpdatedAt` | `boolean` | Shows the `baseUpdatedAt` timestamp in Table, Grid, List, and Kanban views |
937
+ | `showGroupByFeature` | `boolean` | Shows the group-by selector in the toolbar |
938
+ | `showReadFloatingNav` | `boolean` | Shows a floating section navigator in read view |
939
+ | `showExport` | `boolean` | Shows import/export options (default `true`) |
940
+ | `disableEllipsisOnLongWord` | `boolean` | Wraps long text instead of truncating with ellipsis |
941
+ | `fixedPagination` | `boolean` | Fixes the pagination bar to the bottom of the viewport |
942
+ | `filterComponentNewRow` | `boolean` | Renders each filter component on its own row |
943
+ | `addColumnEnabled` | `boolean` | Shows an add-column button in the table header |
944
+ | `persistViewState` | `"session" \| "local"` | Remembers the list's sort, filters, hidden columns, page and search in `sessionStorage` / `localStorage` per collection, so a Back navigation lands where the user left |
945
+ | `groupBy` | `string` | Column ID to group list results by |
946
+ | `groupIdCollapsible` | `{ [key: string]: boolean }` | Initial collapsed/expanded state per group ID |
947
+ | `sortGroupByAlphabetically` | `boolean` | Sorts group-by values alphabetically |
948
+ | `unionCollections` | `any[]` | Additional collections to union-query alongside the main collection |
949
+ | `moreSettings` | `{ text: string; onClick: () => void }[]` | Extra items appended to the "more" dropdown menu |
950
+ | `exportSettings` | `ExportSettings` | See Export Settings below |
951
+ | `onChangeSort` | `(value: Sort) => void` | Called when the user changes the sort |
952
+ | `onChangeHide` | `(value: DataStructure[]) => void` | Called when a column is hidden from the view settings panel. Providing it switches the panel to schema mode — the hide is written to the model for everyone instead of being this user's own |
953
+ | `onChangeDrag` | `(dragId: string, dropId: string, newHeader: TableHeader[]) => void` | Called after a column is reordered in the view settings panel, so the consumer can persist the order |
954
+ | `onChangeTabs` | `(value: ExtendedTabs[]) => void` | Called when tabs are added/removed/reordered |
955
+ | `onChangePagination` | `(page: number) => void` | Called when the page changes |
956
+ | `customPaginationCount` | `(pageDataCount: number) => void` | Called after each data fetch with the actual record count. Use this to override the count shown in the pagination bar — store the value in your own state and pass it back via `customPaginationSize` on `Table`, `Grid`, `List`, or `Pagination` if needed, or use it to display a custom count elsewhere in your UI |
957
+ | `onAddColumns` | `(model: DataStructure[]) => void` | Called when a new column is added |
958
+ | `handleNavigate` | `(type: string, selectedId?: string, viewId?: string) => void` | Called when the component needs to navigate (e.g. row click → read view) |
959
+ | `handleCustomDownloadFile` | `(url: string, fileName?: string) => void` | Overrides the default file download behaviour |
960
+ | `renderReferenceLabelOptions` | `(spaceId?: string, includeReference?: boolean, type?: string) => Option[]` | Returns column options for reference label selectors |
961
+ | `renderReferenceSpaceOptions` | `() => Option[]` | Returns space options for reference space selectors |
962
+ | `renderGroupByOptions` | `() => Option[]` | Returns custom options for the group-by selector |
737
963
 
738
964
  ### Export Settings
739
965
 
@@ -789,50 +1015,62 @@ const devSettings = parseWorkspaceSettings(
789
1015
 
790
1016
  Injects custom React components and callbacks into the list, read, and update views.
791
1017
 
792
- | Name | Type | Description |
793
- | ---------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
794
- | `bareReadComponent` | `(data: any) => any` | Custom component rendered in read view |
795
- | `bareReadComponentPos` | `"top"` | Renders `bareReadComponent` above the default read content |
796
- | `bareReadComponentHide` | `boolean` | Hides the default read content (shows only `bareReadComponent`) |
797
- | `bareReadReferenceView` | `(dataId, collectionId, attributeId) => boolean \| void` | Controls whether a reference field opens a view |
798
- | `bareReadDescription` | `(key: string, value: any) => any` | Custom renderer for read view field values |
799
- | `bareReadHandleData` | `(data: any) => void` | Called when read view data is loaded |
800
- | `bareReadListTabs` | `boolean` | Shows list-style tabs in read view |
801
- | `bareListComponent` | `(data, prettierData, loading, pageIndex) => any` | Fully replaces the list UI with a custom component |
802
- | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons rendered on each list row |
803
- | `bareListMultipleSelectAddtionalActions` | `{ text: string; className?: string; onClick: (ids, selectAll, query) => void }[]` | Extra bulk-action buttons shown when rows are selected |
804
- | `bareListGridComponent` | `(data: any) => any` | Custom card renderer for grid view |
805
- | `bareListGridColClassName` | `string` | Tailwind class for grid column width |
806
- | `bareListGridTags` | `(data: any) => string[]` | Returns tag strings shown on grid cards |
807
- | `bareListGridFallbackImg` | `(data: any) => string \| ReactElement` | Fallback image/element for grid cards without an image |
808
- | `bareListGridRibbonText` | `(data: any) => string` | Text shown as a ribbon on grid cards |
809
- | `bareListHandleData` | `(data, prettierData) => void` | Called when list data is loaded |
810
- | `bareListHandleSelection` | `(selectAll, selectedIds, query?) => void` | Called when row selection changes |
811
- | `bareListHandleFilter` | `(search, select, date, reference) => void` | Called when any filter changes |
812
- | `bareListFilterSelected` | `(filterSearchParams, filterSelection, filterReference, filterReferenceDate) => void` | Called with the current filter state whenever it changes |
813
- | `bareListDescription` | `(key: string, value: any) => any` | Custom renderer for list view field values |
814
- | `bareListFilterQuery` | `Query[]` | Additional queries always applied to list fetches |
815
- | `bareListFilterAddComponent` | `ReactElement[]` | Extra filter components rendered in the filter bar |
816
- | `bareListPipeline` | `PipeLine[]` | Additional pipeline stages appended to list queries |
817
- | `bareListObjectHandleData` | `(type: "read" \| "update" \| "new", data: any) => void` | Called when a list-object row is opened |
818
- | `bareUpdatePrefill` | `(data: any) => { key: string; value: any }[]` | Returns prefill values for the update form based on existing data |
819
- | `bareUpdateComponent` | `(data: any) => any` | Custom component rendered inside the update form |
820
- | `bareUpdateComponentAbove` | `boolean` | Renders `bareUpdateComponent` above the default form fields |
821
- | `bareUpdateActionComponent` | `(data: any, formRef?: any) => any` | Custom action buttons rendered in the update form footer |
822
- | `bareUpdateHandleData` | `(data: any, changedAttributeIds?: string[]) => void` | Called on every form field change with the current data and changed field IDs |
823
- | `bareUpdateHandlePreComplete` | `(data: any) => Promise<boolean>` | Called before save — return `false` to cancel |
824
- | `bareUpdateHandleComplete` | `(data: any) => Promise<any>` | Called after save completes |
825
- | `bareUpdateHandlePostComplete` | `(data: any) => Promise<any>` | Called after post-save operations complete |
826
- | `bareUpdateColumnType` | `"one" \| "two" \| "four"` | Form column layout: `"one"` = 2-col grid, `"two"` = 4-col grid (default), `"four"` = 4-col grid |
827
- | `bareUpdateTabComponent` | `(tabIds: string[]) => { tabId: string; icon?: ReactElement; skip?: boolean }[]` | Custom icons/skip flags for form tabs |
828
- | `bareUpdateActionBottom` | `boolean` | Renders action buttons at the bottom of the form |
829
- | `bareUpdateTabId` | `(tabId: string) => void` | Called when the active form tab changes |
830
- | `bareUpdateIndividualComponent` | `(columnId, ref, selectedData, setSelectedData) => ReactElement \| null` | Replaces a specific form field with a custom component |
831
- | `bareUpdateMobileView` | `boolean` | Renders the update form in mobile-optimised layout |
832
- | `bareOffline` | `boolean` | Enables offline data caching via IndexedDB |
833
- | `bareCSVImportEndpoint` | `string` | Custom CSV import endpoint |
834
- | `bareCSVExportEndpoint` | `string` | Custom CSV export endpoint |
835
- | `bareHideTableExtraMultipleAction` | `boolean` | Hides the extra multiple-action button in table view |
1018
+ | Name | Type | Description |
1019
+ | ---------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1020
+ | `bareViewSettings` | `boolean` | Turns on the view settings feature — the panel (columns hide / reorder / search, sort, rows per page) and the hide, drag and sort controls in the table header. Always on under `bareNewDTW` |
1021
+ | `bareReadComponent` | `(data: any) => any` | Custom component rendered in read view |
1022
+ | `bareReadComponentPos` | `"top"` | Renders `bareReadComponent` above the default read content |
1023
+ | `bareReadComponentHide` | `boolean` | Hides the default read content (shows only `bareReadComponent`) |
1024
+ | `bareReadReferenceView` | `(dataId, collectionId, attributeId) => boolean \| void` | Controls whether a reference field opens a view |
1025
+ | `bareReadDescription` | `(key: string, value: any) => any` | Custom renderer for read view field values |
1026
+ | `bareReadHandleData` | `(data: any) => void` | Called when read view data is loaded |
1027
+ | `bareReadListTabs` | `boolean` | Shows list-style tabs in read view |
1028
+ | `bareListComponent` | `(data, prettierData, loading, pageIndex) => any` | Fully replaces the list UI with a custom component |
1029
+ | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons rendered on each list row |
1030
+ | `bareListMultipleSelectAddtionalActions` | `{ text: string; className?: string; onClick: (ids, selectAll, query) => void }[]` | Extra bulk-action buttons shown when rows are selected |
1031
+ | `bareListGridComponent` | `(data: any) => any` | Custom card renderer for grid view |
1032
+ | `bareListGridColClassName` | `string` | Tailwind class for grid column width |
1033
+ | `bareListGridTags` | `(data: any) => string[]` | Returns tag strings shown on grid cards |
1034
+ | `bareListGridFallbackImg` | `(data: any) => string \| ReactElement` | Fallback image/element for grid cards without an image |
1035
+ | `bareListGridRibbonText` | `(data: any) => string` | Text shown as a ribbon on grid cards |
1036
+ | `bareListHandleData` | `(data, prettierData) => void` | Called when list data is loaded |
1037
+ | `bareListHandleSelection` | `(selectAll, selectedIds, query?) => void` | Called when row selection changes |
1038
+ | `bareListHandleFilter` | `(search, select, date, reference) => void` | Called when any filter changes |
1039
+ | `bareListFilterSelected` | `(filterSearchParams, filterSelection, filterReference, filterReferenceDate) => void` | Called with the current filter state whenever it changes |
1040
+ | `bareListDescription` | `(key: string, value: any) => any` | Custom renderer for list view field values |
1041
+ | `bareListFilterQuery` | `Query[]` | Additional queries always applied to list fetches |
1042
+ | `bareListFilterAddComponent` | `ReactElement[]` | Extra filter components rendered in the filter bar |
1043
+ | `bareListPipeline` | `PipeLine[]` | Additional pipeline stages appended to list queries |
1044
+ | `bareListObjectHandleData` | `(type: "read" \| "update" \| "new", data: any) => void` | Called when a list-object row is opened |
1045
+ | `bareUpdatePrefill` | `(data: any) => { key: string; value: any }[]` | Returns prefill values for the update form based on existing data |
1046
+ | `bareUpdateComponent` | `(data: any) => any` | Custom component rendered inside the update form |
1047
+ | `bareUpdateComponentAbove` | `boolean` | Renders `bareUpdateComponent` above the default form fields |
1048
+ | `bareSaveOnTabChange` | `boolean` | Auto-save: every Next / Previous on a tabbed update form writes a draft first, silently (no toast). Pair with `edit.enableUpdateDraft` |
1049
+ | `bareUpsertPartialUpdate` | `boolean` | Upsert by `props.id` and send only the fields that changed since load; a save with no changes skips the write. Makes auto-save safe across devices |
1050
+ | `bareUpdateActionComponent` | `(data: any, formRef?: any) => any` | Custom action buttons rendered in the update form footer |
1051
+ | `bareFlexFilters` | `boolean` | Funnel icon opens the Filters builder (column · condition · value, values from the schema) — replaces hand-rolled page filters; new table only |
1052
+ | `bareListFilterAsPopup` | `boolean` | Shows the list's filter inputs in a popup instead of the header row |
1053
+ | `bareListTablePinColumns` | `{ left?: string[]; right?: string[] }` | Columns kept sticky at the edges while the table scrolls sideways (`"update"` is the actions column); new table only |
1054
+ | `bareListMobileView` | `boolean` | Phone card list instead of the table (the app passes its own isMobile) |
1055
+ | `bareListMobileFloatingSearch` | `boolean` | Floating search bar at the bottom on phones; the list reserves room under its last row for it |
1056
+ | `bareListMaxSelectedCount` | `number` | Caps how many rows the checkbox column may select at once |
1057
+ | `bareUpdateHandleData` | `(data: any, changedAttributeIds?: string[]) => void` | Called on every form field change with the current data and changed field IDs |
1058
+ | `bareUpdateHandlePreComplete` | `(data: any) => Promise<boolean>` | Called before save — return `false` to cancel |
1059
+ | `bareUpdateHandleComplete` | `(data: any) => Promise<any>` | Called after save completes |
1060
+ | `bareUpdateHandlePostComplete` | `(data: any) => Promise<any>` | Called after post-save operations complete |
1061
+ | `bareUpdateColumnType` | `"one" \| "two" \| "four"` | Form column layout: `"one"` = 2-col grid, `"two"` = 4-col grid (default), `"four"` = 4-col grid |
1062
+ | `bareUpdateTabComponent` | `(tabIds: string[]) => { tabId: string; icon?: ReactElement; skip?: boolean }[]` | Custom icons/skip flags for form tabs |
1063
+ | `bareUpdateActionBottom` | `boolean` | Plain right-aligned action row instead of the floating pill — for short forms inside a `Modal` |
1064
+ | `bareUpdateTabId` | `(tabId: string) => void` | Called when the active form tab changes |
1065
+ | `bareUpdateIndividualComponent` | `(columnId, ref, selectedData, setSelectedData) => ReactElement \| null` | Replaces a specific form field with a custom component |
1066
+ | `bareUpdateMobileView` | `boolean` | Renders the update form in mobile-optimised layout |
1067
+ | `bareOffline` | `boolean` | Enables offline data caching via IndexedDB |
1068
+ | `bareOfflineNetworkListener` | `boolean` | With `bareOffline`: follow `navigator.onLine` — saves go to the server while online and to IndexedDB only when the network is down. Without it every save goes to IndexedDB until `handleUploadOfflineData()` |
1069
+ | `bareOfflinePrefetchLimit` | `number` | With `bareOffline`: how many of the collection's latest docs to download into IndexedDB on mount (default 10) |
1070
+ | `bareOfflineReferences` | `Array<{ collectionId: string; limit?: number }>` | With `bareOffline`: reference collections to download on mount so reference dropdowns keep working offline |
1071
+ | `bareCSVImportEndpoint` | `string` | Custom CSV import endpoint |
1072
+ | `bareCSVExportEndpoint` | `string` | Custom CSV export endpoint |
1073
+ | `bareHideTableExtraMultipleAction` | `boolean` | Hides the extra multiple-action button in table view |
836
1074
 
837
1075
  ### Extended Tab
838
1076
 
@@ -863,19 +1101,81 @@ Injects custom React components and callbacks into the list, read, and update vi
863
1101
 
864
1102
  ### Calendar Settings
865
1103
 
866
- | Name | Type | Description |
867
- | ------------------ | -------------------- | ---------------------------------------------------------------- |
868
- | `title` | `string` | Column ID for event title |
869
- | `startDate` | `string` | Column ID for event start date |
870
- | `endDate` | `string` | Column ID for event end date |
871
- | `defaultStartDate` | `Date` | Default calendar start date |
872
- | `customView` | `CalendarCustomView` | Custom calendar view config |
873
- | `groupId` | `string` | Column ID — events with the same value share a background colour |
874
- | `groupColor` | `Color[]` | Background colours for groups |
875
- | `customHeader` | `string` | Custom title replacing the default calendar header |
1104
+ | Name | Type | Description |
1105
+ | ------------------ | -------------------------- | --------------------------------------------------------------------------------------------------------- |
1106
+ | `title` | `string` | Column ID for event title |
1107
+ | `startDate` | `string` | Column ID for event start date |
1108
+ | `endDate` | `string` | Column ID for event end date |
1109
+ | `defaultStartDate` | `Date` | Default calendar start date |
1110
+ | `customView` | `CalendarCustomView` | Custom calendar view config |
1111
+ | `groupId` | `string` | Column ID — events with the same value share a background colour |
1112
+ | `groupColor` | `Color[]` | Background colours for groups |
1113
+ | `customHeader` | `string` | Custom title replacing the default calendar header |
1114
+ | `eventColorRules` | `CalendarEventColorRule[]` | Maps a field+value on each event to an explicit color. Takes priority over `groupId` coloring. See below. |
1115
+
1116
+ ### CalendarEventColorRule
1117
+
1118
+ | Name | Type | Required | Description |
1119
+ | ------------ | -------- | -------- | -------------------------------------------------------------------- |
1120
+ | `field` | `string` | yes | Column ID on the event data to match against (e.g. `"status"`) |
1121
+ | `value` | `any` | yes | The value to match (e.g. `"Approved"`) |
1122
+ | `color` | `string` | yes | Tailwind bg class for the event pill, e.g. `"bg-green-500"` |
1123
+ | `hoverColor` | `string` | no | Tailwind hover class for the event pill, e.g. `"hover:bg-green-700"` |
1124
+ | `textColor` | `string` | no | Tailwind text class for the event pill, e.g. `"text-white"` |
1125
+
1126
+ Example — color events by status:
1127
+
1128
+ ```tsx
1129
+ calendarSettings: {
1130
+ title: "name",
1131
+ startDate: "startAt",
1132
+ endDate: "endAt",
1133
+ eventColorRules: [
1134
+ { field: "status", value: "Approved", color: "bg-green-500", hoverColor: "hover:bg-green-700", textColor: "text-white" },
1135
+ { field: "status", value: "Pending", color: "bg-yellow-400", hoverColor: "hover:bg-yellow-600", textColor: "text-white" },
1136
+ { field: "status", value: "Rejected", color: "bg-red-500", hoverColor: "hover:bg-red-700", textColor: "text-white" },
1137
+ ],
1138
+ }
1139
+ ```
1140
+
1141
+ ### List / MultipleList Field Settings
1142
+
1143
+ Properties specific to `type: "list"` and `type: "multipleList"` fields in the DataStructure schema.
1144
+
1145
+ | Name | Type | Default | Description |
1146
+ | ------------------------ | ----------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
1147
+ | `listSelection` | `string[]` | — | Available options for the select field |
1148
+ | `listSelectionLabel` | `string[]` | — | Display labels for each option (matched by index). When omitted, the key itself is shown |
1149
+ | `listSelectionColour` | `string[]` | — | Colour for each option (matched by index). Supports named colours or hex values starting with `#` |
1150
+ | `listView` | `"radioview" \| "modal" \| "chips"` | `undefined` | Render style. `undefined` = dropdown. `"chips"` renders options as inline toggleable chips |
1151
+ | `listNewValue` | `boolean` | `false` | Allows users to add values not in `listSelection`. In chips mode, shows a `+ Add` chip that expands to an inline input |
1152
+ | `listNewValueLabel` | `string` | `"+ Add"` | Custom label for the add-new-value chip (only applies when `listView: "chips"` and `listNewValue: true`) |
1153
+ | `disabledAutoSelect` | `boolean` | `false` | When `true`, no option is pre-selected. The field starts empty |
1154
+ | `disabledKeyboardSearch` | `boolean` | `false` | Disables typeahead filtering in the dropdown |
1155
+ | `showTagSelections` | `boolean` | `false` | Shows selected values as removable tags below the dropdown input |
1156
+ | `closeOnClickOutside` | `boolean` | `false` | For `multipleList` dropdown, closes the options panel when clicking outside |
1157
+
1158
+ #### Chips example
1159
+
1160
+ ```tsx
1161
+ {
1162
+ id: "weather",
1163
+ name: "Weather",
1164
+ type: "multipleList",
1165
+ listView: "chips",
1166
+ listSelection: ["Sunny", "Cloudy", "Drizzle", "Rainy", "Thunderstorm"],
1167
+ listNewValue: true,
1168
+ listNewValueLabel: "+ Other",
1169
+ disabledAutoSelect: true,
1170
+ }
1171
+ ```
1172
+
1173
+ This renders all weather options as toggleable chips. Users can select multiple and also add custom values via the `+ Other` chip.
876
1174
 
877
1175
  ### Feeds Settings
878
1176
 
1177
+ Under `bareNewDTW` the feeds tab renders `NewFeeds` (timeline card that matches NewList's row geometry) with the shared `NewPagination` footer; tapping a row opens the record's read view, the pencil / trash actions stay in the row. Without the flag the legacy `Feeds` renders as before.
1178
+
879
1179
  | Name | Type | Description |
880
1180
  | ----------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
881
1181
  | `title` | `string` | Column ID for feed item title |
@@ -901,3 +1201,17 @@ Injects custom React components and callbacks into the list, read, and update vi
901
1201
  | `title` | `string` | Column ID for map marker info window title |
902
1202
  | `address` | `string` | Column ID for marker coordinates |
903
1203
  | `group` | `string` | Column ID to group markers by colour |
1204
+
1205
+ **Stories** — four groups under `Data / Data Wrapper`: **View** (list, read, drawer, grouped
1206
+ sections, scroll paging), **Edit** (CRUD, inline-edit matrix), **Utils** (flex filters, hidden
1207
+ columns, persisted view state, SSE live) and **Consumer Fixtures** below.
1208
+ Every story mocks its own API and opens without a server.
1209
+
1210
+ **Consumer fixtures** — `Data / Data Wrapper / Consumer Fixtures` holds the DataTemplateWrapper
1211
+ configurations the apps run in production, copied field for field and self-mocked (no
1212
+ server): the KPJ grant proposal form (Blixify Space's kpj-projects shape), Verdant's
1213
+ installer pre- and post-installation checklists, its Sales Leads list and its simulator
1214
+ proposal form, Meraque's offline work order, and an **Action Component Cases** story showing
1215
+ the update form under the three things `bareUpdateActionComponent` can return (undefined /
1216
+ own buttons / an empty fragment). Open them on a phone and a desktop before bumping the app — what changes
1217
+ there is what changes in the app.