@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
|
@@ -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 =
|
|
361
|
-
const HINT_RESERVE =
|
|
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-
|
|
368
|
-
{/* TOP: slide rail + canvas
|
|
369
|
-
|
|
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-
|
|
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
|
|
497
|
-
|
|
498
|
-
|
|
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
|
-
<
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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
|
|
101
|
-
//
|
|
102
|
-
//
|
|
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('
|
|
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-
|
|
11
|
-
ghost: '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: '
|
|
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',
|