Crea un piano di apprendimento locale con FormField composto, TextInput controllato e PrimaryButton di Canvas Kit, distinguendo le fonti attuali dei token semantici dai vecchi esempi di migrazione a space.x4.
Interpretazione originale e autonoma HTML dei modelli di interazione di Canvas e di una gerarchia aziendale sobria. La tavolozza e il layout sono scelte dell’applicazione, non il rendering di un tenant Sana. · Riferimento per l’implementazione
02
Riferimento di progettazione per il sistema di progettazione sistema di design Workday Canvas
Codice sorgente attuale di Canvas Kit e sys.json dei token Canvas. I nomi JSON originali riportati di seguito sono percorsi del codice sorgente, non nomi di variabili CSS generati arbitrariamente. I valori che rimandano ad alias dei token di base sono indicati come alias; il riferimento di migrazione datato è esplicitamente storico.
Sistema di progettazione sistema di design Workday Canvas: consulta il codice sorgente attuale prima di copiare un esempio di migrazione
La spaziatura ora distingue le diverse funzioni
Canvas si è evoluto dalle costanti di spaziatura con taglie di abbigliamento in canvas-kit-react/tokens, passando per i token numerati system.space, fino alle categorie del codice sorgente come padding e gap. L’attuale sys.json esprime i valori sottostanti come riferimenti ai token di base. Questo riferimento conserva i percorsi effettivi invece di inventare una variabile CSS concatenando parole.
La tabella di migrazione resta utile per convertire un’applicazione meno recente: spiega perché in passato space.s corrispondeva a un rem. È una testimonianza storica, non una garanzia che ogni vecchia esportazione rappresenti l’interfaccia attuale preferita. L’anteprima usa intervalli applicativi scelti esplicitamente di 16 e 24px; per i nomi dei token della libreria fa fede la tabella del codice sorgente.
Sistema di progettazione sistema di design Workday Canvas: il colore dipende dal tenant e dallo stato del componente
Un pulsante principale è più di una semplice tonalità di blu
PrimaryButton legge prima brand.action.base e, se non è disponibile, usa il colore d’accento primary legacy. Anche gli stili hover e pressed consultano i ruoli delle azioni del brand prima di derivare gli stati tramite gli helper colorSpace. Per questo, cambiare un singolo colore di sfondo codificato non basta a riprodurre il contratto del tema del componente.
L’anteprima originale del piano di apprendimento usa una sobria tavolozza applicativa blu e si definisce un’interpretazione HTML. Non riproduce un tenant specifico di un cliente né il tema Sana Canvas più recente. L’esempio nativo completo consente ai livelli di token installati di fornire i colori dei componenti.
Sistema di progettazione sistema di design Workday Canvas: i ruoli compositi preservano interlinea e peso
Un alias di dimensione non definisce da solo lo stile
L’oggetto tipografico attuale body.sm combina famiglia di caratteri, peso normal, dimensione del corpo e interlinea. I ruoli dei titoli usano il peso bold. Scegliere soltanto una dimensione in pixel da una vecchia schermata farebbe perdere queste relazioni. Nel codice sorgente il nome è normal, non la chiave regular presente nelle descrizioni di migrazione meno recenti.
Il pacchetto dei componenti Canvas Kit non include i font. Mantieni il caricamento dei font come scelta d’integrazione separata; l’esempio offline usa un font di sistema alternativo e non dichiara di includere Roboto o un font Sana.
Sistema di progettazione sistema di design Workday Canvas: FormField è un componente composto
Lascia che il campo componga etichetta, input e suggerimento
Il codice sorgente espone FormField.Label, FormField.Input e FormField.Hint. Passare TextInput come prop a Input consente al modello di generare le relazioni di accessibilità. È diverso dai vecchi esempi, che impostavano una proprietà label sul campo esterno e inserivano al suo interno un input non racchiuso in un componente.
Nei moduli orizzontali, horizontalStart e horizontalEnd sono i valori di orientamento attuali. FormField.Field raggruppa l’input e il suggerimento secondo tale allineamento. Il nostro filtro resta verticale perché la spiegazione deve comparire direttamente sotto l’etichetta e il controllo.
Inserisci un’etichetta visibile effettiva in FormField.Label.
Passa TextInput tramite lo slot composto Input.
Usa Hint per specificare l’ambito del filtro.
Quando introduci vincoli, lascia la logica di validazione nell’applicazione.
Sistema di progettazione sistema di design Workday Canvas: anche un input che si espande ha bisogno di un contenitore flessibile
Tieni conto della larghezza minima
TextInput ha una larghezza minima di ripiego di 280px, espressa nel codice sorgente tramite px2rem. grow richiede la larghezza completa, ma non rende magicamente compatibile con un viewport stretto un contenitore rigido a due colonne. Nel catalogo offline, su mobile la barra laterale del piano si dispone sotto le schede dei corsi e le colonne del layout possono ridursi.
Il valore della ricerca è un normale stato React. L’app esegue una ricerca per sottostringa senza distinzione tra maiuscole e minuscole nei tre titoli dei corsi e mostra un risultato vuoto esplicito. Il filtro non cancella i corsi selezionati, perché la visibilità e l’appartenenza al piano sono stati distinti.
Sistema di progettazione sistema di design Workday Canvas: la selezione persiste indipendentemente dai risultati visibili
Usa ID stabili per i corsi e calcola i totali
Ogni corso originale ha un ID, un titolo e una durata. L’elenco dei corsi selezionati memorizza gli ID, mentre il totale visualizzato viene calcolato a partire dai dati dei corsi. Filtrare il catalogo non rimuove un elemento selezionato. Rimuovendo un elemento, l’azione Aggiungi viene ripristinata immediatamente e il totale diminuisce.
Questo è uno scenario originale di pianificazione locale. Non chiama le API di Workday, non iscrive un dipendente e non modifica un record di apprendimento. Rendere visibile questo limite evita che un prototipo suggerisca l’esecuzione di una vera transazione aziendale.
Filtra solo la vista del catalogo.
Aggiungi una sola volta ogni ID corso.
Calcola i corsi selezionati e il totale dei minuti a partire da questi ID.
Sistema di progettazione sistema di design Workday Canvas: carica i token prima di aspettarti componenti con tema
Il provider e i livelli CSS hanno responsabilità diverse
L’esempio attuale per iniziare importa gli stili delle variabili di base, brand, componenti e sistema nel punto d’ingresso dell’applicazione, quindi racchiude l’interfaccia con CanvasProvider. Il provider da solo non sostituisce le definizioni CSS. Il codice qui segue questa composizione e fornisce una radice React completa.
Sana Canvas è facoltativo: le sue variabili vengono caricate dopo quelle di sistema e viene selezionato tramite l’attributo html data-theme documentato. Le applicazioni incorporate che non possono controllare la radice del documento dispongono di un’opzione di tema dedicata nel provider per propagare il tema ai popup. Durante l’aggiornamento dei pacchetti, non aggiungere per errore questo tema a un tenant esistente.
Esempi di componenti per il sistema di progettazione sistema di design Workday Canvas
Esempio interattivo completo e autonomo
Salva il documento completo come index.html e aprilo in un browser. Interpretazione originale e autonoma HTML dei modelli di interazione di Canvas e di una gerarchia aziendale sobria. La tavolozza e il layout sono scelte dell’applicazione, non il rendering di un tenant Sana.
html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Canvas learning plan interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#f3f5f7;color:#20272f;font:16px/1.5 system-ui,sans-serif}button,input{font:inherit}header{background:white;border-bottom:1px solid #d5dbe0;padding:16px 24px;display:flex;gap:12px;align-items:center}.mark{width:32px;height:32px;border:4px solid #ed9b28;border-bottom:0;border-radius:50% 50% 0 0;height:16px;margin-right:8px}header span{font-size:14px;color:#59616b;margin-left:auto}main{max-width:1100px;margin:32px auto;padding:0 24px}h1{font-size:28px;line-height:36px;margin:0 0 8px}p{margin:0 0 24px}label{display:block;font-size:14px;font-weight:600;margin-bottom:8px}#search{width:100%;max-width:580px;height:40px;border:1px solid #89949f;border-radius:8px;padding:8px 12px;background:white}.hint{font-size:12px;color:#59616b;margin:8px 0 24px}.layout{display:grid;grid-template-columns:1fr 290px;gap:24px;align-items:start}.course{display:grid;grid-template-columns:96px 1fr;gap:24px;background:white;padding:24px;border-radius:8px;border:1px solid #d5dbe0;margin-bottom:16px;min-width:0}.art{height:96px;display:grid;place-items:center;border-radius:8px;font-size:40px;color:#005cb9;background:#e7f1fd}.art.orange{background:#fff0d6;color:#805200}.art.green{background:#e6f4ed;color:#236443}.category{font-size:12px;color:#59616b;text-transform:uppercase;letter-spacing:1px}h2{font-size:20px;line-height:28px;margin:4px 0 8px}.course p{font-size:14px;margin:0 0 16px;color:#59616b}.row{display:flex;justify-content:space-between;align-items:center;gap:16px}.row span{font-size:14px;color:#59616b}button{border:0;border-radius:999px;background:#005cb9;color:white;font-size:14px;font-weight:600;padding:8px 16px;cursor:pointer}button:disabled{opacity:.5;cursor:default}button:focus-visible,input:focus-visible{outline:3px solid #005cb9;outline-offset:3px}.plan{padding:24px;background:white;border:1px solid #d5dbe0;border-radius:8px}.plan h2{margin:0 0 16px}.number{font-size:36px;font-weight:700;line-height:1.2}.plan-total{padding-bottom:20px;border-bottom:1px solid #d5dbe0;margin-bottom:20px}.plan-total span{font-size:14px}.plan ul{padding:0;list-style:none;margin:0}.plan li{border-bottom:1px solid #e6e9ed;padding:0 0 16px;margin:0 0 16px;font-size:14px}.remove{background:transparent;color:#005cb9;padding:4px 0;display:block;border-radius:3px;text-decoration:underline;font-weight:400}.empty{font-size:14px;color:#59616b}.boundary{font-size:12px;color:#59616b;margin-top:24px}.no-results{background:white;border:1px solid #d5dbe0;padding:24px;border-radius:8px}@media(max-width:720px){main{padding:0 16px;margin:24px auto}.layout{grid-template-columns:1fr}.course{padding:16px;grid-template-columns:60px 1fr;gap:16px}.art{height:60px;font-size:28px}header span{display:none}.row{align-items:flex-start;flex-direction:column;gap:8px}.plan{padding:20px}}
</style><header><div class="mark" aria-hidden="true"></div><strong>Learning workspace</strong><span>Personal development · Local plan</span></header><main><h1>Make room to grow</h1><p>Choose a few focused lessons for your learning plan.</p><label for="search">Find a course</label><input id="search" type="search" placeholder="Search course titles" aria-describedby="hint"><p id="hint" class="hint">Search filters the catalog; your selected courses stay in the plan.</p><div class="layout"><section id="catalog" aria-label="Course catalog"></section><aside class="plan"><h2>Your local plan</h2><div class="plan-total" role="status"><div class="number" id="minutes">0</div><span>minutes · <span id="count">0</span> <span id="course-word">courses</span></span></div><ul id="selected"></ul><p class="empty" id="empty">Add a course to start your plan.</p><small>No enrollment is submitted.</small></aside></div><p class="boundary">Independent HTML interpretation of Canvas composition patterns. Original palette, course illustrations and content; no Workday account or enrollment service is connected.</p></main><script>const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25,category:'Communication',description:'Practice clear observations and constructive next steps.',art:'◎',color:''},{id:'planning',name:'Planning a focused week',minutes:20,category:'Personal effectiveness',description:'Protect attention and organize a realistic working week.',art:'▤',color:'orange'},{id:'meetings',name:'Running inclusive meetings',minutes:30,category:'Teamwork',description:'Make space for different voices and useful decisions.',art:'◌',color:'green'}];let chosen=new Set;const catalog=document.querySelector('#catalog');function render(){let matches=courses.filter(c=>c.name.toLowerCase().includes(document.querySelector('#search').value.toLowerCase()));catalog.innerHTML=matches.length?matches.map(c=>`<article class="course"><div class="art ${c.color}" aria-hidden="true">${c.art}</div><div><div class="category">${c.category}</div><h2>${c.name}</h2><p>${c.description}</p><div class="row"><span>${c.minutes} minutes</span><button data-add="${c.id}" ${chosen.has(c.id)?'disabled':''}>${chosen.has(c.id)?'Added to plan':'Add to plan'}</button></div></div></article>`).join(''):'<div class="no-results">No matching courses. Try “feedback” or clear your search.</div>';let selected=courses.filter(c=>chosen.has(c.id));document.querySelector('#minutes').textContent=selected.reduce((sum,c)=>sum+c.minutes,0);document.querySelector('#count').textContent=selected.length;document.querySelector('#course-word').textContent=selected.length===1?'course':'courses';document.querySelector('#empty').hidden=selected.length>0;document.querySelector('#selected').innerHTML=selected.map(c=>`<li>${c.name}<button class="remove" data-remove="${c.id}" aria-label="Remove ${c.name}">Remove</button></li>`).join('');document.querySelectorAll('[data-add]').forEach(b=>b.onclick=()=>{let id=b.dataset.add;chosen.add(id);render();document.querySelector('[data-remove="'+id+'"]').focus()});document.querySelectorAll('[data-remove]').forEach(b=>b.onclick=()=>{let id=b.dataset.remove;chosen.delete(id);render();let add=document.querySelector('[data-add="'+id+'"]');(add||document.querySelector('#search')).focus()})}document.querySelector('#search').oninput=render;render();</script></html>
Aggiungere un corso modifica il piano di apprendimento di esempio. L’entry point nativo mostra separatamente CanvasProvider e il componente composto FormField API; non viene inviata alcuna richiesta di iscrizione.
Campo composto ed elementi di apprendimento selezionabili
FormField genera la relazione con l’input, TextInput filtra i dati originali dei corsi e ogni PrimaryButton aggiunge un elemento una sola volta. La rimozione ricalcola il totale selezionato.
jsx
// In a React 18+ application with a bundler:
// npm install @workday/canvas-kit-react @workday/canvas-tokens-web @workday/canvas-kit-styling @emotion/react @emotion/styled
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import {CanvasProvider} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {system} from '@workday/canvas-tokens-web';
import {cssVar} from '@workday/canvas-kit-styling';
import '@workday/canvas-tokens-web/css/base/_variables.css';
import '@workday/canvas-tokens-web/css/brand/_variables.css';
import '@workday/canvas-tokens-web/css/component/_variables.css';
import '@workday/canvas-tokens-web/css/system/_variables.css';
// Default theme example; do not silently add a Sana theme to an existing tenant.
const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25},{id:'planning',name:'Planning a focused week',minutes:20},{id:'meetings',name:'Running inclusive meetings',minutes:30}];
function LearningPlan(){
const [query,setQuery]=useState(''),[chosen,setChosen]=useState([]);
const visible=courses.filter(c=>c.name.toLowerCase().includes(query.toLowerCase()));
const selected=courses.filter(c=>chosen.includes(c.id));
return <main style={{fontFamily:cssVar(system.fontFamily.default),maxWidth:900,margin:'auto',padding:24}}>
<h1>Build a learning plan</h1>
<FormField><FormField.Label>Find a course</FormField.Label>
<FormField.Input as={TextInput} grow value={query} onChange={e=>setQuery(e.target.value)}/>
<FormField.Hint>Filter the three example course titles.</FormField.Hint>
</FormField>
<ul>{visible.map(c=><li key={c.id} style={{margin:'24px 0'}}><h2>{c.name}</h2><p>{c.minutes} minutes</p>
<PrimaryButton type="button" disabled={chosen.includes(c.id)} onClick={()=>setChosen(old=>[...old,c.id])}>
{chosen.includes(c.id)?'Added to plan':'Add to plan'}
</PrimaryButton></li>)}</ul>
{!visible.length&&<p>No matching courses.</p>}
<section aria-label="Learning plan"><h2>Your local plan</h2><p role="status">{selected.length} courses · {selected.reduce((sum,c)=>sum+c.minutes,0)} minutes</p>
<ul>{selected.map(c=><li key={c.id}>{c.name} <button type="button" onClick={()=>setChosen(old=>old.filter(id=>id!==c.id))}>Remove {c.name}</button></li>)}</ul>
<p>No enrollment is submitted.</p></section></main>;
}
createRoot(document.getElementById('root')).render(<CanvasProvider><LearningPlan/></CanvasProvider>);
PrimaryButton appartiene a ciascun corso indipendente; per l’intero piano non c’è un’azione Iscriviti fuorviante.
La rimozione usa un pulsante nativo esplicitamente gestito dall’applicazione.
Lo stato disabilitato Aggiunto impedisce duplicati, mentre un conteggio aggiornato in tempo reale conferma la modifica.
04
Configurazione dell’agente AI del sistema di progettazione sistema di design Workday Canvas
Punto di partenza per l’implementazione
Composizione React completa per un’applicazione con pacchetti inclusi. Configurazione attuale di CanvasProvider e dei livelli di token CSS; dati originali dei corsi e controlli nativi per la rimozione. Nessuna iscrizione remota. Codice sorgente verificato, ma non compilato come pacchetto in questo ambiente.
jsx
// In a React 18+ application with a bundler:
// npm install @workday/canvas-kit-react @workday/canvas-tokens-web @workday/canvas-kit-styling @emotion/react @emotion/styled
import React,{useState} from 'react';
import {createRoot} from 'react-dom/client';
import {CanvasProvider} from '@workday/canvas-kit-react/common';
import {FormField} from '@workday/canvas-kit-react/form-field';
import {TextInput} from '@workday/canvas-kit-react/text-input';
import {PrimaryButton} from '@workday/canvas-kit-react/button';
import {system} from '@workday/canvas-tokens-web';
import {cssVar} from '@workday/canvas-kit-styling';
import '@workday/canvas-tokens-web/css/base/_variables.css';
import '@workday/canvas-tokens-web/css/brand/_variables.css';
import '@workday/canvas-tokens-web/css/component/_variables.css';
import '@workday/canvas-tokens-web/css/system/_variables.css';
// Default theme example; do not silently add a Sana theme to an existing tenant.
const courses=[{id:'feedback',name:'Giving useful feedback',minutes:25},{id:'planning',name:'Planning a focused week',minutes:20},{id:'meetings',name:'Running inclusive meetings',minutes:30}];
function LearningPlan(){
const [query,setQuery]=useState(''),[chosen,setChosen]=useState([]);
const visible=courses.filter(c=>c.name.toLowerCase().includes(query.toLowerCase()));
const selected=courses.filter(c=>chosen.includes(c.id));
return <main style={{fontFamily:cssVar(system.fontFamily.default),maxWidth:900,margin:'auto',padding:24}}>
<h1>Build a learning plan</h1>
<FormField><FormField.Label>Find a course</FormField.Label>
<FormField.Input as={TextInput} grow value={query} onChange={e=>setQuery(e.target.value)}/>
<FormField.Hint>Filter the three example course titles.</FormField.Hint>
</FormField>
<ul>{visible.map(c=><li key={c.id} style={{margin:'24px 0'}}><h2>{c.name}</h2><p>{c.minutes} minutes</p>
<PrimaryButton type="button" disabled={chosen.includes(c.id)} onClick={()=>setChosen(old=>[...old,c.id])}>
{chosen.includes(c.id)?'Added to plan':'Add to plan'}
</PrimaryButton></li>)}</ul>
{!visible.length&&<p>No matching courses.</p>}
<section aria-label="Learning plan"><h2>Your local plan</h2><p role="status">{selected.length} courses · {selected.reduce((sum,c)=>sum+c.minutes,0)} minutes</p>
<ul>{selected.map(c=><li key={c.id}>{c.name} <button type="button" onClick={()=>setChosen(old=>old.filter(id=>id!==c.id))}>Remove {c.name}</button></li>)}</ul>
<p>No enrollment is submitted.</p></section></main>;
}
createRoot(document.getElementById('root')).render(<CanvasProvider><LearningPlan/></CanvasProvider>);
Un prompt per il tuo progetto
Prompt per l’agente
Usa l’attuale composizione FormField di Canvas e i livelli di token CSS. Mantieni separati il filtro dei corsi e lo stato di selezione, impedisci i duplicati e calcola il totale dei minuti. Preserva il tema del tenant tramite ruoli semantici; non confondere i nomi storici degli spazi numerati con le categorie di origine preferite attuali.
05
Origini e ambito del sistema di design Workday Canvas
Riferimento indipendente a OpenDesign. Non sono coinvolti iscrizioni dei dipendenti né Workday API. I nomi delle origini attuali e quelli più vecchi usati nella migrazione sono distinti esplicitamente.