@cosmicdrift/kumiko-renderer-web 0.198.0 → 0.199.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer-web",
3
- "version": "0.198.0",
3
+ "version": "0.199.0",
4
4
  "description": "Web-platform bindings for @cosmicdrift/kumiko-renderer. HTML default-primitives, browser history-based navigation, EventSource-backed live events, and a one-call createKumikoApp that mounts the whole stack via react-dom.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -16,9 +16,9 @@
16
16
  "./styles.css": "./src/styles.css"
17
17
  },
18
18
  "dependencies": {
19
- "@cosmicdrift/kumiko-dispatcher-live": "0.198.0",
20
- "@cosmicdrift/kumiko-headless": "0.198.0",
21
- "@cosmicdrift/kumiko-renderer": "0.198.0",
19
+ "@cosmicdrift/kumiko-dispatcher-live": "0.199.0",
20
+ "@cosmicdrift/kumiko-headless": "0.199.0",
21
+ "@cosmicdrift/kumiko-renderer": "0.199.0",
22
22
  "@radix-ui/react-dialog": "^1.1.15",
23
23
  "@radix-ui/react-dropdown-menu": "^2.1.16",
24
24
  "@radix-ui/react-label": "^2.1.8",
@@ -150,6 +150,84 @@ describe("KumikoScreen", () => {
150
150
  expect(seenTypes).toEqual(["tasks:query:task:list"]);
151
151
  });
152
152
 
153
+ // #2062: the search box is a dead toolbar slot (and a guaranteed 422,
154
+ // #2032) once the client knows the server has no SearchAdapter wired.
155
+ describe("entityList search box gated on schema.searchAdapterMissing (#2062)", () => {
156
+ const searchableWidgetEntity = {
157
+ fields: { title: { type: "text", required: true, searchable: true } },
158
+ } as unknown as EntityDefinition;
159
+ const autoSearchScreen: EntityListScreenDefinition = {
160
+ id: "widget-list",
161
+ type: "entityList",
162
+ entity: "widget",
163
+ columns: ["title"],
164
+ };
165
+ const explicitSearchScreen: EntityListScreenDefinition = {
166
+ id: "widget-list-explicit",
167
+ type: "entityList",
168
+ entity: "widget",
169
+ columns: ["title"],
170
+ searchable: true,
171
+ };
172
+ const explicitNoSearchScreen: EntityListScreenDefinition = {
173
+ id: "widget-list-no-search",
174
+ type: "entityList",
175
+ entity: "widget",
176
+ columns: ["title"],
177
+ searchable: false,
178
+ };
179
+
180
+ function buildWidgetSchema(
181
+ screenDef: EntityListScreenDefinition,
182
+ searchAdapterMissing?: boolean,
183
+ ): FeatureSchema {
184
+ return {
185
+ featureName: "widgets",
186
+ entities: { widget: searchableWidgetEntity },
187
+ screens: [screenDef],
188
+ ...(searchAdapterMissing !== undefined && { searchAdapterMissing }),
189
+ };
190
+ }
191
+
192
+ async function renderWidgetList(schemaDef: FeatureSchema, qn: string): Promise<void> {
193
+ render(
194
+ <DispatcherProvider dispatcher={makeDispatcher()}>
195
+ <KumikoScreen schema={schemaDef} qn={qn} />
196
+ </DispatcherProvider>,
197
+ );
198
+ await waitFor(() => expect(screen.queryByTestId("kumiko-screen-loading")).toBeNull());
199
+ }
200
+
201
+ test("auto-detected searchable field renders the search box when the flag is absent", async () => {
202
+ await renderWidgetList(buildWidgetSchema(autoSearchScreen), "widgets:screen:widget-list");
203
+ expect(document.querySelector("#render-list-search")).not.toBeNull();
204
+ });
205
+
206
+ test("searchAdapterMissing: true hides the search box despite an auto-detected searchable field", async () => {
207
+ await renderWidgetList(
208
+ buildWidgetSchema(autoSearchScreen, true),
209
+ "widgets:screen:widget-list",
210
+ );
211
+ expect(document.querySelector("#render-list-search")).toBeNull();
212
+ });
213
+
214
+ test("searchAdapterMissing: true hides the search box even when screen.searchable is explicitly true", async () => {
215
+ await renderWidgetList(
216
+ buildWidgetSchema(explicitSearchScreen, true),
217
+ "widgets:screen:widget-list-explicit",
218
+ );
219
+ expect(document.querySelector("#render-list-search")).toBeNull();
220
+ });
221
+
222
+ test("screen.searchable: false stays hidden regardless of searchAdapterMissing", async () => {
223
+ await renderWidgetList(
224
+ buildWidgetSchema(explicitNoSearchScreen, false),
225
+ "widgets:screen:widget-list-no-search",
226
+ );
227
+ expect(document.querySelector("#render-list-search")).toBeNull();
228
+ });
229
+ });
230
+
153
231
  test("entityEdit with unknown entity on the screen → entity-missing placeholder", () => {
154
232
  const brokenScreen: EntityEditScreenDefinition = {
155
233
  id: "broken",
package/src/index.ts CHANGED
@@ -71,6 +71,8 @@ export {
71
71
  RenderEdit,
72
72
  RenderField,
73
73
  RenderList,
74
+ synthesizeActionFormEntity,
75
+ synthesizeActionFormScreen,
74
76
  TokensProvider,
75
77
  UserRolesProvider,
76
78
  useDispatcher,