Showing preview only (432K chars total). Download the full file or copy to clipboard to get everything.
Repository: TrackMan/Unity.Package.FigmaToUnity
Branch: master
Commit: 6007b2fd106a
Files: 170
Total size: 390.7 KB
Directory structure:
gitextract_gbxs852s/
├── .azuredevops/
│ └── pull_request_template.md
├── .gitattributes
├── .gitignore
├── Assets/
│ ├── Panel Settings.asset
│ ├── Panel Settings.asset.meta
│ ├── UI Theme.tss
│ ├── UI Theme.tss.meta
│ ├── UnityBase.uss
│ └── UnityBase.uss.meta
├── Assets.meta
├── Editor/
│ ├── Assets/
│ │ └── icon.png.meta
│ ├── Assets.meta
│ ├── Core/
│ │ ├── Api.cs
│ │ ├── Api.cs.meta
│ │ ├── Assets/
│ │ │ ├── AssetsInfo.cs
│ │ │ ├── AssetsInfo.cs.meta
│ │ │ ├── CachedAssets.cs
│ │ │ ├── CachedAssets.cs.meta
│ │ │ ├── GradientWriter.cs
│ │ │ ├── GradientWriter.cs.meta
│ │ │ ├── ImagesPostprocessor.cs
│ │ │ └── ImagesPostprocessor.cs.meta
│ │ ├── Assets.meta
│ │ ├── JsonUtility.cs
│ │ ├── JsonUtility.cs.meta
│ │ ├── NodeMetadata.cs
│ │ ├── NodeMetadata.cs.meta
│ │ ├── NodesRegistry.cs
│ │ ├── NodesRegistry.cs.meta
│ │ ├── RichText/
│ │ │ ├── RichTextBuilder.cs
│ │ │ └── RichTextBuilder.cs.meta
│ │ ├── RichText.meta
│ │ ├── RootNodes.cs
│ │ ├── RootNodes.cs.meta
│ │ ├── StylesPreprocessor.cs
│ │ ├── StylesPreprocessor.cs.meta
│ │ ├── Uss/
│ │ │ ├── BaseUssStyle.cs
│ │ │ ├── BaseUssStyle.cs.meta
│ │ │ ├── Properties/
│ │ │ │ ├── AssetProperty.cs
│ │ │ │ ├── AssetProperty.cs.meta
│ │ │ │ ├── ColorProperty.cs
│ │ │ │ ├── ColorProperty.cs.meta
│ │ │ │ ├── CursorProperty.cs
│ │ │ │ ├── CursorProperty.cs.meta
│ │ │ │ ├── DurationProperty.cs
│ │ │ │ ├── DurationProperty.cs.meta
│ │ │ │ ├── EnumProperty.cs
│ │ │ │ ├── EnumProperty.cs.meta
│ │ │ │ ├── FlexProperty.cs
│ │ │ │ ├── FlexProperty.cs.meta
│ │ │ │ ├── IntegerProperty.cs
│ │ │ │ ├── IntegerProperty.cs.meta
│ │ │ │ ├── LayoutDouble4.cs
│ │ │ │ ├── LayoutDouble4.cs.meta
│ │ │ │ ├── Length2Property.cs
│ │ │ │ ├── Length2Property.cs.meta
│ │ │ │ ├── Length4Property.cs
│ │ │ │ ├── Length4Property.cs.meta
│ │ │ │ ├── LengthProperty.cs
│ │ │ │ ├── LengthProperty.cs.meta
│ │ │ │ ├── NumberProperty.cs
│ │ │ │ ├── NumberProperty.cs.meta
│ │ │ │ ├── ShadowProperty.cs
│ │ │ │ └── ShadowProperty.cs.meta
│ │ │ ├── Properties.meta
│ │ │ ├── StyleSlot.cs
│ │ │ ├── StyleSlot.cs.meta
│ │ │ ├── UssStyle.cs
│ │ │ ├── UssStyle.cs.meta
│ │ │ ├── UssWriter.cs
│ │ │ └── UssWriter.cs.meta
│ │ ├── Uss.meta
│ │ ├── Uxml/
│ │ │ ├── UxmlBuilder.cs
│ │ │ ├── UxmlBuilder.cs.meta
│ │ │ ├── UxmlWriter.cs
│ │ │ └── UxmlWriter.cs.meta
│ │ └── Uxml.meta
│ ├── Core.meta
│ ├── Extensions/
│ │ ├── Extensions.cs
│ │ ├── Extensions.cs.meta
│ │ ├── NodeExtensions.cs
│ │ ├── NodeExtensions.cs.meta
│ │ ├── UssStyleExtensions.cs
│ │ └── UssStyleExtensions.cs.meta
│ ├── Extensions.meta
│ ├── Figma.Editor.asmdef
│ ├── Figma.Editor.asmdef.meta
│ ├── FigmaDownloader.cs
│ ├── FigmaDownloader.cs.meta
│ ├── FigmaWriter.cs
│ ├── FigmaWriter.cs.meta
│ ├── Inspector/
│ │ ├── AuthTest.cs
│ │ ├── AuthTest.cs.meta
│ │ ├── FigmaInspector.cs
│ │ ├── FigmaInspector.cs.meta
│ │ ├── Styles.cs
│ │ └── Styles.cs.meta
│ ├── Inspector.meta
│ ├── Interface/
│ │ ├── Const.cs
│ │ ├── Const.cs.meta
│ │ ├── Enums.cs
│ │ ├── Enums.cs.meta
│ │ ├── Figma.Enums.cs
│ │ ├── Figma.Enums.cs.meta
│ │ ├── Figma.Types.Interface.cs
│ │ ├── Figma.Types.Interface.cs.meta
│ │ ├── Figma.Types.Structs.cs
│ │ ├── Figma.Types.Structs.cs.meta
│ │ ├── Figma.Types.cs
│ │ ├── Figma.Types.cs.meta
│ │ ├── Interface.Records.cs
│ │ └── Interface.Records.cs.meta
│ └── Interface.meta
├── Editor.meta
├── License.md
├── License.md.meta
├── Prefabs/
│ ├── Figma.prefab
│ └── Figma.prefab.meta
├── Prefabs.meta
├── Readme.md
├── Readme.md.meta
├── Runtime/
│ ├── AssemblyInfo.cs
│ ├── AssemblyInfo.cs.meta
│ ├── Core/
│ │ ├── Element.cs
│ │ ├── Element.cs.meta
│ │ ├── QueryAttribute.cs
│ │ ├── QueryAttribute.cs.meta
│ │ ├── UxmlAttribute.cs
│ │ ├── UxmlAttribute.cs.meta
│ │ ├── VisualElementMetadata.cs
│ │ └── VisualElementMetadata.cs.meta
│ ├── Core.meta
│ ├── Extensions/
│ │ ├── EnumerableExtensions.cs
│ │ ├── EnumerableExtensions.cs.meta
│ │ ├── Extensions.cs
│ │ ├── Extensions.cs.meta
│ │ ├── PathExtensions.cs
│ │ ├── PathExtensions.cs.meta
│ │ ├── VisualElementExtensions.cs
│ │ └── VisualElementExtensions.cs.meta
│ ├── Extensions.meta
│ ├── Figma.asmdef
│ ├── Figma.asmdef.meta
│ ├── Figma.cs
│ ├── Figma.cs.meta
│ ├── Interface/
│ │ ├── Const.cs
│ │ ├── Const.cs.meta
│ │ ├── Core/
│ │ │ ├── SubElements.cs
│ │ │ ├── SubElements.cs.meta
│ │ │ ├── SyncElements.cs
│ │ │ └── SyncElements.cs.meta
│ │ ├── Core.meta
│ │ ├── Enums.cs
│ │ ├── Enums.cs.meta
│ │ ├── Interface.Core.cs
│ │ ├── Interface.Core.cs.meta
│ │ ├── Interfaces.cs
│ │ └── Interfaces.cs.meta
│ └── Interface.meta
├── Runtime.meta
├── package.json
├── package.json.meta
├── ~Samples/
│ ├── Scripts/
│ │ ├── Figma.Samples.asmdef
│ │ ├── Figma.Samples.asmdef.meta
│ │ ├── Test.cs
│ │ └── Test.cs.meta
│ ├── Scripts.meta
│ ├── Test.unity
│ └── Test.unity.meta
└── ~Samples.meta
================================================
FILE CONTENTS
================================================
================================================
FILE: .azuredevops/pull_request_template.md
================================================
# ⚠️ Before you merge ⚠️
1. 👘 Ensure that your code follows the [codestyle](https://dev.azure.com/trackman/Golf/_wiki/wikis/Golf.wiki/35/Code-Style)
2. 🧠 Ensure that you created PRs for ALL branches
3. 🍄 Test your code by finishing one golf round (download fresh course if tools were changed)
4. 🖼️ Submit a screenshot of a finished golf round
5. 💾 Write a [proper](https://keepachangelog.com/en/1.0.0/) description
================================================
FILE: .gitattributes
================================================
# Default
* text=auto
# Unity
*.cs text
*.shader text
*.hlsl text
*.cginc text
# Unity YAML
*.anim merge=unityyamlmerge auto
*.asset merge=unityyamlmerge auto
*.controller merge=unityyamlmerge auto
*.mat merge=unityyamlmerge auto
*.meta merge=unityyamlmerge auto
*.physicsMaterial merge=unityyamlmerge auto
*.physicsMaterial2D merge=unityyamlmerge auto
*.prefab merge=unityyamlmerge auto
*.unity merge=unityyamlmerge auto
# Unity LFS
*.cubemap filter=lfs diff=lfs merge=lfs
*.unitypackage filter=lfs diff=lfs merge=lfs
# Image
*.ai filter=lfs diff=lfs merge=lfs
*.apng filter=lfs diff=lfs merge=lfs
*.astc filter=lfs diff=lfs merge=lfs
*.bmp filter=lfs diff=lfs merge=lfs
*.dds filter=lfs diff=lfs merge=lfs
*.eps filter=lfs diff=lfs merge=lfs
*.exr filter=lfs diff=lfs merge=lfs
*.gif filter=lfs diff=lfs merge=lfs
*.hdr filter=lfs diff=lfs merge=lfs
*.jpeg filter=lfs diff=lfs merge=lfs
*.jpg filter=lfs diff=lfs merge=lfs
*.JPG filter=lfs diff=lfs merge=lfs
*.ktx filter=lfs diff=lfs merge=lfs
*.png filter=lfs diff=lfs merge=lfs
*.PNG filter=lfs diff=lfs merge=lfs
*.psd filter=lfs diff=lfs merge=lfs
*.pvr filter=lfs diff=lfs merge=lfs
*.svg filter=lfs diff=lfs merge=lfs
*.svgz filter=lfs diff=lfs merge=lfs
*.tga filter=lfs diff=lfs merge=lfs
*.TGA filter=lfs diff=lfs merge=lfs
*.tif filter=lfs diff=lfs merge=lfs
*.tiff filter=lfs diff=lfs merge=lfs
*.webm filter=lfs diff=lfs merge=lfs
*.webp filter=lfs diff=lfs merge=lfs
# Audio
*.aif filter=lfs diff=lfs merge=lfs
*.m4a filter=lfs diff=lfs merge=lfs
*.mp3 filter=lfs diff=lfs merge=lfs
*.ogg filter=lfs diff=lfs merge=lfs
*.wav filter=lfs diff=lfs merge=lfs
*.WAV filter=lfs diff=lfs merge=lfs
# Video
*.asf filter=lfs diff=lfs merge=lfs
*.avi filter=lfs diff=lfs merge=lfs
*.flv filter=lfs diff=lfs merge=lfs
*.mov filter=lfs diff=lfs merge=lfs
*.mp4 filter=lfs diff=lfs merge=lfs
*.mpeg filter=lfs diff=lfs merge=lfs
*.mpg filter=lfs diff=lfs merge=lfs
*.ogv filter=lfs diff=lfs merge=lfs
*.wmv filter=lfs diff=lfs merge=lfs
# 3D Object
*.blend filter=lfs diff=lfs merge=lfs
*.dxf filter=lfs diff=lfs merge=lfs
*.fbx filter=lfs diff=lfs merge=lfs
*.FBX filter=lfs diff=lfs merge=lfs
*.lxo filter=lfs diff=lfs merge=lfs
*.ma filter=lfs diff=lfs merge=lfs
*.max filter=lfs diff=lfs merge=lfs
*.mb filter=lfs diff=lfs merge=lfs
*.obj filter=lfs diff=lfs merge=lfs
*.raw filter=lfs diff=lfs merge=lfs
*.spm filter=lfs diff=lfs merge=lfs
*.sbk filter=lfs diff=lfs merge=lfs
# Compiled Dynamic Library
*.dll filter=lfs diff=lfs merge=lfs
*.pdb filter=lfs diff=lfs merge=lfs
*.so filter=lfs diff=lfs merge=lfs
*.bundle filter=lfs diff=lfs merge=lfs
# Compiled Static Library
*.a filter=lfs diff=lfs merge=lfs
*.la filter=lfs diff=lfs merge=lfs
*.lai filter=lfs diff=lfs merge=lfs
*.lib filter=lfs diff=lfs merge=lfs
*.llblgenproj filter=lfs diff=lfs merge=lfs
# Font
*.otf filter=lfs diff=lfs merge=lfs
*.OTF filter=lfs diff=lfs merge=lfs
*.ttf filter=lfs diff=lfs merge=lfs
*.TTF filter=lfs diff=lfs merge=lfs
*.pdf filter=lfs diff=lfs merge=lfs
# CommandLine Utility
*.exe filter=lfs diff=lfs merge=lfs
# Archives
*.zip filter=lfs diff=lfs merge=lfs
*.rar filter=lfs diff=lfs merge=lfs
*.7z filter=lfs diff=lfs merge=lfs
================================================
FILE: .gitignore
================================================
/[Ll]ibrary/
/[Tt]emp/
/[Ll]ogs/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Uu]ser[Ss]ettings/
/Assets/StreamingAssets*
/Assets/UnityEngine*
/Assets/Temp*
/Packages/com.*
/ProjectSettings/Packages*
/ProjectSettings/boot.config
/ProjectSettings/SceneTemplateSettings.json
# Visual Studio cache directory
/.vs/
/.vscode/
.vsconfig
# Rider cache directory
/.idea/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.code*
# Unity3D generated meta files
*.pidb.meta
# Unity3D generated packages
packages-lock.json
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.aab
*.unitypackage
# OSX files
.DS_Store
# Generated by analyzers
/Assets/Default.ruleset
/Assets/Default.ruleset.meta
# Pipeline files
*.netrc
================================================
FILE: Assets/Panel Settings.asset
================================================
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0}
m_Name: Panel Settings
m_EditorClassIdentifier:
themeUss: {fileID: -4733365628477956816, guid: 999af05a3e7a25744b50c66afc0ac938, type: 3}
m_TargetTexture: {fileID: 0}
m_ScaleMode: 2
m_ReferenceSpritePixelsPerUnit: 100
m_Scale: 1
m_ReferenceDpi: 96
m_FallbackDpi: 96
m_ReferenceResolution: {x: 1920, y: 1080}
m_ScreenMatchMode: 0
m_Match: 0
m_SortingOrder: 0
m_TargetDisplay: 0
m_ClearDepthStencil: 1
m_ClearColor: 0
m_ColorClearValue: {r: 0, g: 0, b: 0, a: 0}
m_DynamicAtlasSettings:
m_MinAtlasSize: 64
m_MaxAtlasSize: 4096
m_MaxSubTextureSize: 64
m_ActiveFilters: 31
m_AtlasBlitShader: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0}
m_RuntimeShader: {fileID: 9100, guid: 0000000000000000f000000000000000, type: 0}
m_RuntimeWorldShader: {fileID: 9102, guid: 0000000000000000f000000000000000, type: 0}
textSettings: {fileID: 0}
================================================
FILE: Assets/Panel Settings.asset.meta
================================================
fileFormatVersion: 2
guid: f486055d8ec653edc96c3f3c38380c8f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/UI Theme.tss
================================================
@import url("unity-theme://default");
@import url("/Packages/com.trackman.figma/Assets/UnityBase.uss");
VisualElement {}
================================================
FILE: Assets/UI Theme.tss.meta
================================================
fileFormatVersion: 2
guid: 999af05a3e7a25744b50c66afc0ac938
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
================================================
FILE: Assets/UnityBase.uss
================================================
:root {
--selection-color: #5890DE;
--cursor-color: #FFFFFF;
}
.unity-base-field {
flex-direction: row;
margin: initial;
overflow: hidden;
flex-shrink: 0;
--unity-sync-text-editor-engine: true;
}
.unity-base-text-field {
white-space: nowrap;
--unity-selection-color: var(--selection-color);
--unity-cursor-color: var(--cursor-color);
}
.unity-base-field__input {
flex: 1 0 0;
overflow: hidden;
margin: initial;
}
.unity-base-text-field__input {
padding: initial;
border-radius: initial;
cursor: initial;
-unity-overflow-clip-box: content-box;
flex: 1 1 auto;
background-color: initial;
border-color: initial;
border-width: initial;
margin: initial;
--unity-sync-text-editor-engine: true;
}
.unity-base-text-field__input:focus,
.unity-base-text-field__input:hover,
.unity-base-text-field:focus > .unity-base-text-field__input,
.unity-base-text-field:hover > .unity-base-text-field__input {
border-color: var(--selection-color);
}
.unity-base-slider, .unity-base-slider__dragger, .unity-base-slider__tracker {
border-width: initial;
border-color: initial;
background-color: initial;
}
.unity-base-slider:focus, .unity-base-slider__dragger, .unity-base-slider__tracker {
border-color: initial;
}
.unity-base-slider--vertical, .unity-base-slider__dragger, .unity-base-slider__tracker {
margin: initial;
}
.unity-scroller, .unity-base-slider__dragger, .unity-base-slider__tracker {
border-color: initial;
background-color: initial;
}
.unity-scroller--vertical, .unity-base-slider__dragger, .unity-base-slider__tracker {
left: initial;
top: initial;
margin: initial;
border-width: initial;
border-color: initial;
background-color: initial;
}
.unity-scroller--vertical > .unity-scroller__slider {
margin: initial;
width: initial;
}
================================================
FILE: Assets/UnityBase.uss.meta
================================================
fileFormatVersion: 2
guid: d97716672acb0ee45bf6697e5adadcdd
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
================================================
FILE: Assets.meta
================================================
fileFormatVersion: 2
guid: 7eedcbb7c4cee534cb8f55eaaa55ee65
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Assets/icon.png.meta
================================================
fileFormatVersion: 2
guid: c0cc7a4d45c57758c894e807bb1af36b
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 1
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Assets.meta
================================================
fileFormatVersion: 2
guid: 5b1014bd7c33f18afb1f58ad7f928370
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Core/Api.cs
================================================
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Figma
{
using Internals;
internal abstract class Api : IDisposable
{
#region Fields
protected readonly string fileKey;
protected readonly HttpClient httpClient;
#endregion
#region Constructors
protected Api(string personalAccessToken, string fileKey)
{
this.fileKey = fileKey;
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("X-FIGMA-TOKEN", personalAccessToken);
}
#endregion
#region Methods
void IDisposable.Dispose() => httpClient.Dispose();
#endregion
#region Support Methods
protected async Task<T> ConvertOnBackgroundAsync<T>(string json, CancellationToken token) where T : class => await Task.Run(() => Task.FromResult(JsonUtility.FromJson<T>(json)), token);
protected async Task<T> GetAsync<T>(string get, CancellationToken token = default) where T : class => await ConvertOnBackgroundAsync<T>(await GetJsonAsync(get, token), token);
protected async Task<string> GetJsonAsync(string get, CancellationToken token = default) => await HttpGetAsync($"{Internals.Const.api}/{get}", token);
async Task<string> HttpGetAsync(string url, CancellationToken token = default)
{
using HttpRequestMessage request = new(HttpMethod.Get, url);
HttpResponseMessage response = await httpClient.SendAsync(request, token);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
throw new HttpRequestException($"{HttpMethod.Get} {url} {response.StatusCode.ToString()}");
}
#endregion
}
}
================================================
FILE: Editor/Core/Api.cs.meta
================================================
fileFormatVersion: 2
guid: 3206e4d9910843d38b90ab361b9a297b
timeCreated: 1696830500
================================================
FILE: Editor/Core/Assets/AssetsInfo.cs
================================================
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
namespace Figma.Core.Assets
{
using Internals;
using static Internals.Const;
internal class AssetsInfo
{
#region Fields
internal readonly string directory;
internal readonly string relativeDirectory;
internal readonly CachedAssets cachedAssets;
internal readonly ConcurrentBag<string> modifiedContent;
readonly IReadOnlyList<string> fontDirectories;
#endregion
#region Constructors
internal AssetsInfo(string directory, string relativeDirectory, string remapsFileName, IReadOnlyList<string> fontDirectories)
{
this.directory = directory;
this.relativeDirectory = relativeDirectory;
this.fontDirectories = fontDirectories;
modifiedContent = new ConcurrentBag<string>();
cachedAssets = new CachedAssets(directory, remapsFileName);
}
#endregion
#region Methods
internal bool GetAssetPath(string name, string extension, out string path)
{
switch (extension)
{
case KnownFormats.otf or KnownFormats.ttf:
path = GetFontPath(name, extension);
return path.NotNullOrEmpty();
case KnownFormats.asset:
string fontAssetPath = GetFontPath(name, extension);
string fontDirectoryPath = Path.GetDirectoryName(fontAssetPath);
string file = $"{name} SDF.{extension}";
path = fontDirectoryPath.NotNullOrEmpty() ? file : PathExtensions.CombinePath(fontDirectoryPath, file);
return fontAssetPath.NotNullOrEmpty();
case KnownFormats.png or KnownFormats.svg:
string mappedName = cachedAssets[name];
path = PathExtensions.CombinePath(imagesDirectoryName, $"{mappedName}.{extension}");
return File.Exists(PathExtensions.CombinePath(directory, path));
default:
throw new NotSupportedException(extension);
}
}
internal void AddModifiedFiles(params string[] items) => items.ForEach(item => modifiedContent.Add(item));
internal string GetAbsolutePath(string path) => PathExtensions.CombinePath(directory, path);
#endregion
#region Support Methods
string GetFontPath(string name, string extension)
{
string file = $"{name}.{extension}";
string localFontsPath = PathExtensions.CombinePath(fontsDirectoryName, file);
string relativePath = PathExtensions.CombinePath(relativeDirectory, localFontsPath);
if (File.Exists(FileUtil.GetPhysicalPath(relativePath)))
return PathExtensions.unixPathSeperator + relativePath;
foreach (string fontsDirectory in fontDirectories)
{
string projectFontPath = PathExtensions.CombinePath(fontsDirectory, file);
if (File.Exists(FileUtil.GetPhysicalPath(projectFontPath)))
return PathExtensions.unixPathSeperator + projectFontPath;
}
return null;
}
#endregion
}
}
================================================
FILE: Editor/Core/Assets/AssetsInfo.cs.meta
================================================
fileFormatVersion: 2
guid: 45f0ac71191d448fb945cd8b96c71dd0
timeCreated: 1733916355
================================================
FILE: Editor/Core/Assets/CachedAssets.cs
================================================
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Figma.Core.Assets
{
using Internals;
using static Internals.PathExtensions;
internal sealed class CachedAssets
{
#region Fields
readonly string targetFilePath;
#endregion
#region Constructor
internal CachedAssets(string directory, string name) => targetFilePath = CombinePath(directory, $"{nameof(CachedAssets)}-{name}.{KnownFormats.json}");
#endregion
#region Properties
internal Dictionary<string, string> Map { get; private set; }
#endregion
#region Operators
internal string this[string key]
{
get => Map.GetValueOrDefault(key, key);
set => Map[key] = value;
}
#endregion
#region Methods
internal async Task LoadAsync(CancellationToken token) => Map = File.Exists(targetFilePath) ? JsonUtility.FromJson<Dictionary<string, string>>(await File.ReadAllTextAsync(targetFilePath, token)) : new Dictionary<string, string>();
internal async Task SaveAsync() => await File.WriteAllTextAsync(targetFilePath, JsonUtility.ToJson(Map, prettyPrint: true));
#endregion
}
}
================================================
FILE: Editor/Core/Assets/CachedAssets.cs.meta
================================================
fileFormatVersion: 2
guid: 17a02e0c1cba42429bc345ea5794a854
timeCreated: 1733918400
================================================
FILE: Editor/Core/Assets/GradientWriter.cs
================================================
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using UnityEngine;
namespace Figma.Core.Assets
{
using Internals;
using static Const;
internal class GradientWriter : IDisposable
{
#region Fields
static readonly XmlWriterSettings xmlWriterSettings = new()
{
Indent = true,
NewLineOnAttributes = true,
NewLineChars = Environment.NewLine,
IndentChars = indentCharacters,
Async = true
};
readonly XmlWriter writer;
#endregion
#region Constructors
public GradientWriter(string xmlPath) => writer = XmlWriter.Create(xmlPath, xmlWriterSettings);
#endregion
#region Methods
public async Task WriteAsync(GradientPaint gradient, CancellationToken token)
{
writer.WriteStartElement(KnownFormats.svg);
writer.WriteStartElement("defs");
switch (gradient.type)
{
case PaintType.GRADIENT_LINEAR:
writer.WriteStartElement("linearGradient");
writer.WriteAttributeString("id", nameof(gradient));
for (int i = 0; i < Mathf.Max(gradient.gradientHandlePositions.Length, 2); ++i)
{
writer.WriteAttributeString($"x{i + 1}", gradient.gradientHandlePositions[i].x.ToString("F2", Culture));
writer.WriteAttributeString($"y{i + 1}", gradient.gradientHandlePositions[i].y.ToString("F2", Culture));
}
break;
case PaintType.GRADIENT_RADIAL:
case PaintType.GRADIENT_DIAMOND:
writer.WriteStartElement("radialGradient");
writer.WriteAttributeString("id", nameof(gradient));
writer.WriteAttributeString("fx", gradient.gradientHandlePositions[0].x.ToString("F2", Culture));
writer.WriteAttributeString("fy", gradient.gradientHandlePositions[0].y.ToString("F2", Culture));
writer.WriteAttributeString("cx", gradient.gradientHandlePositions[0].x.ToString("F2", Culture));
writer.WriteAttributeString("cy", gradient.gradientHandlePositions[0].y.ToString("F2", Culture));
Vector2 a = new ((float)gradient.gradientHandlePositions[1].x, (float)gradient.gradientHandlePositions[1].y);
Vector2 b = new ((float)gradient.gradientHandlePositions[0].x, (float)gradient.gradientHandlePositions[0].y);
float radius = (a - b).magnitude;
writer.WriteAttributeString("r", radius.ToString("F2", Culture));
break;
default:
throw new NotSupportedException();
}
foreach (ColorStop stop in gradient.gradientStops)
{
writer.WriteStartElement(nameof(stop));
writer.WriteAttributeString("offset", stop.position.ToString("F2", Culture));
writer.WriteAttributeString("style", $"stop-color:rgb({(byte)(stop.color.r * 255)},{(byte)(stop.color.g * 255)},{(byte)(stop.color.b * 255)});stop-opacity:{stop.color.a.ToString("F2", Culture)}");
await writer.WriteEndElementAsync();
}
await writer.WriteEndElementAsync();
token.ThrowIfCancellationRequested();
await writer.WriteEndElementAsync();
token.ThrowIfCancellationRequested();
writer.WriteStartElement("rect");
writer.WriteAttributeString("width", "100");
writer.WriteAttributeString("height", "100");
writer.WriteAttributeString("fill", "url(#gradient)");
if (gradient.opacity < 1.0)
writer.WriteAttributeString("fill-opacity", gradient.opacity.ToString("F2", Culture));
await writer.WriteEndElementAsync();
token.ThrowIfCancellationRequested();
await writer.WriteEndElementAsync();
token.ThrowIfCancellationRequested();
}
public void Dispose() => writer?.Close();
#endregion
}
}
================================================
FILE: Editor/Core/Assets/GradientWriter.cs.meta
================================================
fileFormatVersion: 2
guid: ec2d941c5d164f0b8887c69795bd3767
timeCreated: 1734429409
================================================
FILE: Editor/Core/Assets/ImagesPostprocessor.cs
================================================
using Unity.VectorGraphics.Editor;
using UnityEditor;
#pragma warning disable S1144 // Called from Unity
namespace Figma.Core.Assets
{
internal class ImagesPostprocessor : AssetPostprocessor
{
#region Methods
void OnPreprocessAsset()
{
if (!assetPath.Contains("UI/Assets/Images")) return;
if (assetImporter is SVGImporter svgImporter)
#if UNITY_6000_3_OR_NEWER
svgImporter.SvgType = SVGType.UISVGImage;
#else
svgImporter.SvgType = SVGType.UIToolkit;
#endif
if (assetImporter is not TextureImporter textureImporter)
return;
textureImporter.npotScale = TextureImporterNPOTScale.None;
textureImporter.mipmapEnabled = false;
TextureImporterPlatformSettings androidOverrides = textureImporter.GetPlatformTextureSettings("Android");
androidOverrides.overridden = true;
androidOverrides.format = TextureImporterFormat.ETC2_RGBA8Crunched;
androidOverrides.compressionQuality = 90;
textureImporter.SetPlatformTextureSettings(androidOverrides);
}
#endregion
}
}
================================================
FILE: Editor/Core/Assets/ImagesPostprocessor.cs.meta
================================================
fileFormatVersion: 2
guid: 830782a47c09eebd4b66c78e8b91c6a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Core/Assets.meta
================================================
fileFormatVersion: 2
guid: 569bf8b4580a4bd792f747a7a503034c
timeCreated: 1733918411
================================================
FILE: Editor/Core/JsonUtility.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Buffers;
using System.IO;
using UnityEngine;
namespace Figma.Internals
{
public class JsonUtility
{
class ArrayPool : IArrayPool<char>
{
#region Methods
public char[] Rent(int minimumLength) => ArrayPool<char>.Shared.Rent(minimumLength);
public void Return(char[] array) => ArrayPool<char>.Shared.Return(array);
#endregion
}
#region Properties
static JsonSerializer serializer = new();
static readonly IArrayPool<char> arrayPool = new ArrayPool();
#endregion
#region Constructors
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#endif
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
public static void Initialize()
{
JsonSerializerSettings settings = new()
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Converters =
{
new EffectArrayConverter(),
new PaintArrayConverter(),
new LayoutGridArrayConverter(),
new ExportSettingsArrayConverter(),
new TransitionConverter(),
new BaseNodeArrayConverter(),
new SceneNodeArrayConverter()
}
};
serializer = JsonSerializer.Create(settings);
}
public static string ToJson<T>(T value, bool prettyPrint)
{
using StringWriter stringWriter = new();
using JsonTextWriter jsonTextWriter = new(stringWriter) { Formatting = prettyPrint ? Formatting.Indented : Formatting.None };
serializer.Serialize(jsonTextWriter, value);
return stringWriter.ToString();
}
public static T FromJson<T>(string json, bool useArrayPool = true)
{
using StringReader stringReader = new(json);
using JsonTextReader jsonTextReader = new(stringReader);
if (useArrayPool)
jsonTextReader.ArrayPool = arrayPool;
return serializer.Deserialize<T>(jsonTextReader);
}
#endregion
}
public abstract class ArrayConverter<T, TEnum> : JsonConverter
{
#region Methods
public override bool CanConvert(Type objectType) => objectType == typeof(T[]);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = JArray.Load(reader);
T[] result = new T[array.Count];
for (int i = 0; i < array.Count; ++i)
result[i] = ToObject((JObject)array[i], serializer);
return result;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
T[] array = (T[])value;
writer.WriteStartArray();
foreach (T node in array)
serializer.Serialize(writer, node);
writer.WriteEndArray();
}
protected TEnum GetValue(JObject obj, string name = "type") => (TEnum)Enum.Parse(typeof(TEnum), obj[name].Value<string>());
protected abstract T ToObject(JObject obj, JsonSerializer serializer);
#endregion
}
public class EffectArrayConverter : ArrayConverter<Effect, EffectType>
{
#region Methods
protected override Effect ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj) switch
{
EffectType.INNER_SHADOW => obj.ToObject<ShadowEffect>(serializer),
EffectType.DROP_SHADOW => obj.ToObject<ShadowEffect>(serializer),
EffectType.LAYER_BLUR => obj.ToObject<BlurEffect>(serializer),
EffectType.BACKGROUND_BLUR => obj.ToObject<BlurEffect>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class PaintArrayConverter : ArrayConverter<Paint, PaintType>
{
#region Methods
protected override Paint ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj) switch
{
PaintType.SOLID => obj.ToObject<SolidPaint>(serializer),
PaintType.GRADIENT_LINEAR => obj.ToObject<GradientPaint>(serializer),
PaintType.GRADIENT_RADIAL => obj.ToObject<GradientPaint>(serializer),
PaintType.GRADIENT_ANGULAR => obj.ToObject<GradientPaint>(serializer),
PaintType.GRADIENT_DIAMOND => obj.ToObject<GradientPaint>(serializer),
PaintType.IMAGE => obj.ToObject<ImagePaint>(serializer),
PaintType.EMOJI => obj.ToObject<ImagePaint>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class LayoutGridArrayConverter : ArrayConverter<LayoutGrid, Pattern>
{
#region Methods
protected override LayoutGrid ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj, "pattern") switch
{
Pattern.COLUMNS => obj.ToObject<RowsColsLayoutGrid>(serializer),
Pattern.ROWS => obj.ToObject<RowsColsLayoutGrid>(serializer),
Pattern.GRID => obj.ToObject<GridLayoutGrid>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class ExportSettingsArrayConverter : ArrayConverter<ExportSettings, Format>
{
#region Methods
protected override ExportSettings ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj, "format") switch
{
Format.JPG => obj.ToObject<ExportSettingsImage>(serializer),
Format.PNG => obj.ToObject<ExportSettingsImage>(serializer),
Format.SVG => obj.ToObject<ExportSettingsSVG>(serializer),
Format.PDF => obj.ToObject<ExportSettingsPDF>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class TransitionConverter : JsonConverter
{
#region Methods
public override bool CanConvert(Type objectType) => objectType == typeof(Transition);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);
return (TransitionType)Enum.Parse(typeof(TransitionType), obj["type"]!.Value<string>()) switch
{
TransitionType.DISSOLVE => obj.ToObject<SimpleTransition>(serializer),
TransitionType.SMART_ANIMATE => obj.ToObject<SimpleTransition>(serializer),
TransitionType.MOVE_IN => obj.ToObject<DirectionalTransition>(serializer),
TransitionType.MOVE_OUT => obj.ToObject<DirectionalTransition>(serializer),
TransitionType.PUSH => obj.ToObject<DirectionalTransition>(serializer),
TransitionType.SLIDE_IN => obj.ToObject<DirectionalTransition>(serializer),
TransitionType.SLIDE_OUT => obj.ToObject<DirectionalTransition>(serializer),
_ => throw new NotSupportedException()
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
#endregion
}
public class BaseNodeArrayConverter : ArrayConverter<BaseNode, NodeType>
{
#region Methods
protected override BaseNode ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj) switch
{
NodeType.DOCUMENT => obj.ToObject<DocumentNode>(serializer),
NodeType.CANVAS => obj.ToObject<CanvasNode>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class SceneNodeArrayConverter : ArrayConverter<SceneNode, NodeType>
{
#region Methods
protected override SceneNode ToObject(JObject obj, JsonSerializer serializer) =>
GetValue(obj) switch
{
NodeType.SLICE => obj.ToObject<SliceNode>(serializer),
NodeType.FRAME => obj.ToObject<FrameNode>(serializer),
NodeType.GROUP => obj.ToObject<GroupNode>(serializer),
NodeType.COMPONENT_SET => obj.ToObject<ComponentSetNode>(serializer),
NodeType.COMPONENT => obj.ToObject<ComponentNode>(serializer),
NodeType.INSTANCE => obj.ToObject<InstanceNode>(serializer),
NodeType.BOOLEAN_OPERATION => obj.ToObject<BooleanOperationNode>(serializer),
NodeType.VECTOR => obj.ToObject<VectorNode>(serializer),
NodeType.STAR => obj.ToObject<StarNode>(serializer),
NodeType.LINE => obj.ToObject<LineNode>(serializer),
NodeType.ELLIPSE => obj.ToObject<EllipseNode>(serializer),
NodeType.REGULAR_POLYGON => obj.ToObject<RegularPolygonNode>(serializer),
NodeType.RECTANGLE => obj.ToObject<RectangleNode>(serializer),
NodeType.TEXT => obj.ToObject<TextNode>(serializer),
NodeType.SECTION => obj.ToObject<SectionNode>(serializer),
_ => throw new NotSupportedException()
};
#endregion
}
public class FigmaGeneration { }
}
================================================
FILE: Editor/Core/JsonUtility.cs.meta
================================================
fileFormatVersion: 2
guid: c03fe5a0d0b4de848ae40e0ab3bfaac6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Core/NodeMetadata.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace Figma
{
using Attributes;
using Internals;
using static Internals.PathExtensions;
internal class NodeMetadata
{
#region Consts
static readonly Dictionary<Type, ElementType> typeMap = new()
{
// Base elements
{ typeof(VisualElement), ElementType.VisualElement },
{ typeof(BindableElement), ElementType.BindableElement },
// Utilities
{ typeof(Box), ElementType.Box },
{ typeof(TextElement), ElementType.TextElement },
{ typeof(Label), ElementType.Label },
{ typeof(Image), ElementType.Image },
{ typeof(IMGUIContainer), ElementType.IMGUIContainer },
{ typeof(Foldout), ElementType.Foldout },
// Controls
{ typeof(Button), ElementType.Button },
{ typeof(RepeatButton), ElementType.RepeatButton },
{ typeof(Toggle), ElementType.Toggle },
{ typeof(Scroller), ElementType.Scroller },
{ typeof(Slider), ElementType.Slider },
{ typeof(SliderInt), ElementType.SliderInt },
{ typeof(MinMaxSlider), ElementType.MinMaxSlider },
{ typeof(EnumField), ElementType.EnumField },
{ typeof(MaskField), ElementType.MaskField },
{ typeof(LayerField), ElementType.LayerField },
{ typeof(LayerMaskField), ElementType.LayerMaskField },
{ typeof(TagField), ElementType.TagField },
{ typeof(ProgressBar), ElementType.ProgressBar },
// Text input
{ typeof(TextField), ElementType.TextField },
{ typeof(IntegerField), ElementType.IntegerField },
{ typeof(LongField), ElementType.LongField },
{ typeof(FloatField), ElementType.FloatField },
{ typeof(DoubleField), ElementType.DoubleField },
{ typeof(Vector2Field), ElementType.Vector2Field },
{ typeof(Vector2IntField), ElementType.Vector2IntField },
{ typeof(Vector3Field), ElementType.Vector3Field },
{ typeof(Vector3IntField), ElementType.Vector3IntField },
{ typeof(Vector4Field), ElementType.Vector4Field },
{ typeof(RectField), ElementType.RectField },
{ typeof(RectIntField), ElementType.RectIntField },
{ typeof(BoundsField), ElementType.BoundsField },
{ typeof(BoundsIntField), ElementType.BoundsIntField },
// Complex widgets
{ typeof(PropertyField), ElementType.PropertyField },
{ typeof(ColorField), ElementType.ColorField },
{ typeof(CurveField), ElementType.CurveField },
{ typeof(GradientField), ElementType.GradientField },
{ typeof(ObjectField), ElementType.ObjectField },
// Toolbar
{ typeof(Toolbar), ElementType.Toolbar },
{ typeof(ToolbarButton), ElementType.ToolbarButton },
{ typeof(ToolbarToggle), ElementType.ToolbarToggle },
{ typeof(ToolbarMenu), ElementType.ToolbarMenu },
{ typeof(ToolbarSearchField), ElementType.ToolbarSearchField },
{ typeof(ToolbarPopupSearchField), ElementType.ToolbarPopupSearchField },
{ typeof(ToolbarSpacer), ElementType.ToolbarSpacer },
// Views and windows
{ typeof(ListView), ElementType.ListView },
{ typeof(ScrollView), ElementType.ScrollView },
{ typeof(PopupWindow), ElementType.PopupWindow }
};
#endregion
#region Fields
readonly Dictionary<IBaseNodeMixin, RootMetadata> rootMetadata = new();
readonly Dictionary<IBaseNodeMixin, QueryMetadata> queryMetadata = new();
readonly List<IBaseNodeMixin> search = new(256);
#endregion
#region Properties
static BindingFlags FieldsFlags => BindingFlags.NonPublic | BindingFlags.Instance;
#endregion
#region Constructors
internal NodeMetadata(DocumentNode documentNode, IEnumerable<Type> elements, bool filter, bool throwExceptions = true, bool silent = false)
{
void InitializeRootElement(Type elementType)
{
void InitializeElement(Type type, IBaseNodeMixin rootNode)
{
IBaseNodeMixin FindNodeByQuery(QueryAttribute queryRoot, QueryAttribute query, bool throwException) =>
queryRoot != null && !ReferenceEquals(queryRoot, query) && Find(rootNode, queryRoot.Path, throwException, silent) is { } queryRootNode
? Find(queryRootNode, query.Path, throwException, silent)
: Find(rootNode, query.Path, throwException, silent);
QueryAttribute queryRoot = null;
foreach (FieldInfo field in type.GetFields(FieldsFlags))
{
Type fieldType = field.FieldType;
QueryAttribute query = field.GetCustomAttribute<QueryAttribute>();
if (query is null)
continue;
if (query.StartRoot)
queryRoot = query;
IBaseNodeMixin node = FindNodeByQuery(queryRoot, query, throwExceptions &&
!query.Nullable &&
query.ReplaceElementPath.NullOrEmpty() &&
query.RebuildElementEvent.NullOrEmpty());
if (node != null && !queryMetadata.ContainsKey(node))
queryMetadata.Add(node, new QueryMetadata(fieldType, query));
if (query.EndRoot)
queryRoot = null;
if (node != null && typeof(ISubElement).IsAssignableFrom(fieldType))
InitializeElement(fieldType, node);
}
}
UxmlAttribute uxml = elementType.GetCustomAttribute<UxmlAttribute>();
if (uxml is null)
return;
IBaseNodeMixin elementRoot = Find(documentNode, uxml.Root);
IBaseNodeMixin[] elementPreserve = uxml.Preserve.Select(x => Find(documentNode, x)).ToArray();
rootMetadata.Add(elementRoot, new RootMetadata(filter, uxml, uxml.DownloadImages));
foreach (IBaseNodeMixin value in elementPreserve.Where(x => !rootMetadata.ContainsKey(x)))
rootMetadata.Add(value, new RootMetadata(filter, uxml, UxmlDownloadImages.Everything));
InitializeElement(elementType, elementRoot);
}
elements.ForEach(InitializeRootElement);
}
#endregion
#region Methods
internal bool EnabledInHierarchy(IBaseNodeMixin node) => !rootMetadata.Any(x => x.Value.filter) || GetMetadata(node).root != null;
internal bool ShouldDownload(IBaseNodeMixin node, UxmlDownloadImages flag)
{
BaseNodeMetadata metadata = GetMetadata(node);
if (metadata.root is null || !metadata.root.filter)
return true;
bool shouldDownload = metadata.root.downloadImages == UxmlDownloadImages.Everything || metadata.root.downloadImages.HasFlag(flag);
if (!metadata.root.downloadImages.HasFlag(UxmlDownloadImages.ByElements) || metadata.query is null)
return shouldDownload;
return metadata.query.query.DownloadImage switch
{
ElementDownloadImage.Download => true,
ElementDownloadImage.Ignore => false,
_ => shouldDownload
};
}
internal (bool isHash, string templateName) GetTemplate(IBaseNodeMixin node)
{
string GetFullPath(IBaseNodeMixin x) => x.parent != null ? CombinePath(GetFullPath(x.parent), x.name) : x.name;
BaseNodeMetadata metadata = GetMetadata(node);
if (metadata.root is null || !metadata.root.filter || metadata.query is null)
return (false, null);
return !metadata.query.query.Hash ? (false, metadata.query.query.Template) : (true, $"{metadata.query.fieldType.Name}-{Hash128.Compute(GetFullPath(node))}");
}
internal (ElementType, string) GetElementType(IBaseNodeMixin node)
{
ElementType FieldTypeToElementType(Type type) => typeMap.TryGetValue(type, out ElementType elementType)
? elementType
: typeof(VisualElement).IsAssignableFrom(type)
? ElementType.IElement
: throw new ArgumentOutOfRangeException(type.FullName);
BaseNodeMetadata metadata = GetMetadata(node);
return metadata.root != null && metadata.root.filter && metadata.root.uxml.TypeIdentification == UxmlElementTypeIdentification.ByElementType && metadata.query != null
? (FieldTypeToElementType(metadata.query.fieldType), metadata.query.fieldType!.FullName!.Replace("+", "."))
: (ElementType.None, null);
}
#endregion
#region Support Methods
IBaseNodeMixin Find(IBaseNodeMixin value, string path, bool throwException = true, bool silent = false)
{
IEnumerable<IBaseNodeMixin> Search(IBaseNodeMixin value, string path)
{
bool StartsWith(string path, IBaseNodeMixin value, int startIndex)
{
int endIndex = startIndex + value.name.Length;
return path.BeginsWith(value.name, startIndex) && path.Length >= endIndex && (path.Length == endIndex || path[endIndex].IsSeparator());
}
int LastIndexOf(IBaseNodeMixin root, IBaseNodeMixin leaf, IBaseNodeMixin value, string path, int startIndex = 0)
{
if (value.parent != null && value.parent != root)
startIndex = LastIndexOf(root, leaf, value.parent, path, startIndex);
if (startIndex < 0 || !StartsWith(path, value, startIndex))
return -1;
int endIndex = startIndex + value.name.Length;
if (path.Length > endIndex && path[endIndex].IsSeparator() && value != leaf)
endIndex++;
return endIndex;
}
void SearchIn(IBaseNodeMixin value, string path, int startIndex = 0)
{
static bool IsVisible(IBaseNodeMixin mixin)
{
if (mixin is ISceneNodeMixin { visible: false })
return false;
return mixin.parent is null || IsVisible(mixin.parent);
}
static IReadOnlyCollection<BaseNode> GetChildren(IBaseNodeMixin value)
{
List<BaseNode> children = new();
switch (value)
{
case DocumentNode documentNode:
children.AddRange(documentNode.children);
break;
case IChildrenMixin childrenMixin:
children.AddRange(childrenMixin.children);
break;
}
return children;
}
static bool EqualsTo(IBaseNodeMixin value, string path, int startIndex) => path.EqualsTo(value.name, startIndex);
IReadOnlyCollection<BaseNode> children = GetChildren(value);
search.AddRange(children.Where(child => IsVisible(child) && child.name.NotNullOrEmpty() && EqualsTo(child, path, startIndex)));
children.Where(child => IsVisible(child) && child.name.NotNullOrEmpty() && StartsWith(path, child, startIndex)).ForEach(child => SearchIn(child, path, startIndex + child.name.Length + 1));
}
void SearchByFullPath(IBaseNodeMixin value, string path, int startIndex = 0)
{
static bool IsVisible(IBaseNodeMixin mixin)
{
if (mixin is ISceneNodeMixin { visible: false })
return false;
return mixin.parent is null || IsVisible(mixin.parent);
}
static IReadOnlyCollection<BaseNode> GetChildren(IBaseNodeMixin value)
{
List<BaseNode> children = new();
switch (value)
{
case DocumentNode documentNode:
children.AddRange(documentNode.children);
break;
case IChildrenMixin childrenMixin:
children.AddRange(childrenMixin.children);
break;
}
return children;
}
IReadOnlyCollection<BaseNode> children = GetChildren(value);
bool EqualsToFullPath(IBaseNodeMixin root, IBaseNodeMixin value, string path, int startIndex) => LastIndexOf(root, value, value, path, startIndex) == path.Length;
bool StartsWithFullPath(IBaseNodeMixin root, IBaseNodeMixin value, string path, int startIndex)
{
int endIndex = LastIndexOf(root, value, value, path, startIndex);
return endIndex >= 0 && path.Length > endIndex && path[endIndex].IsSeparator();
}
search.AddRange(children.Where(child => IsVisible(child) && child.name.NotNullOrEmpty() && EqualsToFullPath(value, child, path, startIndex)));
foreach (IBaseNodeMixin child in children.Where(child => IsVisible(child) && child.name.NotNullOrEmpty() && StartsWithFullPath(value, child, path, startIndex)))
SearchByFullPath(child, path, startIndex + child.name.Length + 1);
}
search.Clear();
IBaseNodeMixin root = FindRoot(value);
if (root != null)
{
UxmlAttribute uxml = rootMetadata[root].uxml;
if (path.BeginsWith(uxml.DocumentRoot) || uxml.DocumentPreserve.Any(x => path.BeginsWith(x)))
SearchByFullPath(root.parent.parent, path, UxmlAttribute.prefix.Length + 1);
else
SearchIn(value, path);
}
else
SearchByFullPath(value, path);
return search;
}
IBaseNodeMixin result = Search(value, path).FirstOrDefault();
if (result != null)
return result;
if (throwException)
throw new Exception(Internals.Extensions.BuildTargetMessage("Cannot find node at", CombinePath(value.GetFullPath(), path)));
if (!silent)
Debug.LogWarning(Internals.Extensions.BuildTargetMessage("Cannot find node at", CombinePath(value.GetFullPath(), path)));
return null;
}
IBaseNodeMixin FindRoot(IBaseNodeMixin value)
{
try
{
while (value != null)
{
if (rootMetadata.ContainsKey(value))
return value;
value = value.parent;
}
return null;
}
catch (Exception exception)
{
Debug.LogWarning(exception);
throw;
}
}
BaseNodeMetadata GetMetadata(IBaseNodeMixin value)
{
IBaseNodeMixin FindRootInChildren(IBaseNodeMixin value)
{
if (rootMetadata.ContainsKey(value))
return value;
switch (value)
{
case DocumentNode documentNode:
foreach (CanvasNode child in documentNode.children)
{
IBaseNodeMixin node = FindRootInChildren(child);
if (node != null)
return node;
}
break;
case IChildrenMixin children:
foreach (SceneNode child in children.children)
{
IBaseNodeMixin node = FindRootInChildren(child);
if (node != null)
return node;
}
break;
}
return null;
}
IBaseNodeMixin root = FindRoot(value) ?? FindRootInChildren(value);
return root != null ? new BaseNodeMetadata(rootMetadata[root], queryMetadata.GetValueOrDefault(value)) : new BaseNodeMetadata(null, null);
}
#endregion
}
}
================================================
FILE: Editor/Core/NodeMetadata.cs.meta
================================================
fileFormatVersion: 2
guid: 826eb9624b2845ffafc480902c5ed5d6
timeCreated: 1696228041
================================================
FILE: Editor/Core/NodesRegistry.cs
================================================
using System.Collections.Generic;
using System.Linq;
namespace Figma.Core
{
using Internals;
using Const = Const;
internal sealed class NodesRegistry
{
#region Fields
internal List<string> MissingComponents { get; } = new(Const.initialCollectionCapacity);
internal List<IBaseNodeMixin> ImageFills { get; } = new(Const.initialCollectionCapacity);
internal List<IBaseNodeMixin> Pngs { get; } = new(Const.initialCollectionCapacity);
internal List<IBaseNodeMixin> Svgs { get; } = new(Const.initialCollectionCapacity);
internal Dictionary<string, GradientPaint> Gradients { get; } = new(Const.initialCollectionCapacity);
#endregion
public NodesRegistry(Data data, NodeMetadata nodeMetadata)
{
List<IBaseNodeMixin> nodes = data.document.children.SelectMany(canvas => canvas.Flatten(node => node.IsVisible() &&
nodeMetadata.EnabledInHierarchy(node) &&
node.parent is not BooleanOperationNode)).ToList();
MissingComponents.AddRange(nodes.OfType<InstanceNode>()
.Where(instance => data.document.Flatten().Any(node => node.id == instance.componentId))
.Select(instance => instance.componentId));
Pngs.AddRange(nodes.Where(node => node is not BooleanOperationNode && node.IsSvgNode() && node.HasImage()));
Svgs.AddRange(nodes.Where(node => node.IsSvgNode() && !node.HasImage()));
ImageFills.AddRange(nodes.Where(node => node is not BooleanOperationNode && !node.IsSvgNode() && node.HasImage()));
foreach (GradientPaint gradient in nodes.OfType<IGeometryMixin>()
.Where(x => x is not BooleanOperationNode)
.SelectMany(x => x.fills.OfType<GradientPaint>()))
Gradients.TryAdd(gradient.GetHash(), gradient);
}
}
}
================================================
FILE: Editor/Core/NodesRegistry.cs.meta
================================================
fileFormatVersion: 2
guid: e6f8d15f8d194578ad29c8c0a4a0d2e6
timeCreated: 1734424985
================================================
FILE: Editor/Core/RichText/RichTextBuilder.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Figma.Core.RichText
{
using Internals;
internal sealed class TextBuilder
{
#region Container
enum TagType
{
Bold,
Italic,
Underline,
Strikethrough,
Color,
FontSize,
FontWeight,
Indent,
}
class Tag
{
#region Fields
readonly string tag;
readonly StringBuilder stringBuilder;
string value;
bool active;
#endregion
#region Constructor
public Tag(StringBuilder stringBuilder, string tag)
{
this.tag = tag;
this.stringBuilder = stringBuilder;
}
#endregion
#region Methods
public void Set(bool required)
{
if (!active && required)
Open();
if (active && !required)
Close();
if (!required)
value = null;
}
public void Set(bool required, string value)
{
switch (required)
{
case true when active && this.value != value && this.value != null:
Close();
this.value = value;
Open();
return;
case false when !active:
return;
default:
this.value = value;
Set(required);
break;
}
}
void Open()
{
stringBuilder.Append(string.IsNullOrEmpty(value) ? $"<{tag}>" : $"<{tag}={value}>");
active = true;
}
void Close()
{
stringBuilder.Append($"</{tag}>");
active = false;
}
#endregion
}
#endregion
#region Fields
readonly StringBuilder stringBuilder = new();
readonly Dictionary<TagType, Tag> tags;
readonly TextNode node;
#endregion
#region Constructors
public TextBuilder(TextNode textNode)
{
tags = new Dictionary<TagType, Tag>
{
{ TagType.Bold, new Tag(stringBuilder, "b") },
{ TagType.Italic, new Tag(stringBuilder, "i") },
{ TagType.Underline, new Tag(stringBuilder, "u") },
{ TagType.Strikethrough, new Tag(stringBuilder, "strikethrough") },
{ TagType.Color, new Tag(stringBuilder, "color") },
{ TagType.FontSize, new Tag(stringBuilder, "size") },
{ TagType.FontWeight, new Tag(stringBuilder, "font-weight") },
{ TagType.Indent, new Tag(stringBuilder, "indent") },
};
node = textNode;
}
#endregion
#region Methods
public string Build()
{
string text = node.characters;
TextNode.Style baseStyle = node.style;
int[] charOverrides = node.characterStyleOverrides;
Dictionary<int, TextNode.Style> styleTable = node.styleOverrideTable;
LineType[] lineTypes = node.lineTypes;
int[] lineIndents = node.lineIndentations ?? Array.Empty<int>();
int textLength = text.Length;
if (charOverrides.Length < textLength)
{
Array.Resize(ref charOverrides, textLength);
for (int j = node.characterStyleOverrides.Length; j < textLength; j++)
charOverrides[j] = 0;
}
int listLineIndex = 0;
for (int i = 0, line = 0; i < textLength; i++)
{
char ch = text[i];
if (i == 0 || text[i - 1] == '\n')
{
if (i == 0)
line = 0;
else
line++;
int indentLevel = line < lineIndents.Length ? lineIndents[line] : 0;
LineType lineType = line < lineTypes.Length ? lineTypes[line] : LineType.NONE;
for (int s = 0; s < indentLevel; s++)
tags[TagType.Indent].Set(lineType != LineType.NONE, (10 * indentLevel).ToString());
if (lineType is LineType.UNORDERED or LineType.NONE) listLineIndex = 0;
if (lineType is LineType.ORDERED) stringBuilder.Append($"{++listLineIndex}. ");
else if (lineType is LineType.UNORDERED) stringBuilder.Append("• ");
}
if (ch == '\n')
{
foreach (Tag tag in tags.Values)
tag.Set(false);
stringBuilder.Append('\n');
continue;
}
int styleOverrideId = i < charOverrides.Length ? charOverrides[i] : 0;
TextNode.Style charStyle = styleTable.GetValueOrDefault(styleOverrideId, baseStyle);
if (charStyle != null)
{
tags[TagType.Bold].Set(charStyle.fontWeight >= (int)FontWeight.Bold);
tags[TagType.Italic].Set(charStyle.italic);
tags[TagType.Underline].Set(charStyle.textDecoration is TextDecoration.UNDERLINE);
tags[TagType.Strikethrough].Set(charStyle.textDecoration is TextDecoration.STRIKETHROUGH);
SolidPaint paint = charStyle.fills?.OfType<SolidPaint>().FirstOrDefault();
tags[TagType.Color].Set(paint != null, paint == null ? null : "#" + ColorUtility.ToHtmlStringRGBA((Color)paint.color));
tags[TagType.FontWeight].Set(charStyle.fontWeight != (double)FontWeight.Regular, charStyle.fontWeight.ToString());
tags[TagType.FontSize].Set(true, charStyle.fontSize.ToString());
}
stringBuilder.Append(ch);
}
foreach (Tag tag in tags.Values)
tag.Set(false);
return stringBuilder.ToString();
}
#endregion
}
}
================================================
FILE: Editor/Core/RichText/RichTextBuilder.cs.meta
================================================
fileFormatVersion: 2
guid: 63d2b4dce6024b989f78957756f9f22f
timeCreated: 1743683644
================================================
FILE: Editor/Core/RichText.meta
================================================
fileFormatVersion: 2
guid: b4773ce3ee3d4f9f817a7dca740b3afc
timeCreated: 1743683652
================================================
FILE: Editor/Core/RootNodes.cs
================================================
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Figma.Core
{
using Internals;
using Attributes;
internal class RootNodes
{
const int initialCollectionCapacity = 32;
#region Fields
readonly List<CanvasNode> canvases = new(initialCollectionCapacity);
readonly List<ComponentSetNode> componentSets = new(initialCollectionCapacity);
readonly List<FrameNode> frames = new(initialCollectionCapacity);
readonly List<(DefaultShapeNode, string hash)> elements = new(initialCollectionCapacity);
#endregion
#region Properties
public IReadOnlyList<CanvasNode> Canvases => canvases;
public IReadOnlyList<ComponentSetNode> ComponentSets => componentSets;
public IReadOnlyList<FrameNode> Frames => frames;
public IReadOnlyList<(DefaultShapeNode node, string hash)> Elements => elements;
#endregion
#region Constructors
public RootNodes(Data data, NodeMetadata nodeMetadata)
{
foreach (IBaseNodeMixin node in data.document.Flatten())
{
switch (node)
{
case CanvasNode canvasNode:
canvases.Add(canvasNode);
break;
case ComponentSetNode componentSetNode:
componentSets.Add(componentSetNode);
break;
case FrameNode frameNode when node.parent is CanvasNode:
frames.Add(frameNode);
break;
case DefaultShapeNode defaultShapeNode when nodeMetadata.GetTemplate(defaultShapeNode) is (var isHash, { } template) && template.NotNullOrEmpty():
if (!isHash && elements.Any(x => x.hash == template))
{
Debug.LogWarning($"Duplicate hash was found: {template}. This might happen when [{nameof(QueryAttribute)}] is inherited in multiple classes. " +
"This could also happen when you have a template with the same name. In order to fix that in that case, please use \"Hash = true\" parameter.");
break;
}
elements.Add((defaultShapeNode, template));
break;
}
}
}
#endregion
}
}
================================================
FILE: Editor/Core/RootNodes.cs.meta
================================================
fileFormatVersion: 2
guid: 54369dcc94564417aee21cea7980006a
timeCreated: 1733321003
================================================
FILE: Editor/Core/StylesPreprocessor.cs
================================================
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Figma.Core
{
using Assets;
using Uss;
using Internals;
using static Const;
internal class StylesPreprocessor
{
static readonly Regex multipleDashesRegex = new("-{2,}", RegexOptions.Compiled);
static readonly Regex invalidCharsRegex = new("[^a-zA-Z0-9]", RegexOptions.Compiled);
#region Fields
readonly List<(StyleSlot slot, UssStyle style)> styles = new(initialCollectionCapacity);
readonly List<ComponentNode> components = new(initialCollectionCapacity);
readonly List<Dictionary<string, Style>> componentsStyles = new(initialCollectionCapacity);
readonly Dictionary<IBaseNodeMixin, UssStyle> componentStyleMap = new(initialCollectionCapacity);
readonly Dictionary<IBaseNodeMixin, UssStyle> nodeStyleMap = new(initialCollectionCapacity);
readonly AssetsInfo assetsInfo;
readonly Data data;
#endregion
#region Properties
internal IReadOnlyList<(StyleSlot slot, UssStyle style)> Styles => styles;
internal IReadOnlyDictionary<IBaseNodeMixin, UssStyle> NodeStyleMap => nodeStyleMap;
#endregion
internal StylesPreprocessor(Data data, AssetsInfo assetsInfo)
{
this.data = data;
this.assetsInfo = assetsInfo;
AddStyles(data.document, data.styles);
AddRichText(data.document);
for (int i = 0; i < components.Count; i++)
{
AddStyles(components[i], componentsStyles[i]);
AddRichText(components[i]);
}
InheritStyles(data.document);
AddTransitionStyles();
}
#region Methods
void AddStyles(IBaseNodeMixin root, Dictionary<string, Style> styles)
{
string GetClassName(string name, string prefix = "n")
{
const char separator = '-';
if (name.Length > 64)
name = name[..64];
name = invalidCharsRegex.Replace(name, separator.ToString());
name = multipleDashesRegex.Replace(name, separator.ToString());
name = name.Trim(separator);
if (string.IsNullOrEmpty(name) || name.All(c => c == separator))
name = prefix;
if (char.IsDigit(name[0]))
name = $"{prefix}-{name}";
return name;
}
HashSet<IBaseNodeMixin> insideComponents = new();
foreach (IBaseNodeMixin node in root.Flatten())
{
bool insideComponent = node is ComponentNode || insideComponents.Contains(node.parent);
if (!insideComponent)
{
UssStyle style = new(GetClassName(node.name), assetsInfo, (BaseNode)node);
if (node is ComponentSetNode)
{
// Removing annoying borders for ComponentSetNode
style.Attributes.Clear();
style.Attributes.Add("overflow", "hidden");
}
nodeStyleMap[node] = style;
}
else
{
insideComponents.Add(node);
componentStyleMap[node] = new UssStyle(GetClassName(node.name), assetsInfo, (BaseNode)node);
}
if (node is not IBlendMixin { styles: not null } blend)
continue;
foreach ((string styleType, string styleId) in blend.styles)
{
bool text = node.type == NodeType.TEXT;
string slot = styleType;
if (slot[^1] == 's') // Sometimes named 'fill' and sometimes 'fills'. We treat them equally.
slot = slot[..^1];
if (!this.styles.Any(x => x.slot.Text == text && x.slot.Slot == slot && x.slot.key == styles[styleId].key))
{
StyleSlot styleDescriptor = new StyleSlot(text, slot, styles[styleId]);
string className = GetClassName(styleDescriptor.name, "s");
UssStyle ussStyle = new UssStyle(className, assetsInfo, (BaseNode)node, styleDescriptor);
this.styles.Add((styleDescriptor, ussStyle));
}
}
}
}
void AddRichText(IBaseNodeMixin node)
{
foreach (TextNode textNode in node.Flatten().OfType<TextNode>().Where(x => x.lineTypes is { Length: > 1 } && x.lineTypes.Any(lineType => lineType is LineType.ORDERED or LineType.UNORDERED) ||
(x.styleOverrideTable != null && x.styleOverrideTable.Any())))
textNode.characters = new RichText.TextBuilder(textNode).Build();
}
void AddTransitionStyles()
{
ComponentNode GetTransitionNode(ComponentSetNode componentSet, ComponentNode defaultComponent, TriggerType triggerType)
{
Action action = defaultComponent.interactions
.Where(interaction => interaction.trigger.type == triggerType)
.Select(interaction => interaction.actions.FirstOrDefault())
.FirstOrDefault(action => action?.destinationId != null);
string destinationId = action?.destinationId;
ComponentNode node = (ComponentNode)componentSet.children.FirstOrDefault(component => component is ComponentNode && component.id == destinationId);
return node;
}
UssStyle GetStyle(Dictionary<IBaseNodeMixin, UssStyle> componentStyleMap, ComponentSetNode componentSet, ComponentNode defaultComponent, TriggerType triggerType)
{
UssStyle style = null;
ComponentNode node = GetTransitionNode(componentSet, defaultComponent, triggerType);
if (node != null)
componentStyleMap.TryGetValue(node, out style);
return style;
}
UssStyle visualElement = new(nameof(UnityEngine.UIElements.VisualElement));
foreach ((IBaseNodeMixin key, UssStyle componentSetStyle) in nodeStyleMap)
{
if (key is not ComponentSetNode componentSet)
continue;
ComponentNode defaultComponent = null;
Action action = null;
foreach (SceneNode sceneNode in componentSet.children)
{
if (sceneNode is not ComponentNode componentNode)
continue;
Interactions activeInteraction = componentNode.interactions.FirstOrDefault(interaction => interaction.trigger.type == TriggerType.ON_HOVER ||
interaction.trigger.type == TriggerType.ON_CLICK);
if (activeInteraction == null)
continue;
action = activeInteraction.actions.FirstOrDefault(x => x.destinationId != null);
if (action == null)
continue;
defaultComponent = componentNode;
UssStyle subStyle = new(componentSetStyle.Name) { Target = visualElement };
if (action.transition != null)
{
subStyle.transitionDuration = action.transition.duration * 1000;
subStyle.transitionEasing = (EasingFunction)action.transition.easing.type;
}
componentSetStyle.SubStyles.Add(subStyle);
break;
}
if (defaultComponent == null)
continue;
componentStyleMap.TryGetValue(defaultComponent, out UssStyle idleStyle);
UssStyle hoverStyle = GetStyle(componentStyleMap, componentSet, defaultComponent, TriggerType.ON_HOVER);
UssStyle clickStyle = GetStyle(componentStyleMap, componentSet, defaultComponent, TriggerType.ON_CLICK);
if (idleStyle == null)
continue;
void InjectSubStyles(ComponentNode node, IReadOnlyList<UssStyle> defaultStyles, PseudoClass pseudoClass)
{
IReadOnlyList<UssStyle> styles = GetStyles(node);
for (int i = 0; i < styles.Count; i++)
{
UssStyle style = styles[i];
UssStyle defaultStyle = defaultStyles[i];
componentSetStyle.SubStyles.Add(new UssStyle(componentSetStyle.Name) { PseudoClass = pseudoClass, Target = defaultStyle }.CopyFrom(style));
}
}
if (action.transition is { type: TransitionType.SMART_ANIMATE })
{
ComponentNode hoverNode = GetTransitionNode(componentSet, defaultComponent, TriggerType.ON_HOVER);
ComponentNode clickNode = GetTransitionNode(componentSet, defaultComponent, TriggerType.ON_CLICK);
IReadOnlyList<UssStyle> defaultStyles = GetStyles(defaultComponent);
if (hoverNode != null) InjectSubStyles(hoverNode, defaultStyles, PseudoClass.Hover);
if (clickNode != null) InjectSubStyles(clickNode, defaultStyles, PseudoClass.Active);
}
if (action.transition is { type: TransitionType.DISSOLVE })
componentSetStyle.SubStyles.AddRange(UssStyle.MakeTransitionStyles(componentSetStyle, idleStyle, hoverStyle, clickStyle));
}
}
internal void AddMissingComponent(ComponentNode component, Dictionary<string, Style> componentStyles)
{
components.Add(component);
componentsStyles.Add(componentStyles);
}
#endregion
#region Support Methods
internal IReadOnlyList<UssStyle> GetStyles(IBaseNodeMixin root) =>
root.Flatten(node => node.IsVisible() && node is not ComponentSetNode)
.Select(node => componentStyleMap.TryGetValue(node, out UssStyle style) || nodeStyleMap.TryGetValue(node, out style) ? style : null)
.Where(style => style is not null)
.ToList();
void InheritStyles(IBaseNodeMixin root)
{
List<UssStyle> styles = new();
foreach (IBaseNodeMixin node in root.Flatten(x => x.parent is not BooleanOperationNode))
{
UssStyle style = GetStyle(node);
if (node is IBlendMixin { styles: not null } blend)
{
foreach (KeyValuePair<string, string> keyValue in blend.styles)
{
bool text = node.type == NodeType.TEXT;
string styleType = keyValue.Key;
if (styleType[^1] == 's')
styleType = styleType[..^1];
string styleId = keyValue.Value;
string key = null;
if (data.styles.TryGetValue(styleId, out Style documentStyle))
key = documentStyle.key;
foreach (Dictionary<string, Style> componentStyle in componentsStyles)
if (componentStyle.TryGetValue(styleId, out Style value))
key = value.key;
int index;
if (key.NotNullOrEmpty() && (index = this.styles.FindIndex(x => x.slot.Text == text && x.slot.Slot == styleType && x.slot.key == key)) >= 0)
styles.Add(this.styles[index].style);
}
}
if (styles.Count > 0) style.Inherit(styles);
styles.Clear();
}
}
internal string GetClassList(IBaseNodeMixin node)
{
UssStyle style = GetStyle(node);
if (style == null)
return string.Empty;
List<string> styles = new List<string>();
if (node is IBlendMixin { styles: not null } blend)
{
foreach (KeyValuePair<string, string> keyValue in blend.styles)
{
bool text = node.type == NodeType.TEXT;
string styleType = keyValue.Key;
if (styleType[^1] == 's')
styleType = styleType[..^1];
string styleId = keyValue.Value;
string key = null;
if (data.styles.TryGetValue(styleId, out Style documentStyle))
key = documentStyle.key;
foreach (Dictionary<string, Style> componentStyle in componentsStyles)
if (componentStyle.TryGetValue(styleId, out Style value))
key = value.key;
int index;
if (key.NotNullOrEmpty() && (index = this.styles.FindIndex(x => x.slot.Text == text && x.slot.Slot == styleType && x.slot.key == key)) >= 0)
styles.Add(this.styles[index].style.Name);
}
}
if (node.IsSvgNode())
styles.Clear();
List<string> classes = new List<string>();
classes.Add(UssStyle.overrideClass.Name);
if (style.Attributes.Count > 0)
classes.Add(style.Name);
classes.AddRange(styles);
if (node.IsRootNode())
classes.Add(UssStyle.viewportClass.Name);
return string.Join(" ", classes);
}
UssStyle GetStyle(IBaseNodeMixin node) => componentStyleMap.TryGetValue(node, out UssStyle style) || nodeStyleMap.TryGetValue(node, out style) ? style : null;
#endregion
}
}
================================================
FILE: Editor/Core/StylesPreprocessor.cs.meta
================================================
fileFormatVersion: 2
guid: 756f15f2e8e54ce6b41e0fdaa5aa7fe8
timeCreated: 1742559104
================================================
FILE: Editor/Core/Uss/BaseUssStyle.cs
================================================
using Figma.Internals;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Figma.Core.Uss
{
internal abstract class BaseUssStyle
{
#region Fields
readonly List<BaseUssStyle> inherited = new();
#endregion
#region Properties
public string Name { get; set; }
public PseudoClass PseudoClass { get; set; }
public BaseUssStyle Target { get; set; }
public List<BaseUssStyle> SubStyles { get; } = new();
public Dictionary<string, string> Attributes { get; } = new();
public bool HasAttributes => Attributes.Count > 0;
#endregion
#region Constructors
protected BaseUssStyle(string name) => Name = name;
#endregion
#region Methods
public string BuildName()
{
string result = $".{Name}";
if (PseudoClass is not PseudoClass.None)
result += $":{PseudoClass.ToString().ToLower()}";
if (Target == null)
return result;
result += " > ";
if (Target.Name is not (nameof(UnityEngine.UIElements.VisualElement) or
nameof(UnityEngine.UIElements.Button)))
result += ".";
result += Target.Name;
return result;
}
public bool DoesInherit(BaseUssStyle style) => inherited.Contains(style);
public void Inherit(IReadOnlyCollection<BaseUssStyle> styles)
{
inherited.AddRange(styles);
styles.SelectMany(style => style.Attributes.Where(keyValue => Attributes.TryGetValue(keyValue.Key, out string value) && value == keyValue.Value))
.Select(x => x.Key)
.ForEach(key => Attributes.Remove(key));
}
#endregion
#region Support Methods
protected string Get(string name) => Attributes[name];
protected string GetDefault(string name, string defaultValue) => Attributes.ContainsKey(name) ? Attributes[name] : defaultValue;
protected string Get1(string name, string group, int index)
{
if (Attributes.TryGetValue(group, out string groupValue))
{
Length4Property length4 = groupValue;
return length4[index];
}
if (Attributes.TryGetValue(name, out string nameValue))
return nameValue;
throw new NotSupportedException();
}
protected string Get4(string name, params string[] names)
{
if (Attributes.TryGetValue(name, out string value))
return value;
LengthProperty[] properties = new LengthProperty[4];
for (int i = 0; i < 4; ++i)
properties[i] = Attributes.TryGetValue(names[i], out string indexedValue) ? indexedValue : new LengthProperty(Unit.Pixel);
return new Length4Property(properties);
}
protected void Set(string name, string value) => Attributes[name] = value;
protected void Set1(string name, string value, params string[] names)
{
Attributes[name] = value;
for (int i = 0; i < 4; ++i)
Attributes.Remove(names[i]);
}
protected void Set4(string name, string value, string group, int index)
{
if (Attributes.TryGetValue(group, out string item))
{
Length4Property length4 = item;
length4[index] = value;
Set(group, length4);
}
else
Set(name, value);
}
protected static string Url(string url) => $"url('{url}')";
protected static string Resource(string resource) => $"resource('{resource}')";
#endregion
}
}
================================================
FILE: Editor/Core/Uss/BaseUssStyle.cs.meta
================================================
fileFormatVersion: 2
guid: 6a8ef63978cd415290c6cbe844cd7f9b
timeCreated: 1732193154
================================================
FILE: Editor/Core/Uss/Properties/AssetProperty.cs
================================================
using System;
namespace Figma.Core.Uss
{
using Internals;
/// <summary>
/// Represents an asset in a Resources folder or represents an asset specified by a path, it can be expressed as either a relative path or an absolute path.
/// </summary>
internal struct AssetProperty
{
#region Fields
readonly string url;
readonly string resource;
readonly Unit unit;
#endregion
#region Constructors
AssetProperty(Unit unit)
{
url = null;
resource = null;
this.unit = unit;
}
AssetProperty(string value)
{
url = null;
resource = null;
unit = default;
if (value.StartsWith(nameof(url))) url = value;
else if (value.StartsWith(nameof(resource))) resource = value;
else throw new NotSupportedException();
}
#endregion
#region Operators
public static implicit operator AssetProperty(Unit value) => new(value);
public static implicit operator AssetProperty(string value) => Enum.TryParse(value, true, out Unit unit) ? new AssetProperty(unit) : new AssetProperty(value);
public static implicit operator string(AssetProperty value)
{
if (value.url.NotNullOrEmpty()) return value.url;
if (value.resource.NotNullOrEmpty()) return value.resource;
return value.unit switch
{
Unit.None => "none",
Unit.Initial => "initial",
_ => throw new ArgumentException(nameof(value))
};
}
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/AssetProperty.cs.meta
================================================
fileFormatVersion: 2
guid: b1d01eee68b444c88e74da4382b53373
timeCreated: 1727946243
================================================
FILE: Editor/Core/Uss/Properties/ColorProperty.cs
================================================
using System;
namespace Figma.Core.Uss
{
using Internals;
using Const = Const;
/// <summary>
/// Represents a color. You can define a color with a #hexadecimal code, the rgb() or rgba() function, or a color keyword (for example, blue or transparent).
/// </summary>
internal readonly struct ColorProperty
{
#region Fields
readonly string rgba;
readonly string rgb;
readonly string hex;
readonly string name;
#endregion
#region Constructors
internal ColorProperty(RGBA color, Double? opacity = 1, float alphaMult = 1)
{
rgba = $"rgba({(byte)(color.r * 255.0f)},{(byte)(color.g * 255.0f)},{(byte)(color.b * 255.0f)},{(color.a * (opacity ?? alphaMult)).ToString("F2", Const.Culture).Replace(".00", string.Empty)})";
rgb = null;
hex = null;
name = null;
}
ColorProperty(string value)
{
rgba = null;
rgb = null;
hex = null;
name = null;
if (value.StartsWith(nameof(rgba))) rgba = value;
else if (value.StartsWith(nameof(rgb))) rgb = value;
else if (value.StartsWith('#')) hex = value;
else name = value;
}
#endregion
#region Operators
public static implicit operator ColorProperty(Unit _) => new();
public static implicit operator ColorProperty(RGBA value) => new(value);
public static implicit operator ColorProperty(string value) => new(value);
public static implicit operator string(ColorProperty value)
{
if (value.rgba.NotNullOrEmpty()) return value.rgba;
if (value.rgb.NotNullOrEmpty()) return value.rgb;
if (value.hex.NotNullOrEmpty()) return value.hex;
if (value.name.NotNullOrEmpty()) return value.name;
return "initial";
}
public override string ToString() => this;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/ColorProperty.cs.meta
================================================
fileFormatVersion: 2
guid: 11225bd9ebe040f49fab329a81bc3f88
timeCreated: 1727946232
================================================
FILE: Editor/Core/Uss/Properties/CursorProperty.cs
================================================
namespace Figma.Core.Uss
{
internal struct CursorProperty
{
#region Operators
public static implicit operator CursorProperty(string _) => new();
public static implicit operator string(CursorProperty _) => null;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/CursorProperty.cs.meta
================================================
fileFormatVersion: 2
guid: 688b2f12fd56420486ab60eaa3f520c7
timeCreated: 1727946311
================================================
FILE: Editor/Core/Uss/Properties/DurationProperty.cs
================================================
using System;
namespace Figma.Core.Uss
{
/// <summary>
/// Represents a duration value from Figma API.
/// </summary>
internal readonly struct DurationProperty
{
#region Fields
readonly double value;
readonly TimeUnit unit;
#endregion
#region Constructors
internal DurationProperty(TimeUnit unit)
{
value = 0;
this.unit = unit;
}
internal DurationProperty(double value, TimeUnit unit)
{
this.value = value;
this.unit = unit;
}
#endregion
#region Operators
public static implicit operator DurationProperty(TimeUnit value) => new(0, value);
public static implicit operator DurationProperty(double? value) => new(value!.Value, TimeUnit.Millisecond);
public static implicit operator DurationProperty(double value) => new(value, TimeUnit.Millisecond);
public static implicit operator DurationProperty(string value)
{
if (Enum.TryParse(value, true, out TimeUnit unit)) return new DurationProperty(unit);
if (value.ToLower(Const.Culture).Contains("ms")) return new DurationProperty(double.Parse(value.ToLower(Const.Culture).Replace("ms", string.Empty), Const.Culture), TimeUnit.Millisecond);
if (value.ToLower(Const.Culture).Contains("s")) return new DurationProperty(double.Parse(value.ToLower(Const.Culture).Replace("s", string.Empty), Const.Culture), TimeUnit.Second);
return default;
}
public static implicit operator string(DurationProperty value)
{
return value.unit switch
{
TimeUnit.Default => $"0ms",
TimeUnit.Millisecond => $"{value.value.ToString("F2", Const.Culture).Replace(".00", string.Empty)}ms",
TimeUnit.Second => $"{value.value.ToString("F2", Const.Culture).Replace(".00", string.Empty)}s",
_ => throw new ArgumentException(nameof(value))
};
}
public static DurationProperty operator +(DurationProperty a) => a;
public static DurationProperty operator -(DurationProperty a) => new(-a.value, a.unit);
public static DurationProperty operator +(DurationProperty a, double b) => new(a.value + b, a.unit);
public static DurationProperty operator -(DurationProperty a, double b) => new(a.value - b, a.unit);
public static bool operator ==(DurationProperty a, TimeUnit b) => a.unit == b;
public static bool operator !=(DurationProperty a, TimeUnit b) => a.unit != b;
public override bool Equals(object obj) => obj is DurationProperty property && value == property.value && unit == property.unit;
public override int GetHashCode() => HashCode.Combine(value, unit);
public override string ToString() => this;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/DurationProperty.cs.meta
================================================
fileFormatVersion: 2
guid: f01b58e2e2c44e75b07f54061e244f90
timeCreated: 1732271697
================================================
FILE: Editor/Core/Uss/Properties/EnumProperty.cs
================================================
using System;
using System.Text.RegularExpressions;
namespace Figma.Core.Uss
{
#pragma warning disable CS0660, CS0661
internal struct EnumProperty<T> where T : struct, Enum
#pragma warning restore CS0660, CS0661
{
// ReSharper disable StaticMemberInGenericType
static readonly Regex enumParserRegexString = new("(?<name>([a-z]+\\-?))", RegexOptions.Compiled);
static readonly Regex enumParserRegexValue = new("(?<name>([A-Z][a-z]+)?)", RegexOptions.Compiled);
// ReSharper restore StaticMemberInGenericType
#region Fields
T value;
readonly Unit unit;
#endregion
#region Constructors
EnumProperty(T value)
{
this.value = value;
unit = Unit.None;
}
EnumProperty(Unit unit)
{
value = default;
this.unit = unit;
}
#endregion
#region Operators
public static implicit operator EnumProperty<T>(Unit unit) => new(unit);
public static implicit operator EnumProperty<T>(T value) => new(value);
public static implicit operator EnumProperty<T>(string value) => Enum.TryParse(enumParserRegexString.Replace(value, "${name}").Replace("-", string.Empty), true, out T result) ? new EnumProperty<T>(result) : default;
public static implicit operator string(EnumProperty<T> value) => value.unit == Unit.None ? enumParserRegexValue.Replace(value.value.ToString(), "${name}-").ToLower().TrimEnd('-') : "initial";
public static bool operator ==(EnumProperty<T> a, T b) => a.value.Equals(b);
public static bool operator !=(EnumProperty<T> a, T b) => !a.value.Equals(b);
public override string ToString() => this;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/EnumProperty.cs.meta
================================================
fileFormatVersion: 2
guid: 911a38bb38a64ff98a53324b53da101b
timeCreated: 1727946257
================================================
FILE: Editor/Core/Uss/Properties/FlexProperty.cs
================================================
namespace Figma.Core.Uss
{
internal struct FlexProperty
{
#region Operators
public static implicit operator FlexProperty(string _) => new();
public static implicit operator string(FlexProperty _) => null;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/FlexProperty.cs.meta
================================================
fileFormatVersion: 2
guid: c6e36b8acd8548b0add9ddf1a37509b0
timeCreated: 1727946301
================================================
FILE: Editor/Core/Uss/Properties/IntegerProperty.cs
================================================
namespace Figma.Core.Uss
{
/// <summary>
/// Represents a whole number.
/// </summary>
internal struct IntegerProperty
{
#region Fields
readonly int value;
#endregion
#region Constructors
IntegerProperty(int value) => this.value = value;
#endregion
#region Operators
public static implicit operator IntegerProperty(int? value) => new(value!.Value);
public static implicit operator IntegerProperty(int value) => new(value);
public static implicit operator IntegerProperty(string value) => new(int.Parse(value));
public static implicit operator string(IntegerProperty value) => value.value.ToString(Const.Culture);
public static IntegerProperty operator +(IntegerProperty a) => a;
public static IntegerProperty operator -(IntegerProperty a) => new(-a.value);
public static IntegerProperty operator +(IntegerProperty a, int b) => new(a.value + b);
public static IntegerProperty operator -(IntegerProperty a, int b) => new(a.value - b);
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/IntegerProperty.cs.meta
================================================
fileFormatVersion: 2
guid: a466380f063f4ec98d082d2ec7cd1f20
timeCreated: 1727946212
================================================
FILE: Editor/Core/Uss/Properties/LayoutDouble4.cs
================================================
using System;
namespace Figma.Core.Uss
{
struct LayoutDouble4
{
#region Fields
public double top;
public double right;
public double bottom;
public double left;
#endregion
#region Methods
public LayoutDouble4(double top, double right, double bottom, double left)
{
this.top = top;
this.right = right;
this.bottom = bottom;
this.left = left;
}
public LayoutDouble4(double value)
{
top = value;
right = value;
bottom = value;
left = value;
}
public LayoutDouble4 OnlyPositiveValues() => new(top > UssStyle.tolerance ? top : 0.0, right > UssStyle.tolerance ? right : 0.0, bottom > UssStyle.tolerance ? bottom : 0.0, left > UssStyle.tolerance ? left : 0.0);
public LayoutDouble4 OnlyNegativeValues() => new(top < UssStyle.tolerance ? top : 0.0, right < UssStyle.tolerance ? right : 0.0, bottom < UssStyle.tolerance ? bottom : 0.0, left < UssStyle.tolerance ? left : 0.0);
public Length4Property ToLength4Property() => new[] { top, right, bottom, left };
public bool Any() => Math.Abs(top) > UssStyle.tolerance || Math.Abs(right) > UssStyle.tolerance || Math.Abs(bottom) > UssStyle.tolerance || Math.Abs(left) > UssStyle.tolerance;
public static LayoutDouble4 operator +(LayoutDouble4 a, LayoutDouble4 b) => new(a.top + b.top, a.right + b.right, a.bottom + b.bottom, a.left + b.left);
public static LayoutDouble4 operator -(LayoutDouble4 a, LayoutDouble4 b) => new(a.top - b.top, a.right - b.right, a.bottom - b.bottom, a.left - b.left);
public static LayoutDouble4 operator -(LayoutDouble4 a) => new(-a.top, -a.right, -a.bottom, -a.left);
public static LayoutDouble4 operator *(LayoutDouble4 a, double k) => new(a.top * k, a.right * k, a.bottom * k, a.left * k);
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/LayoutDouble4.cs.meta
================================================
fileFormatVersion: 2
guid: 3c58a19efd2f4860a12c1aca6d120164
timeCreated: 1743523469
================================================
FILE: Editor/Core/Uss/Properties/Length2Property.cs
================================================
using System;
using System.Linq;
namespace Figma.Core.Uss
{
internal readonly struct Length2Property
{
#region Fields
readonly Unit unit;
readonly LengthProperty[] properties;
#endregion
#region Properties
internal LengthProperty this[int index] { get => properties[index]; set => properties[index] = value; }
#endregion
#region Constructors
internal Length2Property(Unit unit)
{
this.unit = unit;
properties = new LengthProperty[] { new(unit), new(unit) };
}
internal Length2Property(LengthProperty[] properties)
{
unit = Unit.None;
this.properties = properties;
}
#endregion
#region Operators
public static implicit operator Length2Property(Unit unit) => new(unit);
public static implicit operator Length2Property(Double? value) => new(new LengthProperty[] { value!.Value });
public static implicit operator Length2Property(Double value) => new(new LengthProperty[] { value });
public static implicit operator Length2Property(Double[] values)
{
LengthProperty[] properties = new LengthProperty[values.Length];
for (int i = 0; i < values.Length; i++) properties[i] = values[i];
return new Length2Property(properties);
}
public static implicit operator Length2Property(string value)
{
string[] values = value.Split(" ", StringSplitOptions.RemoveEmptyEntries);
LengthProperty[] properties = new LengthProperty[values.Length];
for (int i = 0; i < values.Length; i++) properties[i] = values[i];
return new Length2Property(properties);
}
public static implicit operator string(Length2Property value)
{
if (value is { unit: Unit.None, properties: not null })
{
string[] values = new string[value.properties.Length];
for (int i = 0; i < values.Length; i++) values[i] = value.properties[i];
return string.Join(" ", values);
}
return new LengthProperty(value.unit);
}
public static Length2Property operator +(Length2Property a) => a;
public static Length2Property operator -(Length2Property a) => new(a.properties.Select(x => -x).ToArray());
public static Length2Property operator +(Length2Property a, Double b) => new(a.properties.Select(x => x + b).ToArray());
public static Length2Property operator -(Length2Property a, Double b) => new(a.properties.Select(x => x - b).ToArray());
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/Length2Property.cs.meta
================================================
fileFormatVersion: 2
guid: ac3787c7e7634fc9983559df65387add
timeCreated: 1738319788
================================================
FILE: Editor/Core/Uss/Properties/Length4Property.cs
================================================
using System;
using System.Linq;
namespace Figma.Core.Uss
{
internal readonly struct Length4Property
{
#region Fields
readonly Unit unit;
readonly LengthProperty[] properties;
#endregion
#region Properties
internal LengthProperty this[int index] { get => properties[index]; set => properties[index] = value; }
#endregion
#region Constructors
internal Length4Property(Unit unit)
{
this.unit = unit;
properties = new LengthProperty[] { new(unit), new(unit), new(unit), new(unit) };
}
internal Length4Property(LengthProperty[] properties)
{
unit = Unit.None;
this.properties = properties;
}
#endregion
#region Operators
public static implicit operator Length4Property(Unit unit) => new(unit);
public static implicit operator Length4Property(double? value) => new(new LengthProperty[] { value!.Value });
public static implicit operator Length4Property(double value) => new(new LengthProperty[] { value });
public static implicit operator Length4Property(double[] values) => new(values.Select(x => (LengthProperty)x).ToArray());
public static implicit operator Length4Property(string value) => new(value.Split(" ", StringSplitOptions.RemoveEmptyEntries).Select(x => (LengthProperty)x).ToArray());
public static implicit operator string(Length4Property value) => value is { unit: Unit.None, properties: not null } ? string.Join(" ", value.properties.Select(p => (string)p)) : new LengthProperty(value.unit);
public static Length4Property operator +(Length4Property a) => a;
public static Length4Property operator -(Length4Property a) => new(a.properties.Select(x => -x).ToArray());
public static Length4Property operator +(Length4Property a, double b) => new(a.properties.Select(x => x + b).ToArray());
public static Length4Property operator -(Length4Property a, double b) => new(a.properties.Select(x => x - b).ToArray());
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/Length4Property.cs.meta
================================================
fileFormatVersion: 2
guid: 22ebc27065094f06894a5301834db528
timeCreated: 1727946288
================================================
FILE: Editor/Core/Uss/Properties/LengthProperty.cs
================================================
using System;
namespace Figma.Core.Uss
{
/// <summary>
/// Represents a distance value.
/// </summary>
internal readonly struct LengthProperty
{
#region Fields
readonly double value;
readonly Unit unit;
#endregion
#region Constructors
internal LengthProperty(Unit unit)
{
value = 0;
this.unit = unit;
}
internal LengthProperty(double value, Unit unit)
{
this.value = value;
this.unit = unit;
}
#endregion
#region Operators
public static implicit operator LengthProperty(Unit value) => new(0, value);
public static implicit operator LengthProperty(double? value) => new(value!.Value, Unit.Pixel);
public static implicit operator LengthProperty(double value) => new(value, Unit.Pixel);
public static implicit operator LengthProperty(string value)
{
if (Enum.TryParse(value, true, out Unit unit)) return new LengthProperty(unit);
if (value.Contains("px")) return new LengthProperty(double.Parse(value.ToLower().Replace("px", string.Empty), Const.Culture), Unit.Pixel);
if (value.Contains("deg")) return new LengthProperty(double.Parse(value.ToLower().Replace("deg", string.Empty), Const.Culture), Unit.Degrees);
if (value.Contains('%')) return new LengthProperty(double.Parse(value.Replace("%", string.Empty), Const.Culture), Unit.Percent);
return default;
}
public static implicit operator string(LengthProperty value)
{
return value.unit switch
{
Unit.Pixel => value.value == 0.0 ? "0" : $"{(int)Math.Round(value.value)}px",
Unit.Degrees => value.value == 0.0 ? "0" : $"{value.value.ToString("F2", Const.Culture).Replace(".00", string.Empty)}deg",
Unit.Percent => value.value == 0.0 ? "0" : $"{value.value.ToString("F2", Const.Culture).Replace(".00", string.Empty)}%",
Unit.Auto => "auto",
Unit.None => "none",
Unit.Initial => "initial",
Unit.Default => "0",
_ => throw new ArgumentException(nameof(value))
};
}
public static LengthProperty operator +(LengthProperty a) => a;
public static LengthProperty operator -(LengthProperty a) => new(-a.value, a.unit);
public static LengthProperty operator +(LengthProperty a, double b) => new(a.value + b, a.unit);
public static LengthProperty operator -(LengthProperty a, double b) => new(a.value - b, a.unit);
public static bool operator ==(LengthProperty a, Unit b) => a.unit == b;
public static bool operator !=(LengthProperty a, Unit b) => a.unit != b;
public override bool Equals(object obj) => obj is LengthProperty property && value == property.value && unit == property.unit;
public override int GetHashCode() => HashCode.Combine(value, unit);
public override string ToString() => this;
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/LengthProperty.cs.meta
================================================
fileFormatVersion: 2
guid: 50407f2db68e4ab3ac1c3fe00a5b98f7
timeCreated: 1727946151
================================================
FILE: Editor/Core/Uss/Properties/NumberProperty.cs
================================================
namespace Figma.Core.Uss
{
/// <summary>
/// Represents either an integer or a number with a fractional component.
/// </summary>
internal struct NumberProperty
{
#region Fields
readonly double value;
#endregion
#region Constructors
NumberProperty(double value) => this.value = value;
#endregion
#region Operators
public static implicit operator NumberProperty(double? value) => new(value!.Value);
public static implicit operator NumberProperty(double value) => new(value);
public static implicit operator NumberProperty(string value) => new(double.Parse(value, Const.Culture));
public static implicit operator string(NumberProperty value) => value.value.ToString("F2", Const.Culture).Replace(".00", string.Empty);
public static NumberProperty operator +(NumberProperty a) => a;
public static NumberProperty operator -(NumberProperty a) => new(-a.value);
public static NumberProperty operator +(NumberProperty a, double b) => new(a.value + b);
public static NumberProperty operator -(NumberProperty a, double b) => new(a.value - b);
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/NumberProperty.cs.meta
================================================
fileFormatVersion: 2
guid: 674b330b5aea49318570f61fabe5e9cb
timeCreated: 1727946179
================================================
FILE: Editor/Core/Uss/Properties/ShadowProperty.cs
================================================
using System.Text.RegularExpressions;
namespace Figma.Core.Uss
{
internal struct ShadowProperty
{
static readonly Regex regex = new(@"(?<offsetHorizontal>\d+[px]*)\s+(?<offsetVertical>\d+[px]*)\s+(?<blurRadius>\d+[px]*)\s+(?<color>(rgba\([\d,\.\s]+\))|#\w{2,8}|[^#][\w-]+)");
#region Fields
readonly LengthProperty offsetHorizontal;
readonly LengthProperty offsetVertical;
readonly LengthProperty blurRadius;
readonly ColorProperty color;
#endregion
#region Constructors
internal ShadowProperty(LengthProperty offsetHorizontal, LengthProperty offsetVertical, LengthProperty blurRadius, ColorProperty color)
{
this.offsetHorizontal = offsetHorizontal;
this.offsetVertical = offsetVertical;
this.blurRadius = blurRadius;
this.color = color;
}
ShadowProperty(string value)
{
Match match = regex.Match(value);
offsetHorizontal = match.Groups[nameof(offsetHorizontal)].Value;
offsetVertical = match.Groups[nameof(offsetVertical)].Value;
blurRadius = match.Groups[nameof(blurRadius)].Value;
color = match.Groups[nameof(color)].Value;
}
#endregion
#region Operators
public static implicit operator ShadowProperty(string value) => new(value);
public static implicit operator string(ShadowProperty value) => $"{value.offsetHorizontal} {value.offsetVertical} {value.blurRadius} {value.color}";
#endregion
}
}
================================================
FILE: Editor/Core/Uss/Properties/ShadowProperty.cs.meta
================================================
fileFormatVersion: 2
guid: c3584d21c614453fa132bc171f4420eb
timeCreated: 1727946275
================================================
FILE: Editor/Core/Uss/Properties.meta
================================================
fileFormatVersion: 2
guid: 049f021dc7f44bb389f9f132ed103b7c
timeCreated: 1727946137
================================================
FILE: Editor/Core/Uss/StyleSlot.cs
================================================
namespace Figma.Core.Uss
{
using Internals;
internal class StyleSlot : Style
{
#region Fields
public bool Text { get; }
public string Slot { get; }
#endregion
#region Constructors
public StyleSlot(bool text, string slot, Style style)
{
Text = text;
Slot = slot;
styleType = style.styleType;
key = style.key;
name = style.name;
description = style.description;
}
#endregion
#region Methods
public override string ToString() => $"text={Text} slot={Slot} styleType={styleType} key={key} name={name} description={description}";
#endregion
}
}
================================================
FILE: Editor/Core/Uss/StyleSlot.cs.meta
================================================
fileFormatVersion: 2
guid: 7cb6785b010e457392b9a283f2cd0e62
timeCreated: 1727945310
================================================
FILE: Editor/Core/Uss/UssStyle.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
namespace Figma.Core.Uss
{
using Assets;
using Internals;
internal class UssStyle : BaseUssStyle
{
/// Problem with figma 2 Unity is that, Unity’s box-sizing property is always border-box, while figma's is a content-box with changing borders. See the MDN documentation https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing
#region Const
public const double tolerance = 0.01;
internal static readonly UssStyle overrideClass = new("unity-base-override")
{
alignItems = Align.Center,
backgroundColor = Unit.Initial,
borderWidth = Unit.Initial,
justifyContent = JustifyContent.Center,
margin = Unit.Initial,
overflow = Unit.Initial,
padding = Unit.Initial,
unityBackgroundPositionX = BackgroundPositionKeyword.Center,
unityBackgroundPositionY = BackgroundPositionKeyword.Center,
unityBackgroundRepeat = Repeat.NoRepeat,
unityFontDefinition = Unit.Initial,
};
internal static readonly UssStyle viewportClass = new("unity-viewport") { position = Position.Absolute, width = "100%", height = "100%" };
#endregion
#region Fields
readonly AssetsInfo assetsInfo;
#endregion
#region Properties
// Box model
// Dimensions
LengthProperty width { get => Get(nameof(width)); set => Set(nameof(width), value); }
LengthProperty height { get => Get(nameof(height)); set => Set(nameof(height), value); }
LengthProperty minWidth { get => Get("min-width"); set => Set("min-width", value); }
LengthProperty minHeight { get => Get("min-height"); set => Set("min-height", value); }
LengthProperty maxWidth { get => Get("max-width"); set => Set("max-width", value); }
LengthProperty maxHeight { get => Get("max-height"); set => Set("max-height", value); }
// Margins
LengthProperty marginLeft { get => Get1("margin-left", nameof(margin), 0); set => Set4("margin-left", value, nameof(margin), 0); }
LengthProperty marginTop { get => Get1("margin-top", nameof(margin), 1); set => Set4("margin-top", value, nameof(margin), 1); }
LengthProperty marginRight { get => Get1("margin-right", nameof(margin), 2); set => Set4("margin-right", value, nameof(margin), 2); }
LengthProperty marginBottom { get => Get1("margin-bottom", nameof(margin), 3); set => Set4("margin-bottom", value, nameof(margin), 3); }
Length4Property margin { get => Get4(nameof(margin), "margin-left", "margin-top", "margin-right", "margin-bottom"); set => Set1(nameof(margin), value, "margin-left", "margin-top", "margin-right", "margin-bottom"); }
// Borders
LengthProperty borderLeftWidth { get => Get1("border-left-width", "border-width", 0); set => Set4("border-left-width", value, "border-width", 0); }
LengthProperty borderTopWidth { get => Get1("border-top-width", "border-width", 1); set => Set4("border-top-width", value, "border-width", 1); }
LengthProperty borderRightWidth { get => Get1("border-right-width", "border-width", 2); set => Set4("border-right-width", value, "border-width", 2); }
LengthProperty borderBottomWidth { get => Get1("border-bottom-width", "border-width", 3); set => Set4("border-bottom-width", value, "border-width", 3); }
Length4Property borderWidth { get => Get4("border-width", "border-left-width", "border-top-width", "border-right-width", "border-bottom-width"); set => Set1("border-width", value, "border-left-width", "border-top-width", "border-right-width", "border-bottom-width"); }
// Padding
LengthProperty paddingLeft { get => Get1("padding-left", nameof(padding), 0); set => Set4("padding-left", value, nameof(padding), 0); }
LengthProperty paddingTop { get => Get1("padding-top", nameof(padding), 1); set => Set4("padding-top", value, nameof(padding), 1); }
LengthProperty paddingRight { get => Get1("padding-right", nameof(padding), 2); set => Set4("padding-right", value, nameof(padding), 2); }
LengthProperty paddingBottom { get => Get1("padding-bottom", nameof(padding), 3); set => Set4("padding-bottom", value, nameof(padding), 3); }
Length4Property padding { get => Get4(nameof(padding), "padding-left", "padding-top", "padding-right", "padding-bottom"); set => Set1(nameof(padding), value, "padding-left", "padding-top", "padding-right", "padding-bottom"); }
// Flex
// Items
NumberProperty flexGrow { get => Get("flex-grow"); set => Set("flex-grow", value); }
NumberProperty flexShrink { get => Get("flex-shrink"); set => Set("flex-shrink", value); }
LengthProperty flexBasis { get => Get("flex-basis"); set => Set("flex-basis", value); }
FlexProperty flex { get => Get(nameof(flex)); set => Set(nameof(flex), value); }
EnumProperty<Align> alignSelf { get => Get("align-self"); set => Set("align-self", value); }
NumberProperty itemSpacing { get => Get("--item-spacing"); set => Set("--item-spacing", value); }
// Containers
EnumProperty<FlexDirection> flexDirection { get => Get("flex-direction"); set => Set("flex-direction", value); }
EnumProperty<FlexWrap> flexWrap { get => Get("flex-wrap"); set => Set("flex-wrap", value); }
EnumProperty<Align> alignContent { get => Get("align-content"); set => Set("align-content", value); }
EnumProperty<Align> alignItems { get => Get("align-items"); set => Set("align-items", value); }
EnumProperty<JustifyContent> justifyContent { get => Get("justify-content"); set => Set("justify-content", value); }
// Positioning
EnumProperty<Position> position { get => Get(nameof(position)); set => Set(nameof(position), value); }
LengthProperty left { get => Get(nameof(left)); set => Set(nameof(left), value); }
LengthProperty top { get => Get(nameof(top)); set => Set(nameof(top), value); }
LengthProperty right { get => Get(nameof(right)); set => Set(nameof(right), value); }
LengthProperty bottom { get => Get(nameof(bottom)); set => Set(nameof(bottom), value); }
LengthProperty rotate { get => Get(nameof(rotate)); set => Set(nameof(rotate), value); }
Length2Property translate { get => GetDefault(nameof(translate), "0 0"); set => Set(nameof(translate), value); }
// Drawing
// Background
ColorProperty backgroundColor { get => Get("background-color"); set => Set("background-color", value); }
AssetProperty backgroundImage { get => Get("background-image"); set => Set("background-image", value); }
EnumProperty<BackgroundPositionKeyword> unityBackgroundPositionX { get => Get("background-position-x"); set => Set("background-position-x", value); }
EnumProperty<BackgroundPositionKeyword> unityBackgroundPositionY { get => Get("background-position-y"); set => Set("background-position-y", value); }
EnumProperty<Repeat> unityBackgroundRepeat { get => Get("background-repeat"); set => Set("background-repeat", value); }
EnumProperty<BackgroundSizeType> unityBackgroundSize { get => GetDefault("background-size", "auto"); set => Set("background-size", value); }
ColorProperty unityBackgroundImageTintColor { get => Get("-unity-background-image-tint-color"); set => Set("-unity-background-image-tint-color", value); }
// Slicing
IntegerProperty unitySliceLeft { get => Get("-unity-slice-left"); set => Set("-unity-slice-left", value); }
IntegerProperty unitySliceTop { get => Get("-unity-slice-top"); set => Set("-unity-slice-top", value); }
IntegerProperty unitySliceRight { get => Get("-unity-slice-right"); set => Set("-unity-slice-right", value); }
IntegerProperty unitySliceBottom { get => Get("-unity-slice-bottom"); set => Set("-unity-slice-bottom", value); }
// Borders
ColorProperty borderColor { get => Get("border-color"); set => Set("border-color", value); }
LengthProperty borderTopLeftRadius { get => Get1("border-top-left-radius", "border-radius", 0); set => Set4("border-top-left-radius", value, "border-radius", 0); }
LengthProperty borderTopRightRadius { get => Get1("border-top-right-radius", "border-radius", 1); set => Set4("border-top-right-radius", value, "border-radius", 1); }
LengthProperty borderBottomLeftRadius { get => Get1("border-bottom-left-radius", "border-radius", 2); set => Set4("border-bottom-left-radius", value, "border-radius", 2); }
LengthProperty borderBottomRightRadius { get => Get1("border-bottom-right-radius", "border-radius", 3); set => Set4("border-bottom-right-radius", value, "border-radius", 3); }
Length4Property borderRadius { get => Get4("border-radius", "border-top-left-radius", "border-top-right-radius", "border-bottom-left-radius", "border-bottom-right-radius"); set => Set1("border-radius", value, "border-top-left-radius", "border-top-right-radius", "border-bottom-left-radius", "border-bottom-right-radius"); }
// Appearance
EnumProperty<Visibility> overflow { get => Get(nameof(overflow)); set => Set(nameof(overflow), value); }
EnumProperty<OverflowClip> unityOverflowClipBox { get => Get("-unity-overflow-clip-box"); set => Set("-unity-overflow-clip-box", value); }
NumberProperty opacity { get => Get(nameof(opacity)); set => Set(nameof(opacity), value); }
EnumProperty<Visibility> visibility { get => Get(nameof(visibility)); set => Set(nameof(visibility), value); }
EnumProperty<Display> display { get => Get(nameof(display)); set => Set(nameof(display), value); }
// Text
ColorProperty color { get => Get(nameof(color)); set => Set(nameof(color), value); }
AssetProperty unityFont { get => Get("-unity-font"); set => Set("-unity-font", value); }
AssetProperty unityFontDefinition { get => Get("-unity-font-definition"); set => Set("-unity-font-definition", value); }
LengthProperty fontSize { get => Get("font-size"); set => Set("font-size", value); }
EnumProperty<FontStyle> unityFontStyle { get => Get("-unity-font-style"); set => Set("-unity-font-style", value); }
EnumProperty<TextAlign> unityTextAlign { get => Get("-unity-text-align"); set => Set("-unity-text-align", value); }
EnumProperty<Wrap> whiteSpace { get => Get("white-space"); set => Set("white-space", value); }
ShadowProperty textShadow { get => Get("text-shadow"); set => Set("text-shadow", value); }
EnumProperty<TextOverflow> textOverflow { get => Get("text-overflow"); set => Set("text-overflow", value); }
// Cursor
CursorProperty cursor { get => Get(nameof(cursor)); set => Set(nameof(cursor), value); }
// Effects
ShadowProperty boxShadow { get => Get("--box-shadow"); set => Set("--box-shadow", value); }
// Transitions
internal DurationProperty transitionDuration { get => Get("transition-duration"); set => Set("transition-duration", value); }
internal EnumProperty<EasingFunction> transitionEasing { get => Get("transition-timing-function"); set => Set("transition-timing-function", value); }
#endregion
#region Constructors
public UssStyle(string name) : base(name) { }
public UssStyle(string name, AssetsInfo assetsInfo) : this(name) => this.assetsInfo = assetsInfo;
public UssStyle(string name, AssetsInfo assetsInfo, BaseNode node, StyleSlot styleSlot) : this(name, assetsInfo)
{
switch (styleSlot.styleType)
{
case StyleType.FILL when node is IGeometryMixin geometry:
switch (styleSlot.Slot)
{
case "fill":
{
if (node is TextNode)
Name += "-Text";
AddFill(geometry);
break;
}
case "stroke":
Name += node is TextNode ? "-TextStroke" : "-Border";
AddStrokeColor(geometry);
break;
}
break;
case StyleType.TEXT when node is TextNode text:
AddSharedTextStyle(text.style);
break;
case StyleType.EFFECT when node is IBlendMixin blend:
AddBlend(blend);
break;
case StyleType.GRID or StyleType.NONE:
LogWarningIgnoredFigmaProperty(node, $"{nameof(styleSlot)} {nameof(styleSlot.styleType)} with {styleSlot.styleType}");
break;
default:
throw new NotSupportedException();
}
}
public UssStyle(string name, AssetsInfo assetsInfo, BaseNode node) : this(name, assetsInfo)
{
if (node.IsSvgNode())
{
AddSvg(assetsInfo, node); // AddSvg has to be called first in the constructor, because it overwrites its own boundingbox
}
else
{
if (node is IGeometryMixin geometry)
AddGeometry(geometry);
AddBorderRadius(node);
}
if (node is IBlendMixin blend)
AddBlend(blend);
if (node is ILayoutMixin layout && !node.IsRootNode())
AddLayout(layout);
if (node is IDefaultFrameMixin frame)
AddFrame(frame);
if (node is TextNode text)
AddText(text);
}
#endregion
#region Methods
internal UssStyle CopyFrom(UssStyle style)
{
style.Attributes.ForEach(x => Attributes[x.Key] = x.Value);
return this;
}
void AddFrame(IDefaultFrameMixin frame)
{
if (frame.clipsContent)
overflow = Visibility.Hidden;
LayoutDouble4 correctedPadding = frame.GetCorrectedPadding();
if (correctedPadding.Any())
padding = correctedPadding.ToLength4Property();
if (frame.layoutMode is LayoutMode.NONE)
return;
if (frame.layoutWrap is LayoutWrap.WRAP)
flexWrap = FlexWrap.Wrap;
if (frame.layoutMode is LayoutMode.HORIZONTAL)
flexDirection = FlexDirection.Row;
justifyContent = frame.primaryAxisAlignItems switch
{
PrimaryAxisAlignItems.MIN => JustifyContent.FlexStart,
PrimaryAxisAlignItems.CENTER => JustifyContent.Center,
PrimaryAxisAlignItems.MAX => JustifyContent.FlexEnd,
PrimaryAxisAlignItems.SPACE_BETWEEN => JustifyContent.SpaceBetween,
_ => throw new NotSupportedException()
};
alignItems = frame.counterAxisAlignItems switch
{
CounterAxisAlignItems.MIN => Align.FlexStart,
CounterAxisAlignItems.CENTER => Align.Center,
CounterAxisAlignItems.MAX => Align.FlexEnd,
CounterAxisAlignItems.BASELINE => Align.Center,
_ => throw new NotSupportedException()
};
if (frame.itemSpacing > 0.0)
itemSpacing = frame.itemSpacing;
}
void AddGeometry(IGeometryMixin geometry)
{
AddFill(geometry);
if (!geometry.HasBorder())
return;
AddStrokeColor(geometry);
if (geometry.individualStrokeWeights != null)
{
if (geometry.individualStrokeWeights.left > 0)
borderLeftWidth = geometry.individualStrokeWeights.left;
if (geometry.individualStrokeWeights.right > 0)
borderRightWidth = geometry.individualStrokeWeights.right;
if (geometry.individualStrokeWeights.top > 0)
borderTopWidth = geometry.individualStrokeWeights.top;
if (geometry.individualStrokeWeights.bottom > 0)
borderBottomWidth = geometry.individualStrokeWeights.bottom;
}
else
{
borderWidth = geometry.strokeWeight;
}
}
void AddLayout(ILayoutMixin layout)
{
void SetPositioning(IDefaultFrameMixin parent)
{
Rect frameBorderBox = layout.GetBorderBox();
Rect parentContentBox = parent.GetContentBox();
double x = frameBorderBox.x - parentContentBox.x;
double y = frameBorderBox.y - parentContentBox.y;
double r = parentContentBox.width - frameBorderBox.width - x;
double b = parentContentBox.height - frameBorderBox.height - y;
switch (layout.constraints.horizontal)
{
case ConstraintHorizontal.LEFT:
left = x;
break;
case ConstraintHorizontal.RIGHT:
right = r;
break;
case ConstraintHorizontal.LEFT_RIGHT:
left = x;
right = r;
break;
case ConstraintHorizontal.CENTER:
if (parent.layoutMode is LayoutMode.VERTICAL or LayoutMode.NONE)
alignSelf = Align.Center;
else if (parent.primaryAxisAlignItems is not PrimaryAxisAlignItems.CENTER)
LogWarningImpossibleDesign((IBaseNodeMixin)layout, $"Has center constraint on {nameof(LayoutMode.HORIZONTAL)} axis, but parent doesnt align items center it has {parent.layoutMode}.");
if (parent.HasBorder() && parent.strokeAlign is not StrokeAlign.OUTSIDE)
LogWarningImpossibleDesign((IBaseNodeMixin)layout, $"Center constraint should only be combined with parent that has {nameof(StrokeAlign.OUTSIDE)} border. Parent has {parent.strokeAlign}. The scaling will be off by a few pixels when growing");
double cx = parentContentBox.halfWidth - frameBorderBox.halfWidth - x;
if (Math.Abs(cx) >= tolerance)
translate = new Length2Property(new LengthProperty[] { -cx, 0.0 });
break;
case ConstraintHorizontal.SCALE when parentContentBox.width > 0.0:
left = new LengthProperty(100.0 * x / parentContentBox.width, Unit.Percent);
right = new LengthProperty(100.0 * r / parentContentBox.width, Unit.Percent);
break;
case ConstraintHorizontal.SCALE:
break;
default:
throw new NotSupportedException();
}
switch (layout.constraints.vertical)
{
case ConstraintVertical.TOP:
top = y;
break;
case ConstraintVertical.BOTTOM:
bottom = b;
break;
case ConstraintVertical.TOP_BOTTOM:
top = y;
bottom = b;
break;
case ConstraintVertical.CENTER:
if (parent.layoutMode is not LayoutMode.HORIZONTAL)
alignSelf = Align.Center;
else if (parent.primaryAxisAlignItems is not PrimaryAxisAlignItems.CENTER)
LogWarningImpossibleDesign((IBaseNodeMixin)layout, $"Has center constraint on {nameof(LayoutMode.VERTICAL)} axis, but parent doesnt align items center it has {parent.layoutMode}");
if (parent.HasBorder() && parent.strokeAlign is not StrokeAlign.OUTSIDE)
LogWarningImpossibleDesign((IBaseNodeMixin)layout, $"Center constraint should only be combined with parent that has {nameof(StrokeAlign.OUTSIDE)} border. Parent has {parent.strokeAlign}. The scaling will be off by a few pixels when growing");
double cy = parentContentBox.halfHeight - frameBorderBox.halfHeight - y;
if (Math.Abs(cy) >= tolerance)
translate = new Length2Property(new[] { translate[0], -cy });
break;
case ConstraintVertical.SCALE when parentContentBox.height > 0.0:
top = new LengthProperty(100.0 * y / parentContentBox.height, Unit.Percent);
bottom = new LengthProperty(100.0 * b / parentContentBox.height, Unit.Percent);
break;
case ConstraintVertical.SCALE:
break;
default:
throw new NotSupportedException();
}
}
bool BoxSizingCorrection(IDefaultFrameMixin parent)
{
// When strokesIncludedInLayout it's the same as box-sizing: border-box
if (parent.strokesIncludedInLayout)
return false;
// We modify position of elements to emulate negative padding. However, in UI Toolkit child cant to grow bigger than its parent.
LayoutDouble4 parentNegativePadding = parent.GetCorrectedPadding().OnlyNegativeValues();
bool anyHorizontal = parentNegativePadding.left < -tolerance || parentNegativePadding.right < -tolerance;
bool anyVertical = parentNegativePadding.top < -tolerance || parentNegativePadding.bottom < -tolerance;
bool wrongHorizontal = layout.layoutSizingHorizontal is LayoutSizing.FILL && anyHorizontal;
bool wrongVertical = layout.layoutSizingVertical is LayoutSizing.FILL && anyVertical;
if (wrongHorizontal || wrongVertical)
{
LogWarningImpossibleDesign((IBaseNodeMixin)layout, $"{nameof(LayoutSizing.FILL)} on node with child bounding box being outside parents content, Unity auto layout doesn't allow child to outgrow parents content. " +
$"Wrong {(wrongHorizontal && wrongVertical ? "Horizontal and Vertical" : wrongHorizontal ? "Horizontal" : "Vertical")} axis. " +
$"Element has ({layout.layoutSizingHorizontal}, {layout.layoutSizingVertical}), parent has border {parent.strokeAlign} with width {(string)parent.GetBorderWidths().ToLength4Property()}. " +
"Unity wont grow child above parent. Possible fixes:" +
$"\n1: Change {nameof(IDefaultFrameMixin.strokesIncludedInLayout)} in Auto layout settings to included." +
$"\n2: Use {nameof(LayoutSizing.FIXED)} or {nameof(LayoutSizing.HUG)}\n3: increase padding, currently missing {(string)(-parentNegativePadding).ToLength4Property()} more padding to make them not overlap." +
$"\n3: make parent border {nameof(StrokeAlign.OUTSIDE)}");
return false;
}
bool horizontal = parent.layoutMode is LayoutMode.HORIZONTAL;
double primary = parent.primaryAxisAlignItems switch
{
PrimaryAxisAlignItems.MIN or PrimaryAxisAlignItems.SPACE_BETWEEN => 1.0 * (horizontal ? parentNegativePadding.left : parentNegativePadding.top),
PrimaryAxisAlignItems.MAX => -1.0 * (horizontal ? parentNegativePadding.right : parentNegativePadding.bottom),
PrimaryAxisAlignItems.CENTER => 0.5 * (horizontal ? parentNegativePadding.left - parentNegativePadding.right : parentNegativePadding.top - parentNegativePadding.bottom),
_ => 0.0
};
double counter = parent.counterAxisAlignItems switch
{
CounterAxisAlignItems.MIN => 1.0 * (horizontal ? parentNegativePadding.top : parentNegativePadding.left),
CounterAxisAlignItems.MAX => -1.0 * (horizontal ? parentNegativePadding.bottom : parentNegativePadding.right),
CounterAxisAlignItems.CENTER => 0.5 * (horizontal ? parentNegativePadding.top - parentNegativePadding.bottom : parentNegativePadding.left - parentNegativePadding.right),
_ => 0.0
};
(double leftCorrection, double topCorrection) = horizontal ? (primary, counter) : (counter, primary);
if (Math.Abs(topCorrection) > tolerance)
top = topCorrection;
if (Math.Abs(leftCorrection) > tolerance)
left = leftCorrection;
return true;
}
IDefaultFrameMixin parent = (IDefaultFrameMixin)((IBaseNodeMixin)layout).parent;
bool forceAutoHorizontal = false;
bool forceAutoVertical = false;
if (parent.layoutMode is LayoutMode.NONE || layout.layoutPositioning is LayoutPositioning.ABSOLUTE)
{
forceAutoHorizontal = layout.constraints.horizontal is ConstraintHorizontal.SCALE or ConstraintHorizontal.LEFT_RIGHT;
forceAutoVertical = layout.constraints.vertical is ConstraintVertical.SCALE or ConstraintVertical.TOP_BOTTOM;
position = Position.Absolute;
SetPositioning(parent);
}
else
{
LayoutDouble4 margin4 = new();
if (BoxSizingCorrection(parent))
margin4 -= (layout as IGeometryMixin).GetOutsideBorderWidths();
if (Math.Abs(parent.itemSpacing) > tolerance && parent.primaryAxisAlignItems is not PrimaryAxisAlignItems.SPACE_BETWEEN && layout != parent.children.LastOrDefault(x => x.IsVisible() && x is not ILayoutMixin { layoutPositioning: LayoutPositioning.ABSOLUTE }))
{
if (parent.layoutMode is LayoutMode.HORIZONTAL)
margin4.right += parent.itemSpacing;
else
margin4.bottom += parent.itemSpacing;
}
if (margin4.Any())
margin = margin4.ToLength4Property();
LayoutSizing primarySizing = parent.layoutMode is LayoutMode.HORIZONTAL ? layout.layoutSizingHorizontal : layout.layoutSizingVertical;
if (primarySizing is LayoutSizing.FIXED or LayoutSizing.HUG)
flexShrink = 0.0; // Shrink clamps child to parent. Figma ignores this when using fixed or hug.
}
if (layout.layoutGrow > 0)
flexGrow = 1;
if (layout.layoutAlign is LayoutAlign.STRETCH)
alignSelf = Align.Stretch;
Rect borderBox = layout.GetBorderBox(); // Unity uses border-box
if (layout.layoutSizingHorizontal is LayoutSizing.FIXED && !forceAutoHorizontal)
width = borderBox.width;
if (layout.layoutSizingVertical is LayoutSizing.FIXED && !forceAutoVertical)
height = borderBox.height;
if (layout.minWidth != null)
minWidth = layout.minWidth.Value;
if (layout.minHeight != null)
minHeight = layout.minHeight.Value;
if (layout.maxWidth != null)
maxWidth = layout.maxWidth.Value;
if (layout.maxHeight != null)
maxHeight = layout.maxHeight.Value;
const double rad2deg = 180.0 / Math.PI;
if (Math.Abs(layout.rotation) > tolerance && !((IBaseNodeMixin)layout).IsSvgNode())
{
LogWarningImpossibleDesign(layout as IBaseNodeMixin, "Rotation and anchors are different in figma and unity. Its best to remove rotation from figma elements. In Figma rotation is applied and then constraints. In unity anchors are applied first. Meaning a full screen figma 1920x1080 becomes a 1080x1920 in unity.");
rotate = new LengthProperty(layout.rotation * rad2deg, Unit.Degrees);
}
if (layout is TextNode { style: { textAutoResize: TextAutoResize.WIDTH_AND_HEIGHT } } text)
{
if (parent.counterAxisAlignItems is CounterAxisAlignItems.BASELINE) // Baseline is not supported by unity, so we emulate it
{
double maxSize = parent.children.OfType<TextNode>().Max(x => x.style.fontSize);
const double fontSizeToOffset = 1.0 / 2.75; // Approximate value gotten through trail and error. This works when parent is CounterAxisCenter, siblings have same font family and height is set to auto. Otherwise its random if it works or not
double baselineOffset = (maxSize - text.style.fontSize) * fontSizeToOffset;
if (Math.Abs(baselineOffset) > tolerance)
top = baselineOffset;
}
else
{
const double idealLineHeightFactor = 1.2;
height = text.style.lineHeightPx; // Unity text only aligns correctly when height is 1.2 times font size. Figma allows any text height
if (text.style.lineHeightPx <= text.style.fontSize * idealLineHeightFactor) // Figma centers text when lineheight is too small
text.style.textAlignVertical = TextAlignVertical.CENTER;
}
}
}
void AddText(TextNode text)
{
TextNode.Style style = text.style;
string horizontal = style.textAlignHorizontal switch
{
TextAlignHorizontal.LEFT => nameof(left),
TextAlignHorizontal.RIGHT => nameof(right),
TextAlignHorizontal.CENTER => "center",
TextAlignHorizontal.JUSTIFIED => throw new NotSupportedException(),
_ => throw new NotSupportedException()
};
string vertical = style.textAlignVertical switch
{
TextAlignVertical.TOP => "upper",
TextAlignVertical.BOTTOM => "lower",
TextAlignVertical.CENTER => "middle",
_ => throw new NotSupportedException()
};
unityTextAlign = (EnumProperty<TextAlign>)$"{vertical}-{horizontal}";
if (style.textTruncation is TextTruncation.ENDING)
{
textOverflow = TextOverflow.Ellipsis;
overflow = Visibility.Hidden;
}
switch (style.textAutoResize)
{
case TextAutoResize.NONE:
case TextAutoResize.HEIGHT when style.maxLines is not 1:
whiteSpace = Wrap.Normal;
break;
case TextAutoResize.TRUNCATE:
LogWarningIgnoredFigmaProperty(text, $"{nameof(TextAutoResize)}.{nameof(TextAutoResize.TRUNCATE)} is deprecated, should be changed for element in figma document to use either {nameof(TextAutoResize.HEIGHT)} or {nameof(TextAutoResize.WIDTH_AND_HEIGHT)}");
break;
}
AddSharedTextStyle(style);
}
void AddBlend(IBlendMixin blend)
{
if (blend.opacity < 1.0 - tolerance)
opacity = UssStyleExtension.AlphaCorrection(blend.opacity);
IEnumerable<ShadowEffect> effects = blend.effects.OfType<ShadowEffect>().Where(x => x.visible);
ShadowEffect effect = effects.FirstOrDefault();
if (effect == null)
return;
if (effects.Count() > 1)
LogWarningIgnoredFigmaProperty((IBaseNodeMixin)blend, $"More than 1 effects, we support 1 effect per element, this has {effects.Count()}");
ShadowProperty shadow = new(effect.offset.x, effect.offset.y, effect.radius, effect.color);
if (blend is TextNode text)
{
if (effect.type is EffectType.DROP_SHADOW)
textShadow = shadow;
else
LogWarningImpossibleDesign(text, $"Cant use {effect.type} for text we can only use {nameof(EffectType.DROP_SHADOW)}");
}
else
{
boxShadow = shadow;
LogWarningIgnoredFigmaProperty((IBaseNodeMixin)blend, "Effects on elements, we support effects on text only");
}
}
void AddBorderRadius(BaseNode node)
{
// Unity makes each corner as round as possible while figma limits borders to max 50% of size. In Figma when a corner is bigger than the rest that corner can make other corner less round, we dont know how to recreate that effect in unity
// Figma makes outside borders have radius equal to radius + border
double maxBorderRadius = node is ILayoutMixin layout ? Math.Min(layout.GetBorderBox().width, layout.GetBorderBox().height) * 0.5 : double.MaxValue;
LayoutDouble4 outsideBorder = node is IGeometryMixin geometry ? geometry.GetOutsideBorderWidths() : new LayoutDouble4();
if (node is ICornerMixin { cornerRadius: > 0 } corner)
{
LayoutDouble4 rad = outsideBorder + new LayoutDouble4(corner.cornerRadius.Value);
LayoutDouble4 radius = new(Math.Min(maxBorderRadius, rad.top), Math.Min(maxBorderRadius, rad.left), Math.Min(maxBorderRadius, rad.bottom), Math.Min(maxBorderRadius, rad.right));
borderRadius = radius.ToLength4Property();
}
else if (node is IRectangleCornerMixin { rectangleCornerRadii: not null } rectangleCorner && rectangleCorner.rectangleCornerRadii.Any(x => x > 0.0))
{
double GetBorderCorrection(double radius, double border) => radius == 0.0 ? 0.0 : Math.Min(maxBorderRadius, radius + border);
double[] radii = rectangleCorner.rectangleCornerRadii;
LayoutDouble4 radius = new(GetBorderCorrection(radii[0], outsideBorder.top), GetBorderCorrection(radii[1], outsideBorder.right), GetBorderCorrection(radii[2], outsideBorder.bottom), GetBorderCorrection(radii[3], outsideBorder.left));
borderRadius = radius.ToLength4Property();
}
}
void AddSvg(AssetsInfo assetsInfo, BaseNode svg)
{
IGeometryMixin geometry = (IGeometryMixin)svg;
ILayoutMixin layout = (ILayoutMixin)svg;
Rect boundingBox = layout.absoluteBoundingBox;
if (geometry.HasBorder())
{
boundingBox.x -= geometry.strokeWeight / 2.0;
if (geometry.strokeCap is not StrokeCap.NONE)
boundingBox.y -= geometry.strokeWeight / 2.0;
}
layout.absoluteBoundingBox = boundingBox;
string extension = svg.HasImage() ? KnownFormats.png : KnownFormats.svg;
if (assetsInfo.GetAssetPath(svg.id, extension, out string url))
backgroundImage = Url(url);
}
#endregion
#region Support Methods
void AddSharedTextStyle(TextNode.Style style)
{
const string defaultFont = "Inter-Regular";
bool TryGetFontWithExtension(string font, out string resource)
{
if (assetsInfo.GetAssetPath(font, KnownFormats.ttf, out string ttfPath))
{
resource = Url(ttfPath);
return true;
}
if (assetsInfo.GetAssetPath(font, KnownFormats.otf, out string otfPath))
{
resource = Url(otfPath);
return true;
}
resource = Resource(defaultFont);
return false;
}
(string, string) GetFont()
{
if (string.IsNullOrEmpty(style.fontPostScriptName) && string.IsNullOrEmpty(style.fontFamily))
return (null, null);
string fontPostScriptName = style.fontPostScriptName ?? $"{style.fontFamily}-{style.fontStyle.Replace(" ", string.Empty)}";
string weightPostfix;
if (style.fontWeight > 0)
weightPostfix = Enum.GetValues(typeof(FontWeight)).GetValue((int)(style.fontWeight / 100) - 1).ToString();
else
weightPostfix = fontPostScriptName.Contains('-') ? fontPostScriptName.Split('-')[1].Replace(nameof(Index), string.Empty) : string.Empty;
string italicPostfix = style.italic || fontPostScriptName.Contains(nameof(FontStyle.Italic)) ? nameof(FontStyle.Italic) : string.Empty;
string fontName = $"{style.fontFamily}-{weightPostfix}{italicPostfix}";
if (!TryGetFontWithExtension(fontName, out string font) && !TryGetFontWithExtension(fontPostScriptName, out font))
Debug.LogWarning(Extensions.BuildTargetMessage("Cannot find Font", fontName, string.Empty));
bool exists = assetsInfo.GetAssetPath(fontName, KnownFormats.asset, out string path);
return (font, exists ? path : null);
}
fontSize = style.fontSize;
(string font, string fontDefinition) = GetFont();
if (font != null)
unityFont = font;
if (fontDefinition != null)
unityFontDefinition = Url(fontDefinition);
if (font == null && fontDefinition == null)
{
Debug.LogWarning($"Font style {style.fontFamily} {style.fontStyle} {style.fontPostScriptName} is not resolved");
unityFont = Url(defaultFont);
}
}
void AddFill(IGeometryMixin geometry)
{
bool urlExists = false;
string url = string.Empty;
RGBA finalColor = new RGBA();
foreach (Paint fill in geometry.fills.Where(x => x.visible).Reverse())
{
switch (fill)
{
case SolidPaint solid:
solid.color.a = solid.opacity;
finalColor = finalColor.BlendWith(solid.color);
break;
case GradientPaint gradient:
if (geometry is TextNode)
{
RGBA average = gradient.gradientStops.Select(stop => stop.color).GetAverageColor();
average.a = gradient.opacity;
finalColor = finalColor.BlendWith(average);
}
else
{
urlExists = assetsInfo.GetAssetPath(gradient.GetHash(), KnownFormats.svg, out url);
}
break;
case ImagePaint image:
if (geometry is TextNode text)
{
LogWarningImpossibleDesign(text, $"{nameof(TextElement)} with images, unity places images in background, while figma puts them inside the text");
break;
}
urlExists = assetsInfo.GetAssetPath(image.imageRef, KnownFormats.png, out url);
unityBackgroundSize = image.scaleMode switch
{
ScaleMode.FILL => BackgroundSizeType.Cover,
ScaleMode.FIT => BackgroundSizeType.Contain,
_ => unityBackgroundSize
};
break;
}
finalColor.a = UssStyleExtension.AlphaCorrection(finalColor.a);
if (geometry is TextNode)
color = new ColorProperty(finalColor);
else
backgroundColor = new ColorProperty(finalColor);
if (urlExists)
backgroundImage = Url(url);
}
}
void AddStrokeColor(IGeometryMixin geometry)
{
if (geometry is TextNode)
{
LogWarningIgnoredFigmaProperty((IBaseNodeMixin)geometry, "Stroke on text"); // Stroke on text might not be possible at all as unity makes inside stroke and figma outside stroke
return;
}
RGBA finalColor = new();
foreach (Paint stroke in geometry.strokes.Where(x => x.visible).Reverse())
{
RGBA color = stroke switch
{
SolidPaint solid => solid.color,
GradientPaint gradient => gradient.gradientStops.Select(stop => stop.color).GetAverageColor(),
_ => throw new NotSupportedException()
};
color.a = stroke.opacity;
finalColor = finalColor.BlendWith(color);
}
finalColor.a = UssStyleExtension.AlphaCorrection(finalColor.a);
borderColor = finalColor;
}
internal static List<UssStyle> MakeTransitionStyles(UssStyle root, UssStyle idle, UssStyle hover = null, UssStyle active = null)
{
List<UssStyle> transitions = new() { new UssStyle(root.Name) { Target = idle, opacity = 1 } };
if (hover != null)
transitions.Add(new UssStyle(root.Name) { Target = idle, PseudoClass = PseudoClass.Hover, opacity = 0 });
if (active != null)
transitions.Add(new UssStyle(root.Name) { Target = idle, PseudoClass = PseudoClass.Active, opacity = 0 });
if (hover != null)
{
transitions.Add(new UssStyle(root.Name) { Target = hover, opacity = 0 });
transitions.Add(new UssStyle(root.Name) { Target = hover, PseudoClass = PseudoClass.Hover, opacity = 1 });
if (active != null)
transitions.Add(new UssStyle(root.Name) { Target = hover, PseudoClass = PseudoClass.Active, opacity = 0 });
}
if (active != null)
{
transitions.Add(new UssStyle(root.Name) { Target = active, opacity = 0 });
if (hover != null)
transitions.Add(new UssStyle(root.Name) { Target = active, PseudoClass = PseudoClass.Hover, opacity = 0 });
transitions.Add(new UssStyle(root.Name) { Target = active, PseudoClass = PseudoClass.Active, opacity = 1 });
}
return transitions;
}
static void LogWarningIgnoredFigmaProperty(IBaseNodeMixin node, string message) => Debug.LogWarning(Extensions.BuildTargetMessage("Ignored figma property", node.GetFullPath(), $"No support for {message}. Not implemented."));
static void LogWarningImpossibleDesign(IBaseNodeMixin node, string message) => Debug.LogWarning(Extensions.BuildTargetMessage("Wrong figma design", node.GetFullPath(), $"{message}. We cant create this in Unity."));
#endregion
}
}
================================================
FILE: Editor/Core/Uss/UssStyle.cs.meta
================================================
fileFormatVersion: 2
guid: 8d258033e1644b1fa80fcdf1fb668783
timeCreated: 1727945365
================================================
FILE: Editor/Core/Uss/UssWriter.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Figma.Core.Uss
{
using Internals;
internal class UssWriter : IDisposable, IAsyncDisposable
{
#region Fields
readonly string rootDirectory;
readonly StreamWriter stream;
int count;
#endregion
#region Constructors
public UssWriter(string rootDirectory, string path)
{
this.rootDirectory = rootDirectory;
stream = new StreamWriter(Path = path, false, Encoding.UTF8, 1024);
}
#endregion
#region Properties
public string Path { get; }
#endregion
#region Methods
public void Write(BaseUssStyle style)
{
if (!style.HasAttributes)
return;
if (count > 0)
{
stream.WriteLine();
stream.WriteLine();
}
stream.Write(style.BuildName());
stream.WriteLine(" {");
foreach ((string key, string value) in style.Attributes)
{
switch (key)
{
case "background-image" when value.Contains("url"):
// Getting a relative path to image to keep the reference.
// Since images are located in a parent of a parent directory.
// Assets/Images directory and frames are in Assets/Frames/CanvasName/
// We need to calculate a relative path and the only way of doing this
// is on write operation, since UssStyle is not aware of the path, where it
// would be written.
stream.WriteLine($"\t{key}: url('{System.IO.Path.GetRelativePath(System.IO.Path.GetDirectoryName(Path), PathExtensions.CombinePath(rootDirectory, value[5..^2]))?.Replace('\\', '/')}');");
continue;
default:
stream.WriteLine($"\t{key}: {value};");
break;
}
}
stream.Write("}");
count++;
Write(style.SubStyles);
}
public void Write(IEnumerable<BaseUssStyle> styles) => styles.OrderBy(x => x.Name).ForEach(Write);
void IDisposable.Dispose() => stream?.Dispose();
async ValueTask IAsyncDisposable.DisposeAsync()
{
if (stream != null)
await stream.DisposeAsync();
}
#endregion
}
}
================================================
FILE: Editor/Core/Uss/UssWriter.cs.meta
================================================
fileFormatVersion: 2
guid: d732fb08b4e246c6bce62bad8551f8f8
timeCreated: 1727945385
================================================
FILE: Editor/Core/Uss.meta
================================================
fileFormatVersion: 2
guid: eb2949d8c99346768cecb2a0968b2029
timeCreated: 1732192985
================================================
FILE: Editor/Core/Uxml/UxmlBuilder.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityAsyncAwaitUtil;
using UnityEngine;
namespace Figma.Core.Uxml
{
using Internals;
using static Const;
using static Internals.Extensions;
using static Internals.PathExtensions;
internal class UxmlBuilder
{
#region Fields
readonly Data data;
readonly NodeMetadata nodeMetadata;
readonly string globalUssFilePath;
readonly StylesPreprocessor stylesPreprocessor;
#endregion
#region Constructors
public UxmlBuilder(Data data, NodeMetadata nodeMetadata, string globalUssFilePath, StylesPreprocessor stylesPreprocessor)
{
this.data = data;
this.nodeMetadata = nodeMetadata;
this.globalUssFilePath = globalUssFilePath;
this.stylesPreprocessor = stylesPreprocessor;
}
#endregion
#region Methods
public void CreateDocument(string directory, string fileName, DocumentNode documentNode, IReadOnlyDictionary<string, IReadOnlyList<string>> framesPaths)
{
string CreateTemplateName(string path) => RemoveExtension(path).Replace('/', '-');
using UxmlWriter writer = new(directory, fileName);
writer.WriteUssStyleReference(GetRelativePath(writer.filePath, globalUssFilePath));
writer.StartElement(documentNode, stylesPreprocessor.GetClassList(documentNode), nodeMetadata.GetElementType(documentNode));
foreach (string templatePath in framesPaths.SelectMany(framesPath => framesPath.Value))
{
string path = GetRelativePath(writer.filePath, templatePath);
writer.WriteTemplate(CreateTemplateName(path), path);
}
foreach ((string name, IReadOnlyList<string> scope) in framesPaths)
{
if (scope.Count == 0)
continue;
writer.StartElement(nameof(UnityEngine.UIElements.VisualElement), ("picking-mode", "ignore"), ("class", "unity-viewport"), (nameof(name), name));
foreach (string path in scope)
{
string frameName = Path.GetFileNameWithoutExtension(path);
string templateName = CreateTemplateName(GetRelativePath(writer.filePath, path));
writer.WriteInstance(frameName, templateName, Uss.UssStyle.viewportClass.Name);
}
writer.EndElement();
}
writer.EndElement();
}
public string CreateFrame(string directory, string[] ussStyleFilesPath, IReadOnlyDictionary<string, string> templates, DefaultFrameNode frameNode)
{
using UxmlWriter writer = new(directory, frameNode.name);
WriteStyles(ussStyleFilesPath, writer);
foreach ((string templateName, string templatePath) in templates)
writer.WriteTemplate(templateName, GetRelativePath(writer.filePath, templatePath));
WriteNodesRecursively(frameNode, writer);
return writer.filePath;
}
public string CreateComponentSet(string directory, string[] ussStyleFilesPath, ComponentSetNode componentSetNode)
{
using UxmlWriter writer = new(directory, componentSetNode.name);
WriteStyles(ussStyleFilesPath, writer);
WriteNodesRecursively(componentSetNode, writer);
return writer.filePath;
}
public string CreateElement(string directory, string[] ussStyleFilesPath, DefaultShapeNode node, string template)
{
(bool isHash, string hashedTemplate) = nodeMetadata.GetTemplate(node);
using UxmlWriter writer = new(directory, isHash ? hashedTemplate : template);
WriteStyles(ussStyleFilesPath, writer);
if (node is DefaultFrameNode parent)
foreach (SceneNode child in parent.children)
WriteNodesRecursively(child, writer);
return writer.filePath;
}
void WriteNodesRecursively(BaseNode node, UxmlWriter uxml, bool isComponent = false)
{
void WriteCanvasNode(CanvasNode canvasNode, UxmlWriter writer)
{
writer.StartElement(canvasNode, stylesPreprocessor.GetClassList(canvasNode), nodeMetadata.GetElementType(canvasNode));
canvasNode.children.ForEach(child => WriteNodesRecursively(child, writer));
writer.EndElement();
}
void WriteSectionNode(SectionNode sectionNode, UxmlWriter writer)
{
writer.StartElement(sectionNode, stylesPreprocessor.GetClassList(sectionNode), nodeMetadata.GetElementType(sectionNode));
sectionNode.children.ForEach(child => WriteNodesRecursively(child, writer));
writer.EndElement();
throw new NotImplementedException(nameof(WriteSectionNode));
}
void WriteSliceNode(SliceNode sliceNode, UxmlWriter writer)
{
writer.StartElement(sliceNode, stylesPreprocessor.GetClassList(sliceNode), nodeMetadata.GetElementType(sliceNode));
writer.EndElement();
}
void WriteTextNode(TextNode textNode, UxmlWriter writer)
{
writer.StartElement(textNode, stylesPreprocessor.GetClassList(textNode), nodeMetadata.GetElementType(textNode));
string text = textNode.style.textCase switch
{
TextCase.UPPER => textNode.characters.ToUpper(Culture),
TextCase.LOWER => textNode.characters.ToLower(Culture),
_ => textNode.characters
};
writer.xmlWriter.WriteAttributeString(nameof(text), text);
writer.EndElement();
}
void WriteDefaultFrameNode(DefaultFrameNode defaultFrameNode, UxmlWriter writer)
{
WriteDefaultShapeNode(defaultFrameNode, writer, false);
defaultFrameNode.children.ForEach(child => WriteNodesRecursively(child, writer, isComponent));
writer.EndElement();
}
void WriteBooleanOperationNode(BooleanOperationNode node, UxmlWriter writer)
{
WriteDefaultShapeNode(node, writer); // We shouldn't process children for vector boolean operation
}
void WriteDefaultShapeNode(DefaultShapeNode defaultShapeNode, UxmlWriter writer, bool closeElement = true)
{
string tooltip = null;
if (nodeMetadata.GetTemplate(defaultShapeNode) is (var hash, { } template) && template.NotNullOrEmpty())
tooltip = hash ? template : null;
writer.StartElement(defaultShapeNode, stylesPreprocessor.GetClassList(defaultShapeNode), nodeMetadata.GetElementType(defaultShapeNode));
if (tooltip.NotNullOrEmpty())
writer.xmlWriter.WriteAttributeString(nameof(tooltip), tooltip!); // Use tooltip as a storage for hash template name
if (closeElement)
writer.EndElement();
}
void WriteInstanceNode(InstanceNode instanceNode, UxmlWriter writer)
{
if (data.components.TryGetValue(instanceNode.componentId, out Component component) && !component.remote &&
!string.IsNullOrEmpty(component.componentSetId) &&
data.componentSets.TryGetValue(component.componentSetId, out Component target) && !target.remote)
{
string componentSetName = target.name;
string classList = stylesPreprocessor.GetClassList(instanceNode);
writer.WriteInstance(instanceNode.name, componentSetName, classList);
}
else
{
// Since this code only runs from Parallel, outside of Unity scope
// We cannot use Debug.Log() without returning to Unity's thread
SyncContextUtil.UnitySynchronizationContext.Post(_ => Debug.LogWarning(BuildTargetMessage($"Target {nameof(Component)} for node", instanceNode.GetFullPath(), "is not found")), null);
WriteDefaultFrameNode(instanceNode, writer);
}
}
if (!node.IsVisible() || (!nodeMetadata.EnabledInHierarchy(node) && node is not ComponentSetNode && !isComponent))
return;
if (node is CanvasNode canvas) WriteCanvasNode(canvas, uxml);
if (node is FrameNode frame) WriteDefaultFrameNode(frame, uxml);
if (node is GroupNode group) WriteDefaultFrameNode(group, uxml);
if (node is ComponentSetNode componentSet) WriteDefaultFrameNode(componentSet, uxml);
if (node is SliceNode slice) WriteSliceNode(slice, uxml);
if (node is RectangleNode rectangle) WriteDefaultShapeNode(rectangle, uxml);
if (node is LineNode line) WriteDefaultShapeNode(line, uxml);
if (node is EllipseNode ellipse) WriteDefaultShapeNode(ellipse, uxml);
if (node is RegularPolygonNode regularPolygon) WriteDefaultShapeNode(regularPolygon, uxml);
if (node is StarNode star) WriteDefaultShapeNode(star, uxml);
if (node is VectorNode vector) WriteDefaultShapeNode(vector, uxml);
if (node is TextNode text) WriteTextNode(text, uxml);
if (node is ComponentNode component) WriteDefaultFrameNode(component, uxml);
if (node is InstanceNode instance) WriteInstanceNode(instance, uxml);
if (node is BooleanOperationNode booleanOperation) WriteBooleanOperationNode(booleanOperation, uxml);
if (node is SectionNode sectionNode) WriteDefaultFrameNode(sectionNode, uxml); // WriteSectionNode(sectionNode, uxml);
}
#endregion
#region Support Methods
void WriteStyles(string[] styles, UxmlWriter writer) => styles.ForEach(ussPath => writer.WriteUssStyleReference(CombinePath(GetRelativePath(writer.filePath, ussPath))));
#endregion
}
}
================================================
FILE: Editor/Core/Uxml/UxmlBuilder.cs.meta
================================================
fileFormatVersion: 2
guid: 501228cf0ce84dfda7160110c165f212
timeCreated: 1727945409
================================================
FILE: Editor/Core/Uxml/UxmlWriter.cs
================================================
using System;
using System.Text;
using System.Xml;
using UnityEngine.UIElements;
namespace Figma.Core.Uxml
{
using Internals;
using static Const;
using static Internals.Const;
using static Internals.PathExtensions;
internal sealed class UxmlWriter : IDisposable
{
const string elementsNamespace = "ui";
static readonly XmlWriterSettings xmlWriterSettings = new()
{
OmitXmlDeclaration = true,
Indent = true,
IndentChars = indentCharacters,
NewLineOnAttributes = false,
Encoding = Encoding.UTF8
};
#region Fields
internal readonly string filePath;
internal readonly XmlWriter xmlWriter;
#endregion
#region Constructors
public UxmlWriter(string directory, string fileName)
{
filePath = CombinePath(directory, $"{fileName}.{KnownFormats.uxml}");
xmlWriter = XmlWriter.Create(filePath, xmlWriterSettings);
xmlWriter.WriteStartElement(elementsNamespace, "UXML", uxmlNamespace);
}
#endregion
#region Methods
public void Dispose()
{
xmlWriter.WriteEndElement();
xmlWriter?.Dispose();
}
public void StartElement(BaseNode node, string ussClasses, (ElementType type, string typeFullName) elementTypeInfo)
{
(string prefix, string elementName, string pickingMode) GetElementData(BaseNode node)
{
string prefix = elementsNamespace;
string elementName = nameof(VisualElement);
PickingMode pickingMode = PickingMode.Ignore;
if (elementTypeInfo.type == ElementType.IElement)
{
prefix = null;
elementName = elementTypeInfo.typeFullName;
pickingMode = PickingMode.Position;
}
else if (elementTypeInfo.type == ElementType.None)
{
if (node is not (DefaultFrameNode or TextNode or ComponentSetNode))
return (prefix, elementName, pickingMode.ToString());
const string inputsPrefix = "Inputs";
const string buttonsPrefix = "Buttons";
const string togglesPrefix = "Toggles";
const string scrollViewsPrefix = "ScrollViews";
if (node is TextNode) elementName = node.name.StartsWith(inputsPrefix) ? nameof(TextField) : nameof(Label);
if (node.name.StartsWith(buttonsPrefix)) elementName = nameof(Button);
else if (node.name.StartsWith(togglesPrefix)) elementName = nameof(Toggle);
else if (node.name.StartsWith(scrollViewsPrefix)) elementName = nameof(ScrollView);
pickingMode = node.name.StartsWith(buttonsPrefix) ||
node.name.StartsWith(togglesPrefix) ||
node.name.StartsWith(scrollViewsPrefix) ||
(node is TextNode && node.name.StartsWith(inputsPrefix))
? PickingMode.Position
: pickingMode;
}
else
{
elementName = elementTypeInfo.type.ToString();
pickingMode = elementTypeInfo.type is ElementType.VisualElement or
ElementType.BindableElement or
ElementType.Box or
ElementType.TextElement or
ElementType.Label or
ElementType.Image
? PickingMode.Ignore
: PickingMode.Position;
}
return (prefix, elementName, pickingMode.ToString());
}
(string prefix, string elementName, string pickingMode) = GetElementData(node);
if (prefix.NotNullOrEmpty())
xmlWriter.WriteStartElement(prefix, elementName, uxmlNamespace);
else
xmlWriter.WriteStartElement(elementName);
xmlWriter.WriteAttributeString("name", node.name);
xmlWriter.WriteAttributeString("id", node.id);
if (ussClasses.NotNullOrEmpty())
xmlWriter.WriteAttributeString("class", ussClasses);
if (pickingMode != nameof(PickingMode.Position))
xmlWriter.WriteAttributeString("picking-mode", pickingMode);
}
public void StartElement(string type, params (string name, string value)[] attributes)
{
xmlWriter.WriteStartElement(elementsNamespace, type, uxmlNamespace);
foreach ((string name, string value) attribute in attributes)
xmlWriter.WriteAttributeString(attribute.name, attribute.value);
}
public void EndElement() => xmlWriter.WriteEndElement();
public void WriteUssStyleReference(string path)
{
StartElement(nameof(Style), ("src", path));
EndElement();
}
public void WriteTemplate(string templateName, string templatePath)
{
StartElement("Template", ("name", templateName), ("src", templatePath));
EndElement();
}
public void WriteInstance(string instanceName, string templateName, string classList = null)
{
StartElement("Instance", ("name", instanceName), ("template", templateName), ("picking-mode", "ignore"));
if (!string.IsNullOrEmpty(classList))
xmlWriter.WriteAttributeString("class", classList);
EndElement();
}
#endregion
}
}
================================================
FILE: Editor/Core/Uxml/UxmlWriter.cs.meta
================================================
fileFormatVersion: 2
guid: 32914bba2eaf4c938f1c10a15860d6fa
timeCreated: 1733218152
================================================
FILE: Editor/Core/Uxml.meta
================================================
fileFormatVersion: 2
guid: b264c8b3ae0846dc87a6a96ccb5c5dbf
timeCreated: 1733218052
================================================
FILE: Editor/Core.meta
================================================
fileFormatVersion: 2
guid: 7101b854596dd674dad786dffc6936ab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Extensions/Extensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Figma
{
using Internals;
[DebuggerStepThrough]
internal static class Extensions
{
#region Const
static readonly string[] unitsMap = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
static readonly string[] tensMap = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
#endregion
#region Methods
internal static int ToBit(this bool value) => value ? 1 : 0;
internal static IEnumerable<T> IndexRedundantNames<T>(this IReadOnlyList<T> items, Func<T, string> getName, Action<T, string> setName, Func<int, string> postfixConverter)
{
foreach (IGrouping<string, T> group in items.GroupBy(getName).Where(y => y.Count() > 1))
{
int i = 0;
foreach (T item in group)
setName(item, postfixConverter(i++));
}
return items;
}
internal static string NumberToWords(this int number)
{
switch (number)
{
case 0:
return unitsMap[0];
case < 0:
return $"minus-{NumberToWords(Math.Abs(number))}";
}
string words = string.Empty;
if (number / 1000000 > 0)
{
words += $"{NumberToWords(number / 1000000)}-million ";
number %= 1000000;
}
if (number / 1000 > 0)
{
words += $"{NumberToWords(number / 1000)}-thousand ";
number %= 1000;
}
if (number / 100 > 0)
{
words += $"{NumberToWords(number / 100)}-hundred ";
number %= 100;
}
if (number <= 0)
return words;
if (words != string.Empty)
words += "and-";
if (number < 20)
words += unitsMap[number];
else
{
words += tensMap[number / 10];
if (number % 10 > 0)
words += $"-{unitsMap[number % 10]}";
}
return words;
}
internal static RGBA GetAverageColor(this IEnumerable<RGBA> colors)
{
RGBA avgColor = new();
int count = 0;
foreach (RGBA color in colors)
{
avgColor.r += color.r;
avgColor.g += color.g;
avgColor.b += color.b;
avgColor.a += color.a;
count++;
}
if (count == 0) return avgColor;
avgColor.r /= count;
avgColor.g /= count;
avgColor.b /= count;
avgColor.a /= count;
return avgColor;
}
#endregion
}
}
================================================
FILE: Editor/Extensions/Extensions.cs.meta
================================================
fileFormatVersion: 2
guid: 7130aa1fa17b4bffa5e38dc5887c8364
timeCreated: 1732199774
================================================
FILE: Editor/Extensions/NodeExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Figma
{
using Internals;
[DebuggerStepThrough]
internal static class NodeExtensions
{
#region Methods
internal static IEnumerable<IBaseNodeMixin> Flatten(this IBaseNodeMixin root, Func<IBaseNodeMixin, bool> filter = null)
{
Stack<IBaseNodeMixin> nodes = new();
nodes.Push(root);
if (root is DocumentNode documentNode)
foreach (CanvasNode canvasNode in documentNode.children)
nodes.Push(canvasNode);
for (int depth = 0; depth < Const.maximumAllowedDepthLimit; depth++)
{
if (nodes.Count == 0)
yield break;
IBaseNodeMixin node = nodes.Pop();
if (filter != null && !filter(node))
continue;
yield return node;
if (node is IChildrenMixin parent)
foreach (SceneNode child in parent.children)
nodes.Push(child);
}
throw new InvalidOperationException(Const.maximumDepthLimitReachedExceptionMessage);
}
internal static bool IsRootNode(this IBaseNodeMixin node) => node is DocumentNode or CanvasNode or ComponentNode || node.parent is CanvasNode or ComponentNode;
internal static bool IsSvgNode(this IBaseNodeMixin node) => node is LineNode or EllipseNode or RegularPolygonNode or StarNode or VectorNode ||
(node is BooleanOperationNode && node.Flatten().Any(x => x is not BooleanOperationNode && IsVisible(x) && IsSvgNode(x)));
internal static bool IsVisible(this IBaseNodeMixin node) => (node is not ISceneNodeMixin scene || scene.visible) && (node.parent == null || node.parent.IsVisible());
internal static bool HasImage(this IBaseNodeMixin node) => node is IGeometryMixin geometry && geometry.fills.Any(x => x is ImagePaint);
internal static void SetParent(this BaseNode node)
{
switch (node)
{
case DocumentNode document:
foreach (CanvasNode canvas in document.children)
{
canvas.parent = node;
SetParent(canvas);
}
break;
case IChildrenMixin { children: not null } children:
foreach (SceneNode child in children.children)
{
child.parent = node;
SetParent(child);
}
break;
}
}
internal static string GetHash(this GradientPaint gradient)
{
using SHA1CryptoServiceProvider sha1 = new();
using MemoryStream stream = new();
using BinaryWriter writer = new(stream);
writer.Write((int)gradient.type);
foreach (ColorStop stop in gradient.gradientStops)
{
writer.Write(stop.position);
writer.Write(stop.color.r);
writer.Write(stop.color.g);
writer.Write(stop.color.b);
writer.Write(stop.color.a);
}
foreach (Vector position in gradient.gradientHandlePositions)
{
writer.Write(position.x);
writer.Write(position.y);
}
byte[] bytes = stream.ToArray();
byte[] hashBytes = sha1.ComputeHash(bytes);
StringBuilder hashBuilder = new();
foreach (byte @byte in hashBytes)
hashBuilder.Append(@byte.ToString("x2"));
return hashBuilder.ToString();
}
internal static string GetFullPath(this IBaseNodeMixin node)
{
string result = string.Empty;
for (int depth = 0; depth < Const.maximumAllowedDepthLimit; depth++)
{
if (node == null)
return result;
result = string.IsNullOrEmpty(result) ? node.name : node.name + PathExtensions.unixPathSeperator + result;
node = node.parent;
}
throw new InvalidOperationException(Const.maximumDepthLimitReachedExceptionMessage);
}
#endregion
}
}
================================================
FILE: Editor/Extensions/NodeExtensions.cs.meta
================================================
fileFormatVersion: 2
guid: bc624b728724707428b12ccb11dd0658
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Extensions/UssStyleExtensions.cs
================================================
using System;
using System.Linq;
namespace Figma
{
using Core.Uss;
using Internals;
using UnityEngine;
using Rect = Internals.Rect;
static class UssStyleExtension
{
const bool forceAlphaCorrection = true;
#region Methods
internal static bool HasBorder(this IGeometryMixin geometry) => geometry.strokes.Any(x => x.visible) && geometry.strokeWeight > UssStyle.tolerance;
internal static LayoutDouble4 GetBorderWidths(this IGeometryMixin geometry)
{
if (geometry is null or TextNode || !HasBorder(geometry)) return new LayoutDouble4();
LayoutDouble4 borders = geometry.individualStrokeWeights != null
? new LayoutDouble4(geometry.individualStrokeWeights.top, geometry.individualStrokeWeights.right, geometry.individualStrokeWeights.bottom, geometry.individualStrokeWeights.left)
: new LayoutDouble4(geometry.strokeWeight);
return borders;
}
internal static LayoutDouble4 GetOutsideBorderWidths(this IGeometryMixin geometry) => geometry.GetBorderWidths() * geometry.GetOutsideFraction();
internal static LayoutDouble4 GetInsideBorderWidths(this IGeometryMixin geometry) => geometry.GetBorderWidths() * (1 - geometry.GetOutsideFraction());
internal static Rect GetContentBox(this ILayoutMixin layout)
{
LayoutDouble4 border = GetInsideBorderWidths(layout as IGeometryMixin);
double x = layout.absoluteBoundingBox.x + border.left;
double y = layout.absoluteBoundingBox.y + border.top;
double width = layout.absoluteBoundingBox.width - border.left - border.right;
double height = layout.absoluteBoundingBox.height - border.top - border.bottom;
return new Rect(x, y, width, height);
}
internal static Rect GetBorderBox(this ILayoutMixin layout)
{
LayoutDouble4 border = GetOutsideBorderWidths(layout as IGeometryMixin);
double x = layout.absoluteBoundingBox.x - border.left;
double y = layout.absoluteBoundingBox.y - border.top;
double width = layout.absoluteBoundingBox.width + border.left + border.right;
double height = layout.absoluteBoundingBox.height + border.top + border.bottom;
return new Rect(x, y, width, height);
}
internal static LayoutDouble4 GetCorrectedPadding(this IDefaultFrameMixin frame) => new LayoutDouble4(frame.paddingTop, frame.paddingRight, frame.paddingBottom, frame.paddingLeft) - (frame.strokesIncludedInLayout ? new LayoutDouble4() : GetInsideBorderWidths(frame));
internal static RGBA BlendWith(this RGBA foreground, RGBA background)
{
double blend = background.a * (1.0 - foreground.a);
RGBA color = new();
color.a = foreground.a + blend;
const double alphaTolerance = 0.01;
if (color.a < alphaTolerance) return new RGBA();
color.r = (foreground.r * foreground.a + background.r * blend) / color.a;
color.g = (foreground.g * foreground.a + background.g * blend) / color.a;
color.b = (foreground.b * foreground.a + background.b * blend) / color.a;
return color;
}
// Magical formula found by testing different methods. including LinearToGammaSpaceExact(a), 1-GammaToLinearSpaceExact(1-a), pow(a, 1/2.2), pow(a, 1/1.8), 1.0-pow(1-a, 2.2). This method yielded results close to figma with only one layer of blending. However, with multiple semitransparent elements, this alpha correction makes them darker than figma
public static double AlphaCorrection(double a) => (forceAlphaCorrection || UnityEditor.PlayerSettings.colorSpace is UnityEngine.ColorSpace.Linear) && a is > 0.0 and < 1.0 ? 1.0f - Mathf.GammaToLinearSpace(1.0f - (float)a) : a;
#endregion
#region Support Methods
static double GetOutsideFraction(this IGeometryMixin geometry) => geometry.strokeAlign switch
{
StrokeAlign.OUTSIDE => 1.0,
StrokeAlign.CENTER => 0.5,
StrokeAlign.INSIDE => 0.0,
_ => throw new NotSupportedException()
};
#endregion
}
}
================================================
FILE: Editor/Extensions/UssStyleExtensions.cs.meta
================================================
fileFormatVersion: 2
guid: cd5b7b5e37724678a84ec7eb169a0c3d
timeCreated: 1744032663
================================================
FILE: Editor/Extensions.meta
================================================
fileFormatVersion: 2
guid: 15d902d3df7e2ae40a71e11e3a45e807
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/Figma.Editor.asmdef
================================================
{
"name": "Figma.Editor",
"rootNamespace": "Figma.Editor",
"references": [
"Unity.VectorGraphics.Editor",
"AsyncAwaitUtil",
"CommonUtils",
"Figma"
],
"includePlatforms": [
"Editor"
]
}
================================================
FILE: Editor/Figma.Editor.asmdef.meta
================================================
fileFormatVersion: 2
guid: 5eb4f7c69a0b05842a5bd445fe8970e8
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Editor/FigmaDownloader.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEditor;
namespace Figma
{
using Core;
using Core.Assets;
using Internals;
using static Internals.Const;
using static Internals.PathExtensions;
internal class FigmaDownloader : Api
{
#region Consts
const int maxConcurrentRequests = 5;
const int maxComponentsIdsInOneRequest = 400;
#endregion
#region Fields
readonly AssetsInfo assetsInfo;
string componentsDirectoryPath;
string elementsDirectoryPath;
string imagesDirectoryPath;
string framesDirectoryPath;
FigmaWriter figmaWriter;
NodeMetadata nodeMetadata;
NodesRegistry nodesRegistry;
StylesPreprocessor stylesPreprocessor;
#endregion
#region Constructors
internal FigmaDownloader(string personalAccessToken, string fileKey, AssetsInfo assetsInfo) : base(personalAccessToken, fileKey) => this.assetsInfo = assetsInfo;
#endregion
#region Methods
internal async Task Run(bool downloadImages, string uxmlName, IReadOnlyCollection<Type> frames, bool prune, bool filter, bool systemCopyBuffer, int progress, CancellationToken token)
{
Directory.CreateDirectory(framesDirectoryPath = assetsInfo.GetAbsolutePath(framesDirectoryName));
Directory.CreateDirectory(imagesDirectoryPath = assetsInfo.GetAbsolutePath(imagesDirectoryName));
Directory.CreateDirectory(elementsDirectoryPath = assetsInfo.GetAbsolutePath(elementsDirectoryName));
Directory.CreateDirectory(componentsDirectoryPath = assetsInfo.GetAbsolutePath(componentsDirectoryName));
int steps = downloadImages ? 5 : 4;
await assetsInfo.cachedAssets.LoadAsync(token);
Progress.Report(progress, 1, steps, "Downloading file");
List<string> visibleSceneNodes = new(32);
if (filter)
{
Progress.SetDescription(progress, "Filtering nodes");
Data shallowData = await GetAsync<Data>($"files/{fileKey}?depth=2", token);
shallowData.document.SetParent();
NodeMetadata shallowMetadata = new(shallowData.document, frames, true, false, true);
visibleSceneNodes.AddRange(shallowData.document.children.SelectMany(x => x.children).Where(shallowMetadata.EnabledInHierarchy).Select(node => node.id));
Progress.SetDescription(progress, string.Empty);
}
string idsString = string.Empty;
if (visibleSceneNodes.Any())
idsString = $"?ids={string.Join(",", visibleSceneNodes)}";
Progress.SetDescription(progress, "Resolving Figma file");
string json = await GetJsonAsync($"files/{fileKey}{idsString}", token);
if (systemCopyBuffer)
GUIUtility.systemCopyBuffer = json;
Progress.Report(progress, 2, steps, "Parsing Figma file");
Data data = await ConvertOnBackgroundAsync<Data>(json, token);
data.document.SetParent();
Progress.SetDescription(progress, "Creating entities");
nodeMetadata = new NodeMetadata(data.document, frames, filter);
nodesRegistry = new NodesRegistry(data, nodeMetadata);
stylesPreprocessor = new StylesPreprocessor(data, assetsInfo);
figmaWriter = new FigmaWriter(assetsInfo.directory, uxmlName, data, stylesPreprocessor, nodeMetadata, assetsInfo);
Progress.Report(progress, 3, steps, "Downloading missing components");
await DownloadDocumentsAsync(token);
if (downloadImages)
{
Progress.Report(progress, 4, steps, "Downloading images");
Progress.SetDescription(progress, "Writing Gradients");
await WriteGradientsAsync(token);
Progress.SetDescription(progress, "Downloading image fills");
await GetImageFillsAsync(progress, nodesRegistry.ImageFills, token);
Progress.SetDescription(progress, $"Downloading {KnownFormats.png} files");
await GetImageNodesAsync(progress, nodesRegistry.Pngs, UxmlDownloadImages.RenderAsPng, KnownFormats.png, token);
Progress.SetDescription(progress, $"Downloading {KnownFormats.svg} files");
await GetImageNodesAsync(progress, nodesRegistry.Svgs, UxmlDownloadImages.RenderAsSvg, KnownFormats.svg, token);
await assetsInfo.cachedAssets.SaveAsync();
}
Progress.SetStepLabel(progress, string.Empty);
Progress.Report(progress, steps, steps, "Updating *.uss/*.uxml files");
await figmaWriter.WriteAsync(prune);
}
internal void CleanUp(bool cleanImages = false)
{
void CleanDirectory(string directory, string[] filters)
gitextract_gbxs852s/ ├── .azuredevops/ │ └── pull_request_template.md ├── .gitattributes ├── .gitignore ├── Assets/ │ ├── Panel Settings.asset │ ├── Panel Settings.asset.meta │ ├── UI Theme.tss │ ├── UI Theme.tss.meta │ ├── UnityBase.uss │ └── UnityBase.uss.meta ├── Assets.meta ├── Editor/ │ ├── Assets/ │ │ └── icon.png.meta │ ├── Assets.meta │ ├── Core/ │ │ ├── Api.cs │ │ ├── Api.cs.meta │ │ ├── Assets/ │ │ │ ├── AssetsInfo.cs │ │ │ ├── AssetsInfo.cs.meta │ │ │ ├── CachedAssets.cs │ │ │ ├── CachedAssets.cs.meta │ │ │ ├── GradientWriter.cs │ │ │ ├── GradientWriter.cs.meta │ │ │ ├── ImagesPostprocessor.cs │ │ │ └── ImagesPostprocessor.cs.meta │ │ ├── Assets.meta │ │ ├── JsonUtility.cs │ │ ├── JsonUtility.cs.meta │ │ ├── NodeMetadata.cs │ │ ├── NodeMetadata.cs.meta │ │ ├── NodesRegistry.cs │ │ ├── NodesRegistry.cs.meta │ │ ├── RichText/ │ │ │ ├── RichTextBuilder.cs │ │ │ └── RichTextBuilder.cs.meta │ │ ├── RichText.meta │ │ ├── RootNodes.cs │ │ ├── RootNodes.cs.meta │ │ ├── StylesPreprocessor.cs │ │ ├── StylesPreprocessor.cs.meta │ │ ├── Uss/ │ │ │ ├── BaseUssStyle.cs │ │ │ ├── BaseUssStyle.cs.meta │ │ │ ├── Properties/ │ │ │ │ ├── AssetProperty.cs │ │ │ │ ├── AssetProperty.cs.meta │ │ │ │ ├── ColorProperty.cs │ │ │ │ ├── ColorProperty.cs.meta │ │ │ │ ├── CursorProperty.cs │ │ │ │ ├── CursorProperty.cs.meta │ │ │ │ ├── DurationProperty.cs │ │ │ │ ├── DurationProperty.cs.meta │ │ │ │ ├── EnumProperty.cs │ │ │ │ ├── EnumProperty.cs.meta │ │ │ │ ├── FlexProperty.cs │ │ │ │ ├── FlexProperty.cs.meta │ │ │ │ ├── IntegerProperty.cs │ │ │ │ ├── IntegerProperty.cs.meta │ │ │ │ ├── LayoutDouble4.cs │ │ │ │ ├── LayoutDouble4.cs.meta │ │ │ │ ├── Length2Property.cs │ │ │ │ ├── Length2Property.cs.meta │ │ │ │ ├── Length4Property.cs │ │ │ │ ├── Length4Property.cs.meta │ │ │ │ ├── LengthProperty.cs │ │ │ │ ├── LengthProperty.cs.meta │ │ │ │ ├── NumberProperty.cs │ │ │ │ ├── NumberProperty.cs.meta │ │ │ │ ├── ShadowProperty.cs │ │ │ │ └── ShadowProperty.cs.meta │ │ │ ├── Properties.meta │ │ │ ├── StyleSlot.cs │ │ │ ├── StyleSlot.cs.meta │ │ │ ├── UssStyle.cs │ │ │ ├── UssStyle.cs.meta │ │ │ ├── UssWriter.cs │ │ │ └── UssWriter.cs.meta │ │ ├── Uss.meta │ │ ├── Uxml/ │ │ │ ├── UxmlBuilder.cs │ │ │ ├── UxmlBuilder.cs.meta │ │ │ ├── UxmlWriter.cs │ │ │ └── UxmlWriter.cs.meta │ │ └── Uxml.meta │ ├── Core.meta │ ├── Extensions/ │ │ ├── Extensions.cs │ │ ├── Extensions.cs.meta │ │ ├── NodeExtensions.cs │ │ ├── NodeExtensions.cs.meta │ │ ├── UssStyleExtensions.cs │ │ └── UssStyleExtensions.cs.meta │ ├── Extensions.meta │ ├── Figma.Editor.asmdef │ ├── Figma.Editor.asmdef.meta │ ├── FigmaDownloader.cs │ ├── FigmaDownloader.cs.meta │ ├── FigmaWriter.cs │ ├── FigmaWriter.cs.meta │ ├── Inspector/ │ │ ├── AuthTest.cs │ │ ├── AuthTest.cs.meta │ │ ├── FigmaInspector.cs │ │ ├── FigmaInspector.cs.meta │ │ ├── Styles.cs │ │ └── Styles.cs.meta │ ├── Inspector.meta │ ├── Interface/ │ │ ├── Const.cs │ │ ├── Const.cs.meta │ │ ├── Enums.cs │ │ ├── Enums.cs.meta │ │ ├── Figma.Enums.cs │ │ ├── Figma.Enums.cs.meta │ │ ├── Figma.Types.Interface.cs │ │ ├── Figma.Types.Interface.cs.meta │ │ ├── Figma.Types.Structs.cs │ │ ├── Figma.Types.Structs.cs.meta │ │ ├── Figma.Types.cs │ │ ├── Figma.Types.cs.meta │ │ ├── Interface.Records.cs │ │ └── Interface.Records.cs.meta │ └── Interface.meta ├── Editor.meta ├── License.md ├── License.md.meta ├── Prefabs/ │ ├── Figma.prefab │ └── Figma.prefab.meta ├── Prefabs.meta ├── Readme.md ├── Readme.md.meta ├── Runtime/ │ ├── AssemblyInfo.cs │ ├── AssemblyInfo.cs.meta │ ├── Core/ │ │ ├── Element.cs │ │ ├── Element.cs.meta │ │ ├── QueryAttribute.cs │ │ ├── QueryAttribute.cs.meta │ │ ├── UxmlAttribute.cs │ │ ├── UxmlAttribute.cs.meta │ │ ├── VisualElementMetadata.cs │ │ └── VisualElementMetadata.cs.meta │ ├── Core.meta │ ├── Extensions/ │ │ ├── EnumerableExtensions.cs │ │ ├── EnumerableExtensions.cs.meta │ │ ├── Extensions.cs │ │ ├── Extensions.cs.meta │ │ ├── PathExtensions.cs │ │ ├── PathExtensions.cs.meta │ │ ├── VisualElementExtensions.cs │ │ └── VisualElementExtensions.cs.meta │ ├── Extensions.meta │ ├── Figma.asmdef │ ├── Figma.asmdef.meta │ ├── Figma.cs │ ├── Figma.cs.meta │ ├── Interface/ │ │ ├── Const.cs │ │ ├── Const.cs.meta │ │ ├── Core/ │ │ │ ├── SubElements.cs │ │ │ ├── SubElements.cs.meta │ │ │ ├── SyncElements.cs │ │ │ └── SyncElements.cs.meta │ │ ├── Core.meta │ │ ├── Enums.cs │ │ ├── Enums.cs.meta │ │ ├── Interface.Core.cs │ │ ├── Interface.Core.cs.meta │ │ ├── Interfaces.cs │ │ └── Interfaces.cs.meta │ └── Interface.meta ├── Runtime.meta ├── package.json ├── package.json.meta ├── ~Samples/ │ ├── Scripts/ │ │ ├── Figma.Samples.asmdef │ │ ├── Figma.Samples.asmdef.meta │ │ ├── Test.cs │ │ └── Test.cs.meta │ ├── Scripts.meta │ ├── Test.unity │ └── Test.unity.meta └── ~Samples.meta
SYMBOL INDEX (564 symbols across 62 files)
FILE: Editor/Core/Api.cs
class Api (line 10) | internal abstract class Api : IDisposable
method Api (line 18) | protected Api(string personalAccessToken, string fileKey)
method Dispose (line 27) | void IDisposable.Dispose() => httpClient.Dispose();
method ConvertOnBackgroundAsync (line 31) | protected async Task<T> ConvertOnBackgroundAsync<T>(string json, Cance...
method GetAsync (line 32) | protected async Task<T> GetAsync<T>(string get, CancellationToken toke...
method GetJsonAsync (line 33) | protected async Task<string> GetJsonAsync(string get, CancellationToke...
method HttpGetAsync (line 34) | async Task<string> HttpGetAsync(string url, CancellationToken token = ...
FILE: Editor/Core/Assets/AssetsInfo.cs
class AssetsInfo (line 12) | internal class AssetsInfo
method AssetsInfo (line 24) | internal AssetsInfo(string directory, string relativeDirectory, string...
method GetAssetPath (line 36) | internal bool GetAssetPath(string name, string extension, out string p...
method AddModifiedFiles (line 60) | internal void AddModifiedFiles(params string[] items) => items.ForEach...
method GetAbsolutePath (line 61) | internal string GetAbsolutePath(string path) => PathExtensions.Combine...
method GetFontPath (line 65) | string GetFontPath(string name, string extension)
FILE: Editor/Core/Assets/CachedAssets.cs
class CachedAssets (line 11) | internal sealed class CachedAssets
method CachedAssets (line 18) | internal CachedAssets(string directory, string name) => targetFilePath...
method LoadAsync (line 34) | internal async Task LoadAsync(CancellationToken token) => Map = File.E...
method SaveAsync (line 35) | internal async Task SaveAsync() => await File.WriteAllTextAsync(target...
FILE: Editor/Core/Assets/GradientWriter.cs
class GradientWriter (line 12) | internal class GradientWriter : IDisposable
method GradientWriter (line 28) | public GradientWriter(string xmlPath) => writer = XmlWriter.Create(xml...
method WriteAsync (line 32) | public async Task WriteAsync(GradientPaint gradient, CancellationToken...
method Dispose (line 96) | public void Dispose() => writer?.Close();
FILE: Editor/Core/Assets/ImagesPostprocessor.cs
class ImagesPostprocessor (line 8) | internal class ImagesPostprocessor : AssetPostprocessor
method OnPreprocessAsset (line 11) | void OnPreprocessAsset()
FILE: Editor/Core/JsonUtility.cs
class JsonUtility (line 10) | public class JsonUtility
class ArrayPool (line 12) | class ArrayPool : IArrayPool<char>
method Rent (line 15) | public char[] Rent(int minimumLength) => ArrayPool<char>.Shared.Rent...
method Return (line 16) | public void Return(char[] array) => ArrayPool<char>.Shared.Return(ar...
method Initialize (line 27) | #if UNITY_EDITOR
method ToJson (line 50) | public static string ToJson<T>(T value, bool prettyPrint)
method FromJson (line 57) | public static T FromJson<T>(string json, bool useArrayPool = true)
class ArrayConverter (line 69) | public abstract class ArrayConverter<T, TEnum> : JsonConverter
method CanConvert (line 72) | public override bool CanConvert(Type objectType) => objectType == type...
method ReadJson (line 73) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method WriteJson (line 83) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
method GetValue (line 93) | protected TEnum GetValue(JObject obj, string name = "type") => (TEnum)...
method ToObject (line 94) | protected abstract T ToObject(JObject obj, JsonSerializer serializer);
class EffectArrayConverter (line 98) | public class EffectArrayConverter : ArrayConverter<Effect, EffectType>
method ToObject (line 101) | protected override Effect ToObject(JObject obj, JsonSerializer seriali...
class PaintArrayConverter (line 113) | public class PaintArrayConverter : ArrayConverter<Paint, PaintType>
method ToObject (line 116) | protected override Paint ToObject(JObject obj, JsonSerializer serializ...
class LayoutGridArrayConverter (line 131) | public class LayoutGridArrayConverter : ArrayConverter<LayoutGrid, Pattern>
method ToObject (line 134) | protected override LayoutGrid ToObject(JObject obj, JsonSerializer ser...
class ExportSettingsArrayConverter (line 145) | public class ExportSettingsArrayConverter : ArrayConverter<ExportSetting...
method ToObject (line 148) | protected override ExportSettings ToObject(JObject obj, JsonSerializer...
class TransitionConverter (line 160) | public class TransitionConverter : JsonConverter
method CanConvert (line 163) | public override bool CanConvert(Type objectType) => objectType == type...
method ReadJson (line 164) | public override object ReadJson(JsonReader reader, Type objectType, ob...
method WriteJson (line 179) | public override void WriteJson(JsonWriter writer, object value, JsonSe...
class BaseNodeArrayConverter (line 183) | public class BaseNodeArrayConverter : ArrayConverter<BaseNode, NodeType>
method ToObject (line 186) | protected override BaseNode ToObject(JObject obj, JsonSerializer seria...
class SceneNodeArrayConverter (line 196) | public class SceneNodeArrayConverter : ArrayConverter<SceneNode, NodeType>
method ToObject (line 199) | protected override SceneNode ToObject(JObject obj, JsonSerializer seri...
class FigmaGeneration (line 222) | public class FigmaGeneration { }
FILE: Editor/Core/NodeMetadata.cs
class NodeMetadata (line 15) | internal class NodeMetadata
method NodeMetadata (line 97) | internal NodeMetadata(DocumentNode documentNode, IEnumerable<Type> ele...
method EnabledInHierarchy (line 155) | internal bool EnabledInHierarchy(IBaseNodeMixin node) => !rootMetadata...
method ShouldDownload (line 156) | internal bool ShouldDownload(IBaseNodeMixin node, UxmlDownloadImages f...
method GetTemplate (line 174) | internal (bool isHash, string templateName) GetTemplate(IBaseNodeMixin...
method GetElementType (line 185) | internal (ElementType, string) GetElementType(IBaseNodeMixin node)
method Find (line 201) | IBaseNodeMixin Find(IBaseNodeMixin value, string path, bool throwExcep...
method FindRoot (line 326) | IBaseNodeMixin FindRoot(IBaseNodeMixin value)
method GetMetadata (line 345) | BaseNodeMetadata GetMetadata(IBaseNodeMixin value)
FILE: Editor/Core/NodesRegistry.cs
class NodesRegistry (line 9) | internal sealed class NodesRegistry
method NodesRegistry (line 19) | public NodesRegistry(Data data, NodeMetadata nodeMetadata)
FILE: Editor/Core/RichText/RichTextBuilder.cs
class TextBuilder (line 11) | internal sealed class TextBuilder
type TagType (line 14) | enum TagType
class Tag (line 26) | class Tag
method Tag (line 37) | public Tag(StringBuilder stringBuilder, string tag)
method Set (line 45) | public void Set(bool required)
method Set (line 55) | public void Set(bool required, string value)
method Open (line 75) | void Open()
method Close (line 80) | void Close()
method TextBuilder (line 96) | public TextBuilder(TextNode textNode)
method Build (line 114) | public string Build()
FILE: Editor/Core/RootNodes.cs
class RootNodes (line 10) | internal class RootNodes
method RootNodes (line 29) | public RootNodes(Data data, NodeMetadata nodeMetadata)
FILE: Editor/Core/StylesPreprocessor.cs
class StylesPreprocessor (line 12) | internal class StylesPreprocessor
method StylesPreprocessor (line 33) | internal StylesPreprocessor(Data data, AssetsInfo assetsInfo)
method AddStyles (line 52) | void AddStyles(IBaseNodeMixin root, Dictionary<string, Style> styles)
method AddRichText (line 119) | void AddRichText(IBaseNodeMixin node)
method AddTransitionStyles (line 125) | void AddTransitionStyles()
method AddMissingComponent (line 224) | internal void AddMissingComponent(ComponentNode component, Dictionary<...
method GetStyles (line 232) | internal IReadOnlyList<UssStyle> GetStyles(IBaseNodeMixin root) =>
method InheritStyles (line 238) | void InheritStyles(IBaseNodeMixin root)
method GetClassList (line 274) | internal string GetClassList(IBaseNodeMixin node)
method GetStyle (line 322) | UssStyle GetStyle(IBaseNodeMixin node) => componentStyleMap.TryGetValu...
FILE: Editor/Core/Uss/BaseUssStyle.cs
class BaseUssStyle (line 8) | internal abstract class BaseUssStyle
method BaseUssStyle (line 25) | protected BaseUssStyle(string name) => Name = name;
method BuildName (line 29) | public string BuildName()
method DoesInherit (line 50) | public bool DoesInherit(BaseUssStyle style) => inherited.Contains(style);
method Inherit (line 51) | public void Inherit(IReadOnlyCollection<BaseUssStyle> styles)
method Get (line 61) | protected string Get(string name) => Attributes[name];
method GetDefault (line 62) | protected string GetDefault(string name, string defaultValue) => Attri...
method Get1 (line 63) | protected string Get1(string name, string group, int index)
method Get4 (line 76) | protected string Get4(string name, params string[] names)
method Set (line 88) | protected void Set(string name, string value) => Attributes[name] = va...
method Set1 (line 89) | protected void Set1(string name, string value, params string[] names)
method Set4 (line 96) | protected void Set4(string name, string value, string group, int index)
method Url (line 107) | protected static string Url(string url) => $"url('{url}')";
method Resource (line 108) | protected static string Resource(string resource) => $"resource('{reso...
FILE: Editor/Core/Uss/Properties/AssetProperty.cs
type AssetProperty (line 10) | internal struct AssetProperty
method AssetProperty (line 19) | AssetProperty(Unit unit)
method AssetProperty (line 25) | AssetProperty(string value)
FILE: Editor/Core/Uss/Properties/ColorProperty.cs
type ColorProperty (line 11) | internal readonly struct ColorProperty
method ColorProperty (line 21) | internal ColorProperty(RGBA color, Double? opacity = 1, float alphaMul...
method ColorProperty (line 28) | ColorProperty(string value)
method ToString (line 55) | public override string ToString() => this;
FILE: Editor/Core/Uss/Properties/CursorProperty.cs
type CursorProperty (line 3) | internal struct CursorProperty
FILE: Editor/Core/Uss/Properties/DurationProperty.cs
type DurationProperty (line 8) | internal readonly struct DurationProperty
method DurationProperty (line 16) | internal DurationProperty(TimeUnit unit)
method DurationProperty (line 21) | internal DurationProperty(double value, TimeUnit unit)
method Equals (line 59) | public override bool Equals(object obj) => obj is DurationProperty pro...
method GetHashCode (line 60) | public override int GetHashCode() => HashCode.Combine(value, unit);
method ToString (line 61) | public override string ToString() => this;
FILE: Editor/Core/Uss/Properties/EnumProperty.cs
type EnumProperty (line 7) | internal struct EnumProperty<T> where T : struct, Enum
method EnumProperty (line 21) | EnumProperty(T value)
method EnumProperty (line 26) | EnumProperty(Unit unit)
method ToString (line 42) | public override string ToString() => this;
FILE: Editor/Core/Uss/Properties/FlexProperty.cs
type FlexProperty (line 3) | internal struct FlexProperty
FILE: Editor/Core/Uss/Properties/IntegerProperty.cs
type IntegerProperty (line 6) | internal struct IntegerProperty
method IntegerProperty (line 13) | IntegerProperty(int value) => this.value = value;
FILE: Editor/Core/Uss/Properties/LayoutDouble4.cs
type LayoutDouble4 (line 5) | struct LayoutDouble4
method LayoutDouble4 (line 15) | public LayoutDouble4(double top, double right, double bottom, double l...
method LayoutDouble4 (line 22) | public LayoutDouble4(double value)
method OnlyPositiveValues (line 30) | public LayoutDouble4 OnlyPositiveValues() => new(top > UssStyle.tolera...
method OnlyNegativeValues (line 31) | public LayoutDouble4 OnlyNegativeValues() => new(top < UssStyle.tolera...
method ToLength4Property (line 33) | public Length4Property ToLength4Property() => new[] { top, right, bott...
method Any (line 34) | public bool Any() => Math.Abs(top) > UssStyle.tolerance || Math.Abs(ri...
FILE: Editor/Core/Uss/Properties/Length2Property.cs
type Length2Property (line 6) | internal readonly struct Length2Property
method Length2Property (line 18) | internal Length2Property(Unit unit)
method Length2Property (line 23) | internal Length2Property(LengthProperty[] properties)
FILE: Editor/Core/Uss/Properties/Length4Property.cs
type Length4Property (line 6) | internal readonly struct Length4Property
method Length4Property (line 18) | internal Length4Property(Unit unit)
method Length4Property (line 23) | internal Length4Property(LengthProperty[] properties)
FILE: Editor/Core/Uss/Properties/LengthProperty.cs
type LengthProperty (line 8) | internal readonly struct LengthProperty
method LengthProperty (line 16) | internal LengthProperty(Unit unit)
method LengthProperty (line 21) | internal LengthProperty(double value, Unit unit)
method Equals (line 64) | public override bool Equals(object obj) => obj is LengthProperty prope...
method GetHashCode (line 65) | public override int GetHashCode() => HashCode.Combine(value, unit);
method ToString (line 66) | public override string ToString() => this;
FILE: Editor/Core/Uss/Properties/NumberProperty.cs
type NumberProperty (line 6) | internal struct NumberProperty
method NumberProperty (line 13) | NumberProperty(double value) => this.value = value;
FILE: Editor/Core/Uss/Properties/ShadowProperty.cs
type ShadowProperty (line 5) | internal struct ShadowProperty
method ShadowProperty (line 17) | internal ShadowProperty(LengthProperty offsetHorizontal, LengthPropert...
method ShadowProperty (line 24) | ShadowProperty(string value)
FILE: Editor/Core/Uss/StyleSlot.cs
class StyleSlot (line 5) | internal class StyleSlot : Style
method StyleSlot (line 13) | public StyleSlot(bool text, string slot, Style style)
method ToString (line 25) | public override string ToString() => $"text={Text} slot={Slot} styleTy...
FILE: Editor/Core/Uss/UssStyle.cs
class UssStyle (line 12) | internal class UssStyle : BaseUssStyle
method UssStyle (line 143) | public UssStyle(string name) : base(name) { }
method UssStyle (line 144) | public UssStyle(string name, AssetsInfo assetsInfo) : this(name) => th...
method UssStyle (line 145) | public UssStyle(string name, AssetsInfo assetsInfo, BaseNode node, Sty...
method UssStyle (line 184) | public UssStyle(string name, AssetsInfo assetsInfo, BaseNode node) : t...
method CopyFrom (line 209) | internal UssStyle CopyFrom(UssStyle style)
method AddFrame (line 214) | void AddFrame(IDefaultFrameMixin frame)
method AddGeometry (line 252) | void AddGeometry(IGeometryMixin geometry)
method AddLayout (line 276) | void AddLayout(ILayoutMixin layout)
method AddText (line 496) | void AddText(TextNode text)
method AddBlend (line 537) | void AddBlend(IBlendMixin blend)
method AddBorderRadius (line 564) | void AddBorderRadius(BaseNode node)
method AddSvg (line 584) | void AddSvg(AssetsInfo assetsInfo, BaseNode svg)
method AddSharedTextStyle (line 604) | void AddSharedTextStyle(TextNode.Style style)
method AddFill (line 665) | void AddFill(IGeometryMixin geometry)
method AddStrokeColor (line 720) | void AddStrokeColor(IGeometryMixin geometry)
method MakeTransitionStyles (line 744) | internal static List<UssStyle> MakeTransitionStyles(UssStyle root, Uss...
method LogWarningIgnoredFigmaProperty (line 773) | static void LogWarningIgnoredFigmaProperty(IBaseNodeMixin node, string...
method LogWarningImpossibleDesign (line 774) | static void LogWarningImpossibleDesign(IBaseNodeMixin node, string mes...
FILE: Editor/Core/Uss/UssWriter.cs
class UssWriter (line 12) | internal class UssWriter : IDisposable, IAsyncDisposable
method UssWriter (line 21) | public UssWriter(string rootDirectory, string path)
method Write (line 33) | public void Write(BaseUssStyle style)
method Write (line 73) | public void Write(IEnumerable<BaseUssStyle> styles) => styles.OrderBy(...
method Dispose (line 75) | void IDisposable.Dispose() => stream?.Dispose();
method DisposeAsync (line 76) | async ValueTask IAsyncDisposable.DisposeAsync()
FILE: Editor/Core/Uxml/UxmlBuilder.cs
class UxmlBuilder (line 15) | internal class UxmlBuilder
method UxmlBuilder (line 25) | public UxmlBuilder(Data data, NodeMetadata nodeMetadata, string global...
method CreateDocument (line 35) | public void CreateDocument(string directory, string fileName, Document...
method CreateFrame (line 68) | public string CreateFrame(string directory, string[] ussStyleFilesPath...
method CreateComponentSet (line 81) | public string CreateComponentSet(string directory, string[] ussStyleFi...
method CreateElement (line 90) | public string CreateElement(string directory, string[] ussStyleFilesPa...
method WriteNodesRecursively (line 104) | void WriteNodesRecursively(BaseNode node, UxmlWriter uxml, bool isComp...
method WriteStyles (line 203) | void WriteStyles(string[] styles, UxmlWriter writer) => styles.ForEach...
FILE: Editor/Core/Uxml/UxmlWriter.cs
class UxmlWriter (line 13) | internal sealed class UxmlWriter : IDisposable
method UxmlWriter (line 32) | public UxmlWriter(string directory, string fileName)
method Dispose (line 41) | public void Dispose()
method StartElement (line 46) | public void StartElement(BaseNode node, string ussClasses, (ElementTyp...
method StartElement (line 114) | public void StartElement(string type, params (string name, string valu...
method EndElement (line 121) | public void EndElement() => xmlWriter.WriteEndElement();
method WriteUssStyleReference (line 123) | public void WriteUssStyleReference(string path)
method WriteTemplate (line 128) | public void WriteTemplate(string templateName, string templatePath)
method WriteInstance (line 133) | public void WriteInstance(string instanceName, string templateName, st...
FILE: Editor/Extensions/Extensions.cs
class Extensions (line 10) | [DebuggerStepThrough]
method ToBit (line 19) | internal static int ToBit(this bool value) => value ? 1 : 0;
method IndexRedundantNames (line 21) | internal static IEnumerable<T> IndexRedundantNames<T>(this IReadOnlyLi...
method NumberToWords (line 32) | internal static string NumberToWords(this int number)
method GetAverageColor (line 79) | internal static RGBA GetAverageColor(this IEnumerable<RGBA> colors)
FILE: Editor/Extensions/NodeExtensions.cs
class NodeExtensions (line 13) | [DebuggerStepThrough]
method Flatten (line 17) | internal static IEnumerable<IBaseNodeMixin> Flatten(this IBaseNodeMixi...
method IsRootNode (line 45) | internal static bool IsRootNode(this IBaseNodeMixin node) => node is D...
method IsSvgNode (line 46) | internal static bool IsSvgNode(this IBaseNodeMixin node) => node is Li...
method IsVisible (line 48) | internal static bool IsVisible(this IBaseNodeMixin node) => (node is n...
method HasImage (line 49) | internal static bool HasImage(this IBaseNodeMixin node) => node is IGe...
method SetParent (line 51) | internal static void SetParent(this BaseNode node)
method GetHash (line 74) | internal static string GetHash(this GradientPaint gradient)
method GetFullPath (line 105) | internal static string GetFullPath(this IBaseNodeMixin node)
FILE: Editor/Extensions/UssStyleExtensions.cs
class UssStyleExtension (line 11) | static class UssStyleExtension
method HasBorder (line 16) | internal static bool HasBorder(this IGeometryMixin geometry) => geomet...
method GetBorderWidths (line 17) | internal static LayoutDouble4 GetBorderWidths(this IGeometryMixin geom...
method GetOutsideBorderWidths (line 27) | internal static LayoutDouble4 GetOutsideBorderWidths(this IGeometryMix...
method GetInsideBorderWidths (line 28) | internal static LayoutDouble4 GetInsideBorderWidths(this IGeometryMixi...
method GetContentBox (line 29) | internal static Rect GetContentBox(this ILayoutMixin layout)
method GetBorderBox (line 38) | internal static Rect GetBorderBox(this ILayoutMixin layout)
method GetCorrectedPadding (line 47) | internal static LayoutDouble4 GetCorrectedPadding(this IDefaultFrameMi...
method BlendWith (line 48) | internal static RGBA BlendWith(this RGBA foreground, RGBA background)
method AlphaCorrection (line 64) | public static double AlphaCorrection(double a) => (forceAlphaCorrectio...
method GetOutsideFraction (line 68) | static double GetOutsideFraction(this IGeometryMixin geometry) => geom...
FILE: Editor/FigmaDownloader.cs
class FigmaDownloader (line 19) | internal class FigmaDownloader : Api
method FigmaDownloader (line 41) | internal FigmaDownloader(string personalAccessToken, string fileKey, A...
method Run (line 45) | internal async Task Run(bool downloadImages, string uxmlName, IReadOnl...
method CleanUp (line 117) | internal void CleanUp(bool cleanImages = false)
method RemoveEmptyDirectories (line 146) | public void RemoveEmptyDirectories()
method DownloadDocumentsAsync (line 198) | async Task DownloadDocumentsAsync(CancellationToken token)
method GetImageFillsAsync (line 209) | async Task GetImageFillsAsync(int progress, List<IBaseNodeMixin> image...
method GetImageNodesAsync (line 222) | async Task GetImageNodesAsync(int progress, IEnumerable<IBaseNodeMixin...
method GetImageAsync (line 238) | async Task GetImageAsync(string nodeID, string url, string extension, ...
method WriteGradientsAsync (line 295) | async Task WriteGradientsAsync(CancellationToken token)
FILE: Editor/FigmaWriter.cs
class FigmaWriter (line 21) | internal sealed class FigmaWriter
method FigmaWriter (line 38) | internal FigmaWriter(string directory, string fileName, Data data, Sty...
method WriteAsync (line 52) | internal async Task WriteAsync(bool overrideGlobal = false)
method WriteFrame (line 97) | void WriteFrame(UxmlBuilder uxmlBuilder, Dictionary<string, IReadOnlyL...
method WriteComponentSet (line 158) | void WriteComponentSet(UxmlBuilder uxmlBuilder, ComponentSetNode compo...
method WriteTemplate (line 166) | void WriteTemplate(UxmlBuilder uxmlBuilder, (DefaultShapeNode element,...
FILE: Editor/Inspector/AuthTest.cs
class AuthTest (line 8) | internal class AuthTest : Api
method AuthTest (line 16) | internal AuthTest(string personalAccessToken = null) : base(personalAc...
method AuthAsync (line 20) | internal async Task AuthAsync() => me = await GetAsync<Me>(nameof(me),...
FILE: Editor/Inspector/FigmaInspector.cs
class FigmaInspector (line 26) | [CustomEditor(typeof(Figma), true)]
method Awake (line 60) | void Awake() => icon = AssetDatabase.LoadAssetAtPath<Texture2D>($"{Pac...
method OnEnable (line 61) | void OnEnable()
method OnInspectorGUI (line 75) | public override void OnInspectorGUI()
method DrawPersonalAccessTokenGUI (line 85) | void DrawPersonalAccessTokenGUI()
method DrawAssetGUI (line 137) | void DrawAssetGUI()
method DrawFramesView (line 207) | void DrawFramesView()
method DrawProperties (line 252) | void DrawProperties()
method UpdateWithProgressAsync (line 263) | static async Task UpdateWithProgressAsync(UIDocument document, Figma f...
method GetDirectoryAndRelativeDirectory (line 345) | static (string directory, string relativeDirectory, string product, st...
FILE: Editor/Inspector/Styles.cs
class Styles (line 6) | public static class Styles
FILE: Editor/Interface/Const.cs
class Const (line 3) | public static class Const
class KnownFormats (line 61) | public static class KnownFormats
FILE: Editor/Interface/Enums.cs
type Unit (line 3) | enum Unit
type Align (line 14) | enum Align
type FlexDirection (line 23) | enum FlexDirection
type FlexWrap (line 31) | enum FlexWrap
type JustifyContent (line 38) | enum JustifyContent
type Position (line 47) | enum Position
type Visibility (line 53) | enum Visibility
type OverflowClip (line 59) | enum OverflowClip
type Display (line 65) | enum Display
type FontStyle (line 71) | enum FontStyle
type TextAlign (line 79) | enum TextAlign
type EasingFunction (line 92) | enum EasingFunction
type Wrap (line 102) | enum Wrap
type ElementType (line 108) | public enum ElementType
type TimeUnit (line 190) | enum TimeUnit
type PseudoClass (line 197) | enum PseudoClass
type FontWeight (line 211) | enum FontWeight
FILE: Editor/Interface/Figma.Enums.cs
type EffectType (line 5) | public enum EffectType { INNER_SHADOW, DROP_SHADOW, LAYER_BLUR, BACKGROU...
type BlendMode (line 7) | public enum BlendMode { PASS_THROUGH, NORMAL, DARKEN, MULTIPLY, LINEAR_B...
type ConstraintVertical (line 9) | public enum ConstraintVertical { TOP, BOTTOM, CENTER, TOP_BOTTOM, SCALE }
type ConstraintHorizontal (line 11) | public enum ConstraintHorizontal { LEFT, RIGHT, CENTER, LEFT_RIGHT, SCALE }
type PaintType (line 13) | public enum PaintType { SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIEN...
type Pattern (line 15) | public enum Pattern { COLUMNS, ROWS, GRID }
type Alignment (line 17) | public enum Alignment { MIN, MAX, STRETCH, CENTER }
type ScaleMode (line 19) | public enum ScaleMode { FILL, FIT, TILE, STRETCH }
type ExportSettingsConstraintsType (line 21) | public enum ExportSettingsConstraintsType { SCALE, WIDTH, HEIGHT }
type Format (line 23) | public enum Format { JPG, PNG, SVG, PDF }
type ActionType (line 25) | public enum ActionType { BACK, CLOSE, URL, NODE }
type Navigation (line 27) | public enum Navigation { NAVIGATE, SWAP, OVERLAY, CHANGE_TO }
type TransitionType (line 29) | public enum TransitionType { DISSOLVE, SMART_ANIMATE, MOVE_IN, MOVE_OUT,...
type TransitionDirection (line 31) | public enum TransitionDirection { LEFT, RIGHT, TOP, BOTTOM }
type TriggerType (line 33) | public enum TriggerType { ON_CLICK, ON_HOVER, ON_PRESS, DRAG, AFTER_TIME...
type TriggerDevice (line 35) | public enum TriggerDevice { KEYBOARD, XBOX_ONE, PS4, SWITCH_PRO, UNKNOWN...
type EasingType (line 37) | public enum EasingType { EASE_IN, EASE_OUT, EASE_IN_AND_OUT, LINEAR, SLO...
type LayoutAlign (line 39) | public enum LayoutAlign { CENTER, MIN, MAX, STRETCH, INHERIT }
type StrokeCap (line 41) | public enum StrokeCap { NONE, ROUND, SQUARE, ARROW_LINES, ARROW_EQUILATE...
type StrokeJoin (line 43) | public enum StrokeJoin { MITER, BEVEL, ROUND }
type StrokeAlign (line 45) | public enum StrokeAlign { INSIDE, OUTSIDE, CENTER }
type LayoutMode (line 47) | public enum LayoutMode { NONE, HORIZONTAL, VERTICAL }
type PrimaryAxisSizingMode (line 49) | public enum PrimaryAxisSizingMode { AUTO, FIXED }
type CounterAxisSizingMode (line 51) | public enum CounterAxisSizingMode { AUTO, FIXED }
type PrimaryAxisAlignItems (line 53) | public enum PrimaryAxisAlignItems { MIN, CENTER, MAX, SPACE_BETWEEN }
type CounterAxisAlignItems (line 55) | public enum CounterAxisAlignItems { MIN, CENTER, MAX, BASELINE }
type OverflowDirection (line 57) | public enum OverflowDirection { NONE, HORIZONTAL_SCROLLING, VERTICAL_SCR...
type TextCase (line 59) | public enum TextCase { ORIGINAL, UPPER, LOWER, TITLE }
type TextDecoration (line 61) | public enum TextDecoration { NONE, UNDERLINE, STRIKETHROUGH }
type TextAlignHorizontal (line 63) | public enum TextAlignHorizontal { LEFT, CENTER, RIGHT, JUSTIFIED }
type TextAlignVertical (line 65) | public enum TextAlignVertical { TOP, CENTER, BOTTOM }
type TextAutoResize (line 67) | public enum TextAutoResize { NONE, WIDTH_AND_HEIGHT, HEIGHT, TRUNCATE }
type BooleanOperation (line 69) | public enum BooleanOperation { UNION, INTERSECT, SUBTRACT, EXCLUDE }
type LayoutPositioning (line 71) | public enum LayoutPositioning { AUTO, ABSOLUTE }
type StyleType (line 73) | public enum StyleType { FILL, TEXT, EFFECT, GRID, NONE }
type NodeType (line 75) | public enum NodeType { DOCUMENT, CANVAS, SLICE, FRAME, GROUP, COMPONENT_...
type ComponentPropertyType (line 77) | public enum ComponentPropertyType { BOOLEAN, TEXT, INSTANCE_SWAP, VARIANT }
type LayoutWrap (line 79) | public enum LayoutWrap { NO_WRAP, WRAP }
type MaskType (line 81) | public enum MaskType { ALPHA, VECTOR, LUMINANCE }
type LayoutSizing (line 83) | public enum LayoutSizing { FIXED, HUG, FILL }
type CounterAxisAlignContent (line 85) | public enum CounterAxisAlignContent { AUTO, SPACE_BETWEEN }
type TextTruncation (line 87) | public enum TextTruncation { DISABLED, ENDING }
type LineType (line 89) | public enum LineType { NONE, ORDERED, UNORDERED }
type TextWeight (line 91) | public enum TextWeight { BOLD, NORMAL }
type TextItalic (line 93) | public enum TextItalic { ITALIC, NORMAL }
FILE: Editor/Interface/Figma.Types.Interface.cs
type IBaseNodeMixin (line 15) | public interface IBaseNodeMixin
type ISceneNodeMixin (line 23) | public interface ISceneNodeMixin
type IChildrenMixin (line 28) | public interface IChildrenMixin
type ILayoutMixin (line 33) | public interface ILayoutMixin
type IBlendMixin (line 51) | public interface IBlendMixin
type IGeometryMixin (line 61) | public interface IGeometryMixin
type ICornerMixin (line 74) | public interface ICornerMixin
type IRectangleCornerMixin (line 79) | public interface IRectangleCornerMixin
type IExportMixin (line 84) | public interface IExportMixin
type IReactionMixin (line 89) | public interface IReactionMixin
type ITransitionMixin (line 94) | public interface ITransitionMixin
type IDefaultShapeMixin (line 101) | public interface IDefaultShapeMixin : IBaseNodeMixin, ISceneNodeMixin, I...
type IDefaultFrameMixin (line 103) | public interface IDefaultFrameMixin : IDefaultShapeMixin, ICornerMixin, ...
FILE: Editor/Interface/Figma.Types.Structs.cs
type Vector (line 3) | public struct Vector
type Rect (line 9) | public struct Rect
method Rect (line 27) | public Rect(double x, double y, double width, double height)
type RGBA (line 39) | public struct RGBA
FILE: Editor/Interface/Figma.Types.cs
class ShadowEffect (line 17) | public class ShadowEffect : Effect
class BlurEffect (line 29) | public class BlurEffect : Effect
class Effect (line 36) | public class Effect { }
class IndividualStrokeWeights (line 38) | public class IndividualStrokeWeights
class Constraints (line 46) | public class Constraints
class ColorStop (line 52) | public class ColorStop
class ImageFilter (line 58) | public class ImageFilter
class SolidPaint (line 69) | public class SolidPaint : Paint
class GradientPaint (line 76) | public class GradientPaint : Paint
class ImagePaint (line 83) | public class ImagePaint : Paint
class Paint (line 93) | public class Paint
class RowsColsLayoutGrid (line 100) | public class RowsColsLayoutGrid : LayoutGrid
class GridLayoutGrid (line 112) | public class GridLayoutGrid : LayoutGrid
class LayoutGrid (line 124) | public class LayoutGrid { }
class ExportSettingsConstraints (line 126) | public class ExportSettingsConstraints
class ExportSettingsImage (line 132) | public class ExportSettingsImage : ExportSettings
class ExportSettingsSVG (line 140) | public class ExportSettingsSVG : ExportSettings
class ExportSettingsPDF (line 151) | public class ExportSettingsPDF : ExportSettings
class ExportSettings (line 159) | public class ExportSettings { }
class Reaction (line 161) | public class Reaction
class Action (line 167) | public class Action
class SimpleTransition (line 181) | public class SimpleTransition : Transition { }
class DirectionalTransition (line 183) | public class DirectionalTransition : Transition
class Transition (line 189) | public class Transition
class Trigger (line 196) | public class Trigger
class Easing (line 206) | public class Easing
class DocumentationLink (line 212) | public class DocumentationLink
class ArcData (line 217) | public class ArcData
class FlowStartingPoint (line 224) | public class FlowStartingPoint
class ComponentPropertyReferences (line 230) | public class ComponentPropertyReferences
class DocumentNode (line 239) | public class DocumentNode : BaseNode
class CanvasNode (line 244) | public class CanvasNode : BaseNode, IChildrenMixin, IExportMixin
class FrameNode (line 258) | public class FrameNode : DefaultFrameNode { }
class GroupNode (line 260) | public class GroupNode : DefaultFrameNode { }
class SliceNode (line 262) | public class SliceNode : SceneNode, ILayoutMixin, IExportMixin
class RectangleNode (line 285) | public class RectangleNode : DefaultShapeNode, ICornerMixin, IRectangleC...
class LineNode (line 294) | public class LineNode : DefaultShapeNode { }
class EllipseNode (line 296) | public class EllipseNode : DefaultShapeNode
class RegularPolygonNode (line 301) | public class RegularPolygonNode : DefaultShapeNode, ICornerMixin, IRecta...
class StarNode (line 309) | public class StarNode : DefaultShapeNode, ICornerMixin, IRectangleCorner...
class VectorNode (line 317) | public class VectorNode : DefaultShapeNode, ICornerMixin, IRectangleCorn...
class TextNode (line 326) | public class TextNode : DefaultShapeNode
class Style (line 328) | public class Style
class ComponentSetNode (line 368) | public class ComponentSetNode : DefaultFrameNode
class ComponentNode (line 373) | public class ComponentNode : DefaultFrameNode
class ComponentPropertyDefinition (line 378) | public class ComponentPropertyDefinition
class ComponentProperties (line 387) | public class ComponentProperties : ComponentPropertyDefinition
class PreferredValue (line 392) | public class PreferredValue
class InstanceNode (line 398) | public class InstanceNode : DefaultFrameNode
class Overrides (line 407) | public class Overrides
class BooleanOperationNode (line 413) | public class BooleanOperationNode : DefaultFrameNode
class DefaultShapeNode (line 418) | public class DefaultShapeNode : SceneNode, IDefaultShapeMixin, ITransiti...
class DefaultFrameNode (line 476) | public class DefaultFrameNode : DefaultShapeNode, IDefaultFrameMixin
class BaseNode (line 504) | public class BaseNode : IBaseNodeMixin
method ToString (line 514) | public override string ToString() => name;
class SceneNode (line 517) | public class SceneNode : BaseNode, ISceneNodeMixin
class SectionNode (line 525) | public class SectionNode : DefaultFrameNode, IChildrenMixin
class Component (line 534) | public class Component
class Style (line 544) | public class Style
class Failure (line 553) | public class Failure
class Me (line 559) | public class Me : Failure
class Data (line 567) | public class Data : Failure
class Images (line 569) | public class Images
class Meta (line 571) | public class Meta
class Images (line 596) | public class Images : Failure
class Nodes (line 601) | public class Nodes : Failure
class Document (line 603) | public class Document
class Interactions (line 622) | public class Interactions
class EasingFunctionSpring (line 628) | public class EasingFunctionSpring
FILE: Editor/Interface/Interface.Records.cs
type RootMetadata (line 7) | record RootMetadata(bool filter, UxmlAttribute uxml, UxmlDownloadImages ...
type QueryMetadata (line 10) | record QueryMetadata(Type fieldType, QueryAttribute query);
type BaseNodeMetadata (line 12) | record BaseNodeMetadata(RootMetadata root, QueryMetadata query);
FILE: Runtime/AssemblyInfo.cs
class IsExternalInit (line 9) | public class IsExternalInit { }
FILE: Runtime/Core/Element.cs
class Element (line 10) | public abstract class Element : MonoBehaviour, IRootElement
method OnInitialize (line 24) | void IRootElement.OnInitialize(VisualElement root, VisualElement[] roo...
method OnRebuild (line 30) | void IRootElement.OnRebuild() => OnRebuild();
method OnInitialize (line 32) | protected virtual void OnInitialize() { }
method OnRebuild (line 33) | protected virtual void OnRebuild() { }
method Awake (line 37) | protected virtual void Awake() => className = GetType().Name;
method OnEnable (line 38) | protected virtual void OnEnable() => className = GetType().Name;
method OnDisable (line 39) | protected virtual void OnDisable() { }
FILE: Runtime/Core/QueryAttribute.cs
class QueryAttribute (line 10) | [DebuggerStepThrough]
method QueryAttribute (line 71) | public QueryAttribute(string path, string className = null)
FILE: Runtime/Core/UxmlAttribute.cs
class UxmlAttribute (line 8) | [DebuggerStepThrough]
method UxmlAttribute (line 24) | public UxmlAttribute(string root = null, UxmlDownloadImages downloadIm...
FILE: Runtime/Core/VisualElementMetadata.cs
class VisualElementMetadata (line 20) | public static class VisualElementMetadata
type Metadata (line 24) | record Metadata(UIDocument document, UxmlAttribute uxml, string path);
method Initialize (line 45) | public static void Initialize(UIDocument document, IEnumerable<IRootEl...
method Initialize (line 46) | public static void Initialize(UIDocument document, IRootElement target)
method Initialize (line 66) | public static void Initialize(ISubElement target, VisualElement target...
method Rebuild (line 74) | public static void Rebuild(IEnumerable<IRootElement> targets)
method Rebuild (line 82) | public static void Rebuild(VisualElement target)
method Search (line 95) | public static IEnumerable<T> Search<T>(this VisualElement value, strin...
method Dispose (line 164) | public static void Dispose()
method FindByPath (line 172) | public static VisualElement FindByPath(this VisualElement root, string...
method Find (line 182) | public static T Find<T>(this VisualElement value, string path, bool th...
method Find (line 202) | public static (T1, T2) Find<T1, T2>(this VisualElement value, string p...
method Find (line 203) | public static (T1, T2, T3) Find<T1, T2, T3>(this VisualElement value, ...
method Find (line 204) | public static VisualElement Find(this VisualElement value, string path...
method Clone (line 206) | public static T Clone<T>(this T value, VisualElement parent = null, in...
method Clone (line 307) | public static VisualElement Clone(this VisualElement value, VisualElem...
method Replace (line 309) | public static T Replace<T>(this VisualElement value, VisualElement pre...
method Replace (line 352) | public static VisualElement Replace(this VisualElement value, VisualEl...
method CopyStyleList (line 354) | public static void CopyStyleList(this VisualElement value, VisualEleme...
method CopyResolvedStyle (line 359) | public static void CopyResolvedStyle(this VisualElement value, VisualE...
method CopyStyle (line 468) | public static void CopyStyle(this VisualElement value, VisualElement s...
method GetItemSpacing (line 587) | public static float GetItemSpacing(this ICustomStyle style) => style.T...
method MarginMe (line 588) | public static async void MarginMe(this VisualElement value)
method GetAllElementsPaths (line 652) | public static IEnumerable<(FieldInfo field, string path)> GetAllElemen...
method FindByPathRecursive (line 678) | static VisualElement FindByPathRecursive(this VisualElement root, stri...
method FindRoot (line 727) | static VisualElement FindRoot(VisualElement value)
method FindRoot (line 743) | static (VisualElement value, string path) FindRoot(VisualElement value...
method Initialize (line 758) | static void Initialize(object target, Type targetType, VisualElement t...
FILE: Runtime/Extensions/EnumerableExtensions.cs
class EnumerableExtensions (line 9) | internal static class EnumerableExtensions
method ForEachParallelAsync (line 12) | internal static async Task ForEachParallelAsync<T>(this IEnumerable<T>...
method Chunk (line 23) | internal static IEnumerable<List<TSource>> Chunk<TSource>(this IEnumer...
FILE: Runtime/Extensions/Extensions.cs
class Extensions (line 7) | [DebuggerStepThrough]
method NullOrEmpty (line 11) | internal static bool NullOrEmpty(this string value) => string.IsNullOr...
method NotNullOrEmpty (line 12) | internal static bool NotNullOrEmpty(this string value) => !string.IsNu...
method Invalid (line 13) | internal static bool Invalid(this float value) => float.IsNaN(value) |...
method ForEach (line 14) | internal static void ForEach<T>(this IEnumerable<T> enumerable, Action...
method BuildTargetMessage (line 20) | internal static string BuildTargetMessage(string message, string targe...
method BuildTargetMessage (line 22) | internal static string BuildTargetMessage(string message, string targe...
FILE: Runtime/Extensions/PathExtensions.cs
class PathExtensions (line 8) | public static class PathExtensions
method GetFiles (line 15) | internal static string[] GetFiles(string path, string searchPattern, S...
method CombinePath (line 16) | internal static string CombinePath(params string[] paths)
method GetRelativePath (line 36) | internal static string GetRelativePath(string from, string to) => Comb...
method RemoveExtension (line 37) | internal static string RemoveExtension(string path) => CombinePath(Pat...
method IsSeparator (line 39) | internal static bool IsSeparator(this char ch) => ch == Path.Directory...
method EqualsTo (line 40) | internal static bool EqualsTo(this string path, string value, int star...
method BeginsWith (line 55) | internal static bool BeginsWith(this string path, string value, int st...
FILE: Runtime/Extensions/VisualElementExtensions.cs
class VisualElementExtensions (line 10) | public static class VisualElementExtensions
method HasVisibility (line 17) | public static bool HasVisibility(this VisualElement element) => elemen...
method MakeVisible (line 18) | public static void MakeVisible(this VisualElement element) => element....
method MakeInvisible (line 19) | public static void MakeInvisible(this VisualElement element) => elemen...
method SetVisibility (line 20) | public static void SetVisibility(this VisualElement element, bool visi...
method IsShowing (line 21) | public static bool IsShowing(this VisualElement element) => element.re...
method Show (line 22) | public static void Show(this VisualElement element)
method Hide (line 27) | public static void Hide(this VisualElement element) => element.style.d...
method SetDisplay (line 28) | public static void SetDisplay(this VisualElement element, bool visible)
method Disable (line 33) | public static void Disable(this VisualElement element) => element.pick...
method Enable (line 34) | public static void Enable(this VisualElement element) => element.picki...
method IsEnabled (line 35) | public static bool IsEnabled(this VisualElement element) => element.pi...
method EnsureList (line 36) | public static IList EnsureList<TVisualElement>(TVisualElement prefab, ...
method GetElement (line 45) | public static TVisualElement GetElement<TVisualElement>(this TVisualEl...
method GetElements (line 46) | public static List<TVisualElement> GetElements<TVisualElement>(this TV...
method GetElements (line 47) | public static List<TVisualElement> GetElements<TVisualElement>(this TV...
method GetElements (line 53) | public static List<VisualElement> GetElements(this VisualElement prefa...
method GetElements (line 54) | public static List<VisualElement> GetElements(this VisualElement prefa...
method Sync (line 55) | public static void Sync<TVisualElement, TData>(this TVisualElement pre...
method Sync (line 88) | public static void Sync<TVisualElement, TCreationData, TData>(this TVi...
method As (line 121) | public static T As<T>(this object value) => (T)value;
method GetFullPath (line 122) | public static string GetFullPath(this VisualElement element)
FILE: Runtime/Figma.cs
class Figma (line 10) | [DefaultExecutionOrder(-10)]
method OnEnable (line 28) | void OnEnable()
method OnDestroy (line 71) | void OnDestroy() => VisualElementMetadata.Dispose();
FILE: Runtime/Interface/Const.cs
class Const (line 5) | public static class Const
FILE: Runtime/Interface/Core/SubElements.cs
class SubVisualElement (line 5) | public abstract class SubVisualElement : VisualElement, ISubElement
method OnInitialize (line 8) | protected virtual void OnInitialize() { }
method OnRebuild (line 9) | protected virtual void OnRebuild() { }
method OnInitialize (line 11) | void ISubElement.OnInitialize() => OnInitialize();
method OnRebuild (line 12) | void ISubElement.OnRebuild() => OnRebuild();
class SubButton (line 16) | public abstract class SubButton : Button, ISubElement
method OnInitialize (line 19) | protected virtual void OnInitialize() { }
method OnRebuild (line 20) | protected virtual void OnRebuild() { }
method OnInitialize (line 22) | void ISubElement.OnInitialize() => OnInitialize();
method OnRebuild (line 23) | void ISubElement.OnRebuild() => OnRebuild();
class SubLabel (line 27) | public abstract class SubLabel : Label, ISubElement
method OnInitialize (line 30) | protected virtual void OnInitialize() { }
method OnRebuild (line 31) | protected virtual void OnRebuild() { }
method OnInitialize (line 33) | void ISubElement.OnInitialize() => OnInitialize();
method OnRebuild (line 34) | void ISubElement.OnRebuild() => OnRebuild();
class SubScrollView (line 38) | public abstract class SubScrollView : ScrollView, ISubElement
method OnInitialize (line 41) | protected virtual void OnInitialize() { }
method OnRebuild (line 42) | protected virtual void OnRebuild() { }
method OnInitialize (line 44) | void ISubElement.OnInitialize() => OnInitialize();
method OnRebuild (line 45) | void ISubElement.OnRebuild() => OnRebuild();
FILE: Runtime/Interface/Core/SyncElements.cs
class SyncVisualElement (line 7) | public abstract class SyncVisualElement<T> : SubVisualElement, ISyncElem...
method Sync (line 10) | public virtual void Sync(VisualElement parent, IEnumerable<T> data) =>...
method IsVisible (line 11) | public abstract bool IsVisible(int index, T data);
method Sync (line 18) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 19) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 20) | public abstract bool IsVisible(int index, TData data);
class SyncVisualElement (line 15) | public abstract class SyncVisualElement<TCreationData, TData> : SubVisua...
method Sync (line 10) | public virtual void Sync(VisualElement parent, IEnumerable<T> data) =>...
method IsVisible (line 11) | public abstract bool IsVisible(int index, T data);
method Sync (line 18) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 19) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 20) | public abstract bool IsVisible(int index, TData data);
class SyncButton (line 24) | public abstract class SyncButton<TData> : SubButton, ISyncElement<TData>
method Sync (line 27) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 28) | public abstract bool IsVisible(int index, TData data);
method Sync (line 35) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 36) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 37) | public abstract bool IsVisible(int index, TData data);
class SyncButton (line 32) | public abstract class SyncButton<TCreationData, TData> : SubButton, ISyn...
method Sync (line 27) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 28) | public abstract bool IsVisible(int index, TData data);
method Sync (line 35) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 36) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 37) | public abstract bool IsVisible(int index, TData data);
class SyncButtonSimple (line 41) | public abstract class SyncButtonSimple<TData> : SubButton, ISyncElement<...
method Sync (line 44) | public virtual void Sync(VisualElement parent, Action<int> creationDat...
method Initialize (line 45) | public virtual void Initialize(int index, Action<int> creationData) =>...
method IsVisible (line 46) | public abstract bool IsVisible(int index, TData data);
class SyncLabel (line 50) | public abstract class SyncLabel<TData> : SubLabel, ISyncElement<TData>
method Sync (line 53) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 54) | public abstract bool IsVisible(int index, TData data);
method Sync (line 61) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 62) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 63) | public abstract bool IsVisible(int index, TData data);
class SyncLabel (line 58) | public abstract class SyncLabel<TCreationData, TData> : SubLabel, ISyncE...
method Sync (line 53) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 54) | public abstract bool IsVisible(int index, TData data);
method Sync (line 61) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 62) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 63) | public abstract bool IsVisible(int index, TData data);
class SyncScrollView (line 67) | public abstract class SyncScrollView<TData> : SubScrollView, ISyncElemen...
method Sync (line 70) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 71) | public abstract bool IsVisible(int index, TData data);
method Sync (line 78) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 79) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 80) | public abstract bool IsVisible(int index, TData data);
class SyncScrollView (line 75) | public abstract class SyncScrollView<TCreationData, TData> : SubScrollVi...
method Sync (line 70) | public virtual void Sync(VisualElement parent, IEnumerable<TData> data...
method IsVisible (line 71) | public abstract bool IsVisible(int index, TData data);
method Sync (line 78) | public virtual void Sync(VisualElement parent, TCreationData creationD...
method Initialize (line 79) | public abstract void Initialize(int index, TCreationData creationData);
method IsVisible (line 80) | public abstract bool IsVisible(int index, TData data);
FILE: Runtime/Interface/Enums.cs
type UxmlDownloadImages (line 5) | [Flags]
type UxmlElementTypeIdentification (line 16) | public enum UxmlElementTypeIdentification
type ElementDownloadImage (line 22) | public enum ElementDownloadImage
type CopyStyleMask (line 29) | [Flags]
FILE: Runtime/Interface/Interface.Core.cs
type ISyncElement (line 8) | public interface ISyncElement<TData>
method Sync (line 11) | void Sync(VisualElement parent, IEnumerable<TData> data);
method Initialize (line 12) | void Initialize(int index) { }
method IsVisible (line 13) | bool IsVisible(int index, TData data);
method Cleanup (line 14) | void Cleanup() { }
method Sync (line 21) | void Sync(VisualElement parent, TCreationData creationData, IEnumerabl...
method Initialize (line 22) | void Initialize(int index, TCreationData creationData);
method IsVisible (line 23) | bool IsVisible(int index, TData data);
method Cleanup (line 24) | void Cleanup() { }
type ISyncElement (line 18) | public interface ISyncElement<TCreationData, TData>
method Sync (line 11) | void Sync(VisualElement parent, IEnumerable<TData> data);
method Initialize (line 12) | void Initialize(int index) { }
method IsVisible (line 13) | bool IsVisible(int index, TData data);
method Cleanup (line 14) | void Cleanup() { }
method Sync (line 21) | void Sync(VisualElement parent, TCreationData creationData, IEnumerabl...
method Initialize (line 22) | void Initialize(int index, TCreationData creationData);
method IsVisible (line 23) | bool IsVisible(int index, TData data);
method Cleanup (line 24) | void Cleanup() { }
FILE: Runtime/Interface/Interfaces.cs
type ISubElement (line 5) | public interface ISubElement
method OnInitialize (line 8) | void OnInitialize() { }
method OnRebuild (line 9) | void OnRebuild() { }
type IRootElement (line 13) | public interface IRootElement
method OnInitialize (line 21) | void OnInitialize(VisualElement root, VisualElement[] rootsPreserved) { }
method OnRebuild (line 22) | void OnRebuild() { }
FILE: ~Samples/Scripts/Test.cs
class Test (line 9) | [Uxml("TestPage/TestFrame", UxmlDownloadImages.Everything, UxmlElementTy...
method OnInitialize (line 31) | protected override void OnInitialize() => cloneContainer.style.flexWra...
method OnRebuild (line 32) | protected override void OnRebuild() => header.text = "Welcome to Figma...
method Clone (line 34) | void Clone()
method Remove (line 40) | void Remove()
method Sync (line 46) | void Sync()
class PerfectCircle (line 58) | public class PerfectCircle : SyncButtonSimple<int>
class UxmlFactory (line 60) | public new class UxmlFactory : UxmlFactory<PerfectCircle> { }
method IsVisible (line 63) | public override bool IsVisible(int index, int data) => true;
Condensed preview — 170 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (422K chars).
[
{
"path": ".azuredevops/pull_request_template.md",
"chars": 415,
"preview": "# ⚠️ Before you merge ⚠️\n1. 👘 Ensure that your code follows the [codestyle](https://dev.azure.com/trackman/Golf/_wiki/wi"
},
{
"path": ".gitattributes",
"chars": 3389,
"preview": "# Default\n* text=auto\n\n# Unity\n*.cs text\n*.shader text\n*.hlsl text\n*.cginc text\n\n# Unity YAML\n*.anim "
},
{
"path": ".gitignore",
"chars": 842,
"preview": "/[Ll]ibrary/\n/[Tt]emp/\n/[Ll]ogs/\n/[Oo]bj/\n/[Bb]uild/\n/[Bb]uilds/\n/[Uu]ser[Ss]ettings/\n/Assets/StreamingAssets*\n/Assets/U"
},
{
"path": "Assets/Panel Settings.asset",
"chars": 1252,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!114 &11400000\nMonoBehaviour:\n m_ObjectHideFlags: 0\n m_CorrespondingSou"
},
{
"path": "Assets/Panel Settings.asset.meta",
"chars": 189,
"preview": "fileFormatVersion: 2\nguid: f486055d8ec653edc96c3f3c38380c8f\nNativeFormatImporter:\n externalObjects: {}\n mainObjectFile"
},
{
"path": "Assets/UI Theme.tss",
"chars": 123,
"preview": "@import url(\"unity-theme://default\");\n\n@import url(\"/Packages/com.trackman.figma/Assets/UnityBase.uss\");\n\nVisualElement "
},
{
"path": "Assets/UI Theme.tss.meta",
"chars": 305,
"preview": "fileFormatVersion: 2\nguid: 999af05a3e7a25744b50c66afc0ac938\nScriptedImporter:\n internalIDToNameTable: []\n externalObje"
},
{
"path": "Assets/UnityBase.uss",
"chars": 1909,
"preview": ":root {\n --selection-color: #5890DE;\n --cursor-color: #FFFFFF;\n}\n\n.unity-base-field {\n flex-direction: row;\n mar"
},
{
"path": "Assets/UnityBase.uss.meta",
"chars": 305,
"preview": "fileFormatVersion: 2\nguid: d97716672acb0ee45bf6697e5adadcdd\nScriptedImporter:\n internalIDToNameTable: []\n externalObje"
},
{
"path": "Assets.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 7eedcbb7c4cee534cb8f55eaaa55ee65\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor/Assets/icon.png.meta",
"chars": 2589,
"preview": "fileFormatVersion: 2\nguid: c0cc7a4d45c57758c894e807bb1af36b\nTextureImporter:\n internalIDToNameTable: []\n externalObjec"
},
{
"path": "Editor/Assets.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 5b1014bd7c33f18afb1f58ad7f928370\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor/Core/Api.cs",
"chars": 1807,
"preview": "using System;\nusing System.Net.Http;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Figma\n{\n using "
},
{
"path": "Editor/Core/Api.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 3206e4d9910843d38b90ab361b9a297b\ntimeCreated: 1696830500"
},
{
"path": "Editor/Core/Assets/AssetsInfo.cs",
"chars": 3351,
"preview": "using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;"
},
{
"path": "Editor/Core/Assets/AssetsInfo.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 45f0ac71191d448fb945cd8b96c71dd0\ntimeCreated: 1733916355"
},
{
"path": "Editor/Core/Assets/CachedAssets.cs",
"chars": 1271,
"preview": "using System.Collections.Generic;\nusing System.IO;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Figm"
},
{
"path": "Editor/Core/Assets/CachedAssets.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 17a02e0c1cba42429bc345ea5794a854\ntimeCreated: 1733918400"
},
{
"path": "Editor/Core/Assets/GradientWriter.cs",
"chars": 4224,
"preview": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Xml;\nusing UnityEngine;\n\nnamespace Figm"
},
{
"path": "Editor/Core/Assets/GradientWriter.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: ec2d941c5d164f0b8887c69795bd3767\ntimeCreated: 1734429409"
},
{
"path": "Editor/Core/Assets/ImagesPostprocessor.cs",
"chars": 1176,
"preview": "using Unity.VectorGraphics.Editor;\nusing UnityEditor;\n\n#pragma warning disable S1144 // Called from Unity\n\nnamespace Fig"
},
{
"path": "Editor/Core/Assets/ImagesPostprocessor.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 830782a47c09eebd4b66c78e8b91c6a7\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Core/Assets.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 569bf8b4580a4bd792f747a7a503034c\ntimeCreated: 1733918411"
},
{
"path": "Editor/Core/JsonUtility.cs",
"chars": 9675,
"preview": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Buffers;\nusing System.IO;\nusing UnityEngi"
},
{
"path": "Editor/Core/JsonUtility.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: c03fe5a0d0b4de848ae40e0ab3bfaac6\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Core/NodeMetadata.cs",
"chars": 17631,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing UnityEditor.UIElements"
},
{
"path": "Editor/Core/NodeMetadata.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 826eb9624b2845ffafc480902c5ed5d6\ntimeCreated: 1696228041"
},
{
"path": "Editor/Core/NodesRegistry.cs",
"chars": 2200,
"preview": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace Figma.Core\n{\n using Internals;\n using Const = Cons"
},
{
"path": "Editor/Core/NodesRegistry.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: e6f8d15f8d194578ad29c8c0a4a0d2e6\ntimeCreated: 1734424985"
},
{
"path": "Editor/Core/RichText/RichTextBuilder.cs",
"chars": 6425,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing UnityEngine;\n\nnamespace Figm"
},
{
"path": "Editor/Core/RichText/RichTextBuilder.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 63d2b4dce6024b989f78957756f9f22f\ntimeCreated: 1743683644"
},
{
"path": "Editor/Core/RichText.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: b4773ce3ee3d4f9f817a7dca740b3afc\ntimeCreated: 1743683652"
},
{
"path": "Editor/Core/RootNodes.cs",
"chars": 2477,
"preview": "using System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace Figma.Core\n{\n using Internals;\n "
},
{
"path": "Editor/Core/RootNodes.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 54369dcc94564417aee21cea7980006a\ntimeCreated: 1733321003"
},
{
"path": "Editor/Core/StylesPreprocessor.cs",
"chars": 14314,
"preview": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\n\nnamespace Figma.Core\n{\n u"
},
{
"path": "Editor/Core/StylesPreprocessor.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 756f15f2e8e54ce6b41e0fdaa5aa7fe8\ntimeCreated: 1742559104"
},
{
"path": "Editor/Core/Uss/BaseUssStyle.cs",
"chars": 3827,
"preview": "using Figma.Internals;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Figma.Core.Uss\n{\n "
},
{
"path": "Editor/Core/Uss/BaseUssStyle.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 6a8ef63978cd415290c6cbe844cd7f9b\ntimeCreated: 1732193154"
},
{
"path": "Editor/Core/Uss/Properties/AssetProperty.cs",
"chars": 1679,
"preview": "using System;\n\nnamespace Figma.Core.Uss\n{\n using Internals;\n\n /// <summary>\n /// Represents an asset in a Resou"
},
{
"path": "Editor/Core/Uss/Properties/AssetProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: b1d01eee68b444c88e74da4382b53373\ntimeCreated: 1727946243"
},
{
"path": "Editor/Core/Uss/Properties/ColorProperty.cs",
"chars": 2011,
"preview": "using System;\n\nnamespace Figma.Core.Uss\n{\n using Internals;\n using Const = Const;\n\n /// <summary>\n /// Repre"
},
{
"path": "Editor/Core/Uss/Properties/ColorProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 11225bd9ebe040f49fab329a81bc3f88\ntimeCreated: 1727946232"
},
{
"path": "Editor/Core/Uss/Properties/CursorProperty.cs",
"chars": 269,
"preview": "namespace Figma.Core.Uss\n{\n internal struct CursorProperty\n {\n #region Operators\n public static impl"
},
{
"path": "Editor/Core/Uss/Properties/CursorProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 688b2f12fd56420486ab60eaa3f520c7\ntimeCreated: 1727946311"
},
{
"path": "Editor/Core/Uss/Properties/DurationProperty.cs",
"chars": 2909,
"preview": "using System;\n\nnamespace Figma.Core.Uss\n{\n /// <summary>\n /// Represents a duration value from Figma API.\n /// "
},
{
"path": "Editor/Core/Uss/Properties/DurationProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: f01b58e2e2c44e75b07f54061e244f90\ntimeCreated: 1732271697"
},
{
"path": "Editor/Core/Uss/Properties/EnumProperty.cs",
"chars": 1770,
"preview": "using System;\nusing System.Text.RegularExpressions;\n\nnamespace Figma.Core.Uss\n{\n#pragma warning disable CS0660, CS0661\n "
},
{
"path": "Editor/Core/Uss/Properties/EnumProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 911a38bb38a64ff98a53324b53da101b\ntimeCreated: 1727946257"
},
{
"path": "Editor/Core/Uss/Properties/FlexProperty.cs",
"chars": 263,
"preview": "namespace Figma.Core.Uss\n{\n internal struct FlexProperty\n {\n #region Operators\n public static implic"
},
{
"path": "Editor/Core/Uss/Properties/FlexProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: c6e36b8acd8548b0add9ddf1a37509b0\ntimeCreated: 1727946301"
},
{
"path": "Editor/Core/Uss/Properties/IntegerProperty.cs",
"chars": 1102,
"preview": "namespace Figma.Core.Uss\n{\n /// <summary>\n /// Represents a whole number.\n /// </summary>\n internal struct I"
},
{
"path": "Editor/Core/Uss/Properties/IntegerProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: a466380f063f4ec98d082d2ec7cd1f20\ntimeCreated: 1727946212"
},
{
"path": "Editor/Core/Uss/Properties/LayoutDouble4.cs",
"chars": 1962,
"preview": "using System;\n\nnamespace Figma.Core.Uss\n{\n struct LayoutDouble4\n {\n #region Fields\n public double to"
},
{
"path": "Editor/Core/Uss/Properties/LayoutDouble4.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 3c58a19efd2f4860a12c1aca6d120164\ntimeCreated: 1743523469"
},
{
"path": "Editor/Core/Uss/Properties/Length2Property.cs",
"chars": 2700,
"preview": "using System;\nusing System.Linq;\n\nnamespace Figma.Core.Uss\n{\n internal readonly struct Length2Property\n {\n "
},
{
"path": "Editor/Core/Uss/Properties/Length2Property.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: ac3787c7e7634fc9983559df65387add\ntimeCreated: 1738319788"
},
{
"path": "Editor/Core/Uss/Properties/Length4Property.cs",
"chars": 2113,
"preview": "using System;\nusing System.Linq;\n\nnamespace Figma.Core.Uss\n{\n internal readonly struct Length4Property\n {\n "
},
{
"path": "Editor/Core/Uss/Properties/Length4Property.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 22ebc27065094f06894a5301834db528\ntimeCreated: 1727946288"
},
{
"path": "Editor/Core/Uss/Properties/LengthProperty.cs",
"chars": 3110,
"preview": "using System;\n\nnamespace Figma.Core.Uss\n{\n /// <summary>\n /// Represents a distance value.\n /// </summary>\n "
},
{
"path": "Editor/Core/Uss/Properties/LengthProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 50407f2db68e4ab3ac1c3fe00a5b98f7\ntimeCreated: 1727946151"
},
{
"path": "Editor/Core/Uss/Properties/NumberProperty.cs",
"chars": 1202,
"preview": "namespace Figma.Core.Uss\n{\n /// <summary>\n /// Represents either an integer or a number with a fractional componen"
},
{
"path": "Editor/Core/Uss/Properties/NumberProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 674b330b5aea49318570f61fabe5e9cb\ntimeCreated: 1727946179"
},
{
"path": "Editor/Core/Uss/Properties/ShadowProperty.cs",
"chars": 1574,
"preview": "using System.Text.RegularExpressions;\n\nnamespace Figma.Core.Uss\n{\n internal struct ShadowProperty\n {\n stati"
},
{
"path": "Editor/Core/Uss/Properties/ShadowProperty.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: c3584d21c614453fa132bc171f4420eb\ntimeCreated: 1727946275"
},
{
"path": "Editor/Core/Uss/Properties.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 049f021dc7f44bb389f9f132ed103b7c\ntimeCreated: 1727946137"
},
{
"path": "Editor/Core/Uss/StyleSlot.cs",
"chars": 725,
"preview": "namespace Figma.Core.Uss\n{\n using Internals;\n\n internal class StyleSlot : Style\n {\n #region Fields\n "
},
{
"path": "Editor/Core/Uss/StyleSlot.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 7cb6785b010e457392b9a283f2cd0e62\ntimeCreated: 1727945310"
},
{
"path": "Editor/Core/Uss/UssStyle.cs",
"chars": 43932,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\nusing UnityEngine.UIElements;\n\nnam"
},
{
"path": "Editor/Core/Uss/UssStyle.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 8d258033e1644b1fa80fcdf1fb668783\ntimeCreated: 1727945365"
},
{
"path": "Editor/Core/Uss/UssWriter.cs",
"chars": 2637,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Thre"
},
{
"path": "Editor/Core/Uss/UssWriter.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: d732fb08b4e246c6bce62bad8551f8f8\ntimeCreated: 1727945385"
},
{
"path": "Editor/Core/Uss.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: eb2949d8c99346768cecb2a0968b2029\ntimeCreated: 1732192985"
},
{
"path": "Editor/Core/Uxml/UxmlBuilder.cs",
"chars": 10255,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityAsyncAwaitUtil;\nusing Uni"
},
{
"path": "Editor/Core/Uxml/UxmlBuilder.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 501228cf0ce84dfda7160110c165f212\ntimeCreated: 1727945409"
},
{
"path": "Editor/Core/Uxml/UxmlWriter.cs",
"chars": 5943,
"preview": "using System;\nusing System.Text;\nusing System.Xml;\nusing UnityEngine.UIElements;\n\nnamespace Figma.Core.Uxml\n{\n using "
},
{
"path": "Editor/Core/Uxml/UxmlWriter.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 32914bba2eaf4c938f1c10a15860d6fa\ntimeCreated: 1733218152"
},
{
"path": "Editor/Core/Uxml.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: b264c8b3ae0846dc87a6a96ccb5c5dbf\ntimeCreated: 1733218052"
},
{
"path": "Editor/Core.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 7101b854596dd674dad786dffc6936ab\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor/Extensions/Extensions.cs",
"chars": 3107,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n\nnamespace Figma\n{\n usin"
},
{
"path": "Editor/Extensions/Extensions.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 7130aa1fa17b4bffa5e38dc5887c8364\ntimeCreated: 1732199774"
},
{
"path": "Editor/Extensions/NodeExtensions.cs",
"chars": 4525,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing Syst"
},
{
"path": "Editor/Extensions/NodeExtensions.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: bc624b728724707428b12ccb11dd0658\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Extensions/UssStyleExtensions.cs",
"chars": 4245,
"preview": "using System;\nusing System.Linq;\n\nnamespace Figma\n{\n using Core.Uss;\n using Internals;\n using UnityEngine;\n "
},
{
"path": "Editor/Extensions/UssStyleExtensions.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: cd5b7b5e37724678a84ec7eb169a0c3d\ntimeCreated: 1744032663"
},
{
"path": "Editor/Extensions.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 15d902d3df7e2ae40a71e11e3a45e807\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor/Figma.Editor.asmdef",
"chars": 248,
"preview": "{\n \"name\": \"Figma.Editor\",\n \"rootNamespace\": \"Figma.Editor\",\n \"references\": [\n \"Unity.VectorGraphics.Edi"
},
{
"path": "Editor/Figma.Editor.asmdef.meta",
"chars": 166,
"preview": "fileFormatVersion: 2\nguid: 5eb4f7c69a0b05842a5bd445fe8970e8\nAssemblyDefinitionImporter:\n externalObjects: {}\n userData"
},
{
"path": "Editor/FigmaDownloader.cs",
"chars": 13538,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Http;\nusing System."
},
{
"path": "Editor/FigmaDownloader.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 51ab4c8a6a174660b9a8bff7530d8631\ntimeCreated: 1695908086"
},
{
"path": "Editor/FigmaWriter.cs",
"chars": 9144,
"preview": "using System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\n\n// ReSharper disabl"
},
{
"path": "Editor/FigmaWriter.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: cbfef092900681d478f7beff22ae8f28\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Inspector/AuthTest.cs",
"chars": 647,
"preview": "using System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Figma.Inspectors\n{\n using Internals;\n\n internal c"
},
{
"path": "Editor/Inspector/AuthTest.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: b2f4d6368ca84ba2860d8499592a9019\ntimeCreated: 1696830428"
},
{
"path": "Editor/Inspector/FigmaInspector.cs",
"chars": 15870,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.CodeAnalysis;\nusing "
},
{
"path": "Editor/Inspector/FigmaInspector.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 79908b73109533b4d87fced3ad4caee7\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Inspector/Styles.cs",
"chars": 887,
"preview": "using UnityEditor;\nusing UnityEngine;\n\nnamespace Figma.Inspectors\n{\n public static class Styles\n {\n interna"
},
{
"path": "Editor/Inspector/Styles.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: 54fcfd1c480a4ad290dcae61139be13f\ntimeCreated: 1739275722"
},
{
"path": "Editor/Inspector.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: ee4e1dc47f503814581a191eb139e1b8\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor/Interface/Const.cs",
"chars": 2867,
"preview": "namespace Figma.Internals\n{\n public static class Const\n {\n // Http API target\n public const string a"
},
{
"path": "Editor/Interface/Const.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: e79ce7b985a449c58c07592648c530b7\ntimeCreated: 1728029275"
},
{
"path": "Editor/Interface/Enums.cs",
"chars": 3406,
"preview": "namespace Figma\n{\n enum Unit\n {\n Default,\n None,\n Initial,\n Auto,\n Pixel,\n "
},
{
"path": "Editor/Interface/Enums.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 772df3471b2405947abf34d0b8abcf8f\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Interface/Figma.Enums.cs",
"chars": 3511,
"preview": "// ReSharper disable InconsistentNaming\n\nnamespace Figma.Internals\n{\n public enum EffectType { INNER_SHADOW, DROP_SH"
},
{
"path": "Editor/Interface/Figma.Enums.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 04cc6de496b9b534d9dbdcfae4f2353e\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Interface/Figma.Types.Interface.cs",
"chars": 3946,
"preview": "using System.Collections.Generic;\nusing Newtonsoft.Json;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable B"
},
{
"path": "Editor/Interface/Figma.Types.Interface.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: d433f8c0bc1b474487e41e90ae1ffbd3\ntimeCreated: 1728645091"
},
{
"path": "Editor/Interface/Figma.Types.Structs.cs",
"chars": 1451,
"preview": "namespace Figma.Internals\n{\n public struct Vector\n {\n public double x;\n public double y;\n }\n\n "
},
{
"path": "Editor/Interface/Figma.Types.Structs.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: a20508fa20ef43dfb924e62827afe07d\ntimeCreated: 1729243214"
},
{
"path": "Editor/Interface/Figma.Types.cs",
"chars": 18391,
"preview": "using System;\nusing System.Collections.Generic;\n\n// ReSharper disable InconsistentNaming\n// ReSharper disable BuiltInTy"
},
{
"path": "Editor/Interface/Figma.Types.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: f5f4947df342cf540b908c2dd2e2a2ee\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Editor/Interface/Interface.Records.cs",
"chars": 352,
"preview": "using System;\n\nnamespace Figma\n{\n using Attributes;\n\n record RootMetadata(bool filter, UxmlAttribute uxml, UxmlDow"
},
{
"path": "Editor/Interface/Interface.Records.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: a02ced439c1547dea0ba054f881f0892\ntimeCreated: 1727941971"
},
{
"path": "Editor/Interface.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 9d9c7aa8bf559004a898cba5d982b661\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Editor.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 047c80ffe3f35194089fa29faafd00ff\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "License.md",
"chars": 10330,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "License.md.meta",
"chars": 158,
"preview": "fileFormatVersion: 2\nguid: fdd2e558d847d528a87531ad64ba1e48\nTextScriptImporter:\n externalObjects: {}\n userData: \n ass"
},
{
"path": "Prefabs/Figma.prefab",
"chars": 1950,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!1 &2916098490094507199\nGameObject:\n m_ObjectHideFlags: 0\n m_Correspond"
},
{
"path": "Prefabs/Figma.prefab.meta",
"chars": 154,
"preview": "fileFormatVersion: 2\nguid: a1decc1df2e53b24285e24bfd721a22c\nPrefabImporter:\n externalObjects: {}\n userData: \n assetBu"
},
{
"path": "Prefabs.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: c4567610e8b246a43ac8ab4dce22b73b\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Readme.md",
"chars": 21075,
"preview": "> [!WARNING]\n> **Experimental Release**: This plugin is currently in an experimental phase and is provided \"as is\" witho"
},
{
"path": "Readme.md.meta",
"chars": 158,
"preview": "fileFormatVersion: 2\nguid: 97c5af11bb3cfa4c4952aab609afcd17\nTextScriptImporter:\n externalObjects: {}\n userData: \n ass"
},
{
"path": "Runtime/AssemblyInfo.cs",
"chars": 200,
"preview": "#pragma warning disable S2094\n\nusing System.Runtime.CompilerServices;\n\n[assembly: InternalsVisibleTo(\"Figma.Editor\")]\n\nn"
},
{
"path": "Runtime/AssemblyInfo.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: d02acb23f49d34ad996232782b6f0270\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Core/Element.cs",
"chars": 1236,
"preview": "using UnityEngine;\nusing UnityEngine.UIElements;\n\n// ReSharper disable MemberCanBeProtected.Global\n\nnamespace Figma\n{\n "
},
{
"path": "Runtime/Core/Element.cs.meta",
"chars": 286,
"preview": "fileFormatVersion: 2\nguid: c3d7de8bb8ca66b41a2a58e3c87acd68\ntimeCreated: 1524533501\nlicenseType: Store\nMonoImporter:\n e"
},
{
"path": "Runtime/Core/QueryAttribute.cs",
"chars": 3315,
"preview": "using System;\nusing System.Diagnostics;\nusing UnityEngine.UIElements;\n\n// ReSharper disable UnusedAutoPropertyAccessor."
},
{
"path": "Runtime/Core/QueryAttribute.cs.meta",
"chars": 286,
"preview": "fileFormatVersion: 2\nguid: ba43ed1a94fbe41469ea9d6f2b01ca1b\ntimeCreated: 1512009160\nlicenseType: Store\nMonoImporter:\n e"
},
{
"path": "Runtime/Core/UxmlAttribute.cs",
"chars": 1346,
"preview": "using System;\nusing System.Diagnostics;\n\nnamespace Figma.Attributes\n{\n using static Internals.PathExtensions;\n\n [D"
},
{
"path": "Runtime/Core/UxmlAttribute.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: c1215fc5876343f49f128b37e1181924\ntimeCreated: 1728307231"
},
{
"path": "Runtime/Core/VisualElementMetadata.cs",
"chars": 60747,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing Unity"
},
{
"path": "Runtime/Core/VisualElementMetadata.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 46d8035533165cc498ba4642614403d3\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Core.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: a2887f4413b54672bad1ba5d2c6d7350\ntimeCreated: 1728307245"
},
{
"path": "Runtime/Extensions/EnumerableExtensions.cs",
"chars": 1352,
"preview": "using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Collections.Generic;"
},
{
"path": "Runtime/Extensions/EnumerableExtensions.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: a0dc8b85c82ec86fa8aa435da7d2c758\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Extensions/Extensions.cs",
"chars": 1115,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\n\nnamespace Figma.Internals\n{\n [DebuggerStep"
},
{
"path": "Runtime/Extensions/Extensions.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: f333cb303f7c42e589d3a706dade2e0a\ntimeCreated: 1727960585"
},
{
"path": "Runtime/Extensions/PathExtensions.cs",
"chars": 2836,
"preview": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\nnamespace Figma.Internals\n{\n public static clas"
},
{
"path": "Runtime/Extensions/PathExtensions.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 7967c428b3ee1604e8b5050a79c3278a\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Extensions/VisualElementExtensions.cs",
"chars": 6518,
"preview": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine.UIElements;\n\nnamespace Figma"
},
{
"path": "Runtime/Extensions/VisualElementExtensions.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 84fecb8572fb586409235bea58b5d37e\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Extensions.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 5919892104fee434aa143c8b3a125a90\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Runtime/Figma.asmdef",
"chars": 105,
"preview": "{\n \"name\": \"Figma\",\n \"rootNamespace\": \"Figma\",\n \"references\": [\n \"AsyncAwaitUtil\"\n ]\n}"
},
{
"path": "Runtime/Figma.asmdef.meta",
"chars": 166,
"preview": "fileFormatVersion: 2\nguid: 8b8c60060cf03964dbd41b7237ae33c9\nAssemblyDefinitionImporter:\n externalObjects: {}\n userData"
},
{
"path": "Runtime/Figma.cs",
"chars": 2441,
"preview": "using System.Linq;\nusing UnityEngine;\nusing UnityEngine.UIElements;\n\nnamespace Figma\n{\n using Attributes;\n using "
},
{
"path": "Runtime/Figma.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: aaa4e5d0dd7bf25488b120aa854832eb\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface/Const.cs",
"chars": 495,
"preview": "using System.Globalization;\n\nnamespace Figma\n{\n public static class Const\n {\n public const int maximumAllow"
},
{
"path": "Runtime/Interface/Const.cs.meta",
"chars": 83,
"preview": "fileFormatVersion: 2\nguid: b406df7817a64f298f19ebf7facbbdb8\ntimeCreated: 1747643661"
},
{
"path": "Runtime/Interface/Core/SubElements.cs",
"chars": 1365,
"preview": "using UnityEngine.UIElements;\n\nnamespace Figma\n{\n public abstract class SubVisualElement : VisualElement, ISubElement"
},
{
"path": "Runtime/Interface/Core/SubElements.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 99f85b01fae873ffdac3884951113a85\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface/Core/SyncElements.cs",
"chars": 3866,
"preview": "using System;\nusing System.Collections.Generic;\nusing UnityEngine.UIElements;\n\nnamespace Figma\n{\n public abstract cla"
},
{
"path": "Runtime/Interface/Core/SyncElements.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: fd496d4ec1c37d7af931d627ebf86023\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface/Core.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 4f9a8b3c90b78d644a304baf92e4c76d\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Runtime/Interface/Enums.cs",
"chars": 878,
"preview": "using System;\n\nnamespace Figma\n{\n [Flags]\n public enum UxmlDownloadImages\n {\n Everything = 0,\n N"
},
{
"path": "Runtime/Interface/Enums.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 801e83821cb9e5f408837586af0e8d8f\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface/Interface.Core.cs",
"chars": 780,
"preview": "using System.Collections.Generic;\nusing UnityEngine.UIElements;\n\n#pragma warning disable S1186 // Functions and closures"
},
{
"path": "Runtime/Interface/Interface.Core.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 0162e75c60e15fd4a9bd4da8ac0c62ed\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface/Interfaces.cs",
"chars": 644,
"preview": "using UnityEngine.UIElements;\n\nnamespace Figma\n{\n public interface ISubElement\n {\n #region Methods\n "
},
{
"path": "Runtime/Interface/Interfaces.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: e01966bb91b67f341809945497f0ff2c\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "Runtime/Interface.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 1f0b9b39faba9904dbefcb7c550f313d\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "Runtime.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: 70ee33d9a3494344ab4d51378a9f394f\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "package.json",
"chars": 463,
"preview": "{\n \"name\": \"com.trackman.figma\",\n \"description\": \"Figma to Unity uxml/uss converter, utilities for VisualTree manageme"
},
{
"path": "package.json.meta",
"chars": 158,
"preview": "fileFormatVersion: 2\nguid: 8054faacce927e54296a8be216631c8e\nTextScriptImporter:\n externalObjects: {}\n userData: \n ass"
},
{
"path": "~Samples/Scripts/Figma.Samples.asmdef",
"chars": 367,
"preview": "{\n \"name\": \"Figma.Samples\",\n \"rootNamespace\": \"\",\n \"references\": [\n \"Figma\"\n ],\n \"includePlatforms"
},
{
"path": "~Samples/Scripts/Figma.Samples.asmdef.meta",
"chars": 166,
"preview": "fileFormatVersion: 2\nguid: 40458b32386acba81b5009a08b0c7d40\nAssemblyDefinitionImporter:\n externalObjects: {}\n userData"
},
{
"path": "~Samples/Scripts/Test.cs",
"chars": 2205,
"preview": "using System.Linq;\nusing UnityEngine.UIElements;\nusing Random = UnityEngine.Random;\n\nnamespace Figma.Samples\n{\n using"
},
{
"path": "~Samples/Scripts/Test.cs.meta",
"chars": 243,
"preview": "fileFormatVersion: 2\nguid: 51bc2941ace5c496fbf512e17e9a1939\nMonoImporter:\n externalObjects: {}\n serializedVersion: 2\n "
},
{
"path": "~Samples/Scripts.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: a8bf1e60512441341bdf13c14f151aef\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
},
{
"path": "~Samples/Test.unity",
"chars": 9557,
"preview": "%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!29 &1\nOcclusionCullingSettings:\n m_ObjectHideFlags: 0\n serializedVersi"
},
{
"path": "~Samples/Test.unity.meta",
"chars": 155,
"preview": "fileFormatVersion: 2\nguid: 37c53d635728f3fe3aa97b1d07aa4a2a\nDefaultImporter:\n externalObjects: {}\n userData: \n assetB"
},
{
"path": "~Samples.meta",
"chars": 172,
"preview": "fileFormatVersion: 2\nguid: f562b0f5dfae4abab3176961a5070e1f\nfolderAsset: yes\nDefaultImporter:\n externalObjects: {}\n us"
}
]
About this extraction
This page contains the full source code of the TrackMan/Unity.Package.FigmaToUnity GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 170 files (390.7 KB), approximately 89.5k tokens, and a symbol index with 564 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.