@bycrux/editor 0.4.2 → 0.4.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bycrux/editor",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -84,7 +84,7 @@ function SlideGrid({
84
84
  onDrop={() => handleDrop(idx)}
85
85
  onDragEnd={handleDragEnd}
86
86
  onClick={() => onSelect(slide.id)}
87
- className={`group relative cursor-pointer rounded overflow-hidden border transition-colors ${
87
+ className={`group relative flex-shrink-0 cursor-pointer rounded overflow-hidden border transition-colors ${
88
88
  selectedSlideId === slide.id
89
89
  ? 'border-[var(--editor-accent)]'
90
90
  : dragOverIdx === idx
@@ -357,16 +357,18 @@ export default function CarouselEditor<P extends Project = Project>({ project: i
357
357
  obs.observe(el)
358
358
  return () => obs.disconnect()
359
359
  }, [])
360
- const PADDING = 48
361
- const HINT_RESERVE = 36
360
+ const PADDING = 32
361
+ const HINT_RESERVE = 28
362
362
  const availW = Math.max(0, canvasContainerSize.w - PADDING)
363
363
  const availH = Math.max(0, canvasContainerSize.h - PADDING - HINT_RESERVE)
364
364
  const canvasScale = Math.min(availW / w, availH / h, 1)
365
365
 
366
366
  return (
367
- <div ref={containerRef} className="flex flex-col h-full overflow-hidden bg-[var(--editor-bg)]">
368
- {/* TOP: slide rail + canvas, fills remaining height */}
369
- <div className="flex flex-1 min-h-0 overflow-hidden">
367
+ <div ref={containerRef} className="flex flex-col h-full overflow-y-auto bg-[var(--editor-bg)]">
368
+ {/* TOP: slide rail + canvas. Given a generous viewport-relative height so
369
+ the slide renders large; the below-panels region flows beneath and the
370
+ whole editor scrolls vertically. */}
371
+ <div className="flex flex-shrink-0 min-h-[80vh] overflow-hidden">
370
372
  <SlideGrid
371
373
  project={project}
372
374
  slides={slides}
@@ -380,7 +382,7 @@ export default function CarouselEditor<P extends Project = Project>({ project: i
380
382
  compileOverlay={(t) => adapter.compileOverlay(t)}
381
383
  />
382
384
 
383
- <div ref={canvasContainerRef} className="relative flex-1 flex flex-col items-center justify-center gap-4 overflow-hidden p-6">
385
+ <div ref={canvasContainerRef} className="relative flex-1 flex flex-col items-center justify-center gap-4 overflow-hidden p-4">
384
386
  <button
385
387
  onClick={handleRefresh}
386
388
  disabled={refreshing}
@@ -493,9 +495,11 @@ export default function CarouselEditor<P extends Project = Project>({ project: i
493
495
  </div>
494
496
  </div>
495
497
 
496
- {/* BELOW: the panels, full width under the canvas. Bounded height with
497
- internal scrolling so it never crushes the canvas above. */}
498
- <div className="flex-shrink-0 border-t border-[var(--editor-border)] bg-[var(--editor-bg)] overflow-hidden flex flex-col" style={{ maxHeight: '40%' }}>
498
+ {/* BELOW: the slide editor, stacked vertically full-width under the canvas.
499
+ Flows beneath the tall canvas region and scrolls with the page (the root
500
+ is overflow-y-auto). Order: add-element toolbar property panel
501
+ project media (assets) at the very bottom. */}
502
+ <div className="flex-shrink-0 border-t border-[var(--editor-border)] bg-[var(--editor-bg)] flex flex-col">
499
503
  {selectedSlide && project.status !== 'pending' && (
500
504
  <div className="px-4 py-2 border-b border-[var(--editor-border)] bg-[var(--editor-bg)]">
501
505
  <AddElementMenu
@@ -506,35 +510,31 @@ export default function CarouselEditor<P extends Project = Project>({ project: i
506
510
  />
507
511
  </div>
508
512
  )}
509
- <div className="flex flex-1 min-h-0 overflow-hidden">
510
- <div className="w-80 flex-shrink-0 overflow-y-auto border-r border-[var(--editor-border)]">
511
- <SlidePropertyPanel
512
- project={project}
513
- slide={selectedSlide}
514
- element={selectedElement}
515
- adapter={adapter}
516
- onSlideChange={handleSlideChange}
517
- onElementChange={handlePanelElementChange}
518
- onDeleteSlide={handleDeleteSlide}
519
- onDuplicateSlide={handleDuplicateSlide}
520
- onDeleteElement={handleDeleteElement}
521
- onDuplicateElement={handleDuplicateElement}
522
- onReorderElement={handleReorderElement}
523
- onEnterCrop={(_slideId, elementId) => { setSelectedElementId(elementId); setCropElementId(elementId) }}
524
- updateOverlayProp={state.updateOverlayProp}
525
- hiddenElementIds={hiddenElementIds}
526
- onToggleElementVisibility={onToggleElementVisibility}
527
- />
513
+ <SlidePropertyPanel
514
+ project={project}
515
+ slide={selectedSlide}
516
+ element={selectedElement}
517
+ adapter={adapter}
518
+ onSlideChange={handleSlideChange}
519
+ onElementChange={handlePanelElementChange}
520
+ onDeleteSlide={handleDeleteSlide}
521
+ onDuplicateSlide={handleDuplicateSlide}
522
+ onDeleteElement={handleDeleteElement}
523
+ onDuplicateElement={handleDuplicateElement}
524
+ onReorderElement={handleReorderElement}
525
+ onEnterCrop={(_slideId, elementId) => { setSelectedElementId(elementId); setCropElementId(elementId) }}
526
+ updateOverlayProp={state.updateOverlayProp}
527
+ hiddenElementIds={hiddenElementIds}
528
+ onToggleElementVisibility={onToggleElementVisibility}
529
+ // Stacked full-width here (drop the default w-80 sidebar + left border).
530
+ className="w-full border-l-0 border-b border-[var(--editor-border)]"
531
+ />
532
+ {slots?.assetsPanel && (
533
+ // Project media — at the very bottom, full width.
534
+ <div className="w-full flex flex-col">
535
+ {slots.assetsPanel}
528
536
  </div>
529
- {slots?.assetsPanel && (
530
- // Below the canvas the assets slot fills the remaining width (no longer
531
- // capped to a 320px sidebar) and scrolls vertically within the bounded
532
- // below-canvas region.
533
- <div className="flex-1 min-w-0 flex flex-col overflow-y-auto overflow-x-hidden">
534
- {slots.assetsPanel}
535
- </div>
536
- )}
537
- </div>
537
+ )}
538
538
  </div>
539
539
 
540
540
  {renderOpen && (
@@ -9,7 +9,7 @@ import type {
9
9
  GlobalOverlayProp,
10
10
  EditorAdapter,
11
11
  } from '../types'
12
- import { Button } from '../ui'
12
+ import { Button, cn } from '../ui'
13
13
  import { TextFormattingToolbar } from '../text/TextFormattingToolbar'
14
14
 
15
15
  function parseNumber(v: string): number | null {
@@ -39,6 +39,10 @@ interface Props {
39
39
  // selected element; `hiddenElementIds` reflects the current hidden set.
40
40
  hiddenElementIds?: string[]
41
41
  onToggleElementVisibility?: (elementId: string) => void
42
+ // Override the panel's root container classes. Hosts that stack the panel
43
+ // full-width (e.g. below the canvas) pass this to drop the default `w-80`
44
+ // sidebar constraint.
45
+ className?: string
42
46
  }
43
47
 
44
48
  // Small eye toggle to hide/show the selected element in the editor preview only
@@ -179,6 +183,7 @@ export default function SlidePropertyPanel({
179
183
  adapter,
180
184
  hiddenElementIds,
181
185
  onToggleElementVisibility,
186
+ className,
182
187
  }: Props) {
183
188
  // Map of jsxPath → GlobalOverlay for overlay prop schemas
184
189
  const [overlaySchemas, setOverlaySchemas] = useState<Map<string, GlobalOverlay>>(new Map())
@@ -206,7 +211,7 @@ export default function SlidePropertyPanel({
206
211
 
207
212
  if (!slide) {
208
213
  return (
209
- <div className="w-80 flex-shrink-0 flex items-center justify-center text-[var(--editor-text)]/40 text-xs p-4">
214
+ <div className={cn('w-80 flex-shrink-0 flex items-center justify-center text-[var(--editor-text)]/40 text-xs p-4', className)}>
210
215
  Select a slide
211
216
  </div>
212
217
  )
@@ -216,7 +221,7 @@ export default function SlidePropertyPanel({
216
221
  const overlaySchema = overlayEl ? overlaySchemas.get(overlayEl.overlay.template) : null
217
222
 
218
223
  return (
219
- <div className="w-80 flex-shrink-0 border-l border-[var(--editor-border)] flex flex-col overflow-y-auto bg-[var(--editor-bg)]">
224
+ <div className={cn('w-80 flex-shrink-0 border-l border-[var(--editor-border)] flex flex-col overflow-y-auto bg-[var(--editor-bg)]', className)}>
220
225
  {/* Slide header */}
221
226
  <div className="px-4 py-3 border-b border-[var(--editor-border)]">
222
227
  <div className="text-xs font-semibold text-[var(--editor-text)]/60 uppercase tracking-wider mb-2">Slide</div>
@@ -97,11 +97,11 @@ describe('CarouselEditor — editor-core integration', () => {
97
97
  />,
98
98
  )
99
99
  await waitFor(() => getByTestId('assets'))
100
- // The assets slot now lives in the below-canvas region and fills the remaining
101
- // width (flex-1) rather than being capped to a 320px sidebar so a wide host
102
- // panel uses its full share of the row without crushing the canvas above.
100
+ // The assets slot lives in the below-canvas region, stacked full-width at the
101
+ // very bottom (no longer capped to a 320px sidebar) so the host panel spans
102
+ // the editor width beneath the property panel.
103
103
  const wrapper = getByTestId('assets').parentElement
104
- expect(wrapper?.className).toContain('flex-1')
104
+ expect(wrapper?.className).toContain('w-full')
105
105
  expect(wrapper?.className).not.toContain('w-80')
106
106
  })
107
107
 
package/src/ui/button.tsx CHANGED
@@ -7,10 +7,10 @@ const buttonVariants = cva(
7
7
  variants: {
8
8
  variant: {
9
9
  default: 'bg-[var(--editor-accent)] text-[var(--editor-accent-foreground)] hover:opacity-90',
10
- secondary: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-[var(--editor-surface)] dark:text-[var(--editor-text)] dark:hover:opacity-90',
11
- ghost: 'text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-[var(--editor-text)]/60 dark:hover:bg-[var(--editor-surface)] dark:hover:text-[var(--editor-text)]',
10
+ secondary: 'bg-[var(--editor-surface)] text-[var(--editor-text)] border border-[var(--editor-border)] hover:border-[var(--editor-accent)]',
11
+ ghost: 'text-[var(--editor-text)] hover:bg-[var(--editor-surface)] hover:text-[var(--editor-text)]',
12
12
  danger: 'bg-red-600 text-white hover:bg-red-700',
13
- outline: 'border border-gray-300 dark:border-[var(--editor-border)] text-gray-700 dark:text-[var(--editor-text)] hover:bg-gray-100 dark:hover:bg-[var(--editor-surface)]',
13
+ outline: 'bg-[var(--editor-surface)] text-[var(--editor-text)] border border-[var(--editor-border)] hover:border-[var(--editor-accent)]',
14
14
  },
15
15
  size: {
16
16
  default: 'h-9 px-4 py-2',