pxt-core 13.2.3 → 13.2.4

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.
Files changed (30) hide show
  1. package/built/pxtblocks/fields/field_dropdown.d.ts +1 -0
  2. package/built/react-common/components/theming/SimulatorThemePickerModal.d.ts +1 -0
  3. package/built/react-common/components/theming/ThemePickerModal.d.ts +1 -0
  4. package/built/react-common/components/theming/themeReset.d.ts +2 -0
  5. package/built/react-common/components/theming/useThemeReset.d.ts +6 -0
  6. package/built/target.js +1 -1
  7. package/built/targetlight.js +1 -1
  8. package/built/tests/blocksrunner.js +23 -6
  9. package/built/tests/blockssetup.js +23 -6
  10. package/built/web/main.js +30 -30
  11. package/built/web/pxtasseteditor.js +1 -1
  12. package/built/web/pxtembed.js +1 -1
  13. package/built/web/react-common-authcode.css +1 -1
  14. package/built/web/react-common-multiplayer.css +1 -1
  15. package/built/web/react-common-skillmap.css +1 -1
  16. package/built/web/rtlreact-common-authcode.css +1 -1
  17. package/built/web/rtlreact-common-multiplayer.css +1 -1
  18. package/built/web/rtlreact-common-skillmap.css +1 -1
  19. package/built/web/rtlsemantic.css +1 -1
  20. package/built/web/runnerembed.js +1 -1
  21. package/built/web/semantic.css +1 -1
  22. package/built/web/skillmap/js/{main.6352b119.js → main.99d90503.js} +2 -2
  23. package/package.json +1 -1
  24. package/react-common/components/theming/SimulatorThemePickerModal.tsx +16 -1
  25. package/react-common/components/theming/ThemePickerModal.tsx +6 -1
  26. package/react-common/components/theming/themeReset.ts +16 -0
  27. package/react-common/components/theming/useThemeReset.tsx +67 -0
  28. package/react-common/styles/theming/ThemePickerModal.less +74 -9
  29. package/theme/common.less +13 -0
  30. package/webapp/public/skillmap.html +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pxt-core",
3
- "version": "13.2.3",
3
+ "version": "13.2.4",
4
4
  "description": "Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors",
5
5
  "keywords": [
6
6
  "TypeScript",
@@ -4,6 +4,7 @@ import { Input } from "../controls/Input";
4
4
  import { Modal } from "../controls/Modal";
5
5
  import { copySimulatorTheme, getSimulatorThemeForLayout } from "./simulatorThemeDefaults";
6
6
  import { ThemePickerToggle } from "./ThemePickerModal";
7
+ import { useThemeReset } from "./useThemeReset";
7
8
 
8
9
  export interface SimulatorThemePickerModalProps {
9
10
  presets: pxt.SimulatorThemePreset[];
@@ -16,6 +17,7 @@ export interface SimulatorThemePickerModalProps {
16
17
  onUseAccountTheme?: () => void | Promise<void>;
17
18
  onThemeChanged?: (preference: pxt.auth.SimulatorThemePreference) => void;
18
19
  onSave: (preference: pxt.auth.SimulatorThemePreference) => void | Promise<void>;
20
+ onReset?: () => Promise<void>;
19
21
  onClose: () => void;
20
22
  }
21
23
 
@@ -59,8 +61,17 @@ export const SimulatorThemePickerModal = (props: SimulatorThemePickerModalProps)
59
61
  onUseAccountTheme,
60
62
  onThemeChanged,
61
63
  onSave,
64
+ onReset,
62
65
  onClose,
63
66
  } = props;
67
+ const aspectRatio = pxt.appTarget.simulator?.aspectRatio || 1.22;
68
+ const previewStyle: React.CSSProperties & {
69
+ "--simulator-theme-aspect-ratio": number;
70
+ "--simulator-theme-padding-bottom": string;
71
+ } = {
72
+ "--simulator-theme-aspect-ratio": aspectRatio,
73
+ "--simulator-theme-padding-bottom": `${100 / aspectRatio}%`,
74
+ };
64
75
  const defaultColorFields = getDefaultColorFields(presets[0].theme);
65
76
  const getColorFields = (layoutId: string) => {
66
77
  const fields = layouts?.find(layout => layout.id === layoutId)?.colorFields;
@@ -93,6 +104,7 @@ export const SimulatorThemePickerModal = (props: SimulatorThemePickerModalProps)
93
104
  const layoutId = theme.layout;
94
105
  const layoutIsKnown = layoutId === pxt.auth.DEFAULT_SIMULATOR_LAYOUT || layouts?.some(layout => layout.id === layoutId);
95
106
  const colorFields = getColorFields(layoutId);
107
+ const { resetAction, confirmation } = useThemeReset("simulator-theme-picker-modal", onReset);
96
108
 
97
109
  const selectPreset = (id: string) => {
98
110
  if (id === ACCOUNT_PRESET_ID && onUseAccountTheme) {
@@ -133,6 +145,8 @@ export const SimulatorThemePickerModal = (props: SimulatorThemePickerModalProps)
133
145
  onThemeChanged?.({ presetId: CUSTOM_PRESET_ID, theme: nextTheme });
134
146
  };
135
147
 
148
+ if (confirmation) return confirmation;
149
+
136
150
  return <Modal
137
151
  id="simulator-theme-picker-modal"
138
152
  title={lf("Simulator Theme")}
@@ -143,6 +157,7 @@ export const SimulatorThemePickerModal = (props: SimulatorThemePickerModalProps)
143
157
  selected="simulator"
144
158
  onModeChanged={onEditorThemeClicked} />}
145
159
  actions={[
160
+ ...(resetAction ? [resetAction] : []),
146
161
  {
147
162
  label: lf("Apply"),
148
163
  className: "primary",
@@ -151,7 +166,7 @@ export const SimulatorThemePickerModal = (props: SimulatorThemePickerModalProps)
151
166
  : onSave({ presetId, theme }),
152
167
  },
153
168
  ]}>
154
- <div className="simulator-theme-picker">
169
+ <div className="simulator-theme-picker" style={previewStyle}>
155
170
  {renderPreview(theme)}
156
171
  <div className="simulator-theme-controls">
157
172
  <div className="simulator-theme-select-field">
@@ -2,6 +2,7 @@ import * as React from "react";
2
2
  import { Modal } from "../controls/Modal";
3
3
  import { EditorToggle } from "../controls/EditorToggle";
4
4
  import { ThemeCard } from "./ThemeCard";
5
+ import { useThemeReset } from "./useThemeReset";
5
6
 
6
7
  export type ThemePickerMode = "editor" | "simulator";
7
8
 
@@ -45,6 +46,7 @@ export interface ThemePickerModalProps {
45
46
  selectedThemeId?: string;
46
47
  onThemeChanged: (theme: pxt.ColorThemeInfo) => void;
47
48
  onSave: (theme: pxt.ColorThemeInfo) => void;
49
+ onReset?: () => Promise<void>;
48
50
  onSimulatorThemeClicked?: () => void;
49
51
  onClose(): void;
50
52
  }
@@ -53,6 +55,9 @@ export const ThemePickerModal = (props: ThemePickerModalProps) => {
53
55
  props.selectedThemeId || props.themes[0]?.id
54
56
  );
55
57
  const selectedTheme = props.themes.find(theme => theme.id === selectedThemeId);
58
+ const { resetAction, confirmation } = useThemeReset("theme-picker-modal", props.onReset);
59
+
60
+ if (confirmation) return confirmation;
56
61
 
57
62
  return (
58
63
  <Modal
@@ -64,7 +69,7 @@ export const ThemePickerModal = (props: ThemePickerModalProps) => {
64
69
  rightHeader={props.onSimulatorThemeClicked && <ThemePickerToggle
65
70
  selected="editor"
66
71
  onModeChanged={props.onSimulatorThemeClicked} />}
67
- actions={[{
72
+ actions={[...(resetAction ? [resetAction] : []), {
68
73
  label: lf("Apply"),
69
74
  className: "primary",
70
75
  disabled: !selectedTheme,
@@ -0,0 +1,16 @@
1
+ import { getDefaultSimulatorThemePreference } from "./simulatorThemeDefaults";
2
+
3
+ /** Reset this editor's preferences only. */
4
+ export async function resetEditorThemesAsync(
5
+ target: Pick<pxt.TargetBundle, "appTheme" | "colorThemeMap" | "simulator">,
6
+ saveColorTheme: (theme: pxt.ColorThemeInfo) => Promise<void>,
7
+ clearSimulatorTheme: () => Promise<void>
8
+ ): Promise<pxt.auth.SimulatorThemePreference | undefined> {
9
+ const defaultThemeId = target.appTheme?.defaultColorTheme;
10
+ const defaultTheme = defaultThemeId ? target.colorThemeMap?.[defaultThemeId] : undefined;
11
+ if (!defaultTheme) throw new Error("No default editor theme configured");
12
+
13
+ await saveColorTheme(defaultTheme);
14
+ await clearSimulatorTheme();
15
+ return getDefaultSimulatorThemePreference(defaultTheme, target.simulator?.themePresets);
16
+ }
@@ -0,0 +1,67 @@
1
+ import * as React from "react";
2
+ import { Modal, ModalAction } from "../controls/Modal";
3
+
4
+ /** Shared confirmation for editor-wide pickers, not project-specific theme settings. */
5
+ export function useThemeReset(pickerId: string, onReset: (() => Promise<void>) | undefined) {
6
+ const [confirming, setConfirming] = React.useState(false);
7
+ const [resetting, setResetting] = React.useState(false);
8
+ const [failed, setFailed] = React.useState(false);
9
+ const inFlight = React.useRef(false);
10
+ const restoreFocus = React.useRef(false);
11
+
12
+ React.useEffect(() => {
13
+ if (!confirming && restoreFocus.current) {
14
+ document.getElementById(pickerId)?.querySelector<HTMLElement>(".theme-reset-button")?.focus();
15
+ restoreFocus.current = false;
16
+ }
17
+ }, [confirming, pickerId]);
18
+
19
+ const cancel = () => {
20
+ if (inFlight.current) return;
21
+ restoreFocus.current = true;
22
+ setConfirming(false);
23
+ };
24
+
25
+ const confirm = async () => {
26
+ if (!onReset || inFlight.current) return;
27
+ inFlight.current = true;
28
+ setResetting(true);
29
+ setFailed(false);
30
+ try {
31
+ await onReset();
32
+ } catch (error) {
33
+ pxt.reportException(error);
34
+ setFailed(true);
35
+ } finally {
36
+ inFlight.current = false;
37
+ setResetting(false);
38
+ }
39
+ };
40
+
41
+ const resetAction: ModalAction | undefined = onReset ? {
42
+ label: lf("Reset"),
43
+ className: "primary inverted theme-reset-button",
44
+ onClick: () => {
45
+ setFailed(false);
46
+ setConfirming(true);
47
+ },
48
+ } : undefined;
49
+
50
+ const confirmation = confirming && <Modal
51
+ key="theme-reset-confirmation"
52
+ title={lf("Reset all themes?")}
53
+ ariaDescribedBy="theme-reset-description"
54
+ onClose={cancel}
55
+ hideDismissButton={resetting}
56
+ actions={[
57
+ { label: lf("Cancel"), onClick: cancel, disabled: resetting },
58
+ { label: resetting ? lf("Resetting...") : lf("Reset"), className: "primary", onClick: confirm, disabled: resetting },
59
+ ]}>
60
+ <p id="theme-reset-description">
61
+ {lf("Are you sure you want to reset the editor and simulator themes to their defaults? This will remove your editor-wide theme customizations. Themes set directly on projects will not be changed. This action cannot be undone.")}
62
+ </p>
63
+ {failed && <p role="alert">{lf("Unable to reset themes. Please try again.")}</p>}
64
+ </Modal>;
65
+
66
+ return { resetAction, confirmation };
67
+ }
@@ -19,6 +19,10 @@
19
19
  .common-modal-footer {
20
20
  grid-template-columns: 1fr auto;
21
21
 
22
+ .theme-reset-button {
23
+ justify-self: start;
24
+ }
25
+
22
26
  button:only-child {
23
27
  justify-self: end;
24
28
  min-width: 8rem;
@@ -27,7 +31,7 @@
27
31
  }
28
32
 
29
33
  .theme-picker-modal>.common-modal,
30
- .simulator-theme-picker-modal:not(.standalone)>.common-modal {
34
+ .simulator-theme-picker-modal>.common-modal {
31
35
  height: 90%;
32
36
  max-height: 48rem;
33
37
  display: flex;
@@ -70,30 +74,78 @@
70
74
  padding-left: 1.5rem;
71
75
  }
72
76
 
77
+ .simulator-theme-picker-modal>.common-modal {
78
+ overflow: hidden;
79
+
80
+ .common-modal-body {
81
+ display: flex;
82
+ overflow: hidden;
83
+ }
84
+
85
+ .common-modal-footer {
86
+ flex-shrink: 0;
87
+ }
88
+ }
89
+
73
90
  .simulator-theme-picker {
91
+ flex: 1;
92
+ min-width: 0;
93
+ min-height: 0;
74
94
  display: grid;
75
- grid-template-columns: minmax(18rem, 1fr) minmax(18rem, 1fr);
95
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
96
+ grid-template-rows: minmax(0, 1fr);
76
97
  gap: 2rem;
77
- align-items: center;
98
+ align-items: stretch;
78
99
  }
79
100
 
80
101
  .simulator-theme-preview {
102
+ position: relative;
81
103
  min-width: 0;
104
+ min-height: 0;
82
105
 
83
106
  .simframe {
84
107
  margin: 0;
85
108
  }
86
109
 
110
+ .simframe.ui.embed {
111
+ // Fresh homescreen/skillmap frames have no inline ratio from the simulator driver.
112
+ padding-bottom: var(--simulator-theme-padding-bottom);
113
+ }
114
+
87
115
  .simframe > .ui.loader {
88
116
  display: none;
89
117
  }
90
118
  }
91
119
 
120
+ @media only screen and (min-width: 50.001rem) {
121
+ .simulator-theme-preview .simframe.ui.embed {
122
+ // Cap the viewport at the target's default ratio, even in a short pane.
123
+ // If width is constrained further, the simulator centers itself within the taller viewport.
124
+ // Override the driver's inline padding ratio only while inside the desktop picker.
125
+ position: absolute;
126
+ inset: 0;
127
+ margin: auto;
128
+ width: auto;
129
+ max-width: 100%;
130
+ height: 100%;
131
+ aspect-ratio: var(--simulator-theme-aspect-ratio);
132
+ padding-bottom: 0 !important;
133
+ }
134
+ }
135
+
92
136
  .simulator-theme-controls {
93
137
  display: flex;
94
138
  flex-direction: column;
95
139
  gap: 0.75rem;
96
140
  min-width: 0;
141
+ min-height: 0;
142
+ overflow-y: auto;
143
+ // Leave room for focus outlines inside the independently scrolling controls.
144
+ padding: 0.25rem;
145
+ scrollbar-gutter: stable;
146
+ > * {
147
+ flex-shrink: 0;
148
+ }
97
149
  }
98
150
 
99
151
  .simulator-theme-select-field {
@@ -128,10 +180,14 @@
128
180
 
129
181
  .simulator-theme-color {
130
182
  display: grid;
131
- grid-template-columns: minmax(7rem, 1fr) 3rem minmax(8rem, 1fr);
183
+ grid-template-columns: minmax(0, 1fr) 3rem minmax(0, 1fr);
132
184
  gap: 0.5rem;
133
185
  align-items: center;
134
186
 
187
+ > span {
188
+ overflow-wrap: anywhere;
189
+ }
190
+
135
191
  .common-input-wrapper {
136
192
  min-width: 0;
137
193
  }
@@ -173,18 +229,27 @@
173
229
  }
174
230
 
175
231
  .simulator-theme-picker {
232
+ flex: none;
233
+ width: 100%;
176
234
  grid-template-columns: 1fr;
235
+ grid-template-rows: auto;
236
+ }
237
+
238
+ .simulator-theme-picker-modal>.common-modal .common-modal-body {
239
+ display: block;
240
+ overflow-y: auto;
241
+ }
242
+
243
+ .simulator-theme-controls {
244
+ overflow: visible;
245
+ scrollbar-gutter: auto;
177
246
  }
178
247
 
179
248
  .simulator-theme-preview {
180
- max-width: 28rem;
181
249
  width: 100%;
250
+ max-width: 28rem;
182
251
  justify-self: center;
183
252
  }
184
-
185
- .simulator-theme-color {
186
- grid-template-columns: minmax(5.5rem, 1fr) 3rem minmax(6.5rem, 1fr);
187
- }
188
253
  }
189
254
 
190
255
  .theme-picker {
package/theme/common.less CHANGED
@@ -952,6 +952,19 @@ Avatar
952
952
  width: 0;
953
953
  }
954
954
 
955
+ .common-menu-dropdown-pane li.common-menu-dropdown-item.common-button.github-menuitem {
956
+ padding: 8px 18px;
957
+
958
+ .avatar img {
959
+ position: relative;
960
+ left: -0.25em;
961
+ width: 1.5em;
962
+ height: 1.5em;
963
+ border-radius: 1.5em;
964
+ margin-right: 0.45em;
965
+ }
966
+ }
967
+
955
968
  /* Json editor */
956
969
  #pxtJsonEditor .ui.content {
957
970
  padding: 1rem;
@@ -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.6352b119.js"></script><link href="/blb/skillmap/css/main.450cb46e.css" rel="stylesheet"></head>
10
+ <script defer="defer" src="/blb/skillmap/js/main.99d90503.js"></script><link href="/blb/skillmap/css/main.450cb46e.css" rel="stylesheet"></head>
11
11
  <body class="pxt-theme-root">
12
12
  <noscript>You need to enable JavaScript to run this app.</noscript>
13
13