pxt-core 7.5.36 → 7.5.39
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 +8 -7
- package/built/pxtlib.js +5 -3
- package/built/pxtrunner.d.ts +0 -1
- package/built/pxtrunner.js +1 -2
- package/built/pxtsim.d.ts +0 -1
- package/built/pxtsim.js +3 -4
- package/built/target.js +1 -1
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtembed.js +2 -2
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtrunner.js +1 -1
- package/built/web/pxtsim.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/react-common-authcode.css +140 -0
- package/built/web/react-common-skillmap.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/localtypings/pxtarget.d.ts +2 -2
- package/package.json +1 -1
- package/react-common/components/controls/Card.tsx +48 -0
- package/react-common/components/controls/LazyImage.tsx +82 -0
- package/react-common/components/extensions/ExtensionCard.tsx +70 -0
- package/react-common/styles/controls/Button.less +6 -0
- package/react-common/styles/controls/Card.less +53 -0
- package/react-common/styles/controls/LazyImage.less +29 -0
- package/react-common/styles/extensions/ExtensionCard.less +82 -0
- package/react-common/styles/react-common.less +3 -0
- package/theme/common.less +8 -0
- package/webapp/public/run.html +1 -4
|
@@ -835,7 +835,7 @@ declare namespace ts.pxtc {
|
|
|
835
835
|
mutatePrefix?: string;
|
|
836
836
|
mutateDefaults?: string;
|
|
837
837
|
mutatePropertyEnum?: string;
|
|
838
|
-
inlineInputMode?: string; // can be inline, external, or
|
|
838
|
+
inlineInputMode?: string; // can be inline (horizontal), external (vertical), auto (default), or variable (based off currently expanded number of params)
|
|
839
839
|
expandableArgumentMode?: string; // can be disabled, enabled, or toggle
|
|
840
840
|
compileHiddenArguments?: boolean; // if true, compiles the values in expandable arguments even when collapsed
|
|
841
841
|
draggableParameters?: string; // can be reporter or variable; defaults to variable
|
|
@@ -1192,4 +1192,4 @@ declare namespace pxt.auth {
|
|
|
1192
1192
|
type: "skillmap-completion";
|
|
1193
1193
|
sourceURL: string;
|
|
1194
1194
|
}
|
|
1195
|
-
}
|
|
1195
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { classList, ContainerProps, fireClickOnEnter } from "../util";
|
|
3
|
+
|
|
4
|
+
export interface CardProps extends ContainerProps {
|
|
5
|
+
onClick?: () => void;
|
|
6
|
+
tabIndex?: number;
|
|
7
|
+
ariaLabelledBy?: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
labelClass?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Card = (props: CardProps) => {
|
|
13
|
+
const {
|
|
14
|
+
id,
|
|
15
|
+
className,
|
|
16
|
+
role,
|
|
17
|
+
children,
|
|
18
|
+
ariaDescribedBy,
|
|
19
|
+
ariaLabelledBy,
|
|
20
|
+
ariaHidden,
|
|
21
|
+
ariaLabel,
|
|
22
|
+
onClick,
|
|
23
|
+
label,
|
|
24
|
+
labelClass,
|
|
25
|
+
tabIndex
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
return <div
|
|
29
|
+
id={id}
|
|
30
|
+
className={classList("common-card", className)}
|
|
31
|
+
role={role || (onClick ? "button" : undefined)}
|
|
32
|
+
aria-describedby={ariaDescribedBy}
|
|
33
|
+
aria-labelledby={ariaLabelledBy}
|
|
34
|
+
aria-hidden={ariaHidden}
|
|
35
|
+
aria-label={ariaLabel}
|
|
36
|
+
onClick={onClick}
|
|
37
|
+
tabIndex={tabIndex}
|
|
38
|
+
onKeyDown={fireClickOnEnter}>
|
|
39
|
+
<div className="common-card-body">
|
|
40
|
+
{children}
|
|
41
|
+
</div>
|
|
42
|
+
{label &&
|
|
43
|
+
<label className={classList("common-card-label", labelClass)}>
|
|
44
|
+
{label}
|
|
45
|
+
</label>
|
|
46
|
+
}
|
|
47
|
+
</div>
|
|
48
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ControlProps } from "../util";
|
|
3
|
+
|
|
4
|
+
export interface LazyImageProps extends ControlProps {
|
|
5
|
+
src: string;
|
|
6
|
+
alt: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let observer: IntersectionObserver;
|
|
11
|
+
|
|
12
|
+
export const LazyImage = (props: LazyImageProps) => {
|
|
13
|
+
const {
|
|
14
|
+
id,
|
|
15
|
+
className,
|
|
16
|
+
role,
|
|
17
|
+
src,
|
|
18
|
+
alt,
|
|
19
|
+
title,
|
|
20
|
+
ariaLabel,
|
|
21
|
+
ariaHidden,
|
|
22
|
+
ariaDescribedBy,
|
|
23
|
+
} = props;
|
|
24
|
+
|
|
25
|
+
initObserver();
|
|
26
|
+
|
|
27
|
+
let imageRef: HTMLImageElement;
|
|
28
|
+
|
|
29
|
+
const handleImageRef = (ref: HTMLImageElement) => {
|
|
30
|
+
if (!ref) return;
|
|
31
|
+
|
|
32
|
+
if (imageRef) observer.unobserve(imageRef);
|
|
33
|
+
imageRef = ref;
|
|
34
|
+
observer.observe(ref);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
return <div className="common-lazy-image-wrapper">
|
|
40
|
+
<img
|
|
41
|
+
id={id}
|
|
42
|
+
ref={handleImageRef}
|
|
43
|
+
className={className}
|
|
44
|
+
data-src={src}
|
|
45
|
+
alt={alt}
|
|
46
|
+
title={title}
|
|
47
|
+
role={role}
|
|
48
|
+
aria-label={ariaLabel}
|
|
49
|
+
aria-hidden={ariaHidden}
|
|
50
|
+
aria-describedby={ariaDescribedBy}
|
|
51
|
+
/>
|
|
52
|
+
<div className="common-spinner" />
|
|
53
|
+
</div>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function initObserver() {
|
|
57
|
+
if (observer) return;
|
|
58
|
+
|
|
59
|
+
const config = {
|
|
60
|
+
// If the image gets within 50px in the Y axis, start the download.
|
|
61
|
+
rootMargin: '50px 0px',
|
|
62
|
+
threshold: 0.01
|
|
63
|
+
};
|
|
64
|
+
const onIntersection: IntersectionObserverCallback = (entries) => {
|
|
65
|
+
entries.forEach(entry => {
|
|
66
|
+
// Are we in viewport?
|
|
67
|
+
if (entry.intersectionRatio > 0) {
|
|
68
|
+
// Stop watching and load the image
|
|
69
|
+
observer.unobserve(entry.target);
|
|
70
|
+
const url = entry.target.getAttribute("data-src");
|
|
71
|
+
(entry.target as HTMLImageElement).src = url;
|
|
72
|
+
|
|
73
|
+
const image = entry.target as HTMLImageElement;
|
|
74
|
+
image.src = url;
|
|
75
|
+
image.onload = () => {
|
|
76
|
+
image.parentElement.classList.add("loaded");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
observer = new IntersectionObserver(onIntersection, config);
|
|
82
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Button } from "../controls/Button";
|
|
3
|
+
import { Card } from "../controls/Card";
|
|
4
|
+
import { LazyImage } from "../controls/LazyImage";
|
|
5
|
+
import { classList } from "../util";
|
|
6
|
+
|
|
7
|
+
export interface ExtensionCardProps<U> {
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
imageUrl?: string;
|
|
11
|
+
learnMoreUrl?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
onClick?: (value: U) => void;
|
|
14
|
+
extension?: U;
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ExtensionCard = <U,>(props: ExtensionCardProps<U>) => {
|
|
19
|
+
const {
|
|
20
|
+
title,
|
|
21
|
+
description,
|
|
22
|
+
imageUrl,
|
|
23
|
+
learnMoreUrl,
|
|
24
|
+
label,
|
|
25
|
+
onClick,
|
|
26
|
+
extension,
|
|
27
|
+
loading
|
|
28
|
+
} = props;
|
|
29
|
+
|
|
30
|
+
const onCardClick = () => {
|
|
31
|
+
if (onClick) onClick(extension);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const id = pxt.Util.guidGen();
|
|
35
|
+
|
|
36
|
+
return <>
|
|
37
|
+
<Card
|
|
38
|
+
className={classList("common-extension-card", loading && "loading")}
|
|
39
|
+
onClick={onCardClick}
|
|
40
|
+
ariaLabelledBy={id + "-title"}
|
|
41
|
+
ariaDescribedBy={id + "-description"}
|
|
42
|
+
tabIndex={onClick && 0}
|
|
43
|
+
label={label}>
|
|
44
|
+
<div className="common-extension-card-contents">
|
|
45
|
+
{!loading && <>
|
|
46
|
+
<LazyImage src={imageUrl} alt={title} />
|
|
47
|
+
<div className="common-extension-card-title" id={id + "-title"}>
|
|
48
|
+
{title}
|
|
49
|
+
</div>
|
|
50
|
+
<div className="common-extension-card-description">
|
|
51
|
+
<div id={id + "-description"}>
|
|
52
|
+
{description}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
{learnMoreUrl &&
|
|
56
|
+
<Button
|
|
57
|
+
className="link-button"
|
|
58
|
+
label={lf("Learn More")}
|
|
59
|
+
title={lf("Learn More")}
|
|
60
|
+
onClick={() => {}}
|
|
61
|
+
href={learnMoreUrl}
|
|
62
|
+
/>
|
|
63
|
+
}
|
|
64
|
+
</>
|
|
65
|
+
}
|
|
66
|
+
</div>
|
|
67
|
+
<div className="common-spinner"/>
|
|
68
|
+
</Card>
|
|
69
|
+
</>
|
|
70
|
+
}
|
|
@@ -223,6 +223,12 @@
|
|
|
223
223
|
text-decoration: underline;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
.common-button.link-button:focus {
|
|
227
|
+
outline: none;
|
|
228
|
+
border: none;
|
|
229
|
+
text-decoration: underline;
|
|
230
|
+
}
|
|
231
|
+
|
|
226
232
|
/****************************************************
|
|
227
233
|
* Circle Buttons *
|
|
228
234
|
****************************************************/
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.common-card {
|
|
2
|
+
width: 18rem;
|
|
3
|
+
height: 20rem;
|
|
4
|
+
border-radius: 0.5rem;
|
|
5
|
+
border: 1px solid @inputBorderColor;
|
|
6
|
+
transition: border 0.1s ease;
|
|
7
|
+
position: relative;
|
|
8
|
+
|
|
9
|
+
.common-card-body {
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
border-radius: 0.5rem;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.common-card[role="button"] {
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
border: 1px solid @inputBorderColorFocus;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.common-card-label {
|
|
24
|
+
color: @white;
|
|
25
|
+
background-color: @orange;
|
|
26
|
+
|
|
27
|
+
border-top-left-radius: 0.25rem;
|
|
28
|
+
border-bottom-left-radius: 0.25rem;
|
|
29
|
+
|
|
30
|
+
position: absolute;
|
|
31
|
+
top: 1rem;
|
|
32
|
+
right: -1rem;
|
|
33
|
+
|
|
34
|
+
padding: 0.5rem 0.5rem 0.25rem 0.5rem;
|
|
35
|
+
min-width: 5rem;
|
|
36
|
+
font-size: 16px;
|
|
37
|
+
border-color: darken(@orange, 10%);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.common-card-label::after {
|
|
41
|
+
position: absolute;
|
|
42
|
+
content: "";
|
|
43
|
+
top: 100%;
|
|
44
|
+
left: auto;
|
|
45
|
+
right: 0;
|
|
46
|
+
background-color: transparent;
|
|
47
|
+
border-color: transparent;
|
|
48
|
+
border-style: solid;
|
|
49
|
+
border-width: 1.2em 1.2em 0 0;
|
|
50
|
+
border-top-color: inherit;
|
|
51
|
+
width: 0;
|
|
52
|
+
height: 0;
|
|
53
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.common-lazy-image-wrapper {
|
|
2
|
+
display: flex;
|
|
3
|
+
justify-content: center;
|
|
4
|
+
align-items: center;
|
|
5
|
+
|
|
6
|
+
.common-spinner {
|
|
7
|
+
position: absolute;
|
|
8
|
+
width: 60px;
|
|
9
|
+
height: 60px;
|
|
10
|
+
|
|
11
|
+
opacity: 1;
|
|
12
|
+
transition: opacity 0.3s ease;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
img {
|
|
16
|
+
opacity: 0;
|
|
17
|
+
transition: opacity 0.3s ease;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.common-lazy-image-wrapper.loaded {
|
|
22
|
+
.common-spinner {
|
|
23
|
+
opacity: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
img {
|
|
27
|
+
opacity: 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
.common-extension-card {
|
|
2
|
+
background-color: @white;
|
|
3
|
+
|
|
4
|
+
.common-card-body {
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
height: 100%;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.common-extension-card-title {
|
|
13
|
+
font-weight: 600;
|
|
14
|
+
font-size: 18px;
|
|
15
|
+
padding: 0.5rem 1rem 0.25rem 1rem;
|
|
16
|
+
text-overflow: ellipsis;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
flex-shrink: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.common-extension-card-description {
|
|
22
|
+
flex-grow: 1;
|
|
23
|
+
padding-left: 1rem;
|
|
24
|
+
padding-right: 1rem;
|
|
25
|
+
font-size: 16px;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
|
|
28
|
+
div {
|
|
29
|
+
text-overflow: ellipsis;
|
|
30
|
+
display: -webkit-box;
|
|
31
|
+
-webkit-box-orient: vertical;
|
|
32
|
+
-webkit-line-clamp: 3;
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
img {
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 11rem;
|
|
40
|
+
object-fit: cover;
|
|
41
|
+
flex-shrink: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.common-button.link-button {
|
|
45
|
+
text-align: right;
|
|
46
|
+
padding: 0.5rem 1rem;
|
|
47
|
+
background: @white;
|
|
48
|
+
margin: 0;
|
|
49
|
+
border-radius: 0;
|
|
50
|
+
border-top: solid 1px @inputBorderColor;
|
|
51
|
+
flex-shrink: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.common-extension-card-contents {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
height: 100%;
|
|
58
|
+
width: 100%;
|
|
59
|
+
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transition: opacity 0.3s ease;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.common-spinner {
|
|
65
|
+
opacity: 0;
|
|
66
|
+
transition: opacity 0.3s ease;
|
|
67
|
+
|
|
68
|
+
position: absolute;
|
|
69
|
+
width: 60px;
|
|
70
|
+
height: 60px;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.common-extension-card.loading {
|
|
75
|
+
.common-extension-card-contents {
|
|
76
|
+
opacity: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.common-spinner {
|
|
80
|
+
opacity: 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
@import "profile/profile.less";
|
|
2
2
|
@import "share/share.less";
|
|
3
|
+
@import "extensions/ExtensionCard.less";
|
|
3
4
|
@import "controls/Button.less";
|
|
5
|
+
@import "controls/Card.less";
|
|
4
6
|
@import "controls/Checkbox.less";
|
|
5
7
|
@import "controls/DraggableGraph.less";
|
|
6
8
|
@import "controls/Dropdown.less";
|
|
7
9
|
@import "controls/EditorToggle.less";
|
|
8
10
|
@import "controls/Icon.less";
|
|
9
11
|
@import "controls/Input.less";
|
|
12
|
+
@import "controls/LazyImage.less";
|
|
10
13
|
@import "controls/MenuDropdown.less";
|
|
11
14
|
@import "controls/Modal.less";
|
|
12
15
|
@import "controls/RadioButtonGroup.less";
|
package/theme/common.less
CHANGED
|
@@ -1142,6 +1142,14 @@ Field editors
|
|
|
1142
1142
|
}
|
|
1143
1143
|
}
|
|
1144
1144
|
}
|
|
1145
|
+
|
|
1146
|
+
.extension-cards {
|
|
1147
|
+
display: grid;
|
|
1148
|
+
grid-template-columns: repeat(auto-fit, 18rem);
|
|
1149
|
+
gap: 1rem;
|
|
1150
|
+
width: 100%;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1145
1153
|
.import-extension-modal {
|
|
1146
1154
|
.common-modal-body {
|
|
1147
1155
|
display: flex;
|
package/webapp/public/run.html
CHANGED
|
@@ -106,7 +106,6 @@
|
|
|
106
106
|
var localToken = /local_token(?:[:=])([^&?]+)/i.exec(window.location.href);
|
|
107
107
|
var hex = !!/hex(?:[:=])1/i.exec(window.location.href);
|
|
108
108
|
var footer = !/nofooter(?:[:=])1/i.exec(window.location.href);
|
|
109
|
-
var hideSimButtons = !!/hidesimbuttons(?:[:=])1/i.exec(window.location.href);
|
|
110
109
|
var debugSim = !!/debugSim(?:[:=])1/i.exec(window.location.href);
|
|
111
110
|
var sims = document.getElementById('simulators');
|
|
112
111
|
var highContrast = !!/hc(?:[:=])1/i.exec(window.location.href);
|
|
@@ -181,7 +180,6 @@
|
|
|
181
180
|
code: files["main.ts"],
|
|
182
181
|
assets: JSON.stringify(files),
|
|
183
182
|
dependencies: Object.keys(deps).map(v => v + "=" + deps[v]),
|
|
184
|
-
hideSimButtons: hideSimButtons,
|
|
185
183
|
highContrast: highContrast,
|
|
186
184
|
light: light,
|
|
187
185
|
fullScreen: fullScreen,
|
|
@@ -241,8 +239,7 @@
|
|
|
241
239
|
fullScreen: fullScreen,
|
|
242
240
|
dependencies: deps ? decodeURIComponent(deps[1]).split(",") : undefined,
|
|
243
241
|
builtJsInfo: builtSimJs,
|
|
244
|
-
single: single
|
|
245
|
-
hideSimButtons: hideSimButtons
|
|
242
|
+
single: single
|
|
246
243
|
};
|
|
247
244
|
console.log('simulating script')
|
|
248
245
|
pxt.runner.simulateAsync(sims, options).then(function() {
|