@object-ui/react 6.2.1 → 6.2.2

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @object-ui/react
2
2
 
3
+ ## 6.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - a66f788: fix(react): preserve `data-obj-schema-invalid` flag across re-renders
8
+
9
+ `SchemaRenderer` runs a post-mount `forceUpdate` to pick up lazy plugin
10
+ registrations. The dev-mode validator was deduping via a `WeakSet` that
11
+ always returned `valid: true` on the second call, which stripped the
12
+ `data-obj-schema-invalid` attribute on the immediate re-render. The
13
+ result and the "warn-once" tracking are now stored separately: a
14
+ `WeakMap` caches the validation outcome (so the visual flag is stable),
15
+ while a `WeakSet` continues to dedupe `console.warn` output.
16
+ - @object-ui/types@6.2.2
17
+ - @object-ui/core@6.2.2
18
+ - @object-ui/i18n@6.2.2
19
+ - @object-ui/data-objectstack@6.2.2
20
+
3
21
  ## 6.2.1
4
22
 
5
23
  ### Patch Changes
@@ -31,33 +31,44 @@ const __DEV__ = (() => {
31
31
  return true;
32
32
  }
33
33
  })();
34
- const _validatedSchemas = typeof WeakSet !== 'undefined' ? new WeakSet() : { add() { }, has() { return false; } };
34
+ const _validationCache = typeof WeakMap !== 'undefined'
35
+ ? new WeakMap()
36
+ : { set() { }, get() { return undefined; }, has() { return false; } };
37
+ const _warnedSchemas = typeof WeakSet !== 'undefined' ? new WeakSet() : { add() { }, has() { return false; } };
35
38
  function validateSchemaOnce(schema) {
36
39
  if (!__DEV__ || !schema || typeof schema !== 'object') {
37
40
  return { valid: true, messages: [] };
38
41
  }
39
- if (_validatedSchemas.has(schema)) {
40
- // We don't cache the result intentionally — once a schema object has
41
- // been logged, we don't re-log on every re-render. Visual invalid flag
42
- // still derives from the structural presence of required fields below.
43
- return { valid: true, messages: [] };
42
+ // Return cached result so re-renders (and the post-mount forceUpdate that
43
+ // runs to pick up lazy plugin registrations) preserve the invalid flag.
44
+ // Dedup of the console.warn is handled separately via _warnedSchemas.
45
+ const cached = _validationCache.get(schema);
46
+ if (cached) {
47
+ return cached;
44
48
  }
45
- _validatedSchemas.add(schema);
49
+ let entry = { valid: true, messages: [] };
46
50
  try {
47
51
  const result = validateSchema(schema);
48
52
  if (!result.valid) {
49
53
  const msgs = result.errors.map(e => `${e.path}: ${e.message}`);
50
- // eslint-disable-next-line no-console
51
- console.warn('[ObjectUI] Invalid schema detected:\n' + msgs.join('\n'), schema);
52
- return { valid: false, messages: msgs };
54
+ entry = { valid: false, messages: msgs };
55
+ if (!_warnedSchemas.has(schema)) {
56
+ _warnedSchemas.add(schema);
57
+ // eslint-disable-next-line no-console
58
+ console.warn('[ObjectUI] Invalid schema detected:\n' + msgs.join('\n'), schema);
59
+ }
53
60
  }
54
61
  }
55
62
  catch (err) {
56
63
  // Validator itself failed — surface but don't crash render.
57
- // eslint-disable-next-line no-console
58
- console.warn('[ObjectUI] Schema validator threw:', err);
64
+ if (!_warnedSchemas.has(schema)) {
65
+ _warnedSchemas.add(schema);
66
+ // eslint-disable-next-line no-console
67
+ console.warn('[ObjectUI] Schema validator threw:', err);
68
+ }
59
69
  }
60
- return { valid: true, messages: [] };
70
+ _validationCache.set(schema, entry);
71
+ return entry;
61
72
  }
62
73
  /**
63
74
  * Extract AriaPropsSchema properties from a schema node and convert
@@ -129,7 +140,16 @@ export const SchemaRenderer = forwardRef(({ schema, ...props }, _ref) => {
129
140
  // Re-render trigger when the global ComponentRegistry mutates (e.g. a
130
141
  // lazy-loaded plugin finishes registering its components).
131
142
  const [, forceUpdate] = useReducer((n) => n + 1, 0);
132
- useEffect(() => ComponentRegistry.subscribe(forceUpdate), []);
143
+ useEffect(() => {
144
+ const unsubscribe = ComponentRegistry.subscribe(forceUpdate);
145
+ // Recheck after mount: if the lazy plugin finished registering between
146
+ // the first render and this effect (e.g. its module was already cached so
147
+ // notify() fired synchronously before subscribe()), we'd otherwise stay
148
+ // stuck on the "Loading…" fallback forever. A one-shot forceUpdate gives
149
+ // the next render a fresh look at the registry.
150
+ forceUpdate();
151
+ return unsubscribe;
152
+ }, []);
133
153
  const [lazyError, setLazyError] = useState(null);
134
154
  // Evaluate schema expressions against the data source
135
155
  const evaluatedSchema = useMemo(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/react",
3
- "version": "6.2.1",
3
+ "version": "6.2.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "React bindings and SchemaRenderer component for Object UI",
@@ -26,10 +26,10 @@
26
26
  "dependencies": {
27
27
  "@objectstack/spec": "^6.7.1",
28
28
  "react-hook-form": "^7.76.1",
29
- "@object-ui/core": "6.2.1",
30
- "@object-ui/data-objectstack": "6.2.1",
31
- "@object-ui/i18n": "6.2.1",
32
- "@object-ui/types": "6.2.1"
29
+ "@object-ui/core": "6.2.2",
30
+ "@object-ui/data-objectstack": "6.2.2",
31
+ "@object-ui/i18n": "6.2.2",
32
+ "@object-ui/types": "6.2.2"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^18.0.0 || ^19.0.0",