@cosmicdrift/kumiko-renderer 0.327.0 → 0.328.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/action-form-shim.d.ts +14 -0
- package/{src/app/action-form-shim.ts → dist/app/action-form-shim.js} +26 -44
- package/dist/app/app-features-context.d.ts +8 -0
- package/dist/app/app-features-context.js +16 -0
- package/dist/app/column-renderers.d.ts +30 -0
- package/dist/app/column-renderers.js +34 -0
- package/dist/app/config-edit-shim.d.ts +11 -0
- package/{src/app/config-edit-shim.ts → dist/app/config-edit-shim.js} +12 -25
- package/dist/app/content-editors.d.ts +38 -0
- package/dist/app/content-editors.js +26 -0
- package/dist/app/content-preview.d.ts +11 -0
- package/dist/app/content-preview.js +30 -0
- package/dist/app/custom-screens.d.ts +11 -0
- package/dist/app/custom-screens.js +20 -0
- package/dist/app/dashboard-body.d.ts +16 -0
- package/dist/app/dashboard-body.js +11 -0
- package/dist/app/extension-form-submit.d.ts +32 -0
- package/dist/app/extension-form-submit.js +73 -0
- package/dist/app/extension-sections.d.ts +72 -0
- package/dist/app/extension-sections.js +34 -0
- package/dist/app/feature-schema.d.ts +4 -0
- package/{src/app/feature-schema.ts → dist/app/feature-schema.js} +12 -22
- package/dist/app/form-schema.d.ts +4 -0
- package/dist/app/form-schema.js +85 -0
- package/dist/app/kumiko-screen.d.ts +43 -0
- package/dist/app/kumiko-screen.js +2206 -0
- package/dist/app/layout-fields.d.ts +3 -0
- package/dist/app/layout-fields.js +20 -0
- package/dist/app/list-facets.d.ts +48 -0
- package/dist/app/list-facets.js +185 -0
- package/dist/app/nav.d.ts +61 -0
- package/dist/app/nav.js +139 -0
- package/dist/app/projection-detail-shim.d.ts +8 -0
- package/dist/app/projection-detail-shim.js +71 -0
- package/dist/app/projection-list-shim.d.ts +13 -0
- package/{src/app/projection-list-shim.ts → dist/app/projection-list-shim.js} +26 -38
- package/dist/app/qn.d.ts +7 -0
- package/{src/app/qn.ts → dist/app/qn.js} +9 -11
- package/dist/app/qualify-screen-id.d.ts +2 -0
- package/{src/app/qualify-screen-id.ts → dist/app/qualify-screen-id.js} +5 -6
- package/dist/app/reference-facet-bridge.d.ts +10 -0
- package/dist/app/reference-facet-bridge.js +22 -0
- package/dist/app/return-to.d.ts +31 -0
- package/dist/app/return-to.js +188 -0
- package/dist/app/row-actions.d.ts +77 -0
- package/dist/app/row-actions.js +416 -0
- package/dist/app/screen-access.d.ts +8 -0
- package/dist/app/screen-access.js +48 -0
- package/dist/app/secret-mint-body.d.ts +10 -0
- package/dist/app/secret-mint-body.js +140 -0
- package/dist/app/secrets-edit-body.d.ts +8 -0
- package/dist/app/secrets-edit-body.js +76 -0
- package/dist/app/use-embedded-screen.d.ts +6 -0
- package/dist/app/use-embedded-screen.js +19 -0
- package/dist/app/variable-chips.d.ts +7 -0
- package/dist/app/variable-chips.js +16 -0
- package/dist/app/write-failed-error.d.ts +6 -0
- package/dist/app/write-failed-error.js +21 -0
- package/dist/components/embedded-list-field.d.ts +10 -0
- package/dist/components/embedded-list-field.js +259 -0
- package/dist/components/grid-cell-for-field.d.ts +25 -0
- package/dist/components/grid-cell-for-field.js +31 -0
- package/dist/components/multi-select-checkboxes.d.ts +14 -0
- package/dist/components/multi-select-checkboxes.js +36 -0
- package/dist/components/reference-create-dialog.d.ts +13 -0
- package/dist/components/reference-create-dialog.js +46 -0
- package/dist/components/related-list-section.d.ts +25 -0
- package/dist/components/related-list-section.js +273 -0
- package/dist/components/render-edit-action-button.d.ts +22 -0
- package/dist/components/render-edit-action-button.js +43 -0
- package/dist/components/render-edit-logic.d.ts +6 -0
- package/dist/components/render-edit-logic.js +63 -0
- package/dist/components/render-edit-types.d.ts +209 -0
- package/dist/components/render-edit-types.js +1 -0
- package/dist/components/render-edit.d.ts +6 -0
- package/dist/components/render-edit.js +1169 -0
- package/dist/components/render-field.d.ts +38 -0
- package/dist/components/render-field.js +544 -0
- package/dist/components/render-list.d.ts +117 -0
- package/dist/components/render-list.js +232 -0
- package/dist/components/write-form-section.d.ts +17 -0
- package/dist/components/write-form-section.js +104 -0
- package/dist/context/dispatcher-context.d.ts +10 -0
- package/{src/context/dispatcher-context.tsx → dist/context/dispatcher-context.js} +16 -29
- package/dist/context/draft-storage-context.d.ts +12 -0
- package/dist/context/draft-storage-context.js +18 -0
- package/dist/context/user-roles-context.d.ts +7 -0
- package/{src/context/user-roles-context.tsx → dist/context/user-roles-context.js} +7 -15
- package/dist/format-when.d.ts +1 -0
- package/{src/format-when.ts → dist/format-when.js} +7 -7
- package/dist/hooks/reference-limits.d.ts +3 -0
- package/{src/hooks/reference-limits.ts → dist/hooks/reference-limits.js} +0 -1
- package/dist/hooks/use-ai-text.d.ts +52 -0
- package/dist/hooks/use-ai-text.js +90 -0
- package/dist/hooks/use-disclosure.d.ts +7 -0
- package/dist/hooks/use-disclosure.js +8 -0
- package/dist/hooks/use-form.d.ts +7 -0
- package/dist/hooks/use-form.js +36 -0
- package/dist/hooks/use-list-url-state.d.ts +43 -0
- package/dist/hooks/use-list-url-state.js +131 -0
- package/dist/hooks/use-mutation.d.ts +9 -0
- package/dist/hooks/use-mutation.js +37 -0
- package/dist/hooks/use-query.d.ts +14 -0
- package/dist/hooks/use-query.js +118 -0
- package/dist/hooks/use-reference-lookup.d.ts +14 -0
- package/dist/hooks/use-reference-lookup.js +63 -0
- package/dist/hooks/use-store.d.ts +3 -0
- package/dist/hooks/use-store.js +38 -0
- package/dist/hooks/use-stream-handler.d.ts +14 -0
- package/dist/hooks/use-stream-handler.js +93 -0
- package/dist/i18n-defaults.d.ts +2 -0
- package/dist/i18n-defaults.js +201 -0
- package/dist/i18n.d.ts +64 -0
- package/dist/i18n.js +166 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +55 -0
- package/dist/inside-drawer.d.ts +2 -0
- package/dist/inside-drawer.js +9 -0
- package/dist/page-header-slot.d.ts +2 -0
- package/dist/page-header-slot.js +9 -0
- package/dist/primitives.d.ts +1351 -0
- package/dist/primitives.js +73 -0
- package/dist/screen-fills-height.d.ts +3 -0
- package/dist/screen-fills-height.js +3 -0
- package/dist/share-links.d.ts +4 -0
- package/dist/share-links.js +11 -0
- package/dist/sort-by-accessor.d.ts +5 -0
- package/dist/sort-by-accessor.js +16 -0
- package/dist/sse/live-events.d.ts +23 -0
- package/dist/sse/live-events.js +28 -0
- package/dist/tokens.d.ts +83 -0
- package/dist/tokens.js +80 -0
- package/package.json +16 -9
- package/src/changes.json +52 -0
- package/src/__tests__/error-i18n-defaults.test.ts +0 -82
- package/src/__tests__/format-when.test.ts +0 -12
- package/src/__tests__/i18n.test.tsx +0 -283
- package/src/__tests__/merge-search-params-into-initial.test.ts +0 -525
- package/src/__tests__/qn.test.ts +0 -83
- package/src/__tests__/share-links.test.ts +0 -26
- package/src/__tests__/sort-by-accessor.test.ts +0 -48
- package/src/__tests__/stringify-nav-params.test.ts +0 -33
- package/src/__tests__/use-list-url-state.test.tsx +0 -250
- package/src/app/__tests__/action-form-field-labels.test.tsx +0 -92
- package/src/app/__tests__/action-form-shim.test.ts +0 -137
- package/src/app/__tests__/build-list-query-payload.test.ts +0 -107
- package/src/app/__tests__/config-edit-shim.test.ts +0 -57
- package/src/app/__tests__/content-editors.test.tsx +0 -128
- package/src/app/__tests__/content-preview.test.tsx +0 -184
- package/src/app/__tests__/entity-edit-create-search-params.test.tsx +0 -236
- package/src/app/__tests__/entity-edit-jsonb-embedded-submit.test.tsx +0 -239
- package/src/app/__tests__/entity-list-create-singleton.test.tsx +0 -128
- package/src/app/__tests__/entity-list-row-action-entity-target.test.tsx +0 -424
- package/src/app/__tests__/entity-list-row-action-icon.test.tsx +0 -248
- package/src/app/__tests__/entity-list-row-action-kumiko-actions-view.test.tsx +0 -162
- package/src/app/__tests__/entity-list-row-action-refetch.test.tsx +0 -401
- package/src/app/__tests__/entity-list-screen-padding.test.tsx +0 -111
- package/src/app/__tests__/feature-schema.test.ts +0 -40
- package/src/app/__tests__/form-schema.test.ts +0 -247
- package/src/app/__tests__/list-daterange-facet.test.ts +0 -165
- package/src/app/__tests__/list-filter-facets.test.tsx +0 -521
- package/src/app/__tests__/nav.test.ts +0 -198
- package/src/app/__tests__/projection-detail-actions.test.tsx +0 -719
- package/src/app/__tests__/projection-detail-reference-field.test.tsx +0 -165
- package/src/app/__tests__/projection-detail-shim.test.ts +0 -188
- package/src/app/__tests__/projection-detail-singleton.test.tsx +0 -191
- package/src/app/__tests__/projection-list-bad-shape.test.tsx +0 -152
- package/src/app/__tests__/projection-list-reference-column.test.tsx +0 -219
- package/src/app/__tests__/projection-list-search-sort.test.tsx +0 -212
- package/src/app/__tests__/qualified-names.test.ts +0 -37
- package/src/app/__tests__/return-to.test.ts +0 -396
- package/src/app/__tests__/row-actions-navigate-tab.test.ts +0 -223
- package/src/app/__tests__/row-default-edit-action.test.tsx +0 -324
- package/src/app/__tests__/screen-access-allows.test.ts +0 -34
- package/src/app/__tests__/secret-mint-body.test.tsx +0 -404
- package/src/app/__tests__/variable-chips.test.tsx +0 -70
- package/src/app/app-features-context.tsx +0 -25
- package/src/app/column-renderers.tsx +0 -68
- package/src/app/content-editors.tsx +0 -85
- package/src/app/content-preview.tsx +0 -67
- package/src/app/custom-screens.tsx +0 -29
- package/src/app/dashboard-body.tsx +0 -33
- package/src/app/extension-form-submit.tsx +0 -123
- package/src/app/extension-sections.tsx +0 -111
- package/src/app/form-schema.ts +0 -91
- package/src/app/kumiko-screen.tsx +0 -3614
- package/src/app/layout-fields.ts +0 -31
- package/src/app/list-facets.ts +0 -259
- package/src/app/nav.tsx +0 -258
- package/src/app/projection-detail-shim.ts +0 -85
- package/src/app/reference-facet-bridge.tsx +0 -58
- package/src/app/return-to.tsx +0 -234
- package/src/app/row-actions.ts +0 -639
- package/src/app/screen-access.ts +0 -63
- package/src/app/secret-mint-body.tsx +0 -259
- package/src/app/secrets-edit-body.tsx +0 -194
- package/src/app/use-embedded-screen.ts +0 -27
- package/src/app/variable-chips.tsx +0 -39
- package/src/app/write-failed-error.ts +0 -27
- package/src/components/__tests__/embedded-list-field.test.tsx +0 -531
- package/src/components/__tests__/multi-select-checkboxes.test.tsx +0 -162
- package/src/components/__tests__/related-list-section-empty-state.test.tsx +0 -143
- package/src/components/__tests__/related-list-section.test.tsx +0 -1669
- package/src/components/__tests__/render-edit-action-button.test.tsx +0 -205
- package/src/components/__tests__/render-edit-hidden-section.test.tsx +0 -128
- package/src/components/__tests__/render-edit-logic.test.ts +0 -314
- package/src/components/__tests__/render-edit-screen-description.test.tsx +0 -152
- package/src/components/__tests__/render-edit-submit-actions.test.tsx +0 -460
- package/src/components/__tests__/render-field-app-locale.test.tsx +0 -142
- package/src/components/__tests__/render-field-enum-option.test.tsx +0 -99
- package/src/components/__tests__/render-field-icon-derivation.test.tsx +0 -119
- package/src/components/__tests__/render-field-json-format.test.tsx +0 -164
- package/src/components/__tests__/render-field-money-embedded-list-consistency.test.tsx +0 -212
- package/src/components/__tests__/render-field-money-roundtrip.test.tsx +0 -217
- package/src/components/__tests__/render-field-number-grouping.test.tsx +0 -76
- package/src/components/__tests__/render-field-number-unit.test.tsx +0 -227
- package/src/components/__tests__/render-field-password-format.test.tsx +0 -101
- package/src/components/__tests__/render-field-select-display.test.tsx +0 -134
- package/src/components/__tests__/render-field-unit-format.test.tsx +0 -107
- package/src/components/__tests__/render-field-unsupported-types.test.tsx +0 -195
- package/src/components/__tests__/render-list-toolbar-icon-only.test.tsx +0 -146
- package/src/components/__tests__/write-form-section.test.tsx +0 -375
- package/src/components/embedded-list-field.tsx +0 -354
- package/src/components/grid-cell-for-field.tsx +0 -60
- package/src/components/multi-select-checkboxes.tsx +0 -93
- package/src/components/reference-create-dialog.tsx +0 -91
- package/src/components/related-list-section.tsx +0 -467
- package/src/components/render-edit-action-button.tsx +0 -106
- package/src/components/render-edit-logic.ts +0 -85
- package/src/components/render-edit-types.ts +0 -216
- package/src/components/render-edit.tsx +0 -1700
- package/src/components/render-field.tsx +0 -942
- package/src/components/render-list.tsx +0 -561
- package/src/components/write-form-section.tsx +0 -199
- package/src/context/draft-storage-context.tsx +0 -39
- package/src/hooks/__tests__/use-ai-text.test.tsx +0 -177
- package/src/hooks/__tests__/use-disclosure.test.tsx +0 -25
- package/src/hooks/__tests__/use-form.test.tsx +0 -65
- package/src/hooks/__tests__/use-mutation.test.tsx +0 -77
- package/src/hooks/__tests__/use-stream-handler.test.tsx +0 -107
- package/src/hooks/use-ai-text.ts +0 -172
- package/src/hooks/use-disclosure.ts +0 -20
- package/src/hooks/use-form.ts +0 -78
- package/src/hooks/use-list-url-state.ts +0 -171
- package/src/hooks/use-mutation.ts +0 -61
- package/src/hooks/use-query.ts +0 -132
- package/src/hooks/use-reference-lookup.ts +0 -76
- package/src/hooks/use-store.ts +0 -48
- package/src/hooks/use-stream-handler.ts +0 -134
- package/src/i18n-defaults.ts +0 -220
- package/src/i18n.tsx +0 -286
- package/src/index.ts +0 -272
- package/src/primitives.tsx +0 -1446
- package/src/share-links.ts +0 -12
- package/src/sort-by-accessor.ts +0 -20
- package/src/sse/live-events.tsx +0 -56
- package/src/tokens.tsx +0 -170
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
// Regression #1834: field types without a dedicated widget (embedded
|
|
2
|
-
// without embeddedListCells, jsonb, files, images) must render read-only
|
|
3
|
-
// instead of falling back to a text input. The old default-branch
|
|
4
|
-
// fallback ran the value through stringValue() — an object/array turned
|
|
5
|
-
// into "[object Object]"/"a,b", and saving that overwrote the real data.
|
|
6
|
-
// #1925 gave multiSelect a real combobox widget (so it dropped out of this
|
|
7
|
-
// list) and moved files/images in (no multi-upload widget yet, deliberately
|
|
8
|
-
// deferred — they used to hit the same text-input corruption via the
|
|
9
|
-
// default branch).
|
|
10
|
-
//
|
|
11
|
-
// Capture-Input/Banner instead of real primitives, same pattern as
|
|
12
|
-
// render-field-app-locale.test.tsx.
|
|
13
|
-
|
|
14
|
-
import { describe, expect, test } from "bun:test";
|
|
15
|
-
import type { EditFieldViewModel } from "@cosmicdrift/kumiko-headless";
|
|
16
|
-
import { render } from "@testing-library/react";
|
|
17
|
-
import type { ComponentType, ReactNode } from "react";
|
|
18
|
-
import { createStaticLocaleResolver, LocaleProvider } from "../../i18n";
|
|
19
|
-
import { kumikoDefaultTranslations } from "../../i18n-defaults";
|
|
20
|
-
import {
|
|
21
|
-
type BannerProps,
|
|
22
|
-
type CorePrimitives,
|
|
23
|
-
type InputProps,
|
|
24
|
-
PrimitivesProvider,
|
|
25
|
-
} from "../../primitives";
|
|
26
|
-
import { RenderField } from "../render-field";
|
|
27
|
-
|
|
28
|
-
let capturedInput: InputProps | undefined;
|
|
29
|
-
let capturedBanner: BannerProps | undefined;
|
|
30
|
-
const captureInput: ComponentType<InputProps> = (props) => {
|
|
31
|
-
capturedInput = props;
|
|
32
|
-
return null;
|
|
33
|
-
};
|
|
34
|
-
const captureBanner: ComponentType<BannerProps> = (props) => {
|
|
35
|
-
capturedBanner = props;
|
|
36
|
-
return null;
|
|
37
|
-
};
|
|
38
|
-
const noop = (): ReactNode => null;
|
|
39
|
-
const passChildren = ({ children }: { readonly children?: ReactNode }): ReactNode => children;
|
|
40
|
-
|
|
41
|
-
const testPrimitives: CorePrimitives = {
|
|
42
|
-
Button: noop,
|
|
43
|
-
Banner: captureBanner,
|
|
44
|
-
Field: passChildren,
|
|
45
|
-
Input: captureInput,
|
|
46
|
-
DataTable: noop,
|
|
47
|
-
Form: noop,
|
|
48
|
-
Section: noop,
|
|
49
|
-
Card: noop,
|
|
50
|
-
Grid: noop,
|
|
51
|
-
GridCell: noop,
|
|
52
|
-
Text: noop,
|
|
53
|
-
Heading: noop,
|
|
54
|
-
Dialog: noop,
|
|
55
|
-
Modal: noop,
|
|
56
|
-
Lightbox: noop,
|
|
57
|
-
ConfigSourceBadge: noop,
|
|
58
|
-
ConfigCascadeView: noop,
|
|
59
|
-
Link: noop,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
function baseField(overrides: Partial<EditFieldViewModel>): EditFieldViewModel {
|
|
63
|
-
return {
|
|
64
|
-
field: "positions",
|
|
65
|
-
label: "Positionen",
|
|
66
|
-
type: "text",
|
|
67
|
-
value: null,
|
|
68
|
-
visible: true,
|
|
69
|
-
readOnly: false,
|
|
70
|
-
required: false,
|
|
71
|
-
...overrides,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function renderField(field: EditFieldViewModel): void {
|
|
76
|
-
capturedInput = undefined;
|
|
77
|
-
capturedBanner = undefined;
|
|
78
|
-
render(
|
|
79
|
-
<LocaleProvider
|
|
80
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
81
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
82
|
-
>
|
|
83
|
-
<PrimitivesProvider value={testPrimitives}>
|
|
84
|
-
<RenderField field={field} onChange={() => {}} />
|
|
85
|
-
</PrimitivesProvider>
|
|
86
|
-
</LocaleProvider>,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
describe.each([
|
|
91
|
-
["embedded (kein embeddedListCells)", baseField({ type: "embedded", value: { note: "x" } })],
|
|
92
|
-
["jsonb", baseField({ type: "jsonb", value: { a: 1 } })],
|
|
93
|
-
["files", baseField({ type: "files", value: ["11111111-1111-1111-1111-111111111111"] })],
|
|
94
|
-
["images", baseField({ type: "images", value: ["11111111-1111-1111-1111-111111111111"] })],
|
|
95
|
-
])("RenderField — %s ohne Widget", (_name, field) => {
|
|
96
|
-
test("rendert einen schreibgeschützten Banner statt eines editierbaren Text-Inputs", () => {
|
|
97
|
-
renderField(field);
|
|
98
|
-
expect(capturedInput).toBeUndefined();
|
|
99
|
-
expect(capturedBanner).toBeDefined();
|
|
100
|
-
expect(capturedBanner?.variant).toBe("info");
|
|
101
|
-
// The surrounding <Field> always renders a <label htmlFor={id}> —
|
|
102
|
-
// without an id on the Banner itself that label points at nothing (#1834 review).
|
|
103
|
-
expect(capturedBanner?.id).toBe("kumiko-edit-positions");
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// #1847#6: the Banner used to show only the generic hint, hiding the
|
|
107
|
-
// actual field value from the user entirely (not even read-only).
|
|
108
|
-
test("shows the underlying value read-only alongside the generic hint", () => {
|
|
109
|
-
renderField(field);
|
|
110
|
-
const children = capturedBanner?.children;
|
|
111
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
112
|
-
expect(childArray[0]).toBe("This field type can't be edited here yet.");
|
|
113
|
-
const valuePreview = childArray[1] as { props: { children: unknown } } | false | undefined;
|
|
114
|
-
if (!valuePreview) throw new Error("expected a value-preview element");
|
|
115
|
-
expect(valuePreview.props.children).toBe(JSON.stringify(field.value));
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("RenderField — unsupported-type Banner ohne Wert", () => {
|
|
120
|
-
test("kein Value-Preview-Element wenn field.value leer ist", () => {
|
|
121
|
-
renderField(baseField({ type: "jsonb", value: null }));
|
|
122
|
-
const children = capturedBanner?.children;
|
|
123
|
-
const childArray = Array.isArray(children) ? children : [children];
|
|
124
|
-
expect(childArray[0]).toBe("This field type can't be edited here yet.");
|
|
125
|
-
expect(childArray[1]).toBeFalsy();
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
describe("RenderField — text bleibt weiterhin editierbar", () => {
|
|
130
|
-
test("plain text-Feld rendert weiterhin ein Text-Input, kein Banner", () => {
|
|
131
|
-
renderField(baseField({ type: "text", value: "hallo" }));
|
|
132
|
-
expect(capturedBanner).toBeUndefined();
|
|
133
|
-
expect(capturedInput).toBeDefined();
|
|
134
|
-
expect(capturedInput?.kind).toBe("text");
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// #1925: field types that gained a real widget on the auto-wired
|
|
139
|
-
// entityEdit path (previously either no widget at all or a type-mismatched
|
|
140
|
-
// text-input fallback).
|
|
141
|
-
describe("RenderField — #1925 neue Widgets", () => {
|
|
142
|
-
test("multiSelect rendert eine Multi-Combobox statt eines Banners", () => {
|
|
143
|
-
renderField(
|
|
144
|
-
baseField({
|
|
145
|
-
type: "multiSelect",
|
|
146
|
-
value: ["a"],
|
|
147
|
-
options: ["a", "b"],
|
|
148
|
-
}),
|
|
149
|
-
);
|
|
150
|
-
expect(capturedBanner).toBeUndefined();
|
|
151
|
-
expect(capturedInput).toBeDefined();
|
|
152
|
-
expect(capturedInput?.kind).toBe("combobox");
|
|
153
|
-
if (capturedInput?.kind !== "combobox") return;
|
|
154
|
-
expect(capturedInput.multiple).toBe(true);
|
|
155
|
-
expect(capturedInput.value).toEqual(["a"]);
|
|
156
|
-
expect(capturedInput.options).toEqual([
|
|
157
|
-
{ value: "a", label: "a" },
|
|
158
|
-
{ value: "b", label: "b" },
|
|
159
|
-
]);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test("decimal rendert ein number-Input statt Text (kein String-Fallback mehr)", () => {
|
|
163
|
-
renderField(baseField({ type: "decimal", value: 12.5 }));
|
|
164
|
-
expect(capturedBanner).toBeUndefined();
|
|
165
|
-
expect(capturedInput).toBeDefined();
|
|
166
|
-
expect(capturedInput?.kind).toBe("number");
|
|
167
|
-
if (capturedInput?.kind !== "number") return;
|
|
168
|
-
expect(capturedInput.value).toBe(12.5);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("bigInt rendert ein number-Input statt Text (kein String-Fallback mehr)", () => {
|
|
172
|
-
renderField(baseField({ type: "bigInt", value: 42 }));
|
|
173
|
-
expect(capturedBanner).toBeUndefined();
|
|
174
|
-
expect(capturedInput).toBeDefined();
|
|
175
|
-
expect(capturedInput?.kind).toBe("number");
|
|
176
|
-
if (capturedInput?.kind !== "number") return;
|
|
177
|
-
expect(capturedInput.value).toBe(42);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test("tz rendert ein dediziertes tz-Input statt Text", () => {
|
|
181
|
-
renderField(baseField({ type: "tz", value: "Europe/Berlin" }));
|
|
182
|
-
expect(capturedBanner).toBeUndefined();
|
|
183
|
-
expect(capturedInput).toBeDefined();
|
|
184
|
-
expect(capturedInput?.kind).toBe("tz");
|
|
185
|
-
if (capturedInput?.kind !== "tz") return;
|
|
186
|
-
expect(capturedInput.value).toBe("Europe/Berlin");
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test("longText rendert immer ein textarea, auch ohne explizites multiline-Flag", () => {
|
|
190
|
-
renderField(baseField({ type: "longText", value: "lange Notiz" }));
|
|
191
|
-
expect(capturedBanner).toBeUndefined();
|
|
192
|
-
expect(capturedInput).toBeDefined();
|
|
193
|
-
expect(capturedInput?.kind).toBe("textarea");
|
|
194
|
-
});
|
|
195
|
-
});
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
// ToolbarActionView collapses a group of >2 icon-carrying toolbar actions to
|
|
2
|
-
// icon-only buttons (`shouldRenderActionsIconOnly`). The button then has no
|
|
3
|
-
// accessible name from its children, so the label has to move to `ariaLabel`
|
|
4
|
-
// and must NOT stay in the children — otherwise the text renders inside a
|
|
5
|
-
// button sized for an icon.
|
|
6
|
-
|
|
7
|
-
import { describe, expect, test } from "bun:test";
|
|
8
|
-
import type {
|
|
9
|
-
EntityDefinition,
|
|
10
|
-
EntityListScreenDefinition,
|
|
11
|
-
} from "@cosmicdrift/kumiko-framework/ui-types";
|
|
12
|
-
import { render, screen as rtlScreen } from "@testing-library/react";
|
|
13
|
-
import type { ComponentType, ReactNode } from "react";
|
|
14
|
-
import { createStaticLocaleResolver, LocaleProvider } from "../../i18n";
|
|
15
|
-
import { kumikoDefaultTranslations } from "../../i18n-defaults";
|
|
16
|
-
import {
|
|
17
|
-
type ButtonProps,
|
|
18
|
-
type CorePrimitives,
|
|
19
|
-
type DataTableProps,
|
|
20
|
-
PrimitivesProvider,
|
|
21
|
-
} from "../../primitives";
|
|
22
|
-
import { RenderList, type ToolbarActionButton } from "../render-list";
|
|
23
|
-
|
|
24
|
-
const TestButton: ComponentType<ButtonProps> = ({ children, onClick, testId, ariaLabel, size }) => (
|
|
25
|
-
<button
|
|
26
|
-
type="button"
|
|
27
|
-
data-testid={testId}
|
|
28
|
-
data-size={size ?? "md"}
|
|
29
|
-
aria-label={ariaLabel}
|
|
30
|
-
onClick={() => {
|
|
31
|
-
void onClick?.();
|
|
32
|
-
}}
|
|
33
|
-
>
|
|
34
|
-
{children}
|
|
35
|
-
</button>
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
const toolbarOnlyDataTable: ComponentType<DataTableProps> = ({ toolbarEnd }) => (
|
|
39
|
-
<div>{toolbarEnd}</div>
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
const noop = (): ReactNode => null;
|
|
43
|
-
const passChildren = ({ children }: { readonly children?: ReactNode }): ReactNode => children;
|
|
44
|
-
|
|
45
|
-
const testPrimitives: CorePrimitives = {
|
|
46
|
-
Button: TestButton,
|
|
47
|
-
Banner: passChildren,
|
|
48
|
-
Field: passChildren,
|
|
49
|
-
Input: noop,
|
|
50
|
-
DataTable: toolbarOnlyDataTable,
|
|
51
|
-
Form: passChildren,
|
|
52
|
-
Section: passChildren,
|
|
53
|
-
Card: passChildren,
|
|
54
|
-
Grid: passChildren,
|
|
55
|
-
GridCell: passChildren,
|
|
56
|
-
Text: passChildren,
|
|
57
|
-
Heading: noop,
|
|
58
|
-
Dialog: noop,
|
|
59
|
-
Modal: noop,
|
|
60
|
-
Lightbox: noop,
|
|
61
|
-
ConfigSourceBadge: noop,
|
|
62
|
-
ConfigCascadeView: noop,
|
|
63
|
-
Link: noop,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const entity: EntityDefinition = {
|
|
67
|
-
fields: {
|
|
68
|
-
name: { type: "text", maxLength: 50, required: false, searchable: false, sortable: false },
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const listScreen: EntityListScreenDefinition = {
|
|
73
|
-
id: "widget-list",
|
|
74
|
-
type: "entityList",
|
|
75
|
-
entity: "widget",
|
|
76
|
-
columns: ["name"],
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
function toolbarAction(id: string, label: string, withIcon: boolean): ToolbarActionButton {
|
|
80
|
-
return {
|
|
81
|
-
id,
|
|
82
|
-
label,
|
|
83
|
-
onTrigger: () => {},
|
|
84
|
-
...(withIcon && { icon: "archive" as const }),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function renderToolbar(actions: readonly ToolbarActionButton[]): void {
|
|
89
|
-
render(
|
|
90
|
-
<LocaleProvider
|
|
91
|
-
resolver={createStaticLocaleResolver({ locale: "en" })}
|
|
92
|
-
fallbackBundles={[kumikoDefaultTranslations]}
|
|
93
|
-
>
|
|
94
|
-
<PrimitivesProvider value={testPrimitives}>
|
|
95
|
-
<RenderList
|
|
96
|
-
screen={listScreen}
|
|
97
|
-
entity={entity}
|
|
98
|
-
rows={[]}
|
|
99
|
-
featureName="toolbar-fixture"
|
|
100
|
-
toolbarActions={actions}
|
|
101
|
-
/>
|
|
102
|
-
</PrimitivesProvider>
|
|
103
|
-
</LocaleProvider>,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
describe("RenderList toolbar actions collapse to icon-only", () => {
|
|
108
|
-
test("three icon actions render buttons with no visible text but an aria-label", () => {
|
|
109
|
-
renderToolbar([
|
|
110
|
-
toolbarAction("sync", "Sync", true),
|
|
111
|
-
toolbarAction("export", "Export", true),
|
|
112
|
-
toolbarAction("archive", "Archive", true),
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
|
-
for (const [id, label] of [
|
|
116
|
-
["sync", "Sync"],
|
|
117
|
-
["export", "Export"],
|
|
118
|
-
["archive", "Archive"],
|
|
119
|
-
] as const) {
|
|
120
|
-
const button = rtlScreen.getByTestId(`render-list-toolbar-action-${id}`);
|
|
121
|
-
expect(button.getAttribute("data-size")).toBe("icon");
|
|
122
|
-
expect(button.getAttribute("aria-label")).toBe(label);
|
|
123
|
-
expect(button.textContent).toBe("");
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("two actions stay on text buttons carrying the label as children", () => {
|
|
128
|
-
renderToolbar([toolbarAction("sync", "Sync", true), toolbarAction("export", "Export", true)]);
|
|
129
|
-
|
|
130
|
-
const button = rtlScreen.getByTestId("render-list-toolbar-action-sync");
|
|
131
|
-
expect(button.getAttribute("data-size")).toBe("md");
|
|
132
|
-
expect(button.textContent).toBe("Sync");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test("an icon-less member keeps the whole group on text buttons", () => {
|
|
136
|
-
renderToolbar([
|
|
137
|
-
toolbarAction("sync", "Sync", true),
|
|
138
|
-
toolbarAction("export", "Export", true),
|
|
139
|
-
toolbarAction("archive", "Archive", false),
|
|
140
|
-
]);
|
|
141
|
-
|
|
142
|
-
const button = rtlScreen.getByTestId("render-list-toolbar-action-sync");
|
|
143
|
-
expect(button.getAttribute("data-size")).toBe("md");
|
|
144
|
-
expect(button.textContent).toBe("Sync");
|
|
145
|
-
});
|
|
146
|
-
});
|