@object-ui/react 3.1.5 → 3.3.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.
Files changed (109) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +28 -3
  3. package/dist/SchemaRenderer.js +2 -2
  4. package/dist/components/form/FieldFactory.js +5 -2
  5. package/dist/context/AppShellContext.d.ts +26 -0
  6. package/dist/context/AppShellContext.js +67 -0
  7. package/dist/context/index.d.ts +1 -7
  8. package/dist/context/index.js +1 -7
  9. package/dist/hooks/index.d.ts +1 -0
  10. package/dist/hooks/index.js +1 -0
  11. package/dist/hooks/useDataRefresh.d.ts +36 -0
  12. package/dist/hooks/useDataRefresh.js +50 -0
  13. package/dist/hooks/useDiscovery.d.ts +12 -0
  14. package/dist/hooks/useDiscovery.js +6 -0
  15. package/dist/hooks/usePerformanceBudget.js +1 -1
  16. package/package.json +32 -9
  17. package/.turbo/turbo-build.log +0 -4
  18. package/src/LazyPluginLoader.tsx +0 -174
  19. package/src/SchemaRenderer.tsx +0 -266
  20. package/src/__tests__/LazyPluginLoader.test.tsx +0 -176
  21. package/src/__tests__/SchemaRenderer.aria.test.tsx +0 -118
  22. package/src/__tests__/SchemaRenderer.debug.test.tsx +0 -69
  23. package/src/__tests__/SchemaRenderer.errorBoundary.test.tsx +0 -114
  24. package/src/__tests__/SchemaRenderer.expressions.test.tsx +0 -131
  25. package/src/__tests__/SchemaRendererProvider.smoke.test.tsx +0 -132
  26. package/src/__tests__/ThemeProvider.test.tsx +0 -451
  27. package/src/__tests__/useNavigationOverlay.test.ts +0 -578
  28. package/src/__tests__/useOffline.test.ts +0 -198
  29. package/src/__tests__/usePageTransition.test.ts +0 -214
  30. package/src/__tests__/usePageVariables.test.tsx +0 -334
  31. package/src/__tests__/usePerformance.test.ts +0 -137
  32. package/src/__tests__/useViewData.test.tsx +0 -422
  33. package/src/__tests__/view-switching.test.tsx +0 -456
  34. package/src/components/form/FieldFactory.tsx +0 -509
  35. package/src/components/form/FormRenderer.test.tsx +0 -744
  36. package/src/components/form/FormRenderer.tsx +0 -258
  37. package/src/components/form/README.md +0 -352
  38. package/src/components/form/index.ts +0 -12
  39. package/src/context/ActionContext.tsx +0 -213
  40. package/src/context/DndContext.tsx +0 -260
  41. package/src/context/NotificationContext.tsx +0 -280
  42. package/src/context/SchemaRendererContext.tsx +0 -48
  43. package/src/context/ThemeContext.tsx +0 -325
  44. package/src/context/__tests__/ActionContext.test.tsx +0 -174
  45. package/src/context/__tests__/DndContext.test.tsx +0 -150
  46. package/src/context/__tests__/NotificationContext.test.tsx +0 -176
  47. package/src/context/__tests__/useDataScope.test.tsx +0 -91
  48. package/src/context/index.ts +0 -13
  49. package/src/hooks/__tests__/useActionEngine.test.ts +0 -170
  50. package/src/hooks/__tests__/useActionRunner.test.ts +0 -153
  51. package/src/hooks/__tests__/useAnimation.test.ts +0 -82
  52. package/src/hooks/__tests__/useColumnSummary.test.ts +0 -93
  53. package/src/hooks/__tests__/useCrudShortcuts.test.ts +0 -85
  54. package/src/hooks/__tests__/useDebugMode.test.ts +0 -83
  55. package/src/hooks/__tests__/useDensityMode.test.ts +0 -81
  56. package/src/hooks/__tests__/useDiscovery.test.tsx +0 -149
  57. package/src/hooks/__tests__/useDynamicApp.test.ts +0 -161
  58. package/src/hooks/__tests__/useETagCache.test.ts +0 -153
  59. package/src/hooks/__tests__/useExpression.test.ts +0 -86
  60. package/src/hooks/__tests__/useFocusTrap.test.ts +0 -294
  61. package/src/hooks/__tests__/useKeyboardShortcuts.test.ts +0 -144
  62. package/src/hooks/__tests__/usePageTransition.test.ts +0 -158
  63. package/src/hooks/__tests__/usePerformanceBudget.test.ts +0 -157
  64. package/src/hooks/__tests__/useReducedMotion.test.ts +0 -104
  65. package/src/hooks/__tests__/useSchemaPersistence.test.ts +0 -220
  66. package/src/hooks/__tests__/useViewSharing.test.ts +0 -121
  67. package/src/hooks/__tests__/useViewTransition.test.ts +0 -61
  68. package/src/hooks/index.ts +0 -35
  69. package/src/hooks/useActionEngine.ts +0 -84
  70. package/src/hooks/useActionRunner.ts +0 -119
  71. package/src/hooks/useAnimation.ts +0 -117
  72. package/src/hooks/useClientNotifications.ts +0 -251
  73. package/src/hooks/useColumnSummary.ts +0 -87
  74. package/src/hooks/useCrudShortcuts.ts +0 -126
  75. package/src/hooks/useDebugMode.ts +0 -95
  76. package/src/hooks/useDensityMode.ts +0 -102
  77. package/src/hooks/useDiscovery.ts +0 -154
  78. package/src/hooks/useDynamicApp.ts +0 -142
  79. package/src/hooks/useETagCache.ts +0 -404
  80. package/src/hooks/useExpression.ts +0 -56
  81. package/src/hooks/useFocusManagement.ts +0 -248
  82. package/src/hooks/useFocusTrap.ts +0 -138
  83. package/src/hooks/useGlobalUndo.ts +0 -98
  84. package/src/hooks/useKeyboardShortcuts.ts +0 -119
  85. package/src/hooks/useNavigationOverlay.ts +0 -190
  86. package/src/hooks/useOffline.ts +0 -301
  87. package/src/hooks/usePageTransition.ts +0 -187
  88. package/src/hooks/usePageVariables.tsx +0 -157
  89. package/src/hooks/usePerformance.ts +0 -246
  90. package/src/hooks/usePerformanceBudget.ts +0 -313
  91. package/src/hooks/useReducedMotion.ts +0 -53
  92. package/src/hooks/useSchemaPersistence.ts +0 -222
  93. package/src/hooks/useViewData.ts +0 -201
  94. package/src/hooks/useViewSharing.ts +0 -140
  95. package/src/hooks/useViewTransition.ts +0 -144
  96. package/src/index.ts +0 -41
  97. package/src/spec-bridge/SpecBridge.ts +0 -64
  98. package/src/spec-bridge/__tests__/P1SpecBridge.test.ts +0 -855
  99. package/src/spec-bridge/__tests__/SpecBridge.test.ts +0 -550
  100. package/src/spec-bridge/bridges/dashboard.ts +0 -180
  101. package/src/spec-bridge/bridges/form-view.ts +0 -109
  102. package/src/spec-bridge/bridges/list-view.ts +0 -187
  103. package/src/spec-bridge/bridges/page.ts +0 -136
  104. package/src/spec-bridge/index.ts +0 -14
  105. package/src/spec-bridge/types.ts +0 -38
  106. package/src/utils/i18n.ts +0 -10
  107. package/tsconfig.json +0 -17
  108. package/tsconfig.tsbuildinfo +0 -1
  109. package/vitest.config.ts +0 -2
@@ -1,114 +0,0 @@
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
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
- import { render, screen, fireEvent } from '@testing-library/react';
11
- import React from 'react';
12
- import { ComponentRegistry } from '@object-ui/core';
13
- import { SchemaRenderer, SchemaErrorBoundary } from '../SchemaRenderer';
14
-
15
- // Suppress console.error from React error boundary during tests
16
- const originalConsoleError = console.error;
17
- beforeEach(() => {
18
- console.error = vi.fn();
19
- });
20
- afterEach(() => {
21
- console.error = originalConsoleError;
22
- });
23
-
24
- const CrashingWidget: React.FC = () => {
25
- throw new Error('Widget exploded!');
26
- };
27
-
28
- const StableWidget: React.FC<any> = (props) => (
29
- <div data-testid="stable-widget">{props.content || 'Stable'}</div>
30
- );
31
-
32
- describe('SchemaErrorBoundary', () => {
33
- it('should render children normally when no error', () => {
34
- render(
35
- <SchemaErrorBoundary>
36
- <div data-testid="child">OK</div>
37
- </SchemaErrorBoundary>
38
- );
39
- expect(screen.getByTestId('child')).toBeInTheDocument();
40
- });
41
-
42
- it('should catch render errors and display fallback', () => {
43
- render(
44
- <SchemaErrorBoundary componentType="crashing-widget">
45
- <CrashingWidget />
46
- </SchemaErrorBoundary>
47
- );
48
- expect(screen.getByRole('alert')).toBeInTheDocument();
49
- expect(screen.getByText(/failed to render/i)).toBeInTheDocument();
50
- expect(screen.getByText(/"crashing-widget"/)).toBeInTheDocument();
51
- expect(screen.getByText('Widget exploded!')).toBeInTheDocument();
52
- });
53
-
54
- it('should display retry button that resets the error', () => {
55
- render(
56
- <SchemaErrorBoundary>
57
- <CrashingWidget />
58
- </SchemaErrorBoundary>
59
- );
60
- expect(screen.getByRole('alert')).toBeInTheDocument();
61
- const retryButton = screen.getByText('Retry');
62
- expect(retryButton).toBeInTheDocument();
63
- });
64
-
65
- it('should work without componentType prop', () => {
66
- render(
67
- <SchemaErrorBoundary>
68
- <CrashingWidget />
69
- </SchemaErrorBoundary>
70
- );
71
- expect(screen.getByText(/failed to render/i)).toBeInTheDocument();
72
- });
73
- });
74
-
75
- describe('SchemaRenderer error boundary integration', () => {
76
- beforeEach(() => {
77
- ComponentRegistry.register('crashing-widget', CrashingWidget);
78
- ComponentRegistry.register('stable-widget', StableWidget);
79
- });
80
-
81
- afterEach(() => {
82
- ComponentRegistry.unregister?.('crashing-widget');
83
- ComponentRegistry.unregister?.('stable-widget');
84
- });
85
-
86
- it('should catch errors from a crashing component', () => {
87
- render(
88
- <SchemaRenderer schema={{ type: 'crashing-widget' }} />
89
- );
90
- expect(screen.getByRole('alert')).toBeInTheDocument();
91
- expect(screen.getByText('Widget exploded!')).toBeInTheDocument();
92
- });
93
-
94
- it('should not affect stable components', () => {
95
- render(
96
- <SchemaRenderer schema={{ type: 'stable-widget', content: 'Hello' }} />
97
- );
98
- expect(screen.getByTestId('stable-widget')).toBeInTheDocument();
99
- expect(screen.getByText('Hello')).toBeInTheDocument();
100
- });
101
-
102
- it('should isolate crashes between multiple renderers', () => {
103
- render(
104
- <div>
105
- <SchemaRenderer schema={{ type: 'crashing-widget' }} />
106
- <SchemaRenderer schema={{ type: 'stable-widget', content: 'Still works' }} />
107
- </div>
108
- );
109
- // Crashing one should not affect the other
110
- expect(screen.getByRole('alert')).toBeInTheDocument();
111
- expect(screen.getByTestId('stable-widget')).toBeInTheDocument();
112
- expect(screen.getByText('Still works')).toBeInTheDocument();
113
- });
114
- });
@@ -1,131 +0,0 @@
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
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
10
- import { render, screen } from '@testing-library/react';
11
- import React from 'react';
12
- import { ComponentRegistry } from '@object-ui/core';
13
- import { SchemaRenderer } from '../SchemaRenderer';
14
- import { SchemaRendererContext } from '../context/SchemaRendererContext';
15
-
16
- // Simple test component
17
- const TestComponent = (props: any) => (
18
- <div data-testid="test-component" data-disabled={props.disabled || undefined}>
19
- {props.content || props.label || 'Test'}
20
- </div>
21
- );
22
-
23
- describe('SchemaRenderer Expression Integration', () => {
24
- beforeEach(() => {
25
- ComponentRegistry.register('test-component', TestComponent);
26
- });
27
-
28
- afterEach(() => {
29
- ComponentRegistry.unregister?.('test-component');
30
- });
31
-
32
- describe('visible / hidden expressions', () => {
33
- it('renders when visible is true', () => {
34
- render(<SchemaRenderer schema={{ type: 'test-component', visible: true }} />);
35
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
36
- });
37
-
38
- it('does not render when visible is false', () => {
39
- const { container } = render(<SchemaRenderer schema={{ type: 'test-component', visible: false }} />);
40
- expect(container.innerHTML).toBe('');
41
- });
42
-
43
- it('evaluates visible expression string', () => {
44
- render(
45
- <SchemaRendererContext.Provider value={{ dataSource: { role: 'admin' } }}>
46
- <SchemaRenderer schema={{ type: 'test-component', visible: '${data.role === "admin"}' }} />
47
- </SchemaRendererContext.Provider>
48
- );
49
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
50
- });
51
-
52
- it('hides when visible expression evaluates to false', () => {
53
- const { container } = render(
54
- <SchemaRendererContext.Provider value={{ dataSource: { role: 'viewer' } }}>
55
- <SchemaRenderer schema={{ type: 'test-component', visible: '${data.role === "admin"}' }} />
56
- </SchemaRendererContext.Provider>
57
- );
58
- expect(container.innerHTML).toBe('');
59
- });
60
-
61
- it('hides when hidden is true', () => {
62
- const { container } = render(<SchemaRenderer schema={{ type: 'test-component', hidden: true }} />);
63
- expect(container.innerHTML).toBe('');
64
- });
65
-
66
- it('shows when hidden is false', () => {
67
- render(<SchemaRenderer schema={{ type: 'test-component', hidden: false }} />);
68
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
69
- });
70
-
71
- it('hides with hiddenOn expression', () => {
72
- const { container } = render(
73
- <SchemaRendererContext.Provider value={{ dataSource: { status: 'draft' } }}>
74
- <SchemaRenderer schema={{ type: 'test-component', hiddenOn: '${data.status === "draft"}' }} />
75
- </SchemaRendererContext.Provider>
76
- );
77
- expect(container.innerHTML).toBe('');
78
- });
79
-
80
- it('visible takes precedence over hidden', () => {
81
- render(<SchemaRenderer schema={{ type: 'test-component', visible: true, hidden: true }} />);
82
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
83
- });
84
- });
85
-
86
- describe('disabled expressions', () => {
87
- it('passes disabled=true when disabled expression is true', () => {
88
- render(<SchemaRenderer schema={{ type: 'test-component', disabled: true }} />);
89
- expect(screen.getByTestId('test-component')).toHaveAttribute('data-disabled', 'true');
90
- });
91
-
92
- it('evaluates disabled expression string', () => {
93
- render(
94
- <SchemaRendererContext.Provider value={{ dataSource: { status: 'locked' } }}>
95
- <SchemaRenderer schema={{ type: 'test-component', disabled: '${data.status === "locked"}' }} />
96
- </SchemaRendererContext.Provider>
97
- );
98
- expect(screen.getByTestId('test-component')).toHaveAttribute('data-disabled', 'true');
99
- });
100
-
101
- it('does not set disabled when expression is false', () => {
102
- render(
103
- <SchemaRendererContext.Provider value={{ dataSource: { status: 'active' } }}>
104
- <SchemaRenderer schema={{ type: 'test-component', disabled: '${data.status === "locked"}' }} />
105
- </SchemaRendererContext.Provider>
106
- );
107
- expect(screen.getByTestId('test-component')).not.toHaveAttribute('data-disabled');
108
- });
109
-
110
- it('evaluates disabledOn expression', () => {
111
- render(
112
- <SchemaRendererContext.Provider value={{ dataSource: { readOnly: true } }}>
113
- <SchemaRenderer schema={{ type: 'test-component', disabledOn: '${data.readOnly}' }} />
114
- </SchemaRendererContext.Provider>
115
- );
116
- expect(screen.getByTestId('test-component')).toHaveAttribute('data-disabled', 'true');
117
- });
118
- });
119
-
120
- describe('defaults', () => {
121
- it('renders by default when no visibility props are set', () => {
122
- render(<SchemaRenderer schema={{ type: 'test-component' }} />);
123
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
124
- });
125
-
126
- it('is not disabled by default', () => {
127
- render(<SchemaRenderer schema={{ type: 'test-component' }} />);
128
- expect(screen.getByTestId('test-component')).not.toHaveAttribute('data-disabled');
129
- });
130
- });
131
- });
@@ -1,132 +0,0 @@
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
- /**
10
- * Smoke tests for SchemaRendererProvider.
11
- *
12
- * These tests ensure that every registered plugin component that calls
13
- * useSchemaContext() can render without throwing when wrapped in a
14
- * SchemaRendererProvider. This catches the class of errors reported in
15
- * Storybook ("useSchemaContext must be used within a SchemaRendererProvider").
16
- */
17
-
18
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
19
- import { render, screen } from '@testing-library/react';
20
- import React from 'react';
21
- import { ComponentRegistry } from '@object-ui/core';
22
- import { SchemaRenderer } from '../SchemaRenderer';
23
- import { SchemaRendererProvider, useSchemaContext } from '../context/SchemaRendererContext';
24
-
25
- // Suppress console.error from React error boundary during tests
26
- const originalConsoleError = console.error;
27
- beforeEach(() => {
28
- console.error = vi.fn();
29
- });
30
- afterEach(() => {
31
- console.error = originalConsoleError;
32
- });
33
-
34
- // Helper: a component that calls useSchemaContext (mimics plugin pattern)
35
- const ContextConsumer: React.FC<any> = ({ schema }) => {
36
- const { dataSource } = useSchemaContext();
37
- return <div data-testid="ctx-consumer">dataSource: {JSON.stringify(dataSource)}</div>;
38
- };
39
-
40
- describe('useSchemaContext provider requirement', () => {
41
- it('should throw when used outside SchemaRendererProvider', () => {
42
- expect(() => render(<ContextConsumer schema={{}} />)).toThrow(
43
- 'useSchemaContext must be used within a SchemaRendererProvider'
44
- );
45
- });
46
-
47
- it('should not throw when used inside SchemaRendererProvider', () => {
48
- render(
49
- <SchemaRendererProvider dataSource={{ test: true }}>
50
- <ContextConsumer schema={{}} />
51
- </SchemaRendererProvider>
52
- );
53
- expect(screen.getByTestId('ctx-consumer')).toHaveTextContent('dataSource: {"test":true}');
54
- });
55
-
56
- it('should fall back to empty dataSource when provider has empty object', () => {
57
- render(
58
- <SchemaRendererProvider dataSource={{}}>
59
- <ContextConsumer schema={{}} />
60
- </SchemaRendererProvider>
61
- );
62
- expect(screen.getByTestId('ctx-consumer')).toHaveTextContent('dataSource: {}');
63
- });
64
- });
65
-
66
- describe('SchemaRenderer + SchemaRendererProvider integration', () => {
67
- beforeEach(() => {
68
- ComponentRegistry.register('test-ctx-consumer', ContextConsumer);
69
- });
70
-
71
- afterEach(() => {
72
- ComponentRegistry.unregister?.('test-ctx-consumer');
73
- });
74
-
75
- it('should render a component that calls useSchemaContext without error when provider wraps the tree', () => {
76
- render(
77
- <SchemaRendererProvider dataSource={{ foo: 'bar' }}>
78
- <SchemaRenderer schema={{ type: 'test-ctx-consumer' }} />
79
- </SchemaRendererProvider>
80
- );
81
- expect(screen.getByTestId('ctx-consumer')).toHaveTextContent('dataSource: {"foo":"bar"}');
82
- });
83
-
84
- it('should show error boundary fallback (not crash) when provider is missing', () => {
85
- // Without a provider, the SchemaErrorBoundary catches the throw
86
- render(
87
- <SchemaRenderer schema={{ type: 'test-ctx-consumer' }} />
88
- );
89
- expect(screen.getByRole('alert')).toBeInTheDocument();
90
- expect(screen.getByText(/failed to render/i)).toBeInTheDocument();
91
- });
92
- });
93
-
94
- describe('Plugin component types render inside provider', () => {
95
- // This test ensures all registered plugin types that use useSchemaContext
96
- // can at least mount without throwing inside a SchemaRendererProvider.
97
- const pluginTypes = [
98
- 'kanban',
99
- 'object-kanban',
100
- 'timeline',
101
- 'object-timeline',
102
- 'object-grid',
103
- 'object-calendar',
104
- 'object-map',
105
- 'chart',
106
- 'object-gantt',
107
- ];
108
-
109
- for (const type of pluginTypes) {
110
- it(`type="${type}" should not throw inside SchemaRendererProvider`, () => {
111
- const component = ComponentRegistry.get(type);
112
- if (!component) {
113
- // Component not registered in test environment — skip
114
- return;
115
- }
116
-
117
- // Render via SchemaRenderer inside provider
118
- const { container } = render(
119
- <SchemaRendererProvider dataSource={{}}>
120
- <SchemaRenderer schema={{ type }} />
121
- </SchemaRendererProvider>
122
- );
123
-
124
- // Should NOT show the error boundary alert
125
- const alerts = container.querySelectorAll('[role="alert"]');
126
- const providerErrors = Array.from(alerts).filter((el) =>
127
- el.textContent?.includes('useSchemaContext must be used within')
128
- );
129
- expect(providerErrors).toHaveLength(0);
130
- });
131
- }
132
- });