@getdom/studio 0.1.1 → 0.2.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 (99) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +31 -0
  3. package/SKILL.md +21 -1
  4. package/package.json +4 -2
  5. package/public/llms.txt +13 -2
  6. package/src/pages/_layout/componentCatalog.generated.js +1185 -44
  7. package/src/pages/_layout/componentLoaders.js +41 -0
  8. package/src/pages/_layout/componentManager.js +38 -27
  9. package/src/pages/_layout/componentRuntimeRecords.js +3 -1
  10. package/src/pages/charts/_shared/ChartContainer.vue +67 -0
  11. package/src/pages/charts/_shared/ChartLegend.vue +22 -0
  12. package/src/pages/charts/_shared/ChartTooltip.vue +18 -0
  13. package/src/pages/charts/_shared/DonutRenderer.vue +33 -0
  14. package/src/pages/charts/_shared/XYChart.vue +140 -0
  15. package/src/pages/charts/_shared/XYRenderer.vue +90 -0
  16. package/src/pages/charts/_shared/chartProps.js +23 -0
  17. package/src/pages/charts/_shared/chartUtils.js +95 -0
  18. package/src/pages/charts/area-chart/DomAreaChart.vue +27 -0
  19. package/src/pages/charts/bar-chart/DomBarChart.vue +29 -0
  20. package/src/pages/charts/date-range-picker/DomDateRangePicker.vue +104 -0
  21. package/src/pages/charts/date-range-picker/dateRange.js +69 -0
  22. package/src/pages/charts/donut-chart/DomDonutChart.vue +117 -0
  23. package/src/pages/charts/line-chart/DomLineChart.vue +26 -0
  24. package/src/pages/charts/metric-card/DomMetricCard.vue +49 -0
  25. package/src/pages/charts/sparkline/DomSparkline.vue +30 -0
  26. package/src/pages/components/_shared/media/MediaDeviceSelect.vue +28 -0
  27. package/src/pages/components/_shared/media/useMediaInput.js +200 -0
  28. package/src/pages/components/audio-controls/DomAudioControls.vue +91 -0
  29. package/src/pages/components/audio-input/DomAudioInput.vue +58 -0
  30. package/src/pages/components/button/DomButton.vue +10 -4
  31. package/src/pages/components/button/buttonStyles.js +5 -0
  32. package/src/pages/components/camera-input/DomCameraInput.vue +75 -0
  33. package/src/pages/components/command-palette/DomCommandPalette.vue +12 -2
  34. package/src/pages/components/dialog/DomDialog.vue +338 -36
  35. package/src/pages/components/icon-button/DomIconButton.vue +8 -2
  36. package/src/pages/components/menu-stack/DomMenuStack.vue +111 -0
  37. package/src/pages/components/menu-stack/menuTree.js +35 -0
  38. package/src/pages/components/popover/DomPopover.vue +1 -53
  39. package/src/pages/components/popover/popover.css +50 -0
  40. package/src/pages/components/video-feed/DomVideoFeed.vue +551 -0
  41. package/src/pages/data/agent-chat/DomAgentChatShell.vue +1 -0
  42. package/src/pages/data/agent-chat/DomAgentConversation.vue +1 -0
  43. package/src/pages/data/agent-chat/DomAgentConversationList.vue +1 -0
  44. package/src/pages/data/gantt/DomGantt.vue +788 -0
  45. package/src/pages/data/gantt/ganttTime.js +223 -0
  46. package/src/pages/data/month-calendar/DomMonthCalendar.vue +84 -9
  47. package/src/pages/data/notification-inbox/DomNotificationInbox.vue +505 -0
  48. package/src/pages/data/notification-inbox/notificationPresentation.js +34 -0
  49. package/src/pages/designer/_shared/ControlIconButton.vue +62 -0
  50. package/src/pages/designer/_shared/StyleControlSection.vue +59 -0
  51. package/src/pages/designer/_shared/cssEditorContext.js +19 -0
  52. package/src/pages/designer/backdrop-editor/BackdropControl.vue +57 -0
  53. package/src/pages/designer/backdrop-editor/DomBackdropEditor.vue +33 -0
  54. package/src/pages/designer/backdrop-editor/backdropModel.js +39 -0
  55. package/src/pages/designer/background-editor/BackgroundLayers.vue +210 -0
  56. package/src/pages/designer/background-editor/DomBackgroundEditor.vue +33 -0
  57. package/src/pages/designer/background-editor/backgroundModel.js +102 -0
  58. package/src/pages/designer/border-editor/BorderControl.vue +72 -0
  59. package/src/pages/designer/border-editor/DomBorderEditor.vue +34 -0
  60. package/src/pages/designer/border-editor/borderModel.js +21 -0
  61. package/src/pages/designer/color-swatch/DomColorSwatch.vue +95 -0
  62. package/src/pages/designer/frame/DomDesignerFrame.vue +16 -0
  63. package/src/pages/designer/frame/DomFrameLayoutEditor.vue +41 -0
  64. package/src/pages/designer/frame/frameLayout.js +93 -0
  65. package/src/pages/designer/layers/DomDesignerLayers.vue +11 -0
  66. package/src/pages/designer/shadow-editor/DomShadowEditor.vue +32 -0
  67. package/src/pages/designer/shadow-editor/ShadowLayers.vue +185 -0
  68. package/src/pages/designer/shadow-editor/shadowModel.js +73 -0
  69. package/src/pages/designer/stage/DesignerBounds.vue +31 -0
  70. package/src/pages/designer/stage/DomDesignerStage.vue +237 -0
  71. package/src/pages/designer/stage/SpacingGuides.vue +33 -0
  72. package/src/pages/designer/stage/resizeGeometry.js +15 -0
  73. package/src/pages/designer/stage/snapGeometry.js +69 -0
  74. package/src/pages/designer/stage/snapPipeline.js +17 -0
  75. package/src/pages/designer/stage/spacingGeometry.js +129 -0
  76. package/src/pages/forms/native-select/DomNativeSelect.vue +8 -3
  77. package/src/pages/forms/number-input/DomNumberInput.vue +39 -3
  78. package/src/pages/forms/range-input/DomRangeInput.vue +75 -23
  79. package/src/pages/forms/textarea-composer/DomTextareaComposer.vue +91 -9
  80. package/src/pages/forms/toggle/DomToggle.vue +1 -1
  81. package/src/pages/lib/headless/base.js +10 -5
  82. package/src/pages/lib/headless/dialog.js +25 -6
  83. package/src/pages/lib/headless/drawer.js +49 -21
  84. package/src/pages/lib/vue/index.d.ts +1161 -14
  85. package/src/pages/lib/vue/index.js +43 -0
  86. package/src/pages/mobile/_shared/interactionMath.js +46 -0
  87. package/src/pages/mobile/_shared/useKeyboardViewport.js +91 -0
  88. package/src/pages/mobile/action-sheet/DomActionSheet.vue +102 -65
  89. package/src/pages/mobile/bottom-nav/DomAppBottomNav.vue +4 -2
  90. package/src/pages/mobile/bottom-sheet/DomBottomSheet.vue +221 -0
  91. package/src/pages/mobile/list-item/DomAppListItem.vue +6 -6
  92. package/src/pages/mobile/profile/DomAppProfile.vue +42 -0
  93. package/src/pages/mobile/safe-area/DomSafeArea.vue +6 -6
  94. package/src/pages/mobile/shell/DomAppShell.vue +60 -9
  95. package/src/pages/mobile/stack/DomAppStack.vue +214 -55
  96. package/src/pages/mobile/swipe-actions/DomSwipeActions.vue +346 -0
  97. package/src/pages/mobile/top-bar/DomAppTopBar.vue +3 -3
  98. package/src/pages/visual/audio-visualizer/DomAudioVisualizer.vue +143 -0
  99. package/src/theme.css +13 -0
@@ -66,19 +66,27 @@ const DRAG_EXIT_MS = 170;
66
66
  const DRAG_PROJECT_MS = 220;
67
67
  const DRAG_FLICK_VELOCITY = 0.45;
68
68
 
69
- let scrollLockCount = 0;
70
- function lockBodyScroll() {
71
- if (!isBrowser) return;
72
- if (scrollLockCount++ === 0) document.body.style.overflow = 'hidden';
73
- }
74
- function unlockBodyScroll() {
75
- if (!isBrowser) return;
76
- if (--scrollLockCount <= 0) {
77
- scrollLockCount = 0;
78
- document.body.style.overflow = '';
69
+ const scrollLocks = new WeakMap();
70
+
71
+ /** Locks a scroll container while preserving its existing inline overflow. */
72
+ function lockBodyScroll(target) {
73
+ if (!target) return;
74
+ const lock = scrollLocks.get(target);
75
+ if (lock) lock.count += 1;
76
+ else {
77
+ scrollLocks.set(target, { count: 1, overflow: target.style.overflow });
78
+ target.style.overflow = 'hidden';
79
79
  }
80
80
  }
81
81
 
82
+ /** Restores a container only after its last open drawer releases the lock. */
83
+ function unlockBodyScroll(target) {
84
+ const lock = target && scrollLocks.get(target);
85
+ if (!lock || --lock.count > 0) return;
86
+ target.style.overflow = lock.overflow;
87
+ scrollLocks.delete(target);
88
+ }
89
+
82
90
  function wantsOpen(el) {
83
91
  return el.boolAttr('open') || el.boolAttr('show');
84
92
  }
@@ -117,6 +125,7 @@ export class DomDrawerElement extends DomElementBase {
117
125
  'leave-to',
118
126
  'aria-labelledby',
119
127
  'aria-describedby',
128
+ 'aria-label',
120
129
  ];
121
130
  }
122
131
 
@@ -140,6 +149,7 @@ export class DomDrawerElement extends DomElementBase {
140
149
  { name: 'leave-to', type: 'string', description: 'Tailwind classes applied for the leave transition end state.' },
141
150
  ],
142
151
  events: [
152
+ { name: 'dom:state', description: 'Fired immediately when open state changes, with { open: boolean }, before animation completes.' },
143
153
  { name: 'dom:open', description: 'Fired when the drawer opens.' },
144
154
  { name: 'dom:close', description: 'Fired when the drawer closes (Esc, backdrop, data-close, or programmatic).' },
145
155
  ],
@@ -210,13 +220,17 @@ export class DomDrawerElement extends DomElementBase {
210
220
  if (wantsOpen(this)) this.open = true;
211
221
  }
212
222
 
223
+ /** Cancels pending motion and releases document resources when removed or moved. */
213
224
  disconnectedCallback() {
225
+ this._transitionGen += 1;
226
+ this._transitioning = false;
227
+ this._open = false;
214
228
  this._finishDrag(false);
215
229
  this._teardownDragHandle();
216
230
  if (this._dragResetTimer) window.clearTimeout(this._dragResetTimer);
217
231
  this._dragResetTimer = null;
218
232
  this._unlockScroll();
219
- document.removeEventListener('keydown', this._onKey);
233
+ this.ownerDocument.removeEventListener('keydown', this._onKey);
220
234
  this._releaseFocus?.();
221
235
  this._releaseFocus = null;
222
236
  super.disconnectedCallback();
@@ -280,9 +294,10 @@ export class DomDrawerElement extends DomElementBase {
280
294
  });
281
295
  }
282
296
 
297
+ /** Copies the accessible name and description onto the dialog panel. */
283
298
  _syncAria() {
284
299
  if (!this._panel) return;
285
- for (const name of ['aria-labelledby', 'aria-describedby']) {
300
+ for (const name of ['aria-labelledby', 'aria-describedby', 'aria-label']) {
286
301
  const value = this.getAttribute(name);
287
302
  if (value) this._panel.setAttribute(name, value);
288
303
  else this._panel.removeAttribute(name);
@@ -428,10 +443,10 @@ export class DomDrawerElement extends DomElementBase {
428
443
  ? this._onDragTouchEnd
429
444
  : this._onDragMouseUp;
430
445
  this._dragOffs = [
431
- this.on(document, options.moveType, moveHandler, { passive: false }),
432
- this.on(document, options.upType, upHandler, { passive: false }),
446
+ this.on(this.ownerDocument, options.moveType, moveHandler, { passive: false }),
447
+ this.on(this.ownerDocument, options.upType, upHandler, { passive: false }),
433
448
  ];
434
- if (options.cancelType) this._dragOffs.push(this.on(document, options.cancelType, upHandler, { passive: false }));
449
+ if (options.cancelType) this._dragOffs.push(this.on(this.ownerDocument, options.cancelType, upHandler, { passive: false }));
435
450
  e.preventDefault();
436
451
  }
437
452
 
@@ -547,15 +562,19 @@ export class DomDrawerElement extends DomElementBase {
547
562
  if (this.hasAttribute('show')) this.setBoolAttr('show', next);
548
563
  }
549
564
 
565
+ /** Locks the drawer document or its containing app scroll region. */
550
566
  _lockScroll() {
551
567
  if (this._scrollLocked) return;
552
- lockBodyScroll();
568
+ this._scrollTarget = this.closest('[data-dom-app-shell]')?.querySelector('[data-dom-app-shell-main]') || this.ownerDocument.body;
569
+ lockBodyScroll(this._scrollTarget);
553
570
  this._scrollLocked = true;
554
571
  }
555
572
 
573
+ /** Releases this drawer scroll lock without disturbing other overlays. */
556
574
  _unlockScroll() {
557
575
  if (!this._scrollLocked) return;
558
- unlockBodyScroll();
576
+ unlockBodyScroll(this._scrollTarget);
577
+ this._scrollTarget = null;
559
578
  this._scrollLocked = false;
560
579
  }
561
580
 
@@ -584,21 +603,27 @@ export class DomDrawerElement extends DomElementBase {
584
603
  this._overlay.setAttribute('aria-hidden', String(!open));
585
604
  }
586
605
 
606
+ /** Traps keyboard focus within the newly opened panel. */
587
607
  _finishOpen() {
608
+ this._releaseFocus?.();
588
609
  this._releaseFocus = focusTrap(this._panel);
589
610
  requestAnimationFrame(() => this._panel.focus({ preventScroll: true }));
590
611
  this.emit('dom:open');
591
612
  }
592
613
 
614
+ /** Restores scrolling and returns focus to the control that opened the drawer. */
593
615
  _finishClose() {
594
616
  this._unlockScroll();
595
- document.removeEventListener('keydown', this._onKey);
617
+ this.ownerDocument.removeEventListener('keydown', this._onKey);
596
618
  this._releaseFocus?.();
597
619
  this._releaseFocus = null;
598
- this._trigger?.focus({ preventScroll: true });
620
+ const returnTarget = this._returnFocus || this._trigger;
621
+ if (returnTarget?.isConnected) returnTarget.focus({ preventScroll: true });
622
+ this._returnFocus = null;
599
623
  this.emit('dom:close');
600
624
  }
601
625
 
626
+ /** Synchronizes controlled open state, motion, focus, and scroll ownership. */
602
627
  async _setOpen(next) {
603
628
  if (!this._panel || !this._overlay) return;
604
629
  if (next === this._open && !this._transitioning) return;
@@ -608,12 +633,14 @@ export class DomDrawerElement extends DomElementBase {
608
633
  this._syncMotionClasses();
609
634
 
610
635
  if (next) {
636
+ this._returnFocus = this.ownerDocument.activeElement;
611
637
  this._setupDragHandle();
612
638
  this._open = true;
613
639
  this._reflectOpen(true);
640
+ this.emit('dom:state', { open: true });
614
641
  this._trigger?.setAttribute('aria-expanded', 'true');
615
642
  this._lockScroll();
616
- document.addEventListener('keydown', this._onKey);
643
+ this.ownerDocument.addEventListener('keydown', this._onKey);
617
644
 
618
645
  this._overlay.hidden = false;
619
646
  if (custom) {
@@ -633,6 +660,7 @@ export class DomDrawerElement extends DomElementBase {
633
660
  } else {
634
661
  this._open = false;
635
662
  this._reflectOpen(false);
663
+ this.emit('dom:state', { open: false });
636
664
  this._trigger?.setAttribute('aria-expanded', 'false');
637
665
 
638
666
  if (custom) {
@@ -666,7 +694,7 @@ export class DomDrawerElement extends DomElementBase {
666
694
  if (['enter', 'enter-from', 'enter-to', 'leave', 'leave-from', 'leave-to'].includes(name)) {
667
695
  this._syncMotionClasses();
668
696
  }
669
- if (name === 'aria-labelledby' || name === 'aria-describedby') this._syncAria();
697
+ if (['aria-labelledby', 'aria-describedby', 'aria-label'].includes(name)) this._syncAria();
670
698
  }
671
699
 
672
700
  get open() { return this._open; }