@wrrdev/fenix-ui 1.1.7 → 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,8 +18,8 @@ import { FenixUI } from '@wrrdev/fenix-ui'; // API de tema/tokens (índice)
18
18
  FenixUI.theme('dark');
19
19
  ```
20
20
 
21
- > 📦 npm: [`@wrrdev/fenix-ui`](https://www.npmjs.com/package/@wrrdev/fenix-ui) — **v1.1.7**, acesso público.
22
- > Subpaths disponíveis: `./theme`, `./tokens`, `./jsx`, `./vue`, `./button`, `./badge`, `./spinner`, `./select`, `./input`, `./switch`, `./textarea`, `./checkbox`, `./radio`, `./calendar`, `./datepicker`, `./multiselect`, `./table`, `./floatlabel`, `./dialog`, `./toast`, `./tooltip`, `./tabs`, `./progress`, `./skeleton`, `./alert`, `./drawer`, `./dropdown`, `./sidebar`, `./pagination`, `./autocomplete`, `./auto-import` e o curinga `./components/*`.
21
+ > 📦 npm: [`@wrrdev/fenix-ui`](https://www.npmjs.com/package/@wrrdev/fenix-ui) — **v1.1.8**, acesso público.
22
+ > Subpaths disponíveis: `./theme`, `./tokens`, `./jsx`, `./vue`, `./react`, `./button`, `./badge`, `./spinner`, `./select`, `./input`, `./switch`, `./textarea`, `./checkbox`, `./radio`, `./calendar`, `./datepicker`, `./multiselect`, `./table`, `./floatlabel`, `./dialog`, `./toast`, `./tooltip`, `./tabs`, `./progress`, `./skeleton`, `./alert`, `./drawer`, `./dropdown`, `./icon`, `./icons`, `./pagination`, `./autocomplete`, `./knob`, `./orderlist`, `./picklist`, `./auto-import` e o curinga `./components/*`.
23
23
 
24
24
 
25
25
  ## Consumo
@@ -65,7 +65,7 @@ Carregue o bundle **UMD** único: ele registra todos os componentes e expõe os
65
65
  <fx-toast></fx-toast>
66
66
 
67
67
  <!--
68
- 🔗 Links diretos para CDN (versão 1.1.7):
68
+ 🔗 Links diretos para CDN (versão 1.1.8):
69
69
  • https://cdn.jsdelivr.net/npm/@wrrdev/fenix-ui@latest/dist/fenix-ui.umd.min.js
70
70
  • https://unpkg.com/@wrrdev/fenix-ui@latest/dist/fenix-ui.umd.min.js
71
71
  -->
@@ -77,6 +77,14 @@ Cansado de importar componente por componente? O plugin `FenixAutoImport` percor
77
77
  (`.ts`, `.js`, `.tsx`, `.jsx`, `.vue`, `.html`, `.svelte`) em busca de tags `fx-*` conhecidas e injeta
78
78
  o `import` do subpath de cada componente **automaticamente** — mantendo o tree-shaking: só entra no
79
79
  bundle o que é usado, e ele não duplica imports já existentes.
80
+ - **Vue / Svelte (SFC):** o import entra **dentro do `<script>`** — com CRLF (Windows) e mesmo em
81
+ arquivos que só têm `<template>` (o plugin cria o bloco `<script>`).
82
+ - **Vue:** nos arquivos `.vue` o plugin injeta também `import '@wrrdev/fenix-ui/vue'`, a augmentação
83
+ que habilita autocomplete/validação dos atributos `fx-*` no Volar/vue-tsc — sem passo manual no
84
+ `main.ts` (desligue com `FenixAutoImport({ vueTypes: false })`).
85
+ - **Ícones:** `<fx-icon name="home" />` injeta `@wrrdev/fenix-ui/icon` (componente com `name` tipado
86
+ e `@font-face` leve); a classe `class="fx-icon fx-icon-home"` injeta `@wrrdev/fenix-ui/icons` (CSS
87
+ completo, com as ~4.300 classes por glifo).
80
88
 
81
89
  ### Instale
82
90
 
@@ -145,6 +153,10 @@ export default defineConfig({
145
153
  | `fx-dropdown-item` | `@wrrdev/fenix-ui/dropdown` |
146
154
  | `fx-pagination` | `@wrrdev/fenix-ui/pagination` |
147
155
  | `fx-autocomplete` | `@wrrdev/fenix-ui/autocomplete` |
156
+ | `fx-icon` | `@wrrdev/fenix-ui/icon` |
157
+ | `fx-icon` / `fx-icon-*` (classe) | `@wrrdev/fenix-ui/icons` |
158
+ | `fx-knob` | `@wrrdev/fenix-ui/knob` |
159
+ | `fx-accordion` / `fx-accordion-panel` | `@wrrdev/fenix-ui/accordion` |
148
160
 
149
161
  ### Compatibilidade com frameworks
150
162
 
@@ -313,6 +325,9 @@ Importe o subpath `./vue` **uma única vez** no `main.ts`:
313
325
  import '@wrrdev/fenix-ui/vue'; // habilita autocomplete de fx-* nos templates SFC
314
326
  ```
315
327
 
328
+ > Com o plugin `FenixAutoImport` este import é injetado automaticamente em cada arquivo `.vue`
329
+ > (com os tipos) — o passo manual no `main.ts` continua valendo para projetos sem o plugin.
330
+
316
331
  **Configuração essencial do Vue 3** — diga ao compilador que `fx-*` são Web Components:
317
332
 
318
333
  ```ts
@@ -62,13 +62,49 @@ function fenixIconHtml(icon) {
62
62
  }
63
63
  return `<span aria-hidden="true">${esc(value)}</span>`;
64
64
  }
65
+ function resolveFontUrl() {
66
+ if (typeof __FENIX_ICONS_FONT_URL__ !== "undefined" && __FENIX_ICONS_FONT_URL__) {
67
+ return __FENIX_ICONS_FONT_URL__;
68
+ }
69
+ return new URL("" + new URL("fenix-icons-DmgotBzD.woff2", import.meta.url).href, import.meta.url).toString();
70
+ }
71
+ const FENIX_ICONS_FONT_URL = resolveFontUrl();
72
+ const FENIX_ICONS_FONT_STYLE_ID = "fenix-icons-font";
73
+ const FENIX_ICONS_STYLE_ID = "fenix-icons";
74
+ function buildFenixIconsFontFaceCss() {
75
+ return `@font-face{font-family:'${FENIX_ICON_FONT_FAMILY}';font-style:normal;font-weight:100 700;font-display:block;src:url('${FENIX_ICONS_FONT_URL}') format('woff2');}`;
76
+ }
77
+ function buildFenixIconsFontCss() {
78
+ return buildFenixIconsFontFaceCss() + FENIX_ICON_BASE_CSS;
79
+ }
80
+ let fontInjected = false;
81
+ function loadFenixIconsFont(target = typeof document !== "undefined" ? document : void 0) {
82
+ if (fontInjected || !target) return;
83
+ if (target.getElementById(FENIX_ICONS_STYLE_ID)) {
84
+ fontInjected = true;
85
+ return;
86
+ }
87
+ const style = target.createElement("style");
88
+ style.id = FENIX_ICONS_FONT_STYLE_ID;
89
+ style.textContent = buildFenixIconsFontCss();
90
+ target.head.appendChild(style);
91
+ fontInjected = true;
92
+ }
93
+ function __resetFenixIconsFontInjection() {
94
+ fontInjected = false;
95
+ }
65
96
  export {
66
- FENIX_ICON_FONT_FAMILY as F,
97
+ FENIX_ICONS_STYLE_ID as F,
98
+ __resetFenixIconsFontInjection as _,
67
99
  FENIX_ICON_BASE_CSS as a,
68
- stripTags as b,
100
+ buildFenixIconsFontFaceCss as b,
101
+ FENIX_ICON_FONT_FAMILY as c,
102
+ buildFenixIconsFontCss as d,
69
103
  esc as e,
70
104
  fenixIconHtml as f,
105
+ stripTags as g,
71
106
  isFenixIconName as i,
107
+ loadFenixIconsFont as l,
72
108
  sanitizeData as s
73
109
  };
74
- //# sourceMappingURL=base-css-Be_r8aTo.js.map
110
+ //# sourceMappingURL=font-CF0TXsAP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-CF0TXsAP.js","sources":["../../src/core/sanitize.ts","../../src/icons/base-css.ts","../../src/icons/font.ts"],"sourcesContent":["/**\n * Sanitização de strings para injeção segura em HTML.\n *\n * Previne XSS ao escapar caracteres especiais antes de usar innerHTML.\n * Use SEMPRE que dados externos (API, usuário) forem injetados no DOM.\n */\n\n/** Caracteres que devem ser escapados para prevenir XSS. */\nconst HTML_ENTITIES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n '/': '&#x2F;',\n '`': '&#x60;',\n '=': '&#x3D;',\n};\n\n/** Regex que captura todos os caracteres perigosos. */\nconst SANITIZE_REGEX = /[&<>\"'`=/]/g;\n\n/**\n * Escapa caracteres especiais de HTML para prevenir XSS.\n *\n * @param value - Valor a ser escapado (convertido para string)\n * @returns String segura para innerHTML\n *\n * @example\n * // Seguro contra XSS\n * const userInput = '<img src=x onerror=alert(1)>';\n * element.innerHTML = `<div>${esc(userInput)}</div>`;\n * // Resultado: &lt;img src=x onerror=alert(1)&gt;\n */\nexport function esc(value: unknown): string {\n if (value == null) return '';\n return String(value).replace(SANITIZE_REGEX, (char) => HTML_ENTITIES[char] || char);\n}\n\n/**\n * Remove todas as tags HTML da string (strip tags).\n * Use quando quiser apenas texto puro, sem nenhuma marcação.\n *\n * @param html - String potencialmente contendo HTML\n * @returns String sem tags HTML\n */\nexport function stripTags(html: string): string {\n return html.replace(/<[^>]*>/g, '');\n}\n\n/**\n * Sanitiza um objeto de dados recursivamente.\n * Útil para sanitizar arrays de registros antes de renderizar.\n *\n * @param data - Objeto ou array a ser sanitizado\n * @returns Cópia sanitizada do objeto\n */\nexport function sanitizeData<T>(data: T): T {\n if (data == null) return data;\n if (typeof data === 'string') return esc(data) as unknown as T;\n if (Array.isArray(data)) return data.map(sanitizeData) as unknown as T;\n if (typeof data === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n result[key] = sanitizeData(value);\n }\n return result as T;\n }\n return data;\n}\n","/**\n * CSS base da biblioteca de ícones — módulo LEVE (não importa a lista de nomes\n * nem dispara o carregamento da fonte). Usado dentro dos Shadow DOMs dos\n * componentes que suportam o atributo `icon`.\n *\n * O @font-face em si é injetado no <head> por `@wrrdev/fenix-ui/icons`\n * (ver ./index.ts) — @font-face registrado no documento também se aplica\n * dentro dos Shadow DOMs.\n */\n\nimport { esc } from '../core/sanitize';\n\n/** Nome da família de fontes dos ícones (self-hosted, sem dependência externa). */\nexport const FENIX_ICON_FONT_FAMILY = 'Fenix Icons';\n\n/** Família configurável via CSS custom property (fallback para o nome padrão). */\nexport const FENIX_ICON_FONT_VAR = `var(--fx-icon-font, ${FENIX_ICON_FONT_FAMILY})`;\n\n/**\n * Regras da classe `.fx-icon` para uso DENTRO de Shadow DOM\n * (concatene às `static styles` do componente).\n */\nexport const FENIX_ICON_BASE_CSS = `\n.fx-icon {\n font-family: ${FENIX_ICON_FONT_VAR};\n font-weight: normal;\n font-style: normal;\n line-height: 1;\n letter-spacing: normal;\n text-transform: none;\n display: inline-block;\n white-space: nowrap;\n word-wrap: normal;\n direction: ltr;\n font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n user-select: none;\n}\n.fx-icon.fx-icon-fill { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }\n.fx-icon.fx-icon-bold { font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 24; }\n`;\n\n/** Verifica se o valor parece um nome de ícone da Fenix Icons (e não emoji/texto livre). */\nexport function isFenixIconName(value: string): boolean {\n return /^[a-z][a-z0-9_]*$/.test(value.trim());\n}\n\n/**\n * HTML do ícone para uso DENTRO de Shadow DOM (concatenar ao template).\n *\n * - Nome válido da Fenix Icons (ex.: `home`) → glifo via LIGADURA: o nome\n * vira o conteúdo de texto do elemento com a font-family de ícones.\n * Isso é obrigatório dentro de Shadow DOM: as regras\n * `.fx-icon-<nome>::before` são injetadas no <head> do documento e NÃO\n * atravessam a fronteira do shadow root (apenas o @font-face vale\n * dentro dele) — a classe vazia renderizaria um elemento sem glifo.\n * - Qualquer outro valor (emoji, texto) → texto puro escapado.\n *\n * A classe base `.fx-icon` é fornecida por `FENIX_ICON_BASE_CSS`\n * (concatenada às `static styles` do componente); o @font-face vem do\n * `@wrrdev/fenix-ui/icons` (injetado no <head>).\n */\nexport function fenixIconHtml(icon: string): string {\n const value = (icon ?? '').trim();\n if (!value) return '';\n if (isFenixIconName(value)) {\n return `<i class=\"fx-icon\" aria-hidden=\"true\">${value}</i>`;\n }\n return `<span aria-hidden=\"true\">${esc(value)}</span>`;\n}\n","/**\n * Carregamento LEVE da fonte de ícones (@font-face + classe base).\n *\n * Separado de ./index de propósito: importar este módulo NÃO injeta o CSS\n * completo com as ~4.300 regras `fx-icon-<nome>`. É o que o <fx-icon> usa —\n * dentro do Shadow DOM o glifo vem da ligadura (o nome como conteúdo), então\n * as classes por ícone não atravessam a fronteira do shadow root.\n */\n\nimport { FENIX_ICON_BASE_CSS, FENIX_ICON_FONT_FAMILY } from './base-css';\n\n/** URL da fonte woff2: no build ESM a fonte vive na mesma pasta do módulo (dist/icons). */\ndeclare const __FENIX_ICONS_FONT_URL__: string | undefined;\n\nfunction resolveFontUrl(): string {\n if (typeof __FENIX_ICONS_FONT_URL__ !== 'undefined' && __FENIX_ICONS_FONT_URL__) {\n return __FENIX_ICONS_FONT_URL__;\n }\n // IMPORTANTE: o `import.meta.url` precisa ser usado DIRETAMENTE como 2º\n // argumento de `new URL` (sem variável intermediária). É assim que Vite,\n // webpack e Rollup reconhecem o padrão de asset e copiam/reescrevem a URL\n // da fonte no build do PROJETO CONSUMIDOR — com variável, a URL permanece\n // dinâmica e quebra em produção (a fonte 404 e os ícones viram texto).\n return new URL('./fenix-icons.woff2', import.meta.url).toString();\n}\n\n/** URL resolvida da fonte (reutilizada por ./index para o CSS completo). */\nexport const FENIX_ICONS_FONT_URL = resolveFontUrl();\n\n/** Id do <style> com @font-face + classe base. */\nexport const FENIX_ICONS_FONT_STYLE_ID = 'fenix-icons-font';\n\n/** Id do <style> com o CSS completo (@font-face + base + classes por ícone). */\nexport const FENIX_ICONS_STYLE_ID = 'fenix-icons';\n\n/** CSS do @font-face. */\nexport function buildFenixIconsFontFaceCss(): string {\n return (\n `@font-face{font-family:'${FENIX_ICON_FONT_FAMILY}';font-style:normal;font-weight:100 700;` +\n `font-display:block;src:url('${FENIX_ICONS_FONT_URL}') format('woff2');}`\n );\n}\n\n/** CSS leve: @font-face + classe base (sem as classes por ícone). */\nexport function buildFenixIconsFontCss(): string {\n return buildFenixIconsFontFaceCss() + FENIX_ICON_BASE_CSS;\n}\n\nlet fontInjected = false;\n\n/**\n * Injeta @font-face + classe base no <head> (idempotente). Não duplica quando\n * o CSS completo (`fenix-icons`) já foi carregado por `import '.../icons'`.\n */\nexport function loadFenixIconsFont(\n target: Document | undefined = typeof document !== 'undefined' ? document : undefined,\n): void {\n if (fontInjected || !target) return;\n if (target.getElementById(FENIX_ICONS_STYLE_ID)) {\n fontInjected = true;\n return;\n }\n const style = target.createElement('style');\n style.id = FENIX_ICONS_FONT_STYLE_ID;\n style.textContent = buildFenixIconsFontCss();\n target.head.appendChild(style);\n fontInjected = true;\n}\n\n/** Reseta o estado de injeção da fonte (uso interno/testes). */\nexport function __resetFenixIconsFontInjection(): void {\n fontInjected = false;\n}"],"names":[],"mappings":"AAQA,MAAM,gBAAwC;AAAA,EAC5C,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAGA,MAAM,iBAAiB;AAchB,SAAS,IAAI,OAAwB;AAC1C,MAAI,SAAS,KAAM,QAAO;AAC1B,SAAO,OAAO,KAAK,EAAE,QAAQ,gBAAgB,CAAC,SAAS,cAAc,IAAI,KAAK,IAAI;AACpF;AASO,SAAS,UAAU,MAAsB;AAC9C,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AASO,SAAS,aAAgB,MAAY;AAC1C,MAAI,QAAQ,KAAM,QAAO;AACzB,MAAI,OAAO,SAAS,SAAU,QAAO,IAAI,IAAI;AAC7C,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO,KAAK,IAAI,YAAY;AACrD,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAkC,CAAA;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAA+B,GAAG;AAC1E,aAAO,GAAG,IAAI,aAAa,KAAK;AAAA,IAClC;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;ACxDO,MAAM,yBAAyB;AAG/B,MAAM,sBAAsB,uBAAuB,sBAAsB;AAMzE,MAAM,sBAAsB;AAAA;AAAA,iBAElB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoB7B,SAAS,gBAAgB,OAAwB;AACtD,SAAO,oBAAoB,KAAK,MAAM,KAAA,CAAM;AAC9C;AAiBO,SAAS,cAAc,MAAsB;AAClD,QAAM,SAAS,QAAQ,IAAI,KAAA;AAC3B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,gBAAgB,KAAK,GAAG;AAC1B,WAAO,yCAAyC,KAAK;AAAA,EACvD;AACA,SAAO,4BAA4B,IAAI,KAAK,CAAC;AAC/C;ACxDA,SAAS,iBAAyB;AAChC,MAAI,OAAO,6BAA6B,eAAe,0BAA0B;AAC/E,WAAO;AAAA,EACT;AAMA,SAAO,IAAA,IAAA,kEAAA,YAAA,GAAA,EAAgD,SAAA;AACzD;AAGO,MAAM,uBAAuB,eAAA;AAG7B,MAAM,4BAA4B;AAGlC,MAAM,uBAAuB;AAG7B,SAAS,6BAAqC;AACnD,SACE,2BAA2B,sBAAsB,uEAClB,oBAAoB;AAEvD;AAGO,SAAS,yBAAiC;AAC/C,SAAO,+BAA+B;AACxC;AAEA,IAAI,eAAe;AAMZ,SAAS,mBACd,SAA+B,OAAO,aAAa,cAAc,WAAW,QACtE;AACN,MAAI,gBAAgB,CAAC,OAAQ;AAC7B,MAAI,OAAO,eAAe,oBAAoB,GAAG;AAC/C,mBAAe;AACf;AAAA,EACF;AACA,QAAM,QAAQ,OAAO,cAAc,OAAO;AAC1C,QAAM,KAAK;AACX,QAAM,cAAc,uBAAA;AACpB,SAAO,KAAK,YAAY,KAAK;AAC7B,iBAAe;AACjB;AAGO,SAAS,iCAAuC;AACrD,iBAAe;AACjB;"}
@@ -0,0 +1,79 @@
1
+ import { FxElement } from "../../core/base.js";
2
+ import { css } from "../../core/css.js";
3
+ import { defineElement } from "../../core/define.js";
4
+ import { esc } from "../../core/sanitize.js";
5
+ import { FENIX_ICON_BASE_CSS, isFenixIconName } from "../../icons/base-css.js";
6
+ import { loadFenixIconsFont } from "../../icons/font.js";
7
+ const _FxIcon = class _FxIcon extends FxElement {
8
+ static get observedAttributes() {
9
+ return ["name", "size", "label", "fill", "bold"];
10
+ }
11
+ /** Nome do glifo (ou texto livre/emoji). */
12
+ get name() {
13
+ return this.getAttr("name");
14
+ }
15
+ set name(value) {
16
+ this.setAttribute("name", value);
17
+ }
18
+ /** Tamanho: '' (herda 1em) | 'sm' | 'md' | 'lg' | 'xl'. */
19
+ get size() {
20
+ return this.getAttr("size");
21
+ }
22
+ set size(value) {
23
+ if (value) this.setAttribute("size", value);
24
+ else this.removeAttribute("size");
25
+ }
26
+ /** Nome acessível; vazio = ícone decorativo (aria-hidden). */
27
+ get label() {
28
+ return this.getAttr("label");
29
+ }
30
+ set label(value) {
31
+ if (value) this.setAttribute("label", value);
32
+ else this.removeAttribute("label");
33
+ }
34
+ connectedCallback() {
35
+ loadFenixIconsFont();
36
+ super.connectedCallback();
37
+ }
38
+ render() {
39
+ const name = this.getAttr("name").trim();
40
+ const label = this.getAttr("label").trim();
41
+ const a11y = label ? `role="img" aria-label="${esc(label)}"` : 'aria-hidden="true"';
42
+ if (!name) {
43
+ this.setTemplate(`<span class="icon" part="icon" ${a11y}></span>`);
44
+ return;
45
+ }
46
+ const inner = isFenixIconName(name) ? `<i class="icon fx-icon" part="icon" ${a11y}>${esc(name)}</i>` : `<span class="icon" part="icon" ${a11y}>${esc(name)}</span>`;
47
+ this.setTemplate(inner);
48
+ }
49
+ };
50
+ _FxIcon.styles = css`
51
+ :host {
52
+ display: inline-flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ vertical-align: middle;
56
+ line-height: 1;
57
+ color: currentColor;
58
+ font-size: var(--fx-icon-size, 1em);
59
+ }
60
+ :host([size='sm']) { font-size: var(--fx-icon-size-sm, 16px); }
61
+ :host([size='md']) { font-size: var(--fx-icon-size-md, 20px); }
62
+ :host([size='lg']) { font-size: var(--fx-icon-size-lg, 24px); }
63
+ :host([size='xl']) { font-size: var(--fx-icon-size-xl, 32px); }
64
+ :host([hidden]) { display: none; }
65
+ .icon { display: inline-block; }
66
+ /* Variantes da fonte (FILL/wght): vencem a classe base .fx-icon. */
67
+ :host([fill]) .icon { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }
68
+ :host([bold]) .icon { font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 24; }
69
+ ${FENIX_ICON_BASE_CSS}
70
+ `;
71
+ let FxIcon = _FxIcon;
72
+ function defineFxIcon() {
73
+ return defineElement("fx-icon", FxIcon);
74
+ }
75
+ export {
76
+ FxIcon,
77
+ defineFxIcon
78
+ };
79
+ //# sourceMappingURL=icon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icon.js","sources":["../../../src/components/icon/icon.ts"],"sourcesContent":["import { FxElement } from '../../core/base';\nimport { css } from '../../core/css';\nimport { defineElement } from '../../core/define';\nimport { esc } from '../../core/sanitize';\nimport { FENIX_ICON_BASE_CSS, isFenixIconName } from '../../icons/base-css';\nimport { loadFenixIconsFont } from '../../icons/font';\n\n/**\n * <fx-icon> — Glifo da Fenix Icons com AUTOCOMPLETE no editor.\n *\n * Por que existe: a forma antiga (`<i class=\"fx-icon fx-icon-home\">`) é CSS\n * puro — o TypeScript não valida nem sugere nada enquanto você digita, e o\n * auto-import só injeta o import. Com o elemento, o atributo `name` é tipado\n * como `FenixIconName`, então Volar/vue-tsc, React e TSX listam os +4.000\n * glifos válidos (e o hover mostra a assinatura do atributo).\n *\n * Atributos:\n * - name → nome do glifo (ex.: `home`); texto livre/emoji também funciona\n * - size → sm | md | lg | xl (default: 1em, herda o texto ao redor)\n * - label → nome acessível; sem label o ícone é aria-hidden (decorativo)\n * - fill → variante preenchida\n * - bold → traço mais pesado\n *\n * O glifo sai por LIGADURA (o nome vira o conteúdo de texto com a\n * font-family de ícones) — por isso funciona dentro do Shadow DOM, onde as\n * classes `fx-icon-<nome>` do documento não atravessam a fronteira.\n *\n * Tamanho via CSS: --fx-icon-size (-sm/-md/-lg/-xl).\n */\nexport class FxIcon extends FxElement {\n static override styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n vertical-align: middle;\n line-height: 1;\n color: currentColor;\n font-size: var(--fx-icon-size, 1em);\n }\n :host([size='sm']) { font-size: var(--fx-icon-size-sm, 16px); }\n :host([size='md']) { font-size: var(--fx-icon-size-md, 20px); }\n :host([size='lg']) { font-size: var(--fx-icon-size-lg, 24px); }\n :host([size='xl']) { font-size: var(--fx-icon-size-xl, 32px); }\n :host([hidden]) { display: none; }\n .icon { display: inline-block; }\n /* Variantes da fonte (FILL/wght): vencem a classe base .fx-icon. */\n :host([fill]) .icon { font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24; }\n :host([bold]) .icon { font-variation-settings: 'FILL' 0, 'wght' 600, 'GRAD' 0, 'opsz' 24; }\n ${FENIX_ICON_BASE_CSS}\n `;\n\n static override get observedAttributes(): string[] {\n return ['name', 'size', 'label', 'fill', 'bold'];\n }\n\n /** Nome do glifo (ou texto livre/emoji). */\n get name(): string {\n return this.getAttr('name');\n }\n set name(value: string) {\n this.setAttribute('name', value);\n }\n\n /** Tamanho: '' (herda 1em) | 'sm' | 'md' | 'lg' | 'xl'. */\n get size(): string {\n return this.getAttr('size');\n }\n set size(value: string) {\n if (value) this.setAttribute('size', value);\n else this.removeAttribute('size');\n }\n\n /** Nome acessível; vazio = ícone decorativo (aria-hidden). */\n get label(): string {\n return this.getAttr('label');\n }\n set label(value: string) {\n if (value) this.setAttribute('label', value);\n else this.removeAttribute('label');\n }\n\n protected override connectedCallback(): void {\n // O glifo depende do @font-face: garante o CSS leve (sem as 4k classes).\n loadFenixIconsFont();\n super.connectedCallback();\n }\n\n protected override render(): void {\n const name = this.getAttr('name').trim();\n const label = this.getAttr('label').trim();\n const a11y = label ? `role=\"img\" aria-label=\"${esc(label)}\"` : 'aria-hidden=\"true\"';\n if (!name) {\n this.setTemplate(`<span class=\"icon\" part=\"icon\" ${a11y}></span>`);\n return;\n }\n // Nome válido → ligadura (glifo). Emoji/texto livre → texto puro.\n const inner = isFenixIconName(name)\n ? `<i class=\"icon fx-icon\" part=\"icon\" ${a11y}>${esc(name)}</i>`\n : `<span class=\"icon\" part=\"icon\" ${a11y}>${esc(name)}</span>`;\n this.setTemplate(inner);\n }\n}\n\nexport function defineFxIcon(): typeof FxIcon {\n return defineElement('fx-icon', FxIcon);\n}\n"],"names":[],"mappings":";;;;;;AA6BO,MAAM,UAAN,MAAM,gBAAe,UAAU;AAAA,EAuBpC,WAAoB,qBAA+B;AACjD,WAAO,CAAC,QAAQ,QAAQ,SAAS,QAAQ,MAAM;AAAA,EACjD;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ,MAAM;AAAA,EAC5B;AAAA,EACA,IAAI,KAAK,OAAe;AACtB,SAAK,aAAa,QAAQ,KAAK;AAAA,EACjC;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ,MAAM;AAAA,EAC5B;AAAA,EACA,IAAI,KAAK,OAAe;AACtB,QAAI,MAAO,MAAK,aAAa,QAAQ,KAAK;AAAA,QACrC,MAAK,gBAAgB,MAAM;AAAA,EAClC;AAAA;AAAA,EAGA,IAAI,QAAgB;AAClB,WAAO,KAAK,QAAQ,OAAO;AAAA,EAC7B;AAAA,EACA,IAAI,MAAM,OAAe;AACvB,QAAI,MAAO,MAAK,aAAa,SAAS,KAAK;AAAA,QACtC,MAAK,gBAAgB,OAAO;AAAA,EACnC;AAAA,EAEmB,oBAA0B;AAE3C,uBAAA;AACA,UAAM,kBAAA;AAAA,EACR;AAAA,EAEmB,SAAe;AAChC,UAAM,OAAO,KAAK,QAAQ,MAAM,EAAE,KAAA;AAClC,UAAM,QAAQ,KAAK,QAAQ,OAAO,EAAE,KAAA;AACpC,UAAM,OAAO,QAAQ,0BAA0B,IAAI,KAAK,CAAC,MAAM;AAC/D,QAAI,CAAC,MAAM;AACT,WAAK,YAAY,kCAAkC,IAAI,UAAU;AACjE;AAAA,IACF;AAEA,UAAM,QAAQ,gBAAgB,IAAI,IAC9B,uCAAuC,IAAI,IAAI,IAAI,IAAI,CAAC,SACxD,kCAAkC,IAAI,IAAI,IAAI,IAAI,CAAC;AACvD,SAAK,YAAY,KAAK;AAAA,EACxB;AACF;AAxEE,QAAgB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBrB,mBAAmB;AAAA;AApBlB,IAAM,SAAN;AA2EA,SAAS,eAA8B;AAC5C,SAAO,cAAc,WAAW,MAAM;AACxC;"}
@@ -0,0 +1,7 @@
1
+ import { defineFxIcon } from "./icon.js";
2
+ import { FxIcon } from "./icon.js";
3
+ defineFxIcon();
4
+ export {
5
+ FxIcon
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/icon/index.ts"],"sourcesContent":["import { FxIcon, defineFxIcon } from './icon';\n\nexport { FxIcon };\n\ndefineFxIcon();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'fx-icon': FxIcon;\n }\n}\n"],"names":[],"mappings":";;AAIA,aAAA;"}
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/docs/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAiB,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAgE5B;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBlD;AAkDD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmC9C;AAqqED,eAAO,MAAM,iBAAiB,QAAO,OAAO,CAAC,IAAI,CAAgB,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/docs/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAiB,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAgE5B;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBlD;AAkDD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmC9C;AA0rED,eAAO,MAAM,iBAAiB,QAAO,OAAO,CAAC,IAAI,CAAgB,CAAC"}