@object-ui/core 2.0.0 → 3.0.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @object-ui/core@2.0.0 build /home/runner/work/objectui/objectui/packages/core
2
+ > @object-ui/core@3.0.1 build /home/runner/work/objectui/objectui/packages/core
3
3
  > tsc
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @object-ui/core
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/types@3.0.1
8
+
9
+ ## 3.0.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 87979c3: Upgrade to @objectstack v3.0.0 and console bundle optimization
14
+ - Upgraded all @objectstack/\* packages from ^2.0.7 to ^3.0.0
15
+ - Breaking change migrations: Hub → Cloud namespace, definePlugin removed, PaginatedResult.value → .records, PaginatedResult.count → .total, client.meta.getObject() → client.meta.getItem()
16
+ - Console bundle optimization: split monolithic 3.7 MB chunk into 17 granular cacheable chunks (95% main entry reduction)
17
+ - Added gzip + brotli pre-compression via vite-plugin-compression2
18
+ - Lazy MSW loading for build:server (~150 KB gzip saved)
19
+ - Added bundle analysis with rollup-plugin-visualizer
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [87979c3]
24
+ - @object-ui/types@3.0.0
25
+
3
26
  ## 2.0.0
4
27
 
5
28
  ### Major Changes
@@ -0,0 +1,8 @@
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
+ export {};
@@ -0,0 +1,53 @@
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
+ * Performance benchmark suite for @object-ui/core.
10
+ *
11
+ * Part of Q1 2026 roadmap §1.4 Test Coverage Improvement.
12
+ *
13
+ * Run with: npx vitest bench packages/core/src/__benchmarks__/
14
+ */
15
+ import { bench, describe } from 'vitest';
16
+ import { ExpressionEvaluator } from '@object-ui/core';
17
+ import { ComponentRegistry } from '@object-ui/core';
18
+ import { contrastRatio, meetsContrastLevel, hexToHSL } from '@object-ui/core';
19
+ describe('ExpressionEvaluator performance', () => {
20
+ const evaluator = new ExpressionEvaluator({ data: { name: 'Alice', age: 30, active: true } });
21
+ bench('evaluate simple string', () => {
22
+ evaluator.evaluate('Hello ${data.name}');
23
+ });
24
+ bench('evaluate 100 expressions', () => {
25
+ for (let i = 0; i < 100; i++) {
26
+ evaluator.evaluate('Hello ${data.name}');
27
+ }
28
+ });
29
+ });
30
+ describe('ComponentRegistry performance', () => {
31
+ bench('get registered component', () => {
32
+ ComponentRegistry.get('button');
33
+ });
34
+ bench('has check', () => {
35
+ ComponentRegistry.has('button');
36
+ });
37
+ });
38
+ describe('Theme utilities performance', () => {
39
+ bench('hexToHSL conversion', () => {
40
+ hexToHSL('#336699');
41
+ });
42
+ bench('contrastRatio calculation', () => {
43
+ contrastRatio('#000000', '#ffffff');
44
+ });
45
+ bench('meetsContrastLevel check', () => {
46
+ meetsContrastLevel('#000000', '#ffffff', 'AA');
47
+ });
48
+ bench('100 contrast checks', () => {
49
+ for (let i = 0; i < 100; i++) {
50
+ meetsContrastLevel('#336699', '#ffffff', 'AA');
51
+ }
52
+ });
53
+ });
@@ -0,0 +1,75 @@
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
+ export interface ErrorCodeEntry {
9
+ code: string;
10
+ message: string;
11
+ suggestion: string;
12
+ docUrl: string;
13
+ }
14
+ export declare const ERROR_CODES: Record<string, ErrorCodeEntry>;
15
+ /**
16
+ * Check whether a string is a known ObjectUI error code.
17
+ */
18
+ export declare function isErrorCode(code: unknown): code is keyof typeof ERROR_CODES;
19
+ /**
20
+ * Base error class for all ObjectUI errors.
21
+ */
22
+ export declare class ObjectUIError extends Error {
23
+ code: string;
24
+ details?: Record<string, unknown> | undefined;
25
+ constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
26
+ /**
27
+ * Convert error to JSON for logging / debugging.
28
+ */
29
+ toJSON(): {
30
+ name: string;
31
+ message: string;
32
+ code: string;
33
+ details: Record<string, unknown> | undefined;
34
+ stack: string | undefined;
35
+ };
36
+ }
37
+ /**
38
+ * Type guard to check if an error is an ObjectUIError.
39
+ */
40
+ export declare function isObjectUIError(error: unknown): error is ObjectUIError;
41
+ /** Thrown when a schema is invalid or fails validation. */
42
+ export declare class SchemaError extends ObjectUIError {
43
+ constructor(message: string, details?: Record<string, unknown>);
44
+ }
45
+ /** Thrown when a registry operation fails. */
46
+ export declare class RegistryError extends ObjectUIError {
47
+ constructor(message: string, code: string, details?: Record<string, unknown>);
48
+ }
49
+ /** Thrown when expression evaluation fails. */
50
+ export declare class ExpressionError extends ObjectUIError {
51
+ constructor(message: string, details?: Record<string, unknown>);
52
+ }
53
+ /** Thrown when a plugin operation fails. */
54
+ export declare class PluginError extends ObjectUIError {
55
+ constructor(message: string, code: string, details?: Record<string, unknown>);
56
+ }
57
+ /** Thrown when validation of user input / field config fails. */
58
+ export declare class FieldValidationError extends ObjectUIError {
59
+ constructor(message: string, details?: Record<string, unknown>);
60
+ }
61
+ /**
62
+ * Create an `ObjectUIError` (or subclass) from a known error code.
63
+ *
64
+ * @param code - A registered error code (e.g. `"OBJUI-001"`).
65
+ * @param params - Values to interpolate into the message template.
66
+ * @param details - Optional extra details attached to the error.
67
+ */
68
+ export declare function createError(code: string, params?: Record<string, string>, details?: Record<string, unknown>): ObjectUIError;
69
+ /**
70
+ * Format an error message with actionable fix suggestions in development mode.
71
+ *
72
+ * @param error - The `ObjectUIError` to format.
73
+ * @param isDev - When `true`, appends the suggestion and documentation link.
74
+ */
75
+ export declare function formatErrorMessage(error: ObjectUIError, isDev?: boolean): string;
@@ -0,0 +1,224 @@
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
+ const BASE_DOC_URL = 'https://objectui.dev/docs/errors';
9
+ export const ERROR_CODES = {
10
+ 'OBJUI-001': {
11
+ code: 'OBJUI-001',
12
+ message: 'Unknown component type: "${type}"',
13
+ suggestion: 'Ensure the component is registered via registry.register() before rendering. Check for typos in the component type name.',
14
+ docUrl: `${BASE_DOC_URL}/OBJUI-001`,
15
+ },
16
+ 'OBJUI-002': {
17
+ code: 'OBJUI-002',
18
+ message: 'Schema validation failed: ${reason}',
19
+ suggestion: 'Verify the schema against the ObjectUI JSON spec. Run the built-in schema validator for details.',
20
+ docUrl: `${BASE_DOC_URL}/OBJUI-002`,
21
+ },
22
+ 'OBJUI-003': {
23
+ code: 'OBJUI-003',
24
+ message: 'Expression evaluation failed: ${expression}',
25
+ suggestion: 'Check the expression syntax and ensure all referenced variables exist in the current data scope.',
26
+ docUrl: `${BASE_DOC_URL}/OBJUI-003`,
27
+ },
28
+ 'OBJUI-004': {
29
+ code: 'OBJUI-004',
30
+ message: 'Plugin dependency missing: "${dependency}"',
31
+ suggestion: 'Install the required dependency and register it before loading this plugin.',
32
+ docUrl: `${BASE_DOC_URL}/OBJUI-004`,
33
+ },
34
+ 'OBJUI-005': {
35
+ code: 'OBJUI-005',
36
+ message: 'Plugin already loaded: "${plugin}"',
37
+ suggestion: 'A plugin with the same name is already registered. Remove the duplicate or use a unique plugin name.',
38
+ docUrl: `${BASE_DOC_URL}/OBJUI-005`,
39
+ },
40
+ 'OBJUI-006': {
41
+ code: 'OBJUI-006',
42
+ message: 'Plugin not found: "${plugin}"',
43
+ suggestion: 'Verify the plugin name and ensure it has been registered before access.',
44
+ docUrl: `${BASE_DOC_URL}/OBJUI-006`,
45
+ },
46
+ 'OBJUI-007': {
47
+ code: 'OBJUI-007',
48
+ message: 'Registry namespace deprecated: "${namespace}"',
49
+ suggestion: 'Migrate to the new namespace format. See the migration guide for details.',
50
+ docUrl: `${BASE_DOC_URL}/OBJUI-007`,
51
+ },
52
+ 'OBJUI-008': {
53
+ code: 'OBJUI-008',
54
+ message: 'Read-only scope violation: "${scope}"',
55
+ suggestion: 'You are trying to mutate a read-only data scope. Use a writable scope or clone the data before modifying.',
56
+ docUrl: `${BASE_DOC_URL}/OBJUI-008`,
57
+ },
58
+ 'OBJUI-009': {
59
+ code: 'OBJUI-009',
60
+ message: 'Invalid field configuration: "${field}"',
61
+ suggestion: 'Check the field schema for required properties (type, name). Ensure the field widget is registered.',
62
+ docUrl: `${BASE_DOC_URL}/OBJUI-009`,
63
+ },
64
+ 'OBJUI-010': {
65
+ code: 'OBJUI-010',
66
+ message: 'Action execution failed: "${action}"',
67
+ suggestion: 'Verify the action handler is registered and that all required parameters are provided.',
68
+ docUrl: `${BASE_DOC_URL}/OBJUI-010`,
69
+ },
70
+ };
71
+ // ---------------------------------------------------------------------------
72
+ // Type Guards
73
+ // ---------------------------------------------------------------------------
74
+ /**
75
+ * Check whether a string is a known ObjectUI error code.
76
+ */
77
+ export function isErrorCode(code) {
78
+ return typeof code === 'string' && code in ERROR_CODES;
79
+ }
80
+ // ---------------------------------------------------------------------------
81
+ // Base Error Class
82
+ // ---------------------------------------------------------------------------
83
+ /**
84
+ * Base error class for all ObjectUI errors.
85
+ */
86
+ export class ObjectUIError extends Error {
87
+ constructor(message, code, details) {
88
+ super(message);
89
+ Object.defineProperty(this, "code", {
90
+ enumerable: true,
91
+ configurable: true,
92
+ writable: true,
93
+ value: code
94
+ });
95
+ Object.defineProperty(this, "details", {
96
+ enumerable: true,
97
+ configurable: true,
98
+ writable: true,
99
+ value: details
100
+ });
101
+ this.name = 'ObjectUIError';
102
+ // Maintains proper stack trace for where error was thrown (only in V8)
103
+ if (Error.captureStackTrace) {
104
+ Error.captureStackTrace(this, this.constructor);
105
+ }
106
+ }
107
+ /**
108
+ * Convert error to JSON for logging / debugging.
109
+ */
110
+ toJSON() {
111
+ return {
112
+ name: this.name,
113
+ message: this.message,
114
+ code: this.code,
115
+ details: this.details,
116
+ stack: this.stack,
117
+ };
118
+ }
119
+ }
120
+ /**
121
+ * Type guard to check if an error is an ObjectUIError.
122
+ */
123
+ export function isObjectUIError(error) {
124
+ return error instanceof ObjectUIError;
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // Specialized Error Classes
128
+ // ---------------------------------------------------------------------------
129
+ /** Thrown when a schema is invalid or fails validation. */
130
+ export class SchemaError extends ObjectUIError {
131
+ constructor(message, details) {
132
+ super(message, 'OBJUI-002', details);
133
+ this.name = 'SchemaError';
134
+ }
135
+ }
136
+ /** Thrown when a registry operation fails. */
137
+ export class RegistryError extends ObjectUIError {
138
+ constructor(message, code, details) {
139
+ super(message, code, details);
140
+ this.name = 'RegistryError';
141
+ }
142
+ }
143
+ /** Thrown when expression evaluation fails. */
144
+ export class ExpressionError extends ObjectUIError {
145
+ constructor(message, details) {
146
+ super(message, 'OBJUI-003', details);
147
+ this.name = 'ExpressionError';
148
+ }
149
+ }
150
+ /** Thrown when a plugin operation fails. */
151
+ export class PluginError extends ObjectUIError {
152
+ constructor(message, code, details) {
153
+ super(message, code, details);
154
+ this.name = 'PluginError';
155
+ }
156
+ }
157
+ /** Thrown when validation of user input / field config fails. */
158
+ export class FieldValidationError extends ObjectUIError {
159
+ constructor(message, details) {
160
+ super(message, 'OBJUI-009', details);
161
+ this.name = 'FieldValidationError';
162
+ }
163
+ }
164
+ // ---------------------------------------------------------------------------
165
+ // Factory & Formatting Helpers
166
+ // ---------------------------------------------------------------------------
167
+ /**
168
+ * Interpolate a template string with the given params.
169
+ * Template variables use the `${key}` syntax.
170
+ */
171
+ function interpolate(template, params) {
172
+ return template.replace(/\$\{(\w+)\}/g, (_match, key) => {
173
+ if (!(key in params) && typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
174
+ console.warn(`[ObjectUI] Missing interpolation parameter "${key}" in error message template.`);
175
+ }
176
+ return params[key] ?? `\${${key}}`;
177
+ });
178
+ }
179
+ /**
180
+ * Create an `ObjectUIError` (or subclass) from a known error code.
181
+ *
182
+ * @param code - A registered error code (e.g. `"OBJUI-001"`).
183
+ * @param params - Values to interpolate into the message template.
184
+ * @param details - Optional extra details attached to the error.
185
+ */
186
+ export function createError(code, params = {}, details) {
187
+ const entry = ERROR_CODES[code];
188
+ const message = entry
189
+ ? interpolate(entry.message, params)
190
+ : `Unknown error code: ${code}`;
191
+ switch (code) {
192
+ case 'OBJUI-002':
193
+ return new SchemaError(message, details);
194
+ case 'OBJUI-003':
195
+ return new ExpressionError(message, details);
196
+ case 'OBJUI-004':
197
+ case 'OBJUI-005':
198
+ case 'OBJUI-006':
199
+ return new PluginError(message, code, details);
200
+ case 'OBJUI-007':
201
+ case 'OBJUI-001':
202
+ return new RegistryError(message, code, details);
203
+ case 'OBJUI-009':
204
+ return new FieldValidationError(message, details);
205
+ default:
206
+ return new ObjectUIError(message, code, details);
207
+ }
208
+ }
209
+ /**
210
+ * Format an error message with actionable fix suggestions in development mode.
211
+ *
212
+ * @param error - The `ObjectUIError` to format.
213
+ * @param isDev - When `true`, appends the suggestion and documentation link.
214
+ */
215
+ export function formatErrorMessage(error, isDev = typeof process !== 'undefined' &&
216
+ process.env?.NODE_ENV !== 'production') {
217
+ const entry = ERROR_CODES[error.code];
218
+ let formatted = `[${error.code}] ${error.message}`;
219
+ if (isDev && entry) {
220
+ formatted += `\n\n💡 Suggestion: ${entry.suggestion}`;
221
+ formatted += `\n📖 Docs: ${entry.docUrl}`;
222
+ }
223
+ return formatted;
224
+ }
package/dist/index.d.ts CHANGED
@@ -19,3 +19,5 @@ export * from './query/index.js';
19
19
  export * from './adapters/index.js';
20
20
  export * from './theme/index.js';
21
21
  export * from './data-scope/index.js';
22
+ export * from './errors/index.js';
23
+ export * from './utils/debug.js';
package/dist/index.js CHANGED
@@ -18,3 +18,5 @@ export * from './query/index.js';
18
18
  export * from './adapters/index.js';
19
19
  export * from './theme/index.js';
20
20
  export * from './data-scope/index.js';
21
+ export * from './errors/index.js';
22
+ export * from './utils/debug.js';
@@ -37,7 +37,13 @@ export class Registry {
37
37
  // Warn if registering without namespace (deprecated pattern)
38
38
  if (!meta?.namespace) {
39
39
  console.warn(`Registering component "${type}" without a namespace is deprecated. ` +
40
- `Please provide a namespace in the meta parameter.`);
40
+ `Please provide a namespace in the meta parameter.\n\n` +
41
+ ` Migration:\n` +
42
+ ` // Before (deprecated):\n` +
43
+ ` registry.register('${type}', MyComponent);\n\n` +
44
+ ` // After:\n` +
45
+ ` registry.register('${type}', MyComponent, { namespace: 'my-plugin' });\n\n` +
46
+ ` See: https://github.com/objectstack-ai/objectui/blob/main/MIGRATION_GUIDE.md`);
41
47
  }
42
48
  if (this.components.has(fullType)) {
43
49
  // console.warn(`Component type "${fullType}" is already registered. Overwriting.`);
@@ -80,3 +80,26 @@ export declare function resolveThemeInheritance(theme: Theme, registry: Map<stri
80
80
  * @returns 'light' or 'dark'
81
81
  */
82
82
  export declare function resolveMode(mode?: ThemeMode, systemDark?: boolean): 'light' | 'dark';
83
+ /**
84
+ * Calculate the WCAG 2.1 contrast ratio between two hex colors.
85
+ * Returns a value between 1 and 21.
86
+ *
87
+ * @param hex1 - First color in hex format (#RGB or #RRGGBB)
88
+ * @param hex2 - Second color in hex format (#RGB or #RRGGBB)
89
+ * @returns Contrast ratio (1-21), or null if colors are invalid
90
+ */
91
+ export declare function contrastRatio(hex1: string, hex2: string): number | null;
92
+ /**
93
+ * Check if two colors meet the specified WCAG contrast level.
94
+ *
95
+ * WCAG levels:
96
+ * - AA: 4.5:1 for normal text, 3:1 for large text
97
+ * - AAA: 7:1 for normal text, 4.5:1 for large text
98
+ *
99
+ * @param hex1 - First color in hex format
100
+ * @param hex2 - Second color in hex format
101
+ * @param level - WCAG level: 'AA' or 'AAA'
102
+ * @param isLargeText - Whether the text is large (18pt+ or 14pt+ bold)
103
+ * @returns true if the color pair meets the required contrast level
104
+ */
105
+ export declare function meetsContrastLevel(hex1: string, hex2: string, level?: 'AA' | 'AAA', isLargeText?: boolean): boolean;
@@ -398,3 +398,72 @@ export function resolveMode(mode = 'auto', systemDark) {
398
398
  }
399
399
  return 'light'; // fallback
400
400
  }
401
+ // ============================================================================
402
+ // WCAG Contrast Checking (v2.0.7)
403
+ // ============================================================================
404
+ /**
405
+ * Parse a hex color string to RGB values [0-255].
406
+ */
407
+ function hexToRGB(hex) {
408
+ let clean = hex.replace(/^#/, '');
409
+ if (clean.length === 3) {
410
+ clean = clean[0] + clean[0] + clean[1] + clean[1] + clean[2] + clean[2];
411
+ }
412
+ const match = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(clean);
413
+ if (!match)
414
+ return null;
415
+ return [parseInt(match[1], 16), parseInt(match[2], 16), parseInt(match[3], 16)];
416
+ }
417
+ /**
418
+ * Calculate relative luminance per WCAG 2.1 spec.
419
+ * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
420
+ */
421
+ function relativeLuminance(r, g, b) {
422
+ const [rs, gs, bs] = [r, g, b].map(c => {
423
+ const s = c / 255;
424
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
425
+ });
426
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
427
+ }
428
+ /**
429
+ * Calculate the WCAG 2.1 contrast ratio between two hex colors.
430
+ * Returns a value between 1 and 21.
431
+ *
432
+ * @param hex1 - First color in hex format (#RGB or #RRGGBB)
433
+ * @param hex2 - Second color in hex format (#RGB or #RRGGBB)
434
+ * @returns Contrast ratio (1-21), or null if colors are invalid
435
+ */
436
+ export function contrastRatio(hex1, hex2) {
437
+ const rgb1 = hexToRGB(hex1);
438
+ const rgb2 = hexToRGB(hex2);
439
+ if (!rgb1 || !rgb2)
440
+ return null;
441
+ const l1 = relativeLuminance(...rgb1);
442
+ const l2 = relativeLuminance(...rgb2);
443
+ const lighter = Math.max(l1, l2);
444
+ const darker = Math.min(l1, l2);
445
+ return (lighter + 0.05) / (darker + 0.05);
446
+ }
447
+ /**
448
+ * Check if two colors meet the specified WCAG contrast level.
449
+ *
450
+ * WCAG levels:
451
+ * - AA: 4.5:1 for normal text, 3:1 for large text
452
+ * - AAA: 7:1 for normal text, 4.5:1 for large text
453
+ *
454
+ * @param hex1 - First color in hex format
455
+ * @param hex2 - Second color in hex format
456
+ * @param level - WCAG level: 'AA' or 'AAA'
457
+ * @param isLargeText - Whether the text is large (18pt+ or 14pt+ bold)
458
+ * @returns true if the color pair meets the required contrast level
459
+ */
460
+ export function meetsContrastLevel(hex1, hex2, level = 'AA', isLargeText = false) {
461
+ const ratio = contrastRatio(hex1, hex2);
462
+ if (ratio === null)
463
+ return false;
464
+ if (level === 'AAA') {
465
+ return isLargeText ? ratio >= 4.5 : ratio >= 7;
466
+ }
467
+ // AA
468
+ return isLargeText ? ratio >= 3 : ratio >= 4.5;
469
+ }
@@ -5,4 +5,4 @@
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 { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, } from './ThemeEngine';
8
+ export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine';
@@ -5,4 +5,4 @@
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 { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, } from './ThemeEngine';
8
+ export { hexToHSL, toCSSColor, generateColorVars, generateTypographyVars, generateBorderRadiusVars, generateShadowVars, generateAnimationVars, generateZIndexVars, generateThemeVars, mergeThemes, resolveThemeInheritance, resolveMode, contrastRatio, meetsContrastLevel, } from './ThemeEngine';
@@ -0,0 +1,31 @@
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
+ type DebugCategory = 'schema' | 'registry' | 'expression' | 'action' | 'plugin' | 'render';
9
+ /**
10
+ * Log a debug message when OBJECTUI_DEBUG is enabled.
11
+ * No-op in production or when debug mode is off.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // Enable debug mode
16
+ * globalThis.OBJECTUI_DEBUG = true;
17
+ *
18
+ * debugLog('schema', 'Resolving component', { type: 'Button' });
19
+ * // [ObjectUI Debug][schema] Resolving component { type: 'Button' }
20
+ * ```
21
+ */
22
+ export declare function debugLog(category: DebugCategory, message: string, data?: unknown): void;
23
+ /**
24
+ * Start a debug timer. Pair with {@link debugTimeEnd}.
25
+ */
26
+ export declare function debugTime(label: string): void;
27
+ /**
28
+ * End a debug timer and log the elapsed time.
29
+ */
30
+ export declare function debugTimeEnd(label: string): void;
31
+ export {};
@@ -0,0 +1,62 @@
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
+ function isDebugEnabled() {
9
+ try {
10
+ const g = typeof globalThis !== 'undefined' && globalThis.OBJECTUI_DEBUG;
11
+ return ((g === true || g === 'true') ||
12
+ (typeof process !== 'undefined' && process.env?.OBJECTUI_DEBUG === 'true'));
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ /**
19
+ * Log a debug message when OBJECTUI_DEBUG is enabled.
20
+ * No-op in production or when debug mode is off.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * // Enable debug mode
25
+ * globalThis.OBJECTUI_DEBUG = true;
26
+ *
27
+ * debugLog('schema', 'Resolving component', { type: 'Button' });
28
+ * // [ObjectUI Debug][schema] Resolving component { type: 'Button' }
29
+ * ```
30
+ */
31
+ export function debugLog(category, message, data) {
32
+ if (!isDebugEnabled())
33
+ return;
34
+ if (data !== undefined) {
35
+ console.log(`[ObjectUI Debug][${category}] ${message}`, data);
36
+ }
37
+ else {
38
+ console.log(`[ObjectUI Debug][${category}] ${message}`);
39
+ }
40
+ }
41
+ const timers = new Map();
42
+ /**
43
+ * Start a debug timer. Pair with {@link debugTimeEnd}.
44
+ */
45
+ export function debugTime(label) {
46
+ if (!isDebugEnabled())
47
+ return;
48
+ timers.set(label, performance.now());
49
+ }
50
+ /**
51
+ * End a debug timer and log the elapsed time.
52
+ */
53
+ export function debugTimeEnd(label) {
54
+ if (!isDebugEnabled())
55
+ return;
56
+ const start = timers.get(label);
57
+ if (start !== undefined) {
58
+ const elapsed = (performance.now() - start).toFixed(2);
59
+ console.log(`[ObjectUI Debug][perf] ${label}: ${elapsed}ms`);
60
+ timers.delete(label);
61
+ }
62
+ }
@@ -336,7 +336,13 @@ export class ValidationEngine {
336
336
  */
337
337
  evaluateCondition(condition, values) {
338
338
  if (typeof condition === 'function') {
339
- console.warn('Function-based conditions are deprecated and will be removed. Use declarative conditions instead.');
339
+ console.warn('Function-based conditions are deprecated and will be removed. Use declarative conditions instead.\n\n' +
340
+ ' Migration:\n' +
341
+ ' // Before (deprecated):\n' +
342
+ ' { condition: (values) => values.age > 18 }\n\n' +
343
+ ' // After:\n' +
344
+ ' { condition: { field: "age", operator: ">", value: 18 } }\n\n' +
345
+ ' See: https://github.com/objectstack-ai/objectui/blob/main/MIGRATION_GUIDE.md');
340
346
  return false; // Security: reject function-based conditions
341
347
  }
342
348
  if (typeof condition === 'object' && condition.field) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/core",
3
- "version": "2.0.0",
3
+ "version": "3.0.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -24,10 +24,10 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@objectstack/spec": "^2.0.7",
27
+ "@objectstack/spec": "^3.0.2",
28
28
  "lodash": "^4.17.23",
29
29
  "zod": "^4.3.6",
30
- "@object-ui/types": "2.0.0"
30
+ "@object-ui/types": "3.0.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "typescript": "^5.9.3",