元素
元素是詞彙在瀏覽器端的一半:每種區塊一個不依賴框架的自訂元素。宿主把剖析好的 data 交給每個元素,並監聽一個事件,pbs-answer。
import "pi-better-show/elements"; // defines every pbs-* tag (a no-op without a DOM)import { configure } from "pi-better-show/elements";
el.data = segment.data; // or <pbs-form data-json='{...}'>el.addEventListener("pbs-answer", (event) => send(encodeAnswer(event.detail)));el.answered = event.detail.fields; // once delivered: locks the element and shows what was sent宿主把區塊剖析後的 data 交給元素,並監聽 pbs-answer(會冒泡、composed、可取消),它的 detail 是 core 的 Answer。元素從不讀寫 HTML:文字以文字節點進入頁面,連結只允許 http(s),並帶 rel="noopener noreferrer" 與 target="_blank"。每個元素是帶 constructed stylesheet(adoptedStyleSheets)的 shadow root,所以能在 default-src 'self' 下執行:沒有 <style> 元素,也沒有 style 屬性。examples/ 就是這樣的頁面;用 bun run demo 執行(loopback,連接埠 4177)。
| 標籤 | 區塊 | data |
答案 | 部件 |
|---|---|---|---|---|
pbs-callout |
alert |
AlertData |
callout header icon title body |
|
pbs-cards |
cards |
CardsData |
grid card title icon body |
|
pbs-options |
options |
OptionsData |
pick |
grid option title badge body pros cons actions pick status |
pbs-form |
form |
FormData |
form |
form title question label hint choices choice badge other textarea error actions submit status sent |
pbs-review |
review |
ReviewData |
review |
review title items item item-title pick media image enlarge frame unavailable body comment actions submit status lightbox close sent |
pbs-mindmap |
mindmap |
MindmapData |
mindmap tree item node toggle label group |
|
pbs-suggest |
suggest |
SuggestData |
suggest |
suggest chips chip status |
pbs-checklist |
checklist |
ChecklistData |
checklist |
checklist title items item progress actions submit status sent |
pbs-table |
table |
TableData |
table bar filter count scroll header head sort body row cell empty |
|
pbs-steps |
steps |
StepsData |
steps step rail marker content title badge when body |
|
pbs-stats |
stats |
StatsData |
grid stat label value delta note |
|
pbs-diff |
diff |
DiffData |
diff scroll line |
|
pbs-diagram |
mermaid |
MermaidData |
diagram image source note |
|
pbs-tree |
tree |
TreeData |
treeview bar expand-all collapse-all tree item node toggle name count tags tag note more group |
TAGS 把區塊種類對應到它的標籤。沒有整份文件的元素:extension 在自己的頁面伺服器上渲染 Markdown,其他宿主用自己的渲染器。
屬性與 property
Section titled “屬性與 property”每個元素都有這些。
| 名稱 | 種類 | 意義 |
|---|---|---|
data / data-json |
property / attribute | 區塊的資料;JSON 有誤或元素畫不了的形狀,會顯示錯誤面板並觸發 pbs-error。 |
answered / data-answered |
property / attribute | 已送出的 [name, value][]:鎖定元素並顯示它們。undefined 會重新開啟。 |
ref,或 doc 與 block 屬性 |
property / attributes | 區塊的位址,會複製進每份答案的 ref。 |
density |
attribute 與 property | comfortable(預設)或 compact。 |
scheme |
attribute 與 property | light 或 dark,用來強制配色;否則元素跟隨宿主的 color-scheme。 |
lang |
attribute(或祖先的、文件的) | zh* 顯示繁體中文,其他顯示英文。 |
refresh() |
method | 重新繪製。宿主改變 color-scheme 或文件的 lang 之後要呼叫它,元素觀察不到這些變化。 |
挑選(pbs-options)或 chip(pbs-suggest)會立刻送出,並在監聽者接下事件後鎖定自己;呼叫 preventDefault() 的監聽者會拒絕它,元素維持開啟。表單、review 或 checklist 送出後仍可編輯(狀態列寫「Sent.」),所以使用者可以再送一份修改過的答案;宿主用設定 answered 來鎖定它。表單的必填問題在送出前先檢查。在文字框按 Ctrl/Cmd+Enter 即可送出。
元素本身不該做的事由宿主負責:圖、review 圖片與原型從哪裡來、用字,以及圖能不能被指點。
configure({ strings: { "zh-Hant": { send: "送出" } }, // per locale, per word (see Strings) diagramUrl: (source, scheme) => `/diagram.svg?...`, // an image URL for pbs-diagram; without it the source is shown imageUrl: (ref) => `/files/${ref}`, // a review item's `image`; default admits http(s) and raster data URLs only pageUrl: (ref) => `/pages/${ref}`, // a review item's `page`, shown in a sandboxed frame; without it, its name diagramMap: async (url) => readTargets(url), // makes a diagram's nodes and edges clickable (below); without it the diagram is an image});請從 pi-better-show/server 提供圖片(mermaidSvg(source, { scheme, transparent: true }));圖的標記不會進入頁面。resetConfiguration() 會還原預設值。
設了 diagramMap 後,圖的節點與邊會變成使用者可以留言的按鈕。
宿主要提供什麼
設了 diagramMap 後,pbs-diagram 在圖片的每個節點、邊(它的線與標籤框)與 subgraph 標題上蓋一個透明按鈕。diagramMap(url) 收到 diagramUrl 回傳的 URL,並解析成 DiagramMap:{ viewBox, targets: [{ kind: "node" | "edge" | "group", text, shapes: [{ tag, attrs }] }] },形狀用圖片自己的座標,而且只帶幾何屬性。讀取並剖析繪圖的是宿主,因為元素從不剖析標記;extension 的頁面為 mermaidSvg 畫的 SVG 做這件事(g.node、.edge、g.edge-label、g.subgraph 與它們的 data-* 標籤:流程圖與狀態圖;其他圖種沒有目標,維持圖片)。目標依閱讀順序排列,也就是方向鍵走的順序;不論順序如何,群組畫在邊的下面,邊畫在節點的下面。點擊,或在有焦點的按鈕上按 Enter 或空白鍵,會從按鈕本身觸發 pbs-diagram-target(冒泡、composed),帶 detail: { kind, text },所以 composedPath()[0] 就是宿主要把焦點還回去的地方。整張圖是一個 Tab 停靠點,落在最後取得焦點的按鈕上(一開始是第一個);方向鍵移到下一個或上一個按鈕,Home 與 End 移到第一個或最後一個。按鈕放在一個 role="group" 裡,它的描述(aria-describedby,一個 SVG desc)告訴螢幕閱讀器用方向鍵在按鈕之間移動;DOM 維持繪製的圖層順序,而不是閱讀順序。每個按鈕都帶 aria-label(「Comment on edge: …」),並在滑過與取得焦點時顯示蓋在圖上的色調,所以不會有東西移動。
在元素或任何祖先上設定 --pbs-* 屬性;每個都有跟隨宿主 color-scheme 的 light-dark() 預設值。
| Token | 意義 |
|---|---|
--pbs-bg --pbs-surface |
面板背景;有底色的表面(表頭、程式碼) |
--pbs-fg --pbs-muted |
文字;次要文字 |
--pbs-line --pbs-control |
面板與分隔線;輸入框的邊(與其表面 3:1 對比) |
--pbs-accent --pbs-on-accent |
按鈕、連結、選取;其上的文字 |
--pbs-note --pbs-ok --pbs-warn --pbs-risk |
語氣 |
--pbs-radius --pbs-gap |
圓角;區塊之間與內部的間距 |
--pbs-font --pbs-mono --pbs-font-size |
字體 |
--pbs-font-display |
標題(預設為 --pbs-font) |
結構帶有 part 名稱,可用 ::part() 重新設計樣式。面板四邊的框線相同,或完全沒有;語氣以色調、徽章、圖示與標題顏色呈現,絕不用有顏色或較粗的單邊框線。examples/demo.css 把 Roundtable 與 Straw boss 的 token 對應起來當範例。
每個控制項都是有標籤的原生控制項。pbs-mindmap 遵循 ARIA tree 模式(方向鍵移動,右鍵與左鍵展開與收合,Enter 與空白鍵切換,Home 與 End 跳轉);pbs-tree 也遵循,並把資料夾展開到第 2 層(更深、含有帶標籤節點的資料夾會展開到那條路徑),附「expand all」與「collapse all」按鈕;pbs-table 從表頭按鈕排序(aria-sort),並從有標籤的搜尋框篩選。