0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-01 09:31:26 -05:00

Merge pull request #1095 from penpot/text-editor-improvements

Text editor improvements
This commit is contained in:
Andrey Antukh 2021-07-26 11:02:29 +02:00 committed by GitHub
commit 44f96dd6a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 390 additions and 79 deletions

View file

@ -64,7 +64,8 @@
(defn ^boolean is-text-node?
[node]
(string? (:text node)))
(and (string? (:text node))
(not= (:text node) "")))
(defn ^boolean is-paragraph-node?
[node]

View file

@ -207,7 +207,16 @@
:workspace-file
:workspace-project
:workspace-media-objects
:workspace-persistence))
:workspace-persistence
:workspace-local
:workspace-data
:workspace-editor-state
:workspace-undo
:current-file-id
:current-project-id
:workspace-layout
:workspace-libraries
:workspace-presence))
ptk/WatchEvent
(watch [_ _ _]
@ -242,9 +251,10 @@
(update [_ state]
(let [page-id (or page-id (get-in state [:workspace-data :pages 0]))
local (-> (:workspace-local state)
(dissoc :edition)
(dissoc :edit-path)
(dissoc :selected))]
(dissoc
:edition
:edit-path
:selected))]
(-> state
(assoc-in [:workspace-cache page-id] local)
(dissoc :current-page-id :workspace-local :trimmed-page :workspace-drawing))))))

View file

@ -75,11 +75,14 @@
(ptk/reify ::initialize-editor-state
ptk/UpdateEvent
(update [_ state]
(update-in state [:workspace-editor-state id]
(fn [_]
(ted/create-editor-state
(some->> content ted/import-content)
decorator))))
(let [text-state (some->> content ted/import-content)
attrs (get-in state [:workspace-local :defaults :font])
editor (cond-> (ted/create-editor-state text-state decorator)
(and (nil? content) (some? attrs))
(ted/update-editor-current-block-data attrs))]
(-> state
(assoc-in [:workspace-editor-state id] editor))))
ptk/WatchEvent
(watch [_ _ stream]
@ -101,6 +104,13 @@
(update [_ state]
(d/update-in-when state [:workspace-editor-state id] ted/editor-select-all))))
(defn cursor-to-end
[{:keys [id] :as shape}]
(ptk/reify ::cursor-to-end
ptk/UpdateEvent
(update [_ state]
(d/update-in-when state [:workspace-editor-state id] ted/cursor-to-end))))
;; --- Helpers
(defn- shape-current-values
@ -193,8 +203,11 @@
(when-not (some? (get-in state [:workspace-editor-state id]))
(let [objects (wsh/lookup-page-objects state)
shape (get objects id)
update-node? (fn [node]
(or (txt/is-text-node? node)
(txt/is-paragraph-node? node)))
update-fn #(update-shape % txt/is-text-node? attrs/merge attrs)
update-fn #(update-shape % update-node? attrs/merge attrs)
shape-ids (cond (= (:type shape) :text) [id]
(= (:type shape) :group) (cp/get-children id objects))]
(rx/of (dch/update-shapes shape-ids update-fn)))))))
@ -309,3 +322,14 @@
(rx/race resize-batch change-page)
(rx/of #(dissoc % ::handling-texts))))
(rx/empty))))))
(defn save-font
[data]
(ptk/reify ::save-font
ptk/UpdateEvent
(update [_ state]
(let [multiple? (->> data vals (d/seek #(= % :multiple)))]
(cond-> state
(not multiple?)
(assoc-in [:workspace-local :defaults :font] data))))))

View file

@ -14,19 +14,23 @@
[app.util.timers :as timers]
[rumext.alpha :as mf]))
(mf/defc editable-select [{:keys [value type options class on-change placeholder]}]
(mf/defc editable-select [{:keys [value type options class on-change placeholder on-blur]}]
(let [state (mf/use-state {:id (uuid/next)
:is-open? false
:current-value value
:top nil
:left nil
:bottom nil})
emit-blur? (mf/use-ref nil)
open-dropdown #(swap! state assoc :is-open? true)
close-dropdown #(swap! state assoc :is-open? false)
select-item (fn [value]
(fn [_]
(swap! state assoc :current-value value)
(when on-change (on-change value))))
(when on-change (on-change value))
(when on-blur (on-blur))))
as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item]))
@ -55,21 +59,38 @@
assoc
:left left
:top top
:bottom bottom))))))]
:bottom bottom))))))
handle-focus
(mf/use-callback
(fn []
(mf/set-ref-val! emit-blur? false)))
handle-blur
(mf/use-callback
(fn []
(mf/set-ref-val! emit-blur? true)
(timers/schedule
200
(fn []
(when (and on-blur (mf/ref-val emit-blur?)) (on-blur))))))]
(mf/use-effect
(mf/deps value)
#(reset! state {:current-value value}))
(mf/deps value (:current-value @state))
#(when (not= value (:current-value @state))
(reset! state {:current-value value})))
(mf/use-effect
(mf/deps options)
#(reset! state {:is-open? false
:current-value value}))
(mf/deps (:is-open? @state))
(fn []
(mf/set-ref-val! emit-blur? (not (:is-open? @state)))))
[:div.editable-select {:class class
:ref on-node-load}
[:input.input-text {:value (or (-> @state :current-value value->label) "")
:on-change handle-change-input
:on-focus handle-focus
:on-blur handle-blur
:placeholder placeholder
:type type}]
[:span.dropdown-button {:on-click open-dropdown} i/arrow-down]

View file

@ -47,8 +47,8 @@
text-align (:text-align data "start")
grow-type (:grow-type shape)
base #js {:fontSize (str (:font-size txt/default-text-attrs) "px")
:lineHeight (:line-height txt/default-text-attrs)
base #js {:fontSize (str (:font-size data (:font-size txt/default-text-attrs)) "px")
:lineHeight (:line-height data (:line-height txt/default-text-attrs))
:margin "inherit"}]
(cond-> base
(some? line-height) (obj/set! "lineHeight" line-height)

View file

@ -7,6 +7,7 @@
(ns app.main.ui.workspace.shapes.text.editor
(:require
["draft-js" :as draft]
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.text :as txt]
[app.main.data.workspace :as dw]
@ -32,7 +33,7 @@
(let [bprops (obj/get props "blockProps")
data (obj/get bprops "data")
style (sts/generate-paragraph-styles (obj/get bprops "shape")
(obj/get bprops "data"))
(obj/get bprops "data"))
dir (:text-direction data "auto")]
@ -56,12 +57,35 @@
:shape shape}}
nil)))
(defn styles-fn [styles content]
(if (= (.getText content) "")
(-> (.getData content)
(.toJS)
(js->clj :keywordize-keys true)
(sts/generate-text-styles))
(-> (txt/styles-to-attrs styles)
(sts/generate-text-styles))))
(def default-decorator
(ted/create-decorator "PENPOT_SELECTION" selection-component))
(def empty-editor-state
(ted/create-editor-state nil default-decorator))
(defn get-content-changes
[old-state state]
(let [old-blocks (js->clj (.toJS (.getBlockMap (.getCurrentContent ^js old-state)))
:keywordize-keys false)
new-blocks (js->clj (.toJS (.getBlockMap (.getCurrentContent ^js state)))
:keywordize-keys false)]
(->> old-blocks
(d/mapm
(fn [bkey bstate]
{:old (get bstate "text")
:new (get-in new-blocks [bkey "text"])}))
(filter #(contains? new-blocks (first %)))
(into {}))))
(mf/defc text-shape-edit-html
{::mf/wrap [mf/memo]
::mf/wrap-props false
@ -106,10 +130,35 @@
(fn [_]
(reset! blured false)))
prev-value (mf/use-ref state)
;; Effect that keeps updated the `prev-value` reference
_ (mf/use-effect
(mf/deps state)
#(mf/set-ref-val! prev-value state))
handle-change
(mf/use-callback
(fn [state]
(let [old-state (mf/ref-val prev-value)]
(if (and (some? state) (some? old-state))
(let [block-states (get-content-changes old-state state)
block-to-add-styles
(->> block-states
(filter
(fn [[_ v]]
(and (not= (:old v) (:new v))
(= (:old v) ""))))
(mapv first))]
(ted/apply-block-styles-to-content state block-to-add-styles))
state))))
on-change
(mf/use-callback
(fn [val]
(let [val (if (true? @blured)
(let [val (handle-change val)
val (if (true? @blured)
(ted/add-editor-blur-selection val)
(ted/remove-editor-blur-selection val))]
(st/emit! (dwt/update-editor-state shape val)))))
@ -124,9 +173,17 @@
handle-return
(mf/use-callback
(fn [_ state]
(st/emit! (dwt/update-editor-state shape (ted/editor-split-block state)))
(let [state (ted/editor-split-block state)
state (handle-change state)]
(st/emit! (dwt/update-editor-state shape state)))
"handled"))
]
on-click
(mf/use-callback
(fn [event]
(when (dom/class? (dom/get-target event) "DraftEditor-root")
(st/emit! (dwt/cursor-to-end shape)))
(st/emit! (dwt/focus-editor))))]
(mf/use-layout-effect on-mount)
@ -135,7 +192,7 @@
:style {:cursor cur/text
:width (:width shape)
:height (:height shape)}
:on-click (st/emitf (dwt/focus-editor))
:on-click on-click
:class (dom/classnames
:align-top (= (:vertical-align content "top") "top")
:align-center (= (:vertical-align content) "center")
@ -146,9 +203,7 @@
:on-focus on-focus
:handle-return handle-return
:strip-pasted-styles true
:custom-style-fn (fn [styles _]
(-> (txt/styles-to-attrs styles)
(sts/generate-text-styles)))
:custom-style-fn styles-fn
:block-renderer-fn #(render-block % shape)
:ref on-editor
:editor-state state}]]))

View file

@ -20,6 +20,7 @@
[app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry typography-options]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.timers :as tm]
[cuerdas.core :as str]
[rumext.alpha :as mf]))
@ -80,11 +81,12 @@
(def attrs (d/concat #{} shape-attrs root-attrs paragraph-attrs text-attrs))
(mf/defc text-align-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [{:keys [text-align]} values
handle-change
(fn [_ new-align]
(on-change {:text-align new-align}))]
(on-change {:text-align new-align})
(when (some? on-blur) (on-blur)))]
;; --- Align
[:div.align-icons
@ -110,10 +112,12 @@
i/text-align-justify]]))
(mf/defc text-direction-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [direction (:text-direction values)
handle-change (fn [_ val]
(on-change {:text-direction val}))]
handle-change
(fn [_ val]
(on-change {:text-direction val})
(when (some? on-blur) (on-blur)))]
;; --- Align
[:div.align-icons
[:span.tooltip.tooltip-bottom-left
@ -128,12 +132,13 @@
i/text-direction-rtl]]))
(mf/defc vertical-align
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [{:keys [vertical-align]} values
vertical-align (or vertical-align "top")
handle-change
(fn [_ new-align]
(on-change {:vertical-align new-align}))]
(on-change {:vertical-align new-align})
(when (some? on-blur) (on-blur)))]
[:div.align-icons
[:span.tooltip.tooltip-bottom-left
@ -153,11 +158,12 @@
i/align-bottom]]))
(mf/defc grow-options
[{:keys [ids values] :as props}]
[{:keys [ids values on-blur] :as props}]
(let [grow-type (:grow-type values)
handle-change-grow
(fn [_ grow-type]
(st/emit! (dch/update-shapes ids #(assoc % :grow-type grow-type))))]
(st/emit! (dch/update-shapes ids #(assoc % :grow-type grow-type)))
(when (some? on-blur) (on-blur)))]
[:div.align-icons
[:span.tooltip.tooltip-bottom
@ -177,11 +183,12 @@
i/auto-height]]))
(mf/defc text-decoration-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [text-decoration (or (:text-decoration values) "none")
handle-change
(fn [_ type]
(on-change {:text-decoration type}))]
(on-change {:text-decoration type})
(when (some? on-blur) (on-blur)))]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.none")
@ -220,7 +227,11 @@
emit-update!
(mf/use-callback
(mf/deps values)
(fn [id attrs]
(st/emit! (dwt/save-font (-> (merge txt/default-text-attrs values attrs)
(select-keys text-attrs))))
(let [attrs (select-keys attrs root-attrs)]
(when-not (empty? attrs)
(st/emit! (dwt/update-root-attrs {:id id :attrs attrs}))))
@ -235,7 +246,7 @@
on-change
(mf/use-callback
(mf/deps ids)
(mf/deps ids emit-update!)
(fn [attrs]
(run! #(emit-update! % attrs) ids)))
@ -287,7 +298,15 @@
opts #js {:ids ids
:values values
:on-change on-change}]
:on-change on-change
:on-blur
(fn []
(tm/schedule
100
(fn []
(when (not= "INPUT" (-> (dom/get-active) (dom/get-tag-name)))
(let [node (dom/get-element-by-class "public-DraftEditor-content")]
(dom/focus! node))))))}]
[:div.element-set
[:div.element-set-title

View file

@ -230,7 +230,7 @@
:current? (= (:id font) (:id selected))}])))
(mf/defc font-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [{:keys [font-id font-size font-variant-id]} values
font-id (or font-id (:font-id txt/default-text-attrs))
@ -271,18 +271,26 @@
:font-family (:family font)
:font-variant-id new-variant-id
:font-weight (:weight variant)
:font-style (:style variant)}))))
:font-style (:style variant)})
(dom/blur! (dom/get-target event)))))
on-font-select
(mf/use-callback
(mf/deps change-font)
(fn [font*]
(when (not= font font*)
(change-font (:id font*)))))
(change-font (:id font*)))
(when (some? on-blur)
(on-blur))))
on-font-selector-close
(mf/use-callback
#(reset! open-selector? false))]
(fn []
(reset! open-selector? false)
(when (some? on-blur)
(on-blur))
))]
[:*
(when @open-selector?
@ -314,12 +322,14 @@
:options size-options
:type "number"
:placeholder "--"
:on-change on-font-size-change}])
:on-change on-font-size-change
:on-blur on-blur}])
[:select.input-select.variant-option
{:disabled (= font-id :multiple)
:value (attr->string font-variant-id)
:on-change on-font-variant-change}
:on-change on-font-variant-change
:on-blur on-blur}
(when (or (= font-id :multiple) (= font-variant-id :multiple))
[:option {:value ""} "--"])
(for [variant (:variants font)]
@ -329,7 +339,7 @@
(mf/defc spacing-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [{:keys [line-height
letter-spacing]} values
@ -353,7 +363,8 @@
:max "200"
:value (attr->string line-height)
:placeholder (tr "settings.multiple")
:on-change #(handle-change % :line-height)}]]
:on-change #(handle-change % :line-height)
:on-blur on-blur}]]
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
@ -366,18 +377,21 @@
:max "200"
:value (attr->string letter-spacing)
:placeholder (tr "settings.multiple")
:on-change #(handle-change % :letter-spacing)}]]]))
:on-change #(handle-change % :letter-spacing)
:on-blur on-blur}]]]))
(mf/defc text-transform-options
[{:keys [values on-change] :as props}]
[{:keys [values on-change on-blur] :as props}]
(let [text-transform (or (:text-transform values) "none")
handle-change
(fn [_ type]
(on-change {:text-transform type}))]
(on-change {:text-transform type})
(when (some? on-blur) (on-blur)))]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform))
:focus #(dom/prevent-default %)
:on-click #(handle-change % "none")}
i/minus]
[:span.tooltip.tooltip-bottom
@ -397,11 +411,12 @@
i/titlecase]]))
(mf/defc typography-options
[{:keys [ids editor values on-change]}]
[{:keys [ids editor values on-change on-blur]}]
(let [opts #js {:editor editor
:ids ids
:values values
:on-change on-change}]
:on-change on-change
:on-blur on-blur}]
[:div.element-set-content
[:> font-options opts]
[:div.row-flex

View file

@ -11,7 +11,7 @@
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-menu]]
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-menu fill-attrs]]
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]]
@ -42,6 +42,7 @@
text-values (d/merge
(select-keys shape [:grow-type])
(select-keys shape fill-attrs)
(dwt/current-root-values
{:shape shape
:attrs root-attrs})

View file

@ -223,11 +223,13 @@
(defn focus!
[node]
(.focus node))
(when (some? node)
(.focus node)))
(defn blur!
[node]
(.blur node))
(when (some? node)
(.blur node)))
(defn fullscreen?
[]
@ -291,8 +293,11 @@
(defn get-user-agent []
(.-userAgent globals/navigator))
(defn get-active []
(.-activeElement globals/document))
(defn active? [node]
(= (.-activeElement globals/document) node))
(= (get-active) node))
(defn get-data [^js node ^string attr]
(.getAttribute node (str "data-" attr)))

View file

@ -70,8 +70,11 @@
(defn get-editor-current-inline-styles
[state]
(-> (.getCurrentInlineStyle ^js state)
(txt/styles-to-attrs)))
(if (impl/isCurrentEmpty state)
(let [block (impl/getCurrentBlock state)]
(get-editor-block-data block))
(-> (.getCurrentInlineStyle ^js state)
(txt/styles-to-attrs))))
(defn update-editor-current-block-data
[state attrs]
@ -79,7 +82,18 @@
(defn update-editor-current-inline-styles
[state attrs]
(impl/applyInlineStyle state (txt/attrs-to-styles attrs)))
(let [update-blocks
(fn [state block-key]
(if (empty? (impl/getBlockContent state block-key))
(impl/updateBlockData state block-key (clj->js attrs))
(let [attrs (-> (impl/getInlineStyle state block-key 0)
(txt/styles-to-attrs))]
(impl/updateBlockData state block-key (clj->js attrs)))))
state (impl/applyInlineStyle state (txt/attrs-to-styles attrs))
selected (impl/getSelectedBlocks state)]
(reduce update-blocks state selected)))
(defn editor-split-block
[state]
@ -92,3 +106,23 @@
(defn remove-editor-blur-selection
[state]
(impl/removeBlurSelectionEntity state))
(defn cursor-to-end
[state]
(impl/cursorToEnd state))
(defn apply-block-styles-to-content
[state blocks]
(if (empty? blocks)
state
(let [selection (impl/getSelection state)
redfn
(fn [state bkey]
(let [attrs (-> (impl/getBlockData state bkey)
(js->clj :keywordize-keys true))]
(-> state
(impl/selectBlock bkey)
(impl/applyInlineStyle (txt/attrs-to-styles attrs)))))]
(as-> state $
(reduce redfn $ blocks)
(impl/setSelection $ selection)))))

View file

@ -22,6 +22,23 @@ function isDefined(v) {
return v !== undefined && v !== null;
}
function mergeBlockData(block, newData) {
let data = block.getData();
for (let key of Object.keys(newData)) {
const oldVal = data.get(key);
if (oldVal === newData[key]) {
data = data.delete(key);
} else {
data = data.set(key, newData[key]);
}
}
return block.mergeDeep({
data: data
});
}
export function createEditorState(content, decorator) {
if (content === null) {
return EditorState.createEmpty(decorator);
@ -56,6 +73,18 @@ function getSelectAllSelection(state) {
});
}
function getCursorInEndPosition(state) {
const content = state.getCurrentContent();
const lastBlock = content.getBlockMap().last();
return new SelectionState({
"anchorKey": lastBlock.getKey(),
"anchorOffset": lastBlock.getLength(),
"focusKey": lastBlock.getKey(),
"focusOffset": lastBlock.getLength()
});
}
export function selectAll(state) {
return EditorState.forceSelection(state, getSelectAllSelection(state));
}
@ -83,43 +112,38 @@ export function updateCurrentBlockData(state, attrs) {
let content = state.getCurrentContent();
content = modifySelectedBlocks(content, selection, (block) => {
let data = block.getData();
for (let key of Object.keys(attrs)) {
const oldVal = data.get(key);
if (oldVal === attrs[key]) {
data = data.delete(key);
} else {
data = data.set(key, attrs[key]);
}
}
return block.merge({
data: data
});
return mergeBlockData(block, attrs);
});
return EditorState.push(state, content, "change-block-data");
}
export function applyInlineStyle(state, styles) {
const selection = state.getSelection();
const userSelection = state.getSelection();
let selection = userSelection;
if (selection.isCollapsed()) {
selection = getSelectAllSelection(state);
}
let result = state;
let content = null;
for (let style of styles) {
const [p, k, v] = style.split("$$$");
const prefix = [p, k, ""].join("$$$");
content = state.getCurrentContent();
content = result.getCurrentContent();
content = removeInlineStylePrefix(content, selection, prefix);
if (v !== "z:null") {
content = Modifier.applyInlineStyle(content, selection, style);
}
state = EditorState.push(state, content, "change-inline-style");
result = EditorState.push(result, content, "change-inline-style");
}
return state;
return EditorState.acceptSelection(result, userSelection);
}
export function splitBlockPreservingData(state) {
@ -209,3 +233,105 @@ export function removeInlineStylePrefix(contentState, selectionState, stylePrefi
return block.set("characterList", chars);
});
}
export function cursorToEnd(state) {
const newSelection = getCursorInEndPosition(state);
const selection = state.getSelection();
let content = state.getCurrentContent();
content = Modifier.applyEntity(content, newSelection, null);
state = EditorState.forceSelection(state, newSelection);
state = EditorState.push(state, content, "apply-entity");
return state;
}
export function isCurrentEmpty(state) {
const selection = state.getSelection();
if (!selection.isCollapsed()) {
return false;
}
const blockKey = selection.getStartKey();
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getText() === "";
}
/*
Returns the block keys between a selection
*/
export function getSelectedBlocks(state) {
const selection = state.getSelection();
const startKey = selection.getStartKey();
const endKey = selection.getEndKey();
const content = state.getCurrentContent();
const result = [ startKey ];
let currentKey = startKey;
while (currentKey !== endKey) {
const currentBlock = content.getBlockAfter(currentKey);
currentKey = currentBlock.getKey();
result.push(currentKey);
}
return result;
}
export function getBlockContent(state, blockKey) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getText();
}
export function getBlockData(state, blockKey) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block && block.getData().toJS();
}
export function updateBlockData(state, blockKey, data) {
const userSelection = state.getSelection();
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
const newBlock = mergeBlockData(block, data);
const blockData = newBlock.getData();
const newContent = Modifier.setBlockData(
state.getCurrentContent(),
SelectionState.createEmpty(blockKey),
blockData
);
const result = EditorState.push(state, newContent, 'change-block-data');
return EditorState.acceptSelection(result, userSelection);
}
export function getSelection(state) {
return state.getSelection();
}
export function setSelection(state, selection) {
return EditorState.acceptSelection(state, selection);
}
export function selectBlock(state, blockKey) {
const block = state.getCurrentContent().getBlockForKey(blockKey);
const length = block.getText().length;
const selection = SelectionState.createEmpty(blockKey).merge({
focusOffset: length
});
return EditorState.acceptSelection(state, selection);
}
export function getInlineStyle(state, blockKey, offset) {
const content = state.getCurrentContent();
const block = content.getBlockForKey(blockKey);
return block.getInlineStyleAt(offset).toJS();
}