@braincrew-lab/langchain-canvas 0.1.14 → 0.3.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.
package/dist/styles.css CHANGED
@@ -143,8 +143,74 @@
143
143
  .cv-undo button:hover:not(:disabled) { background: var(--cv-surface); }
144
144
  .cv-undo button:disabled { opacity: 0.35; cursor: default; }
145
145
 
146
- .cv-versions { display: flex; align-items: center; gap: 6px; }
147
- .cv-versions__label { font-size: 12px; color: var(--cv-muted); font-variant-numeric: tabular-nums; }
146
+ .cv-versions { position: relative; display: flex; align-items: center; gap: 6px; }
147
+ .cv-versions__label {
148
+ font-size: 12px;
149
+ color: var(--cv-muted);
150
+ font-variant-numeric: tabular-nums;
151
+ border: none;
152
+ background: none;
153
+ cursor: pointer;
154
+ padding: 2px 4px;
155
+ border-radius: 6px;
156
+ }
157
+ .cv-versions__label:hover { background: var(--cv-surface); color: var(--cv-text); }
158
+ .cv-versions__list {
159
+ position: absolute;
160
+ top: calc(100% + 6px);
161
+ right: 0;
162
+ z-index: 30;
163
+ min-width: 220px;
164
+ max-height: 260px;
165
+ overflow-y: auto;
166
+ margin: 0;
167
+ padding: 4px;
168
+ list-style: none;
169
+ border: 1px solid var(--cv-border);
170
+ border-radius: 10px;
171
+ background: var(--cv-surface);
172
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
173
+ }
174
+ .cv-versions__list button {
175
+ display: flex;
176
+ gap: 8px;
177
+ align-items: baseline;
178
+ width: 100%;
179
+ padding: 6px 8px;
180
+ border: none;
181
+ border-radius: 6px;
182
+ background: none;
183
+ color: var(--cv-text);
184
+ text-align: left;
185
+ font-size: 12px;
186
+ cursor: pointer;
187
+ }
188
+ .cv-versions__list button:hover { background: var(--cv-bg); }
189
+ .cv-versions__list button.is-current { background: var(--cv-bg); font-weight: 600; }
190
+ .cv-versions__v { color: var(--cv-muted); font-variant-numeric: tabular-nums; flex: none; }
191
+ .cv-versions__desc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
192
+
193
+ /* Historical snapshot view: content is visible and scrollable but not editable
194
+ (children lose hit-testing; the scroll container itself still gets the wheel). */
195
+ .cv-history-banner {
196
+ display: flex;
197
+ gap: 8px;
198
+ align-items: center;
199
+ padding: 6px 14px;
200
+ font-size: 12px;
201
+ color: var(--cv-muted);
202
+ background: var(--cv-surface);
203
+ border-bottom: 1px solid var(--cv-border);
204
+ }
205
+ .cv-history-banner button {
206
+ border: none;
207
+ background: none;
208
+ color: var(--cv-accent, #4f46e5);
209
+ cursor: pointer;
210
+ font-size: 12px;
211
+ padding: 0;
212
+ }
213
+ .cv-body--history > * { pointer-events: none; }
148
214
  .cv-versions__nav {
149
215
  width: 24px;
150
216
  height: 24px;
@@ -212,6 +278,16 @@
212
278
  .cv-body--flush { padding: 0; overflow: hidden; }
213
279
  .cv-fallback { color: var(--cv-muted); font-size: 14px; }
214
280
 
281
+ /* Browsing an old version: a preview, not an editing surface. Interaction is
282
+ blocked wholesale — renderers patch by artifact id, so edits made "in the
283
+ past" would silently overwrite the live version. */
284
+ .cv-body--history > :not(.cv-history-note) { pointer-events: none; user-select: none; }
285
+ .cv-history-note {
286
+ position: sticky; top: 0; z-index: 5; margin-bottom: 12px;
287
+ padding: 6px 12px; border-radius: 8px; font-size: 12.5px; font-weight: 600;
288
+ color: var(--cv-muted); background: var(--cv-surface); border: 1px solid var(--cv-border);
289
+ }
290
+
215
291
  /* --- inline editing (document / table / slides) ------------------------------- */
216
292
 
217
293
  .cv-edit-toolbar { display: flex; justify-content: flex-end; margin-bottom: 10px; }
@@ -404,7 +480,308 @@
404
480
  .cv-sheet-tools__filter { min-width: 96px; max-width: 160px; }
405
481
  .cv-sheet-tools__sort:focus, .cv-sheet-tools__filter:focus { outline: none; border-color: var(--cv-accent); }
406
482
  .cv-sheet-tools__hint { margin-left: auto; font-size: 11px; color: var(--cv-muted); }
483
+
484
+ /* --- Excel-style ribbon toolbar ----------------------------------------------- */
485
+ /* The Excel model in the canvas's language: each group is a soft "keycap" tray
486
+ of ghost controls with the group's name set small underneath — organized at a
487
+ glance, quiet until hovered. */
488
+
489
+ .cv-ribbon {
490
+ align-items: flex-start;
491
+ gap: 8px;
492
+ padding: 7px 12px 5px;
493
+ overflow-x: auto;
494
+ scrollbar-width: thin;
495
+ }
496
+ .cv-ribbon__group {
497
+ display: flex;
498
+ flex-direction: column;
499
+ align-items: center;
500
+ gap: 3px;
501
+ }
502
+ .cv-ribbon__items {
503
+ display: flex;
504
+ align-items: center;
505
+ gap: 1px;
506
+ padding: 2px;
507
+ background: var(--cv-surface);
508
+ border: 1px solid var(--cv-border);
509
+ border-radius: 9px;
510
+ }
511
+ .cv-ribbon__label {
512
+ font-size: 10px;
513
+ font-weight: 600;
514
+ letter-spacing: 0.05em;
515
+ color: var(--cv-muted);
516
+ white-space: nowrap;
517
+ user-select: none;
518
+ }
519
+ .cv-ribbon__gap { width: 5px; }
520
+
521
+ /* ghost controls — the tray is the chrome */
522
+ .cv-ribbon .cv-ribbon__btn {
523
+ height: 26px;
524
+ min-width: 26px;
525
+ padding: 0 9px;
526
+ border: none;
527
+ border-radius: 7px;
528
+ background: transparent;
529
+ color: var(--cv-text);
530
+ font-size: 12px;
531
+ font-weight: 600;
532
+ line-height: 1;
533
+ white-space: nowrap;
534
+ cursor: pointer;
535
+ display: inline-flex;
536
+ align-items: center;
537
+ justify-content: center;
538
+ gap: 4px;
539
+ transition: background 0.12s, box-shadow 0.12s;
540
+ }
541
+ .cv-ribbon .cv-ribbon__btn:hover:not(:disabled) {
542
+ background: var(--cv-bg);
543
+ border: none;
544
+ color: var(--cv-text);
545
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
546
+ }
547
+ .cv-ribbon .cv-ribbon__btn:active:not(:disabled) { box-shadow: none; }
548
+ .cv-ribbon .cv-ribbon__btn:disabled { opacity: 0.35; cursor: default; }
549
+ .cv-ribbon .cv-ribbon__btn.is-on {
550
+ background: var(--cv-accent-weak);
551
+ color: var(--cv-accent);
552
+ box-shadow: inset 0 0 0 1px var(--cv-accent);
553
+ }
554
+ .cv-ribbon .cv-ribbon__btn--icon { padding: 0 6px; }
555
+ .cv-ribbon .cv-ribbon__btn--glyph { font-weight: 800; font-size: 13px; width: 26px; padding: 0; }
556
+
557
+ /* Excel-style color swatches: glyph over a live color bar, picker underneath */
558
+ .cv-ribbon__swatch {
559
+ position: relative;
560
+ display: inline-flex;
561
+ flex-direction: column;
562
+ align-items: center;
563
+ justify-content: center;
564
+ gap: 2px;
565
+ width: 26px;
566
+ height: 26px;
567
+ border-radius: 7px;
568
+ cursor: pointer;
569
+ transition: background 0.12s, box-shadow 0.12s;
570
+ }
571
+ .cv-ribbon__swatch:hover:not(.is-disabled) { background: var(--cv-bg); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }
572
+ .cv-ribbon__swatch.is-disabled { opacity: 0.35; cursor: default; }
573
+ .cv-ribbon__swatch-glyph { font-size: 12px; font-weight: 800; line-height: 1; display: inline-flex; align-items: center; }
574
+ .cv-ribbon__swatch-bar { width: 15px; height: 3.5px; border-radius: 2px; box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.12); }
575
+ .cv-ribbon__swatch input[type="color"] {
576
+ position: absolute;
577
+ inset: 0;
578
+ opacity: 0;
579
+ width: 100%;
580
+ height: 100%;
581
+ padding: 0;
582
+ border: none;
583
+ cursor: pointer;
584
+ }
585
+ .cv-ribbon__swatch.is-disabled input { pointer-events: none; }
586
+
587
+ /* selects/inputs live in the tray as quiet controls */
588
+ .cv-ribbon .cv-ribbon__select,
589
+ .cv-ribbon .cv-ribbon__input {
590
+ height: 26px;
591
+ font: inherit;
592
+ font-size: 12px;
593
+ font-weight: 600;
594
+ padding: 0 7px;
595
+ border: none;
596
+ border-radius: 7px;
597
+ background: transparent;
598
+ color: var(--cv-text);
599
+ max-width: 130px;
600
+ transition: background 0.12s;
601
+ }
602
+ .cv-ribbon .cv-ribbon__select:hover:not(:disabled),
603
+ .cv-ribbon .cv-ribbon__input:hover { background: var(--cv-bg); border: none; }
604
+ .cv-ribbon .cv-ribbon__select:focus,
605
+ .cv-ribbon .cv-ribbon__input:focus { outline: none; background: var(--cv-bg); box-shadow: inset 0 0 0 1px var(--cv-accent); }
606
+ .cv-ribbon .cv-ribbon__select:disabled { opacity: 0.35; }
607
+ .cv-ribbon .cv-ribbon__input { width: 88px; font-weight: 500; }
608
+ .cv-ribbon .cv-ribbon__input::placeholder { color: var(--cv-muted); }
609
+
610
+ /* selection formatting cluster — reads as one tight group between separators */
611
+ .cv-sheet-tools__fmt { display: inline-flex; align-items: center; gap: 3px; }
612
+ .cv-sheet-tools__fmt button:disabled,
613
+ .cv-sheet-tools button:disabled { opacity: 0.4; cursor: default; }
614
+ .cv-sheet-tools button:disabled:hover { border-color: var(--cv-border); color: var(--cv-text); }
615
+ .cv-sheet-tools__bold, .cv-sheet-tools__align { width: 28px; padding: 4px 0 !important; text-align: center; }
616
+ .cv-sheet-tools__bold--on,
617
+ .cv-sheet-tools__freeze--on {
618
+ background: var(--cv-accent-weak) !important; border-color: var(--cv-accent) !important;
619
+ color: var(--cv-accent) !important;
620
+ }
621
+ .cv-sheet-tools__color {
622
+ width: 28px; height: 26px; padding: 2px; border: 1px solid var(--cv-border);
623
+ border-radius: 6px; background: var(--cv-bg); cursor: pointer;
624
+ }
625
+ .cv-sheet-tools__color:disabled { opacity: 0.4; cursor: default; }
626
+ .cv-sheet-tools__numfmt, .cv-sheet-tools__fx {
627
+ font: inherit; font-size: 12.5px; padding: 4px 6px; border-radius: 6px;
628
+ border: 1px solid var(--cv-border); background: var(--cv-bg); color: var(--cv-text);
629
+ }
630
+ .cv-sheet-tools__numfmt:disabled, .cv-sheet-tools__fx:disabled { opacity: 0.4; }
631
+ .cv-sheet-tools__numfmt:focus, .cv-sheet-tools__fx:focus { outline: none; border-color: var(--cv-accent); }
632
+
633
+ /* formula bar — a hairline row between the toolbar and the grid */
634
+ .cv-sheet-fxbar {
635
+ display: flex; align-items: center; gap: 8px; padding: 4px 10px;
636
+ border-bottom: 1px solid var(--cv-border); background: var(--cv-bg); flex: 0 0 auto;
637
+ }
638
+ .cv-sheet-fxbar__cell {
639
+ min-width: 44px; text-align: center; font-size: 12px; font-weight: 600;
640
+ color: var(--cv-muted); font-variant-numeric: tabular-nums;
641
+ border-right: 1px solid var(--cv-border); padding-right: 8px;
642
+ }
643
+ .cv-sheet-fxbar__input {
644
+ flex: 1; font-family: var(--cv-mono); font-size: 12.5px; padding: 3px 8px;
645
+ border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--cv-text);
646
+ }
647
+ .cv-sheet-fxbar__input:focus { outline: none; border-color: var(--cv-accent); background: var(--cv-bg); }
648
+ .cv-sheet-fxbar__input:disabled { opacity: 0.5; }
407
649
  .cv-sheet { position: relative; width: 100%; flex: 1; height: auto; min-height: 0; }
650
+
651
+ /* --- Fortune-sheet internals, retuned to the canvas design language ----------- */
652
+ /* Fortune ships its own visual defaults (raw blues, hard corners, UA-grey
653
+ dialogs). Everything user-visible is re-tokenized here so the spreadsheet
654
+ reads as part of the canvas, not an embedded third-party widget. */
655
+
656
+ /* toolbar */
657
+ .cv-sheet .fortune-toolbar {
658
+ background: var(--cv-bg);
659
+ border-bottom: 1px solid var(--cv-border);
660
+ padding: 4px 8px;
661
+ }
662
+ .cv-sheet .fortune-toolbar-button,
663
+ .cv-sheet .fortune-toolbar-item {
664
+ border-radius: 6px;
665
+ transition: background 0.12s;
666
+ }
667
+ .cv-sheet .fortune-toolbar-button:hover,
668
+ .cv-sheet .fortune-toolbar-item:hover,
669
+ .cv-sheet .fortune-toolbar-combo-button:hover {
670
+ background: var(--cv-surface);
671
+ }
672
+ .cv-sheet .fortune-toolbar-divider { border-color: var(--cv-border); }
673
+ .cv-sheet .fortune-toolbar-combo { border-radius: 6px; }
674
+
675
+ /* Fortune's own formula row duplicates the canvas formula bar above it — hide it
676
+ (the name box A1 + fx input live in .cv-sheet-fxbar). */
677
+ .cv-sheet .fortune-fx-editor { display: none !important; }
678
+
679
+ /* dialogs (conditional format, insert link, …) */
680
+ .luckysheet-modal-dialog {
681
+ border: 1px solid var(--cv-border) !important;
682
+ border-radius: 12px !important;
683
+ box-shadow: 0 18px 50px rgba(0, 0, 0, 0.22) !important;
684
+ background: var(--cv-bg) !important;
685
+ color: var(--cv-text) !important;
686
+ font-family: var(--cv-font) !important;
687
+ padding: 18px 20px !important;
688
+ }
689
+ .luckysheet-modal-dialog-border { border: none !important; }
690
+ .luckysheet-modal-dialog input[type="text"],
691
+ .luckysheet-modal-dialog input[type="number"],
692
+ .luckysheet-modal-dialog select,
693
+ .luckysheet-modal-dialog textarea {
694
+ font: inherit;
695
+ padding: 6px 10px;
696
+ border: 1px solid var(--cv-border);
697
+ border-radius: 8px;
698
+ background: var(--cv-bg);
699
+ color: var(--cv-text);
700
+ }
701
+ .luckysheet-modal-dialog input:focus,
702
+ .luckysheet-modal-dialog select:focus,
703
+ .luckysheet-modal-dialog textarea:focus { outline: none; border-color: var(--cv-accent); }
704
+ .luckysheet-modal-dialog button {
705
+ font: 600 13px/1.2 var(--cv-font);
706
+ padding: 7px 16px;
707
+ border: 1px solid var(--cv-border);
708
+ border-radius: 8px;
709
+ background: var(--cv-bg);
710
+ color: var(--cv-text);
711
+ cursor: pointer;
712
+ }
713
+ .luckysheet-modal-dialog button:hover { background: var(--cv-surface); }
714
+ /* Fortune marks its confirm buttons with a solid blue — remap to the accent. */
715
+ .luckysheet-modal-dialog button[style*="rgb(26, 115, 232)"],
716
+ .luckysheet-modal-dialog .fortune-message-box-button-primary,
717
+ .luckysheet-modal-dialog button.primary {
718
+ background: var(--cv-accent) !important;
719
+ border-color: var(--cv-accent) !important;
720
+ color: #fff !important;
721
+ }
722
+
723
+ /* context menus (right-click, header menus) */
724
+ .fortune-context-menu,
725
+ .luckysheet-cols-menu {
726
+ border: 1px solid var(--cv-border) !important;
727
+ border-radius: 10px !important;
728
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.16) !important;
729
+ background: var(--cv-bg) !important;
730
+ color: var(--cv-text) !important;
731
+ font-family: var(--cv-font) !important;
732
+ padding: 6px !important;
733
+ overflow: hidden;
734
+ }
735
+ .fortune-context-menu > div,
736
+ .luckysheet-cols-menuitem {
737
+ border-radius: 7px;
738
+ font-size: 13px;
739
+ }
740
+ .fortune-context-menu > div:hover,
741
+ .luckysheet-cols-menuitem:hover { background: var(--cv-surface) !important; }
742
+ .fortune-context-menu-divider { border-color: var(--cv-border) !important; }
743
+
744
+ /* sheet tabs + status bar */
745
+ .cv-sheet .fortune-sheettab-container {
746
+ background: var(--cv-bg);
747
+ border-top: 1px solid var(--cv-border);
748
+ font-family: var(--cv-font);
749
+ }
750
+ .cv-sheet .luckysheet-sheets-item {
751
+ border-radius: 7px 7px 0 0;
752
+ color: var(--cv-muted);
753
+ }
754
+ .cv-sheet .luckysheet-sheets-item-active {
755
+ color: var(--cv-accent);
756
+ background: var(--cv-accent-weak);
757
+ font-weight: 600;
758
+ }
759
+ .cv-sheet .fortune-sheettab-button { border-radius: 6px; }
760
+ .cv-sheet .fortune-sheettab-button:hover { background: var(--cv-surface); }
761
+ .cv-sheet .fortune-stat-area,
762
+ .cv-sheet .fortune-zoom-container { font-family: var(--cv-font); color: var(--cv-muted); }
763
+ .cv-sheet .fortune-zoom-button { border-radius: 6px; }
764
+ .cv-sheet .fortune-zoom-button:hover { background: var(--cv-surface); }
765
+
766
+ /* tooltips + scrollbars */
767
+ .fortune-tooltip {
768
+ border-radius: 7px !important;
769
+ font-family: var(--cv-font) !important;
770
+ font-size: 12px !important;
771
+ }
772
+ .cv-sheet .luckysheet-scrollbar-x::-webkit-scrollbar,
773
+ .cv-sheet .luckysheet-scrollbar-y::-webkit-scrollbar { width: 8px; height: 8px; }
774
+ .cv-sheet .luckysheet-scrollbar-x::-webkit-scrollbar-thumb,
775
+ .cv-sheet .luckysheet-scrollbar-y::-webkit-scrollbar-thumb {
776
+ background: var(--cv-border);
777
+ border-radius: 999px;
778
+ }
779
+ .cv-sheet .luckysheet-scrollbar-x::-webkit-scrollbar-thumb:hover,
780
+ .cv-sheet .luckysheet-scrollbar-y::-webkit-scrollbar-thumb:hover { background: var(--cv-muted); }
781
+
782
+ /* in-cell editor */
783
+ .cv-sheet .luckysheet-cell-input,
784
+ .cv-sheet .luckysheet-input-box-inner { font-family: var(--cv-font); }
408
785
  .cv-sheet .fortune-container { height: 100% !important; width: 100% !important; }
409
786
  .cv-sheet--empty { display: grid; place-items: center; height: 200px; color: var(--cv-muted); font-size: 14px; }
410
787
 
@@ -445,6 +822,7 @@
445
822
  border: 1px solid var(--cv-border);
446
823
  border-radius: 5px;
447
824
  overflow: hidden;
825
+ container-type: inline-size;
448
826
  }
449
827
  .cv-deck__thumb.is-active .cv-deck__thumb-slide { border-color: var(--cv-accent); box-shadow: 0 0 0 1px var(--cv-accent); }
450
828
  .cv-deck__thumb-slide b { display: block; margin-bottom: 3px; font-size: 9px; line-height: 1.2; }
@@ -572,14 +950,19 @@
572
950
 
573
951
  /* blank / free-canvas layout */
574
952
  .cv-slide { position: relative; }
575
- .cv-slide--blank { display: block; padding: 0; }
953
+ .cv-slide--blank { display: block; padding: 0; container-type: inline-size; }
954
+ /* Text on a free slide is sized in cqw (1cqw = 1% of the slide's width), so type
955
+ scales with the slide exactly like the percent geometry does — the editor,
956
+ thumbnails, and present mode all show the same proportions at any width. */
576
957
  .cv-free { position: absolute; inset: 0; }
577
958
  .cv-free__el { position: absolute; box-sizing: border-box; cursor: move; }
578
959
  .cv-free__guide { position: absolute; z-index: 6; background: #f43f5e; pointer-events: none; }
579
960
  .cv-free__guide--v { top: 0; bottom: 0; width: 1px; }
580
961
  .cv-free__guide--h { left: 0; right: 0; height: 1px; }
581
962
  .cv-free__el.is-selected { outline: 1.5px solid var(--cv-accent); outline-offset: 1px; }
582
- .cv-free__text { width: 100%; height: 100%; outline: none; overflow: hidden; line-height: 1.3; }
963
+ /* PowerPoint semantics: a text box is a layout hint, not a clip — text that
964
+ runs long paints past the box instead of vanishing mid-word. */
965
+ .cv-free__text { width: 100%; min-height: 100%; outline: none; overflow: visible; line-height: 1.2; }
583
966
  .cv-free__img { width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
584
967
  .cv-free__resize {
585
968
  position: absolute; right: -5px; bottom: -5px; width: 12px; height: 12px;
@@ -613,6 +996,42 @@
613
996
  .cv-free__fmt input[type="number"] { width: 46px; height: 24px; border: 1px solid var(--cv-border); border-radius: 5px; background: var(--cv-bg); color: var(--cv-text); font-size: 12px; padding: 0 4px; }
614
997
  .cv-free__fmt input[type="color"] { width: 26px; height: 24px; padding: 0; border: 1px solid var(--cv-border); border-radius: 5px; background: none; cursor: pointer; }
615
998
 
999
+ /* multi-select: marquee, selection state, floating action bar */
1000
+ .cv-free { outline: none; } /* the canvas is focusable for keyboard nudge/shortcuts */
1001
+ .cv-free:focus-visible { outline: 2px solid var(--cv-accent); outline-offset: -2px; border-radius: 4px; }
1002
+ .cv-free__marquee {
1003
+ position: absolute; z-index: 7; pointer-events: none;
1004
+ border: 1px solid var(--cv-accent);
1005
+ background: color-mix(in srgb, var(--cv-accent) 10%, transparent);
1006
+ border-radius: 2px;
1007
+ }
1008
+ .cv-free__el--selected { outline: 1.5px solid var(--cv-accent); outline-offset: 1px; }
1009
+ .cv-free__multibar {
1010
+ position: absolute; z-index: 8; transform: translate(-50%, calc(-100% - 8px));
1011
+ display: flex; align-items: center; gap: 2px;
1012
+ padding: 3px; background: var(--cv-bg); border: 1px solid var(--cv-border);
1013
+ border-radius: 8px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.16); cursor: default;
1014
+ }
1015
+ .cv-free__multibar--below { transform: translate(-50%, 8px); }
1016
+ .cv-free__multibar button {
1017
+ min-width: 24px; height: 24px; padding: 0 6px; border: none; border-radius: 5px;
1018
+ background: transparent; color: var(--cv-text); cursor: pointer; font-size: 12px; white-space: nowrap;
1019
+ }
1020
+ .cv-free__multibar button:hover { background: var(--cv-surface); }
1021
+ .cv-free__multibar button:disabled { opacity: 0.4; cursor: default; background: transparent; }
1022
+ .cv-free__multibar-del:hover { background: #fee2e2 !important; color: #dc2626; }
1023
+
1024
+ /* per-element control-bar inputs: rotation + corner radius */
1025
+ .cv-free__ctl-rot, .cv-free__ctl-radius {
1026
+ width: 44px; height: 22px; font: inherit; font-size: 11.5px; padding: 0 4px;
1027
+ border: 1px solid var(--cv-border); border-radius: 5px; background: var(--cv-bg); color: var(--cv-text);
1028
+ }
1029
+ .cv-free__ctl-rot:focus, .cv-free__ctl-radius:focus { outline: none; border-color: var(--cv-accent); }
1030
+
1031
+ /* slide reorder: insertion indicator while dragging a thumbnail */
1032
+ .cv-deck__thumb-wrap--drop-before { box-shadow: 0 -2px 0 0 var(--cv-accent); }
1033
+ .cv-deck__thumb-wrap--drop-after { box-shadow: 0 2px 0 0 var(--cv-accent); }
1034
+
616
1035
  /* toolbar: background swatch + present button */
617
1036
  .cv-deck__bg input[type="color"] {
618
1037
  width: 30px; height: 30px; padding: 0;
@@ -656,6 +1075,22 @@
656
1075
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08);
657
1076
  border-radius: 10px; padding: 12px 16px; cursor: default; white-space: pre-wrap;
658
1077
  }
1078
+ /* Deck progress: a hairline track pinned to the bottom edge, plus a counter chip. */
1079
+ .cv-present__progress {
1080
+ position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
1081
+ background: rgba(255, 255, 255, 0.08);
1082
+ }
1083
+ .cv-present__progress-fill {
1084
+ height: 100%; background: var(--cv-accent);
1085
+ transition: width 0.28s ease;
1086
+ }
1087
+ @media (prefers-reduced-motion: reduce) { .cv-present__progress-fill { transition: none; } }
1088
+ .cv-present__count {
1089
+ position: absolute; top: 16px; right: 20px;
1090
+ color: #9aa4b2; font-size: 13px; font-variant-numeric: tabular-nums;
1091
+ background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08);
1092
+ border-radius: 999px; padding: 3px 10px; cursor: default;
1093
+ }
659
1094
 
660
1095
  /* in-place editing cues */
661
1096
  .cv-word .cv-doc { cursor: text; }
@@ -917,6 +1352,14 @@
917
1352
  transition: width 0.2s ease;
918
1353
  }
919
1354
 
1355
+ /* document-mode chip on the html toolbar (imported .hwp/.hwpx etc.) */
1356
+ .cv-html-doc-chip {
1357
+ display: inline-flex; align-items: center; gap: 4px;
1358
+ font-size: 11.5px; font-weight: 700; color: var(--cv-accent);
1359
+ background: var(--cv-accent-weak); border: 1px solid var(--cv-border);
1360
+ border-radius: 999px; padding: 3px 10px; white-space: nowrap;
1361
+ }
1362
+
920
1363
  /* --- selection quick-edit bar ------------------------------------------------- */
921
1364
 
922
1365
  .cv-selection {
@@ -1086,6 +1529,36 @@
1086
1529
  color: var(--cv-muted);
1087
1530
  }
1088
1531
 
1532
+ /* --- PDF viewer ---------------------------------------------------------------- */
1533
+
1534
+ /* Fills the flush body outright — `flex: 1` alone collapsed the iframe to its
1535
+ content height (a thin strip of page) because `.cv-body` is a block, not a
1536
+ flex container. */
1537
+ .cv-pdf-panel { display: flex; flex-direction: column; height: 100%; min-height: 480px; }
1538
+ .cv-pdf-tools {
1539
+ display: flex; align-items: center; gap: 6px; padding: 6px 10px;
1540
+ border-bottom: 1px solid var(--cv-border); background: var(--cv-bg); flex: 0 0 auto;
1541
+ }
1542
+ .cv-pdf-tools button {
1543
+ font-size: 12px; font-weight: 600; padding: 4px 10px; border: 1px solid var(--cv-border);
1544
+ border-radius: 6px; background: var(--cv-bg); color: var(--cv-text); cursor: pointer;
1545
+ }
1546
+ .cv-pdf-tools button:hover { border-color: var(--cv-accent); color: var(--cv-accent); }
1547
+ .cv-pdf-tools__name {
1548
+ font-size: 12px; font-weight: 600; color: var(--cv-muted);
1549
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 55%;
1550
+ }
1551
+ .cv-pdf-tools__spacer { flex: 1; }
1552
+ .cv-pdf-tools__sep { width: 1px; height: 18px; background: var(--cv-border); margin: 0 2px; }
1553
+ .cv-pdf-tools__zoom { display: inline-flex; align-items: center; gap: 3px; }
1554
+ .cv-pdf-tools__zoom button { min-width: 26px; }
1555
+ .cv-pdf-tools__zoom-label {
1556
+ min-width: 52px; font-variant-numeric: tabular-nums; color: var(--cv-muted);
1557
+ }
1558
+ .cv-pdf { position: relative; flex: 1; min-height: 0; background: var(--cv-surface); }
1559
+ .cv-pdf__frame { display: block; width: 100%; height: 100%; border: 0; }
1560
+ .cv-pdf--empty { display: grid; place-items: center; min-height: 200px; color: var(--cv-muted); }
1561
+
1089
1562
  /* --- inline artifact card (for the transcript) -------------------------------- */
1090
1563
 
1091
1564
  .cv-card {
package/package.json CHANGED
@@ -1,14 +1,35 @@
1
1
  {
2
2
  "name": "@braincrew-lab/langchain-canvas",
3
- "version": "0.1.14",
3
+ "version": "0.3.0",
4
4
  "description": "A live canvas for LangChain agents — stream documents, charts, and rich artifacts into a React panel.",
5
5
  "license": "MIT",
6
+ "author": "Brain Crew (https://github.com/braincrew-lab)",
7
+ "homepage": "https://github.com/braincrew-lab/langchain-canvas#readme",
6
8
  "type": "module",
9
+ "keywords": [
10
+ "langchain",
11
+ "langgraph",
12
+ "ai",
13
+ "agent",
14
+ "canvas",
15
+ "artifacts",
16
+ "generative-ui",
17
+ "streaming",
18
+ "llm",
19
+ "react",
20
+ "document",
21
+ "chart",
22
+ "spreadsheet",
23
+ "slides"
24
+ ],
7
25
  "repository": {
8
26
  "type": "git",
9
27
  "url": "git+https://github.com/braincrew-lab/langchain-canvas.git",
10
28
  "directory": "packages/canvas-react"
11
29
  },
30
+ "bugs": {
31
+ "url": "https://github.com/braincrew-lab/langchain-canvas/issues"
32
+ },
12
33
  "sideEffects": [
13
34
  "*.css",
14
35
  "./dist/index.js"
@@ -58,6 +79,9 @@
58
79
  "build": "tsup",
59
80
  "dev": "tsup --watch",
60
81
  "typecheck": "tsc --noEmit",
61
- "test": "vitest run"
82
+ "test": "vitest run",
83
+ "release:patch": "npm version patch -m \"release: %s\"",
84
+ "release:minor": "npm version minor -m \"release: %s\"",
85
+ "release:major": "npm version major -m \"release: %s\""
62
86
  }
63
87
  }