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.
@@ -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 auto
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pxt-core",
3
- "version": "7.5.36",
3
+ "version": "7.5.39",
4
4
  "description": "Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors",
5
5
  "keywords": [
6
6
  "TypeScript",
@@ -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;
@@ -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() {