Uvod: Figma da reagira

Kako smo koristili Figmin web API za pretvorbu dizajna u React kod

Zapošljavamo! Pogledajte puni popis otvorenih pozicija i fotografija našeg prozračnog ureda u San Franciscu na Figminoj karijeri.

Od pokretanja Figma API-ja, mnogi ljudi nagađaju o mogućnosti automatskog pretvaranja Figma dokumenata u React komponente. Neki od vas su zapravo napravili radne prototipove, a Pagedraw je čak izgradio čitav proizvod izgrađen oko njega!

Volimo entuzijazam i mislili smo da ćemo zajednički pokušati pretvoriti React, razgovarati o nekim suptilnim dizajnerskim izborima i tehničkim rješenjima koja su ušla u njegov razvoj, te objasniti viziju koja je motivirala njegovo stvaranje. Ako želite slijediti, otvorili smo kod na GitHub. (Previše sam uzbuđen da bih čitao ovaj post na blogu i želite se trenutno poigrati s našim API-jem za čitanje? Pogledajte našu stranicu za razvojne programere!)

Željeli smo riješiti dva glavna problema prilikom izgradnje Figme do React. Jedan je bio dizajnirati komponente koje generiramo kako bismo živjeli što više na Figmi. Koliko bi nevjerojatno bilo ažurirati dizajn na Figmi, a zatim kliknite gumb za sinkronizaciju promjena dizajna na vašoj web lokaciji? To također znači da moramo osigurati da ažuriranje vašeg dizajna ne prepiše bilo koji prilagođeni kôd koji smo napisali da bi web stranica ili aplikacija funkcionalni i da se, naravno, podvrgava da dizajnirani kôd dizajna i funkcijski kod odvojeno žive uredno odjeljaka.

Drugi, ali povezani cilj, bio je olakšati priključivanje postojećeg funkcionalnog koda na nove dizajne. Na primjer, u gore navedenom primjeru popisa, bilo bi lijepo kada bismo mogli dizajnirati novi poredani popis i lako priložiti kôd koji smo mu već napisali. Drugim riječima, bilo bi sjajno da se naš funkcionalni kod ponovo upotrebljava u različitim dizajnovima, baš poput načina na koji možete ponovno koristiti komponente React.

Koliko bi nevjerojatno bilo ažurirati dizajn na Figmi, a zatim kliknite gumb za sinkronizaciju promjena dizajna na vašoj web lokaciji?

Od Figma do CSS-a

Prva prepreka Figma-u do React-a bila je kreiranje komponenti React-a koje izgledaju poput dizajna koji predstavljaju - jer u protivnom nema mnogo smisla. Koristimo gornji primjer popisa za sortiranje:

Izvorna Figma datoteka

Postoji puno različitih načina na koje bismo mogli reproducirati izgled ovog popisa u HTML-u. Na primjer, mogli bismo prikazati sliku cijelog okvira i stvoriti komponentu koja samo crta tu sliku. Ovaj je pristup jednostavan, ali vrlo ograničen; Na primjer, gotovo je nemoguće ovdje napraviti nešto interaktivno poput klika na gumb za razvrstavanje.

Prva prepreka Figma-u do React-a bila je kreiranje komponenti React-a koje izgledaju poput dizajna koji predstavljaju - jer u protivnom nema mnogo smisla.

Upotrijebite apsolutni izgled za pozicioniranje čvorova

Bolji pristup bi bio da se okvir razbije na njegove sastavne dijelove, pretvori svaki komad u DOM element poput

ili , a zatim te DOM elemente sastavi zajedno. Sastavljanje ovih elemenata je postupak koji se naziva izgledom u kojem određujemo gdje treba svaki element postaviti i kako treba biti veličine u odnosu na svaki drugi element.

Figma API pruža čvrste temelje za određivanje izgleda. Svaki čvor u dokumentu ima svojstvo koje se naziva absolutniBingingBox. Koristeći absolutniBingingBox možemo utvrditi točno gdje svaki čvor trenutno živi na platnu i koliko prostora zauzima. Iz toga bi ideja bila uzeti svaki čvor, prikazati ga kao element, a zatim upotrijebiti CSS apsolutno pozicioniranje kako bi ga smjestili na stranicu. Ako to učinimo, možda ćemo dobiti nešto slično (primijetite da je okvir još uvijek zaglavljen u gornjem lijevom kutu):

To izgleda otprilike isto kao da smo čitav kadar stvorili kao sliku, ali već smo postigli velik napredak. Sada možemo odabrati tekst na popisu, možemo potencijalno zamijeniti tekst nečim dinamičnim, a događaje možemo priložiti klikom na različite stvari u sceni (poput strelica za razvrstavanje). Unatoč tome, i dalje postoje mnogi nedostaci. Ako ovom polju stavke na popisu dodamo puno teksta, tekst će se preliti van pravokutnika. Gledanje ovih apsolutnih granica ispada previše suviše ograničeno. Moramo olabaviti raspored i omogućiti elementima da dinamički promijene veličinu prema dizajnu.

Koristite Figma ograničenja kako biste dinamički promijenili veličinu čvorova

Figma i drugi alati za dizajn imaju koncept ograničenja koja se mogu primijeniti na sloj koji ih čini da promijene veličinu prema matičnom okviru. Ta se ograničenja odražavaju u API-ju kao svojstvu ograničenja, ovdje prikazanom za prethodni tekstni čvor:

"ograničenja": {
  "okomito": "TOP",
  "vodoravno": "LEFT_RIGHT"
}

Ovo kaže da bi ovaj određeni tekstni element trebao biti postavljen u odnosu na vrh nadređenog i treba se protezati s nadređenim vodoravno tako da su lijeva i desna margina sačuvana. Roditelj je u ovom slučaju pravokutnik koji okružuje "Popis stavke 1". Primjena ograničenja izvan okvira na apsolutno pozicioniranje izravno je preslikavanje atributa lijevo, desno, gornje i donje u CSS-u. To se bavi promjenom veličine i oblika spremnika popisa, ali ne i promjenom samog sadržaja popisa. Na primjer, kako bismo se prilagodili ako želimo dinamički dodati još jedan element popisa ili ako tekst koji se nalazi u tom popisnom elementu premašuje dimenzije izvornog okvira?

Izgled: odozdo ili odozdo?

Gornji problemi su ono što je sam HTML spretan u rješavanju. Ako dva elementa div postavite jedan na drugi, promjena visine prvog div automatski će gurnuti drugi div. Takvo ponašanje ne funkcionira u našoj situaciji jer je sve apsolutno postavljeno, pa su zaključani!

Slaganje div-a jedan iznad drugog na osnovu količine sadržaja u svakom je pristup koji ćemo nazvati izgledom odozdo prema gore, što znači da počinjemo od najnižih građevnih blokova (recimo, dijelova teksta) i stvaramo strukturu sastavljanjem ti blokovi zajedno da dobiju oblik slojeva više razine. Suprotno tome, ono što smo do sada radili je izgled odozgo prema dolje, u kojem određujemo koliko prostora treba zauzimati sloj koji se nalazi na vrhu, a zatim unutar njega stavimo elemente koji čine taj viši sloj. Što ako koristimo kombinaciju pristupa odozdo i odozdo prema gore?

Odlučimo o tome kako želimo reagirati kada se sadržaj unutar jednog od naših elemenata promijeni. U nekim je slučajevima odgovor očit:

Zamislite da su isprekidane kutije elementi koji žive unutar vanjskog okvira. Ako dodamo tekst na gornji element, trebali bismo gurnuti i sliku i donji tekst jednakom količinom. Ali postoje i druge situacije u kojima ispravno rješenje možda neće biti jasno:

Što činimo u slučajevima A i B ako želimo dodati tekst u prvi okvir? Rješenje s kojim sam završio bilo je pragmatično, ali u mnogim slučajevima nesavršeno. Glavni uvid je da je većina web lokacija uređena vertikalno, jer konvencija web stranica je da se pomičete odozgo prema gore da biste pogledali sav dostupni sadržaj. S obzirom na to, odlučio sam tretirati dječje elemente čvora kao da imaju linearni redoslijed od vrha do dna.

Primijenimo li to na prvi gornji primjer, naređivanje bi moglo izgledati ovako:

Ako želimo proširiti prvi tekstni okvir, sve naredbe nakon njega guramo redom prema dolje da odgovara iznosu koji je proširio za:

Primijetite da je u gornjem primjeru rezultat čudan, ali granično razuman. Suprotno tome, ovo je rezultat u B:

To najvjerojatnije nije ono što smo željeli: većina ljudi bi očekivala da slika i drugi tekstni okviri ostanu poravnati. Mnogo je načina na koje bismo mogli riješiti ovaj problem. Mogli bismo uvesti heuristiku poput „elementi koji su vertikalno usklađeni treba ostati vertikalno poravnani“ ili označiti čvorove na Figmi na određeni način da napomenu da bi trebali držati svoje vertikalne položaje. Isprobajte svoj vlastiti pristup izmjenom koda Figma u React i javite nam imate li neke nove ideje!

Pristup s 3 stope

Naoružani našom odlukom, sada se možemo vratiti općenitom problemu izgleda. Uzevši skup čvorova koji su poravnati TOP, možemo ih smjestiti jedan prema drugom određivanjem udaljenosti između dna prethodnog elementa i vrha trenutnog elementa:

Linearni izgled temeljen na marginama

Imajte na umu da ta marža može biti negativna. Tada jednostavno postavljamo ovu razliku na margin-top CSS svojstvo trenutnog elementa. Sada, ako se promijeni jedan element, drugi će teći gore i dolje po stranici kako se očekuje. Isto se može učiniti s BOTTOM poravnatim elementima, tretirajući ih kao zasebnu skupinu. Rezultat toga je da za bilo koji čvor možemo podijeliti njegove podređene elemente u tri skupine:

  • Skupina od TOP usklađenih elemenata, s izgledom odozdo prema gore
  • Skupina elemenata koji su poravnati CENTER, SCALE ili TOP_BOTTOM, postavljeni s apsolutnim (ili odozgo) izgledom
  • Skupina BOTTOM poravnatih elemenata, opet s izgledom odozdo prema gore
Izgled s 3 stope

Primijenimo li ove ideje na popis za sortiranje, sada možemo izbaciti potpuno reaktivnu komponentu koja oboje mijenja veličinu spremnika i prilagođava se promjenjivom sadržaju u sebi, kao što je prikazano u nastavku.

Zamotavanje i ograničenja na djelu

Jedna stvar koju treba istaknuti u ovom isječku jest da se podnožje u određenom trenutku prestane kretati - drugim riječima, dokument u fiksnoj točki prestaje biti kraći. Ovo je ključno kako bi se osiguralo da se podnožje podnožja ne nađe u glavnom sadržaju komponente. Međutim, to se ne može primijeniti kao minimalna visina elementa: kako tekst mijenja veličinu, tako minimalna visina mora rasti kako bi se prilagodio dodatni tekst. Rješenje ovdje je dodavanje donje margine elementima koji su usmjereni prema vrhu (i gornje granice do elemenata usmjerenih prema dnu) tako da se naslanjaju na suprotni kraj roditelja i "podupiru" roditelja otvoren do određene veličine ,

Istodobno istisnite

Za kraj, vratimo se natrag kako ograničenja od dna prema gore i od vrha prema dolje međusobno djeluju u slučaju gornjeg popisa. U ovom sljedećem primjeru ističemo tri elementa koji su od značaja za ispravnu veličinu stavki popisa: okvir koji sadrži (vanjski isprekidani okvir), tekstualno polje (unutarnji isprekidani okvir) i okrugla pravokutna obrub (ocrtani u punoj plavoj boji).

Ograničenja vizualizirana

Odnos tih elemenata je sljedeći: tekstualni element i pravokutna faza oboje su djeca okvira. Tekstualni element ima ograničenja LEFT_RIGHT i TOP, a pravokutnik LEFT_RIGHT i TOP_BOTTOM ograničenja. Kako se okvir sužava, tekst se mora utisnuti u drugi redak, povećavajući njegovu visinu. Budući da njegove margine ostaju konstantne, to uzrokuje da se i okvir koji sadrži sadrži povećava, što uzrokuje da se sljedeći okvir na popisu gurne prema dolje. U isto vrijeme, jer pravokutnik (opet plavom bojom) ima ograničenje TOP_BOTTOM na taj okvir, on također mora promijeniti veličinu i postati veći da bi zadovoljio to ograničenje. Dakle, imamo ograničenje odozdo prema gore gdje unutarnji tekst čini vanjski okvir većim, a zatim ograničenje odozgo prema dolje, gdje vanjski okvir čini unutarnji pravokutnik većim. Stvarno osjećam da je ovo jedna od onih interakcija u kojoj je rezultat potpuno neupadljiv (upravo bi to očekivali ponašanje), ali putovanje tamo je prilično kreativno.

Neka popis djeluje kao popis

Sada kada smo sebi postavili nešto nalik popisu, kako napraviti ovaj popis da nam napravi popis? Kako možemo, na primjer, učiniti da učitava proizvoljne podatke? Ili razvrstati te podatke?

Naš React pretvarač će morati ispljunuti neke datoteke s komponentama React u njima. Svaki put kad promijenimo dizajn, morat ćemo barem promijeniti dio sadržaja nekih od ovih datoteka kako bi predstavljali promjene u dizajnu. Da bi komponente napravile stvari, vjerojatno želimo negdje napisati kôd koji može komunicirati s generiranim komponentama. I na kraju, generator koji pišemo nikada ne bi smio prepisivati ​​od strane generatora i idealno bi mogao biti prenosiv s jedne komponente na drugu.

Već ste mogli primijetiti da prethodni odjeljak o dizajnu uopće ne ovisi o React. U pravu ste - mogli smo učiniti da naš pretvarač generira čist HTML i CSS i on bi funkcionirao jednako dobro kao i do sada. To je zato što čista pretvorba okvira Figma rezultira statičkom komponentom, a React ne pruža značajne prednosti kada je u pitanju stvaranje statičkog mjesta osim uporedivosti koda.

Sada kada smo sebi postavili nešto nalik popisu, kako napraviti ovaj popis da nam napravi popis?

Ali sada ćemo se morati jače nasloniti na React. Uvest ću samo dva osnovna koncepta koja sam zamislila da riješim problem sa funkcionalnošću. Njihova je prednost što su jednostavni, ali iznenađujuće moćni, ali ni na koji način ne podrazumijevam da su ti koncepti jedini načini za postizanje stvari - možda možete ponuditi ili implementirati vlastita rješenja za ovaj problem.

Naprave: kodovi koji se mogu višekratno koristiti i koji se drže dizajna

Prvi koncept koji želim uvesti je koncept gadgeta (koji se u kodu naziva „komponente“). Gadget je omotač koji obilazi bilo koji čvor u Figma dizajnu i dodaje mu dio funkcionalnosti - bilo koju funkcionalnost uopće. Možete stvoriti ili pričvrstiti gadget na čvor Figma tako što ćete ispred njegovog imena staviti hash simbol ("#").

Na primjer, ako želite reći da bi se okvir trebao ponašati kao sat, mogli biste ga imenovati #Clock. Ovo neće učiniti ništa posebno u samoj datoteci, ali će aktivirati taj čvor u gadgetiziranom pretvaraču - to će stvoriti gadget datoteku zvanu CClock.js koju možete ispuniti funkcionalnošću. Možda je najlakši način da se objasni to pokazuje primjer:

Uzorak generirani kod

U ovoj sceni imamo spremnik s dva okvira unutar. Jedan okvir sadrži sliku kruga, a drugi sliku kvadrata. Recimo da želimo da oba okvira pokazuju neko prilagođeno (ali isto) ponašanje, poput da želimo animirati oba oko vrtića. Svaki okvir možemo zamotati u isti Gadget (zvan #Spinner). Ovo će generirati prilagodljivu kodnu datoteku CSpinner.js. Generirana lijeva strana uputit će se na ovu komponentu svaki put kada se čvor označen kao #Spinner pojavi u stablu čvora. Kôd će također proslijediti nodeID uređaju koji može koristiti za traženje njegovog sadržaja u svakom slučaju - moć Gadgeta je što se mogu primijeniti na bilo koji čvor, tako da sadržaj čvora može varirati od slučaja do instance.

Gadget je omotač koji obilazi bilo koji čvor u Figma dizajnu i dodaje mu dio funkcionalnosti - bilo koju funkcionalnost uopće.

To znači da ako kodiramo CSpinner.js da sadržaj učini animiranim i vrti se oko njega, možemo napraviti bilo koji čvor da se okreće tako što ćemo ga imenovati #Spinner i na taj način pričvrstiti kôd gadgeta. Primijenimo li animacijski kôd na CSpinner, dobit ćemo ovo:

#Spinner u akciji

Primijetite da u svojoj funkciji rendera CSpinner komponenta jednostavno referencuje Component koji je dobiven od getComponentById. CSpinner nije svjestan što zamata - potpuno odvajanje funkcija od dizajna. Također imajte na umu da nakon što se generira CSpinner.js, nikad je nećemo prepisati: bilo kakve promjene učinjene na njemu održat će se bez obzira koliko puta regenerirali dizajne.

Varijable: zamjenite tekst rezerviranog mjesta dinamičkim vrijednostima

Varijable su drugi koncept koji uvodimo. Varijabla je jednostavno čvor teksta čije ime započinje s $. Takav čvor će po defaultu prikazati tekst u dizajnu, ali može ga nadjačati React rekvizit da pokaže proizvoljni tekst. Svojstvo koje nadjačava tekst isto je kao i ime čvora minus $. Tako, primjerice, ako imam čvor nazvan $ pile i rekviziti koji ulaze u taj element izgleda poput {chicken: "poptarts"}, tada će tekst tog čvora biti zamijenjen nizom "poptarts". Ova svojstva možete poslati dolje tako što ćete čvorove omotati varijablama u gadget.

Skupimo ovo sve zajedno: za naš poredani popis želimo nešto što može uzeti izvor podataka i popuniti unos popisa za svaku stavku u izvoru podataka. S obzirom na to da želimo uzeti jednu stavku popisa i duplicirati je više puta, ima smisla staviti gadget oko čvora koji odgovara stavci popisa. Takav uređaj može izgledati ovako:

O ovom isječku koda možemo izvršiti nekoliko opažanja:

  • Ovdje ne čitamo iz izvora podataka. Umjesto toga očekujemo da će biti donesen popis predmeta koji su već obrađeni. Razlog zašto će to postati vidljivo kasnije.
  • Naziv gadgeta započinje s nazivom C, što vrijedi za sve predloške gadgeta generirane pretvornikom. To će osigurati da uvijek možemo započeti s velikim slovom, što je React konvencija za nazive komponenata (drugi način bi bio samo velika slova s ​​velikim slovom).
  • Prema zadanim postavkama prikazujemo što je u Figma dokumentu ako nisu navedeni popisi. Ovo se preporučuje kako bi stranica mogla funkcionirati bez davanja izvora podataka.
  • Možemo koristiti komponentu, a to je čvor koji Gadget omota, više puta u funkciji prikazivanja! Na taj način možemo kopirati stavku popisa.
  • Svaku komponentu moramo zamotati u div. Ovo je cilj za primjenu položaja: relativni stil, što je potrebno u slučaju naše datoteke. Pojedinosti zbog čega to nije važno, ali lijepo je što to možemo učiniti. Imajte na umu da biste jednako lako mogli ovdje dodati klasu i stilski to dodati u CSS. Reagiranje zapravo obeshrabruje inline stilove u svom vodiču za stil. Možete zamisliti implementaciju pretvarača koji proizvodi CSS datoteku bez previše dodatnih poteškoća.

Pa zašto ne možemo jednostavno učitati izvor podataka izravno u ovu komponentu? Razlog je taj što želimo stvoriti popis za sortiranje, a kontrole za sortiranje su izvan ove komponente. Budući da se komponenta ListItems i gumbi za sortiranje uzlaznih i silaznih nalaze na potpuno različitim potkoljenicama, mogu međusobno komunicirati samo putem zajedničkog roditelja. Moraju razgovarati preko ovog roditelja, tako da i mi bismo mogli biti odgovorni za to što je kanonski izvor istine za elemente popisa.

Postoji više načina oko toga. Lako možete priključiti Redux na svaku komponentu i komunicirati putem akcija i globalne trgovine. To bi također imalo prednost što je održivije. Ali zbog jednostavnosti koda, pokazat ću kako postići isti krajnji rezultat samo s Reactom.

Učitajte prilagođene podatke u popis

Dalje postavimo uobičajenu roditeljsku komponentu:

Ako proslijedimo listSource ovom gadgetu, on će pokušati učitati URL pohranjen u listSource i spremiti rezultirajući raščlanjeni JSON objekt u listItems. Također definiramo dvije funkcije sortiranja i prenosimo ih kao svojstva na Component. Sada bilo koji čvor koji je potomak CSortableList-a može nazvati ove vrste sortiranja, a ako stavimo CListItems Gadget nizvodno od toga, moći će popis donijeti iz izvora podataka!

Na kraju ćemo ukratko pokazati Gadget koji pokreće razvrstavanje:

Ovaj je uređaj omotan oko gumba koji aktivira razvrstavanje popisa uzlaznim redoslijedom. Budući da je jedan od njegovih predaka CSortableList, u mogućnosti smo pozvati funkciju props.sortAscending () koja će uzrokovati promjenu stanja u CSortableList, pokrećući ponovno prikazivanje naprava CListItems i preuređivanje stavki popisa u njima. Priključimo sve ove Gadgete našem originalnom dizajnu, stvorimo CSortableList komponentu s listSource postavljenom na /shapes.json i pogledajte što se događa:

Razvrstavanje prilagođenih podataka

Ponovna upotreba koda

Ovaj konkretni primjer je sada funkcionalan! Još uzbudljivije je to što je sada kada imamo ovaj kôd, lako ga povezati s bilo čim što želimo napraviti na popisu za sortiranje imenovanjem čvorova na Figmi na ono što smo nazvali našim gadgetima. Uspjeli smo integrirati funkcionalnost u te gadget datoteke koje se mogu proizvoljno uklopiti na bilo koji Figma čvor. Je li to način na koji se trebaju graditi sučelja? Vjerojatno ne baš. Treba li ovdje naučiti lekcije i uvide koji se mogu prilagoditi poboljšanju načina na koji razmišljamo o interakciji dizajna i koda? Nadamo se.

Je li to način na koji se trebaju graditi sučelja? Vjerojatno ne baš.

Budući rad: izrada prototipa, CSS Grid, Layout Grids

Nekoliko ideja za proširenje Figme na React:

  • Poštujte veze za prototipiranje tako da klikom na element prijeđe aplikacija u drugo stanje
  • Provedite stanja lebdjenja
  • Stvorite tablicu stilova koja za izgled elemenata koristi CSS mrežu
  • Poštujte stupce i retke izgleda na Figma
  • Implementirajte podršku za rotirane čvorove (trenutno bilo koji čvor s rotacijom ili nagibom neće biti ispravno prikazan)

Idi na zapad

Ovdje smo predstavili ono za što se nadamo da će biti dijamant u grubim. Izložili smo našu strategiju za preslikavanje ograničenja u HTML i za dodavanje višekratnog koda dizajnu. Ako ste propustili vezu u uvodu, otvorili smo kod kod Github-a za Figma To React.

Primjenom sučelja može se koristiti prihvaćanjem koda, umjesto da dizajn i kôd žive u dva odvojena svijeta. Spajajući ih u zajedničku biblioteku, dizajneri i programeri mogu smanjiti posao i potrošiti vrijeme na ono što je važno: rješavanje većih izazova.

Želite li izgraditi nešto svoje pomoću našeg API-ja? Potražite inspiraciju na našoj stranici za razvojne programere i na kanalu Show & Tell na Spectrumu za zajednicu kolega majstora. Budućnost je da forsirate.