@object-ui/react 17.5.0 → 17.7.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 +4100 -0
- package/README.md +303 -46
- package/dist/LazyPluginLoader.d.ts +14 -7
- package/dist/LazyPluginLoader.js +14 -7
- package/dist/SchemaRenderer.d.ts +38 -7
- package/dist/SchemaRenderer.js +1603 -60
- package/dist/context/ActionContext.js +40 -1
- package/dist/context/DiscussionContext.d.ts +12 -0
- package/dist/context/DiscussionContext.js +2 -0
- package/dist/context/DrillNavigationContext.d.ts +13 -0
- package/dist/context/HostNavigationContext.d.ts +82 -0
- package/dist/context/HostNavigationContext.js +65 -0
- package/dist/context/InlineEditContext.d.ts +81 -1
- package/dist/context/InlineEditContext.js +8 -2
- package/dist/context/RecordContext.d.ts +48 -5
- package/dist/context/RecordContext.js +10 -1
- package/dist/context/RelatedRecordActionsContext.d.ts +20 -1
- package/dist/context/SchemaRendererContext.d.ts +54 -2
- package/dist/context/SchemaRendererContext.js +38 -5
- package/dist/context/ThemeContext.js +1 -1
- package/dist/context/actionRunnerTranslator.d.ts +27 -0
- package/dist/context/actionRunnerTranslator.js +37 -0
- package/dist/context/index.d.ts +13 -12
- package/dist/context/index.js +13 -12
- package/dist/element-data-source/ElementDataSourceGate.d.ts +163 -3
- package/dist/element-data-source/ElementDataSourceGate.js +407 -15
- package/dist/hooks/index.d.ts +37 -35
- package/dist/hooks/index.js +44 -35
- package/dist/hooks/useActionEngine.js +47 -4
- package/dist/hooks/useActionRunner.js +4 -0
- package/dist/hooks/useActionTextLocalizer.d.ts +21 -8
- package/dist/hooks/useActionTextLocalizer.js +33 -8
- package/dist/hooks/useCapabilityGate.js +6 -5
- package/dist/hooks/useConfigBagEvaluator.d.ts +30 -0
- package/dist/hooks/useConfigBagEvaluator.js +39 -0
- package/dist/hooks/useCrudShortcuts.js +1 -1
- package/dist/hooks/useDatasetDimensionLabels.js +1 -1
- package/dist/hooks/useDensityMode.d.ts +6 -2
- package/dist/hooks/useDensityMode.js +6 -2
- package/dist/hooks/useDiscovery.d.ts +1 -10
- package/dist/hooks/useDiscovery.js +1 -1
- package/dist/hooks/useETagCache.js +25 -4
- package/dist/hooks/useElementDataSource.d.ts +15 -2
- package/dist/hooks/useElementDataSource.js +29 -9
- package/dist/hooks/useExpression.d.ts +52 -38
- package/dist/hooks/useExpression.js +62 -42
- package/dist/hooks/useFilterScope.d.ts +22 -2
- package/dist/hooks/useFilterScope.js +29 -4
- package/dist/hooks/useGlobalUndo.d.ts +10 -0
- package/dist/hooks/useGlobalUndo.js +112 -46
- package/dist/hooks/useNavigationOverlay.d.ts +77 -12
- package/dist/hooks/useNavigationOverlay.js +119 -9
- package/dist/hooks/useOffline.js +65 -11
- package/dist/hooks/usePageAssignment.d.ts +8 -5
- package/dist/hooks/usePageAssignment.js +38 -17
- package/dist/hooks/usePageTransition.js +1 -1
- package/dist/hooks/usePageVariableActionBridge.js +2 -2
- package/dist/hooks/useRecordSearch.d.ts +34 -1
- package/dist/hooks/useRecordSearch.js +42 -7
- package/dist/hooks/useResolvedFilter.d.ts +46 -0
- package/dist/hooks/useResolvedFilter.js +130 -0
- package/dist/hooks/useSchemaPersistence.d.ts +7 -0
- package/dist/hooks/useSchemaPersistence.js +144 -5
- package/dist/hooks/useSettledSchema.d.ts +123 -0
- package/dist/hooks/useSettledSchema.js +186 -0
- package/dist/hooks/useViewData.d.ts +7 -2
- package/dist/hooks/useViewData.js +1 -1
- package/dist/hooks/useViewTransition.js +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.js +54 -10
- package/dist/schema-input.d.ts +55 -14
- package/dist/schema-input.js +55 -12
- package/dist/utils/configBag.d.ts +68 -0
- package/dist/utils/configBag.js +70 -0
- package/dist/utils/error-message.d.ts +59 -0
- package/dist/utils/error-message.js +116 -1
- package/dist/utils/inlineAria.d.ts +61 -0
- package/dist/utils/inlineAria.js +70 -0
- package/dist/utils/nonGridRowCeiling.d.ts +44 -0
- package/dist/utils/nonGridRowCeiling.js +78 -0
- package/dist/utils/paramsBag.d.ts +28 -0
- package/dist/utils/paramsBag.js +146 -0
- package/dist/utils/propsBagDiagnostic.d.ts +196 -0
- package/dist/utils/propsBagDiagnostic.js +421 -0
- package/dist/utils/refusedDataPropDiagnostic.d.ts +44 -0
- package/dist/utils/refusedDataPropDiagnostic.js +94 -0
- package/dist/utils/unevaluatedExpression.d.ts +110 -0
- package/dist/utils/unevaluatedExpression.js +257 -0
- package/dist/utils/visibilityDiagnostic.d.ts +371 -0
- package/dist/utils/visibilityDiagnostic.js +551 -0
- package/package.json +10 -10
- package/dist/hooks/useClientNotifications.d.ts +0 -47
- package/dist/hooks/useClientNotifications.js +0 -162
- package/dist/spec-bridge/SpecBridge.d.ts +0 -28
- package/dist/spec-bridge/SpecBridge.js +0 -56
- package/dist/spec-bridge/bridges/form-view.d.ts +0 -82
- package/dist/spec-bridge/bridges/form-view.js +0 -126
- package/dist/spec-bridge/bridges/list-view.d.ts +0 -20
- package/dist/spec-bridge/bridges/list-view.js +0 -241
- package/dist/spec-bridge/index.d.ts +0 -11
- package/dist/spec-bridge/index.js +0 -10
- package/dist/spec-bridge/types.d.ts +0 -55
- package/dist/spec-bridge/types.js +0 -8
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { useEffect, useState } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Is this refetch's answer the SAME answer, by value, as the one already
|
|
11
|
+
* published?
|
|
12
|
+
*
|
|
13
|
+
* Used for exactly one decision — whether a settle republishes or keeps the
|
|
14
|
+
* object consumers already hold — and its failure direction is chosen for
|
|
15
|
+
* that decision. A false NEGATIVE (two encodings of the same metadata that
|
|
16
|
+
* serialise differently, e.g. with the keys in another order) republishes,
|
|
17
|
+
* which is precisely what this hook did for every answer before
|
|
18
|
+
* objectui#10106: no consumer can be worse off than it already was. A false
|
|
19
|
+
* POSITIVE would withhold a genuinely new definition from consumers, so the
|
|
20
|
+
* comparison is deliberately a whole-payload one and never a sampled or
|
|
21
|
+
* shallow test.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ An answer JSON cannot express — a cycle, a `BigInt` — makes
|
|
24
|
+
* `JSON.stringify` throw; that is answered as "not equal" rather than allowed
|
|
25
|
+
* to escape into a state updater, which lands on the safe side above.
|
|
26
|
+
*/
|
|
27
|
+
function isEqualPayload(a, b) {
|
|
28
|
+
if (Object.is(a, b))
|
|
29
|
+
return true;
|
|
30
|
+
try {
|
|
31
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolves an object's schema/definition and tracks whether that resolution
|
|
39
|
+
* has SETTLED for the object CURRENTLY being asked about — one piece of
|
|
40
|
+
* state a caller cannot observe half of.
|
|
41
|
+
*
|
|
42
|
+
* ## The shape, and why it is exactly this one
|
|
43
|
+
*
|
|
44
|
+
* This is the RESOLUTION half of the settled-schema gate four views
|
|
45
|
+
* (`ObjectKanban`, `ObjectView`, `ObjectCalendar`, and — pre-fix —
|
|
46
|
+
* `ObjectTree`) each hand-wrote (objectui#6271, #6419, #6453, #6014). Ruled
|
|
47
|
+
* objectui#6482 (maintainer, 2026-08-27, Option A): extract the resolution
|
|
48
|
+
* half as a shared, published hook; leave GATE PLACEMENT — deciding which
|
|
49
|
+
* effect branch actually waits on `ready` — to each component, because that
|
|
50
|
+
* part is genuinely component-private (`ObjectCalendar` gates only its
|
|
51
|
+
* `object`-provider branch and keys on the object the block RESOLVES rather
|
|
52
|
+
* than on `schema.objectName`, because an inline `value` data set issues no
|
|
53
|
+
* metadata read at all — a whole-effect gate would hold its query open on a
|
|
54
|
+
* resolution nothing was ever going to produce).
|
|
55
|
+
*
|
|
56
|
+
* `ready` is DERIVED at render time — `resolution !== null && resolution.key
|
|
57
|
+
* === key` — from a SINGLE piece of state, `{ key, def } | null`, rather than
|
|
58
|
+
* stored as a second, independent boolean. That is not a style choice; it is
|
|
59
|
+
* the fix for the defect this card exists to close. objectui#6481's
|
|
60
|
+
* `ObjectTree` carried the definition (`objectSchema`) and "has it settled"
|
|
61
|
+
* (`schemaSettled`) as two SEPARATE `useState`s. `schemaSettled` was a
|
|
62
|
+
* one-way latch — set `true` on first settle and never reset — so when the
|
|
63
|
+
* host swapped `objectName` mid-life, the fetch effect re-ran and started
|
|
64
|
+
* refetching the NEW object's schema, but `schemaSettled` stayed `true` from
|
|
65
|
+
* the OLD object's settle. The gated effect read `schemaSettled === true`
|
|
66
|
+
* and `objectSchema` still holding the OLD object's fields, and queried with
|
|
67
|
+
* the WRONG `$expand` — a stale key reading as ready.
|
|
68
|
+
*
|
|
69
|
+
* With one state value and a render-time key comparison, that failure mode
|
|
70
|
+
* is not merely fixed, it is UNREPRESENTABLE: the instant `key` changes,
|
|
71
|
+
* `resolution.key === key` is false in that very render (no effect needs to
|
|
72
|
+
* run first), so `ready` flips to `false` in the same commit the key
|
|
73
|
+
* changed — there is no window, and no second piece of state a caller could
|
|
74
|
+
* read out of sync with the first, because there is no second piece of
|
|
75
|
+
* state. A caller cannot spell "ready for the wrong object": `ready` and
|
|
76
|
+
* `def` are two views of one value, never independently settable.
|
|
77
|
+
*
|
|
78
|
+
* Every exit of the internal fetch effect settles the resolution — success,
|
|
79
|
+
* a thrown read, and "there is no source to read from" alike — because a
|
|
80
|
+
* caller's gated effect WAITS on `ready`. An exit that returned without
|
|
81
|
+
* settling would not merely skip the expansion; it would hold that gated
|
|
82
|
+
* query open forever.
|
|
83
|
+
*
|
|
84
|
+
* ## What this hook does NOT do
|
|
85
|
+
*
|
|
86
|
+
* It does not decide when to fetch beyond "when `key` or `dataSource`
|
|
87
|
+
* change", and it does not decide what a caller's OTHER effects should wait
|
|
88
|
+
* on. A caller that should not fetch at all for the current render (e.g.
|
|
89
|
+
* `ObjectCalendar`'s inline `value` provider, which issues no metadata read)
|
|
90
|
+
* passes `dataSource: undefined` for that render rather than a new "should
|
|
91
|
+
* fetch" flag — the hook already settles-with-`null` whenever `dataSource`
|
|
92
|
+
* is absent, which is the exact "no source to read from" outcome that case
|
|
93
|
+
* needs.
|
|
94
|
+
*
|
|
95
|
+
* @param key - The identity of the object THIS render is asking about — for a
|
|
96
|
+
* record-bound view, `resolveRecordSourceObjectName(schema, dataConfig) ?? ''`
|
|
97
|
+
* from `@object-ui/core`. ⛔ Do NOT re-spell that ladder inline here: six view
|
|
98
|
+
* plugins each carried their own copy and had drifted, which is the whole of
|
|
99
|
+
* what `b041b9c0c` collapsed. Choosing the key is still the caller's job — it is the
|
|
100
|
+
* component-private half of the original hand copies, not something this hook
|
|
101
|
+
* can infer — but the ladder behind it is published and shared.
|
|
102
|
+
* @param dataSource - The data source to read the definition from. Pass
|
|
103
|
+
* `undefined`/`null` for a render that should settle immediately with no
|
|
104
|
+
* definition (no source, or a provider that needs none) rather than adding
|
|
105
|
+
* a separate enable flag.
|
|
106
|
+
* @returns `{ ready, def }` — see {@link SettledSchema}.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```tsx
|
|
110
|
+
* const schemaKey = resolveRecordSourceObjectName(schema, dataConfig); // @object-ui/core
|
|
111
|
+
* const { ready: objectSchemaReady, def: objectSchema } =
|
|
112
|
+
* useSettledSchema(schemaKey ?? '', hasInlineData ? undefined : dataSource);
|
|
113
|
+
*
|
|
114
|
+
* useEffect(() => {
|
|
115
|
+
* // A PROVIDER test, not an object-name read — it asks "is there metadata to
|
|
116
|
+
* // wait for at all", which the shared reader deliberately does not answer.
|
|
117
|
+
* // Gate placement stays local (objectui#6482); the ladder does not.
|
|
118
|
+
* if (dataConfig?.provider === 'object' && !objectSchemaReady) return;
|
|
119
|
+
* // ...issue the record query, `buildExpandFields(objectSchema?.fields)`
|
|
120
|
+
* }, [objectSchemaReady, objectSchema, /* ... *\/]);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function useSettledSchema(key, dataSource) {
|
|
124
|
+
const [resolution, setResolution] = useState(null);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
let isMounted = true;
|
|
127
|
+
const settleKey = key;
|
|
128
|
+
/**
|
|
129
|
+
* Settle THIS effect run's resolution — and, when the answer is one
|
|
130
|
+
* consumers already hold, settle it as the object they already hold.
|
|
131
|
+
*
|
|
132
|
+
* This is the PRODUCER half of `AGENTS.md` §5 commandment #10: *"a
|
|
133
|
+
* provider that refetches may not republish an equal payload as a new
|
|
134
|
+
* object, and a consumer that needs stability keys on the data, not on a
|
|
135
|
+
* cache"*. This hook refetches whenever the adapter identity changes, and
|
|
136
|
+
* the consumers its own `@example` instructs do exactly what the other
|
|
137
|
+
* half of that sentence asks — they key their record fetch on `def`, the
|
|
138
|
+
* payload, never on a memo identity. So a fresh object for an unchanged
|
|
139
|
+
* answer is not a wasted allocation; it is a DUPLICATE RECORD QUERY at
|
|
140
|
+
* every one of them, carrying the same expand set as the one before it.
|
|
141
|
+
* Pinned with its control in
|
|
142
|
+
* `useSettledSchema.equalPayload-10106.test.tsx` (objectui#10106).
|
|
143
|
+
*
|
|
144
|
+
* ⛔ The cure may NOT be moved to the consumer — the same sentence names
|
|
145
|
+
* keying on a cache as the wrong one, and a consumer that stopped keying
|
|
146
|
+
* on `def` would also stop re-querying when the definition genuinely
|
|
147
|
+
* changes, which the control case in that pin holds open.
|
|
148
|
+
*
|
|
149
|
+
* Bailing out is only ever safe for the SAME key: `resolution` is one
|
|
150
|
+
* piece of state whose `key` decides `ready`, so a settle for a different
|
|
151
|
+
* key must always publish (see the hook doc comment above).
|
|
152
|
+
*/
|
|
153
|
+
const settle = (settledDef) => {
|
|
154
|
+
setResolution((prev) => prev && prev.key === settleKey && isEqualPayload(prev.def, settledDef)
|
|
155
|
+
? prev
|
|
156
|
+
: { key: settleKey, def: settledDef });
|
|
157
|
+
};
|
|
158
|
+
const resolve = async () => {
|
|
159
|
+
if (!dataSource || !settleKey || typeof dataSource.getObjectSchema !== 'function') {
|
|
160
|
+
// No source for a definition: settle with none, so anything gated on
|
|
161
|
+
// `ready` still runs (unexpanded — with no schema there is no expand
|
|
162
|
+
// set to derive).
|
|
163
|
+
if (isMounted)
|
|
164
|
+
settle(null);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const def = await dataSource.getObjectSchema(settleKey);
|
|
169
|
+
if (isMounted)
|
|
170
|
+
settle(def);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
console.error('[useSettledSchema] getObjectSchema failed for', settleKey, err);
|
|
174
|
+
if (isMounted)
|
|
175
|
+
settle(null);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
resolve();
|
|
179
|
+
return () => {
|
|
180
|
+
isMounted = false;
|
|
181
|
+
};
|
|
182
|
+
}, [key, dataSource]);
|
|
183
|
+
const ready = resolution !== null && resolution.key === key;
|
|
184
|
+
const def = ready ? resolution.def : null;
|
|
185
|
+
return { ready, def };
|
|
186
|
+
}
|
|
@@ -37,8 +37,13 @@ export interface UseViewDataResult<T = any> {
|
|
|
37
37
|
dataSource: DataSource<T> | null;
|
|
38
38
|
/** Re-fetch data with current or new params */
|
|
39
39
|
refresh: (newParams?: QueryParams) => Promise<void>;
|
|
40
|
-
/**
|
|
41
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Fetch a single record by ID. The id is a `string`, as every record door on
|
|
42
|
+
* `DataSource` declares it — this hook hands the value straight to
|
|
43
|
+
* `DataSource.findOne`, so the union it used to admit was a claim the
|
|
44
|
+
* protocol never made (objectui#9511).
|
|
45
|
+
*/
|
|
46
|
+
fetchOne: (id: string) => Promise<T | null>;
|
|
42
47
|
/** Whether more records are available */
|
|
43
48
|
hasMore: boolean;
|
|
44
49
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { useState, useEffect, useCallback, useMemo, useContext } from 'react';
|
|
12
12
|
import { resolveDataSource } from '@object-ui/core';
|
|
13
|
-
import { SchemaRendererContext } from '../context/SchemaRendererContext';
|
|
13
|
+
import { SchemaRendererContext } from '../context/SchemaRendererContext.js';
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
// Hook
|
|
16
16
|
// ---------------------------------------------------------------------------
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
import { useState, useCallback, useMemo } from 'react';
|
|
9
|
-
import { useReducedMotion } from './useReducedMotion';
|
|
9
|
+
import { useReducedMotion } from './useReducedMotion.js';
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
// Helpers
|
|
12
12
|
// ---------------------------------------------------------------------------
|
package/dist/index.d.ts
CHANGED
|
@@ -5,15 +5,22 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
export * from './SchemaRenderer';
|
|
9
|
-
export * from './schema-input';
|
|
10
|
-
export * from './hooks';
|
|
11
|
-
export * from './context';
|
|
12
|
-
export * from './LazyPluginLoader';
|
|
13
|
-
export * from './
|
|
14
|
-
export * from './data-
|
|
15
|
-
export
|
|
16
|
-
export {
|
|
17
|
-
export {
|
|
18
|
-
export
|
|
8
|
+
export * from './SchemaRenderer.js';
|
|
9
|
+
export * from './schema-input.js';
|
|
10
|
+
export * from './hooks/index.js';
|
|
11
|
+
export * from './context/index.js';
|
|
12
|
+
export * from './LazyPluginLoader.js';
|
|
13
|
+
export * from './data-invalidation.js';
|
|
14
|
+
export * from './element-data-source/ElementDataSourceGate.js';
|
|
15
|
+
export { resolveKeyedI18nLabel } from './utils/i18n.js';
|
|
16
|
+
export { resolveInlineAriaProps } from './utils/inlineAria.js';
|
|
17
|
+
export { isConfigBag } from './utils/configBag.js';
|
|
18
|
+
export { reportUnresolvableVisibilityPredicate, formatUnresolvableVisibilityMessage, UNRESOLVABLE_VISIBILITY_PREFIX, UNRESOLVABLE_ENABLEMENT_PREFIX, __resetVisibilityPredicateWarnings, } from './utils/visibilityDiagnostic.js';
|
|
19
|
+
export type { PredicateScopeTier } from './utils/visibilityDiagnostic.js';
|
|
20
|
+
export type { PredicateGateKind } from './utils/visibilityDiagnostic.js';
|
|
21
|
+
export { extractWriteErrorMessage, isPermissionError, extractFieldErrors, classifyLoadError, declaredUserMessage } from './utils/error-message.js';
|
|
22
|
+
export type { WriteFieldError, LoadErrorKind } from './utils/error-message.js';
|
|
19
23
|
export { I18nProvider, useObjectTranslation, useSafeTranslate, useObjectLabel, useSafeFieldLabel, useI18nContext, createI18n, getDirection, getAvailableLanguages, formatDate, formatDateTime, formatRelativeTime, formatCurrency, formatNumber, type I18nConfig, type I18nProviderProps, type TranslationKeys, type DateFormatOptions, type CurrencyFormatOptions, type NumberFormatOptions, } from '@object-ui/i18n';
|
|
24
|
+
export { NON_GRID_ROW_CEILING, applyNonGridRowCeiling } from '@object-ui/core';
|
|
25
|
+
export type { NonGridCeilingResult } from '@object-ui/core';
|
|
26
|
+
export { NonGridRowCeilingNote } from './utils/nonGridRowCeiling.js';
|
package/dist/index.js
CHANGED
|
@@ -5,20 +5,64 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
export * from './SchemaRenderer';
|
|
9
|
-
export * from './schema-input';
|
|
10
|
-
export * from './hooks'; // will be empty for now
|
|
11
|
-
export * from './context'; // will be empty for now
|
|
12
|
-
export * from './LazyPluginLoader';
|
|
13
|
-
export * from './
|
|
14
|
-
export * from './data-invalidation';
|
|
8
|
+
export * from './SchemaRenderer.js';
|
|
9
|
+
export * from './schema-input.js';
|
|
10
|
+
export * from './hooks/index.js'; // will be empty for now
|
|
11
|
+
export * from './context/index.js'; // will be empty for now
|
|
12
|
+
export * from './LazyPluginLoader.js';
|
|
13
|
+
export * from './data-invalidation.js';
|
|
15
14
|
// PageComponentSchema.dataSource — mapping the spec's per-element data binding
|
|
16
15
|
// onto the schema keys each object-bound block reads (objectstack#6953).
|
|
17
|
-
export * from './element-data-source/ElementDataSourceGate';
|
|
16
|
+
export * from './element-data-source/ElementDataSourceGate.js';
|
|
18
17
|
// i18n utilities
|
|
19
|
-
export { resolveKeyedI18nLabel } from './utils/i18n';
|
|
18
|
+
export { resolveKeyedI18nLabel } from './utils/i18n.js';
|
|
19
|
+
// The spec's NESTED `aria` bag (`AriaPropsSchema`) → `aria-label` /
|
|
20
|
+
// `aria-describedby` / `role`, with `ariaLabel` resolved as an inline locale
|
|
21
|
+
// map (objectui#11051). Exported for the renderers in `@object-ui/components`,
|
|
22
|
+
// which depends on this package, so the mapping is written once. It is not the
|
|
23
|
+
// flat keyed reader `SchemaRenderer` applies to every node; objectui#4580 Q2-B
|
|
24
|
+
// keeps the two vocabularies apart.
|
|
25
|
+
export { resolveInlineAriaProps } from './utils/inlineAria.js';
|
|
26
|
+
// "Is this a real config bag?" — the ONE definition of that question
|
|
27
|
+
// (objectui#6761), exported at the package entry for the same reason the node-gate
|
|
28
|
+
// reporter above is (objectui#6038): a surface in `@object-ui/components`, which
|
|
29
|
+
// depends on this package, asks it too. `element:*` renderers there read their
|
|
30
|
+
// config out of `{ ...schema.props, ...schema.properties }`, the third channel of
|
|
31
|
+
// the degenerate-bag hazard objectui#6752 / objectui#6760 closed here
|
|
32
|
+
// (objectui#6783). A second copy one package over would be a spelling that
|
|
33
|
+
// `utils/configBag.pin.test.ts` — which scans `packages/react/src` — cannot see,
|
|
34
|
+
// which is the drift that pin exists to stop.
|
|
35
|
+
export { isConfigBag } from './utils/configBag.js';
|
|
36
|
+
// Node-gate predicate diagnostics. Exported at the package entry (objectui#6038)
|
|
37
|
+
// so every surface that evaluates a node `visibleWhen` reports a fault through
|
|
38
|
+
// ONE reporter and ONE dedupe `Set` — `page:tabs` item predicates live in
|
|
39
|
+
// `@object-ui/components`, which depends on this package. A second copy of the
|
|
40
|
+
// reporter would mean a second rate limit, and the same broken predicate would
|
|
41
|
+
// then be entitled to one line per package instead of one line, which is the
|
|
42
|
+
// property the 2026-08-25 ruling asked for.
|
|
43
|
+
export { reportUnresolvableVisibilityPredicate, formatUnresolvableVisibilityMessage, UNRESOLVABLE_VISIBILITY_PREFIX,
|
|
44
|
+
// The ENABLEMENT gate's opening line (objectui#6445). Exported beside its
|
|
45
|
+
// sibling for the reason that one is: an app filtering these out of its
|
|
46
|
+
// console transport filters by the constant, and a second line it cannot
|
|
47
|
+
// name is a second thing to hard-code. Not a second reporter — the emit,
|
|
48
|
+
// the dedupe `Set` and the reset above are still the only ones.
|
|
49
|
+
UNRESOLVABLE_ENABLEMENT_PREFIX, __resetVisibilityPredicateWarnings, } from './utils/visibilityDiagnostic.js';
|
|
20
50
|
// Write-error surfacing utilities (shared by drag-write plugins so a failed
|
|
21
51
|
// PATCH — e.g. an RLS 403 — is never silently swallowed).
|
|
22
|
-
export { extractWriteErrorMessage, isPermissionError, extractFieldErrors } from './utils/error-message';
|
|
52
|
+
export { extractWriteErrorMessage, isPermissionError, extractFieldErrors, classifyLoadError, declaredUserMessage } from './utils/error-message.js';
|
|
23
53
|
// Built-in i18n support
|
|
24
54
|
export { I18nProvider, useObjectTranslation, useSafeTranslate, useObjectLabel, useSafeFieldLabel, useI18nContext, createI18n, getDirection, getAvailableLanguages, formatDate, formatDateTime, formatRelativeTime, formatCurrency, formatNumber, } from '@object-ui/i18n';
|
|
55
|
+
// The platform row ceiling for NON-GRID visualisations — gantt, calendar, map
|
|
56
|
+
// and tree (objectui#7210, maintainer ruling a′). One constant across the
|
|
57
|
+
// four, because a per-plugin copy would be four constants wearing one name,
|
|
58
|
+
// which is the thing the ruling ruled out.
|
|
59
|
+
//
|
|
60
|
+
// HOME: `@object-ui/core`, beside the `extractRecords` it wraps (objectui#7508,
|
|
61
|
+
// maintainer ruling A′). This entry re-exports the three names it published
|
|
62
|
+
// first, the same way it re-exports `@object-ui/i18n` above, and keeps only
|
|
63
|
+
// the React half — `NonGridRowCeilingNote`, which takes the
|
|
64
|
+
// `NonGridCeilingResult` and nothing else. The probe row's `+ 1` lives in
|
|
65
|
+
// core's `nonGridRowCeilingQuery()` and nowhere else; the constant that used
|
|
66
|
+
// to carry it here is deleted, not re-exported.
|
|
67
|
+
export { NON_GRID_ROW_CEILING, applyNonGridRowCeiling } from '@object-ui/core';
|
|
68
|
+
export { NonGridRowCeilingNote } from './utils/nonGridRowCeiling.js';
|
package/dist/schema-input.d.ts
CHANGED
|
@@ -5,27 +5,68 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
9
|
-
import type { SchemaRendererProps } from './SchemaRenderer';
|
|
8
|
+
import type { SchemaNode } from '@object-ui/types';
|
|
9
|
+
import type { SchemaRendererProps } from './SchemaRenderer.js';
|
|
10
10
|
/**
|
|
11
11
|
* Narrow a loosely-typed metadata node onto {@link SchemaRendererProps.schema}.
|
|
12
12
|
*
|
|
13
13
|
* `@object-ui/types` declares `SchemaNode` as
|
|
14
|
-
* `
|
|
15
|
-
* metadata plumbing (page regions, header-bar actions, detail tabs, view
|
|
14
|
+
* `DeclaredNode | string | number | boolean | null | undefined` (its object
|
|
15
|
+
* arm the declared-node union, objectui#11466), and a lot of metadata plumbing (page regions, header-bar actions, detail tabs, view
|
|
16
16
|
* configs) is typed with it. `SchemaRenderer` deliberately does NOT declare the
|
|
17
17
|
* `number` / `boolean` members — nobody should be invited to author them — so
|
|
18
18
|
* forwarding such a value needs one honest step in between.
|
|
19
19
|
*
|
|
20
20
|
* This is that step, and it is a TOTAL function rather than a cast: it maps the
|
|
21
|
-
* two primitive members onto
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
21
|
+
* two primitive members onto whatever `SchemaRenderer` would itself render for
|
|
22
|
+
* them. So it changes no behaviour and tells no lie — the value a caller
|
|
23
|
+
* forwards renders identically whether or not it passes through here.
|
|
24
|
+
*
|
|
25
|
+
* ## Why the mapping has TWO legs and not one
|
|
26
|
+
*
|
|
27
|
+
* Because the renderer's own narrowing has two, in a fixed order: the
|
|
28
|
+
* `!evaluatedSchema` leg returns nothing and runs FIRST, and only below it does
|
|
29
|
+
* the defensive branch return the value's `String` form. So the falsy
|
|
30
|
+
* primitives — `0`, `-0`, `NaN`, `false` — never reach that branch at all; they
|
|
31
|
+
* render as nothing. `!node` is exactly that set for the two members this
|
|
32
|
+
* function converts, so the ternary below IS the renderer's order, restated for
|
|
33
|
+
* a value that has to cross the type boundary as a string.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ The single-leg `String(node)` that stood here until objectui#8908 was the
|
|
36
|
+
* lie this paragraph used to tell. `String(0)` and `String(false)` are the
|
|
37
|
+
* NON-EMPTY strings `'0'` and `'false'`, which are truthy, so they sailed past
|
|
38
|
+
* the renderer's first leg and printed themselves — while the same two values
|
|
39
|
+
* handed to `SchemaRenderer` directly render nothing, pinned since
|
|
40
|
+
* objectui#4548 in `packages/react/src/__tests__/SchemaRenderer.primitiveSchema.test.tsx`.
|
|
41
|
+
* The shipped `empty` renderer, whose `action` slot gates on nullish rather than
|
|
42
|
+
* truthiness, printed a stray `0` for `{ type: 'empty', action: 0 }` because of
|
|
43
|
+
* it. ⛔ Do not "simplify" the two legs back into one.
|
|
44
|
+
*
|
|
45
|
+
* ## Why the falsy leg returns nothing rather than the value itself
|
|
46
|
+
*
|
|
47
|
+
* Passing `0` / `false` through UNCHANGED would widen this function's return
|
|
48
|
+
* type to admit `number` / `boolean`, and that is not a free choice: the return
|
|
49
|
+
* type is pinned exactly equal to `SchemaRendererProps['schema']` by
|
|
50
|
+
* `packages/react/src/__tests__/SchemaRenderer.propsResolution.test.ts`, which
|
|
51
|
+
* also pins that the prop admits NEITHER member (objectui#4548 ruling Q2). A
|
|
52
|
+
* widened return would therefore be a TS2322 at every call site that forwards
|
|
53
|
+
* it straight into `<SchemaRenderer schema={…} />`, which is all of them. The
|
|
54
|
+
* nullish leg is the spelling that keeps the guarantee and the type both.
|
|
55
|
+
*
|
|
56
|
+
* The bridge is PERMANENT — not scaffolding awaiting a merge. The two competing
|
|
57
|
+
* repo-wide `SchemaNode` spellings ARE reconciled (objectui#4580, PR #4608):
|
|
58
|
+
* `@object-ui/core` stopped hand-declaring its own interface and now re-exports
|
|
59
|
+
* `@object-ui/types`' union, so one declaration is left to disagree with. That
|
|
60
|
+
* reconciliation resolved in favour of the UNION, while `SchemaRenderer`'s prop
|
|
61
|
+
* stays deliberately narrow (objectui#4548 ruling Q2 — it declares no `number`
|
|
62
|
+
* or `boolean`), so a `SchemaNode` is now LESS assignable to that prop than it
|
|
63
|
+
* was, not more. This step therefore bridges two intentionally different types,
|
|
64
|
+
* and it stays. ⛔ Do not "tidy" a call site back into a direct forward: the
|
|
65
|
+
* five `apps/site` sites that were forwarding directly when PR #4608 landed are
|
|
66
|
+
* what kept `Build Docs` red on `main` for ~5 hours — each one a TS2322 naming
|
|
67
|
+
* `number` against this function's return type, spelled
|
|
68
|
+
* `string | BaseSchema | null | undefined` in objectui#4617's logs — until
|
|
69
|
+
* PR #4621 routed all five through here. An earlier revision of this paragraph
|
|
70
|
+
* said the reconciliation was still pending and invited exactly that edit.
|
|
30
71
|
*/
|
|
31
|
-
export declare function toRenderableSchema(node:
|
|
72
|
+
export declare function toRenderableSchema(node: SchemaNode): SchemaRendererProps['schema'];
|
package/dist/schema-input.js
CHANGED
|
@@ -9,23 +9,66 @@
|
|
|
9
9
|
* Narrow a loosely-typed metadata node onto {@link SchemaRendererProps.schema}.
|
|
10
10
|
*
|
|
11
11
|
* `@object-ui/types` declares `SchemaNode` as
|
|
12
|
-
* `
|
|
13
|
-
* metadata plumbing (page regions, header-bar actions, detail tabs, view
|
|
12
|
+
* `DeclaredNode | string | number | boolean | null | undefined` (its object
|
|
13
|
+
* arm the declared-node union, objectui#11466), and a lot of metadata plumbing (page regions, header-bar actions, detail tabs, view
|
|
14
14
|
* configs) is typed with it. `SchemaRenderer` deliberately does NOT declare the
|
|
15
15
|
* `number` / `boolean` members — nobody should be invited to author them — so
|
|
16
16
|
* forwarding such a value needs one honest step in between.
|
|
17
17
|
*
|
|
18
18
|
* This is that step, and it is a TOTAL function rather than a cast: it maps the
|
|
19
|
-
* two primitive members onto
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
19
|
+
* two primitive members onto whatever `SchemaRenderer` would itself render for
|
|
20
|
+
* them. So it changes no behaviour and tells no lie — the value a caller
|
|
21
|
+
* forwards renders identically whether or not it passes through here.
|
|
22
|
+
*
|
|
23
|
+
* ## Why the mapping has TWO legs and not one
|
|
24
|
+
*
|
|
25
|
+
* Because the renderer's own narrowing has two, in a fixed order: the
|
|
26
|
+
* `!evaluatedSchema` leg returns nothing and runs FIRST, and only below it does
|
|
27
|
+
* the defensive branch return the value's `String` form. So the falsy
|
|
28
|
+
* primitives — `0`, `-0`, `NaN`, `false` — never reach that branch at all; they
|
|
29
|
+
* render as nothing. `!node` is exactly that set for the two members this
|
|
30
|
+
* function converts, so the ternary below IS the renderer's order, restated for
|
|
31
|
+
* a value that has to cross the type boundary as a string.
|
|
32
|
+
*
|
|
33
|
+
* ⚠️ The single-leg `String(node)` that stood here until objectui#8908 was the
|
|
34
|
+
* lie this paragraph used to tell. `String(0)` and `String(false)` are the
|
|
35
|
+
* NON-EMPTY strings `'0'` and `'false'`, which are truthy, so they sailed past
|
|
36
|
+
* the renderer's first leg and printed themselves — while the same two values
|
|
37
|
+
* handed to `SchemaRenderer` directly render nothing, pinned since
|
|
38
|
+
* objectui#4548 in `packages/react/src/__tests__/SchemaRenderer.primitiveSchema.test.tsx`.
|
|
39
|
+
* The shipped `empty` renderer, whose `action` slot gates on nullish rather than
|
|
40
|
+
* truthiness, printed a stray `0` for `{ type: 'empty', action: 0 }` because of
|
|
41
|
+
* it. ⛔ Do not "simplify" the two legs back into one.
|
|
42
|
+
*
|
|
43
|
+
* ## Why the falsy leg returns nothing rather than the value itself
|
|
44
|
+
*
|
|
45
|
+
* Passing `0` / `false` through UNCHANGED would widen this function's return
|
|
46
|
+
* type to admit `number` / `boolean`, and that is not a free choice: the return
|
|
47
|
+
* type is pinned exactly equal to `SchemaRendererProps['schema']` by
|
|
48
|
+
* `packages/react/src/__tests__/SchemaRenderer.propsResolution.test.ts`, which
|
|
49
|
+
* also pins that the prop admits NEITHER member (objectui#4548 ruling Q2). A
|
|
50
|
+
* widened return would therefore be a TS2322 at every call site that forwards
|
|
51
|
+
* it straight into `<SchemaRenderer schema={…} />`, which is all of them. The
|
|
52
|
+
* nullish leg is the spelling that keeps the guarantee and the type both.
|
|
53
|
+
*
|
|
54
|
+
* The bridge is PERMANENT — not scaffolding awaiting a merge. The two competing
|
|
55
|
+
* repo-wide `SchemaNode` spellings ARE reconciled (objectui#4580, PR #4608):
|
|
56
|
+
* `@object-ui/core` stopped hand-declaring its own interface and now re-exports
|
|
57
|
+
* `@object-ui/types`' union, so one declaration is left to disagree with. That
|
|
58
|
+
* reconciliation resolved in favour of the UNION, while `SchemaRenderer`'s prop
|
|
59
|
+
* stays deliberately narrow (objectui#4548 ruling Q2 — it declares no `number`
|
|
60
|
+
* or `boolean`), so a `SchemaNode` is now LESS assignable to that prop than it
|
|
61
|
+
* was, not more. This step therefore bridges two intentionally different types,
|
|
62
|
+
* and it stays. ⛔ Do not "tidy" a call site back into a direct forward: the
|
|
63
|
+
* five `apps/site` sites that were forwarding directly when PR #4608 landed are
|
|
64
|
+
* what kept `Build Docs` red on `main` for ~5 hours — each one a TS2322 naming
|
|
65
|
+
* `number` against this function's return type, spelled
|
|
66
|
+
* `string | BaseSchema | null | undefined` in objectui#4617's logs — until
|
|
67
|
+
* PR #4621 routed all five through here. An earlier revision of this paragraph
|
|
68
|
+
* said the reconciliation was still pending and invited exactly that edit.
|
|
28
69
|
*/
|
|
29
70
|
export function toRenderableSchema(node) {
|
|
30
|
-
return typeof node === 'number' || typeof node === 'boolean'
|
|
71
|
+
return typeof node === 'number' || typeof node === 'boolean'
|
|
72
|
+
? (node ? String(node) : undefined)
|
|
73
|
+
: node;
|
|
31
74
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Is this value a real config bag — an object, and not an array pretending to
|
|
10
|
+
* be one? (objectui#6761)
|
|
11
|
+
*
|
|
12
|
+
* This is the ONE definition of that question in `@object-ui/react`, and it
|
|
13
|
+
* lives here rather than in whichever module happened to need it first,
|
|
14
|
+
* because every module that asks it is a CONSUMER of the same authored shape:
|
|
15
|
+
* the `properties` / `props` bags a node may carry. `typeof null === 'object'`
|
|
16
|
+
* is covered by the truthiness test.
|
|
17
|
+
*
|
|
18
|
+
* ## Why one definition, when all the copies agreed
|
|
19
|
+
*
|
|
20
|
+
* They agreed; that was never the cost. The cost is that disagreement between
|
|
21
|
+
* them produces NO error — each copy is a boolean expression, and a copy that
|
|
22
|
+
* drifts answers a different question on ONE channel while every other channel
|
|
23
|
+
* keeps the old answer. That is the same failure mode `hasDeclaredPredicate`
|
|
24
|
+
* (`@object-ui/core`) was created to end for "is a gate DECLARED?", which had
|
|
25
|
+
* three spellings with three different SCOPES before objectui#3850 —
|
|
26
|
+
* `disabled: null` greying a control out on one path and not another
|
|
27
|
+
* (objectui#3862).
|
|
28
|
+
*
|
|
29
|
+
* ## The spellings this replaces, measured on `b98352a15`
|
|
30
|
+
*
|
|
31
|
+
* Six occurrences, four spellings, all in `packages/react/src`:
|
|
32
|
+
*
|
|
33
|
+
* 1. `SchemaRenderer`'s module-private `isConfigBag` — itself already the
|
|
34
|
+
* merge of the `properties` evaluation guard and `propsWithoutCanonicalKeys`
|
|
35
|
+
* (objectui#6752, which unified those two because it had to touch both,
|
|
36
|
+
* and filed the rest as objectui#6761 rather than smuggling it in);
|
|
37
|
+
* 2. `SchemaRenderer`'s `winningVisibilityKey`, inline, spelled with
|
|
38
|
+
* `!= null` where the others spell truthiness;
|
|
39
|
+
* 3. `utils/propsBagDiagnostic.ts`'s module-private twin (objectui#6708);
|
|
40
|
+
* 4. `utils/unevaluatedExpression.ts`'s `scanBag` early return, spelled
|
|
41
|
+
* NEGATED (objectui#4795);
|
|
42
|
+
* 5. `utils/unevaluatedExpression.ts`'s `hoisted`, in the same file as (4)
|
|
43
|
+
* and spelled positively — this one is not in objectui#6761's inventory
|
|
44
|
+
* of five, which counted the file once; six occurrences is the count
|
|
45
|
+
* measured on this branch's base, and it was six on the card's base
|
|
46
|
+
* (`b76ca6764`) too.
|
|
47
|
+
*
|
|
48
|
+
* `!= null` (2) and truthiness (1, 3, 5) cannot disagree HERE, and the
|
|
49
|
+
* difference is worth naming rather than smoothing over: they part company
|
|
50
|
+
* only on a falsy value, and every falsy value except `document.all` fails
|
|
51
|
+
* `typeof === 'object'` in the very next conjunct. The texts differ; the
|
|
52
|
+
* answers cannot.
|
|
53
|
+
*
|
|
54
|
+
* ## What this is NOT
|
|
55
|
+
*
|
|
56
|
+
* Not a general "is this a plain object?" utility, and deliberately not shared
|
|
57
|
+
* with the two sites that ask the same SHAPE question about a data ROW —
|
|
58
|
+
* `SchemaRenderer`'s `boundRecord` scope entry and
|
|
59
|
+
* `usePredicateRecordContext` (`hooks/useExpression.ts`). Those answer "did a
|
|
60
|
+
* row bind?", and their answer has its own pinned meaning: binding NOTHING
|
|
61
|
+
* rather than an empty row is what keeps a host-supplied `record` from being
|
|
62
|
+
* shadowed. Should "config bag" ever narrow (rejecting a class instance, say),
|
|
63
|
+
* the row sites must NOT follow — merging them would make that a single edit
|
|
64
|
+
* with two rulings behind it. The pin in `configBag.pin.test.ts` names both
|
|
65
|
+
* sites with this reason, so the next reader finds a decision rather than an
|
|
66
|
+
* oversight.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isConfigBag(value: unknown): value is Record<string, unknown>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Is this value a real config bag — an object, and not an array pretending to
|
|
10
|
+
* be one? (objectui#6761)
|
|
11
|
+
*
|
|
12
|
+
* This is the ONE definition of that question in `@object-ui/react`, and it
|
|
13
|
+
* lives here rather than in whichever module happened to need it first,
|
|
14
|
+
* because every module that asks it is a CONSUMER of the same authored shape:
|
|
15
|
+
* the `properties` / `props` bags a node may carry. `typeof null === 'object'`
|
|
16
|
+
* is covered by the truthiness test.
|
|
17
|
+
*
|
|
18
|
+
* ## Why one definition, when all the copies agreed
|
|
19
|
+
*
|
|
20
|
+
* They agreed; that was never the cost. The cost is that disagreement between
|
|
21
|
+
* them produces NO error — each copy is a boolean expression, and a copy that
|
|
22
|
+
* drifts answers a different question on ONE channel while every other channel
|
|
23
|
+
* keeps the old answer. That is the same failure mode `hasDeclaredPredicate`
|
|
24
|
+
* (`@object-ui/core`) was created to end for "is a gate DECLARED?", which had
|
|
25
|
+
* three spellings with three different SCOPES before objectui#3850 —
|
|
26
|
+
* `disabled: null` greying a control out on one path and not another
|
|
27
|
+
* (objectui#3862).
|
|
28
|
+
*
|
|
29
|
+
* ## The spellings this replaces, measured on `b98352a15`
|
|
30
|
+
*
|
|
31
|
+
* Six occurrences, four spellings, all in `packages/react/src`:
|
|
32
|
+
*
|
|
33
|
+
* 1. `SchemaRenderer`'s module-private `isConfigBag` — itself already the
|
|
34
|
+
* merge of the `properties` evaluation guard and `propsWithoutCanonicalKeys`
|
|
35
|
+
* (objectui#6752, which unified those two because it had to touch both,
|
|
36
|
+
* and filed the rest as objectui#6761 rather than smuggling it in);
|
|
37
|
+
* 2. `SchemaRenderer`'s `winningVisibilityKey`, inline, spelled with
|
|
38
|
+
* `!= null` where the others spell truthiness;
|
|
39
|
+
* 3. `utils/propsBagDiagnostic.ts`'s module-private twin (objectui#6708);
|
|
40
|
+
* 4. `utils/unevaluatedExpression.ts`'s `scanBag` early return, spelled
|
|
41
|
+
* NEGATED (objectui#4795);
|
|
42
|
+
* 5. `utils/unevaluatedExpression.ts`'s `hoisted`, in the same file as (4)
|
|
43
|
+
* and spelled positively — this one is not in objectui#6761's inventory
|
|
44
|
+
* of five, which counted the file once; six occurrences is the count
|
|
45
|
+
* measured on this branch's base, and it was six on the card's base
|
|
46
|
+
* (`b76ca6764`) too.
|
|
47
|
+
*
|
|
48
|
+
* `!= null` (2) and truthiness (1, 3, 5) cannot disagree HERE, and the
|
|
49
|
+
* difference is worth naming rather than smoothing over: they part company
|
|
50
|
+
* only on a falsy value, and every falsy value except `document.all` fails
|
|
51
|
+
* `typeof === 'object'` in the very next conjunct. The texts differ; the
|
|
52
|
+
* answers cannot.
|
|
53
|
+
*
|
|
54
|
+
* ## What this is NOT
|
|
55
|
+
*
|
|
56
|
+
* Not a general "is this a plain object?" utility, and deliberately not shared
|
|
57
|
+
* with the two sites that ask the same SHAPE question about a data ROW —
|
|
58
|
+
* `SchemaRenderer`'s `boundRecord` scope entry and
|
|
59
|
+
* `usePredicateRecordContext` (`hooks/useExpression.ts`). Those answer "did a
|
|
60
|
+
* row bind?", and their answer has its own pinned meaning: binding NOTHING
|
|
61
|
+
* rather than an empty row is what keeps a host-supplied `record` from being
|
|
62
|
+
* shadowed. Should "config bag" ever narrow (rejecting a class instance, say),
|
|
63
|
+
* the row sites must NOT follow — merging them would make that a single edit
|
|
64
|
+
* with two rulings behind it. The pin in `configBag.pin.test.ts` names both
|
|
65
|
+
* sites with this reason, so the next reader finds a decision rather than an
|
|
66
|
+
* oversight.
|
|
67
|
+
*/
|
|
68
|
+
export function isConfigBag(value) {
|
|
69
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
70
|
+
}
|