@bigbluebutton/tldraw 2.0.0-alpha.24 → 2.0.0-alpha.25
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/dist-cjs/index.d.ts +9 -1
- package/dist-cjs/lib/defaultShapeUtils.js +3 -1
- package/dist-cjs/lib/defaultShapeUtils.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/poll/PollShapeTool.js +30 -0
- package/dist-cjs/lib/shapes/poll/PollShapeTool.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/PollShapeUtil.js +121 -0
- package/dist-cjs/lib/shapes/poll/PollShapeUtil.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/components/poll-content.js +101 -0
- package/dist-cjs/lib/shapes/poll/components/poll-content.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/components/styles.js +53 -0
- package/dist-cjs/lib/shapes/poll/components/styles.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-migrations.js +45 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-migrations.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-props.js +39 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-props.js.map +7 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-types.js +17 -0
- package/dist-cjs/lib/shapes/poll/poll-shape-types.js.map +7 -0
- package/dist-cjs/lib/tools/HandTool/HandTool.js +3 -3
- package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
- package/dist-cjs/lib/ui/components/ContextMenu.js +0 -1
- package/dist-cjs/lib/ui/components/ContextMenu.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-esm/index.d.mts +9 -1
- package/dist-esm/lib/defaultShapeUtils.mjs +3 -1
- package/dist-esm/lib/defaultShapeUtils.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/poll/PollShapeTool.mjs +10 -0
- package/dist-esm/lib/shapes/poll/PollShapeTool.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/PollShapeUtil.mjs +97 -0
- package/dist-esm/lib/shapes/poll/PollShapeUtil.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/components/poll-content.mjs +71 -0
- package/dist-esm/lib/shapes/poll/components/poll-content.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/components/styles.mjs +23 -0
- package/dist-esm/lib/shapes/poll/components/styles.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/poll-shape-migrations.mjs +25 -0
- package/dist-esm/lib/shapes/poll/poll-shape-migrations.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/poll-shape-props.mjs +19 -0
- package/dist-esm/lib/shapes/poll/poll-shape-props.mjs.map +7 -0
- package/dist-esm/lib/shapes/poll/poll-shape-types.mjs +1 -0
- package/dist-esm/lib/shapes/poll/poll-shape-types.mjs.map +7 -0
- package/dist-esm/lib/tools/HandTool/HandTool.mjs +3 -3
- package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
- package/dist-esm/lib/ui/components/ContextMenu.mjs +0 -1
- package/dist-esm/lib/ui/components/ContextMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -1
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/package.json +4 -3
- package/src/lib/Tldraw.test.tsx +9 -13
- package/src/lib/defaultShapeUtils.ts +2 -0
- package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +1 -1
- package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.ts.snap +6 -6
- package/src/lib/shapes/poll/PollShapeTool.tsx +7 -0
- package/src/lib/shapes/poll/PollShapeUtil.tsx +108 -0
- package/src/lib/shapes/poll/components/poll-content.tsx +100 -0
- package/src/lib/shapes/poll/components/styles.ts +21 -0
- package/src/lib/shapes/poll/poll-shape-migrations.ts +23 -0
- package/src/lib/shapes/poll/poll-shape-props.ts +17 -0
- package/src/lib/shapes/poll/poll-shape-types.ts +21 -0
- package/src/lib/tools/HandTool/HandTool.ts +4 -5
- package/src/lib/ui/components/ContextMenu.tsx +1 -1
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +5 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +5 -0
- package/src/test/Editor.test.tsx +2 -2
- package/src/test/HandTool.test.ts +55 -56
- package/src/test/TLSessionStateSnapshot.test.ts +5 -5
- package/src/test/TestEditor.ts +4 -1
- package/src/test/TldrawEditor.test.tsx +28 -30
- package/src/test/__snapshots__/resizing.test.ts.snap +8 -8
- package/src/test/commands/__snapshots__/packShapes.test.ts.snap +20 -20
- package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
- package/src/test/commands/createShapes.test.ts +1 -1
- package/src/test/commands/putContent.test.ts +4 -4
- package/src/test/commands/updateShapes.test.ts +1 -1
- package/src/test/resizing.test.ts +203 -203
- package/src/test/selection-omnibus.test.ts +41 -41
- package/src/test/test-jsx.tsx +7 -3
- package/src/test/translating.test.ts +42 -42
package/src/lib/Tldraw.test.tsx
CHANGED
|
@@ -5,12 +5,10 @@ import { Tldraw } from './Tldraw'
|
|
|
5
5
|
|
|
6
6
|
describe('<Tldraw />', () => {
|
|
7
7
|
it('Renders without crashing', async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
</Tldraw>
|
|
13
|
-
)
|
|
8
|
+
render(
|
|
9
|
+
<Tldraw>
|
|
10
|
+
<div data-testid="canvas-1" />
|
|
11
|
+
</Tldraw>
|
|
14
12
|
)
|
|
15
13
|
|
|
16
14
|
await screen.findByTestId('canvas-1')
|
|
@@ -27,7 +25,7 @@ describe('<Tldraw />', () => {
|
|
|
27
25
|
)
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
render(<TestComponent />)
|
|
31
29
|
await screen.findByTestId('canvas-1')
|
|
32
30
|
})
|
|
33
31
|
|
|
@@ -57,12 +55,10 @@ describe('<Tldraw />', () => {
|
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
const rendered =
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
</Tldraw>
|
|
65
|
-
)
|
|
58
|
+
const rendered = render(
|
|
59
|
+
<Tldraw shapeUtils={[FakeShapeUtil1]}>
|
|
60
|
+
<div data-testid="canvas-1" />
|
|
61
|
+
</Tldraw>
|
|
66
62
|
)
|
|
67
63
|
await screen.findByTestId('canvas-1')
|
|
68
64
|
|
|
@@ -9,6 +9,7 @@ import { HighlightShapeUtil } from './shapes/highlight/HighlightShapeUtil'
|
|
|
9
9
|
import { ImageShapeUtil } from './shapes/image/ImageShapeUtil'
|
|
10
10
|
import { LineShapeUtil } from './shapes/line/LineShapeUtil'
|
|
11
11
|
import { NoteShapeUtil } from './shapes/note/NoteShapeUtil'
|
|
12
|
+
import { PollShapeUtil } from './shapes/poll/PollShapeUtil'
|
|
12
13
|
import { TextShapeUtil } from './shapes/text/TextShapeUtil'
|
|
13
14
|
import { VideoShapeUtil } from './shapes/video/VideoShapeUtil'
|
|
14
15
|
|
|
@@ -26,4 +27,5 @@ export const defaultShapeUtils: TLAnyShapeUtilConstructor[] = [
|
|
|
26
27
|
EmbedShapeUtil,
|
|
27
28
|
ImageShapeUtil,
|
|
28
29
|
VideoShapeUtil,
|
|
30
|
+
PollShapeUtil,
|
|
29
31
|
]
|
|
@@ -518,7 +518,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
|
|
|
518
518
|
|
|
519
519
|
const path = info.isStraight ? getSolidStraightArrowPath(info) : getSolidCurvedArrowPath(info)
|
|
520
520
|
|
|
521
|
-
let handlePath: null | JSX.Element = null
|
|
521
|
+
let handlePath: null | React.JSX.Element = null
|
|
522
522
|
|
|
523
523
|
if (onlySelectedShape === shape && shouldDisplayHandles) {
|
|
524
524
|
const sw = 2
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`Misc resizes: line shape after resize 1`] = `
|
|
4
|
-
|
|
4
|
+
{
|
|
5
5
|
"id": "shape:line1",
|
|
6
6
|
"index": "a1",
|
|
7
7
|
"isLocked": false,
|
|
8
|
-
"meta":
|
|
8
|
+
"meta": {},
|
|
9
9
|
"opacity": 1,
|
|
10
10
|
"parentId": "page:page",
|
|
11
|
-
"props":
|
|
11
|
+
"props": {
|
|
12
12
|
"color": "black",
|
|
13
13
|
"dash": "draw",
|
|
14
|
-
"handles":
|
|
15
|
-
"end":
|
|
14
|
+
"handles": {
|
|
15
|
+
"end": {
|
|
16
16
|
"canBind": false,
|
|
17
17
|
"id": "end",
|
|
18
18
|
"index": "a2",
|
|
@@ -20,7 +20,7 @@ Object {
|
|
|
20
20
|
"x": 100,
|
|
21
21
|
"y": 700,
|
|
22
22
|
},
|
|
23
|
-
"start":
|
|
23
|
+
"start": {
|
|
24
24
|
"canBind": false,
|
|
25
25
|
"id": "start",
|
|
26
26
|
"index": "a1",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HTMLContainer,
|
|
3
|
+
Rectangle2d,
|
|
4
|
+
ShapeUtil,
|
|
5
|
+
TLOnResizeHandler,
|
|
6
|
+
getDefaultColorTheme,
|
|
7
|
+
resizeBox,
|
|
8
|
+
} from '@bigbluebutton/editor'
|
|
9
|
+
|
|
10
|
+
import ChatPollContent from './components/poll-content'
|
|
11
|
+
import { pollShapeMigrations } from './poll-shape-migrations'
|
|
12
|
+
import { pollShapeProps } from './poll-shape-props'
|
|
13
|
+
import { IPollShape } from './poll-shape-types'
|
|
14
|
+
|
|
15
|
+
export class PollShapeUtil extends ShapeUtil<IPollShape> {
|
|
16
|
+
static override type = 'poll' as const
|
|
17
|
+
|
|
18
|
+
static override props = pollShapeProps
|
|
19
|
+
|
|
20
|
+
static override migrations = pollShapeMigrations
|
|
21
|
+
|
|
22
|
+
override isAspectRatioLocked = (_shape: IPollShape) => false
|
|
23
|
+
|
|
24
|
+
override canResize = (_shape: IPollShape) => true
|
|
25
|
+
|
|
26
|
+
override canBind = (_shape: IPollShape) => true
|
|
27
|
+
|
|
28
|
+
getDefaultProps(): IPollShape['props'] {
|
|
29
|
+
return {
|
|
30
|
+
w: 300,
|
|
31
|
+
h: 300,
|
|
32
|
+
color: 'black',
|
|
33
|
+
fill: 'white',
|
|
34
|
+
question: '',
|
|
35
|
+
numRespondents: 0,
|
|
36
|
+
numResponders: 0,
|
|
37
|
+
questionText: '',
|
|
38
|
+
questionType: '',
|
|
39
|
+
answers: [],
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getGeometry(shape: IPollShape) {
|
|
44
|
+
return new Rectangle2d({
|
|
45
|
+
width: shape.props.w,
|
|
46
|
+
height: shape.props.h,
|
|
47
|
+
isFilled: true,
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
component(shape: IPollShape) {
|
|
52
|
+
const { bounds } = this.editor.getShapeGeometry(shape)
|
|
53
|
+
const theme = getDefaultColorTheme({
|
|
54
|
+
isDarkMode: this.editor.user.getIsDarkMode(),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// const contentRef = React.useRef<HTMLDivElement>(null)
|
|
58
|
+
const pollMetadata = JSON.stringify({
|
|
59
|
+
id: shape.id,
|
|
60
|
+
question: shape.props.question,
|
|
61
|
+
numRespondents: shape.props.numRespondents,
|
|
62
|
+
numResponders: shape.props.numResponders,
|
|
63
|
+
questionText: shape.props.questionText,
|
|
64
|
+
questionType: shape.props.questionType,
|
|
65
|
+
answers: shape.props.answers,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const adjustedHeight = shape.props.questionText.length > 0 ? bounds.height - 75 : bounds.height
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<HTMLContainer
|
|
72
|
+
id={shape.id}
|
|
73
|
+
style={{
|
|
74
|
+
border: '1px solid #8B9AA8',
|
|
75
|
+
borderRadius: '4px',
|
|
76
|
+
boxShadow: '0px 0px 4px 0px rgba(0, 0, 0, 0.20)',
|
|
77
|
+
display: 'flex',
|
|
78
|
+
flexDirection: 'column',
|
|
79
|
+
alignItems: 'center',
|
|
80
|
+
justifyContent: 'center',
|
|
81
|
+
pointerEvents: 'all',
|
|
82
|
+
backgroundColor: theme[shape.props.color].semi,
|
|
83
|
+
color: theme[shape.props.color].solid,
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
86
|
+
<div
|
|
87
|
+
style={{
|
|
88
|
+
width: `${bounds.width}px`,
|
|
89
|
+
overflow: 'hidden',
|
|
90
|
+
position: 'relative',
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
<ChatPollContent metadata={pollMetadata} height={adjustedHeight} />
|
|
94
|
+
</div>
|
|
95
|
+
</HTMLContainer>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
indicator(shape: IPollShape) {
|
|
100
|
+
return <rect width={shape.props.w} height={shape.props.h} />
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override onResize: TLOnResizeHandler<IPollShape> = (shape, info) => {
|
|
104
|
+
return resizeBox(shape, info)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default PollShapeUtil
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis } from 'recharts'
|
|
4
|
+
import { TLUiTranslationKey } from '../../../ui/hooks/useTranslation/TLUiTranslationKey'
|
|
5
|
+
import Styled from './styles'
|
|
6
|
+
|
|
7
|
+
const caseInsensitiveReducer = (acc: any[], item: { key: string; numVotes: number }) => {
|
|
8
|
+
const index = acc.findIndex((ans) => ans.key.toLowerCase() === item.key.toLowerCase())
|
|
9
|
+
if (index !== -1) {
|
|
10
|
+
if (acc[index].numVotes >= item.numVotes) acc[index].numVotes += item.numVotes
|
|
11
|
+
else {
|
|
12
|
+
const tempVotes = acc[index].numVotes
|
|
13
|
+
acc[index] = item
|
|
14
|
+
acc[index].numVotes += tempVotes
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
acc.push(item)
|
|
18
|
+
}
|
|
19
|
+
return acc
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface ChatPollContentProps {
|
|
23
|
+
metadata: string
|
|
24
|
+
height?: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Metadata {
|
|
28
|
+
id: string
|
|
29
|
+
question: string
|
|
30
|
+
numRespondents: number
|
|
31
|
+
numResponders: number
|
|
32
|
+
questionText: string
|
|
33
|
+
questionType: string
|
|
34
|
+
answers: Array<Answers>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Answers {
|
|
38
|
+
key: string
|
|
39
|
+
numVotes: number
|
|
40
|
+
id: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertAsMetadata(metadata: unknown): asserts metadata is Metadata {
|
|
44
|
+
if (typeof metadata !== 'object' || metadata === null) {
|
|
45
|
+
throw new Error('metadata is not an object')
|
|
46
|
+
}
|
|
47
|
+
if (typeof (metadata as Metadata).id !== 'string') {
|
|
48
|
+
throw new Error('metadata.id is not a string')
|
|
49
|
+
}
|
|
50
|
+
if (typeof (metadata as Metadata).numRespondents !== 'number') {
|
|
51
|
+
throw new Error('metadata.numRespondents is not a number')
|
|
52
|
+
}
|
|
53
|
+
if (typeof (metadata as Metadata).numResponders !== 'number') {
|
|
54
|
+
throw new Error('metadata.numResponders is not a number')
|
|
55
|
+
}
|
|
56
|
+
if (typeof (metadata as Metadata).questionText !== 'string') {
|
|
57
|
+
throw new Error('metadata.questionText is not a string')
|
|
58
|
+
}
|
|
59
|
+
if (typeof (metadata as Metadata).questionType !== 'string') {
|
|
60
|
+
throw new Error('metadata.questionType is not a string')
|
|
61
|
+
}
|
|
62
|
+
if (!Array.isArray((metadata as Metadata).answers)) {
|
|
63
|
+
throw new Error('metadata.answers is not an array')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ChatPollContent: React.FC<ChatPollContentProps> = ({
|
|
68
|
+
metadata: string,
|
|
69
|
+
height = undefined,
|
|
70
|
+
}) => {
|
|
71
|
+
const pollData = JSON.parse(string) as unknown
|
|
72
|
+
assertAsMetadata(pollData)
|
|
73
|
+
|
|
74
|
+
const answers = pollData.answers.reduce(caseInsensitiveReducer, [])
|
|
75
|
+
|
|
76
|
+
const translatedAnswers = answers.map((answer: Answers) => {
|
|
77
|
+
const translationKey = answer.key as TLUiTranslationKey
|
|
78
|
+
const pollAnswer = translationKey ? translationKey : answer.key
|
|
79
|
+
return {
|
|
80
|
+
...answer,
|
|
81
|
+
pollAnswer,
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const useHeight = height || translatedAnswers.length * 50
|
|
86
|
+
return (
|
|
87
|
+
<Styled.PollWrapper data-test="chatPollMessageText">
|
|
88
|
+
<Styled.PollText>{pollData.questionText}</Styled.PollText>
|
|
89
|
+
<ResponsiveContainer width="90%" height={useHeight}>
|
|
90
|
+
<BarChart data={translatedAnswers} layout="vertical">
|
|
91
|
+
<XAxis type="number" />
|
|
92
|
+
<YAxis width={80} type="category" dataKey="pollAnswer" />
|
|
93
|
+
<Bar dataKey="numVotes" fill="#0C57A7" />
|
|
94
|
+
</BarChart>
|
|
95
|
+
</ResponsiveContainer>
|
|
96
|
+
</Styled.PollWrapper>
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default ChatPollContent
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
2
|
+
import styled from 'styled-components'
|
|
3
|
+
|
|
4
|
+
export const PollText = styled.div`
|
|
5
|
+
margin-top: 0.5rem;
|
|
6
|
+
margin-bottom: 0.5rem;
|
|
7
|
+
font-size: 1.25rem;
|
|
8
|
+
font-weight: 500;
|
|
9
|
+
margin-left: 2.75rem;
|
|
10
|
+
color: var(--color-text, var(--color-gray, #4e5a66));
|
|
11
|
+
word-break: break-word;
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
export const PollWrapper = styled.div`
|
|
15
|
+
width: 100%;
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
PollText,
|
|
20
|
+
PollWrapper,
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineMigrations } from '@bigbluebutton/editor'
|
|
2
|
+
|
|
3
|
+
// Migrations for the custom poll shape (optional but very helpful)
|
|
4
|
+
export const pollShapeMigrations = defineMigrations({
|
|
5
|
+
currentVersion: 1,
|
|
6
|
+
migrators: {
|
|
7
|
+
1: {
|
|
8
|
+
// example, removing a property from the shape
|
|
9
|
+
up(shape) {
|
|
10
|
+
const migratedUpShape = { ...shape }
|
|
11
|
+
delete migratedUpShape.somePropertyToRemove
|
|
12
|
+
return migratedUpShape
|
|
13
|
+
},
|
|
14
|
+
down(shape) {
|
|
15
|
+
const migratedDownShape = { ...shape }
|
|
16
|
+
migratedDownShape.somePropertyToRemove = 'some value'
|
|
17
|
+
return migratedDownShape
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export default pollShapeMigrations
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DefaultColorStyle, ShapeProps, T } from '@bigbluebutton/editor'
|
|
2
|
+
import { IPollShape } from './poll-shape-types'
|
|
3
|
+
|
|
4
|
+
export const pollShapeProps: ShapeProps<IPollShape> = {
|
|
5
|
+
w: T.number,
|
|
6
|
+
h: T.number,
|
|
7
|
+
color: DefaultColorStyle,
|
|
8
|
+
fill: T.string,
|
|
9
|
+
question: T.string,
|
|
10
|
+
numRespondents: T.number,
|
|
11
|
+
numResponders: T.number,
|
|
12
|
+
questionText: T.string,
|
|
13
|
+
questionType: T.string,
|
|
14
|
+
answers: T.any,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default pollShapeProps
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TLBaseShape, TLDefaultColorStyle } from '@bigbluebutton/editor'
|
|
2
|
+
|
|
3
|
+
export type IPollShape = TLBaseShape<
|
|
4
|
+
'poll',
|
|
5
|
+
{
|
|
6
|
+
w: number
|
|
7
|
+
h: number
|
|
8
|
+
color: TLDefaultColorStyle
|
|
9
|
+
fill: string
|
|
10
|
+
question: string
|
|
11
|
+
numRespondents: number
|
|
12
|
+
numResponders: number
|
|
13
|
+
questionText: string
|
|
14
|
+
questionType: string
|
|
15
|
+
answers: Array<{
|
|
16
|
+
id: number
|
|
17
|
+
key: string
|
|
18
|
+
numVotes: number
|
|
19
|
+
}>
|
|
20
|
+
}
|
|
21
|
+
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StateNode, TLClickEvent } from '@bigbluebutton/editor'
|
|
2
2
|
import { Dragging } from './childStates/Dragging'
|
|
3
3
|
import { Idle } from './childStates/Idle'
|
|
4
4
|
import { Pointing } from './childStates/Pointing'
|
|
@@ -9,27 +9,26 @@ export class HandTool extends StateNode {
|
|
|
9
9
|
static override initial = 'idle'
|
|
10
10
|
static override children = () => [Idle, Pointing, Dragging]
|
|
11
11
|
|
|
12
|
-
override onDoubleClick: TLClickEvent = (
|
|
12
|
+
override onDoubleClick: TLClickEvent = (_info) => {
|
|
13
13
|
// if (info.phase === 'settle') {
|
|
14
14
|
// const { currentScreenPoint } = this.editor.inputs
|
|
15
15
|
// this.editor.zoomIn(currentScreenPoint, { duration: 220, easing: EASINGS.easeOutQuint })
|
|
16
16
|
// }
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
override onTripleClick: TLClickEvent = (
|
|
19
|
+
override onTripleClick: TLClickEvent = (_info) => {
|
|
20
20
|
// if (info.phase === 'settle') {
|
|
21
21
|
// const { currentScreenPoint } = this.editor.inputs
|
|
22
22
|
// this.editor.zoomOut(currentScreenPoint, { duration: 320, easing: EASINGS.easeOutQuint })
|
|
23
23
|
// }
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
override onQuadrupleClick: TLClickEvent = (
|
|
26
|
+
override onQuadrupleClick: TLClickEvent = (_info) => {
|
|
27
27
|
// if (info.phase === 'settle') {
|
|
28
28
|
// const zoomLevel = this.editor.getZoomLevel()
|
|
29
29
|
// const {
|
|
30
30
|
// inputs: { currentScreenPoint },
|
|
31
31
|
// } = this.editor
|
|
32
|
-
|
|
33
32
|
// if (zoomLevel === 1) {
|
|
34
33
|
// this.editor.zoomToFit({ duration: 400, easing: EASINGS.easeOutQuint })
|
|
35
34
|
// } else {
|
|
@@ -366,4 +366,9 @@ export const DEFAULT_TRANSLATION = {
|
|
|
366
366
|
'vscode.file-open.backup-failed': 'Backup failed: this is not a .tldr file.',
|
|
367
367
|
'vscode.file-open.dont-show-again': "Don't ask again",
|
|
368
368
|
'cursor-chat.type-to-chat': 'Type to chat...',
|
|
369
|
+
'app.poll.t': 'True',
|
|
370
|
+
'app.poll.f': 'False',
|
|
371
|
+
'app.poll.y': 'Yes',
|
|
372
|
+
'app.poll.n': 'No',
|
|
373
|
+
'app.poll.abstention': 'Abstention',
|
|
369
374
|
}
|
package/src/test/Editor.test.tsx
CHANGED
|
@@ -511,13 +511,13 @@ describe('getShapeUtil', () => {
|
|
|
511
511
|
it('throws if that shape type isnt registered', () => {
|
|
512
512
|
const myMissingShape = { type: 'missing' } as TLShape
|
|
513
513
|
expect(() => editor.getShapeUtil(myMissingShape)).toThrowErrorMatchingInlineSnapshot(
|
|
514
|
-
`"No shape util found for type
|
|
514
|
+
`"No shape util found for type "missing""`
|
|
515
515
|
)
|
|
516
516
|
})
|
|
517
517
|
|
|
518
518
|
it('throws if that type isnt registered', () => {
|
|
519
519
|
expect(() => editor.getShapeUtil('missing')).toThrowErrorMatchingInlineSnapshot(
|
|
520
|
-
`"No shape util found for type
|
|
520
|
+
`"No shape util found for type "missing""`
|
|
521
521
|
)
|
|
522
522
|
})
|
|
523
523
|
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TestEditor, createDefaultShapes } from './TestEditor'
|
|
1
|
+
import { TestEditor } from './TestEditor'
|
|
3
2
|
|
|
4
3
|
let editor: TestEditor
|
|
5
4
|
|
|
@@ -16,60 +15,60 @@ afterEach(() => {
|
|
|
16
15
|
|
|
17
16
|
jest.useFakeTimers()
|
|
18
17
|
|
|
19
|
-
describe(HandTool, () => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
})
|
|
18
|
+
// describe(HandTool, () => {
|
|
19
|
+
// it('Double taps to zoom in', () => {
|
|
20
|
+
// editor.setCurrentTool('hand')
|
|
21
|
+
// expect(editor.getZoomLevel()).toBe(1)
|
|
22
|
+
// editor.click()
|
|
23
|
+
// editor.click() // double click!
|
|
24
|
+
// jest.advanceTimersByTime(300)
|
|
25
|
+
// expect(editor.getZoomLevel()).not.toBe(1) // animating
|
|
26
|
+
// jest.advanceTimersByTime(300)
|
|
27
|
+
// expect(editor.getZoomLevel()).toBe(2) // all done
|
|
28
|
+
// })
|
|
29
|
+
|
|
30
|
+
// it('Triple taps to zoom out', () => {
|
|
31
|
+
// editor.setCurrentTool('hand')
|
|
32
|
+
// expect(editor.getZoomLevel()).toBe(1)
|
|
33
|
+
// editor.click()
|
|
34
|
+
// editor.click()
|
|
35
|
+
// editor.click() // triple click!
|
|
36
|
+
// jest.advanceTimersByTime(300)
|
|
37
|
+
// expect(editor.getZoomLevel()).not.toBe(1) // animating
|
|
38
|
+
// jest.advanceTimersByTime(300)
|
|
39
|
+
// expect(editor.getZoomLevel()).toBe(0.5) // all done
|
|
40
|
+
// })
|
|
41
|
+
|
|
42
|
+
// it('Quadruple taps to reset zoom', () => {
|
|
43
|
+
// editor.setCurrentTool('hand')
|
|
44
|
+
// editor.zoomIn() // zoom to 2
|
|
45
|
+
// expect(editor.getZoomLevel()).toBe(2)
|
|
46
|
+
// editor.click()
|
|
47
|
+
// editor.click()
|
|
48
|
+
// editor.click()
|
|
49
|
+
// editor.click() // quad click!
|
|
50
|
+
// jest.advanceTimersByTime(300)
|
|
51
|
+
// expect(editor.getZoomLevel()).not.toBe(2) // animating
|
|
52
|
+
// jest.advanceTimersByTime(300)
|
|
53
|
+
// expect(editor.getZoomLevel()).toBe(1) // all done
|
|
54
|
+
// })
|
|
55
|
+
|
|
56
|
+
// it('Quadruple taps from zoom=1 to zoom to fit', () => {
|
|
57
|
+
// editor.setCurrentTool('hand')
|
|
58
|
+
// expect(editor.getZoomLevel()).toBe(1)
|
|
59
|
+
// editor.createShapes(createDefaultShapes()) // makes some shapes
|
|
60
|
+
// editor.click()
|
|
61
|
+
// editor.click()
|
|
62
|
+
// editor.click()
|
|
63
|
+
// editor.click() // quad click!
|
|
64
|
+
// jest.advanceTimersByTime(300)
|
|
65
|
+
// expect(editor.getZoomLevel()).not.toBe(1) // animating
|
|
66
|
+
// jest.advanceTimersByTime(300)
|
|
67
|
+
// const z = editor.getZoomLevel()
|
|
68
|
+
// editor.zoomToFit() // call zoom to fit manually to compare
|
|
69
|
+
// expect(editor.getZoomLevel()).toBe(z) // zoom should not have changed
|
|
70
|
+
// })
|
|
71
|
+
// })
|
|
73
72
|
|
|
74
73
|
describe('When in the idle state', () => {
|
|
75
74
|
it('Returns to select on cancel', () => {
|
|
@@ -124,23 +124,23 @@ describe(extractSessionStateFromLegacySnapshot, () => {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
expect(extractSessionStateFromLegacySnapshot(oldSnapshot as any)).toMatchInlineSnapshot(`
|
|
127
|
-
|
|
127
|
+
{
|
|
128
128
|
"currentPageId": "page:whatever",
|
|
129
129
|
"exportBackground": false,
|
|
130
130
|
"isDebugMode": false,
|
|
131
131
|
"isFocusMode": false,
|
|
132
132
|
"isGridMode": false,
|
|
133
133
|
"isToolLocked": false,
|
|
134
|
-
"pageStates":
|
|
135
|
-
|
|
136
|
-
"camera":
|
|
134
|
+
"pageStates": [
|
|
135
|
+
{
|
|
136
|
+
"camera": {
|
|
137
137
|
"x": 0,
|
|
138
138
|
"y": 0,
|
|
139
139
|
"z": 1,
|
|
140
140
|
},
|
|
141
141
|
"focusedGroupId": null,
|
|
142
142
|
"pageId": "page:whatever",
|
|
143
|
-
"selectedShapeIds":
|
|
143
|
+
"selectedShapeIds": [
|
|
144
144
|
"shape:whatever",
|
|
145
145
|
],
|
|
146
146
|
},
|
package/src/test/TestEditor.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
createTLStore,
|
|
25
25
|
rotateSelectionHandle,
|
|
26
26
|
} from '@bigbluebutton/editor'
|
|
27
|
+
import React from 'react'
|
|
27
28
|
import { defaultShapeTools } from '../lib/defaultShapeTools'
|
|
28
29
|
import { defaultShapeUtils } from '../lib/defaultShapeUtils'
|
|
29
30
|
import { defaultTools } from '../lib/defaultTools'
|
|
@@ -560,7 +561,9 @@ export class TestEditor extends Editor {
|
|
|
560
561
|
return this
|
|
561
562
|
}
|
|
562
563
|
|
|
563
|
-
createShapesFromJsx(
|
|
564
|
+
createShapesFromJsx(
|
|
565
|
+
shapesJsx: React.JSX.Element | React.JSX.Element[]
|
|
566
|
+
): Record<string, TLShapeId> {
|
|
564
567
|
const { shapes, ids } = shapesFromJsx(shapesJsx)
|
|
565
568
|
this.createShapes(shapes)
|
|
566
569
|
return ids
|