@haklex/rich-ext-poll 0.5.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/README.md +69 -0
- package/dist/PollDataContext.d.ts +11 -0
- package/dist/PollDataContext.d.ts.map +1 -0
- package/dist/PollEditDecorator.d.ts +13 -0
- package/dist/PollEditDecorator.d.ts.map +1 -0
- package/dist/PollNode-Cd9E_bOt.js +186 -0
- package/dist/PollRenderer.d.ts +3 -0
- package/dist/PollRenderer.d.ts.map +1 -0
- package/dist/augment.d.ts +9 -0
- package/dist/augment.d.ts.map +1 -0
- package/dist/edit-CUuz0vB8.js +372 -0
- package/dist/edit.d.ts +6 -0
- package/dist/edit.d.ts.map +1 -0
- package/dist/edit.mjs +2 -0
- package/dist/extractPolls.d.ts +4 -0
- package/dist/extractPolls.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +5 -0
- package/dist/node-D-hnG4zJ.js +47 -0
- package/dist/node.d.ts +8 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.mjs +3 -0
- package/dist/nodes/PollEditNode.d.ts +14 -0
- package/dist/nodes/PollEditNode.d.ts.map +1 -0
- package/dist/nodes/PollNode.d.ts +52 -0
- package/dist/nodes/PollNode.d.ts.map +1 -0
- package/dist/poll-edit.css.d.ts +43 -0
- package/dist/poll-edit.css.d.ts.map +1 -0
- package/dist/poll.css.d.ts +43 -0
- package/dist/poll.css.d.ts.map +1 -0
- package/dist/renderer-CJEY_O80.js +257 -0
- package/dist/renderer.d.ts +8 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.mjs +2 -0
- package/dist/rich-ext-poll.css +2 -0
- package/dist/slot.d.ts +8 -0
- package/dist/slot.d.ts.map +1 -0
- package/dist/static.d.ts +3 -0
- package/dist/static.d.ts.map +1 -0
- package/dist/static.mjs +4 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @haklex/rich-ext-poll
|
|
2
|
+
|
|
3
|
+
Reader-facing vote/poll widget extension. Single- or multi-choice polls with optional close time and result-visibility policy.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @haklex/rich-ext-poll
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Register nodes
|
|
14
|
+
|
|
15
|
+
Editor (read + write):
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { pollEditNodes } from '@haklex/rich-ext-poll'
|
|
19
|
+
|
|
20
|
+
const editorConfig = { nodes: [...pollEditNodes] }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Static / read-only:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { pollNodes } from '@haklex/rich-ext-poll/static'
|
|
27
|
+
|
|
28
|
+
const staticConfig = { nodes: [...pollNodes] }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Provide a data adapter
|
|
32
|
+
|
|
33
|
+
The renderer reads tallies and submits votes through a `PollDataAdapter`. Wrap the renderer with `PollDataProvider`:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { PollDataProvider } from '@haklex/rich-ext-poll'
|
|
37
|
+
|
|
38
|
+
<PollDataProvider adapter={myAdapter} initialStates={initial}>
|
|
39
|
+
<RichRenderer value={state} />
|
|
40
|
+
</PollDataProvider>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Without an adapter the renderer falls back to a static read-only display.
|
|
44
|
+
|
|
45
|
+
### Extract poll metadata for SSR
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { extractPolls } from '@haklex/rich-ext-poll/static'
|
|
49
|
+
|
|
50
|
+
const polls = extractPolls(serializedEditorState)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Stylesheet
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import '@haklex/rich-ext-poll/style.css'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Sub-path Exports
|
|
60
|
+
|
|
61
|
+
| Path | Description |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `@haklex/rich-ext-poll` | Full exports (edit + static) |
|
|
64
|
+
| `@haklex/rich-ext-poll/static` | Static-only (no editor UI deps) |
|
|
65
|
+
| `@haklex/rich-ext-poll/style.css` | Stylesheet |
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { PollDataAdapter, PollState } from './types';
|
|
3
|
+
export interface PollDataProviderProps {
|
|
4
|
+
adapter: PollDataAdapter;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
initialStates?: Record<string, PollState>;
|
|
7
|
+
}
|
|
8
|
+
export declare function PollDataProvider({ adapter, initialStates, children }: PollDataProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function usePollDataAdapter(): PollDataAdapter | null;
|
|
10
|
+
export declare function useInitialPollState(pollId: string): PollState | undefined;
|
|
11
|
+
//# sourceMappingURL=PollDataContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollDataContext.d.ts","sourceRoot":"","sources":["../src/PollDataContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAY1D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAC3C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,qBAAqB,2CAM3F;AAED,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAE3D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAEzE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PollMode, PollOption, PollShowResults } from './types';
|
|
2
|
+
interface PollEditDecoratorProps {
|
|
3
|
+
closeAt?: string;
|
|
4
|
+
mode: PollMode;
|
|
5
|
+
nodeKey: string;
|
|
6
|
+
options: PollOption[];
|
|
7
|
+
pollId: string;
|
|
8
|
+
question: string;
|
|
9
|
+
showResults?: PollShowResults;
|
|
10
|
+
}
|
|
11
|
+
export declare function PollEditDecorator({ closeAt, mode, nodeKey, options, pollId, question, showResults, }: PollEditDecoratorProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=PollEditDecorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollEditDecorator.d.ts","sourceRoot":"","sources":["../src/PollEditDecorator.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAUrE,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AA8DD,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,EACN,QAAQ,EACR,WAAW,GACZ,EAAE,sBAAsB,2CAiNxB"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { DecoratorNode } from "lexical";
|
|
2
|
+
import { customAlphabet } from "nanoid";
|
|
3
|
+
import { createRendererDecoration } from "@haklex/rich-editor/renderers";
|
|
4
|
+
//#region src/slot.ts
|
|
5
|
+
/**
|
|
6
|
+
* RendererConfig slot key for `@haklex/rich-ext-poll`.
|
|
7
|
+
*
|
|
8
|
+
* Override modules should reference this constant instead of the bare string
|
|
9
|
+
* literal so renames stay searchable across the workspace.
|
|
10
|
+
*/
|
|
11
|
+
var POLL_NODE_KEY = "Poll";
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/typeof.js
|
|
14
|
+
function _typeof(o) {
|
|
15
|
+
"@babel/helpers - typeof";
|
|
16
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
17
|
+
return typeof o;
|
|
18
|
+
} : function(o) {
|
|
19
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
20
|
+
}, _typeof(o);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPrimitive.js
|
|
24
|
+
function toPrimitive(t, r) {
|
|
25
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
26
|
+
var e = t[Symbol.toPrimitive];
|
|
27
|
+
if (void 0 !== e) {
|
|
28
|
+
var i = e.call(t, r || "default");
|
|
29
|
+
if ("object" != _typeof(i)) return i;
|
|
30
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
31
|
+
}
|
|
32
|
+
return ("string" === r ? String : Number)(t);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPropertyKey.js
|
|
36
|
+
function toPropertyKey(t) {
|
|
37
|
+
var i = toPrimitive(t, "string");
|
|
38
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/defineProperty.js
|
|
42
|
+
function _defineProperty(e, r, t) {
|
|
43
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
44
|
+
value: t,
|
|
45
|
+
enumerable: !0,
|
|
46
|
+
configurable: !0,
|
|
47
|
+
writable: !0
|
|
48
|
+
}) : e[r] = t, e;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/nodes/PollNode.ts
|
|
52
|
+
var idAlphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
53
|
+
var makePollIdSuffix = customAlphabet(idAlphabet, 10);
|
|
54
|
+
var makeOptionIdSuffix = customAlphabet(idAlphabet, 6);
|
|
55
|
+
function createPollId() {
|
|
56
|
+
return `p_${makePollIdSuffix()}`;
|
|
57
|
+
}
|
|
58
|
+
function createOptionId() {
|
|
59
|
+
return `o_${makeOptionIdSuffix()}`;
|
|
60
|
+
}
|
|
61
|
+
var PollNode = class PollNode extends DecoratorNode {
|
|
62
|
+
static getType() {
|
|
63
|
+
return "poll";
|
|
64
|
+
}
|
|
65
|
+
static clone(node) {
|
|
66
|
+
return new PollNode({
|
|
67
|
+
pollId: node.__pollId,
|
|
68
|
+
question: node.__question,
|
|
69
|
+
options: node.__options,
|
|
70
|
+
mode: node.__mode,
|
|
71
|
+
closeAt: node.__closeAt,
|
|
72
|
+
showResults: node.__showResults
|
|
73
|
+
}, node.__key);
|
|
74
|
+
}
|
|
75
|
+
constructor(payload = {}, key) {
|
|
76
|
+
super(key);
|
|
77
|
+
_defineProperty(this, "__pollId", void 0);
|
|
78
|
+
_defineProperty(this, "__question", void 0);
|
|
79
|
+
_defineProperty(this, "__options", void 0);
|
|
80
|
+
_defineProperty(this, "__mode", void 0);
|
|
81
|
+
_defineProperty(this, "__closeAt", void 0);
|
|
82
|
+
_defineProperty(this, "__showResults", void 0);
|
|
83
|
+
this.__pollId = payload.pollId ?? createPollId();
|
|
84
|
+
this.__question = payload.question ?? "";
|
|
85
|
+
this.__options = payload.options && payload.options.length > 0 ? payload.options : [{
|
|
86
|
+
id: createOptionId(),
|
|
87
|
+
label: ""
|
|
88
|
+
}, {
|
|
89
|
+
id: createOptionId(),
|
|
90
|
+
label: ""
|
|
91
|
+
}];
|
|
92
|
+
this.__mode = payload.mode ?? "single";
|
|
93
|
+
this.__closeAt = payload.closeAt;
|
|
94
|
+
this.__showResults = payload.showResults;
|
|
95
|
+
}
|
|
96
|
+
createDOM(_config) {
|
|
97
|
+
const div = document.createElement("div");
|
|
98
|
+
div.className = "rich-poll-wrapper";
|
|
99
|
+
return div;
|
|
100
|
+
}
|
|
101
|
+
updateDOM() {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
isInline() {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
getPollId() {
|
|
108
|
+
return this.getLatest().__pollId;
|
|
109
|
+
}
|
|
110
|
+
getQuestion() {
|
|
111
|
+
return this.getLatest().__question;
|
|
112
|
+
}
|
|
113
|
+
setQuestion(question) {
|
|
114
|
+
const writable = this.getWritable();
|
|
115
|
+
writable.__question = question;
|
|
116
|
+
}
|
|
117
|
+
getOptions() {
|
|
118
|
+
return this.getLatest().__options;
|
|
119
|
+
}
|
|
120
|
+
setOptions(options) {
|
|
121
|
+
const writable = this.getWritable();
|
|
122
|
+
writable.__options = options;
|
|
123
|
+
}
|
|
124
|
+
getMode() {
|
|
125
|
+
return this.getLatest().__mode;
|
|
126
|
+
}
|
|
127
|
+
setMode(mode) {
|
|
128
|
+
const writable = this.getWritable();
|
|
129
|
+
writable.__mode = mode;
|
|
130
|
+
}
|
|
131
|
+
getCloseAt() {
|
|
132
|
+
return this.getLatest().__closeAt;
|
|
133
|
+
}
|
|
134
|
+
setCloseAt(closeAt) {
|
|
135
|
+
const writable = this.getWritable();
|
|
136
|
+
writable.__closeAt = closeAt;
|
|
137
|
+
}
|
|
138
|
+
getShowResults() {
|
|
139
|
+
return this.getLatest().__showResults;
|
|
140
|
+
}
|
|
141
|
+
setShowResults(showResults) {
|
|
142
|
+
const writable = this.getWritable();
|
|
143
|
+
writable.__showResults = showResults;
|
|
144
|
+
}
|
|
145
|
+
static importJSON(serializedNode) {
|
|
146
|
+
return new PollNode({
|
|
147
|
+
pollId: serializedNode.pollId,
|
|
148
|
+
question: serializedNode.question,
|
|
149
|
+
options: serializedNode.options,
|
|
150
|
+
mode: serializedNode.mode,
|
|
151
|
+
closeAt: serializedNode.closeAt,
|
|
152
|
+
showResults: serializedNode.showResults
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
exportJSON() {
|
|
156
|
+
return {
|
|
157
|
+
...super.exportJSON(),
|
|
158
|
+
type: "poll",
|
|
159
|
+
pollId: this.__pollId,
|
|
160
|
+
question: this.__question,
|
|
161
|
+
options: this.__options,
|
|
162
|
+
mode: this.__mode,
|
|
163
|
+
...this.__closeAt ? { closeAt: this.__closeAt } : {},
|
|
164
|
+
...this.__showResults ? { showResults: this.__showResults } : {},
|
|
165
|
+
version: 1
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
decorate(_editor, _config) {
|
|
169
|
+
return createRendererDecoration(POLL_NODE_KEY, void 0, {
|
|
170
|
+
pollId: this.__pollId,
|
|
171
|
+
question: this.__question,
|
|
172
|
+
options: this.__options,
|
|
173
|
+
mode: this.__mode,
|
|
174
|
+
closeAt: this.__closeAt,
|
|
175
|
+
showResults: this.__showResults
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
function $createPollNode(payload) {
|
|
180
|
+
return new PollNode(payload);
|
|
181
|
+
}
|
|
182
|
+
function $isPollNode(node) {
|
|
183
|
+
return node instanceof PollNode;
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
export { createPollId as a, createOptionId as i, $isPollNode as n, _defineProperty as o, PollNode as r, POLL_NODE_KEY as s, $createPollNode as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollRenderer.d.ts","sourceRoot":"","sources":["../src/PollRenderer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,iBAAiB,EAGlB,MAAM,SAAS,CAAC;AAgPjB,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,2CAIpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"augment.d.ts","sourceRoot":"","sources":["../src/augment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,cAAc;QACtB,IAAI,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;KACzC;CACF;AAED,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { n as $isPollNode, o as _defineProperty, r as PollNode } from "./PollNode-Cd9E_bOt.js";
|
|
3
|
+
import { $getNodeByKey, $insertNodes } from "lexical";
|
|
4
|
+
import { CalendarClock, ChevronDown, ChevronUp, Plus, Vote, X } from "lucide-react";
|
|
5
|
+
import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
6
|
+
import { SegmentedControl, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@haklex/rich-editor-ui";
|
|
7
|
+
import { customAlphabet } from "nanoid";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/poll-edit.css.ts
|
|
10
|
+
var pollEditClasses = {
|
|
11
|
+
container: "jr1ls70",
|
|
12
|
+
meta: "jr1ls71",
|
|
13
|
+
question: "jr1ls72",
|
|
14
|
+
optionList: "jr1ls73",
|
|
15
|
+
optionRow: "jr1ls74",
|
|
16
|
+
reorderColumn: "jr1ls75",
|
|
17
|
+
reorderButton: "jr1ls76",
|
|
18
|
+
optionInput: "jr1ls77",
|
|
19
|
+
removeButton: "jr1ls78",
|
|
20
|
+
addOption: "jr1ls79",
|
|
21
|
+
advancedSummary: "jr1ls7a",
|
|
22
|
+
advancedGrid: "jr1ls7b",
|
|
23
|
+
advancedLabel: "jr1ls7c",
|
|
24
|
+
dateTimeField: "jr1ls7d",
|
|
25
|
+
dateTimeIcon: "jr1ls7e",
|
|
26
|
+
dateTimeInput: "jr1ls7f",
|
|
27
|
+
selectTrigger: "jr1ls7g",
|
|
28
|
+
selectContent: "jr1ls7h",
|
|
29
|
+
modeRow: "jr1ls7i",
|
|
30
|
+
modeControl: "jr1ls7j"
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region ../../node_modules/.pnpm/@lexical+react@0.44.0_react-dom@19.2.5_react@19.2.5__react@19.2.5_yjs@13.6.29/node_modules/@lexical/react/LexicalComposerContext.prod.mjs
|
|
34
|
+
/**
|
|
35
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
36
|
+
*
|
|
37
|
+
* This source code is licensed under the MIT license found in the
|
|
38
|
+
* LICENSE file in the root directory of this source tree.
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
var r = createContext(null);
|
|
42
|
+
function o() {
|
|
43
|
+
const n = useContext(r);
|
|
44
|
+
return n ?? function(n, ...e) {
|
|
45
|
+
const r = new URL("https://lexical.dev/docs/error"), t = new URLSearchParams();
|
|
46
|
+
t.append("code", n);
|
|
47
|
+
for (const n of e) t.append("v", n);
|
|
48
|
+
throw r.search = t.toString(), Error(`Minified Lexical error #${n}; visit ${r.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`);
|
|
49
|
+
}(8), n;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/PollEditDecorator.tsx
|
|
53
|
+
var makeOptionId = customAlphabet("abcdefghijklmnopqrstuvwxyz0123456789", 6);
|
|
54
|
+
var pollModeItems = [{
|
|
55
|
+
label: "Single",
|
|
56
|
+
value: "single"
|
|
57
|
+
}, {
|
|
58
|
+
label: "Multiple",
|
|
59
|
+
value: "multiple"
|
|
60
|
+
}];
|
|
61
|
+
function moveItem(arr, from, to) {
|
|
62
|
+
if (to < 0 || to >= arr.length) return arr;
|
|
63
|
+
const next = arr.slice();
|
|
64
|
+
const [item] = next.splice(from, 1);
|
|
65
|
+
next.splice(to, 0, item);
|
|
66
|
+
return next;
|
|
67
|
+
}
|
|
68
|
+
function ImeSafeInput({ value, onValueChange, onCompositionEnd, ...rest }) {
|
|
69
|
+
const [local, setLocal] = useState(value);
|
|
70
|
+
const composingRef = useRef(false);
|
|
71
|
+
const lastCommittedRef = useRef(value);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (composingRef.current) return;
|
|
74
|
+
if (value !== lastCommittedRef.current) {
|
|
75
|
+
lastCommittedRef.current = value;
|
|
76
|
+
setLocal(value);
|
|
77
|
+
}
|
|
78
|
+
}, [value]);
|
|
79
|
+
const commit = useCallback((next) => {
|
|
80
|
+
lastCommittedRef.current = next;
|
|
81
|
+
if (next !== value) onValueChange(next);
|
|
82
|
+
}, [onValueChange, value]);
|
|
83
|
+
return /* @__PURE__ */ jsx("input", {
|
|
84
|
+
...rest,
|
|
85
|
+
value: local,
|
|
86
|
+
onChange: (event) => {
|
|
87
|
+
const next = event.target.value;
|
|
88
|
+
setLocal(next);
|
|
89
|
+
if (!composingRef.current) commit(next);
|
|
90
|
+
},
|
|
91
|
+
onCompositionEnd: (event) => {
|
|
92
|
+
composingRef.current = false;
|
|
93
|
+
const next = event.currentTarget.value;
|
|
94
|
+
setLocal(next);
|
|
95
|
+
commit(next);
|
|
96
|
+
onCompositionEnd?.(event);
|
|
97
|
+
},
|
|
98
|
+
onCompositionStart: () => {
|
|
99
|
+
composingRef.current = true;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function PollEditDecorator({ closeAt, mode, nodeKey, options, pollId, question, showResults }) {
|
|
104
|
+
const [editor] = o();
|
|
105
|
+
const editable = editor.isEditable();
|
|
106
|
+
const updatePoll = useCallback((mutate) => {
|
|
107
|
+
editor.update(() => {
|
|
108
|
+
const node = $getNodeByKey(nodeKey);
|
|
109
|
+
if ($isPollNode(node)) mutate(node);
|
|
110
|
+
});
|
|
111
|
+
}, [editor, nodeKey]);
|
|
112
|
+
const handleQuestionChange = useCallback((value) => {
|
|
113
|
+
updatePoll((node) => node.setQuestion(value));
|
|
114
|
+
}, [updatePoll]);
|
|
115
|
+
const handleOptionLabelChange = useCallback((id, label) => {
|
|
116
|
+
updatePoll((node) => node.setOptions(node.getOptions().map((o) => o.id === id ? {
|
|
117
|
+
...o,
|
|
118
|
+
label
|
|
119
|
+
} : o)));
|
|
120
|
+
}, [updatePoll]);
|
|
121
|
+
const handleOptionRemove = useCallback((id) => {
|
|
122
|
+
updatePoll((node) => node.setOptions(node.getOptions().filter((o) => o.id !== id)));
|
|
123
|
+
}, [updatePoll]);
|
|
124
|
+
const handleOptionAdd = useCallback(() => {
|
|
125
|
+
updatePoll((node) => node.setOptions([...node.getOptions(), {
|
|
126
|
+
id: `o_${makeOptionId()}`,
|
|
127
|
+
label: ""
|
|
128
|
+
}]));
|
|
129
|
+
}, [updatePoll]);
|
|
130
|
+
const handleOptionMove = useCallback((index, direction) => {
|
|
131
|
+
updatePoll((node) => {
|
|
132
|
+
const current = node.getOptions();
|
|
133
|
+
const next = moveItem(current, index, index + direction);
|
|
134
|
+
if (next !== current) node.setOptions(next);
|
|
135
|
+
});
|
|
136
|
+
}, [updatePoll]);
|
|
137
|
+
const handleModeChange = useCallback((next) => {
|
|
138
|
+
updatePoll((node) => node.setMode(next));
|
|
139
|
+
}, [updatePoll]);
|
|
140
|
+
const handleCloseAtChange = useCallback((value) => {
|
|
141
|
+
updatePoll((node) => node.setCloseAt(value || void 0));
|
|
142
|
+
}, [updatePoll]);
|
|
143
|
+
const handleShowResultsChange = useCallback((value) => {
|
|
144
|
+
updatePoll((node) => {
|
|
145
|
+
if (value === "always" || value === "after-vote" || value === "after-close") node.setShowResults(value);
|
|
146
|
+
else node.setShowResults(void 0);
|
|
147
|
+
});
|
|
148
|
+
}, [updatePoll]);
|
|
149
|
+
const handleShowResultsSelectChange = useCallback((value) => {
|
|
150
|
+
if (typeof value === "string") handleShowResultsChange(value);
|
|
151
|
+
}, [handleShowResultsChange]);
|
|
152
|
+
const handleOptionKeyDown = useCallback((event, index) => {
|
|
153
|
+
if (event.key === "Enter") {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
if (index === options.length - 1) handleOptionAdd();
|
|
156
|
+
}
|
|
157
|
+
}, [handleOptionAdd, options.length]);
|
|
158
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
159
|
+
className: pollEditClasses.container,
|
|
160
|
+
"data-poll-id": pollId,
|
|
161
|
+
children: [
|
|
162
|
+
/* @__PURE__ */ jsxs("div", {
|
|
163
|
+
className: pollEditClasses.meta,
|
|
164
|
+
children: ["Poll · ", mode === "single" ? "Single choice" : "Multiple choice"]
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ jsx(ImeSafeInput, {
|
|
167
|
+
"aria-label": "Poll question",
|
|
168
|
+
className: pollEditClasses.question,
|
|
169
|
+
disabled: !editable,
|
|
170
|
+
placeholder: "Question",
|
|
171
|
+
value: question,
|
|
172
|
+
onValueChange: handleQuestionChange
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ jsx("ul", {
|
|
175
|
+
className: pollEditClasses.optionList,
|
|
176
|
+
children: options.map((option, index) => /* @__PURE__ */ jsxs("li", {
|
|
177
|
+
className: pollEditClasses.optionRow,
|
|
178
|
+
children: [
|
|
179
|
+
editable && options.length > 1 && /* @__PURE__ */ jsxs("span", {
|
|
180
|
+
className: pollEditClasses.reorderColumn,
|
|
181
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
182
|
+
"aria-label": "Move option up",
|
|
183
|
+
className: pollEditClasses.reorderButton,
|
|
184
|
+
disabled: index === 0,
|
|
185
|
+
type: "button",
|
|
186
|
+
onClick: () => handleOptionMove(index, -1),
|
|
187
|
+
children: /* @__PURE__ */ jsx(ChevronUp, {
|
|
188
|
+
"aria-hidden": true,
|
|
189
|
+
size: 14
|
|
190
|
+
})
|
|
191
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
192
|
+
"aria-label": "Move option down",
|
|
193
|
+
className: pollEditClasses.reorderButton,
|
|
194
|
+
disabled: index === options.length - 1,
|
|
195
|
+
type: "button",
|
|
196
|
+
onClick: () => handleOptionMove(index, 1),
|
|
197
|
+
children: /* @__PURE__ */ jsx(ChevronDown, {
|
|
198
|
+
"aria-hidden": true,
|
|
199
|
+
size: 14
|
|
200
|
+
})
|
|
201
|
+
})]
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ jsx(ImeSafeInput, {
|
|
204
|
+
"aria-label": "Option label",
|
|
205
|
+
className: pollEditClasses.optionInput,
|
|
206
|
+
disabled: !editable,
|
|
207
|
+
placeholder: "Option",
|
|
208
|
+
value: option.label,
|
|
209
|
+
onKeyDown: (event) => handleOptionKeyDown(event, index),
|
|
210
|
+
onValueChange: (next) => handleOptionLabelChange(option.id, next)
|
|
211
|
+
}),
|
|
212
|
+
editable && options.length > 2 && /* @__PURE__ */ jsx("button", {
|
|
213
|
+
"aria-label": "Remove option",
|
|
214
|
+
className: pollEditClasses.removeButton,
|
|
215
|
+
type: "button",
|
|
216
|
+
onClick: () => handleOptionRemove(option.id),
|
|
217
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
218
|
+
"aria-hidden": true,
|
|
219
|
+
size: 16
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
}, option.id))
|
|
224
|
+
}),
|
|
225
|
+
editable && /* @__PURE__ */ jsxs("button", {
|
|
226
|
+
className: pollEditClasses.addOption,
|
|
227
|
+
type: "button",
|
|
228
|
+
onClick: handleOptionAdd,
|
|
229
|
+
children: [/* @__PURE__ */ jsx(Plus, {
|
|
230
|
+
"aria-hidden": true,
|
|
231
|
+
size: 16
|
|
232
|
+
}), /* @__PURE__ */ jsx("span", { children: "Add option" })]
|
|
233
|
+
}),
|
|
234
|
+
editable && /* @__PURE__ */ jsxs("div", {
|
|
235
|
+
className: pollEditClasses.modeRow,
|
|
236
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
237
|
+
className: pollEditClasses.advancedLabel,
|
|
238
|
+
children: "Mode"
|
|
239
|
+
}), /* @__PURE__ */ jsx(SegmentedControl, {
|
|
240
|
+
className: pollEditClasses.modeControl,
|
|
241
|
+
items: pollModeItems,
|
|
242
|
+
value: mode,
|
|
243
|
+
onChange: handleModeChange
|
|
244
|
+
})]
|
|
245
|
+
}),
|
|
246
|
+
editable && /* @__PURE__ */ jsxs("details", { children: [/* @__PURE__ */ jsx("summary", {
|
|
247
|
+
className: pollEditClasses.advancedSummary,
|
|
248
|
+
children: "Advanced"
|
|
249
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
250
|
+
className: pollEditClasses.advancedGrid,
|
|
251
|
+
children: [
|
|
252
|
+
/* @__PURE__ */ jsx("span", {
|
|
253
|
+
className: pollEditClasses.advancedLabel,
|
|
254
|
+
children: "Close at"
|
|
255
|
+
}),
|
|
256
|
+
/* @__PURE__ */ jsxs("div", {
|
|
257
|
+
className: pollEditClasses.dateTimeField,
|
|
258
|
+
children: [/* @__PURE__ */ jsx(CalendarClock, {
|
|
259
|
+
"aria-hidden": true,
|
|
260
|
+
className: pollEditClasses.dateTimeIcon,
|
|
261
|
+
size: 16
|
|
262
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
263
|
+
"aria-label": "Closing time",
|
|
264
|
+
className: pollEditClasses.dateTimeInput,
|
|
265
|
+
type: "datetime-local",
|
|
266
|
+
value: closeAt ?? "",
|
|
267
|
+
onChange: (event) => handleCloseAtChange(event.target.value)
|
|
268
|
+
})]
|
|
269
|
+
}),
|
|
270
|
+
/* @__PURE__ */ jsx("span", {
|
|
271
|
+
className: pollEditClasses.advancedLabel,
|
|
272
|
+
children: "Show results"
|
|
273
|
+
}),
|
|
274
|
+
/* @__PURE__ */ jsxs(Select, {
|
|
275
|
+
value: showResults ?? "always",
|
|
276
|
+
onValueChange: handleShowResultsSelectChange,
|
|
277
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
278
|
+
"aria-label": "Show results policy",
|
|
279
|
+
className: pollEditClasses.selectTrigger,
|
|
280
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
281
|
+
}), /* @__PURE__ */ jsxs(SelectContent, {
|
|
282
|
+
className: pollEditClasses.selectContent,
|
|
283
|
+
sideOffset: 6,
|
|
284
|
+
children: [
|
|
285
|
+
/* @__PURE__ */ jsx(SelectItem, {
|
|
286
|
+
value: "always",
|
|
287
|
+
children: "Always"
|
|
288
|
+
}),
|
|
289
|
+
/* @__PURE__ */ jsx(SelectItem, {
|
|
290
|
+
value: "after-vote",
|
|
291
|
+
children: "After vote"
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ jsx(SelectItem, {
|
|
294
|
+
value: "after-close",
|
|
295
|
+
children: "After close"
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
})]
|
|
299
|
+
})
|
|
300
|
+
]
|
|
301
|
+
})] })
|
|
302
|
+
]
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/nodes/PollEditNode.ts
|
|
307
|
+
var PollEditNode = class PollEditNode extends PollNode {
|
|
308
|
+
static getType() {
|
|
309
|
+
return "poll";
|
|
310
|
+
}
|
|
311
|
+
static clone(node) {
|
|
312
|
+
return new PollEditNode({
|
|
313
|
+
pollId: node.__pollId,
|
|
314
|
+
question: node.__question,
|
|
315
|
+
options: node.__options,
|
|
316
|
+
mode: node.__mode,
|
|
317
|
+
closeAt: node.__closeAt,
|
|
318
|
+
showResults: node.__showResults
|
|
319
|
+
}, node.__key);
|
|
320
|
+
}
|
|
321
|
+
constructor(payload, key) {
|
|
322
|
+
super(payload, key);
|
|
323
|
+
}
|
|
324
|
+
static importJSON(serializedNode) {
|
|
325
|
+
return new PollEditNode({
|
|
326
|
+
pollId: serializedNode.pollId,
|
|
327
|
+
question: serializedNode.question,
|
|
328
|
+
options: serializedNode.options,
|
|
329
|
+
mode: serializedNode.mode,
|
|
330
|
+
closeAt: serializedNode.closeAt,
|
|
331
|
+
showResults: serializedNode.showResults
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
decorate(_editor, _config) {
|
|
335
|
+
return createElement(PollEditDecorator, {
|
|
336
|
+
nodeKey: this.__key,
|
|
337
|
+
pollId: this.__pollId,
|
|
338
|
+
question: this.__question,
|
|
339
|
+
options: this.__options,
|
|
340
|
+
mode: this.__mode,
|
|
341
|
+
closeAt: this.__closeAt,
|
|
342
|
+
showResults: this.__showResults
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
_defineProperty(PollEditNode, "commandItems", [{
|
|
347
|
+
title: "Poll",
|
|
348
|
+
icon: createElement(Vote, { size: 20 }),
|
|
349
|
+
description: "Reader-facing vote widget",
|
|
350
|
+
keywords: [
|
|
351
|
+
"poll",
|
|
352
|
+
"vote",
|
|
353
|
+
"survey",
|
|
354
|
+
"choice"
|
|
355
|
+
],
|
|
356
|
+
section: "ADVANCED",
|
|
357
|
+
placement: ["slash", "toolbar"],
|
|
358
|
+
group: "insert",
|
|
359
|
+
onSelect: (editor) => {
|
|
360
|
+
editor.update(() => {
|
|
361
|
+
$insertNodes([$createPollEditNode()]);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}]);
|
|
365
|
+
function $createPollEditNode(payload) {
|
|
366
|
+
return new PollEditNode(payload);
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/edit.ts
|
|
370
|
+
var pollEditNodes = [PollEditNode];
|
|
371
|
+
//#endregion
|
|
372
|
+
export { pollEditClasses as a, PollEditDecorator as i, $createPollEditNode as n, PollEditNode as r, pollEditNodes as t };
|
package/dist/edit.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Klass, LexicalNode } from 'lexical';
|
|
2
|
+
export { $createPollEditNode, PollEditNode } from './nodes/PollEditNode';
|
|
3
|
+
export { pollEditClasses } from './poll-edit.css';
|
|
4
|
+
export { PollEditDecorator } from './PollEditDecorator';
|
|
5
|
+
export declare const pollEditNodes: Array<Klass<LexicalNode>>;
|
|
6
|
+
//# sourceMappingURL=edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../src/edit.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAkB,CAAC"}
|