pxt-core 7.4.11 → 7.4.15

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 (69) hide show
  1. package/built/cli.js +117 -83
  2. package/built/nodeutil.d.ts +1 -1
  3. package/built/nodeutil.js +2 -2
  4. package/built/pxt.js +119 -84
  5. package/built/pxtblockly.js +153 -60
  6. package/built/pxtblocks.d.ts +8 -0
  7. package/built/pxtblocks.js +96 -60
  8. package/built/pxtlib.js +2 -1
  9. package/built/target.js +1 -1
  10. package/built/web/blockly.css +1 -1
  11. package/built/web/main.js +1 -1
  12. package/built/web/pxtapp.js +1 -1
  13. package/built/web/pxtasseteditor.js +1 -1
  14. package/built/web/pxtblockly.js +53 -1
  15. package/built/web/pxtblocks.js +1 -1
  16. package/built/web/pxtembed.js +53 -1
  17. package/built/web/pxtlib.js +1 -1
  18. package/built/web/pxtworker.js +1 -1
  19. package/built/web/react-common-skillmap.css +13 -0
  20. package/built/web/rtlblockly.css +1 -1
  21. package/built/web/rtlreact-common-skillmap.css +13 -0
  22. package/built/web/rtlsemantic.css +14 -2
  23. package/built/web/semantic.css +14 -2
  24. package/built/web/skillmap/css/main.b2b69d60.chunk.css +1 -0
  25. package/built/web/skillmap/js/2.fce3190c.chunk.js +2 -0
  26. package/built/web/skillmap/js/main.9d64b2d7.chunk.js +1 -0
  27. package/docfiles/tracking.html +1 -1
  28. package/localtypings/pxtarget.d.ts +1 -0
  29. package/localtypings/pxtblockly.d.ts +37 -0
  30. package/package.json +8 -4
  31. package/react-common/components/Notification.tsx +82 -0
  32. package/react-common/components/controls/Button.tsx +63 -0
  33. package/react-common/components/controls/Checkbox.tsx +47 -0
  34. package/react-common/components/controls/Input.tsx +117 -0
  35. package/react-common/components/controls/List.tsx +28 -0
  36. package/react-common/components/controls/Modal.tsx +143 -0
  37. package/react-common/components/profile/Badge.tsx +33 -0
  38. package/react-common/components/profile/BadgeInfo.tsx +74 -0
  39. package/react-common/components/profile/BadgeList.tsx +67 -0
  40. package/react-common/components/profile/Profile.tsx +42 -0
  41. package/react-common/components/profile/UserNotification.tsx +32 -0
  42. package/react-common/components/profile/UserPane.tsx +68 -0
  43. package/react-common/components/types.d.ts +29 -0
  44. package/react-common/components/util.tsx +61 -0
  45. package/react-common/styles/controls/Button.less +174 -0
  46. package/react-common/styles/controls/Checkbox.less +13 -0
  47. package/react-common/styles/controls/Icon.less +11 -0
  48. package/react-common/styles/controls/Input.less +95 -0
  49. package/react-common/styles/controls/List.less +12 -0
  50. package/react-common/styles/controls/Modal.less +105 -0
  51. package/react-common/styles/controls/Spinner.less +24 -0
  52. package/{built/web/react-common.css → react-common/styles/profile/profile.less} +13 -0
  53. package/react-common/styles/react-common-skillmap-core.less +10 -0
  54. package/react-common/styles/react-common-skillmap.less +12 -0
  55. package/react-common/styles/react-common-variables.less +47 -0
  56. package/react-common/styles/react-common.less +12 -0
  57. package/react-common/tsconfig.json +36 -0
  58. package/theme/asset-editor.less +13 -29
  59. package/theme/blockly-core.less +16 -0
  60. package/theme/common-components.less +7 -0
  61. package/theme/common.less +1 -1
  62. package/theme/highcontrast.less +4 -0
  63. package/theme/pxt.less +2 -0
  64. package/theme/tutorial-sidebar.less +64 -6
  65. package/webapp/public/blockly/plugins.js +57 -0
  66. package/webapp/public/skillmap.html +3 -3
  67. package/built/web/skillmap/css/main.96b1b3f1.chunk.css +0 -1
  68. package/built/web/skillmap/js/2.7dd06a3a.chunk.js +0 -2
  69. package/built/web/skillmap/js/main.55881627.chunk.js +0 -1
@@ -0,0 +1,117 @@
1
+ import * as React from "react";
2
+ import { classList, ControlProps } from "../util";
3
+
4
+ import { Button } from "./Button";
5
+
6
+ export interface InputProps extends ControlProps {
7
+ initialValue?: string;
8
+ label?: string;
9
+ title?: string;
10
+ placeholder?: string;
11
+ icon?: string;
12
+ iconTitle?: string;
13
+ disabled?: boolean;
14
+ type?: string;
15
+ readOnly?: boolean;
16
+ autoComplete?: boolean;
17
+ selectOnClick?: boolean;
18
+
19
+ onChange?: (newValue: string) => void;
20
+ onEnterKey?: (value: string) => void;
21
+ onIconClick?: (value: string) => void;
22
+ }
23
+
24
+ export function Input(props: InputProps) {
25
+ const {
26
+ id,
27
+ className,
28
+ role,
29
+ ariaHidden,
30
+ ariaLabel,
31
+ initialValue,
32
+ label,
33
+ title,
34
+ placeholder,
35
+ icon,
36
+ iconTitle,
37
+ disabled,
38
+ type,
39
+ readOnly,
40
+ autoComplete,
41
+ selectOnClick,
42
+ onChange,
43
+ onEnterKey,
44
+ onIconClick
45
+ } = props;
46
+
47
+ const [value, setValue] = React.useState(initialValue || "");
48
+
49
+ const clickHandler = (evt: React.MouseEvent<any>) => {
50
+ if (selectOnClick) {
51
+ (evt.target as any).select()
52
+ }
53
+ }
54
+
55
+ const changeHandler = (e: React.ChangeEvent<any>) => {
56
+ const newValue = (e.target as any).value;
57
+ if (!readOnly && (value !== newValue)) {
58
+ setValue(newValue);
59
+ }
60
+ if (onChange) {
61
+ onChange(newValue);
62
+ }
63
+ }
64
+
65
+ const enterKeyHandler = (e: React.KeyboardEvent) => {
66
+ const charCode = (typeof e.which == "number") ? e.which : e.keyCode;
67
+ if (charCode === /*enter*/13 || charCode === /*space*/32) {
68
+ if (onEnterKey) {
69
+ e.preventDefault();
70
+ onEnterKey(value);
71
+ }
72
+ }
73
+ }
74
+
75
+ const iconClickHandler = () => {
76
+ if (onIconClick) onIconClick(value);
77
+ }
78
+
79
+ return (
80
+ <div className={classList("common-input-wrapper", disabled && "disabled", className)}>
81
+ {label && <label className="common-input-label">
82
+ {label}
83
+ </label>}
84
+ <div className="common-input-group">
85
+ <input
86
+ id={id}
87
+ className={classList("common-input", icon && "has-icon")}
88
+ title={title}
89
+ role={role || "button"}
90
+ tabIndex={disabled ? 0 : -1}
91
+ aria-label={ariaLabel}
92
+ aria-hidden={ariaHidden}
93
+ type={type || "text"}
94
+ placeholder={placeholder}
95
+ value={value || ''}
96
+ readOnly={!!readOnly}
97
+ onClick={clickHandler}
98
+ onChange={changeHandler}
99
+ onKeyDown={enterKeyHandler}
100
+ autoComplete={autoComplete ? "" : "off"}
101
+ autoCorrect={autoComplete ? "" : "off"}
102
+ autoCapitalize={autoComplete ? "" : "off"}
103
+ spellCheck={autoComplete}
104
+ disabled={disabled} />
105
+ {icon && (onIconClick
106
+ ? <Button
107
+ leftIcon={icon}
108
+ title={iconTitle}
109
+ disabled={disabled}
110
+ onClick={iconClickHandler} />
111
+ : <i
112
+ className={icon}
113
+ aria-hidden={true} />) }
114
+ </div>
115
+ </div>
116
+ );
117
+ }
@@ -0,0 +1,28 @@
1
+ import * as React from "react";
2
+ import { classList, ContainerProps } from "../util";
3
+
4
+ export interface ListProps extends ContainerProps {
5
+ }
6
+
7
+ export const List = (props: ListProps) => {
8
+ const {
9
+ id,
10
+ className,
11
+ ariaHidden,
12
+ ariaLabel,
13
+ role
14
+ } = props;
15
+
16
+ return <div
17
+ id={id}
18
+ aria-hidden={ariaHidden}
19
+ aria-label={ariaLabel}
20
+ role={role}
21
+ className={classList("common-list", className)}>
22
+ {React.Children.map(props.children, (child, index) =>
23
+ <div key={index} className="common-list-item">
24
+ {child}
25
+ </div>
26
+ )}
27
+ </div>
28
+ }
@@ -0,0 +1,143 @@
1
+ import React = require("react");
2
+ import { classList, ContainerProps } from "../util";
3
+ import { Button } from "./Button";
4
+
5
+ export interface ModalAction {
6
+ label: string;
7
+ className?: string;
8
+ disabled?: boolean;
9
+ icon?: string;
10
+ xicon?: boolean;
11
+ onClick: () => void;
12
+ url?: string;
13
+
14
+ // TODO: It would be nice to make fullscreen modals their own thing and deprecate this prop. right
15
+ // now it's required to render the back arrow
16
+ fullscreen?: boolean;
17
+ }
18
+
19
+ export interface ModalProps extends ContainerProps {
20
+ title: string;
21
+ ariaDescribedBy?: string;
22
+ actions?: ModalAction[];
23
+ onClose?: () => void;
24
+ fullscreen?: boolean;
25
+ }
26
+
27
+ export const Modal = (props: ModalProps) => {
28
+ const {
29
+ children,
30
+ id,
31
+ className,
32
+ ariaLabel,
33
+ ariaHidden,
34
+ ariaDescribedBy,
35
+ role,
36
+ title,
37
+ actions,
38
+ onClose,
39
+ fullscreen
40
+ } = props;
41
+
42
+ const closeClickHandler = (e?: React.MouseEvent<HTMLButtonElement>) => {
43
+ if (onClose) onClose();
44
+ }
45
+
46
+ let firstFocusableElement: HTMLElement;
47
+ let lastFocusableElement: HTMLElement;
48
+
49
+ const handleRef = (ref: HTMLDivElement) => {
50
+ if (!ref) return;
51
+
52
+ const focusable = ref.querySelectorAll(`[tabindex]:not([tabindex="-1"])`);
53
+
54
+ firstFocusableElement = focusable.item(0) as HTMLElement;
55
+ lastFocusableElement = focusable.item(focusable.length - 1) as HTMLElement;
56
+
57
+ // TODO: Add an error here? this should never happen
58
+ if (!firstFocusableElement) return;
59
+
60
+ if (!ref.contains(document.activeElement)) firstFocusableElement.focus();
61
+ }
62
+
63
+ const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
64
+ if (e.key !== "Tab") return;
65
+
66
+ const target = e.target;
67
+
68
+ if (e.shiftKey) {
69
+ if (target === firstFocusableElement) {
70
+ lastFocusableElement.focus();
71
+ e.preventDefault();
72
+ e.stopPropagation();
73
+ }
74
+ }
75
+ else if (target === lastFocusableElement) {
76
+ firstFocusableElement.focus();
77
+ e.preventDefault();
78
+ e.stopPropagation();
79
+ }
80
+ }
81
+
82
+ const classes = classList(
83
+ "common-modal-container",
84
+ fullscreen && "fullscreen",
85
+ className
86
+ );
87
+
88
+ return <div className={classes} ref={handleRef} onKeyDown={onKeyDown}>
89
+ <div id={id}
90
+ className="common-modal"
91
+ role={role || "dialog"}
92
+ aria-hidden={ariaHidden}
93
+ aria-label={ariaLabel}
94
+ aria-describedby={ariaDescribedBy}
95
+ aria-labelledby="modal-title">
96
+ <div className="common-modal-header">
97
+ {fullscreen &&
98
+ <div className="common-modal-back">
99
+ <Button
100
+ className="menu-button"
101
+ onClick={closeClickHandler}
102
+ title={lf("Go Back")}
103
+ label={lf("Go Back")}
104
+ leftIcon="fas fa-arrow-left"
105
+ />
106
+ </div>
107
+ }
108
+ <div id="modal-title" className="common-modal-title">
109
+ {title}
110
+ </div>
111
+ {!fullscreen &&
112
+ <div className="common-modal-close">
113
+ <Button
114
+ className="menu-button"
115
+ onClick={closeClickHandler}
116
+ title={lf("Close")}
117
+ rightIcon="fas fa-times-circle"
118
+ />
119
+ </div>
120
+ }
121
+ </div>
122
+ <div className="common-modal-body">
123
+ {children}
124
+ </div>
125
+ {actions?.length &&
126
+ <div className="common-modal-footer">
127
+ { actions.map((action, index) =>
128
+ <Button
129
+ key={index}
130
+ className="primary inverted"
131
+ disabled={action.disabled}
132
+ onClick={action.onClick}
133
+ href={action.url}
134
+ label={action.label}
135
+ title={action.label}
136
+ rightIcon={(action.xicon ? "xicon " : "") + action.icon}
137
+ />
138
+ )}
139
+ </div>
140
+ }
141
+ </div>
142
+ </div>
143
+ }
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import { fireClickOnEnter } from "../util";
3
+
4
+ export interface BadgeProps {
5
+ onClick?: (badge: pxt.auth.Badge) => void;
6
+ badge: pxt.auth.Badge;
7
+ disabled?: boolean;
8
+ isNew?: boolean;
9
+ }
10
+
11
+ export const Badge = (props: BadgeProps) => {
12
+ const { badge, disabled, isNew, onClick } = props;
13
+
14
+ const onBadgeClick = onClick && (() => {
15
+ onClick(badge);
16
+ })
17
+
18
+ const image = (disabled && badge.lockedImage) || badge.image;
19
+ const alt = disabled ? pxt.U.lf("Locked '{0}' badge", badge.title) : badge.title;
20
+
21
+ return (
22
+ <div className={`profile-badge ${onClick ? "clickable" : ""}`}
23
+ role={onClick ? "button" : undefined}
24
+ tabIndex={onClick ? 0 : undefined}
25
+ title={lf("{0} Badge", badge.title)}
26
+ onClick={onBadgeClick}
27
+ onKeyDown={fireClickOnEnter}>
28
+ {isNew && <div className="profile-badge-notification">{pxt.U.lf("New!")}</div>}
29
+ <img src={image} alt={alt} />
30
+ </div>
31
+ );
32
+ }
33
+
@@ -0,0 +1,74 @@
1
+ import * as React from "react";
2
+ import { jsxLF } from "../util";
3
+ import { Badge } from "./Badge";
4
+
5
+ export interface BadgeInfoProps {
6
+ badge: pxt.auth.Badge;
7
+ }
8
+
9
+ export const BadgeInfo = (props: BadgeInfoProps) => {
10
+ const { badge } = props;
11
+
12
+ const date = new Date(badge.timestamp)
13
+
14
+ return <div className="profile-badge-info">
15
+ <div className="profile-badge-info-image">
16
+ <Badge badge={badge} disabled={!badge.timestamp} />
17
+ </div>
18
+ <div className="profile-badge-info-item">
19
+ <div className="profile-badge-info-header">
20
+ {lf("Awarded For:")}
21
+ </div>
22
+ <div className="profile-badge-info-text">
23
+ {badgeDescription(badge)}
24
+ </div>
25
+ </div>
26
+ { badge.timestamp ?
27
+ <div className="profile-badge-info-item">
28
+ <div className="profile-badge-info-header">
29
+ {lf("Awarded On:")}
30
+ </div>
31
+ <div className="profile-badge-info-text">
32
+ {date.toLocaleDateString(pxt.U.userLanguage())}
33
+ </div>
34
+ </div>
35
+ : undefined }
36
+ </div>
37
+ }
38
+
39
+
40
+ export const badgeDescription = (badge: pxt.auth.Badge) => {
41
+ switch (badge.type) {
42
+ case "skillmap-completion":
43
+ return <span>{jsxLF(
44
+ lf("Completing {0}"),
45
+ <a target="_blank" rel="noopener noreferrer" href={sourceURLToSkillmapURL(badge.sourceURL)}>{pxt.U.rlf(badge.title)}</a>
46
+ )}</span>
47
+ }
48
+ }
49
+
50
+ function sourceURLToSkillmapURL(sourceURL: string) {
51
+ if (sourceURL.indexOf("/api/md/") !== -1) {
52
+ // docs url: https://www.makecode.com/api/md/arcade/skillmap/forest
53
+ const path = sourceURL.split("/api/md/")[1];
54
+ // remove the target from the url
55
+ const docsPath = path.split("/").slice(1).join("/");
56
+ return pxt.webConfig?.skillmapUrl + "#docs:" + docsPath;
57
+ }
58
+ else {
59
+ // github url: /user/repo#filename
60
+ const parts = sourceURL.split("#");
61
+
62
+ if (parts.length == 2) {
63
+ return pxt.webConfig.skillmapUrl + "#github:https://github.com/" + parts[0] + "/" + parts[1];
64
+ }
65
+ }
66
+
67
+ if (pxt.BrowserUtils.isLocalHostDev()) {
68
+ // local url: skillmap/forest
69
+ return "http://localhost:3000#local:" + sourceURL
70
+ }
71
+
72
+ return sourceURL;
73
+ }
74
+
@@ -0,0 +1,67 @@
1
+ import * as React from "react";
2
+ import { Badge } from "./Badge";
3
+
4
+ export interface BadgeListProps {
5
+ onBadgeClick: (badge: pxt.auth.Badge) => void;
6
+ availableBadges: pxt.auth.Badge[];
7
+ userState: pxt.auth.UserBadgeState;
8
+ }
9
+
10
+ export const BadgeList = (props: BadgeListProps) => {
11
+ const { onBadgeClick, availableBadges, userState } = props;
12
+
13
+ const badges = availableBadges.slice();
14
+
15
+ let unlocked: pxt.Map<boolean> = {};
16
+
17
+ for (const badge of userState.badges) {
18
+ unlocked[badge.id] = true;
19
+ const existing = badges.findIndex(b => b.id === badge.id);
20
+ if (existing > -1) {
21
+ badges[existing] = {
22
+ ...badges[existing],
23
+ timestamp: badges[existing].timestamp || badge.timestamp
24
+ }
25
+ } else {
26
+ badges.push(badge);
27
+ }
28
+ }
29
+
30
+ const bg: JSX.Element[] = []
31
+ for (let i = 0; i < Math.max(badges.length + 10, 20); i++) {
32
+ bg.push(<div key={i} className="placeholder-badge" />)
33
+ }
34
+
35
+ return <div className="profile-badge-list">
36
+ <div className="profile-badge-header">
37
+ <span className="profile-badge-title">
38
+ {lf("Badges")}
39
+ </span>
40
+
41
+ <span className="profile-badge-subtitle">
42
+ {lf("Click each badge to see details")}
43
+ </span>
44
+ </div>
45
+ <div className="profile-badges-scroller">
46
+ <div className="profile-badges">
47
+ <div className="profile-badges-background-container">
48
+ <div className="profile-badges-background">
49
+ { bg }
50
+ </div>
51
+ </div>
52
+ { badges.map(badge =>
53
+ <div className="profile-badge-and-title">
54
+ <Badge key={badge.id}
55
+ onClick={onBadgeClick}
56
+ badge={badge}
57
+ disabled={!unlocked[badge.id]}
58
+ />
59
+ <div className="profile-badge-name">
60
+ {badge.title}
61
+ </div>
62
+ </div>
63
+ ) }
64
+ </div>
65
+ </div>
66
+ </div>
67
+ }
@@ -0,0 +1,42 @@
1
+ /// <reference path="../types.d.ts" />
2
+
3
+ import * as React from "react";
4
+ import { BadgeList } from "./BadgeList";
5
+ import { UserPane } from "./UserPane";
6
+ import { BadgeInfo } from "./BadgeInfo";
7
+ import { CheckboxStatus } from "../util";
8
+
9
+ export interface ProfileProps {
10
+ user: pxt.auth.State;
11
+ signOut: () => void;
12
+ deleteProfile: () => void;
13
+ checkedEmail: CheckboxStatus;
14
+ onClickedEmail: (isChecked: boolean) => void;
15
+ notification?: pxt.ProfileNotification;
16
+ showModalAsync(options: DialogOptions): Promise<void>;
17
+ }
18
+
19
+ export const Profile = (props: ProfileProps) => {
20
+ const { user, signOut, deleteProfile, onClickedEmail, notification, checkedEmail, showModalAsync } = props;
21
+ const userProfile = user?.profile || { idp: {} };
22
+ const userBadges = user?.preferences?.badges || { badges: [] };
23
+
24
+ const onBadgeClick = (badge: pxt.auth.Badge) => {
25
+ showModalAsync({
26
+ header: lf("{0} Badge", badge.title),
27
+ size: "tiny",
28
+ hasCloseIcon: true,
29
+ jsx: <BadgeInfo badge={badge} />
30
+ });
31
+ }
32
+
33
+ return <div className="user-profile">
34
+ <UserPane profile={userProfile} onSignOutClick={signOut} onDeleteProfileClick={deleteProfile} notification={notification}
35
+ emailChecked={checkedEmail} onEmailCheckClick={onClickedEmail}/>
36
+ <BadgeList
37
+ availableBadges={pxt.appTarget.defaultBadges || []}
38
+ userState={userBadges}
39
+ onBadgeClick={onBadgeClick}
40
+ />
41
+ </div>
42
+ }
@@ -0,0 +1,32 @@
1
+ import * as React from "react";
2
+
3
+ export interface UserNotificationProps {
4
+ notification: pxt.ProfileNotification;
5
+ }
6
+
7
+ export const UserNotification = (props: UserNotificationProps) => {
8
+ const { message, icon, actionText, link, xicon, title } = props.notification;
9
+
10
+ const onActionClick = () => {
11
+ window.open(link, "_blank");
12
+ }
13
+
14
+
15
+ return (
16
+ <div className="profile-notification">
17
+ <div className="profile-notification-icon">
18
+ <i className={`${xicon ? "xicon" : "ui large circular icon "} ${icon}`} />
19
+ </div>
20
+ <div className="profile-notification-title">
21
+ {title}
22
+ </div>
23
+ <div className="profile-notification-message">
24
+ {message}
25
+ </div>
26
+ <button className="ui icon button profile-notification-button" onClick={onActionClick} role="link" >
27
+ <i className="icon external alternate"></i>
28
+ {actionText}
29
+ </button>
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,68 @@
1
+ import * as React from "react";
2
+ import { fireClickOnEnter, CheckboxStatus } from "../util";
3
+ import { UserNotification } from "./UserNotification";
4
+ import { Checkbox } from "../controls/Checkbox";
5
+
6
+ export interface UserPaneProps {
7
+ profile: pxt.auth.UserProfile;
8
+ notification?: pxt.ProfileNotification;
9
+ emailChecked: CheckboxStatus;
10
+
11
+ onSignOutClick: () => void;
12
+ onDeleteProfileClick: () => void;
13
+ onEmailCheckClick: (isChecked: boolean) => void;
14
+ }
15
+
16
+ export const UserPane = (props: UserPaneProps) => {
17
+ const { profile, onSignOutClick, onDeleteProfileClick, onEmailCheckClick, notification, emailChecked } = props;
18
+
19
+ const { username, displayName, picture } = profile.idp;
20
+
21
+ const emailLabel = <>
22
+ {emailChecked === CheckboxStatus.Waiting ? <div className="common-spinner" /> : undefined}
23
+ {lf("I would like to receive the MakeCode newsletter. ")}
24
+ <a href="https://makecode.com/privacy" target="_blank" rel="noopener noreferrer">{lf("View Privacy Statement")}</a>
25
+ </>
26
+
27
+ return <div className="profile-user-pane">
28
+ <div className="profile-portrait">
29
+ { picture?.dataUrl ?
30
+ <img src={picture?.dataUrl} alt={pxt.U.lf("Profile Picture")} />
31
+ : <div className="profile-initials-portrait">
32
+ {pxt.auth.userInitials(profile)}
33
+ </div>
34
+ }
35
+ </div>
36
+ <div className="profile-user-details">
37
+ <div className="profile-display-name">
38
+ {displayName}
39
+ </div>
40
+ { username &&
41
+ <div className="profile-username">
42
+ {username}
43
+ </div>
44
+ }
45
+ </div>
46
+ { notification && <UserNotification notification={notification}/> }
47
+ <div className="profile-spacer"></div>
48
+ <div className="profile-email">
49
+ <Checkbox id="profile-email-checkbox"
50
+ className={emailChecked === CheckboxStatus.Waiting ? "loading" : ""}
51
+ isChecked={emailChecked === CheckboxStatus.Selected}
52
+ onChange={onEmailCheckClick}
53
+ label={emailLabel}/>
54
+ </div>
55
+ <div className="profile-actions">
56
+ <a role="button"
57
+ tabIndex={0}
58
+ onKeyPress={fireClickOnEnter}
59
+ onClick={onDeleteProfileClick}>
60
+ {lf("Delete Profile")}
61
+ </a>
62
+ <button onClick={onSignOutClick} className="ui icon button sign-out">
63
+ <i className="icon sign-out"></i>
64
+ {lf("Sign Out")}
65
+ </button>
66
+ </div>
67
+ </div>
68
+ }
@@ -0,0 +1,29 @@
1
+ /// <reference path="../../built/pxtlib.d.ts" />
2
+
3
+
4
+ interface DialogOptions {
5
+ type?: string;
6
+ hideCancel?: boolean;
7
+ disagreeLbl?: string;
8
+ disagreeClass?: string;
9
+ disagreeIcon?: string;
10
+ logos?: string[];
11
+ className?: string;
12
+ header: string;
13
+ headerIcon?: string;
14
+ body?: string;
15
+ jsx?: JSX.Element;
16
+ jsxd?: () => JSX.Element; // dynamic-er version of jsx
17
+ copyable?: string;
18
+ size?: "" | "small" | "fullscreen" | "large" | "mini" | "tiny"; // defaults to "small"
19
+ onLoaded?: (_: HTMLElement) => void;
20
+ // buttons?: sui.ModalButton[];
21
+ timeout?: number;
22
+ modalContext?: string;
23
+ hasCloseIcon?: boolean;
24
+ helpUrl?: string;
25
+ bigHelpButton?: boolean;
26
+ confirmationText?: string; // Display a text input the user must type to confirm.
27
+ confirmationCheckbox?: string; // Display a checkbox the user must check to confirm.
28
+ confirmationGranted?: boolean;
29
+ }