@jackuait/blok 0.7.3-beta.3 → 0.7.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.
Files changed (68) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-CdxHhr5i.mjs → blok-BmlbETK7.mjs} +2119 -2013
  3. package/dist/chunks/{constants-C_H9o9Ao.mjs → constants-WhLyFkza.mjs} +260 -223
  4. package/dist/chunks/{i18next-loader-D5HxE5ZQ.mjs → i18next-loader-CZARkla1.mjs} +1 -1
  5. package/dist/chunks/{lightweight-i18n-Safdy0ua.mjs → lightweight-i18n-BQa0F2X6.mjs} +9 -0
  6. package/dist/chunks/{tools-B0YXCZFW.mjs → tools-BCb5bMO3.mjs} +973 -843
  7. package/dist/full.mjs +3 -3
  8. package/dist/locales.mjs +9 -0
  9. package/dist/react.mjs +2 -2
  10. package/dist/tools.mjs +2 -2
  11. package/package.json +1 -1
  12. package/src/components/block/style-manager.ts +1 -1
  13. package/src/components/blocks.ts +26 -54
  14. package/src/components/constants/data-attributes.ts +0 -2
  15. package/src/components/i18n/locales/en/messages.json +9 -0
  16. package/src/components/icons/index.ts +34 -6
  17. package/src/components/inline-tools/inline-tool-link.ts +202 -5
  18. package/src/components/inline-tools/inline-tool-marker.ts +166 -23
  19. package/src/components/inline-tools/utils/formatting-range-utils.ts +10 -1
  20. package/src/components/modules/blockManager/blockManager.ts +2 -2
  21. package/src/components/modules/blockManager/operations.ts +2 -2
  22. package/src/components/modules/blockManager/repository.ts +1 -9
  23. package/src/components/modules/blockManager/types.ts +1 -1
  24. package/src/components/modules/drag/operations/DragOperations.ts +45 -6
  25. package/src/components/modules/paste/google-docs-preprocessor.ts +69 -2
  26. package/src/components/modules/paste/handlers/blok-data-handler.ts +96 -19
  27. package/src/components/modules/renderer.ts +2 -0
  28. package/src/components/modules/toolbar/blockSettings.ts +1 -1
  29. package/src/components/modules/toolbar/index.ts +21 -0
  30. package/src/components/modules/toolbar/plus-button.ts +15 -5
  31. package/src/components/selection/fake-background/index.ts +9 -10
  32. package/src/components/shared/color-picker.ts +108 -95
  33. package/src/components/shared/color-presets.ts +30 -2
  34. package/src/components/ui/toolbox.ts +36 -7
  35. package/src/components/utils/color-mapping.ts +43 -1
  36. package/src/components/utils/color-migration.ts +37 -0
  37. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +4 -3
  38. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +5 -39
  39. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
  40. package/src/components/utils/popover/components/popover-item/popover-item.ts +11 -0
  41. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -3
  42. package/src/components/utils/popover/components/search-input/search-input.ts +1 -32
  43. package/src/components/utils/popover/popover-abstract.ts +2 -4
  44. package/src/components/utils/popover/popover-desktop.ts +1 -16
  45. package/src/components/utils/popover/popover-inline.ts +1 -2
  46. package/src/components/utils/popover/popover-mobile.ts +2 -2
  47. package/src/components/utils/popover/popover.const.ts +1 -1
  48. package/src/stories/Table.stories.ts +15 -9
  49. package/src/styles/main.css +312 -14
  50. package/src/tools/header/index.ts +5 -5
  51. package/src/tools/list/constants.ts +11 -4
  52. package/src/tools/list/depth-validator.ts +13 -1
  53. package/src/tools/list/dom-builder.ts +5 -3
  54. package/src/tools/list/index.ts +3 -2
  55. package/src/tools/paragraph/index.ts +2 -2
  56. package/src/tools/table/table-cell-color-picker.ts +1 -1
  57. package/src/tools/table/table-cell-selection.ts +1 -2
  58. package/src/tools/table/table-core.ts +2 -2
  59. package/src/tools/table/table-grip-visuals.ts +13 -5
  60. package/src/tools/table/table-heading-toggle.ts +15 -9
  61. package/src/tools/table/table-row-col-controls.ts +17 -11
  62. package/src/tools/table/table-row-col-drag.ts +26 -3
  63. package/src/tools/toggle/constants.ts +5 -5
  64. package/src/tools/toggle/index.ts +1 -1
  65. package/types/tools/hook-events.d.ts +6 -0
  66. package/types/tools/toggle.d.ts +23 -0
  67. package/types/tools-entry.d.ts +3 -0
  68. package/types/utils/popover/popover-item.d.ts +6 -0
@@ -212,7 +212,7 @@
212
212
  override Blok's styling — even when the host uses `!important`.
213
213
  Specificity raised from (0,0,1) to (0,1,1) to beat host element-selector rules.
214
214
  font-size and font-weight are intentionally omitted from this rule so that the
215
- Header tool's own Tailwind utility classes (text-4xl, font-bold, etc.) remain
215
+ Header tool's own Tailwind utility classes (text-3xl, font-bold, etc.) remain
216
216
  effective in the normal cascade. The all:initial !important on the root boundary
217
217
  already neutralizes the UA stylesheet's default heading sizes inside the editor.
218
218
  */
@@ -234,6 +234,13 @@
234
234
  font-weight: bolder;
235
235
  }
236
236
 
237
+ /* Override the browser UA color: MarkText on <mark> elements so that marks
238
+ without an explicit inline color inherit the parent's text color instead
239
+ of defaulting to black in dark mode. */
240
+ :where([data-blok-interface], [data-blok-popover]) mark {
241
+ color: inherit;
242
+ }
243
+
237
244
  /* Correct the odd em font sizing in all browsers for code elements. */
238
245
  :where([data-blok-interface], [data-blok-popover]) :is(code, kbd, samp, pre) {
239
246
  font-family: --theme(
@@ -484,7 +491,7 @@
484
491
  --spacing-block-padding-vertical: 0.4em;
485
492
 
486
493
  /* Max-width */
487
- --max-width-content: 650px;
494
+ --max-width-content: 720px;
488
495
 
489
496
  /* Font family */
490
497
  --font-mono: 'PT Mono', 'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace;
@@ -638,6 +645,11 @@
638
645
  --color-link-input-border: var(--blok-link-input-border);
639
646
  --color-popover-icon-bg: var(--blok-popover-icon-bg);
640
647
  --color-popover-icon-active-bg: var(--blok-popover-icon-active-bg);
648
+
649
+ /* Color picker swatch ring */
650
+ --color-swatch-ring-hover: var(--blok-swatch-ring-hover);
651
+ --color-swatch-ring-active: var(--blok-swatch-ring-active);
652
+
641
653
  }
642
654
 
643
655
  @layer utilities {
@@ -667,6 +679,7 @@
667
679
  --blok-popover-border: rgba(55, 53, 47, 0.09);
668
680
  --blok-popover-shadow: rgba(13, 20, 33, 0.1);
669
681
  --blok-popover-bg: #ffffff;
682
+ --blok-popover-box-shadow: 0 0 0 1px rgba(55, 53, 47, 0.09), 0 4px 16px rgba(0, 0, 0, 0.1), 0 16px 40px -8px rgba(0, 0, 0, 0.08);
670
683
  --blok-popover-border-icon: rgb(201 201 204 / 48%);
671
684
  --blok-popover-border-icon-disabled: #eff0f1;
672
685
  --blok-item-focus-bg: rgba(35, 131, 226, 0.14);
@@ -695,6 +708,50 @@
695
708
  /* Popover icon container */
696
709
  --blok-popover-icon-bg: rgba(55, 53, 47, 0.06);
697
710
  --blok-popover-icon-active-bg: rgba(35, 131, 226, 0.1);
711
+
712
+ /* Table */
713
+ --blok-table-border: #d1d5db;
714
+ --blok-table-heading-bg: #f9fafb;
715
+ --blok-table-grip-outline: transparent;
716
+ --blok-table-drag-source-bg: #f3f4f6;
717
+
718
+ /* Toggle switch */
719
+ --blok-toggle-off-bg: #d4d4d8;
720
+ --blok-toggle-on-bg: #2383e2;
721
+ --blok-toggle-thumb-on-bg: #ffffff;
722
+
723
+ /* Checklist */
724
+ --blok-checklist-border: rgba(0, 0, 0, 0.28);
725
+ --blok-checklist-shadow: rgba(0, 0, 0, 0.08);
726
+ --blok-checklist-hover-ring: rgba(35, 131, 226, 0.14);
727
+ --blok-checklist-readonly-fill: #94a3b8;
728
+
729
+ /* Color picker swatch */
730
+ --blok-swatch-neutral-bg: #f7f7f5;
731
+ --blok-swatch-ring-hover: rgba(0, 0, 0, 0.10);
732
+ --blok-swatch-ring-active: rgba(0, 0, 0, 0.30);
733
+
734
+ /* Marker colors — light theme */
735
+ --blok-color-gray-text: #787774;
736
+ --blok-color-gray-bg: #f1f1ef;
737
+ --blok-color-brown-text: #9f6b53;
738
+ --blok-color-brown-bg: #f4eeee;
739
+ --blok-color-orange-text: #d9730d;
740
+ --blok-color-orange-bg: #fbecdd;
741
+ --blok-color-yellow-text: #cb9b00;
742
+ --blok-color-yellow-bg: #fbf3db;
743
+ --blok-color-green-text: #448361;
744
+ --blok-color-green-bg: #edf3ec;
745
+ --blok-color-teal-text: #2b9a8f;
746
+ --blok-color-teal-bg: #e4f5f3;
747
+ --blok-color-blue-text: #337ea9;
748
+ --blok-color-blue-bg: #e7f3f8;
749
+ --blok-color-purple-text: #9065b0;
750
+ --blok-color-purple-bg: #f6f3f9;
751
+ --blok-color-pink-text: #c14c8a;
752
+ --blok-color-pink-bg: #f9f0f5;
753
+ --blok-color-red-text: #d44c47;
754
+ --blok-color-red-bg: #fdebec;
698
755
  }
699
756
 
700
757
  /* ─── Dark theme — system preference ────────────────── */
@@ -711,14 +768,15 @@
711
768
  --blok-link: #529cca;
712
769
  --blok-line-gray: #37352f;
713
770
  --blok-tooltip-bg: #191918;
714
- --blok-tooltip-font: #ffffff;
771
+ --blok-tooltip-font: #e8e6e3;
715
772
  --blok-icon-active-bg: rgba(35, 131, 226, 0.2);
716
773
  --blok-icon-active-text: #529cca;
717
- --blok-text-primary: #f0efed;
774
+ --blok-text-primary: #e2e0dc;
718
775
  --blok-text-secondary: #a39e98;
719
- --blok-popover-border: rgba(255, 255, 255, 0.07);
776
+ --blok-popover-border: rgba(255, 255, 255, 0.14);
720
777
  --blok-popover-shadow: rgba(0, 0, 0, 0.6);
721
778
  --blok-popover-bg: #252525;
779
+ --blok-popover-box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 4px 24px rgba(0, 0, 0, 0.5), 0 16px 40px -8px rgba(0, 0, 0, 0.4);
722
780
  --blok-popover-border-icon: #37352f;
723
781
  --blok-popover-border-icon-disabled: #2f2d29;
724
782
  --blok-item-focus-bg: rgba(35, 131, 226, 0.2);
@@ -737,12 +795,56 @@
737
795
  --blok-notify-btn-cancel-text: #a39e98;
738
796
  --blok-notify-btn-confirm-bg: #34c992;
739
797
  --blok-mobile-border: rgba(255, 255, 255, 0.07);
740
- --blok-search-input-bg: #2f2f2f;
741
- --blok-search-input-border: rgba(255, 255, 255, 0.07);
798
+ --blok-search-input-bg: #363636;
799
+ --blok-search-input-border: rgba(255, 255, 255, 0.20);
742
800
  --blok-search-input-focus-border: rgba(35, 131, 226, 0.5);
743
801
  --blok-link-input-border: #37352f;
744
802
  --blok-popover-icon-bg: rgba(255, 255, 255, 0.08);
745
803
  --blok-popover-icon-active-bg: rgba(35, 131, 226, 0.15);
804
+
805
+ /* Table */
806
+ --blok-table-border: #3e3e3d;
807
+ --blok-table-heading-bg: #272725;
808
+ --blok-table-grip-outline: rgba(255, 255, 255, 0.12);
809
+ --blok-table-drag-source-bg: rgba(255, 255, 255, 0.07);
810
+
811
+ /* Toggle switch */
812
+ --blok-toggle-off-bg: #3f3f46;
813
+ --blok-toggle-on-bg: #529cca;
814
+ --blok-toggle-thumb-on-bg: #ffffff;
815
+
816
+ /* Checklist */
817
+ --blok-checklist-border: rgba(255, 255, 255, 0.22);
818
+ --blok-checklist-shadow: rgba(0, 0, 0, 0.3);
819
+ --blok-checklist-hover-ring: rgba(82, 156, 202, 0.2);
820
+ --blok-checklist-readonly-fill: #475569;
821
+
822
+ /* Color picker swatch */
823
+ --blok-swatch-neutral-bg: #3a3a38;
824
+ --blok-swatch-ring-hover: rgba(255, 255, 255, 0.15);
825
+ --blok-swatch-ring-active: rgba(255, 255, 255, 0.35);
826
+
827
+ /* Marker colors — dark theme */
828
+ --blok-color-gray-text: #9b9b9b;
829
+ --blok-color-gray-bg: #2f2f2f;
830
+ --blok-color-brown-text: #c59177;
831
+ --blok-color-brown-bg: #452a1c;
832
+ --blok-color-orange-text: #dc8c47;
833
+ --blok-color-orange-bg: #4d2f14;
834
+ --blok-color-yellow-text: #d4ab49;
835
+ --blok-color-yellow-bg: #544012;
836
+ --blok-color-green-text: #5db184;
837
+ --blok-color-green-bg: #1e432f;
838
+ --blok-color-teal-text: #5cbcb3;
839
+ --blok-color-teal-bg: #1b4642;
840
+ --blok-color-blue-text: #5c9fcc;
841
+ --blok-color-blue-bg: #123a54;
842
+ --blok-color-purple-text: #a67dca;
843
+ --blok-color-purple-bg: #341d49;
844
+ --blok-color-pink-text: #d45e99;
845
+ --blok-color-pink-bg: #4b1b33;
846
+ --blok-color-red-text: #dd5e5a;
847
+ --blok-color-red-bg: #4e1a18;
746
848
  }
747
849
  }
748
850
 
@@ -759,14 +861,15 @@
759
861
  --blok-link: #529cca;
760
862
  --blok-line-gray: #37352f;
761
863
  --blok-tooltip-bg: #191918;
762
- --blok-tooltip-font: #ffffff;
864
+ --blok-tooltip-font: #e8e6e3;
763
865
  --blok-icon-active-bg: rgba(35, 131, 226, 0.2);
764
866
  --blok-icon-active-text: #529cca;
765
- --blok-text-primary: #f0efed;
867
+ --blok-text-primary: #e2e0dc;
766
868
  --blok-text-secondary: #a39e98;
767
- --blok-popover-border: rgba(255, 255, 255, 0.07);
869
+ --blok-popover-border: rgba(255, 255, 255, 0.14);
768
870
  --blok-popover-shadow: rgba(0, 0, 0, 0.6);
769
871
  --blok-popover-bg: #252525;
872
+ --blok-popover-box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 4px 24px rgba(0, 0, 0, 0.5), 0 16px 40px -8px rgba(0, 0, 0, 0.4);
770
873
  --blok-popover-border-icon: #37352f;
771
874
  --blok-popover-border-icon-disabled: #2f2d29;
772
875
  --blok-item-focus-bg: rgba(35, 131, 226, 0.2);
@@ -785,12 +888,134 @@
785
888
  --blok-notify-btn-cancel-text: #a39e98;
786
889
  --blok-notify-btn-confirm-bg: #34c992;
787
890
  --blok-mobile-border: rgba(255, 255, 255, 0.07);
788
- --blok-search-input-bg: #2f2f2f;
789
- --blok-search-input-border: rgba(255, 255, 255, 0.07);
891
+ --blok-search-input-bg: #363636;
892
+ --blok-search-input-border: rgba(255, 255, 255, 0.20);
790
893
  --blok-search-input-focus-border: rgba(35, 131, 226, 0.5);
791
894
  --blok-link-input-border: #37352f;
792
895
  --blok-popover-icon-bg: rgba(255, 255, 255, 0.08);
793
896
  --blok-popover-icon-active-bg: rgba(35, 131, 226, 0.15);
897
+
898
+ /* Table */
899
+ --blok-table-border: #3e3e3d;
900
+ --blok-table-heading-bg: #272725;
901
+ --blok-table-grip-outline: rgba(255, 255, 255, 0.12);
902
+ --blok-table-drag-source-bg: rgba(255, 255, 255, 0.07);
903
+
904
+ /* Toggle switch */
905
+ --blok-toggle-off-bg: #3f3f46;
906
+ --blok-toggle-on-bg: #e4e4e7;
907
+ --blok-toggle-thumb-on-bg: #252525;
908
+
909
+ /* Checklist */
910
+ --blok-checklist-border: rgba(255, 255, 255, 0.22);
911
+ --blok-checklist-shadow: rgba(0, 0, 0, 0.3);
912
+ --blok-checklist-hover-ring: rgba(82, 156, 202, 0.2);
913
+
914
+ /* Color picker swatch */
915
+ --blok-swatch-neutral-bg: #3a3a38;
916
+ --blok-swatch-ring-hover: rgba(255, 255, 255, 0.15);
917
+ --blok-swatch-ring-active: rgba(255, 255, 255, 0.35);
918
+
919
+ /* Marker colors — dark theme */
920
+ --blok-color-gray-text: #9b9b9b;
921
+ --blok-color-gray-bg: #2f2f2f;
922
+ --blok-color-brown-text: #c59177;
923
+ --blok-color-brown-bg: #452a1c;
924
+ --blok-color-orange-text: #dc8c47;
925
+ --blok-color-orange-bg: #4d2f14;
926
+ --blok-color-yellow-text: #d4ab49;
927
+ --blok-color-yellow-bg: #544012;
928
+ --blok-color-green-text: #5db184;
929
+ --blok-color-green-bg: #1e432f;
930
+ --blok-color-teal-text: #5cbcb3;
931
+ --blok-color-teal-bg: #1b4642;
932
+ --blok-color-blue-text: #5c9fcc;
933
+ --blok-color-blue-bg: #123a54;
934
+ --blok-color-purple-text: #a67dca;
935
+ --blok-color-purple-bg: #341d49;
936
+ --blok-color-pink-text: #d45e99;
937
+ --blok-color-pink-bg: #4b1b33;
938
+ --blok-color-red-text: #dd5e5a;
939
+ --blok-color-red-bg: #4e1a18;
940
+ }
941
+
942
+ /* ─── Checklist checkbox — custom styled ────────────────── */
943
+ /*
944
+ appearance: none removes native browser rendering entirely, eliminating the
945
+ bright-white native checkbox that causes harsh contrast in dark mode.
946
+ We rebuild the full visual state in CSS for consistent cross-browser rendering.
947
+ */
948
+
949
+ @keyframes blok-checkbox-pop {
950
+ 0% { transform: scale(1); }
951
+ 35% { transform: scale(1.18); }
952
+ 65% { transform: scale(0.9); }
953
+ 82% { transform: scale(1.07); }
954
+ 100% { transform: scale(1); }
955
+ }
956
+
957
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"] {
958
+ appearance: none;
959
+ -webkit-appearance: none;
960
+ flex-shrink: 0;
961
+ border-radius: 5px;
962
+ border: 2px solid var(--blok-checklist-border);
963
+ background-color: transparent;
964
+ box-shadow: inset 0 1px 2px var(--blok-checklist-shadow);
965
+ transition: background-color 150ms ease, border-color 150ms ease, transform 150ms ease, box-shadow 150ms ease;
966
+ }
967
+
968
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:checked {
969
+ background-color: var(--blok-active-icon);
970
+ border-color: var(--blok-active-icon);
971
+ box-shadow: none;
972
+ animation: blok-checkbox-pop 280ms linear;
973
+ /* SVG checkmark — white path on accent-blue background */
974
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 10 10' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.5 5L4 7.5L8.5 2.5' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
975
+ background-size: 10px 10px;
976
+ background-position: center;
977
+ background-repeat: no-repeat;
978
+ }
979
+
980
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:not(:disabled):not(:checked):hover {
981
+ border-color: var(--blok-active-icon);
982
+ transform: scale(1.06);
983
+ box-shadow: 0 0 0 3px var(--blok-checklist-hover-ring), inset 0 1px 2px var(--blok-checklist-shadow);
984
+ }
985
+
986
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:not(:disabled):checked:hover {
987
+ box-shadow: 0 0 0 3px var(--blok-checklist-hover-ring);
988
+ }
989
+
990
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:disabled:not(:checked) {
991
+ opacity: 0.5;
992
+ }
993
+
994
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:disabled:checked {
995
+ background-color: var(--blok-checklist-readonly-fill);
996
+ border-color: var(--blok-checklist-readonly-fill);
997
+ box-shadow: none;
998
+ animation: none;
999
+ }
1000
+
1001
+ /*
1002
+ The global input:focus-visible rule above suppresses all input focus rings.
1003
+ Checkboxes need a visible focus ring for keyboard accessibility — restore it.
1004
+ */
1005
+ [data-blok-interface] [data-list-style="checklist"] input[type="checkbox"]:focus-visible {
1006
+ outline: 2px solid var(--blok-active-icon);
1007
+ outline-offset: 2px;
1008
+ }
1009
+
1010
+ /* Dark mode: more muted checked text so completed items feel visually "done" */
1011
+ @media (prefers-color-scheme: dark) {
1012
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-list-style="checklist"] [data-checked="true"] {
1013
+ opacity: 0.45;
1014
+ }
1015
+ }
1016
+
1017
+ [data-blok-theme="dark"] [data-blok-interface] [data-list-style="checklist"] [data-checked="true"] {
1018
+ opacity: 0.45;
794
1019
  }
795
1020
 
796
1021
  /*
@@ -963,7 +1188,8 @@
963
1188
  */
964
1189
  [data-blok-table-heading] [data-blok-table-cell],
965
1190
  [data-blok-table-heading-col] {
966
- @apply font-semibold bg-gray-50;
1191
+ @apply font-semibold;
1192
+ background-color: var(--blok-table-heading-bg);
967
1193
  }
968
1194
 
969
1195
  /**
@@ -974,6 +1200,74 @@
974
1200
  @apply opacity-100;
975
1201
  }
976
1202
 
1203
+ /**
1204
+ * Dark theme overrides for table UI chrome.
1205
+ * Grip handles, add-row/col pills, and scroll haze all use hardcoded
1206
+ * Tailwind light-gray/white classes that are too bright on dark backgrounds.
1207
+ * Rules are written for both dark entry points (media query + explicit attr).
1208
+ */
1209
+ @media (prefers-color-scheme: dark) {
1210
+ /* Grip pills — collapsed/idle state */
1211
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-blok-table-grip]:not(.bg-gray-200):not(.bg-blue-500) {
1212
+ background-color: #4a4a4a;
1213
+ }
1214
+ /* Grip pills — hover-expanded state */
1215
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-blok-table-grip].bg-gray-200 {
1216
+ background-color: #555554;
1217
+ }
1218
+ /* Grip dot SVG (exclude active/blue state — text-white must win there) */
1219
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-blok-table-grip]:not(.bg-blue-500) svg {
1220
+ color: white;
1221
+ }
1222
+ /* Add row/col pill: border + subtle rest-state fill */
1223
+ :root:not([data-blok-theme="light"]) [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]) .border-gray-300 {
1224
+ border-color: rgba(255, 255, 255, 0.17);
1225
+ background-color: #2c2c2b;
1226
+ }
1227
+ /* Add row/col pill hover background */
1228
+ :root:not([data-blok-theme="light"]) [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]):hover .border-gray-300 {
1229
+ background-color: #2e2e2d;
1230
+ }
1231
+ /* Add row/col icon color */
1232
+ :root:not([data-blok-theme="light"]) [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]) .border-gray-300 svg {
1233
+ color: #9e9e9d;
1234
+ }
1235
+ /* Scroll haze: dark background gradient instead of white */
1236
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-blok-table-haze="left"] {
1237
+ background-image: linear-gradient(to right, var(--blok-dark), transparent);
1238
+ }
1239
+ :root:not([data-blok-theme="light"]) [data-blok-interface] [data-blok-table-haze="right"] {
1240
+ background-image: linear-gradient(to left, var(--blok-dark), transparent);
1241
+ }
1242
+ }
1243
+
1244
+ /* Explicit dark theme attribute — same overrides */
1245
+ [data-blok-theme="dark"] [data-blok-interface] [data-blok-table-grip]:not(.bg-gray-200):not(.bg-blue-500) {
1246
+ background-color: #4a4a4a;
1247
+ }
1248
+ [data-blok-theme="dark"] [data-blok-interface] [data-blok-table-grip].bg-gray-200 {
1249
+ background-color: #555554;
1250
+ }
1251
+ [data-blok-theme="dark"] [data-blok-interface] [data-blok-table-grip]:not(.bg-blue-500) svg {
1252
+ color: white;
1253
+ }
1254
+ [data-blok-theme="dark"] [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]) .border-gray-300 {
1255
+ border-color: rgba(255, 255, 255, 0.17);
1256
+ background-color: #2c2c2b;
1257
+ }
1258
+ [data-blok-theme="dark"] [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]):hover .border-gray-300 {
1259
+ background-color: #2e2e2d;
1260
+ }
1261
+ [data-blok-theme="dark"] [data-blok-interface] :is([data-blok-table-add-row], [data-blok-table-add-col]) .border-gray-300 svg {
1262
+ color: #9e9e9d;
1263
+ }
1264
+ [data-blok-theme="dark"] [data-blok-interface] [data-blok-table-haze="left"] {
1265
+ background-image: linear-gradient(to right, var(--blok-dark), transparent);
1266
+ }
1267
+ [data-blok-theme="dark"] [data-blok-interface] [data-blok-table-haze="right"] {
1268
+ background-image: linear-gradient(to left, var(--blok-dark), transparent);
1269
+ }
1270
+
977
1271
  /**
978
1272
  * Slash search input appearance
979
1273
  * When the user types "/" to open the toolbox, the contenteditable
@@ -981,7 +1275,7 @@
981
1275
  */
982
1276
  [data-blok-slash-search],
983
1277
  [data-blok-slash-search]:focus-visible {
984
- @apply bg-search-input-bg rounded-[4px] transition-colors duration-150 max-w-[240px];
1278
+ @apply bg-search-input-bg rounded-md transition-colors duration-150 w-fit max-w-[240px] px-2;
985
1279
  }
986
1280
 
987
1281
  [data-blok-slash-search]::after {
@@ -989,6 +1283,10 @@
989
1283
  @apply text-gray-text font-medium text-base pointer-events-none;
990
1284
  }
991
1285
 
1286
+ [data-blok-slash-search]::before {
1287
+ content: none !important;
1288
+ }
1289
+
992
1290
  /**
993
1291
  * Custom scrollbar for popover items
994
1292
  */
@@ -702,7 +702,7 @@ export class Header implements BlockTool {
702
702
  * @returns The arrow element
703
703
  */
704
704
  private buildArrow(): HTMLElement {
705
- const arrow = buildArrow(this._isOpen, this.readOnly ? null : () => this.toggleOpen(), {}, {
705
+ const arrow = buildArrow(this._isOpen, () => this.toggleOpen(), {}, {
706
706
  collapse: this.api.i18n.t('tools.toggle.ariaLabelCollapse'),
707
707
  expand: this.api.i18n.t('tools.toggle.ariaLabelExpand'),
708
708
  });
@@ -971,10 +971,10 @@ export class Header implements BlockTool {
971
971
  icon: string;
972
972
  styles: string;
973
973
  }> = [
974
- { number: 1, tag: 'H1', nameKey: 'tools.header.heading1', name: 'Heading 1', icon: IconH1, styles: 'text-4xl font-bold mt-8 mb-1' },
975
- { number: 2, tag: 'H2', nameKey: 'tools.header.heading2', name: 'Heading 2', icon: IconH2, styles: 'text-3xl font-semibold mt-6 mb-px' },
976
- { number: 3, tag: 'H3', nameKey: 'tools.header.heading3', name: 'Heading 3', icon: IconH3, styles: 'text-2xl font-semibold mt-4 mb-px' },
977
- { number: 4, tag: 'H4', nameKey: 'tools.header.heading4', name: 'Heading 4', icon: IconH4, styles: 'text-xl font-semibold mt-3 mb-px' },
974
+ { number: 1, tag: 'H1', nameKey: 'tools.header.heading1', name: 'Heading 1', icon: IconH1, styles: 'text-3xl font-semibold mt-8 mb-px' },
975
+ { number: 2, tag: 'H2', nameKey: 'tools.header.heading2', name: 'Heading 2', icon: IconH2, styles: 'text-2xl font-semibold mt-[26px] mb-px' },
976
+ { number: 3, tag: 'H3', nameKey: 'tools.header.heading3', name: 'Heading 3', icon: IconH3, styles: 'text-xl font-semibold mt-5 mb-px' },
977
+ { number: 4, tag: 'H4', nameKey: 'tools.header.heading4', name: 'Heading 4', icon: IconH4, styles: 'text-lg font-semibold mt-3 mb-px' },
978
978
  { number: 5, tag: 'H5', nameKey: 'tools.header.heading5', name: 'Heading 5', icon: IconH5, styles: 'text-base font-semibold mt-3 mb-px' },
979
979
  { number: 6, tag: 'H6', nameKey: 'tools.header.heading6', name: 'Heading 6', icon: IconH6, styles: 'text-sm font-semibold mt-3 mb-px' },
980
980
  ];
@@ -3,9 +3,16 @@
3
3
  */
4
4
 
5
5
  /**
6
- * Indentation padding per depth level in pixels
6
+ * Indentation padding per depth level in pixels (unordered/checklist)
7
+ * Matches Notion's bullet indent: 1.7em × 16px = 27.2px
7
8
  */
8
- export const INDENT_PER_LEVEL = 24;
9
+ export const INDENT_PER_LEVEL = 27;
10
+
11
+ /**
12
+ * Indentation padding per depth level in pixels (ordered lists)
13
+ * Matches Notion's number indent: 1.6em × 16px = 25.6px
14
+ */
15
+ export const ORDERED_INDENT_PER_LEVEL = 26;
9
16
 
10
17
  /**
11
18
  * Base styles for list wrapper
@@ -17,7 +24,7 @@ export const BASE_STYLES = 'outline-hidden py-[3px] mt-[2px] mb-px';
17
24
  /**
18
25
  * Styles for standard list items (unordered, ordered)
19
26
  */
20
- export const ITEM_STYLES = 'outline-hidden pl-0.5 leading-[1.6em]';
27
+ export const ITEM_STYLES = 'outline-hidden pl-0.5 leading-[1.5] items-center';
21
28
 
22
29
  /**
23
30
  * Styles for checklist items
@@ -27,7 +34,7 @@ export const CHECKLIST_ITEM_STYLES = 'flex items-start pl-0.5';
27
34
  /**
28
35
  * Styles for checkbox input
29
36
  */
30
- export const CHECKBOX_STYLES = 'mt-1 w-4 mr-2 h-4 cursor-pointer accent-current';
37
+ export const CHECKBOX_STYLES = 'mt-0.5 w-5 mr-2 h-5 cursor-pointer accent-current';
31
38
 
32
39
  /**
33
40
  * Placeholder translation key
@@ -16,6 +16,11 @@ export interface DepthValidationOptions {
16
16
  blockIndex: number;
17
17
  /** Current depth */
18
18
  currentDepth: number;
19
+ /**
20
+ * When true, skip depth-promotion heuristics (shouldMatchNext/Prev).
21
+ * Used during group drag-drops where the group's relative structure is preserved.
22
+ */
23
+ skipDepthPromotion?: boolean;
19
24
  }
20
25
 
21
26
  /**
@@ -63,7 +68,7 @@ export class ListDepthValidator {
63
68
  * @returns The target depth for the dropped item
64
69
  */
65
70
  getTargetDepthForMove(options: DepthValidationOptions): number {
66
- const { blockIndex, currentDepth } = options;
71
+ const { blockIndex, currentDepth, skipDepthPromotion } = options;
67
72
  const maxAllowedDepth = this.getMaxAllowedDepth(blockIndex);
68
73
 
69
74
  // If current depth exceeds max, cap it
@@ -71,6 +76,13 @@ export class ListDepthValidator {
71
76
  return maxAllowedDepth;
72
77
  }
73
78
 
79
+ // Depth-promotion heuristics are skipped for group moves: the group preserves
80
+ // its own relative structure, so we should not promote a block's depth to match
81
+ // its new neighbours (which may be members of the same group).
82
+ if (skipDepthPromotion) {
83
+ return currentDepth;
84
+ }
85
+
74
86
  // Check if we're inserting before a list item (next block)
75
87
  const nextBlock = this.blocks.getBlockByIndex(blockIndex + 1);
76
88
  const nextIsListItem = nextBlock && nextBlock.name === TOOL_NAME;
@@ -11,6 +11,7 @@ import { twMerge } from '../../components/utils/tw';
11
11
 
12
12
  import {
13
13
  INDENT_PER_LEVEL,
14
+ ORDERED_INDENT_PER_LEVEL,
14
15
  BASE_STYLES,
15
16
  ITEM_STYLES,
16
17
  CHECKLIST_ITEM_STYLES,
@@ -162,10 +163,11 @@ export const buildStandardContent = (context: DOMBuilderContext): HTMLElement =>
162
163
  item.style.fontSize = itemSize;
163
164
  }
164
165
 
165
- // Apply indentation based on depth
166
+ // Apply indentation based on depth (ordered lists use smaller indent to match Notion)
166
167
  const depth = data.depth ?? 0;
167
168
  if (depth > 0) {
168
- item.style.marginLeft = `${depth * INDENT_PER_LEVEL}px`;
169
+ const indent = data.style === 'ordered' ? ORDERED_INDENT_PER_LEVEL : INDENT_PER_LEVEL;
170
+ item.style.marginLeft = `${depth * indent}px`;
169
171
  }
170
172
 
171
173
  // Create marker element
@@ -224,7 +226,7 @@ export const buildChecklistContent = (context: DOMBuilderContext): HTMLElement =
224
226
 
225
227
  const content = document.createElement('div');
226
228
  content.className = twMerge(
227
- 'flex-1 outline-hidden leading-[1.6em]',
229
+ 'flex-1 outline-hidden leading-[1.5]',
228
230
  data.checked ? 'line-through opacity-60' : '',
229
231
  ...PLACEHOLDER_CLASSES
230
232
  );
@@ -149,7 +149,7 @@ export class ListItem implements BlockTool {
149
149
  }
150
150
 
151
151
  public moved(event: MoveEvent): void {
152
- this.validateAndAdjustDepthAfterMove(event.toIndex);
152
+ this.validateAndAdjustDepthAfterMove(event.toIndex, event.isGroupMove);
153
153
  this.updateMarkersAfterPositionChange();
154
154
  }
155
155
 
@@ -162,11 +162,12 @@ export class ListItem implements BlockTool {
162
162
  this.updateSiblingListMarkers();
163
163
  }
164
164
 
165
- private validateAndAdjustDepthAfterMove(newIndex: number): void {
165
+ private validateAndAdjustDepthAfterMove(newIndex: number, skipDepthPromotion?: boolean): void {
166
166
  const currentDepth = this.getDepth();
167
167
  const targetDepth = this.depthValidator.getTargetDepthForMove({
168
168
  blockIndex: newIndex,
169
169
  currentDepth,
170
+ skipDepthPromotion,
170
171
  });
171
172
 
172
173
  if (currentDepth !== targetDepth) {
@@ -199,9 +199,9 @@ export class Paragraph implements BlockTool {
199
199
  * Paragraph wrapper styling classes using Tailwind.
200
200
  */
201
201
  private static readonly WRAPPER_CLASSES = [
202
- 'leading-[1.6em]',
202
+ 'leading-[1.5]',
203
203
  'outline-hidden',
204
- 'mt-[2px]',
204
+ 'mt-px',
205
205
  'mb-px',
206
206
  '[&>p:first-of-type]:mt-0',
207
207
  '[&>p:last-of-type]:mb-0',
@@ -20,12 +20,12 @@ export const createCellColorPicker = (options: CellColorPickerOptions): CellColo
20
20
  const handle = createColorPicker({
21
21
  i18n: options.i18n,
22
22
  testIdPrefix: 'cell-color',
23
- defaultModeIndex: 1,
24
23
  modes: [
25
24
  { key: 'textColor', labelKey: 'tools.marker.textColor', presetField: 'text' },
26
25
  { key: 'backgroundColor', labelKey: 'tools.marker.background', presetField: 'bg' },
27
26
  ],
28
27
  onColorSelect: (color, modeKey) => {
28
+ handle.setActiveColor(color, modeKey);
29
29
  options.onColorSelect(color, modeKey as CellColorMode);
30
30
  },
31
31
  });
@@ -682,7 +682,7 @@ export class TableCellSelection {
682
682
  pill.style.height = `${PILL_HEIGHT}px`;
683
683
  pill.style.pointerEvents = 'auto';
684
684
  pill.style.transform = 'translate(-50%, -50%)';
685
- pill.style.outline = '2px solid white';
685
+ pill.style.outline = '2px solid var(--blok-table-grip-outline, transparent)';
686
686
 
687
687
  const svg = createGripDotsSvg('vertical');
688
688
 
@@ -740,7 +740,6 @@ export class TableCellSelection {
740
740
  element: pickerElement,
741
741
  }],
742
742
  isFlippable: false,
743
- width: '12.5rem',
744
743
  },
745
744
  });
746
745
  }
@@ -7,7 +7,7 @@ export const ROW_ATTR = 'data-blok-table-row';
7
7
  export const CELL_ATTR = 'data-blok-table-cell';
8
8
 
9
9
  export const BORDER_WIDTH = 1;
10
- const BORDER_STYLE = `${BORDER_WIDTH}px solid #d1d5db`;
10
+ const BORDER_STYLE = `${BORDER_WIDTH}px solid var(--blok-table-border)`;
11
11
 
12
12
  const ROW_CLASSES = [
13
13
  'flex',
@@ -18,7 +18,7 @@ const CELL_CLASSES = [
18
18
  'px-2',
19
19
  'min-h-[2em]',
20
20
  'outline-hidden',
21
- 'leading-normal',
21
+ 'leading-none',
22
22
  'text-sm',
23
23
  'cursor-text',
24
24
  ];
@@ -1,5 +1,17 @@
1
1
  export const GRIP_HOVER_SIZE = 16;
2
2
 
3
+ /**
4
+ * Sets only the size dimension of a grip pill (height for col, width for row).
5
+ * Use this in full-state resets where the bg class is already handled by a className overwrite.
6
+ */
7
+ export const setGripPillSize = (grip: HTMLElement, type: 'col' | 'row', size: number): void => {
8
+ if (type === 'col') {
9
+ Object.assign(grip.style, { height: `${size}px` });
10
+ } else {
11
+ Object.assign(grip.style, { width: `${size}px` });
12
+ }
13
+ };
14
+
3
15
  /**
4
16
  * Dot positions for vertical layout (2 cols × 3 rows) — used by row grips.
5
17
  */
@@ -78,11 +90,7 @@ export const expandGrip = (grip: HTMLElement, type: 'col' | 'row'): void => {
78
90
  * Column grips shrink height; row grips shrink width.
79
91
  */
80
92
  export const collapseGrip = (grip: HTMLElement, type: 'col' | 'row', pillSize: number): void => {
81
- if (type === 'col') {
82
- Object.assign(grip.style, { height: `${pillSize}px` });
83
- } else {
84
- Object.assign(grip.style, { width: `${pillSize}px` });
85
- }
93
+ setGripPillSize(grip, type, pillSize);
86
94
 
87
95
  grip.classList.remove('bg-gray-200');
88
96
  grip.classList.add('bg-gray-300');