Software aziendale · Nuova risorsa

Workday Canvas Sistema di progettazione.

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.

Guida OpenDesign7 capitoli33 voci di riferimentoGuida applicativa originale
01

Anteprima dell’interfaccia del sistema di progettazione sistema di design Workday Canvas

Filtra i titoli dei corsi, aggiungi ciascun corso una sola volta, rimuovi le selezioni e confronta il totale delle ore in tempo reale.

Crea un piano di apprendimentoApri l’esempio completo
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.

Semantica attuale della spaziatura

Fonte
Nome / regolaValore / configurazioneUtilizzo
sys.padding.xs{base.size.100}Ruolo della spaziatura orizzontale dell’input.
sys.padding.md{base.size.200}Spaziatura predefinita del componente.
sys.padding.xl{base.size.300}Spaziatura interna della scheda.
sys.gap.sm{base.size.100}Distanza ridotta tra elementi affiancati.
sys.gap.md{base.size.200}Distanza predefinita tra elementi in linea.
sys.gap.xl{base.size.400}Spaziatura interna della scheda.
sys.gap.xxl{base.size.800}Distanza tra sezioni.

Tipografia e forme attuali

Fonte
Nome / regolaValore / configurazioneUtilizzo
sys.type.body.smfont-size body.sm + line-height body.sm + normal weightRuolo composito per il corpo del testo.
sys.font-size.body.sm{base.size.200}Alias della dimensione base del corpo del testo.
sys.line-height.body.sm{base.size.300}Alias dell’interlinea del corpo del testo.
sys.font-weight.normal{base.font-weight.400}Nome attuale: normal, non regular.
sys.shape.sm{base.size.50}Arrotondamento ridotto.
sys.shape.md{base.size.100}Arrotondamento dell’input.
sys.shape.full{base.size.75} × 100Arrotondamento completo.

Composizione di FormField

Fonte
Nome / regolaValore / configurazioneUtilizzo
FormField.LabelConnected label elementRelazione generata con l’input.
FormField.Input as={TextInput}Polymorphic input slotNon è la vecchia proprietà label API.
FormField.HintLinked helper contentDescrive l’input previsto.
orientationvertical / horizontalStart / horizontalEndUsa i valori di allineamento attuali.
FormField.FieldInput and hint alignment wrapperUtile nei layout orizzontali.

Implementazione di TextInput

Fonte
Nome / regolaValore / configurazioneUtilizzo
grow100% width when trueEspansione adattiva dell’input.
widthnumber or stringOverride facoltativo.
minimum width fallbackpx2rem(280)Controlla i layout con contenitori stretti.
errorerror / caution stylingLa validazione è gestita dall’applicazione.
transition0.2s box-shadow, 0.2s border-colorTransizione effettiva nel codice sorgente.
font size rolesystem.legacy.fontSize.subtext.lgNon sostituire i dettagli interni del componente con un tipo di titolo non pertinente.

Implementazione di PrimaryButton

Fonte
Nome / regolaValore / configurazioneUtilizzo
Backgroundbrand.action.base, with legacy accent fallbackBranding del tenant.
Hoverbrand.action.dark or colorSpace.hoverLo stato deriva dal colore dell’azione.
Pressedbrand.action.darkest or colorSpace.pressedStile di pressione distinto.
variant="inverse"Inverse surface and foreground rolesPer un contesto con contrasto adeguato.
Border radiussystem.legacy.shape.fullIl codice sorgente mantiene attualmente la compatibilità con la versione legacy.

Riferimento di migrazione, non nomi dei token attuali

Fonte
Nome / regolaValore / configurazioneUtilizzo
Former space.s → system.space.x41rem in 2023 migration tableIl codice sorgente attuale distingue la spaziatura interna dalla distanza.
Former space.m → system.space.x61.5rem in 2023 migration tableNon dare per scontato che i vecchi nomi siano ancora quelli preferiti.
Former borderRadius.m → system.shape.x10.25rem in 2023 migration tableIl codice sorgente attuale usa dimensioni semantiche per le forme.
03

Guida completa al sistema di progettazione sistema di design Workday Canvas

Una guida pratica per scegliere, applicare e valutare questo sistema in un’interfaccia reale.

DESIGN-workday-canvas.md

Indicazioni complete, un punto di partenza per l’implementazione e link alle fonti.

Scarica la guida

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.

Da questa guida su OpenDesign

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.

Leggi la specifica di supporto

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.

Leggi la specifica di supporto

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.

Leggi la specifica di supporto

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.

Leggi la specifica di supporto

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.

Leggi la specifica di supporto

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.

  1. Filtra solo la vista del catalogo.
  2. Aggiungi una sola volta ogni ID corso.
  3. Calcola i corsi selezionati e il totale dei minuti a partire da questi ID.
  4. Rimuovi una selezione senza azzerare la ricerca.

Leggi la specifica di supporto

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.

Leggi la specifica di supporto

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>

Riferimento del codice

  • 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>);

Riferimento del codice

  • 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.