Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/stale-steaks-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-typescript-playground-plugin": patch
---

Remove innerHTML uses
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,3 @@ export const requireURL = (path: string) => {
const prefix = isDev ? 'local/' : 'unpkg/typescript-playground-presentation-mode/dist/'
return prefix + path
}

/** Use this to make a few dumb element generation funcs */
export const el = (str: string, el: string, container: Element) => {
const para = document.createElement(el)
para.innerHTML = str
container.appendChild(para)
}
58 changes: 50 additions & 8 deletions packages/playground/src/createConfigDropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,40 @@ const notRelevantToPlayground = [
"forceConsistentCasingInFileNames",
]

const createInfoIcon = () => {
const svgNamespace = "http://www.w3.org/2000/svg"
const svg = document.createElementNS(svgNamespace, "svg")
svg.setAttribute("width", "20px")
svg.setAttribute("height", "20px")
svg.setAttribute("viewBox", "0 0 20 20")
svg.setAttribute("version", "1.1")

const g = document.createElementNS(svgNamespace, "g")
g.setAttribute("stroke", "none")
g.setAttribute("stroke-width", "1")
g.setAttribute("fill", "none")
g.setAttribute("fill-rule", "evenodd")
svg.appendChild(g)

const circle = document.createElementNS(svgNamespace, "circle")
circle.setAttribute("stroke", "#0B6F57")
circle.setAttribute("cx", "10")
circle.setAttribute("cy", "10")
circle.setAttribute("r", "9")
g.appendChild(circle)

const path = document.createElementNS(svgNamespace, "path")
path.setAttribute(
"d",
"M9.99598394,6 C10.2048193,6 10.4243641,5.91700134 10.6546185,5.75100402 C10.8848728,5.58500669 11,5.33601071 11,5.00401606 C11,4.66666667 10.8848728,4.41499331 10.6546185,4.24899598 C10.4243641,4.08299866 10.2048193,4 9.99598394,4 C9.79250335,4 9.57563588,4.08299866 9.34538153,4.24899598 C9.11512718,4.41499331 9,4.66666667 9,5.00401606 C9,5.33601071 9.11512718,5.58500669 9.34538153,5.75100402 C9.57563588,5.91700134 9.79250335,6 9.99598394,6 Z M10.6877323,16 L10.6877323,14.8898836 L10.6877323,8 L9.30483271,8 L9.30483271,9.11011638 L9.30483271,16 L10.6877323,16 Z"
)
path.setAttribute("fill", "#0B6F57")
path.setAttribute("fill-rule", "nonzero")
g.appendChild(path)

return svg
}

export const createConfigDropdown = (sandbox: Sandbox, monaco: Monaco) => {
const configContainer = document.getElementById("config-container")!
const container = document.createElement("div")
Expand Down Expand Up @@ -121,13 +155,21 @@ export const createConfigDropdown = (sandbox: Sandbox, monaco: Monaco) => {
label.style.position = "relative"
label.style.width = "100%"

const svg = `<?xml version="1.0" encoding="UTF-8"?><svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<circle stroke="#0B6F57" cx="10" cy="10" r="9"></circle>
<path d="M9.99598394,6 C10.2048193,6 10.4243641,5.91700134 10.6546185,5.75100402 C10.8848728,5.58500669 11,5.33601071 11,5.00401606 C11,4.66666667 10.8848728,4.41499331 10.6546185,4.24899598 C10.4243641,4.08299866 10.2048193,4 9.99598394,4 C9.79250335,4 9.57563588,4.08299866 9.34538153,4.24899598 C9.11512718,4.41499331 9,4.66666667 9,5.00401606 C9,5.33601071 9.11512718,5.58500669 9.34538153,5.75100402 C9.57563588,5.91700134 9.79250335,6 9.99598394,6 Z M10.6877323,16 L10.6877323,14.8898836 L10.6877323,8 L9.30483271,8 L9.30483271,9.11011638 L9.30483271,16 L10.6877323,16 Z" fill="#0B6F57" fill-rule="nonzero"></path>
</g>
</svg>`
label.innerHTML = `<span>${optSummary.id}</span><a href='../tsconfig#${optSummary.id}' class='compiler_info_link' alt='Look up ${optSummary.id} in the TSConfig Reference' target='_blank'>${svg}</a><br/>${optSummary.oneliner}`
const optionName = document.createElement("span")
optionName.textContent = optSummary.id
label.appendChild(optionName)

const optionReference = document.createElement("a")
optionReference.href = `../tsconfig#${optSummary.id}`
optionReference.className = "compiler_info_link"
optionReference.setAttribute("aria-label", `Look up ${optSummary.id} in the TSConfig Reference`)
optionReference.target = "_blank"
optionReference.rel = "noopener noreferrer"
optionReference.appendChild(createInfoIcon())
label.appendChild(optionReference)

label.appendChild(document.createElement("br"))
label.appendChild(document.createTextNode(optSummary.oneliner))

const input = document.createElement("input")
input.value = optSummary.id
Expand Down Expand Up @@ -244,7 +286,7 @@ const createSelect = (title: string, id: string, blurb: string, sandbox: Sandbox
})

const span = document.createElement("span")
span.innerHTML = blurb
span.textContent = blurb
span.classList.add("compiler-flag-blurb")
label.appendChild(span)

Expand Down
6 changes: 3 additions & 3 deletions packages/playground/src/createElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ export const createSidebar = () => {
return sidebar
}

const toggleIconWhenOpen = "&#x21E5;"
const toggleIconWhenClosed = "&#x21E4;"
const toggleIconWhenOpen = "\u21E5"
const toggleIconWhenClosed = "\u21E4"

export const setupSidebarToggle = () => {
const toggle = document.getElementById("sidebar-toggle")!
Expand All @@ -129,7 +129,7 @@ export const setupSidebarToggle = () => {
const sidebar = window.document.querySelector(".playground-sidebar") as HTMLDivElement
const sidebarShowing = sidebar.style.display !== "none"

toggle.innerHTML = sidebarShowing ? toggleIconWhenOpen : toggleIconWhenClosed
toggle.textContent = sidebarShowing ? toggleIconWhenOpen : toggleIconWhenClosed
toggle.setAttribute("aria-label", sidebarShowing ? "Hide Sidebar" : "Show Sidebar")
}

Expand Down
81 changes: 69 additions & 12 deletions packages/playground/src/ds/createDesignSystem.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Sandbox } from "@typescript/sandbox"
import type { DiagnosticRelatedInformation, Node } from "typescript"
import type { DiagnosticRelatedInformation, Node as TSNode } from "typescript"

export type LocalStorageOption = {
blurb: string
Expand All @@ -17,9 +17,24 @@ export type OptionsListConfig = {
requireRestart?: true
}

type ElementChild = string | Node

const appendChildren = (el: Element, children: ElementChild[]) => {
children.forEach(child => {
el.appendChild(typeof child === "string" ? document.createTextNode(child) : child)
})
}

const el = (str: string, elementType: string, container: Element) => {
const el = document.createElement(elementType)
el.innerHTML = str
el.textContent = str
container.appendChild(el)
return el
}

const elWithChildren = (children: ElementChild[], elementType: string, container: Element) => {
const el = document.createElement(elementType)
appendChildren(el, children)
container.appendChild(el)
return el
}
Expand Down Expand Up @@ -102,8 +117,11 @@ export const createDesignSystem = (sandbox: Sandbox) => {

const li = document.createElement("li")
const label = document.createElement("label")
const split = setting.oneline ? "" : "<br/>"
label.innerHTML = `<span>${setting.display}</span>${split}${setting.blurb}`
const display = document.createElement("span")
display.textContent = setting.display
label.appendChild(display)
if (!setting.oneline) label.appendChild(document.createElement("br"))
label.appendChild(document.createTextNode(setting.blurb))

const key = setting.flag
const input = document.createElement("input")
Expand Down Expand Up @@ -187,6 +205,32 @@ export const createDesignSystem = (sandbox: Sandbox) => {
return noErrorsMessage
}

const link = (href: string, text: string) => {
const a = document.createElement("a")
a.href = href
a.textContent = text
return a
}

const inlineCode = (text: string) => {
const code = document.createElement("code")
code.textContent = text
return code
}

const lineBreak = () => document.createElement("br")

const unorderedList = (...items: ElementChild[][]) => {
const ul = document.createElement("ul")
items.forEach(item => {
const li = document.createElement("li")
appendChildren(li, item)
ul.appendChild(li)
})
container.appendChild(ul)
return ul
}

const createTabBar = () => {
const tabBar = document.createElement("div")
tabBar.classList.add("playground-plugin-tabview")
Expand Down Expand Up @@ -305,13 +349,13 @@ export const createDesignSystem = (sandbox: Sandbox) => {
container.appendChild(ol)
}

const createASTTree = (node: Node, settings?: { closedByDefault?: true }) => {
const createASTTree = (node: TSNode, settings?: { closedByDefault?: true }) => {
const autoOpen = !settings || !settings.closedByDefault

const div = document.createElement("div")
div.className = "ast"

const infoForNode = (node: Node) => {
const infoForNode = (node: TSNode) => {
const name = ts.SyntaxKind[node.kind]

return {
Expand All @@ -337,33 +381,34 @@ export const createDesignSystem = (sandbox: Sandbox) => {
return li
}

const renderSingleChild = (key: string, value: Node, depth: number) => {
const renderSingleChild = (key: string, value: TSNode, depth: number) => {
const li = document.createElement("li")
li.innerHTML = `${key}: `
li.textContent = `${key}: `

renderItem(li, value, depth + 1)
return li
}

const renderManyChildren = (key: string, nodes: Node[], depth: number) => {
const renderManyChildren = (key: string, nodes: TSNode[], depth: number) => {
const children = document.createElement("div")
children.classList.add("ast-children")

const li = document.createElement("li")
li.innerHTML = `${key}: [<br/>`
li.textContent = `${key}: [`
li.appendChild(document.createElement("br"))
children.appendChild(li)

nodes.forEach(node => {
renderItem(children, node, depth + 1)
})

const liEnd = document.createElement("li")
liEnd.innerHTML += "]"
liEnd.textContent = "]"
children.appendChild(liEnd)
return children
}

const renderItem = (parentElement: Element, node: Node, depth: number) => {
const renderItem = (parentElement: Element, node: TSNode, depth: number) => {
const itemDiv = document.createElement("div")
parentElement.appendChild(itemDiv)
itemDiv.className = "ast-tree-start"
Expand Down Expand Up @@ -497,6 +542,18 @@ export const createDesignSystem = (sandbox: Sandbox) => {
subtitle: (subtitle: string) => el(subtitle, "h4", container),
/** Used to show a paragraph */
p: (subtitle: string) => el(subtitle, "p", container),
/** Used to show a paragraph with safe DOM children */
pWithChildren: (...children: ElementChild[]) => elWithChildren(children, "p", container),
/** Used to show a section heading with safe DOM children */
subtitleWithChildren: (...children: ElementChild[]) => elWithChildren(children, "h4", container),
/** Creates an unattached anchor with safe text */
link,
/** Creates an unattached inline code element with safe text */
inlineCode,
/** Creates an unattached line break */
lineBreak,
/** Appends an unordered list with safe DOM children */
unorderedList,
/** When you can't do something, or have nothing to show */
showEmptyScreen,
/**
Expand Down
57 changes: 46 additions & 11 deletions packages/playground/src/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,45 @@ type StoryContent =

import type { Sandbox } from "@typescript/sandbox"

const createStoryIcon = (type: "code" | "html") => {
const svgNamespace = "http://www.w3.org/2000/svg"
const svg = document.createElementNS(svgNamespace, "svg")
svg.setAttribute("fill", "none")

if (type === "code") {
svg.setAttribute("width", "7")
svg.setAttribute("height", "7")
svg.setAttribute("viewBox", "0 0 7 7")

const rect = document.createElementNS(svgNamespace, "rect")
rect.setAttribute("width", "7")
rect.setAttribute("height", "7")
rect.setAttribute("fill", "#187ABF")
svg.appendChild(rect)
} else {
svg.setAttribute("width", "9")
svg.setAttribute("height", "11")
svg.setAttribute("viewBox", "0 0 9 11")

const path = document.createElementNS(svgNamespace, "path")
path.setAttribute("d", "M8 5.5V3.25L6 1H4M8 5.5V10H1V1H4M8 5.5H4V1")
path.setAttribute("stroke", "#C4C4C4")
svg.appendChild(path)
}

return svg
}

const createLocalDevStoryMessage = () => {
const p = document.createElement("p")
p.appendChild(document.createTextNode("Because the gatsby dev server uses JS to build your pages, and not statically, the page will not load during dev. It does work in prod though - use "))
const code = document.createElement("code")
code.textContent = "pnpm build-site"
p.appendChild(code)
p.appendChild(document.createTextNode(" to test locally with a static build."))
return p
}

/** Use the handbook TOC which is injected into the globals to create a sidebar */
export const showNavForHandbook = (sandbox: Sandbox, escapeFunction: () => void) => {
// @ts-ignore
Expand Down Expand Up @@ -73,16 +112,10 @@ const updateNavWithStoryContent = (title: string, storyContent: StoryContent[],
li.classList.add("selectable")
const a = document.createElement("a")

let logo: string
if (element.type === "code") {
logo = `<svg width="7" height="7" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="7" height="7" fill="#187ABF"/></svg>`
} else if (element.type === "html") {
logo = `<svg width="9" height="11" viewBox="0 0 9 11" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 5.5V3.25L6 1H4M8 5.5V10H1V1H4M8 5.5H4V1" stroke="#C4C4C4"/></svg>`
} else {
logo = ""
if (element.type === "code" || element.type === "html") {
a.appendChild(createStoryIcon(element.type))
}

a.innerHTML = `${logo}${element.title}`
a.appendChild(document.createTextNode(element.title))
a.href = `/play#${prefix}-${i}`

a.onclick = e => {
Expand Down Expand Up @@ -164,12 +197,14 @@ const setStoryViaHref = (href: string, sandbox: Sandbox) => {
}

if (document.location.host === "localhost:8000") {
setStory("<p>Because the gatsby dev server uses JS to build your pages, and not statically, the page will not load during dev. It does work in prod though - use <code>pnpm build-site</code> to test locally with a static build.</p>", sandbox)
setStory(createLocalDevStoryMessage(), sandbox)
} else {
setStory(text, sandbox)
}
} else {
setStory(`<p>Failed to load the content at ${href}. Reason: ${req.status} ${req.statusText}</p>`, sandbox)
const errorMessage = document.createElement("p")
errorMessage.textContent = `Failed to load the content at ${href}. Reason: ${req.status} ${req.statusText}`
setStory(errorMessage, sandbox)
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/src/pluginUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const createUtils = (sb: any, react: typeof React) => {

const el = (str: string, elementType: string, container: Element) => {
const el = document.createElement(elementType)
el.innerHTML = str
el.textContent = str
container.appendChild(el)
return el
}
Expand Down
Loading