pxt-core 10.0.21 → 10.0.23
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/built/pxt.js +12 -42
- package/built/pxtcompiler.d.ts +0 -1
- package/built/pxtcompiler.js +12 -42
- package/built/react-common/components/controls/Accordion/Accordion.d.ts +4 -0
- package/built/react-common/components/controls/Accordion/context.d.ts +11 -6
- package/built/react-common/components/util.d.ts +1 -0
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/multiplayer/js/{main.0e73ac24.js → main.121cfaf0.js} +2 -2
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtcompiler.js +1 -1
- package/built/web/pxtembed.js +1 -1
- package/built/web/pxtweb.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/react-common-authcode.css +1 -1
- package/built/web/react-common-multiplayer.css +1 -1
- package/built/web/react-common-skillmap.css +1 -1
- package/built/web/rtlreact-common-authcode.css +1 -1
- package/built/web/rtlreact-common-multiplayer.css +1 -1
- package/built/web/rtlreact-common-skillmap.css +1 -1
- package/built/web/rtlsemantic.css +1 -1
- package/built/web/semantic.css +1 -1
- package/built/web/skillmap/js/{main.f7e01730.js → main.e95746dc.js} +2 -2
- package/built/web/teachertool/css/main.00de32e9.css +1 -0
- package/built/web/teachertool/js/{main.dc513d1e.js → main.b94a6d6a.js} +2 -2
- package/built/web/tutorialtool/js/{main.c3bf42cf.js → main.03b71032.js} +2 -2
- package/common-docs/teachertool/catalog-shared.json +5 -0
- package/common-docs/teachertool/test/catalog-shared.json +1 -0
- package/docfiles/pxtweb/cookieCompliance.ts +15 -0
- package/package.json +1 -1
- package/react-common/components/controls/Accordion/Accordion.tsx +16 -7
- package/react-common/components/controls/Accordion/context.tsx +23 -16
- package/react-common/components/controls/EditorToggle.tsx +5 -1
- package/react-common/components/controls/FocusList.tsx +7 -38
- package/react-common/components/controls/FocusTrap.tsx +7 -7
- package/react-common/components/share/ShareInfo.tsx +8 -5
- package/react-common/components/util.tsx +21 -0
- package/react-common/styles/controls/Modal.less +3 -1
- package/react-common/styles/react-common-variables.less +1 -1
- package/react-common/styles/share/share.less +7 -0
- package/webapp/public/multiplayer.html +1 -1
- package/webapp/public/skillmap.html +1 -1
- package/webapp/public/teachertool.html +1 -1
- package/webapp/public/tutorialtool.html +1 -1
- package/built/web/teachertool/css/main.7ff56db5.css +0 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"template": "${Block} used ${count} times",
|
|
7
7
|
"description": "This block was used the specified number of times in your project.",
|
|
8
8
|
"docPath": "/teachertool",
|
|
9
|
+
"tags": ["General"],
|
|
9
10
|
"params": [
|
|
10
11
|
{
|
|
11
12
|
"name": "block",
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
"description": "The project contains at least the specified number of comments.",
|
|
28
29
|
"docPath": "/teachertool",
|
|
29
30
|
"maxCount": 1,
|
|
31
|
+
"tags": ["General"],
|
|
30
32
|
"params": [
|
|
31
33
|
{
|
|
32
34
|
"name": "count",
|
|
@@ -43,6 +45,7 @@
|
|
|
43
45
|
"docPath": "/teachertool",
|
|
44
46
|
"description": "The program uses at least this many loops of any kind (for, repeat, while, or for-of).",
|
|
45
47
|
"maxCount": 1,
|
|
48
|
+
"tags": ["Code Elements"],
|
|
46
49
|
"params": [
|
|
47
50
|
{
|
|
48
51
|
"name": "count",
|
|
@@ -59,6 +62,7 @@
|
|
|
59
62
|
"docPath": "/teachertool",
|
|
60
63
|
"description": "At least this many user-defined functions are created and called.",
|
|
61
64
|
"maxCount": 1,
|
|
65
|
+
"tags": ["Code Elements"],
|
|
62
66
|
"params": [
|
|
63
67
|
{
|
|
64
68
|
"name": "count",
|
|
@@ -75,6 +79,7 @@
|
|
|
75
79
|
"docPath": "/teachertool",
|
|
76
80
|
"description": "The program creates and uses at least this many user-defined variables.",
|
|
77
81
|
"maxCount": 1,
|
|
82
|
+
"tags": ["Code Elements"],
|
|
78
83
|
"params": [
|
|
79
84
|
{
|
|
80
85
|
"name": "count",
|
|
@@ -9,6 +9,7 @@ namespace pxt {
|
|
|
9
9
|
let analyticsLoaded = false;
|
|
10
10
|
let interactiveConsent = false;
|
|
11
11
|
let isProduction = false;
|
|
12
|
+
let partnerName: string;
|
|
12
13
|
|
|
13
14
|
class TelemetryQueue<A, B, C> {
|
|
14
15
|
private q: [A, B, C][] = [];
|
|
@@ -185,6 +186,16 @@ namespace pxt {
|
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
export function initializeAppInsightsInternal(includeCookie = false) {
|
|
189
|
+
try {
|
|
190
|
+
const params = new URLSearchParams(window.location.search);
|
|
191
|
+
if (params.has("partner")) {
|
|
192
|
+
partnerName = params.get("partner");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
console.warn("Could not parse search string", e);
|
|
197
|
+
}
|
|
198
|
+
|
|
188
199
|
// loadAppInsights is defined in docfiles/tracking.html
|
|
189
200
|
const loadAI = (window as any).loadAppInsights;
|
|
190
201
|
if (loadAI) {
|
|
@@ -221,6 +232,10 @@ namespace pxt {
|
|
|
221
232
|
telemetryItem.properties["target"] = pxtConfig.targetId;
|
|
222
233
|
telemetryItem.properties["stage"] = (pxtConfig.relprefix || "/--").replace(/[^a-z]/ig, '')
|
|
223
234
|
|
|
235
|
+
if (partnerName) {
|
|
236
|
+
telemetryItem.properties["partner"] = partnerName;
|
|
237
|
+
}
|
|
238
|
+
|
|
224
239
|
const userAgent = navigator.userAgent.toLowerCase();
|
|
225
240
|
const electronRegexResult = /\belectron\/(\d+\.\d+\.\d+.*?)(?: |$)/i.exec(userAgent); // Example navigator.userAgent: "Mozilla/5.0 Chrome/61.0.3163.100 Electron/2.0.0 Safari/537.36"
|
|
226
241
|
if (electronRegexResult) {
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { ContainerProps, classList, fireClickOnEnter } from "../../util";
|
|
3
3
|
import { useId } from "../../../hooks/useId";
|
|
4
|
-
import { AccordionProvider,
|
|
4
|
+
import { AccordionProvider, removeExpanded, setExpanded, useAccordionDispatch, useAccordionState } from "./context";
|
|
5
5
|
|
|
6
6
|
export interface AccordionProps extends ContainerProps {
|
|
7
|
+
multiExpand?: boolean;
|
|
8
|
+
defaultExpandedIds?: string[];
|
|
7
9
|
children?: React.ReactElement<AccordionItemProps>[] | React.ReactElement<AccordionItemProps>;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export interface AccordionItemProps extends ContainerProps {
|
|
11
13
|
children?: [React.ReactElement<AccordionHeaderProps>, React.ReactElement<AccordionPanelProps>];
|
|
12
14
|
noChevron?: boolean;
|
|
15
|
+
itemId?: string;
|
|
16
|
+
onExpandToggled?: (expanded: boolean) => void;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
export interface AccordionHeaderProps extends ContainerProps {
|
|
@@ -27,10 +31,12 @@ export const Accordion = (props: AccordionProps) => {
|
|
|
27
31
|
ariaHidden,
|
|
28
32
|
ariaDescribedBy,
|
|
29
33
|
role,
|
|
34
|
+
multiExpand,
|
|
35
|
+
defaultExpandedIds
|
|
30
36
|
} = props;
|
|
31
37
|
|
|
32
38
|
return (
|
|
33
|
-
<AccordionProvider>
|
|
39
|
+
<AccordionProvider multiExpand={multiExpand} defaultExpandedIds={defaultExpandedIds}>
|
|
34
40
|
<div
|
|
35
41
|
className={classList("common-accordion", className)}
|
|
36
42
|
id={id}
|
|
@@ -54,23 +60,26 @@ export const AccordionItem = (props: AccordionItemProps) => {
|
|
|
54
60
|
ariaHidden,
|
|
55
61
|
ariaDescribedBy,
|
|
56
62
|
role,
|
|
57
|
-
noChevron
|
|
63
|
+
noChevron,
|
|
64
|
+
itemId,
|
|
65
|
+
onExpandToggled,
|
|
58
66
|
} = props;
|
|
59
67
|
|
|
60
68
|
const { expanded } = useAccordionState();
|
|
61
69
|
const dispatch = useAccordionDispatch();
|
|
62
70
|
|
|
63
|
-
const panelId = useId();
|
|
71
|
+
const panelId = itemId ?? useId();
|
|
64
72
|
const mappedChildren = React.Children.toArray(children);
|
|
65
|
-
const isExpanded = expanded
|
|
73
|
+
const isExpanded = expanded.indexOf(panelId) !== -1;
|
|
66
74
|
|
|
67
75
|
const onHeaderClick = React.useCallback(() => {
|
|
68
76
|
if (isExpanded) {
|
|
69
|
-
dispatch(
|
|
77
|
+
dispatch(removeExpanded(panelId));
|
|
70
78
|
}
|
|
71
79
|
else {
|
|
72
80
|
dispatch(setExpanded(panelId));
|
|
73
81
|
}
|
|
82
|
+
onExpandToggled?.(!isExpanded);
|
|
74
83
|
}, [isExpanded]);
|
|
75
84
|
|
|
76
85
|
return (
|
|
@@ -150,4 +159,4 @@ export const AccordionPanel = (props: AccordionPanelProps) => {
|
|
|
150
159
|
{children}
|
|
151
160
|
</div>
|
|
152
161
|
);
|
|
153
|
-
}
|
|
162
|
+
}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
interface AccordionState {
|
|
4
|
-
|
|
4
|
+
multiExpand?: boolean;
|
|
5
|
+
expanded: string[];
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
const AccordionStateContext = React.createContext<AccordionState>(null);
|
|
8
9
|
const AccordionDispatchContext = React.createContext<(action: Action) => void>(null);
|
|
9
10
|
|
|
10
|
-
export const AccordionProvider = ({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
export const AccordionProvider = ({
|
|
12
|
+
multiExpand,
|
|
13
|
+
defaultExpandedIds,
|
|
14
|
+
children,
|
|
15
|
+
}: React.PropsWithChildren<{ multiExpand?: boolean; defaultExpandedIds?: string[] }>) => {
|
|
16
|
+
const [state, dispatch] = React.useReducer(accordionReducer, {
|
|
17
|
+
expanded: defaultExpandedIds ?? [],
|
|
18
|
+
multiExpand,
|
|
19
|
+
});
|
|
15
20
|
|
|
16
21
|
return (
|
|
17
22
|
<AccordionStateContext.Provider value={state}>
|
|
@@ -27,11 +32,12 @@ type SetExpanded = {
|
|
|
27
32
|
id: string;
|
|
28
33
|
};
|
|
29
34
|
|
|
30
|
-
type
|
|
31
|
-
type: "
|
|
35
|
+
type RemoveExpanded = {
|
|
36
|
+
type: "REMOVE_EXPANDED";
|
|
37
|
+
id: string;
|
|
32
38
|
};
|
|
33
39
|
|
|
34
|
-
type Action = SetExpanded |
|
|
40
|
+
type Action = SetExpanded | RemoveExpanded;
|
|
35
41
|
|
|
36
42
|
export const setExpanded = (id: string): SetExpanded => (
|
|
37
43
|
{
|
|
@@ -40,14 +46,15 @@ export const setExpanded = (id: string): SetExpanded => (
|
|
|
40
46
|
}
|
|
41
47
|
);
|
|
42
48
|
|
|
43
|
-
export const
|
|
49
|
+
export const removeExpanded = (id: string): RemoveExpanded => (
|
|
44
50
|
{
|
|
45
|
-
type: "
|
|
51
|
+
type: "REMOVE_EXPANDED",
|
|
52
|
+
id
|
|
46
53
|
}
|
|
47
54
|
);
|
|
48
55
|
|
|
49
56
|
export function useAccordionState() {
|
|
50
|
-
return React.useContext(AccordionStateContext)
|
|
57
|
+
return React.useContext(AccordionStateContext);
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
export function useAccordionDispatch() {
|
|
@@ -59,12 +66,12 @@ function accordionReducer(state: AccordionState, action: Action): AccordionState
|
|
|
59
66
|
case "SET_EXPANDED":
|
|
60
67
|
return {
|
|
61
68
|
...state,
|
|
62
|
-
expanded: action.id
|
|
69
|
+
expanded: state.multiExpand ? [...state.expanded, action.id] : [action.id],
|
|
63
70
|
};
|
|
64
|
-
case "
|
|
71
|
+
case "REMOVE_EXPANDED":
|
|
65
72
|
return {
|
|
66
73
|
...state,
|
|
67
|
-
expanded:
|
|
74
|
+
expanded: state.expanded.filter((id) => id !== action.id),
|
|
68
75
|
};
|
|
69
76
|
}
|
|
70
|
-
}
|
|
77
|
+
}
|
|
@@ -125,7 +125,11 @@ const EditorToggleAccessibleMenu = (props: EditorToggleProps) => {
|
|
|
125
125
|
next.push({...current});
|
|
126
126
|
|
|
127
127
|
// The selected item will always be a top-level option, not in a dropdown
|
|
128
|
-
if (selected === index)
|
|
128
|
+
if (selected === index) {
|
|
129
|
+
next[next.length - 1].selected = true;
|
|
130
|
+
} else {
|
|
131
|
+
next[next.length - 1].selected = false;
|
|
132
|
+
}
|
|
129
133
|
|
|
130
134
|
if (isDropdownItem(current)) {
|
|
131
135
|
next.push(...current.items.filter(i => i.focusable))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { ContainerProps } from "../util";
|
|
2
|
+
import { ContainerProps, findNextFocusableElement } from "../util";
|
|
3
3
|
|
|
4
4
|
export interface FocusListProps extends ContainerProps {
|
|
5
5
|
role: string;
|
|
@@ -62,37 +62,6 @@ export const FocusList = (props: FocusListProps) => {
|
|
|
62
62
|
&& getComputedStyle(e).display !== "none";
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const firstFocusableElement = () => {
|
|
66
|
-
return focusableElements.find(e => isFocusable(e))
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const lastFocusableElement = () => {
|
|
70
|
-
for (let i = 0; i < focusableElements.length; i++) {
|
|
71
|
-
if (isFocusable(focusableElements[focusableElements.length - 1 - i])) {
|
|
72
|
-
return focusableElements[focusableElements.length - 1 - i];
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return focusableElements[0];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const nextFocusableElement = (index: number, forwards: boolean) => {
|
|
80
|
-
let current: HTMLElement
|
|
81
|
-
for (let i = 1; i < focusableElements.length; i++) {
|
|
82
|
-
if (forwards) {
|
|
83
|
-
current = focusableElements[(index + i) % focusableElements.length];
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
current = focusableElements[(index + focusableElements.length - i) % focusableElements.length];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (isFocusable(current)) {
|
|
90
|
-
return current;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return focusableElements[0];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
65
|
const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
|
97
66
|
if (!focusableElements?.length) return;
|
|
98
67
|
|
|
@@ -120,31 +89,31 @@ export const FocusList = (props: FocusListProps) => {
|
|
|
120
89
|
}
|
|
121
90
|
else if (e.key === (useUpAndDownArrowKeys ? "ArrowDown" : "ArrowRight")) {
|
|
122
91
|
if (index === focusableElements.length - 1 || target === focusList) {
|
|
123
|
-
focus(
|
|
92
|
+
focus(findNextFocusableElement(focusableElements, index, 0, true, isFocusable));
|
|
124
93
|
}
|
|
125
94
|
else {
|
|
126
|
-
focus(
|
|
95
|
+
focus(findNextFocusableElement(focusableElements, index, index + 1, true, isFocusable));
|
|
127
96
|
}
|
|
128
97
|
e.preventDefault();
|
|
129
98
|
e.stopPropagation();
|
|
130
99
|
}
|
|
131
100
|
else if (e.key === (useUpAndDownArrowKeys ? "ArrowUp" : "ArrowLeft")) {
|
|
132
101
|
if (index === 0 || target === focusList) {
|
|
133
|
-
focus(
|
|
102
|
+
focus(findNextFocusableElement(focusableElements, index, focusableElements.length - 1, false, isFocusable));
|
|
134
103
|
}
|
|
135
104
|
else {
|
|
136
|
-
focus(
|
|
105
|
+
focus(findNextFocusableElement(focusableElements, index, index - 1, false, isFocusable));
|
|
137
106
|
}
|
|
138
107
|
e.preventDefault();
|
|
139
108
|
e.stopPropagation();
|
|
140
109
|
}
|
|
141
110
|
else if (e.key === "Home") {
|
|
142
|
-
focus(
|
|
111
|
+
focus(findNextFocusableElement(focusableElements, index, 0, true, isFocusable));
|
|
143
112
|
e.preventDefault();
|
|
144
113
|
e.stopPropagation();
|
|
145
114
|
}
|
|
146
115
|
else if (e.key === "End") {
|
|
147
|
-
focus(
|
|
116
|
+
focus(findNextFocusableElement(focusableElements, index, focusableElements.length - 1, true, isFocusable));
|
|
148
117
|
e.preventDefault();
|
|
149
118
|
e.stopPropagation();
|
|
150
119
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { classList, nodeListToArray } from "../util";
|
|
2
|
+
import { classList, nodeListToArray, findNextFocusableElement } from "../util";
|
|
3
3
|
|
|
4
4
|
export interface FocusTrapProps extends React.PropsWithChildren<{}> {
|
|
5
5
|
onEscape: () => void;
|
|
@@ -58,24 +58,24 @@ export const FocusTrap = (props: FocusTrapProps) => {
|
|
|
58
58
|
|
|
59
59
|
if (forward) {
|
|
60
60
|
if (goToEnd) {
|
|
61
|
-
focusable
|
|
61
|
+
findNextFocusableElement(focusable, index, focusable.length - 1, forward).focus();
|
|
62
62
|
}
|
|
63
63
|
else if (index === focusable.length - 1) {
|
|
64
|
-
focusable
|
|
64
|
+
findNextFocusableElement(focusable, index, 0, forward).focus();
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
|
-
focusable
|
|
67
|
+
findNextFocusableElement(focusable, index, index + 1, forward).focus();
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
else {
|
|
71
71
|
if (goToEnd) {
|
|
72
|
-
focusable
|
|
72
|
+
findNextFocusableElement(focusable, index, 0, forward).focus();
|
|
73
73
|
}
|
|
74
74
|
else if (index === 0) {
|
|
75
|
-
focusable
|
|
75
|
+
findNextFocusableElement(focusable, index, focusable.length - 1, forward).focus();
|
|
76
76
|
}
|
|
77
77
|
else {
|
|
78
|
-
focusable
|
|
78
|
+
findNextFocusableElement(focusable, index, Math.max(index - 1, 0), forward).focus();
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -32,6 +32,7 @@ export interface ShareInfoProps {
|
|
|
32
32
|
onClose: () => void;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
|
|
35
36
|
export const ShareInfo = (props: ShareInfoProps) => {
|
|
36
37
|
const {
|
|
37
38
|
projectName,
|
|
@@ -323,7 +324,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
|
|
|
323
324
|
{showSimulator && shareState !== "gifrecord" &&
|
|
324
325
|
<div className="project-share-thumbnail">
|
|
325
326
|
{thumbnailUri
|
|
326
|
-
? <img src={thumbnailUri} />
|
|
327
|
+
? <img src={thumbnailUri} alt={lf("Preview of your code running on the simulator")} aria-label={lf("Simulator preview")}/>
|
|
327
328
|
: <div className="project-thumbnail-placeholder">
|
|
328
329
|
<div className="common-spinner" />
|
|
329
330
|
</div>
|
|
@@ -406,6 +407,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
|
|
|
406
407
|
<div className="common-input-attached-button">
|
|
407
408
|
<Input
|
|
408
409
|
ariaDescribedBy="share-input-title"
|
|
410
|
+
ariaLabel={lf("Your shareable project link")}
|
|
409
411
|
handleInputRef={handleInputRef}
|
|
410
412
|
initialValue={shareData.url}
|
|
411
413
|
readOnly={true}
|
|
@@ -462,7 +464,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
|
|
|
462
464
|
className="menu-button project-qrcode"
|
|
463
465
|
buttonRef={handleQRCodeButtonRef}
|
|
464
466
|
title={lf("Show QR Code")}
|
|
465
|
-
label={<img className="qrcode-image" src={shareData?.qr} />}
|
|
467
|
+
label={<img className="qrcode-image" src={shareData?.qr} alt={lf("QR code to access your project")} aria-label={lf("Project share link QR code")}/>}
|
|
466
468
|
onClick={handleQRCodeClick}
|
|
467
469
|
/>
|
|
468
470
|
</div>
|
|
@@ -475,7 +477,8 @@ export const ShareInfo = (props: ShareInfoProps) => {
|
|
|
475
477
|
selected={embedOptions.findIndex(i => i.name === embedState)} />
|
|
476
478
|
<Textarea readOnly={true}
|
|
477
479
|
rows={5}
|
|
478
|
-
initialValue={shareData?.embed[embedState]}
|
|
480
|
+
initialValue={shareData?.embed[embedState]}
|
|
481
|
+
ariaLabel={lf("Embed code textarea")} />
|
|
479
482
|
</div>}
|
|
480
483
|
{kioskState &&
|
|
481
484
|
<div>
|
|
@@ -511,9 +514,9 @@ export const ShareInfo = (props: ShareInfoProps) => {
|
|
|
511
514
|
</div>
|
|
512
515
|
|
|
513
516
|
{showQRCode &&
|
|
514
|
-
<Modal title={lf("QR Code")} onClose={handleQRCodeModalClose}>
|
|
517
|
+
<Modal title={lf("QR Code")} onClose={handleQRCodeModalClose} ariaLabel={lf("QR Code modal")} >
|
|
515
518
|
<div className="qrcode-modal-body">
|
|
516
|
-
<img className="qrcode-image" src={shareData?.qr} />
|
|
519
|
+
<img className="qrcode-image" src={shareData?.qr} alt={lf("QR code to access your project")} aria-label={lf("Project share link QR code enlarged")} />
|
|
517
520
|
</div>
|
|
518
521
|
</Modal>
|
|
519
522
|
}
|
|
@@ -91,4 +91,25 @@ export function screenToSVGCoord(ref: SVGSVGElement, coord: ClientCoordinates) {
|
|
|
91
91
|
screenCoord.x = coord.clientX;
|
|
92
92
|
screenCoord.y = coord.clientY;
|
|
93
93
|
return screenCoord.matrixTransform(ref.getScreenCTM().inverse());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function findNextFocusableElement(elements: HTMLElement[], focusedIndex: number, index: number, forward: boolean, isFocusable?: (e: HTMLElement) => boolean): HTMLElement {
|
|
97
|
+
const increment = forward ? 1 : -1;
|
|
98
|
+
const element = elements[index];
|
|
99
|
+
// in this case, there are no focusable elements
|
|
100
|
+
if (focusedIndex === index) {
|
|
101
|
+
return element;
|
|
102
|
+
}
|
|
103
|
+
if (isFocusable ? isFocusable(element) : getComputedStyle(element).display !== "none") {
|
|
104
|
+
return element;
|
|
105
|
+
} else {
|
|
106
|
+
if (index + increment >= elements.length) {
|
|
107
|
+
index = 0;
|
|
108
|
+
} else if (index + increment < 0) {
|
|
109
|
+
index = elements.length - 1;
|
|
110
|
+
} else {
|
|
111
|
+
index += increment;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return findNextFocusableElement(elements, focusedIndex, index, forward);
|
|
94
115
|
}
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
* EditorToggle *
|
|
106
106
|
****************************************************/
|
|
107
107
|
|
|
108
|
-
@editorToggleBackgroundColor: rgba(52,73,94,.
|
|
108
|
+
@editorToggleBackgroundColor: rgba(52,73,94,.8);
|
|
109
109
|
@editorToggleBorderColor: rgba(52,73,94,.2);
|
|
110
110
|
@editorToggleBorderWidth: 3px;
|
|
111
111
|
|
|
@@ -150,6 +150,7 @@
|
|
|
150
150
|
margin-top: 1rem;
|
|
151
151
|
position: relative;
|
|
152
152
|
margin-bottom: 2rem;
|
|
153
|
+
justify-content: space-between;
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
.project-share-social {
|
|
@@ -312,6 +313,12 @@
|
|
|
312
313
|
.gif-recorder-content .thumbnail-controls {
|
|
313
314
|
padding: 0 2rem;
|
|
314
315
|
}
|
|
316
|
+
|
|
317
|
+
.common-button.square-button.embed.gray.mobile-portrait-hidden {
|
|
318
|
+
// important is need for color to override semantic ui's use of important
|
|
319
|
+
color: #323130 !important;
|
|
320
|
+
background: #e0e1e2;
|
|
321
|
+
}
|
|
315
322
|
}
|
|
316
323
|
|
|
317
324
|
@media @mobileAndBelow {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/blb/semantic.css">
|
|
10
10
|
<link rel="stylesheet" href="/blb/icons.css">
|
|
11
11
|
<link rel="stylesheet" href="/blb/react-common-multiplayer.css">
|
|
12
|
-
<script defer="defer" src="/blb/multiplayer/js/main.
|
|
12
|
+
<script defer="defer" src="/blb/multiplayer/js/main.121cfaf0.js"></script><link href="/blb/multiplayer/css/main.2a6ba47d.css" rel="stylesheet"></head>
|
|
13
13
|
<body>
|
|
14
14
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
15
15
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/blb/semantic.css">
|
|
8
8
|
<link rel="stylesheet" href="/blb/icons.css">
|
|
9
9
|
<link rel="stylesheet" href="/blb/react-common-skillmap.css">
|
|
10
|
-
<script defer="defer" src="/blb/skillmap/js/main.
|
|
10
|
+
<script defer="defer" src="/blb/skillmap/js/main.e95746dc.js"></script><link href="/blb/skillmap/css/main.3c703680.css" rel="stylesheet"></head>
|
|
11
11
|
<body>
|
|
12
12
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
13
13
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<!-- <link rel="manifest" href="/teachertool-data/manifest.json" /> -->
|
|
17
17
|
<title>MakeCode Teacher Tool</title>
|
|
18
18
|
<script>var pxtConfig=null</script>
|
|
19
|
-
<script defer="defer" src="/blb/teachertool/js/main.
|
|
19
|
+
<script defer="defer" src="/blb/teachertool/js/main.b94a6d6a.js"></script><link href="/blb/teachertool/css/main.00de32e9.css" rel="stylesheet"></head>
|
|
20
20
|
<body>
|
|
21
21
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
22
22
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<!-- <link rel="manifest" href="/tutorialtool-data/manifest.json" /> -->
|
|
18
18
|
<title>MakeCode Tutorial Tool</title>
|
|
19
19
|
<script>var pxtConfig=null</script>
|
|
20
|
-
<script defer="defer" src="/blb/tutorialtool/js/main.
|
|
20
|
+
<script defer="defer" src="/blb/tutorialtool/js/main.03b71032.js"></script><link href="/blb/tutorialtool/css/main.02bb1797.css" rel="stylesheet"></head>
|
|
21
21
|
|
|
22
22
|
<body>
|
|
23
23
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|