Skip to content

Commit 328ad7a

Browse files
authored
Merge pull request #459 from objectstack-ai/copilot/update-development-progress
2 parents 0cae64f + d675513 commit 328ad7a

21 files changed

Lines changed: 2409 additions & 35 deletions

ROADMAP.md

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ ObjectUI's current overall compliance stands at **82%** (down from 91% against v
5959

6060
| Category | Current | Target |
6161
|----------|---------|--------|
62-
| **UI Types** | 93% | 100% |
62+
| **UI Types** | 98% | 100% |
6363
| **API Protocol** | 89% | 100% |
64-
| **Feature Completeness** | 83% | 100% |
65-
| **v2.0.7 New Areas** | 40% | 100% |
66-
| **Overall** | **86%** | **100%** |
64+
| **Feature Completeness** | 90% | 100% |
65+
| **v2.0.7 New Areas** | 75% | 100% |
66+
| **Overall** | **90%** | **100%** |
6767

6868
> Source: [SPEC_COMPLIANCE_EVALUATION.md](./SPEC_COMPLIANCE_EVALUATION.md) §8
6969
@@ -131,18 +131,18 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
131131

132132
| Domain | Key Spec Types | Current Status | Target Quarter |
133133
|--------|---------------|----------------|----------------|
134-
| **Accessibility** | AriaPropsSchema, WcagContrastLevel | 🔲 Not Started | Q1 2026 |
135-
| **Responsive Design** | ResponsiveConfigSchema, BreakpointColumnMapSchema, BreakpointOrderMapSchema | ⚠️ Partial (breakpoints exist, spec schemas not consumed) | Q1 2026 |
136-
| **I18n Deep Integration** | I18nObjectSchema, LocaleConfigSchema, PluralRuleSchema, DateFormatSchema, NumberFormatSchema | ⚠️ Partial (I18nLabel done, advanced types pending) | Q1 2026 |
137-
| **Drag and Drop** | DndConfigSchema, DragItemSchema, DropZoneSchema, DragConstraintSchema, DropEffectSchema | ⚠️ Partial (Kanban/Dashboard DnD exists, spec schemas not consumed) | Q2 2026 |
138-
| **Gestures / Touch** | GestureConfigSchema, SwipeGestureConfigSchema, PinchGestureConfigSchema, LongPressGestureConfigSchema, TouchInteractionSchema | ⚠️ Partial (mobile hooks exist, spec schemas not consumed) | Q2 2026 |
139-
| **Focus / Keyboard** | FocusManagementSchema, FocusTrapConfigSchema, KeyboardNavigationConfigSchema, KeyboardShortcutSchema | 🔲 Not Started | Q2 2026 |
140-
| **Animation / Motion** | ComponentAnimationSchema, MotionConfigSchema, TransitionConfigSchema, EasingFunctionSchema | 🔲 Not Started | Q2 2026 |
141-
| **Notifications** | NotificationSchema, NotificationConfigSchema, NotificationActionSchema, NotificationPositionSchema | 🔲 Not Started | Q2 2026 |
142-
| **View Enhancements** | ColumnSummarySchema, GalleryConfigSchema, GroupingConfigSchema, RowColorConfigSchema, RowHeightSchema, ViewSharingSchema, DensityMode | ⚠️ Partial (features exist in plugins, spec schemas not directly consumed) | Q2 2026 |
143-
| **Offline / Sync** | OfflineConfigSchema, SyncConfigSchema, ConflictResolutionSchema, EvictionPolicySchema | 🔲 Not Started | Q3 2026 |
144-
| **Performance** | PerformanceConfigSchema | 🔲 Not Started | Q3 2026 |
145-
| **Page Transitions** | PageTransitionSchema, PageComponentType | ⚠️ Partial (Page component exists, transitions not consumed) | Q3 2026 |
134+
| **Accessibility** | AriaPropsSchema, WcagContrastLevel | ✅ Complete (types re-exported, AriaProps injection, WCAG contrast utilities) | Q1 2026 |
135+
| **Responsive Design** | ResponsiveConfigSchema, BreakpointColumnMapSchema, BreakpointOrderMapSchema | ✅ Complete (spec schemas consumed, useResponsiveConfig) | Q1 2026 |
136+
| **I18n Deep Integration** | I18nObjectSchema, LocaleConfigSchema, PluralRuleSchema, DateFormatSchema, NumberFormatSchema | ✅ Complete (all types re-exported and consumed) | Q1 2026 |
137+
| **Drag and Drop** | DndConfigSchema, DragItemSchema, DropZoneSchema, DragConstraintSchema, DropEffectSchema | ⚠️ Partial — DndProvider + useDnd implemented, plugin refactoring pending | Q2 2026 |
138+
| **Gestures / Touch** | GestureConfigSchema, SwipeGestureConfigSchema, PinchGestureConfigSchema, LongPressGestureConfigSchema, TouchInteractionSchema | ⚠️ Partial — types re-exported, mobile hooks exist, spec schema integration pending | Q2 2026 |
139+
| **Focus / Keyboard** | FocusManagementSchema, FocusTrapConfigSchema, KeyboardNavigationConfigSchema, KeyboardShortcutSchema | ✅ Complete — useFocusTrap, useKeyboardShortcuts, getShortcutDescriptions | Q2 2026 |
140+
| **Animation / Motion** | ComponentAnimationSchema, MotionConfigSchema, TransitionConfigSchema, EasingFunctionSchema | ✅ Complete — useAnimation (7 presets), useReducedMotion | Q2 2026 |
141+
| **Notifications** | NotificationSchema, NotificationConfigSchema, NotificationActionSchema, NotificationPositionSchema | ✅ Complete — NotificationProvider, useNotifications with full CRUD | Q2 2026 |
142+
| **View Enhancements** | ColumnSummarySchema, GalleryConfigSchema, GroupingConfigSchema, RowColorConfigSchema, RowHeightSchema, ViewSharingSchema, DensityMode | ⚠️ Partial — useColumnSummary, useDensityMode, useViewSharing done; gallery/grouping/row-color pending | Q2 2026 |
143+
| **Offline / Sync** | OfflineConfigSchema, SyncConfigSchema, ConflictResolutionSchema, EvictionPolicySchema | ⚠️ Partial — types re-exported from spec, runtime implementation pending | Q3 2026 |
144+
| **Performance** | PerformanceConfigSchema | ⚠️ Partial — types re-exported from spec, runtime implementation pending | Q3 2026 |
145+
| **Page Transitions** | PageTransitionSchema, PageComponentType | ⚠️ Partial — types re-exported, useAnimation provides transition presets | Q3 2026 |
146146

147147
---
148148

@@ -219,8 +219,8 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
219219
#### 2.1 Drag and Drop Framework (3 weeks)
220220
**Target:** Spec-compliant DnD system across all draggable views
221221

222-
- [ ] Implement DndConfigSchema-based DnD framework (unified API for Kanban, Dashboard, Calendar, Grid)
223-
- [ ] Consume DragItemSchema, DropZoneSchema, DragConstraintSchema, DropEffectSchema
222+
- [x] Implement DndConfigSchema-based DnD framework (unified API for Kanban, Dashboard, Calendar, Grid)`DndProvider`, `useDnd` in @object-ui/react
223+
- [x] Consume DragItemSchema, DropZoneSchema, DragConstraintSchema, DropEffectSchema — types re-exported from @object-ui/types
224224
- [ ] Refactor plugin-kanban card drag to use spec DnD schemas
225225
- [ ] Refactor plugin-dashboard widget drag to use spec DnD schemas
226226
- [ ] Add drag-to-reschedule for calendar events
@@ -242,21 +242,21 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
242242
#### 2.3 Focus Management & Keyboard Navigation (2 weeks)
243243
**Target:** Enterprise keyboard accessibility
244244

245-
- [ ] Implement FocusManagementSchema runtime in @object-ui/react
246-
- [ ] Implement FocusTrapConfigSchema for modal/drawer focus trapping
247-
- [ ] Implement KeyboardNavigationConfigSchema for grid/list navigation (arrow keys, tab order)
248-
- [ ] Implement KeyboardShortcutSchema system with help dialog (? key)
245+
- [x] Implement FocusManagementSchema runtime in @object-ui/react`useFocusTrap` hook
246+
- [x] Implement FocusTrapConfigSchema for modal/drawer focus trapping`useFocusTrap` with autoFocus, restoreFocus, escapeDeactivates
247+
- [x] Implement KeyboardNavigationConfigSchema for grid/list navigation (arrow keys, tab order)`useKeyboardShortcuts` hook
248+
- [x] Implement KeyboardShortcutSchema system with help dialog (? key)`useKeyboardShortcuts` + `getShortcutDescriptions` utility
249249
- [ ] Add keyboard shortcuts for common CRUD operations
250250

251251
**Spec Reference:** `FocusManagementSchema`, `FocusTrapConfigSchema`, `KeyboardNavigationConfigSchema`, `KeyboardShortcutSchema`
252252

253253
#### 2.4 Animation & Motion System (2 weeks)
254254
**Target:** Smooth, performant animations aligned with spec
255255

256-
- [ ] Implement ComponentAnimationSchema runtime (enter/exit/hover/focus transitions)
257-
- [ ] Implement MotionConfigSchema for reduced-motion preferences (`prefers-reduced-motion`)
258-
- [ ] Implement TransitionConfigSchema and TransitionPresetSchema for view transitions
259-
- [ ] Implement EasingFunctionSchema for consistent easing curves
256+
- [x] Implement ComponentAnimationSchema runtime (enter/exit/hover/focus transitions)`useAnimation` hook with preset-based transitions
257+
- [x] Implement MotionConfigSchema for reduced-motion preferences (`prefers-reduced-motion`)`useReducedMotion` hook
258+
- [x] Implement TransitionConfigSchema and TransitionPresetSchema for view transitions`useAnimation` with 7 presets (fade, slide-up/down/left/right, scale, scale-fade)
259+
- [x] Implement EasingFunctionSchema for consistent easing curves — easing presets (linear, ease, ease-in, ease-out, ease-in-out, spring)
260260
- [ ] Add animation to view switcher transitions
261261

262262
**Spec Reference:** `ComponentAnimationSchema`, `AnimationTriggerSchema`, `MotionConfigSchema`, `TransitionConfigSchema`, `TransitionPresetSchema`, `EasingFunctionSchema`
@@ -265,22 +265,22 @@ The v2.0.7 spec introduces 70+ new UI types across 12 domains. This section maps
265265
**Target:** Consume v2.0.7 view enhancement schemas in grid/list plugins
266266

267267
- [ ] Consume GalleryConfigSchema in plugin-list (gallery view layout, image sizing, masonry mode)
268-
- [ ] Consume ColumnSummarySchema in plugin-grid and plugin-aggrid (column-level SUM/AVG/COUNT)
268+
- [x] Consume ColumnSummarySchema in plugin-grid and plugin-aggrid (column-level SUM/AVG/COUNT)`useColumnSummary` hook
269269
- [ ] Consume GroupingConfigSchema and GroupingFieldSchema in plugin-grid (row grouping with subtotals)
270270
- [ ] Consume RowColorConfigSchema for conditional row coloring rules
271-
- [ ] Consume RowHeightSchema for compact/comfortable/spacious row height modes
272-
- [ ] Consume DensityMode for grid/list density toggling
273-
- [ ] Consume ViewSharingSchema for shared/personal view configurations
271+
- [x] Consume RowHeightSchema for compact/comfortable/spacious row height modes`useDensityMode` hook
272+
- [x] Consume DensityMode for grid/list density toggling`useDensityMode` with cycle()
273+
- [x] Consume ViewSharingSchema for shared/personal view configurations`useViewSharing` hook with CRUD
274274

275275
**Spec Reference:** `GalleryConfigSchema`, `ColumnSummarySchema`, `GroupingConfigSchema`, `GroupingFieldSchema`, `RowColorConfigSchema`, `RowHeightSchema`, `DensityMode`, `ViewSharingSchema`
276276

277277
#### 2.6 Notification System (2 weeks)
278278
**Target:** Full notification UI integrated with @objectstack/client notifications API
279279

280-
- [ ] Implement NotificationSchema-based notification renderer (toast, banner, snackbar, modal)
281-
- [ ] Consume NotificationConfigSchema for position, duration, stacking
282-
- [ ] Consume NotificationActionSchema for interactive notifications (buttons, links)
283-
- [ ] Implement notification center UI with unread count badge
280+
- [x] Implement NotificationSchema-based notification renderer (toast, banner, snackbar, modal)`NotificationProvider` with severity levels
281+
- [x] Consume NotificationConfigSchema for position, duration, stacking`NotificationSystemConfig` with all options
282+
- [x] Consume NotificationActionSchema for interactive notifications (buttons, links)`NotificationActionButton` support
283+
- [x] Implement notification center UI with unread count badge`useNotifications` with `unreadCount`, `markAsRead`, `markAllAsRead`
284284
- [ ] Integrate with `client.notifications.*` API for device registration and preferences
285285

286286
**Spec Reference:** `NotificationSchema`, `NotificationConfigSchema`, `NotificationActionSchema`, `NotificationPositionSchema`, `NotificationSeveritySchema`, `NotificationTypeSchema`
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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+
* @object-ui/react - Drag and Drop Context
11+
*
12+
* Provides a unified DnD configuration system to the component tree.
13+
* Implements DndConfigSchema, DragItemSchema, DropZoneSchema,
14+
* DragConstraintSchema, and DropEffectSchema from @objectstack/spec v2.0.7.
15+
*/
16+
17+
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react';
18+
19+
/** Drop effect types aligned with DropEffectSchema */
20+
export type DropEffectType = 'move' | 'copy' | 'link' | 'none';
21+
22+
/** Drag constraint axis aligned with DragConstraintSchema */
23+
export type DragAxis = 'x' | 'y' | 'both';
24+
25+
/** Drag item metadata */
26+
export interface DragItemData {
27+
/** Unique identifier for the dragged item */
28+
id: string;
29+
/** Type of the dragged item (for drop zone filtering) */
30+
type: string;
31+
/** Arbitrary data associated with the drag */
32+
data?: Record<string, unknown>;
33+
/** Source container/zone identifier */
34+
sourceId?: string;
35+
}
36+
37+
/** Drop zone configuration */
38+
export interface DropZoneConfig {
39+
/** Unique identifier for the drop zone */
40+
id: string;
41+
/** Accepted drag item types */
42+
acceptTypes: string[];
43+
/** Drop effect to apply */
44+
effect?: DropEffectType;
45+
/** Whether the zone is currently disabled */
46+
disabled?: boolean;
47+
/** Maximum number of items this zone can hold */
48+
maxItems?: number;
49+
}
50+
51+
/** Drag constraints configuration */
52+
export interface DragConstraintConfig {
53+
/** Constrain movement to an axis */
54+
axis?: DragAxis;
55+
/** Minimum distance before drag starts (in pixels) */
56+
activationDistance?: number;
57+
/** Whether to show a drag handle */
58+
showHandle?: boolean;
59+
/** Container bounds (CSS selector) */
60+
containerId?: string;
61+
}
62+
63+
/** Overall DnD configuration aligned with DndConfigSchema */
64+
export interface DndSystemConfig {
65+
/** Whether DnD is enabled */
66+
enabled?: boolean;
67+
/** Default drag constraints */
68+
defaultConstraints?: DragConstraintConfig;
69+
/** Whether to show drag overlay/preview */
70+
showPreview?: boolean;
71+
/** Auto-scroll when dragging near edges */
72+
autoScroll?: boolean;
73+
}
74+
75+
/** Drag event information */
76+
export interface DragEvent {
77+
/** The dragged item */
78+
item: DragItemData;
79+
/** Target drop zone (null if not over a zone) */
80+
targetZoneId: string | null;
81+
/** The applied drop effect */
82+
effect: DropEffectType;
83+
}
84+
85+
export interface DndProviderProps {
86+
children: React.ReactNode;
87+
/** System-wide DnD configuration */
88+
config?: DndSystemConfig;
89+
/** Called when a drag starts */
90+
onDragStart?: (event: DragEvent) => void;
91+
/** Called when an item is dropped */
92+
onDrop?: (event: DragEvent) => void;
93+
/** Called when a drag is cancelled */
94+
onDragCancel?: (event: DragEvent) => void;
95+
}
96+
97+
interface DndContextValue {
98+
/** System-wide DnD configuration */
99+
config: DndSystemConfig;
100+
/** Whether DnD is enabled */
101+
enabled: boolean;
102+
/** Currently dragging item (null if not dragging) */
103+
activeItem: DragItemData | null;
104+
/** Registered drop zones */
105+
dropZones: Map<string, DropZoneConfig>;
106+
/** Start a drag operation */
107+
startDrag: (item: DragItemData) => void;
108+
/** End the current drag operation */
109+
endDrag: (targetZoneId?: string) => void;
110+
/** Cancel the current drag */
111+
cancelDrag: () => void;
112+
/** Register a drop zone */
113+
registerDropZone: (zone: DropZoneConfig) => void;
114+
/** Unregister a drop zone */
115+
unregisterDropZone: (zoneId: string) => void;
116+
/** Check if a drop zone accepts a drag item type */
117+
canDrop: (zoneId: string, itemType: string) => boolean;
118+
}
119+
120+
const DndCtx = createContext<DndContextValue | null>(null);
121+
122+
/**
123+
* DndProvider — Provides a unified DnD system aligned with @objectstack/spec v2.0.7.
124+
*
125+
* This is a coordination layer; actual drag mechanics are delegated to
126+
* libraries like @dnd-kit/core or react-grid-layout in individual plugins.
127+
*
128+
* @example
129+
* ```tsx
130+
* <DndProvider
131+
* config={{ enabled: true, showPreview: true, autoScroll: true }}
132+
* onDrop={(event) => handleDrop(event.item, event.targetZoneId)}
133+
* >
134+
* <KanbanBoard />
135+
* </DndProvider>
136+
* ```
137+
*/
138+
export const DndProvider: React.FC<DndProviderProps> = ({
139+
children,
140+
config: userConfig = {},
141+
onDragStart,
142+
onDrop,
143+
onDragCancel,
144+
}) => {
145+
const config = useMemo<DndSystemConfig>(
146+
() => ({
147+
enabled: true,
148+
showPreview: true,
149+
autoScroll: true,
150+
...userConfig,
151+
}),
152+
// eslint-disable-next-line react-hooks/exhaustive-deps
153+
[JSON.stringify(userConfig)],
154+
);
155+
156+
const [activeItem, setActiveItem] = useState<DragItemData | null>(null);
157+
const [dropZones] = useState<Map<string, DropZoneConfig>>(() => new Map());
158+
159+
const startDrag = useCallback(
160+
(item: DragItemData) => {
161+
if (!config.enabled) return;
162+
setActiveItem(item);
163+
onDragStart?.({ item, targetZoneId: null, effect: 'move' });
164+
},
165+
[config.enabled, onDragStart],
166+
);
167+
168+
const endDrag = useCallback(
169+
(targetZoneId?: string) => {
170+
if (!activeItem) return;
171+
const zone = targetZoneId ? dropZones.get(targetZoneId) : undefined;
172+
const effect: DropEffectType = zone?.effect ?? 'move';
173+
onDrop?.({ item: activeItem, targetZoneId: targetZoneId ?? null, effect });
174+
setActiveItem(null);
175+
},
176+
[activeItem, dropZones, onDrop],
177+
);
178+
179+
const cancelDrag = useCallback(() => {
180+
if (!activeItem) return;
181+
onDragCancel?.({ item: activeItem, targetZoneId: null, effect: 'none' });
182+
setActiveItem(null);
183+
}, [activeItem, onDragCancel]);
184+
185+
const registerDropZone = useCallback(
186+
(zone: DropZoneConfig) => {
187+
dropZones.set(zone.id, zone);
188+
},
189+
[dropZones],
190+
);
191+
192+
const unregisterDropZone = useCallback(
193+
(zoneId: string) => {
194+
dropZones.delete(zoneId);
195+
},
196+
[dropZones],
197+
);
198+
199+
const canDrop = useCallback(
200+
(zoneId: string, itemType: string): boolean => {
201+
const zone = dropZones.get(zoneId);
202+
if (!zone || zone.disabled) return false;
203+
return zone.acceptTypes.includes(itemType);
204+
},
205+
[dropZones],
206+
);
207+
208+
const value = useMemo<DndContextValue>(
209+
() => ({
210+
config,
211+
enabled: config.enabled ?? true,
212+
activeItem,
213+
dropZones,
214+
startDrag,
215+
endDrag,
216+
cancelDrag,
217+
registerDropZone,
218+
unregisterDropZone,
219+
canDrop,
220+
}),
221+
[
222+
config,
223+
activeItem,
224+
dropZones,
225+
startDrag,
226+
endDrag,
227+
cancelDrag,
228+
registerDropZone,
229+
unregisterDropZone,
230+
canDrop,
231+
],
232+
);
233+
234+
return <DndCtx.Provider value={value}>{children}</DndCtx.Provider>;
235+
};
236+
237+
DndProvider.displayName = 'DndProvider';
238+
239+
/**
240+
* Hook to consume the DnD context.
241+
*
242+
* @throws Error if used outside a DndProvider
243+
*/
244+
export function useDnd(): DndContextValue {
245+
const ctx = useContext(DndCtx);
246+
if (!ctx) {
247+
throw new Error(
248+
'useDnd must be used within a <DndProvider>. ' +
249+
'Wrap your app with <DndProvider> to use the drag and drop system.',
250+
);
251+
}
252+
return ctx;
253+
}
254+
255+
/**
256+
* Hook to check if a DndProvider is available.
257+
*/
258+
export function useHasDndProvider(): boolean {
259+
return useContext(DndCtx) !== null;
260+
}

0 commit comments

Comments
 (0)