@object-ui/components 2.0.0 → 3.0.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.
Files changed (34) hide show
  1. package/.turbo/turbo-build.log +12 -12
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.js +19610 -19344
  5. package/dist/index.umd.cjs +29 -29
  6. package/dist/src/custom/index.d.ts +2 -0
  7. package/dist/src/custom/view-skeleton.d.ts +37 -0
  8. package/dist/src/custom/view-states.d.ts +33 -0
  9. package/package.json +17 -17
  10. package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +811 -0
  11. package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +327 -0
  12. package/src/__tests__/accessibility.test.tsx +137 -0
  13. package/src/__tests__/api-consistency.test.tsx +596 -0
  14. package/src/__tests__/color-contrast.test.tsx +212 -0
  15. package/src/__tests__/edge-cases.test.tsx +285 -0
  16. package/src/__tests__/snapshot-critical.test.tsx +317 -0
  17. package/src/__tests__/snapshot.test.tsx +205 -0
  18. package/src/__tests__/wcag-audit.test.tsx +493 -0
  19. package/src/custom/index.ts +2 -0
  20. package/src/custom/view-skeleton.tsx +243 -0
  21. package/src/custom/view-states.tsx +153 -0
  22. package/src/renderers/complex/data-table.tsx +28 -13
  23. package/src/renderers/complex/resizable.tsx +20 -17
  24. package/src/renderers/data-display/list.tsx +1 -1
  25. package/src/renderers/data-display/table.tsx +1 -1
  26. package/src/renderers/data-display/tree-view.tsx +2 -1
  27. package/src/renderers/form/form.tsx +10 -6
  28. package/src/renderers/layout/aspect-ratio.tsx +1 -1
  29. package/src/stories-json/Accessibility.mdx +297 -0
  30. package/src/stories-json/EdgeCases.stories.tsx +160 -0
  31. package/src/stories-json/GettingStarted.mdx +89 -0
  32. package/src/stories-json/Introduction.mdx +127 -0
  33. package/src/ui/slider.tsx +6 -2
  34. package/src/stories/Introduction.mdx +0 -61
@@ -0,0 +1,297 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Getting Started/Accessibility" />
4
+
5
+ # Accessibility Reference
6
+
7
+ ObjectUI targets **WCAG 2.1 Level AA** conformance. Every component inherits accessible
8
+ primitives from [Radix UI](https://www.radix-ui.com/) and is styled with Tailwind CSS
9
+ utility classes that respect user preferences for reduced motion and color contrast.
10
+
11
+ ---
12
+
13
+ ## Compliance Baseline
14
+
15
+ | Standard | Level | Status |
16
+ |---|---|---|
17
+ | WCAG 2.1 | AA | ✅ Target conformance for all components |
18
+ | WAI-ARIA 1.2 | — | ✅ Roles, states, and properties via Radix |
19
+ | Section 508 | — | ✅ Covered by WCAG AA compliance |
20
+
21
+ ObjectUI relies on **Radix UI** for its accessible primitive layer. Radix components
22
+ ship with correct ARIA roles, keyboard interactions, and focus management built in.
23
+ Shadcn UI wraps these primitives with Tailwind styling while preserving all accessibility
24
+ behaviour.
25
+
26
+ ---
27
+
28
+ ## Keyboard Navigation Patterns
29
+
30
+ All interactive components support keyboard navigation following WAI-ARIA authoring
31
+ practices. Below is a reference of the patterns used across component types.
32
+
33
+ ### General Controls
34
+
35
+ | Component | Key | Action |
36
+ |---|---|---|
37
+ | **Button** | `Enter` / `Space` | Activate the button |
38
+ | **Link** | `Enter` | Follow the link |
39
+ | **Toggle** | `Enter` / `Space` | Toggle the state |
40
+ | All focusable | `Tab` | Move focus to next element |
41
+ | All focusable | `Shift + Tab` | Move focus to previous element |
42
+
43
+ ### Composite Widgets
44
+
45
+ | Component | Key | Action |
46
+ |---|---|---|
47
+ | **Tabs** | `Arrow Left` / `Arrow Right` | Move between tab triggers |
48
+ | **Tabs** | `Enter` / `Space` | Activate focused tab |
49
+ | **Tabs** | `Home` / `End` | Jump to first / last tab |
50
+ | **Accordion** | `Arrow Up` / `Arrow Down` | Move between headers |
51
+ | **Accordion** | `Enter` / `Space` | Expand / collapse section |
52
+ | **Accordion** | `Home` / `End` | Jump to first / last header |
53
+ | **Menu / DropdownMenu** | `Arrow Up` / `Arrow Down` | Navigate menu items |
54
+ | **Menu / DropdownMenu** | `Enter` / `Space` | Activate item |
55
+ | **Menu / DropdownMenu** | `Escape` | Close menu and return focus |
56
+ | **NavigationMenu** | `Arrow Left` / `Arrow Right` | Move between top-level items |
57
+ | **NavigationMenu** | `Arrow Down` | Open submenu |
58
+ | **NavigationMenu** | `Escape` | Close submenu |
59
+
60
+ ### Form Fields
61
+
62
+ | Component | Key | Action |
63
+ |---|---|---|
64
+ | **Input / Textarea** | Standard typing | Enter text |
65
+ | **Select** | `Arrow Up` / `Arrow Down` | Navigate options |
66
+ | **Select** | `Enter` | Select option |
67
+ | **Select** | `Escape` | Close listbox |
68
+ | **Checkbox** | `Space` | Toggle checked state |
69
+ | **Radio Group** | `Arrow Up` / `Arrow Down` | Move selection |
70
+ | **Switch** | `Space` | Toggle on/off |
71
+ | **Slider** | `Arrow Left` / `Arrow Right` | Decrease / increase value |
72
+ | **Slider** | `Home` / `End` | Set to minimum / maximum |
73
+ | **DatePicker** | `Arrow Keys` | Navigate calendar grid |
74
+ | **DatePicker** | `Enter` | Select date |
75
+ | **DatePicker** | `Escape` | Close calendar popover |
76
+
77
+ ### Overlay Components
78
+
79
+ | Component | Key | Action |
80
+ |---|---|---|
81
+ | **Dialog** | `Escape` | Close the dialog |
82
+ | **Dialog** | `Tab` | Cycle focus within dialog (focus trap) |
83
+ | **AlertDialog** | `Escape` | Close (if not critical) |
84
+ | **AlertDialog** | `Tab` | Cycle focus within alert |
85
+ | **Popover** | `Escape` | Close popover |
86
+ | **Tooltip** | `Escape` | Dismiss tooltip |
87
+ | **Sheet** | `Escape` | Close sheet overlay |
88
+ | **Sheet** | `Tab` | Cycle focus within sheet |
89
+
90
+ ### Data Views (Plugins)
91
+
92
+ | Component | Key | Action |
93
+ |---|---|---|
94
+ | **DataTable / Grid** | `Arrow Keys` | Navigate cells |
95
+ | **DataTable / Grid** | `Enter` | Activate cell / begin editing |
96
+ | **DataTable / Grid** | `Escape` | Cancel editing |
97
+ | **DataTable / Grid** | `Tab` | Move to next focusable cell |
98
+ | **Kanban** | `Tab` | Move between cards |
99
+ | **Kanban** | `Enter` / `Space` | Open card detail |
100
+
101
+ ---
102
+
103
+ ## ARIA Roles and Attributes
104
+
105
+ ObjectUI components emit the correct ARIA roles and attributes automatically through
106
+ Radix primitives. Below is a reference of the key mappings.
107
+
108
+ ### Primitive Components
109
+
110
+ | Component | ARIA Role | Key Attributes |
111
+ |---|---|---|
112
+ | **Button** | `button` | `aria-disabled`, `aria-pressed` (toggle) |
113
+ | **Badge** | `status` | `aria-label` (when used as status indicator) |
114
+ | **Card** | `region` | `aria-labelledby` (card title) |
115
+ | **Separator** | `separator` | `aria-orientation` |
116
+ | **Avatar** | `img` | `alt` text on image, fallback initials |
117
+ | **Progress** | `progressbar` | `aria-valuenow`, `aria-valuemin`, `aria-valuemax` |
118
+ | **Skeleton** | `status` | `aria-busy="true"`, `aria-label="Loading"` |
119
+
120
+ ### Composite Components
121
+
122
+ | Component | ARIA Role | Key Attributes |
123
+ |---|---|---|
124
+ | **Tabs** | `tablist`, `tab`, `tabpanel` | `aria-selected`, `aria-controls`, `aria-labelledby` |
125
+ | **Accordion** | `region` | `aria-expanded`, `aria-controls` on triggers |
126
+ | **Breadcrumb** | `navigation` | `aria-label="Breadcrumb"`, `aria-current="page"` on active |
127
+ | **NavigationMenu** | `navigation` | `aria-label`, `aria-expanded` on submenus |
128
+ | **Carousel** | `region` | `aria-roledescription="carousel"`, `aria-label` on slides |
129
+
130
+ ### Form Components
131
+
132
+ | Component | ARIA Role | Key Attributes |
133
+ |---|---|---|
134
+ | **Input** | `textbox` | `aria-required`, `aria-invalid`, `aria-describedby` (error/hint) |
135
+ | **Textarea** | `textbox` | `aria-required`, `aria-invalid`, `aria-describedby` |
136
+ | **Select** | `combobox` / `listbox` | `aria-expanded`, `aria-activedescendant`, `aria-required` |
137
+ | **Checkbox** | `checkbox` | `aria-checked`, `aria-required` |
138
+ | **Radio Group** | `radiogroup`, `radio` | `aria-checked`, `aria-required` |
139
+ | **Switch** | `switch` | `aria-checked`, `aria-label` |
140
+ | **Slider** | `slider` | `aria-valuenow`, `aria-valuemin`, `aria-valuemax`, `aria-label` |
141
+ | **Label** | — | `for` / `htmlFor` association with input |
142
+
143
+ ### Overlay Components
144
+
145
+ | Component | ARIA Role | Key Attributes |
146
+ |---|---|---|
147
+ | **Dialog** | `dialog` | `aria-modal="true"`, `aria-labelledby`, `aria-describedby` |
148
+ | **AlertDialog** | `alertdialog` | `aria-modal="true"`, `aria-labelledby`, `aria-describedby` |
149
+ | **Popover** | `dialog` | `aria-expanded` on trigger, auto `aria-labelledby` |
150
+ | **Tooltip** | `tooltip` | `aria-describedby` on trigger element |
151
+ | **Sheet** | `dialog` | `aria-modal="true"`, `aria-labelledby` |
152
+ | **DropdownMenu** | `menu`, `menuitem` | `aria-expanded`, `aria-haspopup` |
153
+ | **ContextMenu** | `menu`, `menuitem` | `aria-expanded`, `aria-haspopup` |
154
+
155
+ ### Data View Components
156
+
157
+ | Component | ARIA Role | Key Attributes |
158
+ |---|---|---|
159
+ | **DataTable** | `table`, `row`, `cell` | `aria-sort` on sortable columns, `aria-rowcount` |
160
+ | **Grid (AG Grid)** | `grid`, `row`, `gridcell` | `aria-colcount`, `aria-rowindex`, `aria-selected` |
161
+ | **Kanban** | `list`, `listitem` | `aria-label` per column, `aria-grabbed` on draggable cards |
162
+
163
+ ---
164
+
165
+ ## Screen Reader Behaviour
166
+
167
+ ObjectUI components are designed to work seamlessly with screen readers
168
+ (NVDA, JAWS, VoiceOver, TalkBack). Key behaviours include:
169
+
170
+ ### Focus Management
171
+ - **Dialogs and Sheets** trap focus within the overlay while open. On close, focus
172
+ returns to the trigger element.
173
+ - **Menus and Popovers** return focus to their trigger on dismiss.
174
+ - **Toast notifications** use `role="status"` with `aria-live="polite"` so screen
175
+ readers announce them without interrupting the user.
176
+
177
+ ### Live Regions
178
+ - **Form validation errors** are linked via `aria-describedby`, so errors are announced
179
+ when the field receives focus.
180
+ - **Loading states** use `aria-busy="true"` on the loading container and `aria-live`
181
+ regions to announce completion.
182
+ - **Toast / Alert** components use `aria-live="polite"` or `aria-live="assertive"`
183
+ depending on urgency.
184
+
185
+ ### Landmark Regions
186
+ - **AppShell** emits `<header>`, `<nav>`, `<main>`, and `<aside>` landmarks so screen
187
+ reader users can jump between sections.
188
+ - **Breadcrumb** uses `<nav aria-label="Breadcrumb">` for quick landmark navigation.
189
+ - **Sidebar** uses `<aside>` with a descriptive `aria-label`.
190
+
191
+ ### Announcements
192
+ - **Sortable table columns** announce sort direction changes via `aria-sort`.
193
+ - **Accordion** sections announce expanded/collapsed state.
194
+ - **Tabs** announce the active tab label on selection.
195
+ - **Carousel** announces slide transitions with `aria-roledescription`.
196
+
197
+ ---
198
+
199
+ ## Color Contrast Requirements
200
+
201
+ ObjectUI uses Tailwind CSS design tokens (CSS custom properties) for all color
202
+ values. The default theme meets WCAG AA contrast ratios:
203
+
204
+ | Element | Minimum Ratio | Standard |
205
+ |---|---|---|
206
+ | Body text (`foreground` on `background`) | **4.5 : 1** | WCAG AA — Normal text |
207
+ | Large text (≥ 18pt or ≥ 14pt bold) | **3 : 1** | WCAG AA — Large text |
208
+ | UI components and graphical objects | **3 : 1** | WCAG 2.1 SC 1.4.11 |
209
+ | Focus indicators | **3 : 1** | WCAG 2.1 SC 1.4.11 |
210
+
211
+ ### Theme Tokens
212
+
213
+ All colors are defined as CSS variables in HSL format:
214
+
215
+ ```css
216
+ :root {
217
+ --background: 0 0% 100%;
218
+ --foreground: 222 84% 5%;
219
+ --primary: 222 47% 11%;
220
+ --primary-foreground: 210 40% 98%;
221
+ --destructive: 0 84% 60%;
222
+ --destructive-foreground: 0 0% 98%;
223
+ --muted: 210 40% 96%;
224
+ --muted-foreground: 215 16% 47%;
225
+ /* ...additional tokens */
226
+ }
227
+ ```
228
+
229
+ When customising tokens, verify contrast ratios with a tool such as the
230
+ [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) or the
231
+ built-in Storybook accessibility panel.
232
+
233
+ ### Dark Mode
234
+
235
+ ObjectUI supports a `.dark` class on the root element. The dark theme ships with
236
+ its own set of tokens that maintain the same contrast ratios:
237
+
238
+ ```css
239
+ .dark {
240
+ --background: 222 84% 5%;
241
+ --foreground: 210 40% 98%;
242
+ /* ...dark tokens */
243
+ }
244
+ ```
245
+
246
+ ### Focus Indicators
247
+
248
+ All interactive elements display a visible focus ring when navigated via keyboard.
249
+ The default ring uses the `--ring` token and applies a `2px` outline with a `2px`
250
+ offset, ensuring it meets the **3 : 1** non-text contrast requirement.
251
+
252
+ ```css
253
+ :root {
254
+ --ring: 222 47% 11%;
255
+ }
256
+ ```
257
+
258
+ > **Tip:** Never remove focus outlines (`outline: none`) without providing an
259
+ > equivalent visible indicator. ObjectUI's `focus-visible` styles handle this
260
+ > automatically.
261
+
262
+ ---
263
+
264
+ ## Testing Accessibility
265
+
266
+ ### Storybook A11y Addon
267
+
268
+ Every story in this Storybook can be audited via the **Accessibility** panel in the
269
+ addons bar. It runs [axe-core](https://github.com/dequelabs/axe-core) checks and
270
+ reports violations, passes, and incomplete audits.
271
+
272
+ ### Automated Testing
273
+
274
+ Use `vitest` with `@testing-library/jest-dom` matchers for assertions like
275
+ `toBeVisible()`, `toHaveAccessibleName()`, and `toHaveAttribute('aria-expanded')`.
276
+
277
+ ```tsx
278
+ import { render, screen } from '@testing-library/react';
279
+ import { axe, toHaveNoViolations } from 'jest-axe';
280
+
281
+ expect.extend(toHaveNoViolations);
282
+
283
+ it('Button has no accessibility violations', async () => {
284
+ const { container } = render(<Button>Click me</Button>);
285
+ const results = await axe(container);
286
+ expect(results).toHaveNoViolations();
287
+ });
288
+ ```
289
+
290
+ ### Manual Testing Checklist
291
+
292
+ - [ ] Navigate all interactive elements using only the keyboard (`Tab`, `Enter`, `Space`, `Escape`, `Arrow` keys).
293
+ - [ ] Verify visible focus indicators on every focusable element.
294
+ - [ ] Test with a screen reader (VoiceOver on macOS, NVDA on Windows).
295
+ - [ ] Check colour contrast using the browser DevTools or WebAIM checker.
296
+ - [ ] Confirm the page is usable at 200% browser zoom.
297
+ - [ ] Verify `prefers-reduced-motion` is respected (animations are disabled or reduced).
@@ -0,0 +1,160 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { SchemaRenderer } from '../SchemaRenderer';
3
+ import type { BaseSchema } from '@object-ui/types';
4
+
5
+ const meta = {
6
+ title: 'Components / Edge Cases',
7
+ component: SchemaRenderer,
8
+ parameters: { layout: 'padded' },
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ schema: { table: { disable: true } },
12
+ },
13
+ } satisfies Meta<any>;
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof meta>;
17
+
18
+ const renderStory = (args: any) => <SchemaRenderer schema={args as unknown as BaseSchema} />;
19
+
20
+ // ── Empty States ──────────────────────────────────────────────
21
+
22
+ export const EmptyStateDefault: Story = {
23
+ name: 'Empty State – Default',
24
+ render: renderStory,
25
+ args: {
26
+ type: 'empty',
27
+ description: 'No items to display',
28
+ } as any,
29
+ };
30
+
31
+ export const EmptyStateWithAction: Story = {
32
+ name: 'Empty State – With Action',
33
+ render: renderStory,
34
+ args: {
35
+ type: 'empty',
36
+ description: 'No results found. Try a different search or create a new item.',
37
+ children: [
38
+ { type: 'button', content: 'Create New', variant: 'default', size: 'sm' },
39
+ ],
40
+ } as any,
41
+ };
42
+
43
+ // ── Loading / Spinner ─────────────────────────────────────────
44
+
45
+ export const SpinnerSmall: Story = {
46
+ name: 'Spinner – Small',
47
+ render: renderStory,
48
+ args: {
49
+ type: 'spinner',
50
+ size: 'sm',
51
+ className: 'text-primary',
52
+ } as any,
53
+ };
54
+
55
+ export const SpinnerLarge: Story = {
56
+ name: 'Spinner – Large',
57
+ render: renderStory,
58
+ args: {
59
+ type: 'spinner',
60
+ size: 'lg',
61
+ className: 'text-primary',
62
+ } as any,
63
+ };
64
+
65
+ export const LoadingWithText: Story = {
66
+ name: 'Loading – With Text',
67
+ render: renderStory,
68
+ args: {
69
+ type: 'loading',
70
+ text: 'Please wait while we fetch your data…',
71
+ className: 'h-[200px]',
72
+ } as any,
73
+ };
74
+
75
+ // ── Overflow / Long Text ──────────────────────────────────────
76
+
77
+ const LONG_TEXT =
78
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit.';
79
+
80
+ export const CardWithLongText: Story = {
81
+ name: 'Card – Very Long Text',
82
+ render: renderStory,
83
+ args: {
84
+ type: 'card',
85
+ className: 'w-[350px]',
86
+ title: 'This is an extremely long card title that should test how the component handles overflow and text wrapping gracefully',
87
+ description: LONG_TEXT,
88
+ children: [
89
+ {
90
+ type: 'text',
91
+ content: LONG_TEXT + ' ' + LONG_TEXT,
92
+ },
93
+ ],
94
+ } as any,
95
+ };
96
+
97
+ export const BadgeWithLongText: Story = {
98
+ name: 'Badge – Very Long Text',
99
+ render: renderStory,
100
+ args: {
101
+ type: 'badge',
102
+ label: 'This is an unusually long badge label that tests truncation and overflow behaviour in tight layouts',
103
+ } as any,
104
+ };
105
+
106
+ export const ButtonWithIconAndLongText: Story = {
107
+ name: 'Button – Icon + Long Text',
108
+ render: (args: any) => <SchemaRenderer schema={args as unknown as BaseSchema} />,
109
+ args: {
110
+ type: 'button',
111
+ props: { variant: 'default' },
112
+ children: [
113
+ { type: 'icon', name: 'download', className: 'mr-2 h-4 w-4' },
114
+ {
115
+ type: 'text',
116
+ content: 'Download All Reports For The Current Financial Year Including Amendments',
117
+ },
118
+ ],
119
+ } as any,
120
+ };
121
+
122
+ // ── RTL Layout ────────────────────────────────────────────────
123
+
124
+ export const RTLCard: Story = {
125
+ name: 'RTL – Card Layout',
126
+ render: (args: any) => (
127
+ <div dir="rtl">
128
+ <SchemaRenderer schema={args as unknown as BaseSchema} />
129
+ </div>
130
+ ),
131
+ args: {
132
+ type: 'card',
133
+ className: 'w-[350px]',
134
+ title: 'عنوان البطاقة',
135
+ description: 'هذا النص باللغة العربية لاختبار تخطيط الاتجاه من اليمين إلى اليسار.',
136
+ children: [
137
+ { type: 'text', content: 'محتوى البطاقة الرئيسي يظهر هنا باللغة العربية.' },
138
+ ],
139
+ footer: [
140
+ { type: 'button', props: { variant: 'outline' }, children: [{ type: 'text', content: 'إلغاء' }] },
141
+ { type: 'button', children: [{ type: 'text', content: 'حفظ' }] },
142
+ ],
143
+ } as any,
144
+ };
145
+
146
+ export const RTLAlert: Story = {
147
+ name: 'RTL – Alert',
148
+ render: (args: any) => (
149
+ <div dir="rtl">
150
+ <SchemaRenderer schema={args as unknown as BaseSchema} />
151
+ </div>
152
+ ),
153
+ args: {
154
+ type: 'alert',
155
+ variant: 'destructive',
156
+ title: 'خطأ',
157
+ description: 'انتهت صلاحية الجلسة. الرجاء تسجيل الدخول مرة أخرى.',
158
+ className: 'w-[400px]',
159
+ } as any,
160
+ };
@@ -0,0 +1,89 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Getting Started" />
4
+
5
+ # ObjectUI Component Library
6
+
7
+ ObjectUI is a **server-driven UI engine** that renders enterprise interfaces from JSON metadata.
8
+ Built on **React**, **Tailwind CSS**, and **Shadcn UI (Radix)**, it bridges the speed of
9
+ low-code with the design quality of hand-crafted components.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # Core packages
15
+ pnpm add @object-ui/types @object-ui/core @object-ui/react
16
+
17
+ # UI layer
18
+ pnpm add @object-ui/components @object-ui/fields @object-ui/layout
19
+ ```
20
+
21
+ Peer dependencies — make sure these are in your project:
22
+
23
+ ```bash
24
+ pnpm add react react-dom tailwindcss
25
+ ```
26
+
27
+ ## Quick Usage
28
+
29
+ ```tsx
30
+ import { ObjectRenderer } from '@object-ui/react';
31
+
32
+ const schema = {
33
+ type: 'Card',
34
+ props: { title: 'Hello' },
35
+ children: [
36
+ {
37
+ type: 'Text',
38
+ props: { content: 'Rendered from JSON!' },
39
+ },
40
+ ],
41
+ };
42
+
43
+ export default function App() {
44
+ return <ObjectRenderer schema={schema} />;
45
+ }
46
+ ```
47
+
48
+ The `ObjectRenderer` resolves each node in the schema tree against the **Component Registry**,
49
+ producing a fully interactive React tree.
50
+
51
+ ## Accessibility
52
+
53
+ Every component in ObjectUI follows the **WAI-ARIA** authoring practices provided by
54
+ [Radix UI](https://www.radix-ui.com/). This means:
55
+
56
+ - Correct ARIA roles and attributes out of the box
57
+ - Full keyboard navigation support
58
+ - Focus management for overlays, dialogs, and menus
59
+ - Screen-reader-friendly labels and live regions
60
+
61
+ Run the Storybook accessibility addon (included) to audit any story for violations.
62
+
63
+ ## Theme Configuration
64
+
65
+ ObjectUI uses Tailwind CSS for styling. Customise the design tokens through your
66
+ `tailwind.config` and CSS variables:
67
+
68
+ ```css
69
+ @layer base {
70
+ :root {
71
+ --background: 0 0% 100%;
72
+ --foreground: 222 84% 5%;
73
+ --primary: 222 47% 11%;
74
+ --primary-foreground: 210 40% 98%;
75
+ /* ...other tokens */
76
+ }
77
+ }
78
+ ```
79
+
80
+ All Shadcn-based components pick up these tokens automatically — no prop drilling required.
81
+
82
+ ## Explore
83
+
84
+ Use the sidebar to browse every component. Each story shows:
85
+
86
+ - **Live preview** — interact directly in the canvas
87
+ - **Controls** — tweak props in real time
88
+ - **Docs** — auto-generated API tables (when tagged with `autodocs`)
89
+ - **Accessibility** — axe audit panel
@@ -0,0 +1,127 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Getting Started/Introduction" />
4
+
5
+ # ObjectUI — Universal Server-Driven UI Engine
6
+
7
+ ObjectUI is a **JSON-to-UI rendering engine** for React that transforms declarative schemas
8
+ into fully interactive enterprise interfaces. Built on **Shadcn UI**, **Radix Primitives**,
9
+ and **Tailwind CSS**, it bridges the speed of low-code platforms with the design quality of
10
+ hand-crafted components.
11
+
12
+ ---
13
+
14
+ ## Why ObjectUI?
15
+
16
+ | Benefit | Description |
17
+ |---|---|
18
+ | **Schema-Driven** | Define your UI as JSON — render it anywhere with zero custom JSX. |
19
+ | **Enterprise-Ready** | Dashboards, data grids, Kanbans, forms, and CRUDs out of the box. |
20
+ | **Accessible by Default** | Every component inherits WAI-ARIA patterns from Radix UI. |
21
+ | **Themeable** | Tailwind CSS design tokens + CSS variables — no prop drilling required. |
22
+ | **Backend Agnostic** | Works with any API or data source; no server lock-in. |
23
+
24
+ ---
25
+
26
+ ## Architecture Overview
27
+
28
+ ObjectUI follows a layered architecture where each layer has a single responsibility:
29
+
30
+ ```
31
+ ┌─────────────────────────────────────────────────────┐
32
+ │ Your Application │
33
+ ├─────────────────────────────────────────────────────┤
34
+ │ @object-ui/react (Runtime) │
35
+ │ ObjectRenderer · SchemaRenderer · Hooks │
36
+ ├──────────┬──────────────────────────┬───────────────┤
37
+ │ Plugins │ @object-ui/fields │ @object-ui/ │
38
+ │ Grid, │ Text, Number, Select, │ layout │
39
+ │ Kanban, │ Date, Checkbox, … │ AppShell, │
40
+ │ Charts, │ │ Sidebar, │
41
+ │ Form, … │ │ Header │
42
+ ├──────────┴──────────────────────────┴───────────────┤
43
+ │ @object-ui/components (Atoms) │
44
+ │ Button · Card · Badge · Dialog · Tabs · … │
45
+ ├─────────────────────────────────────────────────────┤
46
+ │ @object-ui/core (Engine) │
47
+ │ Component Registry · Schema Validation · │
48
+ │ Expression Evaluation · Data Binding │
49
+ ├─────────────────────────────────────────────────────┤
50
+ │ @object-ui/types (Protocol) │
51
+ │ ComponentSchema · ActionSchema · FieldSchema │
52
+ │ Pure TypeScript — 0 deps │
53
+ └─────────────────────────────────────────────────────┘
54
+ ```
55
+
56
+ ### Layer Breakdown
57
+
58
+ 1. **`@object-ui/types`** — Pure TypeScript interfaces that define the JSON protocol.
59
+ Zero runtime dependencies.
60
+ 2. **`@object-ui/core`** — The rendering engine: component registry, schema validation,
61
+ expression evaluation (`visible: "${data.age > 18}"`), and data binding. No UI code.
62
+ 3. **`@object-ui/components`** — Shadcn-based UI atoms (Button, Card, Badge, Dialog, etc.).
63
+ Pure presentation — no business logic.
64
+ 4. **`@object-ui/fields`** — Standard field renderers for form inputs (Text, Number,
65
+ Select, Date). Each field implements the `FieldWidgetProps` contract.
66
+ 5. **`@object-ui/layout`** — Page-level structure components (AppShell, Header, Sidebar).
67
+ Routing-aware composition.
68
+ 6. **`@object-ui/plugin-*`** — Complex view widgets (Grid, Kanban, Charts, Map, Gantt,
69
+ Form, Timeline). Heavy third-party dependencies are isolated here.
70
+ 7. **`@object-ui/react`** — The public runtime entry point that ties everything together.
71
+ Provides `ObjectRenderer`, hooks, and provider components.
72
+
73
+ ---
74
+
75
+ ## Quick Start
76
+
77
+ ```tsx
78
+ import { ObjectRenderer } from '@object-ui/react';
79
+
80
+ const schema = {
81
+ type: 'Card',
82
+ props: { title: 'Welcome' },
83
+ children: [
84
+ { type: 'Text', props: { content: 'Rendered from JSON!' } },
85
+ { type: 'Button', props: { label: 'Click me', variant: 'default' } },
86
+ ],
87
+ };
88
+
89
+ export default function App() {
90
+ return <ObjectRenderer schema={schema} />;
91
+ }
92
+ ```
93
+
94
+ The `ObjectRenderer` walks the schema tree, resolves each node against the **Component
95
+ Registry**, and produces a fully interactive React component tree.
96
+
97
+ ---
98
+
99
+ ## Browsing This Storybook
100
+
101
+ Use the **sidebar** on the left to explore every component. Stories are organised into:
102
+
103
+ | Section | What You'll Find |
104
+ |---|---|
105
+ | **Getting Started** | Introduction, data binding guides, and setup instructions. |
106
+ | **Primitives** | Base Shadcn atoms — Buttons, Cards, Badges, Inputs, Dialogs, and more. |
107
+ | **Fields** | Form field renderers — text, number, select, date, checkbox, etc. |
108
+ | **Plugins** | Complex view widgets — Data Grid, Kanban, Charts, Map, Gantt, Timeline. |
109
+ | **Templates** | Pre-built page layouts — Dashboards, Reports, Sidebar navigation. |
110
+ | **Apps** | Full application demos (e.g. CRM) composed from multiple plugins. |
111
+
112
+ Each story provides:
113
+
114
+ - **Canvas** — Live interactive preview.
115
+ - **Controls** — Tweak JSON props in real time via the controls panel.
116
+ - **Docs** — Auto-generated API reference (for stories tagged `autodocs`).
117
+ - **Accessibility** — axe-core audit panel to check WCAG compliance.
118
+
119
+ ---
120
+
121
+ ## Documentation
122
+
123
+ Full documentation, migration guides, and API references are available at the
124
+ [ObjectUI docs site](https://objectui.dev).
125
+
126
+ For source code and contribution guidelines, visit the
127
+ [GitHub repository](https://github.com/objectstack-ai/objectui).
package/src/ui/slider.tsx CHANGED
@@ -16,7 +16,7 @@ import { cn } from "../lib/utils"
16
16
  const Slider = React.forwardRef<
17
17
  React.ElementRef<typeof SliderPrimitive.Root>,
18
18
  React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
19
- >(({ className, ...props }, ref) => (
19
+ >(({ className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }, ref) => (
20
20
  <SliderPrimitive.Root
21
21
  ref={ref}
22
22
  className={cn(
@@ -28,7 +28,11 @@ const Slider = React.forwardRef<
28
28
  <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
29
29
  <SliderPrimitive.Range className="absolute h-full bg-primary" />
30
30
  </SliderPrimitive.Track>
31
- <SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
31
+ <SliderPrimitive.Thumb
32
+ aria-label={ariaLabel}
33
+ aria-labelledby={ariaLabelledBy}
34
+ className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
35
+ />
32
36
  </SliderPrimitive.Root>
33
37
  ))
34
38
  Slider.displayName = SliderPrimitive.Root.displayName