diff --git a/demo/stories/css-variables/CSSVariables.stories.tsx b/demo/stories/css-variables/CSSVariables.stories.tsx index 89a7faf1..5964f1ac 100644 --- a/demo/stories/css-variables/CSSVariables.stories.tsx +++ b/demo/stories/css-variables/CSSVariables.stories.tsx @@ -28,6 +28,30 @@ export const Story: StoryObj = { control: {type: 'text'}, description: 'Editor contents padding', }, + '--g-selection-bg-color': { + control: {type: 'text'}, + description: 'Editor selection bg color', + }, + '--g-selection-border': { + control: {type: 'text'}, + description: 'Editor selection border', + }, + '--g-selection-border-radius': { + control: {type: 'text'}, + description: 'Editor selection border radius', + }, + '--g-selection-outline': { + control: {type: 'text'}, + description: 'Editor selection outline', + }, + '--g-selection-background': { + control: {type: 'text'}, + description: 'Editor selection background', + }, + '--g-selection-box-shadow': { + control: {type: 'text'}, + description: 'Editor selection box-shadow', + }, }, }; Story.storyName = 'Custom CSS Variables'; diff --git a/docs/how-to-customize-the-editor.md b/docs/how-to-customize-the-editor.md index 3ae64cc7..69d93484 100644 --- a/docs/how-to-customize-the-editor.md +++ b/docs/how-to-customize-the-editor.md @@ -3,6 +3,7 @@ ## How to customize the editor You can use CSS variables to make editor contents fit your own needs +### Elements styles | **Variable** | **Description** | **CSS Property Type** | **Default** | | :---: | :---: | :---: | :---: | | `--g-md-toolbar-padding` | Toolbar padding | padding | 0px | @@ -11,3 +12,11 @@ You can use CSS variables to make editor contents fit your own needs | `--g-md-toolbar-sticky-offset` | Toolbar offset in sticky mode | top | 0px | | `--g-md-toolbar-sticky-border` | Toolbar border in sticky mode | border | 1px solid var(--g-color-line-generic-solid) | | `--g-md-editor-padding` | Editor contents padding | padding | 0px | + +### Selection styles +| **Variable** | **Description** | **CSS Property Type** | **Default** | +| `--g-selection-border` | Editor selection border | border | none | +| `--g-selection-border-radius` | Editor selection border radius | border-radius | 6px | +| `--g-selection-outline` | Editor selection outline | outline | none | +| `--g-selection-background` | Editor selection background | background | #e6e6e6 | +| `--g-selection-box-shadow` | Editor selection box shadow | box-shadow | none | diff --git a/src/extensions/base/BaseStyles/index.scss b/src/extensions/base/BaseStyles/index.scss index 233c8fa3..37d99ba5 100644 --- a/src/extensions/base/BaseStyles/index.scss +++ b/src/extensions/base/BaseStyles/index.scss @@ -1,28 +1,80 @@ -@use '../../../../node_modules/prosemirror-view/style/prosemirror'; +$active-node-default-indent-top: calc(-1 * var(--g-spacing-1)); +$active-node-default-indent-bottom: calc(-1 * var(--g-spacing-1)); +$active-node-default-indent-left: calc(-1 * var(--g-spacing-2)); +$active-node-default-indent-right: calc(-1 * var(--g-spacing-2)); -// Make outline appear only if ProseMirror is focused +$active-node-selector: '.pm-node-selected'; +$basic-elements: h1, h2, h3, h4, h5, h6, p, ul, ol, span, pre, '*[data-html], .g-md-checkbox'; -.ProseMirror-selectednode { - outline: none; +$default-selection-border: none; +$default-selection-border-radius: var(--g-border-radius-m); +$default-selection-outline: none; +// TODO: CHANGE TO TOKEN +$default-selection-background: #e6e6e6; +$default-selection-box-shadow: none; + +$default-li-marker-width: var(--g-spacing-4); + +@mixin node-props { + position: relative; + + border: $default-selection-border; + border-radius: $default-selection-border-radius; + outline: $default-selection-outline; + background: var(--g-selection-background, $default-selection-background); + box-shadow: $default-selection-box-shadow; } -.li.ProseMirror-selectednode:after { - border: none; +@mixin selection-props { + border: var(--g-selection-border, $default-selection-border); + border-radius: var(--g-selection-border-radius, $default-selection-border-radius); + outline: var(--g-selection-outline, $default-selection-outline); + background: var(--g-selection-background, $default-selection-background); + box-shadow: var(--g-selection-box-shadow, $default-selection-box-shadow); } -.g-md-editor.ProseMirror-focused { - .ProseMirror-selectednode { - outline: 2px solid #8cf; - } +[class].g-md-editor { + @each $basic-element in $basic-elements { + & #{$basic-element}#{$active-node-selector} { + @include node-props; + + &::after { + position: absolute; + z-index: -1; + inset: $active-node-default-indent-top + $active-node-default-indent-right + $active-node-default-indent-bottom + $active-node-default-indent-left; + + content: ''; - li.ProseMirror-selectednode:after { - border: 2px solid #8cf; + @include selection-props; + } + + & img { + mix-blend-mode: multiply; + } + } } -} -.g-md-editor.ProseMirror, -.g-md-editor .ProseMirror { - &:focus { - outline: none; + & li#{$active-node-selector} { + @include node-props; + + &::marker { + @include selection-props; + } + + &::after { + position: absolute; + z-index: -1; + inset: $active-node-default-indent-top + $active-node-default-indent-right + $active-node-default-indent-bottom + calc($active-node-default-indent-left - max(var(--li-marker-width, 0), $default-li-marker-width)); + + content: ''; + + @include selection-props; + } } } diff --git a/src/extensions/markdown/Lists/ListsSpecs/index.ts b/src/extensions/markdown/Lists/ListsSpecs/index.ts index 734e8b9f..c8118fe8 100644 --- a/src/extensions/markdown/Lists/ListsSpecs/index.ts +++ b/src/extensions/markdown/Lists/ListsSpecs/index.ts @@ -17,6 +17,27 @@ export const ListsSpecs: ExtensionAuto = (builder) => { spec: schemaSpecs[ListNode.ListItem], toMd: serializerTokens[ListNode.ListItem], fromMd: {tokenSpec: parserTokens[ListNode.ListItem]}, + // @ts-expect-error + view: () => (node, view, getPos) => { + return { + update: (node_) => { + node = node_; + + const pos = getPos(); + if (pos === undefined) return false; + + const dom = view.domAtPos(pos + 1).node as HTMLElement; + + const markerWidth = Math.max( + Math.floor(parseFloat(getComputedStyle(dom, '::marker').width)), + ); + + dom.style.setProperty('--li-marker-width', `${markerWidth}px`); + + return true; + }, + }; + }, })) .addNode(ListNode.BulletList, () => ({ spec: schemaSpecs[ListNode.BulletList],