Skip to content

Commit

Permalink
remove query selector in tutorial container
Browse files Browse the repository at this point in the history
  • Loading branch information
riknoll committed Oct 24, 2023
1 parent 8d611b3 commit 4ec37bc
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 9 deletions.
16 changes: 10 additions & 6 deletions webapp/src/components/tutorial/TutorialContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ export function TutorialContainer(props: TutorialContainerProps) {
const showImmersiveReader = pxt.appTarget.appTheme.immersiveReader;
const isHorizontal = props.tutorialSimSidebar || pxt.BrowserUtils.isTabletSize();

const container = React.useRef();
const containerRef = React.useRef<HTMLDivElement>();
const stepContentRef = React.useRef<HTMLDivElement>();

React.useEffect(() => {
const observer = new ResizeObserver(updateScrollGradient);
observer.observe(document.body)

// We also want to update the scroll gradient if the tutorial wrapper is resized by the user.
if (container.current) {
observer.observe(container.current);
if (containerRef.current) {
observer.observe(containerRef.current);
}

return () => observer.disconnect();
Expand Down Expand Up @@ -94,7 +95,7 @@ export function TutorialContainer(props: TutorialContainerProps) {

React.useEffect(() => {
const contentDiv = contentRef?.current;
contentDiv.querySelector(".tutorial-step-content")?.focus();
if (stepContentRef.current) stepContentRef.current.focus();
contentDiv.scrollTo(0, 0);
updateScrollGradient();
setStepErrorAttemptCount(0);
Expand Down Expand Up @@ -248,8 +249,11 @@ export function TutorialContainer(props: TutorialContainerProps) {
onDone={onTutorialComplete} />;
const hasHint = !!hintMarkdown;

const handleMarkedContentRef = (ref: HTMLDivElement) => {
stepContentRef.current = ref;
}

return <div className="tutorial-container" ref={container}>
return <div className="tutorial-container" ref={containerRef}>
{!isHorizontal && stepCounter}
<div className={classList("tutorial-content", hasHint && "has-hint")} ref={contentRef} onScroll={updateScrollGradient}>
<div className={"tutorial-content-bkg"}>
Expand All @@ -259,7 +263,7 @@ export function TutorialContainer(props: TutorialContainerProps) {
</div>}
{showImmersiveReader && <ImmersiveReaderButton ref={immReaderRef} content={markdown} tutorialOptions={tutorialOptions} />}
{title && <div className="tutorial-title">{title}</div>}
<MarkedContent className="no-select tutorial-step-content" tabIndex={0} markdown={markdown} parent={parent}/>
<MarkedContent className="no-select tutorial-step-content" tabIndex={0} markdown={markdown} parent={parent} contentRef={handleMarkedContentRef}/>
<div className="tutorial-controls">
{hasHint && <TutorialHint tutorialId={tutorialId} currentStep={visibleStep} markdown={hintMarkdown} parent={parent} />}
{isHorizontal && stepCounter}
Expand Down
18 changes: 15 additions & 3 deletions webapp/src/marked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface MarkedContentProps extends ISettingsProps {
blocksDiffOptions?: pxt.blocks.DiffOptions;
textDiffOptions?: pxt.diff.RenderOptions;
onDidRender?: () => void;
contentRef?: (el: HTMLDivElement) => void;
}

interface MarkedContentState {
Expand All @@ -27,6 +28,7 @@ interface MarkedContentState {
export class MarkedContent extends data.Component<MarkedContentProps, MarkedContentState> {
protected readonly semanticIconNames = ["flipped", "horizontally", "vertically", "rotated", "counterclockwise", "access", "accessible", "accusoft", "add", "address", "adjust", "adn", "adversal", "affiliatetheme", "aid", "alarm", "ald", "algolia", "alien", "align", "all", "alphabet", "als", "alt", "alternate", "alternative", "amazon", "ambulance", "american", "amex", "amilia", "amount", "anchor", "and", "android", "angellist", "angle", "angrycreative", "angular", "announcement", "app", "apper", "apple", "archive", "area", "arrow", "arrows", "ascending", "asexual", "asl", "assistive", "asterisk", "asymmetrik", "at", "attach", "attention", "audible", "audio", "autoprefixer", "avianex", "aviato", "awesome", "aws", "backward", "badge", "bag", "balance", "ball", "ban", "band", "bandcamp", "bar", "barcode", "bars", "baseball", "basket", "basketball", "bath", "bathtub", "battery", "bed", "beer", "beginner", "behance", "bell", "bicycle", "bill", "bimobject", "binary", "binoculars", "birthday", "bishop", "bitbucket", "bitcoin", "bity", "black", "blackberry", "blind", "block", "blogger", "bluetooth", "board", "bold", "bolt", "bomb", "book", "bookmark", "bowling", "box", "boxes", "braille", "branch", "briefcase", "broken", "browser", "brush", "btc", "bug", "building", "bullhorn", "bullseye", "bureau", "buromobelexperte", "bus", "buysellads", "cake", "calculator", "calendar", "call", "camera", "camp", "cancel", "cap", "captioning", "car", "card", "caret", "cart", "cc", "center", "centercode", "certificate", "chain", "chart", "chat", "check", "checked", "checkered", "checkmark", "chess", "chevron", "child", "chrome", "circle", "clipboard", "clock", "clone", "close", "closed", "cloud", "cloudscale", "cloudsmith", "cloudversify", "club", "cny", "cocktail", "code", "codepen", "codiepie", "coffee", "cog", "cogs", "columns", "combinator", "comment", "commenting", "comments", "commons", "compass", "compose", "compress", "computer", "configure", "connectdevelop", "contao", "content", "control", "conversation", "copy", "copyright", "cord", "cpanel", "creative", "credit", "crop", "crosshairs", "css3", "cube", "cubes", "currency", "cursor", "cut", "cuttlefish", "dashboard", "dashcube", "database", "deaf", "deafness", "delete", "delicious", "deploydog", "descending", "description", "deskpro", "desktop", "detective", "deviantart", "devices", "diamond", "digg", "digital", "diners", "discord", "discourse", "discover", "discussions", "disk", "dna", "dochub", "docker", "doctor", "dollar", "dolly", "dont", "dot", "double", "down", "download", "draft2digital", "dribbble", "dribble", "drive", "drivers", "dropbox", "dropdown", "dropper", "drupal", "dyalog", "earlybirds", "edge", "edit", "eercast", "eject", "elementor", "ellipsis", "ember", "emergency", "empire", "empty", "end", "envelope", "envira", "erase", "eraser", "erlang", "ethereum", "etsy", "eur", "euro", "excel", "exchange", "exclamation", "expand", "expeditedssl", "explorer", "express", "external", "extinguisher", "eye", "eyedropper", "facebook", "factory", "fast", "favorite", "fax", "feed", "female", "fi", "fighter", "file", "film", "filter", "find", "fire", "firefox", "first", "firstdraft", "five", "flag", "flask", "flatbed", "flickr", "flipboard", "fly", "folder", "font", "fonticons", "food", "football", "fork", "forms", "fort", "forumbee", "forward", "four", "foursquare", "framework", "free", "freebsd", "from", "frown", "full", "futbol", "gallery", "game", "gavel", "gay", "gbp", "gem", "gender", "genderless", "get", "gg", "ghost", "gift", "git", "github", "gitkraken", "gitlab", "gitter", "gittip", "glass", "glide", "globe", "gofore", "golf", "goodreads", "google", "grab", "graduation", "graph", "gratipay", "grav", "grid", "gripfire", "group", "grunt", "gulp", "hacker", "half", "hand", "handicap", "handshake", "hard", "hash", "hashtag", "hat", "hdd", "header", "heading", "headphones", "hearing", "heart", "heartbeat", "height", "help", "helper", "heterosexual", "hide", "high", "hips", "hire", "history", "hockey", "home", "homosexual", "hooli", "horizontal", "hospital", "hotel", "hotjar", "hourglass", "houzz", "html5", "hubspot", "hundred", "hunt", "id", "idea", "ils", "image", "images", "imdb", "in", "in-cart", "inbox", "indent", "industry", "info", "inr", "instagram", "intergender", "international", "internet", "interpreting", "intersex", "ios", "ioxhost", "isle", "italic", "itunes", "japan", "jcb", "jenkins", "jet", "joget", "joomla", "jpy", "js", "jsfiddle", "justify", "key", "keyboard", "keycdn", "kickstarter", "king", "knight", "korvue", "krw", "lab", "language", "laptop", "laravel", "large", "lastfm", "law", "layout", "leaf", "leanpub", "left", "legal", "lemon", "lesbian", "less", "level", "license", "life", "lightbulb", "lightning", "like", "line", "linechat", "linkedin", "linkify", "linode", "linux", "lira", "list", "listening", "lizard", "location", "lock", "log", "logout", "long", "low", "lyft", "magento", "magic", "magnet", "magnify", "mail", "male", "man", "map", "marker", "mars", "martini", "mastercard", "maxcdn", "maximize", "md", "meanpath", "medapps", "medium", "medkit", "medrt", "meetup", "meh", "mercury", "messenger", "microchip", "microphone", "microsoft", "military", "minimize", "minus", "mix", "mixcloud", "mizuni", "mobile", "modx", "monero", "money", "monster", "moon", "motorcycle", "mouse", "move", "ms", "mule", "music", "mute", "napster", "neuter", "new", "news", "newspaper", "nintendo", "node", "non", "notch", "notched", "note", "npm", "ns8", "numbered", "numeric", "nutritionix", "object", "ocean", "odnoklassniki", "of", "off", "official", "ol", "on", "one", "open", "opencart", "openid", "opera", "optin", "optinmonster", "options", "order", "ordered", "osi", "other", "out", "outdent", "outline", "overflow", "page4", "pagelines", "paint", "palfed", "pallet", "paper", "paperclip", "paragraph", "paste", "patreon", "pause", "paw", "pawn", "pay", "payment", "paypal", "pdf", "peace", "pen", "pencil", "percent", "periscope", "phabricator", "phoenix", "phone", "photo", "php", "picture", "pie", "piece", "pied", "pills", "pin", "pinterest", "piper", "pixels", "plane", "play", "playstation", "play", "plug", "plus", "pocket", "podcast", "point", "pointer", "pointing", "pound", "power", "powerpoint", "pp", "print", "privacy", "product", "protect", "puck", "pushed", "puzzle", "python", "qq", "qrcode", "quarter", "quarters", "queen", "question", "quidditch", "quinscape", "quora", "quote", "radio", "rain", "random", "ravelry", "react", "rebel", "record", "rectangle", "recycle", "reddit", "redo", "redriver", "refresh", "registered", "remove", "rendact", "renren", "repeat", "reply", "replyd", "resize", "resolving", "restore", "retro", "retweet", "right", "ring", "rmb", "road", "rock", "rocket", "rocketchat", "rockrms", "rook", "rouble", "rss", "rub", "ruble", "rupee", "s15", "safari", "sass", "save", "scale", "schlix", "scissors", "scribd", "search", "searchengin", "secret", "selected", "sellcast", "sellsy", "send", "server", "servicestack", "setting", "settings", "share", "shekel", "sheqel", "shield", "ship", "shipping", "shirtsinbulk", "shop", "shopping", "shower", "shuffle", "shutdown", "shuttle", "sidebar", "sign", "sign-in", "sign-out", "signal", "signing", "signs", "signup", "simple", "simplybuilt", "sistrix", "sitemap", "skyatlas", "skype", "slack", "slash", "sliders", "slideshare", "smile", "snapchat", "snowflake", "soccer", "sort", "sound", "soundcloud", "space", "speakap", "spinner", "spock", "spoon", "spotify", "spy", "square", "stack", "star", "start", "staylinked", "steam", "step", "stethoscope", "sticker", "sticky", "stop", "stopwatch", "store", "strava", "street", "strikethrough", "stripe", "stroke", "student", "studiovinari", "stumbleupon", "subscript", "subway", "suitcase", "sun", "superpowers", "superscript", "supple", "switch", "symbol", "sync", "syringe", "systems", "table", "tablet", "tachometer", "tack", "tag", "tags", "talk", "target", "tasks", "taxi", "telegram", "telephone", "teletype", "television", "tencent", "tennis", "terminal", "text", "th", "theme", "themeisle", "thermometer", "thin", "three", "thumb", "thumbs", "thumbtack", "ticket", "tie", "time", "times", "tint", "tm", "to", "toggle", "trademark", "train", "transgender", "translate", "trash", "travel", "treatment", "tree", "trello", "triangle", "tripadvisor", "trophy", "truck", "try", "tumblr", "tv", "twitch", "twitter", "two", "uber", "uikit", "ul", "umbrella", "underline", "undo", "ungroup", "unhide", "uniregistry", "universal", "university", "unlink", "unlinkify", "unlock", "unmute", "unordered", "untappd", "up", "upload", "usb", "usd", "user", "users", "ussunnah", "utensil", "utensils", "vaadin", "vcard", "venus", "vertical", "viacoin", "viadeo", "viber", "victory", "video", "view", "vimeo", "vine", "visa", "vision", "vk", "vnv", "volleyball", "volume", "vuejs", "wait", "wallet", "warehouse", "warning", "wechat", "weibo", "weight", "weixin", "whatsapp", "wheelchair", "whmcs", "wi-fi", "width", "wifi", "wikipedia", "window", "windows", "winner", "wizard", "woman", "won", "word", "wordpress", "world", "wpbeginner", "wpexplorer", "wpforms", "wrench", "write", "xbox", "xing", "yahoo", "yandex", "yc", "ycombinator", "yelp", "yen", "yoast", "youtube", "zero", "zip", "zoom", "zoom-in", "zoom-out"];
protected readonly customIconNames = ["blocks", "js", "python", "toolbox", "book-reader", "photo-video", "gamepad", "function"];
protected contentRef: HTMLDivElement;

// Local cache for images, cleared when we create a new project.
// Stores code => data-uri image of decompiled result
Expand Down Expand Up @@ -623,7 +625,7 @@ export class MarkedContent extends data.Component<MarkedContentProps, MarkedCont
}

renderMarkdown(markdown: string) {
const content = this.refs["marked-content"] as HTMLDivElement;
const content = this.contentRef;
const pubinfo = this.getBuiltinMacros();

if (!markdown) return;
Expand Down Expand Up @@ -693,8 +695,18 @@ export class MarkedContent extends data.Component<MarkedContentProps, MarkedCont
}
}

handleContentRef = (ref: HTMLDivElement) => {
if (!ref) return;

this.contentRef = ref;
if (this.props.contentRef) {
this.props.contentRef(ref);
}
}

renderCore() {
const { className, tabIndex } = this.props;
return <div ref="marked-content" className={className || ""} tabIndex={tabIndex} />;
const { className, tabIndex, } = this.props;

return <div ref={this.handleContentRef} className={className || ""} tabIndex={tabIndex} />;
}
}

0 comments on commit 4ec37bc

Please sign in to comment.