Preskočiť na obsah

Skiny ​

Skin je jeden vzhľad rámca editora: lišty nástrojov, tlačidiel a skupín v nej, bublinových ponúk, rozbaľovacích ponúk, dialógov, rámca okolo obsahu a rámca výberu obrázka. Vyberá sa propom skin:

vue
<Tiptapify skin="pastel" />

Skin tvoria dve veci: tokeny (farby a rozmery ako premenné CSS) a tvar (štrukturálne varianty, ktoré token nevyjadrí). Dva vstavané skiny sú default — klasický vzhľad, zvýšený panel nástrojov so zvýšenými skupinami tlačidiel — a pastel, pokojný vzhľad. Vlastné skiny sú plnohodnotné: registerSkin() a inline objekty skinov sa spracúvajú úplne rovnakým mechanizmom a vstavané skiny sú registrované skiny, nie osobitné prípady.

Terminológia: skin vs téma Vuetify ​

  • skin — používateľský pojem pre jeden vzhľad rámca editora: tokeny + tvar. Prop sa volá skin, typy TiptapifySkin*, register registerSkin() a koreňová trieda tiptapify-skin-{name}.
  • theme (téma) — vyhradené pre svetlé a tmavé témy Vuetify. Komponenty Tiptapify majú svoje props theme napájané z názvu aktuálnej témy Vuetify; systém skinov sa ich nikdy nedotýka.

Dopĺňajú sa: väčšina farieb vstavaných tokenov odkazuje na premenné témy Vuetify (rgb(var(--v-theme-surface)), …), takže skiny automaticky sledujú svetlý a tmavý režim. Bunky s pevnou tmavou farbou v stĺpci classic — úchyt zmeny veľkosti (rgba(0, 0, 0, .5/.8)), obyčajný obrys obrázka, tieň bubliny a tiene vyvýšenia ponúk a dialógov — sú zámerné: klasický vzhľad kreslí neutrálny tmavý rámec v oboch témach a nameraný základ ich pripína. Vlastný skin môže na premenné témy odkazovať voľne — pozri tabuľku tokenov.

Koncept ​

Tokeny ​

Token je vlastnosť CSS s názvom --tf-*. Kľúč v katalógu je camelCase prípony CSS: toolbarBg → --tf-toolbar-bg, dialogTitleSize → --tf-dialog-title-size. Hodnoty sú obyčajné reťazce — farby, úplné skrátené zápisy okrajov, tiene, odsadenia, polomery.

Každé pravidlo skinu v knižnici existuje raz a číta svoj token s rezervou rovnou klasickej (základnej) hodnote:

css
.tiptapify-toolbar-group {
  border-radius: var(--tf-group-radius, 4px);
}

Vyriešený skin vypíše ako premenné iba svoje prepísania; základ nesú rezervné hodnoty CSS. Premenné sa dostanú na koreň editora — a keďže sa ponuky a dialógy z neho teleportujú, aj na obaľovač SkinScope každej ponuky a na samotnú kartu dialógu, takže tokeny sledujú každú plochu.

Tvar ​

Šesť príznakov určuje, ktoré sady pravidiel sa použijú; tokeny ich vykreslia:

príznakhodnotyčo prepína
toolbarraised · flatvyvýšenie VToolbar + bez vnútornej tenkej čiary vs plochý tónovaný panel
groupsbox · flatsekcie lišty nástrojov ako vyvýšené boxy VBtnGroup (značkovanie z 0.3.2: spojené tlačidlá, tokeny skupiny kreslia box) vs obyčajné rady div s flexom
buttonsvuetify · quietnatívne tlačidlá Vuetify vs priehľadné tlačidlá s neutrálnym stavom stlačenia
bubblecard · flatponechané pre kompatibilitu: bublinové ponuky sú v oboch tvaroch jeden riadok tlačidiel s ikonami vykreslený tokenmi (ich tlačidlá sledujú buttons)
dialogclassic · softoddeľovač pod titulkom, vyvýšené zatvorenie vs jemná karta, textové zatvorenie
menuvuetify · softrozbaľovacie ponuky: zoznam Vuetify vs svetlá karta s odsadením

Vyriešený tvar je zakódovaný na koreni editora ako šesť tried .tiptapify-shape-{flag}-{value} a pre vlastné komponenty lišty nástrojov je dostupný ako shape: ComputedRef<ResolvedShape> v useTiptapifyConfig().

Extends ​

Skin sa rieši nad klasickým základom, potom jeho reťazcom extends od koreňa a nakoniec jeho vlastnými členmi:

classic (base tokens + classic shape) → extends chain → own colors/metrics/flags

Chýbajúce články sa vyriešia na nazbieraný reťazec (s upozornením pre vývojára); cyklus sa vyrieši na classic (s upozornením pre vývojára). Registrovaný skin sa odkazuje názvom; inline objekt skinu môže použiť extends s registrovaným názvom a nikdy nevstúpi do globálneho registra — vlastné skiny sa nikdy nepresúvajú medzi editormi. Neznáme kľúče tokenov sa ignorujú s upozornením pre vývojára.

Živé ukážky všetkých troch foriem sú na stránke príkladov Skinov.

Katalóg tokenov ​

Tabuľky nižšie sú kontrakt v1: kľúče katalógu (TiptapifySkinColors / TiptapifySkinMetrics) sú názvy, ktoré môžete nastaviť. Bunky classic sú rezervné hodnoty CSS — hodnota, ktorú základné pravidlá kreslia, keď token neprepíše žiadny skin.

Lišta nástrojov / panel ​

tokenpremenná CSSclassicpastel
toolbarBg--tf-toolbar-bgrgb(var(--v-theme-surface))rgba(var(--v-theme-on-surface), 0.03)
toolbarBorderBottom--tf-toolbar-border-bottomnone1px solid rgba(var(--v-border-color), var(--v-border-opacity))
toolbarFg--tf-toolbar-fginheritrgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity))

Položky / skupiny / oddeľovače ​

tokenpremenná CSSclassicpastel
itemsPadding--tf-items-padding12px 16px6px 8px
itemsGap--tf-items-gapnormal ¹6px
itemsRowGap--tf-items-row-gap5px4px
groupGap--tf-group-gap0px2px
groupHeight--tf-group-height32pxauto
groupBg--tf-group-bgrgb(var(--v-theme-surface))transparent
groupRadius--tf-group-radius4px0px
groupShadow--tf-group-shadowvyvýšenie Vuetify 2 ²none
dividerWidth--tf-divider-width0px (rozpórka: margin 0 4px)1px
dividerHeight--tf-divider-height0px20px
dividerColor--tf-divider-colortransparentrgba(var(--v-border-color), var(--v-border-opacity))

¹ Nameraná bunka classic je normal — natívna hodnota flexu Vuetify, ktorú nesie rezervná hodnota CSS. Základná hodnota katalógu 0px je ekvivalentná explicitná dĺžka pre prepísania skinu.

² Bunky s textom „vyvýšenie Vuetify n“ sú popisné: presný reťazec trojitého tieňa je nameraná hodnota v odovzdanom základnom súbore fixture (src/skins/__fixtures__/skin-baseline.json) a je to rezervná hodnota CSS. Pre groupShadow je to vyvýšenie 2 (0 3px 1px -2px …, 0 2px 2px 0 …, 0 1px 5px 0 …) — pri groups: 'box' je sekcia VBtnGroup (elevation="4") a pravidlo tokenu kreslí box touto trojicou nad vlastným vyvýšením skupiny: box vlastní vyvýšenie, spojené podriadené tlačidlá žiadne nenesú.

Tlačidlá ​

Tieto tokeny sa používajú iba pri buttons: 'quiet' — pozri Dosiahnuteľnosť.

tokenpremenná CSShodnota quiet (classic: natívny Vuetify)
buttonFg--tf-button-fgrgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))
buttonHoverBg--tf-button-hover-bgrgba(var(--v-theme-on-surface), 0.07)
buttonHoverFg--tf-button-hover-fgrgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity))
buttonActiveBg--tf-button-active-bgrgba(var(--v-theme-on-surface), 0.1)
buttonActiveHoverBg--tf-button-active-hover-bgrgba(var(--v-theme-on-surface), 0.14)
buttonRadius--tf-button-radius6px

Bublinové ponuky (výber, prázdny riadok, obrázok) ​

tokenpremenná CSSclassicpastel
bubbleBg--tf-bubble-bgrgb(var(--v-theme-surface))rovnaké
bubbleBorder--tf-bubble-bordernone1px solid rgba(var(--v-border-color), var(--v-border-opacity))
bubbleShadow--tf-bubble-shadow0 4px 14px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.08)0 6px 20px rgba(0, 0, 0, 0.12)
bubbleRadius--tf-bubble-radius6px10px
bubblePadding--tf-bubble-padding4pxrovnaké
bubbleGap--tf-bubble-gap2pxrovnaké
tokenpremenná CSSclassicpastel
menuListPadding--tf-menu-list-padding8px 0px4px
menuRadius--tf-menu-radius4px8px
menuBorder--tf-menu-bordernone1px solid rgba(var(--v-border-color), var(--v-border-opacity))
menuShadow--tf-menu-shadowvyvýšenie Vuetify 8 ²0 4px 16px rgba(0, 0, 0, 0.08)
menuItemRadius--tf-menu-item-radius0px6px
menuItemPadding--tf-menu-item-paddingVuetify ³4px 8px
menuItemMinHeight--tf-menu-item-min-heightVuetify ³34px
menuItemActiveBg--tf-menu-item-active-bgVuetify ³rgba(var(--v-theme-on-surface), 0.06)

³ Box zoznamu (polomer, tieň, odsadenie zoznamu) klasickej ponuky je dnes pravidlo skinu — obaľovač tokenov SkinScope sa nachádza medzi vlastným pravidlom potomka Vuetify a zoznamom, takže knižnica tieto pixely obnovuje ako pravidlá skinu čítajúce vyššie uvedené tokeny. Pixely položiek zostávajú natívne Vuetify (fixture tam meria predvolené hodnoty Vuetify): štyri tokeny položiek sú pri menu: 'vuetify' nečinné.

Dialógy ​

tokenpremenná CSSclassicpastel
dialogShadow--tf-dialog-shadowvyvýšenie VCard ²0 20px 48px rgba(0, 0, 0, 0.16), 0 2px 6px rgba(0, 0, 0, 0.06)
dialogRadius--tf-dialog-radius4px (VCard)12px
dialogHeaderPadding--tf-dialog-header-padding8px 16px16px 12px 12px 20px
dialogContentPadding--tf-dialog-content-padding16px 24px 24px4px 20px
dialogActionsPadding--tf-dialog-actions-padding8px16px 20px 20px
dialogTitleSize--tf-dialog-title-size1.25rem1.125rem
dialogTitleWeight--tf-dialog-title-weight400600
dialogFieldRadius--tf-dialog-field-radiuspredvolená hodnota poľa (4px)8px (outlined)
dialogActionBtnMinHeight--tf-dialog-action-btn-min-heightVuetify (auto)38px
dialogActionBtnRadius--tf-dialog-action-btn-radiusVuetify (4px)8px
dialogGridGap--tf-dialog-grid-gap24px16px

Rámec (obal okraja editora) ​

tokenpremenná CSSclassicpastel
frameBorder--tf-frame-border1px solid rgba(var(--v-border-color), var(--v-border-opacity)), bez horného okrajaúplný okraj
frameBg--tf-frame-bgtransparentrgb(var(--v-theme-surface))
frameShadow--tf-frame-shadownone0 1px 2px rgba(0, 0, 0, 0.05)

Pri plochom tvare lišty nástrojov rámec kreslí aj deltu pre jednotlivé strany (horný okraj a spodný okraj s 1,6× krytím okraja). Táto delta patrí tvaru, nie tokenu: token ju nedosiahne.

Obrázky a úchyty zmeny veľkosti ​

tokenpremenná CSSclassicpastel
imageRadius--tf-image-radius0.125rem4px
imageBg--tf-image-bgtransparentrgba(var(--v-theme-on-surface), 0.04)
imageOutline--tf-image-outline1px solid rgba(0, 0, 0, 0.25) (vybraný)2px solid rgb(var(--v-theme-primary))
imageOutlineHover--tf-image-outline-hovertransparentrgba(var(--v-theme-primary), 0.35)
handleBg--tf-handle-bgrgba(0, 0, 0, 0.5)rgb(var(--v-theme-primary))
handleBgHover--tf-handle-bg-hoverrgba(0, 0, 0, 0.8) (hover)rgb(var(--v-theme-primary))
handleBorder--tf-handle-bordernone2px solid rgb(var(--v-theme-surface))
handleShadow--tf-handle-shadownone0 0 0 1px rgba(0, 0, 0, 0.15)
handleRadius--tf-handle-radius2px50%

Lišta obrázka sleduje príznak buttons: pri tichom tvare dostane tichú plochu — jej odsadenie 2px/4px číta --tf-bubble-gap / --tf-bubble-padding s rezervami ponuky obrázka; špeciálny token lišty obrázka neexistuje.

Nie je v katalógu (oblasť únikového východu) ​

Niektoré rozmery spomenuté v prehľade dizajnu nemajú vo v1 token v katalógu: výška lišty nástrojov, šírka rámca, polomer rámca, šírka tlačidla, odsadenie tlačidla, šírka dialógu. Tabuľky katalógu vyššie sú kontrakt; pre tieto pixely použite únikový východ a štýlujte stabilné triedy priamo.

Dosiahnuteľnosť ​

Kontrakt, ktorý stačí uviesť raz a dodržiava ho každá skupina vyššie:

Token kreslí plochu iba vtedy, keď túto plochu tvar aktivuje; natívne vizuály Vuetify sa štýlujú farbami témy Vuetify.

Podľa skupín:

  • Lišta nástrojov, rámec, rámec obrázka a úchytov — aktívne v každom tvare; tokeny ich kreslia, bunky classic sú natívny vzhľad, na ktorý sa tokeny vracajú.
  • Box skupín (groupBg, groupRadius, groupHeight, groupShadow) — pri groups: 'box' je sekcia VBtnGroup (štruktúra z 0.3.2: tlačidlá sa spoja, box nesie vyvýšenie); pravidlá boxu ho kreslia tokenmi skupiny a --tf-group-height drží kontrakt 32px s !important (pravidlo hustoty Vuetify s ním zápasí, ako v 0.3.2). Pri groups: 'flat' sú sekcie obyčajné rady div (priehľadné, bez tieňa, polomer 0 je základ tvaru).
  • Tenké čiary oddeľovačov (dividerWidth/Height/Color) — viditeľná tenká čiara je vlastnosť groups: 'flat'; v tvare box je oddeľovač rozpórka nulovej veľkosti (margin: 0 4px zo základného pravidla).
  • Odsadenie a medzery položiek — kompaktný rad 6px 8px je viazaný na plochý panel (toolbar: 'flat'), medzery skupín na ploché sekcie (groups: 'flat'); vyvýšený panel si ponecháva klasické metriky.
  • Tlačidlá (buttonFg, buttonHover*, buttonActive*, buttonRadius) — pri buttons: 'vuetify' nečinné: natívne tlačidlá Vuetify kreslia svoje stavy samy. Štýlujte ich farbami témy Vuetify (primary, surface, …) — klasické tvary ich zámerne preberajú.
  • Metriky položiek ponuky (menuItemRadius/Padding/MinHeight/ActiveBg) — pri menu: 'vuetify' nečinné; tieto pixely položiek vlastní Vuetify. Box zoznamu ponuky (polomer/tieň/odsadenie) kreslí skin v oboch tvaroch (pozri poznámku k ponuke).
  • Jemný rámec dialógu (dialogActionBtn*, dialogFieldRadius, jemné odsadenia, chýbajúci oddeľovač) — kreslí sa pri dialog: 'soft'; pri dialog: 'classic' je dialóg VCard s klasickým odsadením.
  • Rámec bubliny — ponuky výberu, prázdneho riadka a obrázka sú v oboch tvaroch jeden riadok tlačidiel s ikonami kreslený tokenmi bubliny; bubble už nemení ich značkovanie.

Prepísanie rovné základu katalógu sa nevypíše — pri nie klasickom tvare kreslí základ tvaru rezervná hodnota CSS, takže „obnovenie“ klasickej hodnoty (napr. nastavenie buttonActiveBg späť na rgb(var(--v-theme-primary)) pri buttons: 'quiet') potichu nič nespraví. Ak chcete pri neklasickom tvare vynútiť klasicky vyzerajúcu hodnotu, nastavte prepísanie, ktoré sa od základu katalógu líši — ekvivalentný literál, napríklad rgba(var(--v-theme-primary), 1), kreslí rovnako a vynechaniu unikne.

Tokeny zámerne nie sú zapojené do natívnych ciest — vďaka tomu zostáva default pixel-identický s klasickým vzhľadom, zatiaľ čo všetko prechádza katalógom.

Recepty ​

Rozšírenie pastelu ​

Zdedíte tichý tvar a prefarbíte niekoľko plôch. Registrované názvy fungujú na každom editore:

ts
// main.ts — call once, before any editor mounts
import { registerSkin } from 'tiptapify'

registerSkin('mint', {
  extends: 'pastel',
  colors: {
    toolbarBg: 'rgba(0, 128, 0, 0.05)',   // mint tint over the pastel wash
    handleBg: 'rgb(0, 100, 0)',           // deep green handles
    handleBgHover: 'rgb(0, 128, 0)',
    imageOutline: '2px solid rgb(0, 100, 0)',
    imageOutlineHover: 'rgba(0, 100, 0, 0.35)',
  },
})
vue
<Tiptapify skin="mint" />

Tvar (flat/quiet/soft) pochádza z pastelu; nedotknuté tokeny si ponechávajú hodnoty pastelu — tichý odtieň tlačidiel zostáva neutrálny, mení sa iba to, čo prepíšete. Tento skin je živo vykreslený na stránke príkladov.

Rozšírenie default ​

Ponechajte klasickú štruktúru a doladte farby:

ts
registerSkin('paper', {
  extends: 'default',
  colors: { toolbarBg: 'rgb(var(--v-theme-background))' },
  metrics: { groupRadius: '8px', itemsPadding: '10px 14px' },
})

extends: 'default' je implicitný koreň, takže kľúč možno vynechať: { toolbar: 'flat', … } tiež začína z classic.

Úplne vlastný ​

Bez extends, bez registrácie: odovzdajte objekt propu skin a príznaky tvaru a tokeny nastavujte voľne. name dá koreňovej triede vašu vlastnú značku (pozri nižšie); bez neho je to tiptapify-skin-inline.

vue
<script setup lang="ts">
import { defineSkin } from 'tiptapify'

const slate = defineSkin({
  name: 'slate',
  toolbar: 'flat',
  groups: 'flat',
  buttons: 'quiet',
  bubble: 'flat',
  dialog: 'soft',
  menu: 'soft',
  colors: { toolbarBg: 'rgb(30, 41, 59)', toolbarFg: 'rgb(226, 232, 240)' },
  metrics: { buttonRadius: '8px' },
})
</script>

<template>
  <Tiptapify :skin="slate" />
</template>

defineSkin je pomocná identitná funkcia pre typované konštantné definície (do registra nevstupuje). Príznaky tvaru možno nastaviť jednotlivo — každý vynechaný príznak zostáva classic.

Únikový východ: koreňová trieda ​

Koreň každého editora nesie tiptapify-skin-{name} (tiptapify-skin-inline pre inline objekt bez názvu). Knižnica nikdy nekľúčuje žiadne pravidlo na názov skinu — trieda je vaša:

css
/* Style the frame of one skin, dimensions the catalog does not cover */
.tiptapify-skin-mint .tiptapify-frame {
  max-width: 720px;
  margin-inline: auto;
}

Stabilné háčiky, na ktoré môžete písať štýly:

triedakde
tiptapify-skin-{name}koreň editora
tiptapify-shape-{flag}-{value} ×6koreň editora — vyriešený tvar
tiptapify-toolbar · tiptapify-toolbar-items · tiptapify-toolbar-group · menu-dividerlišta nástrojov a jej sekcie
tiptapify-quiet-buttonskorene lišty nástrojov a bubliny pri buttons: 'quiet'
tiptapify-bubble-row · tiptapify-bubble-dividerriadok každej bublinovej ponuky a tenká čiara medzi jej skupinami
tiptapify-bubble-menu · floating-menu · tiptapify-image-menuriadky ponúk výberu, prázdneho riadka a obrázka
tiptapify-btn--activestlačené tlačidlo bublinovej ponuky (aktívna značka, obtekanie obrázka)
tiptapify-menu · tiptapify-menu--softobsah prekrytia rozbaľovacej ponuky, nositeľ pravidiel jemnej ponuky
tiptapify-skin-scopediv s rozsahom tokenov vo vnútri teleportovaných ponúk
tiptapify-dialog · tiptapify-dialog--softkarta dialógu a jej jemný nositeľ
tiptapify-frameobal okraja editora

Obrana pred témou konzumenta. Vrstva skinov je postavená tak, aby prežila administrátorské témy, ktoré odsadzujú a prefarbujú vnútro Vuetify: pravidlá sa viažu na triedy tvaru/nositeľa, na špecifickosť používajú zdvojené triedy (.v-list.v-list, .v-btn.v-btn.v-btn) a !important ponechávajú len tam, kde sa to v prípade administrátorskej témy základného commitu ukázalo ako nevyhnutné (obranná sada menu.css). Konvencie, vďaka ktorým vaše vlastné prepísania fungujú na rovnakom bojisku:

  • svoje CSS ohraničte pod .tiptapify-skin-{name} (alebo triedu tvaru) — nikdy nie na holé vnútro Vuetify;
  • pre rozmery katalógu uprednostnite tokeny (--tf-*), pre zvyšok triedy;
  • pri prepisovaní komponentov Vuetify zopakujte zdvojenie (samotné .v-list-item prehrá s pravidlami skinu).

Vizuálny kontrakt (poznámka pre prispievateľov) ​

Vypočítané štýly vstavaných skinov pripína základný súbor fixture src/skins/__fixtures__/skin-baseline.json (13 sekcií × svetlá/tmavá): vrstva CSS je hotová, keď sa nameraná matica s ním zhoduje. Poznámky k čítaniu fixture:

  • Rozmery pre hover/active sa zo stránky nedajú vynútiť, preto záznam číta text deklarácie prvého zásahu pravidla CSSOM pre každý selektor hover a vyrieši ho cez sondu vo vnútri koreňa skinu (pole resolved) — je to kontrakt víťazného pravidla, nie živý snímok :hover.
  • _meta.selectors.menu zaznamenáva text selektora pred SkinScope. Fixture je zmrazený (normatívne hodnoty), takže pole je zámerne zastarané; záznamový balík pripína aktuálny selektor.
  • Fixture nesie svoje schválené zmeny v _meta.notes: obnovenie značkovania VBtnGroup pri groups: 'box' zo 2026-10-18 znovu zmeralo polia podriadených tlačidiel groupBtn/buttonsActive v classic (spojené rohy, box vlastní vyvýšenie). Polia pastelu zostávajú nedotknuté — zámerná vizuálna zmena aktualizuje iba dotknuté bunky classic, zaznamená poznámku a dodá riadok CHANGELOG.

Pozri tiež ​

Vydané pod licenciou MIT.