# Posicionamento da UI

Para todos os tipos de conteúdo de UI, use o `uiTransform` componente para definir o tamanho, posição e outras propriedades relacionadas ao alinhamento da entidade.

O `uiTransform` componente funciona no espaço 2D da tela muito parecido com o `Transform` componente funciona no espaço 3D da cena.

***arquivo ui.tsx:***

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: '200px',
			height: '100px',
			justifyContent: 'center',
			alignItems: 'center',
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

{% hint style="warning" %}
**📔 Nota**: Todos os trechos a seguir nesta página presumem que você tem um `.ts` similar ao acima, executando a `ReactEcsRenderer.setUiRenderer()` função.
{% endhint %}

## Propriedades de posicionamento

O alinhamento das entidades de UI é baseado no modelo de alinhamento Flexbox. Este é um modelo muito poderoso para organizar dinamicamente entidades aninhadas dentro de modais que podem variar de tamanho.

{% hint style="info" %}
**💡 Tip**: A implementação de UI do Decentraland é baseada na de [Yoga](https://yogalayout.com/docs/). Leia [este artigo](https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/) para uma cobertura acessível e aprofundada das propriedades disponíveis no Flexbox.
{% endhint %}

### Tamanho da entidade

Use `width` e `height` para definir o tamanho da entidade. Os seguintes tipos de valores são suportados:

* `auto`: O tamanho se adapta para caber no conteúdo interno. Isso é muito conveniente para texto que pode variar em comprimento. Escreva o valor como "auto".
* **Porcentagem**: Como uma porcentagem das medidas do pai. Escreva o valor como uma string que termina em "%", por exemplo `10 %`.
* **Pixels**: Escreva o valor como um número.
* **Largura ou altura da tela**: Use vw (view width) e vh (view height) para indicar uma fração do tamanho total da janela onde o Decentraland está sendo executado. Por exemplo `10vw` refere-se a 10% da largura da janela, `25vh` a 25% da altura da janela.

Observe que essas propriedades afetam o **default** tamanho desse item, o tamanho do item antes de quaisquer cálculos de flex grow e flex shrink serem realizados. O tamanho final pode ser interpretado de forma diferente com base no tamanho da entidade pai e nas propriedades do Flexbox que estão definidas.

{% hint style="warning" %}
**📔 Nota**: Em propriedades que suportam tanto números quanto strings, para definir o valor em pixels, escreva um número. Para definir esses campos como uma porcentagem das medidas do pai, escreva o valor como uma string que termina em "%", por exemplo `10 %`. Você também pode definir um valor em pixels como uma string terminando em `px`, por exemplo `200px`.

* Quando os valores são expressos como porcentagem, eles estão sempre em relação ao contêiner pai. Se a entidade não tiver pais, então o valor é uma porcentagem da tela inteira.
* Se os valores forem expressos em pixels, eles são absolutos e não são afetados pela escala do pai.
* Se os valores forem expressos em `vh` ou `vw`, eles são uma porcentagem da janela inteira, não afetados pela escala do pai.

Para o `auto` Para width/height funcionarem, as seguintes regras se aplicam:

* O UiTransform que usa width/height como “auto” deve ter `alignSelf`: `“center”`/`“flex-start”`/`“flex-end”` OU `positionType: “absolute”`
* Se o UiTransform de um filho usar `positionType: “absolute”`, o pai não se adaptará ao seu tamanho/posição
* Se o UiTransform de um filho usar qualquer sobrescrita de posição, o pai não se adaptará ao seu tamanho/posição
  {% endhint %}

Estas outras propriedades também estão disponíveis para ajustar o tamanho de forma mais avançada:

* `maxWidth` e `maxHeight`: *maxDistance* ou string (como height e width). O tamanho máximo que a entidade pode ter.
* `minWidth` e `minHeight`: *maxDistance* ou string (como height e width). O tamanho mínimo que a entidade pode ter. Se o pai for muito pequeno para caber o tamanho mínimo das entidades, elas irão transbordar do seu pai.
* `flexBasis`: Esta é uma forma independente de eixo de fornecer o tamanho padrão de um item ao longo do eixo principal. Definir o flex basis de um filho é semelhante a definir a largura desse filho se seu pai for um contêiner com flex direction: row ou definir a altura de um filho se seu pai for um contêiner com flex direction: column.

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			alignSelf: 'center',
			alignContent: 'center',
			width: '80%',
			height: '30%',
			minWidth: 300,
			maxWidth: 2500,
			margin: { left: '10%', right: '10%' },
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

### Organizando entidades filhas

Por padrão, as entidades filhas são posicionadas em relação ao canto superior esquerdo de seu pai. Você pode usar propriedades como `justifyContent` e `alignItems` para alterar esse comportamento.

{% hint style="info" %}
**💡 Tip**: Qualquer propriedade que se refira a *content* refere-se a entidades ao longo do eixo principal (determinado por `flexDirection`). Qualquer propriedade que se refira
{% endhint %}

* `flexDirection`: Flex direction controla a direção na qual os filhos de um nó são dispostos. Isso também é referido como o eixo principal. O eixo principal é a direção na qual os filhos são dispostos. O eixo cruzado é o eixo perpendicular ao eixo principal, ou o eixo no qual as linhas de quebra são dispostas. Ele obtém seu valor do `FlexDirectionType` type. As seguintes opções estão disponíveis:
  * `row` (PADRÃO)
  * `row-reverse`
  * `column`
  * `column-reverse`
* `justifyContent`: Esta propriedade descreve como alinhar os filhos dentro do eixo principal do seu contêiner. Por exemplo, você pode usar esta propriedade para centralizar um filho horizontalmente dentro de um contêiner com `flexDirection` definido como row ou verticalmente dentro de um contêiner com `flexDirection` definido como column. O valor desta propriedade deve ser do `AlignType` type. Valores possíveis são:
  * `flex-start` (PADRÃO): Alinha os filhos de um contêiner ao início do eixo principal do contêiner.
  * `flex-end`: Alinha os filhos de um contêiner ao fim do eixo principal do contêiner.
  * `center`: Alinha os filhos de um contêiner no centro do eixo principal do contêiner.
  * `space-between`: Distribui os filhos de forma uniforme ao longo do eixo principal do contêiner, distribuindo o espaço restante entre os filhos.
  * `space-around`: Distribui os filhos de forma uniforme ao longo do eixo principal do contêiner, distribuindo o espaço restante ao redor dos filhos. Comparado ao space-between, usar space-around resultará em espaço sendo distribuído no início do primeiro filho e no final do último filho.
* `alignItems`: Descreve como alinhar os filhos ao longo do eixo cruzado do seu contêiner. Align items é muito similar a justify content, mas em vez de aplicar ao eixo principal, align items aplica-se ao eixo cruzado. Esta propriedade requer um valor do `AlignType` type. As seguintes opções estão disponíveis:
  * `stretch`: (PADRÃO) Estica os filhos de um contêiner para corresponder à altura do eixo cruzado do contêiner.
  * `flex-start`: Alinha os filhos de um contêiner ao início do eixo cruzado do contêiner.
  * `flex-end`: Alinha os filhos de um contêiner ao fim do eixo cruzado do contêiner.
  * `center`: Alinha os filhos de um contêiner no centro do eixo cruzado do contêiner.
  * `baseline`: Alinha os filhos de um contêiner ao longo de uma linha de base comum. Filhos individuais podem ser definidos como a linha de base de referência para seus pais.
* `alignSelf`: Align self tem as mesmas opções e efeito que `alignItems` mas em vez de afetar os filhos dentro de um contêiner, você pode aplicar esta propriedade a um único filho para alterar seu alinhamento dentro do pai. align self substitui qualquer opção definida pelo pai com align items. Ele obtém seu valor de `AlignType`, veja `alignItems` acima para detalhes sobre essas opções.
* `alignContent`: Align content define a distribuição das linhas ao longo do eixo cruzado. Isto só tem efeito quando os itens são quebrados em várias linhas usando `flexWrap`. Ele obtém seu valor do `AlignType` type. As seguintes opções estão disponíveis:
  * `flex-start`: (PADRÃO) Alinha as linhas quebradas ao início do eixo cruzado do contêiner.
  * `flex-end`: Alinha as linhas quebradas ao fim do eixo cruzado do contêiner.
  * `stretch`: Estica as linhas quebradas para corresponder à altura do eixo cruzado do contêiner.
  * `center`: Alinha as linhas quebradas no centro do eixo cruzado do contêiner.
  * `space-between`: Distribui uniformemente as linhas quebradas ao longo do eixo principal do contêiner, distribuindo o espaço restante entre as linhas.
  * `space-around`: Distribui uniformemente as linhas quebradas ao longo do eixo principal do contêiner, distribuindo o espaço restante ao redor das linhas. Comparado ao space-between, usar space-around resultará em espaço sendo distribuído no início das primeiras linhas e no final da última linha.
* `flexGrow`: Isso descreve como qualquer espaço dentro de um contêiner deve ser distribuído entre seus filhos ao longo do eixo principal. Depois de posicionar seus filhos, um contêiner distribuirá qualquer espaço restante de acordo com os valores de flex grow especificados por seus filhos. Flex grow aceita qualquer valor float >= 0, com 0 sendo o valor padrão. Um contêiner distribuirá qualquer espaço restante entre seus filhos ponderado pelo valor de flex grow do filho.
* `flexShrink`: Descreve como reduzir (shrink) os filhos ao longo do eixo principal no caso de o tamanho total dos filhos exceder o tamanho do contêiner no eixo principal. flex shrink é muito similar ao flex grow e pode ser pensado da mesma forma se qualquer tamanho excedente for considerado espaço restante negativo. Essas duas propriedades também funcionam bem em conjunto permitindo que os filhos cresçam e encolham conforme necessário. Flex shrink aceita qualquer valor float >= 0, com 1 sendo o valor padrão. Um contêiner encolherá seus filhos ponderado pelo valor de flex shrink do filho.
* `overflow`: Determina o que acontece se o tamanho dos filhos de uma entidade exceder seu pai. Ele usa valores do `OverflowType` Entity
  * `hidden`: Entidades que excedem ficam invisíveis.
  * `visible`: Entidades que excedem saem das margens do pai.
* `flexWrap`: A propriedade flex wrap é definida em contêineres e controla o que acontece quando os filhos excedem o tamanho do contêiner ao longo do eixo principal. Por padrão, os filhos são forçados a uma única linha (o que pode encolher entidades). Se o wrapping for permitido, os itens serão quebrados em várias linhas ao longo do eixo principal, se necessário. wrap-reverse se comporta da mesma forma, mas a ordem das linhas é invertida. Esta propriedade obtém seu valor de `FlexWrapType` Entity
  * `wrap`
  * `no-wrap`
  * `wrap-reverse`

### Margens e padding

* `margin`: Esta propriedade afeta o espaçamento ao redor fora de um nó. Um nó com margin se deslocará em relação aos limites do seu pai, mas também deslocará a localização de quaisquer irmãos. A margem de um nó contribui para o tamanho total de seu pai se o pai tiver tamanho automático. Define o espaçamento entre a entidade e as margens do pai. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`, e `right`.
* `padding`: Esta propriedade afeta o tamanho do nó ao qual é aplicada. Padding em Yoga age como se box-sizing: border-box; estivesse definido. Ou seja, padding não aumentará o tamanho total de uma entidade se ela tiver um tamanho explícito definido. Para nós com tamanho automático, padding aumentará o tamanho do nó e também deslocará a localização de quaisquer filhos. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`, e `right`.

### Ajustar posição finamente

No Flexbox, as posições das entidades são majoritariamente determinadas por como elas são parentadas e quais propriedades de arranjo estão definidas no pai e no filho. Frequentemente você nem precisa definir a propriedade `position` de todo. Mas se você quiser ajustar isso, ou sobrescrever completamente o fluxo normal do Flexbox e definir uma posição absoluta, aqui estão as propriedades relevantes:

* `positionType`: Define como as entidades são posicionadas. Usa um valor do `PositionType` enum.
  * `relative`: (PADRÃO) Por padrão uma entidade é posicionada relativamente. Isso significa que a entidade é posicionada de acordo com o fluxo normal do layout e então deslocada relativamente a essa posição com base nos valores de `top`, `right`, `bottom`, e `left`. O deslocamento não afeta a posição de quaisquer entidades irmãs ou pais.
  * `absolute`: Quando posicionada absolutamente, uma entidade não participa do fluxo normal do layout. Ela é, em vez disso, posicionada independentemente de seus irmãos. A posição é determinada com base no `top`, `right`, `bottom`, e `left` valores
* `position`: Os valores de posição `top`, `right`, `bottom`, e `left` se comportam de forma diferente dependendo do `positionType`. Para uma entidade relativa eles deslocam a posição da entidade na direção especificada. Para uma entidade absoluta, entretanto, essas propriedades especificam o deslocamento do lado da entidade em relação ao mesmo lado no pai. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`, e `right`.

{% hint style="warning" %}
**📔 Nota** : Ao medir a partir do topo, os números para `position` devem ser negativos. Exemplo: para posicionar um componente deixando uma margem de 20 pixels em relação ao pai nas bordas superior e esquerda, defina `position` para 20, -20.
{% endhint %}

### Visibility

* `display`: Determina se uma entidade está visível ou não. Para tornar uma entidade invisível, defina `display` para `none`.

### Z Index

O `zIndex` propriedade de um `UiEntity` determina a ordem na qual as entidades são renderizadas. Entidades com um `zIndex` mais alto são renderizadas acima de entidades com um `zIndex`. O `zIndex` padrão é 0.

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			zIndex: 4
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

{% hint style="warning" %}
**📔 Nota** : O `zIndex` a propriedade somente ordenará elementos relativos a irmãos diretos, não pode ser usada para renderizar uma entidade acima de outras partes da árvore de layout. Em termos de html/CSS, cada elemento de UI do DCL cria um novo [contexto de empilhamento](https://web.dev/learn/css/z-index#stacking_context).

A UI padrão do Decentraland, incluindo o mapa, chat, etc., é sempre renderizada acima de todos os outros elementos de UI.
{% endhint %}

## Tamanho de UI responsiva

Jogadores com diferentes tamanhos de tela podem ver seu layout de UI de forma diferente. Se você definir o tamanho de qualquer elemento de UI para um número fixo de pixels, essa UI pode ficar pequena demais para leitura em displays retina, que têm uma densidade de pixels muito maior.

Em vez de posicionar e dimensionar elementos de UI em termos de porcentagens da tela, você também pode obter as dimensões do canvas e então calcular as posições e tamanhos absolutos seguindo sua própria lógica personalizada. Por exemplo, você poderia escolher arranjos de diálogo diferentes dependendo do tamanho da tela.

Para obter informações sobre a dimensão da tela, você pode checar o `UiCanvasInformation`, que é adicionado por padrão à entidade raiz da cena.

O `UiCanvasInformation` o componente contém as seguintes informações:

* `height`: Altura do canvas em pixels
* `width`: Largura do canvas em pixels
* `devicePixelRatio`: A razão da resolução em pixels físicos do dispositivo em relação aos pixels no canvas
* `interactableArea`: Um `BorderRect` objeto, detalhando a área designada para os elementos de UI da cena. Este objeto contém valores para `top`, `bottom`, `left` e `right`, cada um desses é o número de pixels nessa margem da tela que são ocupados pela UI do Explorer.

{% hint style="warning" %}
**📔 Nota** : Diferentes Explorers do Decentraland terão valores diferentes para estes, já que as UIs globais da plataforma podem diferir, e os valores podem mudar dinamicamente conforme o usuário expande ou oculta diferentes menus de UI globais.
{% endhint %}

```ts
export function Main(){
  let canvas = UiCanvasInformation.get(engine.RootEntity)
	console.log("CANVAS DIMENSIONS: ", canvas.width, canvas.height)
})
```

O trecho a seguir calcula continuamente um valor multiplicador baseado no tamanho da tela:

```ts
import { engine, UiCanvasInformation } from "@dcl/sdk/ecs"

let timer = 0
let canvasInfoTimer = 0.5
export let scaleFactor = 1

export function UIScaleUpdate() {

  // checar raios
    timer += dt

    if (timer <= canvasInfoTimer) return
    timer = 0

    const uiCanvasInfo = UiCanvasInformation.getOrNull(engine.RootEntity)

    if (!uiCanvasInfo) return

    const newScaleFactor = Math.min(uiCanvasInfo.width / 1920, uiCanvasInfo.height / 1080)

    if (newScaleFactor !== scaleFactor) {
      scaleFactor = newScaleFactor
      console.log('NEW UI scaleFactor: ', scaleFactor)
    }
  })
}
```

O valor do `scaleFactor` variável, que esta função atualiza, pode então ser usado como multiplicador em qualquer elemento de UI na cena, incluindo `heigh`, `width` e `fontSize` valores

```ts
import { UiEntity, Label, ReactEcs } from '@dcl/sdk/react-ecs'
import { scaleFactor } from './calculate-scale-factor'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: 200 * scaleFactor,
			height: 100 * scaleFactor,
			justifyContent: 'center',
			alignItems: 'center',
			padding: 4 * scaleFactor
		}}
		uiBackground={{ color: Color4.Green() }}
	>
	  	<Label
		        value={description}
		        fontSize={18 * scaleFactor}
		        textAlign="middle-center"
		        uiTransform={{
		          width: "auto",
		          height: "auto",
		          alignSelf: "center",
		          margin: { top: 10 * scaleFactor, bottom: 10 * scaleFactor },
		        }}
	      />
	</UiEntity>
)
```

Algumas outras melhores práticas relacionadas a tamanhos de UI:

* Se a largura ou altura de qualquer elemento de UI for dinâmica, é bom também usar os `maxWidth`, `minWidth`, `maxHeight`, e `minHeight` parâmetros para garantir que eles fiquem dentro de valores razoáveis.
* O tamanho da fonte do texto é relativo a um número fixo de pixels; você deve torná-lo dinâmico para que permaneça legível em displays retina. Veja [Tamanho de texto responsivo](https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/ui_text#responsive-text-size)
