UNPKG

text-editor-studio-ts

Version:

A powerful mobile-responsive rich text editor built with Lexical and React

202 lines (201 loc) 7.48 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { useMemo, useState, useRef, useCallback, useEffect } from "react"; import { l } from "./LexicalCollaborationContext.prod-_XIRbBSl.js"; import { o, u, q as $isPollNode, B as Button, s as createPollOption, I as Input } from "./index-BwW17RmP.js"; import { mergeRegister } from "@lexical/utils"; import { $getSelection, $isNodeSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, KEY_DELETE_COMMAND, KEY_BACKSPACE_COMMAND, $getNodeByKey } from "lexical"; function getTotalVotes(options) { return options.reduce((totalVotes, next) => { return totalVotes + next.votes.length; }, 0); } function PollOptionComponent({ option, index, options, totalVotes, withPollNode }) { const { clientID } = l(); const checkboxRef = useRef(null); const votesArray = option.votes; const checkedIndex = votesArray.indexOf(clientID); const checked = checkedIndex !== -1; const votes = votesArray.length; const text = option.text; return /* @__PURE__ */ jsxs("div", { className: "mb-2.5 flex flex-row items-center", children: [ /* @__PURE__ */ jsx( "div", { className: `relative mr-2.5 flex h-[22px] w-[22px] rounded-md border border-border-system-global-secondary ${checked ? 'border-border-presentation-action-primary bg-background-presentation-action-primary after:pointer-events-none after:absolute after:left-2 after:top-1 after:m-0 after:block after:h-[9px] after:w-[5px] after:rotate-45 after:cursor-pointer after:border-b-2 after:border-r-2 after:border-solid after:border-white after:content-[""]' : ""}`, children: /* @__PURE__ */ jsx( "input", { ref: checkboxRef, className: "absolute block h-full w-full cursor-pointer border-0 opacity-0", type: "checkbox", onChange: () => { withPollNode((node) => { node.toggleVote(option, clientID); }); }, checked } ) } ), /* @__PURE__ */ jsxs("div", { className: "relative flex flex-[10px] cursor-pointer overflow-hidden rounded-md border border-border-presentation-action-primary", children: [ /* @__PURE__ */ jsx( "div", { className: "transition-width absolute left-0 top-0 z-0 h-full bg-background-presentation-state-success-primary duration-1000 ease-in-out", style: { width: `${votes === 0 ? 0 : votes / totalVotes * 100}%` } } ), /* @__PURE__ */ jsx("span", { className: "absolute right-4 top-1.5 text-xs text-content-presentation-action-primary", children: votes > 0 && (votes === 1 ? "1 vote" : `${votes} votes`) }), /* @__PURE__ */ jsx( Input, { type: "text", value: text, onChange: (e) => { const target = e.target; const value = target.value; const selectionStart = target.selectionStart; const selectionEnd = target.selectionEnd; withPollNode( (node) => { node.setOptionText(option, value); }, () => { target.selectionStart = selectionStart; target.selectionEnd = selectionEnd; } ); }, placeholder: `Option ${index + 1}` } ) ] }), /* @__PURE__ */ jsx( "button", { disabled: options.length < 3, className: `relative z-0 ml-1.5 flex h-7 w-7 cursor-pointer rounded-md border-0 bg-transparent bg-[position:6px_6px] bg-no-repeat opacity-30 before:absolute before:left-[13px] before:top-1.5 before:block before:h-[15px] before:w-0.5 before:-rotate-45 before:bg-border-system-global-secondary before:content-[''] after:absolute after:left-[13px] after:top-1.5 after:block after:h-[15px] after:w-0.5 after:rotate-45 after:bg-border-system-global-secondary after:content-[''] hover:bg-background-system-body-primary-presentation-action-hover hover:opacity-100 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:opacity-30`, "aria-label": "Remove", onClick: () => { withPollNode((node) => { node.deleteOption(option); }); } } ) ] }); } function PollComponent({ question, options, nodeKey }) { const [editor] = o(); const totalVotes = useMemo(() => getTotalVotes(options), [options]); const [isSelected, setSelected, clearSelection] = u(nodeKey); const [selection, setSelection] = useState(null); const ref = useRef(null); const $onDelete = useCallback( (payload) => { const deleteSelection = $getSelection(); if (isSelected && $isNodeSelection(deleteSelection)) { const event = payload; event.preventDefault(); editor.update(() => { deleteSelection.getNodes().forEach((node) => { if ($isPollNode(node)) { node.remove(); } }); }); } return false; }, [editor, isSelected] ); useEffect(() => { return mergeRegister( editor.registerUpdateListener(({ editorState }) => { setSelection(editorState.read(() => $getSelection())); }), editor.registerCommand( CLICK_COMMAND, (payload) => { const event = payload; if (event.target === ref.current) { if (!event.shiftKey) { clearSelection(); } setSelected(!isSelected); return true; } return false; }, COMMAND_PRIORITY_LOW ), editor.registerCommand( KEY_DELETE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW ), editor.registerCommand( KEY_BACKSPACE_COMMAND, $onDelete, COMMAND_PRIORITY_LOW ) ); }, [clearSelection, editor, isSelected, nodeKey, $onDelete, setSelected]); const withPollNode = (cb, onUpdate) => { editor.update( () => { const node = $getNodeByKey(nodeKey); if ($isPollNode(node)) { cb(node); } }, { onUpdate } ); }; const addOption = () => { withPollNode((node) => { node.addOption(createPollOption()); }); }; const isFocused = $isNodeSelection(selection) && isSelected; return /* @__PURE__ */ jsx( "div", { className: `min-w-[400px] max-w-[600px] cursor-pointer select-none rounded-lg border border-border-system-global-secondary bg-background-system-body-primary ${isFocused ? " outline-2 outline-primary" : ""}`, ref, children: /* @__PURE__ */ jsxs("div", { className: "m-4 cursor-default", children: [ /* @__PURE__ */ jsx("h2", { className: "m-0 mb-4 text-center text-lg text-content-system-global-secondary", children: question }), options.map((option, index) => { const key = option.uid; return /* @__PURE__ */ jsx( PollOptionComponent, { withPollNode, option, index, options, totalVotes }, key ); }), /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(Button, { onClick: addOption, size: "M", children: "Add Option" }) }) ] }) } ); } export { PollComponent as default }; //# sourceMappingURL=poll-component-DwrVM5FN.js.map