@object-ui/components 11.2.0 → 11.4.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/CHANGELOG.md +164 -0
- package/dist/context/gridFieldAuthoring.d.ts +33 -0
- package/dist/custom/mobile-dialog-content.d.ts +27 -0
- package/dist/index.css +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3689 -3307
- package/dist/index.umd.cjs +6 -6
- package/dist/renderers/basic/html-elements.d.ts +23 -0
- package/dist/renderers/layout/react-page.d.ts +33 -0
- package/package.json +17 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,169 @@
|
|
|
1
1
|
# @object-ui/components
|
|
2
2
|
|
|
3
|
+
## 11.4.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1948c5b: fix(plugin-grid): keep the grid's row selection in sync when a bulk-action dialog closes
|
|
8
|
+
|
|
9
|
+
Closing a bulk-action result dialog (e.g. 派工 / 下推) on **Done** cleared
|
|
10
|
+
ObjectGrid's `selectedRows` — which drives the selection toolbar — but never
|
|
11
|
+
touched the DataTable's internal checkbox state. Two visible problems:
|
|
12
|
+
|
|
13
|
+
- **Desync on success.** The toolbar disappeared while every row stayed visibly
|
|
14
|
+
ticked, because the checkboxes are table-internal state the grid couldn't
|
|
15
|
+
reach.
|
|
16
|
+
|
|
17
|
+
- **Lost selection on total failure.** When the run failed for _every_ row
|
|
18
|
+
(0 succeeded — a precondition error, say), the toolbar still vanished,
|
|
19
|
+
stranding the user with no way to retry the exact rows they'd picked.
|
|
20
|
+
|
|
21
|
+
The dialog-close handler now gates the reset on `result.succeeded > 0`: a total
|
|
22
|
+
failure keeps both the selection _and_ the toolbar (and skips the phantom
|
|
23
|
+
refetch) so the user can fix the cause and retry. When it does reset, a new
|
|
24
|
+
`selectionResetKey` prop on DataTable clears the internal checkbox selection in
|
|
25
|
+
lockstep with the toolbar, so the two never drift apart.
|
|
26
|
+
|
|
27
|
+
- bce581a: Fix dependent (cascading) lookups: unlock on parent selection and enforce the
|
|
28
|
+
cascade filter on every candidate surface (#2215).
|
|
29
|
+
|
|
30
|
+
Two breaks made `depends_on` unusable end to end:
|
|
31
|
+
|
|
32
|
+
- **The gate never unlocked in create mode.** `LookupField` resolved dependent
|
|
33
|
+
values from `ctx.formValues` — a member `SchemaRendererContext` never had —
|
|
34
|
+
and nothing injected the `dependentValues` prop, so with a fresh record
|
|
35
|
+
(`ctx.data = {}`) the child lookup stayed disabled no matter what the user
|
|
36
|
+
picked in the parent field. The form renderer now injects its live form
|
|
37
|
+
values (the same reactive snapshot that drives field rules) as
|
|
38
|
+
`dependentValues` for data-source fields.
|
|
39
|
+
- **The Level-2 table picker bypassed the cascade.** The `depends_on` chain
|
|
40
|
+
only reached the quick-select popover filter; `RecordPickerDialog` (and the
|
|
41
|
+
search-first `PeoplePicker`) received just `lookup_filters`, listing the full
|
|
42
|
+
unfiltered record set. Both pickers now take a `baseFilter` — a hard
|
|
43
|
+
`$filter` constraint merged after `lookupFilters` and user filter-bar input,
|
|
44
|
+
so it can never be widened back out — and `LookupField` passes the dependent
|
|
45
|
+
chain there, shares the same filter with the popover query, and disables the
|
|
46
|
+
browse-all button while dependencies are missing.
|
|
47
|
+
|
|
48
|
+
- c38d107: Fix view-level `FormField.visibleOn` (CEL) never taking effect (#2212).
|
|
49
|
+
|
|
50
|
+
The spec ships `visibleOn` as an Expression object `{ dialect: 'cel', source }`
|
|
51
|
+
(what the `P` template emits) or a bare string, but the whole chain dropped it:
|
|
52
|
+
|
|
53
|
+
- `sectionFields.ts` / `ObjectForm.tsx` only accepted the bare-string shape and
|
|
54
|
+
attached a dead `visible()` closure no renderer ever called — the Expression
|
|
55
|
+
object shape was silently discarded.
|
|
56
|
+
- The form renderer destructured `visibleOn` out of the field config and never
|
|
57
|
+
evaluated it.
|
|
58
|
+
- `RecordFormPage` dropped a `simple` form view's `sections` entirely, so
|
|
59
|
+
page-mode create/edit fell back to the raw schema (every field, no authored
|
|
60
|
+
selection/grouping) while the modal path honored the same view.
|
|
61
|
+
- `ObjectForm`'s grouped-sections path matched section fields by name only,
|
|
62
|
+
dropping per-field `visibleOn` overrides.
|
|
63
|
+
|
|
64
|
+
`visibleOn` now flows through normalization verbatim (both wire shapes) and is
|
|
65
|
+
evaluated reactively by the form renderer with the canonical expression engine
|
|
66
|
+
(`evalFieldPredicate` — same engine, record scope, and fail-open semantics as
|
|
67
|
+
field-level `visibleWhen`; both predicates must allow a field for it to show).
|
|
68
|
+
Sectioned/flat normalization also copies field-level `visibleWhen` /
|
|
69
|
+
`readonlyWhen` / `requiredWhen` rules it previously lost.
|
|
70
|
+
|
|
71
|
+
- 7782698: fix(components): page:header record title honours `nameField` via the unified ADR-0079 resolver
|
|
72
|
+
|
|
73
|
+
The default console record detail page renders the synthesized `page:header`
|
|
74
|
+
(`buildDefaultPageSchema`, renderViaSchema default-on), whose record-chip title
|
|
75
|
+
chain probed `objSchema.primaryField` (not a spec property — always undefined),
|
|
76
|
+
`titleFormat`, then hardcoded `name`/`full_name`/`title`/`subject`/
|
|
77
|
+
`display_name`/`label` record keys. It never consulted the object's declared
|
|
78
|
+
`nameField`/`displayNameField`, so an object titled by e.g. `subject` rendered
|
|
79
|
+
`<ObjectLabel> <id-prefix>` as its H1 instead of the record's real name.
|
|
80
|
+
|
|
81
|
+
`PageHeaderRenderer` now resolves through `getRecordDisplayName(objSchema, data,
|
|
82
|
+
{ deriveFromRecordKeys: false })` after the author overrides and before the
|
|
83
|
+
legacy probes — mirroring `DetailView.resolveDisplayTitle` so both headers
|
|
84
|
+
agree. `RecordDetailView`'s `primaryField` derivation and
|
|
85
|
+
`buildDefaultPageSchema`'s highlight-strip dedup also honour
|
|
86
|
+
`nameField`/`displayNameField`.
|
|
87
|
+
|
|
88
|
+
- e84d64d: Block record-scoped toolbar actions launched with zero rows selected (#2210).
|
|
89
|
+
|
|
90
|
+
A flow/script action that also mounts on list rows (`locations` includes
|
|
91
|
+
`list_item`) has no record to run on when triggered from the list toolbar with
|
|
92
|
+
nothing selected — pre-fix the wizard opened anyway, collected input, and died
|
|
93
|
+
at its first record-bound node ("Update requires an ID or options.multi=true").
|
|
94
|
+
The console runtime now blocks up front with "select a row first", mirroring
|
|
95
|
+
the existing multi-selection guard. Pure object-level toolbar actions
|
|
96
|
+
(`locations: ['list_toolbar']` only) keep triggering without a record.
|
|
97
|
+
|
|
98
|
+
The action renderers (button/icon/menu/group) now forward the `locations`
|
|
99
|
+
declaration to the ActionRunner — previously it was dropped by their
|
|
100
|
+
allow-list payloads, so the runtime could not tell the two shapes apart.
|
|
101
|
+
|
|
102
|
+
- Updated dependencies [8bf6295]
|
|
103
|
+
- Updated dependencies [1948c5b]
|
|
104
|
+
- Updated dependencies [9cd9be1]
|
|
105
|
+
- Updated dependencies [c38d107]
|
|
106
|
+
- Updated dependencies [790558b]
|
|
107
|
+
- @object-ui/types@11.4.0
|
|
108
|
+
- @object-ui/i18n@11.4.0
|
|
109
|
+
- @object-ui/core@11.4.0
|
|
110
|
+
- @object-ui/react@11.4.0
|
|
111
|
+
- @object-ui/react-runtime@11.4.0
|
|
112
|
+
- @object-ui/sdui-parser@11.4.0
|
|
113
|
+
|
|
114
|
+
## 11.3.0
|
|
115
|
+
|
|
116
|
+
### Minor Changes
|
|
117
|
+
|
|
118
|
+
- d23d6eb: Three-tier AI page authoring: `kind:'html'` and a trusted `kind:'react'` tier.
|
|
119
|
+
|
|
120
|
+
- **`@object-ui/react-runtime`** (new) — the trusted runtime-React tier for
|
|
121
|
+
`kind:'react'` pages (vendored react-runner: Sucrase transpile + scope-eval,
|
|
122
|
+
no sandbox). Renders real JSX/TSX (any HTML + JS + hooks/useState/map/onClick)
|
|
123
|
+
in the main React tree with an injected scope (React, the public data blocks,
|
|
124
|
+
page data) and a built-in error boundary.
|
|
125
|
+
- **`@object-ui/core`** — new runtime capability gate (`enableCapability` /
|
|
126
|
+
`disableCapability` / `isCapabilityEnabled`, `CAP_REACT_PAGES`). `react-pages`
|
|
127
|
+
defaults **ON** (the platform trusts reviewed, draft-gated authors); a
|
|
128
|
+
deployment turns it OFF server-side (the runtime injects the disable global
|
|
129
|
+
when `OS_DISABLE_REACT_PAGES` is set). Never controlled from authored metadata.
|
|
130
|
+
- **`@object-ui/components`** — PageRenderer now routes `kind:'react'`
|
|
131
|
+
(capability-gated, lazy-loads the runtime) and renders `kind:'html'` (the
|
|
132
|
+
former `kind:'jsx'`, still accepted as a deprecated alias). The `html` tier
|
|
133
|
+
now resolves the full safe native HTML tag set (h1–h6, p, a, ul/ol/li, img,
|
|
134
|
+
blockquote, pre, strong/em, …) so authored HTML lives up to its name.
|
|
135
|
+
|
|
136
|
+
### Patch Changes
|
|
137
|
+
|
|
138
|
+
- d88c8ec: fix(data-table): surface inline-edit save failures instead of swallowing them
|
|
139
|
+
|
|
140
|
+
A rejected inline-edit save (e.g. a 400 validation failure like an invalid
|
|
141
|
+
status transition) was caught with only `console.error` — the toolbar stayed
|
|
142
|
+
stuck, the cell kept the unsaved value, and the author got no feedback. Now the
|
|
143
|
+
data-table shows the server's reason in the toolbar (with an alert icon) and
|
|
144
|
+
tints the affected row(s) destructive so it's clear which rows didn't persist.
|
|
145
|
+
The pending edit is kept for retry; the error clears on a successful save or on
|
|
146
|
+
cancel. Adds the `table.saveFailed` string across all locales.
|
|
147
|
+
|
|
148
|
+
- b7237bb: fix(components): keep MobileDialogContent open when interacting with a portalled dropdown
|
|
149
|
+
|
|
150
|
+
Radix Select / Popover / DropdownMenu render their flyout into a portal at
|
|
151
|
+
`document.body`, outside the dialog's DOM. Clicking an empty part of an open
|
|
152
|
+
dropdown registered as an "interact outside" and closed the entire dialog
|
|
153
|
+
(create/edit forms). `MobileDialogContent` now guards `onInteractOutside`:
|
|
154
|
+
interactions whose real target is inside a Radix popper layer are ignored
|
|
155
|
+
(the popper dismisses itself), while a genuine backdrop click still closes the
|
|
156
|
+
dialog as before.
|
|
157
|
+
|
|
158
|
+
- Updated dependencies [d88c8ec]
|
|
159
|
+
- Updated dependencies [d23d6eb]
|
|
160
|
+
- @object-ui/i18n@11.3.0
|
|
161
|
+
- @object-ui/react-runtime@11.3.0
|
|
162
|
+
- @object-ui/core@11.3.0
|
|
163
|
+
- @object-ui/react@11.3.0
|
|
164
|
+
- @object-ui/types@11.3.0
|
|
165
|
+
- @object-ui/sdui-parser@11.3.0
|
|
166
|
+
|
|
3
167
|
## 11.2.0
|
|
4
168
|
|
|
5
169
|
### Minor Changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface GridFieldAuthoring {
|
|
3
|
+
/** Invoked when the user clicks the trailing "+" add-column header affordance. */
|
|
4
|
+
onAddColumn?: () => void;
|
|
5
|
+
/** Optional tooltip/aria-label for the add-column button (defaults to "Add field"). */
|
|
6
|
+
addColumnLabel?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Invoked when the user clicks the per-column "edit field" affordance in a
|
|
9
|
+
* column header (Airtable-style). Receives the column's accessorKey (= field
|
|
10
|
+
* name). Omit to hide the edit affordance.
|
|
11
|
+
*/
|
|
12
|
+
onEditColumn?: (fieldName: string) => void;
|
|
13
|
+
/** Optional tooltip/aria-label for the edit-field button (defaults to "Edit field"). */
|
|
14
|
+
editColumnLabel?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Invoked when the user drag-reorders columns. Receives the new column order
|
|
17
|
+
* as accessorKeys (= field names, including any non-field columns). Providing
|
|
18
|
+
* this also ENABLES the table's built-in column drag-reorder (design mode), so
|
|
19
|
+
* the host can persist the order to the object's field metadata. Omit to leave
|
|
20
|
+
* reordering to the table's own `reorderableColumns`/`onColumnsReorder`.
|
|
21
|
+
*/
|
|
22
|
+
onReorderFields?: (orderedFieldNames: string[]) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function GridFieldAuthoringProvider({ value, children, }: {
|
|
25
|
+
value: GridFieldAuthoring | null;
|
|
26
|
+
children: React.ReactNode;
|
|
27
|
+
}): React.ReactElement;
|
|
28
|
+
/**
|
|
29
|
+
* Read the ambient grid field-authoring affordances. Returns `null` outside a
|
|
30
|
+
* provider — design surfaces opt in by wrapping the table tree in
|
|
31
|
+
* {@link GridFieldAuthoringProvider}.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useGridFieldAuthoring(): GridFieldAuthoring | null;
|
|
@@ -17,4 +17,31 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import * as React from 'react';
|
|
19
19
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
20
|
+
/**
|
|
21
|
+
* True when `target` sits inside a Radix popper flyout (Select / Popover /
|
|
22
|
+
* DropdownMenu). Such elements are portalled to `document.body`, so an
|
|
23
|
+
* "interact outside" the dialog whose target is one of them is really an
|
|
24
|
+
* interaction with the dialog's own dropdown — it must not close the dialog.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isInsidePopperLayer(target: Element | null | undefined): boolean;
|
|
27
|
+
type InteractOutsideHandler = NonNullable<React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>['onInteractOutside']>;
|
|
28
|
+
/**
|
|
29
|
+
* Popper-aware interact-outside guard for Radix Dialog/Sheet content.
|
|
30
|
+
*
|
|
31
|
+
* Covers a second dismissal path `isInsidePopperLayer` alone cannot: with a
|
|
32
|
+
* dropdown OPEN, one outside click must only close the dropdown — but
|
|
33
|
+
* radix-dialog@1.1.17 defers its outside-pointerdown verdict to the `click`
|
|
34
|
+
* phase (`deferPointerDownOutside`), while radix-select@2.3.1 dismisses and
|
|
35
|
+
* unregisters on `pointerdown`. By the deferred verdict the dialog has become
|
|
36
|
+
* the top layer, so it treats the dropdown-closing click as its own outside
|
|
37
|
+
* click and dismisses too (#2156).
|
|
38
|
+
*
|
|
39
|
+
* The guard snapshots "was a popper flyout open?" on every `pointerdown`
|
|
40
|
+
* (document capture phase — runs before Radix's bubble-phase dismissal
|
|
41
|
+
* unmounts the flyout) and swallows the pointer-initiated interact-outside
|
|
42
|
+
* that follows. Focus-driven interact-outside (Tab out) is untouched, as is a
|
|
43
|
+
* plain backdrop click with no flyout open.
|
|
44
|
+
*/
|
|
45
|
+
export declare function usePopperAwareInteractOutside(onInteractOutside?: InteractOutsideHandler): InteractOutsideHandler;
|
|
20
46
|
export declare const MobileDialogContent: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
47
|
+
export {};
|
package/dist/index.css
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
--color-red-600: oklch(57.7% 0.245 27.325);
|
|
16
16
|
--color-red-700: oklch(50.5% 0.213 27.518);
|
|
17
17
|
--color-amber-50: oklch(98.7% 0.022 95.277);
|
|
18
|
+
--color-amber-200: oklch(92.4% 0.12 95.746);
|
|
18
19
|
--color-amber-300: oklch(87.9% 0.169 91.605);
|
|
19
20
|
--color-amber-400: oklch(82.8% 0.189 84.429);
|
|
20
21
|
--color-amber-700: oklch(55.5% 0.163 48.998);
|
|
@@ -1653,6 +1654,12 @@
|
|
|
1653
1654
|
.border-amber-300 {
|
|
1654
1655
|
border-color: var(--color-amber-300);
|
|
1655
1656
|
}
|
|
1657
|
+
.border-amber-400\/40 {
|
|
1658
|
+
border-color: color-mix(in srgb, oklch(82.8% 0.189 84.429) 40%, transparent);
|
|
1659
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1660
|
+
border-color: color-mix(in oklab, var(--color-amber-400) 40%, transparent);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1656
1663
|
.border-blue-300 {
|
|
1657
1664
|
border-color: var(--color-blue-300);
|
|
1658
1665
|
}
|
|
@@ -2282,6 +2289,9 @@
|
|
|
2282
2289
|
.text-amber-800 {
|
|
2283
2290
|
color: var(--color-amber-800);
|
|
2284
2291
|
}
|
|
2292
|
+
.text-amber-900 {
|
|
2293
|
+
color: var(--color-amber-900);
|
|
2294
|
+
}
|
|
2285
2295
|
.text-card-foreground {
|
|
2286
2296
|
color: var(--color-card-foreground);
|
|
2287
2297
|
}
|
|
@@ -2495,6 +2505,12 @@
|
|
|
2495
2505
|
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
|
2496
2506
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2497
2507
|
}
|
|
2508
|
+
.ring-destructive\/40 {
|
|
2509
|
+
--tw-ring-color: color-mix(in srgb, hsl(var(--destructive)) 40%, transparent);
|
|
2510
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
2511
|
+
--tw-ring-color: color-mix(in oklab, var(--color-destructive) 40%, transparent);
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2498
2514
|
.ring-primary {
|
|
2499
2515
|
--tw-ring-color: var(--color-primary);
|
|
2500
2516
|
}
|
|
@@ -2668,6 +2684,9 @@
|
|
|
2668
2684
|
.fade-in-80 {
|
|
2669
2685
|
--tw-enter-opacity: 0.8;
|
|
2670
2686
|
}
|
|
2687
|
+
.ring-inset {
|
|
2688
|
+
--tw-ring-inset: inset;
|
|
2689
|
+
}
|
|
2671
2690
|
.running {
|
|
2672
2691
|
animation-play-state: running;
|
|
2673
2692
|
}
|
|
@@ -5600,6 +5619,14 @@
|
|
|
5600
5619
|
}
|
|
5601
5620
|
}
|
|
5602
5621
|
}
|
|
5622
|
+
.dark\:bg-destructive\/15 {
|
|
5623
|
+
&:where(.dark, .dark *) {
|
|
5624
|
+
background-color: color-mix(in srgb, hsl(var(--destructive)) 15%, transparent);
|
|
5625
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
5626
|
+
background-color: color-mix(in oklab, var(--color-destructive) 15%, transparent);
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5603
5630
|
.dark\:bg-emerald-950\/50 {
|
|
5604
5631
|
&:where(.dark, .dark *) {
|
|
5605
5632
|
background-color: color-mix(in srgb, oklch(26.2% 0.051 172.552) 50%, transparent);
|
|
@@ -5608,6 +5635,11 @@
|
|
|
5608
5635
|
}
|
|
5609
5636
|
}
|
|
5610
5637
|
}
|
|
5638
|
+
.dark\:text-amber-200 {
|
|
5639
|
+
&:where(.dark, .dark *) {
|
|
5640
|
+
color: var(--color-amber-200);
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5611
5643
|
.dark\:text-amber-300 {
|
|
5612
5644
|
&:where(.dark, .dark *) {
|
|
5613
5645
|
color: var(--color-amber-300);
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { renderChildren } from './lib/utils';
|
|
|
3
3
|
export { cva } from 'class-variance-authority';
|
|
4
4
|
export { getLazyIcon, LazyIcon, toKebabIconName } from './lib/lazy-icon';
|
|
5
5
|
export { registerPlaceholders } from './renderers/placeholders';
|
|
6
|
+
export { GridFieldAuthoringProvider, useGridFieldAuthoring, type GridFieldAuthoring, } from './context/gridFieldAuthoring';
|
|
6
7
|
export * from './ui';
|
|
7
8
|
export * from './custom';
|
|
8
9
|
export { useConfigDraft } from './hooks/use-config-draft';
|