rook-cli 1.3.2 → 1.3.4

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.
Files changed (89) hide show
  1. package/package.json +3 -2
  2. package/rook-framework/PRD-INSTALL-COMMAND.md +379 -0
  3. package/rook-framework/PRD.md +1214 -0
  4. package/rook-framework/README.md +143 -0
  5. package/rook-framework/assets/rk-accordion.js +99 -0
  6. package/rook-framework/assets/rk-alert-dialog.js +132 -0
  7. package/rook-framework/assets/rk-bottom-app-bar.js +88 -0
  8. package/rook-framework/assets/rk-carousel.js +145 -0
  9. package/rook-framework/assets/rk-collapsible.js +151 -0
  10. package/rook-framework/assets/rk-dialog.js +161 -0
  11. package/rook-framework/assets/rk-drawer.js +214 -0
  12. package/rook-framework/assets/rk-framework-core.css +2554 -0
  13. package/rook-framework/assets/rk-framework-tokens.css +101 -0
  14. package/rook-framework/assets/rk-modal.js +91 -0
  15. package/rook-framework/assets/rk-popover.js +264 -0
  16. package/rook-framework/assets/rk-progress.js +81 -0
  17. package/rook-framework/assets/rk-quantity.js +91 -0
  18. package/rook-framework/assets/rk-scroll-area.js +286 -0
  19. package/rook-framework/assets/rk-sheet.js +157 -0
  20. package/rook-framework/assets/rk-tabs.js +179 -0
  21. package/rook-framework/assets/rk-toggle.js +153 -0
  22. package/rook-framework/blocks/rk-accordion.liquid +97 -0
  23. package/rook-framework/blocks/rk-badge.liquid +103 -0
  24. package/rook-framework/blocks/rk-button.liquid +166 -0
  25. package/rook-framework/blocks/rk-divider.liquid +100 -0
  26. package/rook-framework/blocks/rk-form-field.liquid +120 -0
  27. package/rook-framework/blocks/rk-icon.liquid +134 -0
  28. package/rook-framework/blocks/rk-image.liquid +198 -0
  29. package/rook-framework/blocks/rk-installments.liquid +99 -0
  30. package/rook-framework/blocks/rk-pix-discount.liquid +99 -0
  31. package/rook-framework/blocks/rk-price.liquid +128 -0
  32. package/rook-framework/blocks/rk-quantity.liquid +108 -0
  33. package/rook-framework/blocks/rk-quick-add.liquid +137 -0
  34. package/rook-framework/blocks/rk-skeleton.liquid +104 -0
  35. package/rook-framework/blocks/rk-typography.liquid +183 -0
  36. package/rook-framework/config/rk-settings_schema.json +259 -0
  37. package/rook-framework/snippets/rk-accordion.liquid +31 -0
  38. package/rook-framework/snippets/rk-alert-dialog.liquid +83 -0
  39. package/rook-framework/snippets/rk-aspect-ratio.liquid +23 -0
  40. package/rook-framework/snippets/rk-badge.liquid +17 -0
  41. package/rook-framework/snippets/rk-bottom-app-bar.liquid +51 -0
  42. package/rook-framework/snippets/rk-button.liquid +49 -0
  43. package/rook-framework/snippets/rk-card.liquid +64 -0
  44. package/rook-framework/snippets/rk-carousel.liquid +74 -0
  45. package/rook-framework/snippets/rk-checkbox.liquid +34 -0
  46. package/rook-framework/snippets/rk-collapsible.liquid +52 -0
  47. package/rook-framework/snippets/rk-dialog.liquid +85 -0
  48. package/rook-framework/snippets/rk-divider.liquid +25 -0
  49. package/rook-framework/snippets/rk-drawer.liquid +81 -0
  50. package/rook-framework/snippets/rk-external-assets copy.liquid +33 -0
  51. package/rook-framework/snippets/rk-external-assets.liquid +68 -0
  52. package/rook-framework/snippets/rk-form-field.liquid +83 -0
  53. package/rook-framework/snippets/rk-gap-style.liquid +32 -0
  54. package/rook-framework/snippets/rk-icon.liquid +28 -0
  55. package/rook-framework/snippets/rk-image.liquid +60 -0
  56. package/rook-framework/snippets/rk-input.liquid +35 -0
  57. package/rook-framework/snippets/rk-installments.liquid +54 -0
  58. package/rook-framework/snippets/rk-item.liquid +69 -0
  59. package/rook-framework/snippets/rk-layout-style.liquid +37 -0
  60. package/rook-framework/snippets/rk-modal.liquid +31 -0
  61. package/rook-framework/snippets/rk-pix-discount.liquid +34 -0
  62. package/rook-framework/snippets/rk-popover.liquid +77 -0
  63. package/rook-framework/snippets/rk-price.liquid +48 -0
  64. package/rook-framework/snippets/rk-progress.liquid +38 -0
  65. package/rook-framework/snippets/rk-quantity.liquid +56 -0
  66. package/rook-framework/snippets/rk-quick-add.liquid +67 -0
  67. package/rook-framework/snippets/rk-scripts.liquid +17 -0
  68. package/rook-framework/snippets/rk-scroll-area.liquid +60 -0
  69. package/rook-framework/snippets/rk-sheet.liquid +86 -0
  70. package/rook-framework/snippets/rk-size-style.liquid +48 -0
  71. package/rook-framework/snippets/rk-skeleton.liquid +25 -0
  72. package/rook-framework/snippets/rk-spacing-padding.liquid +18 -0
  73. package/rook-framework/snippets/rk-spacing-style.liquid +54 -0
  74. package/rook-framework/snippets/rk-spinner.liquid +43 -0
  75. package/rook-framework/snippets/rk-swatch.liquid +33 -0
  76. package/rook-framework/snippets/rk-table.liquid +44 -0
  77. package/rook-framework/snippets/rk-tabs.liquid +52 -0
  78. package/rook-framework/snippets/rk-textarea.liquid +42 -0
  79. package/rook-framework/snippets/rk-toggle-group.liquid +27 -0
  80. package/rook-framework/snippets/rk-toggle.liquid +58 -0
  81. package/rook-framework/snippets/rk-typography.liquid +27 -0
  82. package/rook-framework/snippets/rk-variables.liquid +74 -0
  83. package/src/app.js +24 -0
  84. package/src/commands/InstallCommand.js +133 -0
  85. package/src/mcp/server.js +111 -1
  86. package/src/services/FrameworkInstaller.js +379 -0
  87. package/src/templates/block.liquid.txt +0 -15
  88. package/src/ui/PromptUI.js +15 -1
  89. package/src/utils/logger.js +1 -1
@@ -0,0 +1,1214 @@
1
+ # PRD: Rook UI Core Framework for Shopify
2
+
3
+ ## 1. Visão Geral
4
+
5
+ O **Rook UI Core** é uma biblioteca de componentes UI **agnóstica e desacoplada** para Shopify, focada em **reutilização entre temas**. Apesar de ser validada inicialmente no tema **Horizon**, toda a arquitetura é pensada para funcionar em qualquer tema Shopify, podendo ser extraída e portada sem acoplamento.
6
+
7
+ ### 1.1 Nomenclatura
8
+
9
+ - **Prefixo:** `rk-` (Rook)
10
+ - **BEM:** `rk-block__element--modifier`
11
+ - **Exemplo:** `rk-btn--primary`, `rk-price__compare`, `rk-quantity__input`
12
+
13
+ ### 1.2 Stack Técnico
14
+
15
+ | Camada | Tecnologia |
16
+ |---|---|
17
+ | Markup | Liquid (`{% doc %}`, `{% render %}`) |
18
+ | Estilização | CSS Variables + BEM |
19
+ | Lógica | Web Components (`customElements.define`) |
20
+ | Configuração | `settings_schema.json` (injeção manual no tema) |
21
+
22
+ ---
23
+
24
+ ## 2. Pilares de Arquitetura
25
+
26
+ ### 2.1 SOLID (SRP)
27
+
28
+ Cada componente tem **uma única responsabilidade**. O `rk-price` exibe preço, o `rk-installments` calcula parcelamento, o `rk-pix-discount` calcula Pix. Nunca misturar responsabilidades em um mesmo componente.
29
+
30
+ ### 2.2 BEM Methodology
31
+
32
+ Toda classe CSS segue o padrão BEM:
33
+ ```
34
+ .rk-btn → Block
35
+ .rk-btn__text → Element
36
+ .rk-btn--primary → Modifier
37
+ ```
38
+
39
+ ### 2.3 Design Tokens (CSS Variables)
40
+
41
+ Todas as cores, espaçamentos e formas são gerenciados via CSS Variables no arquivo `rk-framework-tokens.css`, populados via Liquid/settings_schema:
42
+ ```css
43
+ --rk-color-primary: {{ settings.rk_color_primary }};
44
+ --rk-radius: {{ settings.rk_border_radius }}px;
45
+ --rk-transition-speed: {{ settings.rk_transition_speed }}ms;
46
+ ```
47
+
48
+ ### 2.4 Factory Pattern
49
+
50
+ Componentes como `rk-button` e `rk-price` usam o padrão Factory: uma prop (e.g. `style: 'outline'`) controla qual variante visual será renderizada.
51
+
52
+ ### 2.5 Performance-First
53
+
54
+ - **`loading: 'lazy'`** por padrão em todos os `rk-image`
55
+ - **`aspect-ratio`** inline para prevenir CLS
56
+ - **Web Components** com `if (!customElements.get())` para evitar re-registro
57
+ - **CSS sem `!important`** — tudo via especificidade BEM
58
+
59
+ ### 2.6 Desacoplamento Total
60
+
61
+ O framework inteiro vive em `/rook-framework/` como pasta isolada. Para portar para outro tema:
62
+ 1. Copiar a pasta `/rook-framework/`
63
+ 2. Mover os assets para `/assets/`, snippets para `/snippets/`
64
+ 3. Injetar o `rk-settings_schema.json` dentro do `settings_schema.json` do tema alvo
65
+
66
+ ---
67
+
68
+ ## 3. Estrutura de Arquivos
69
+
70
+ ```
71
+ /rook-framework/
72
+ ├── config/
73
+ │ └── rk-settings_schema.json ← Seção de settings para injetar no tema
74
+ ├── assets/
75
+ │ ├── rk-framework-tokens.css ← Design Tokens (CSS Variables + Liquid)
76
+ │ ├── rk-framework-core.css ← Estilos BEM de todos os componentes
77
+ │ ├── rk-quantity.js ← Controller: <rk-quantity-selector>
78
+ │ ├── rk-modal.js ← Controller: <rk-modal-element>
79
+ │ ├── rk-popover.js ← Controller: <rk-popover-element>
80
+ │ ├── rk-scroll-area.js ← Controller: <rk-scroll-area>
81
+ │ ├── rk-drawer.js ← Controller: <rk-drawer-element>
82
+ │ ├── rk-dialog.js ← Controller: <rk-dialog-element>
83
+ │ ├── rk-sheet.js ← Controller: <rk-sheet-element>
84
+ │ ├── rk-tabs.js ← Controller: <rk-tabs-element>
85
+ │ ├── rk-toggle.js ← Controller: <rk-toggle-element> & <rk-toggle-group>
86
+ │ ├── rk-progress.js ← Controller: <rk-progress-element>
87
+ │ ├── rk-collapsible.js ← Controller: <rk-collapsible-element>
88
+ │ ├── rk-carousel.js ← Controller: <rk-carousel-element>
89
+ │ ├── rk-bottom-app-bar.js ← Controller: <rk-bottom-app-bar-element>
90
+ │ └── rk-accordion.js ← Controller: <rk-accordion-element>
91
+ ├── snippets/
92
+ │ ├── rk-size-style.liquid ← Style: CSS vars de width/height (portável)
93
+ │ ├── rk-spacing-style.liquid ← Style: CSS vars de padding com scaling (portável)
94
+ │ ├── rk-spacing-padding.liquid ← Style: CSS vars de padding simples (portável)
95
+ │ ├── rk-gap-style.liquid ← Style: CSS vars de gap com scaling (portável)
96
+ │ ├── rk-layout-style.liquid ← Style: CSS vars de layout/flex (portável)
97
+ │ ├── rk-button.liquid ← Átomo: Botão/Link com variantes
98
+ │ ├── rk-image.liquid ← Átomo: Imagem responsiva com CLS
99
+ │ ├── rk-icon.liquid ← Átomo: Wrapper SVG para ícones
100
+ │ ├── rk-input.liquid ← Átomo: Campo de texto
101
+ │ ├── rk-textarea.liquid ← Átomo: Campo de texto multilinhas
102
+ │ ├── rk-checkbox.liquid ← Átomo: Checkbox acessível
103
+ │ ├── rk-badge.liquid ← Átomo: Label de status
104
+ │ ├── rk-typography.liquid ← Átomo: Controle tipográfico
105
+ │ ├── rk-divider.liquid ← Átomo: Separador visual
106
+ │ ├── rk-skeleton.liquid ← Átomo: Placeholder de carregamento
107
+ │ ├── rk-swatch.liquid ← Átomo: Swatch de variante
108
+ │ ├── rk-aspect-ratio.liquid ← Átomo: Container utilitário 16:9, 4:3, etc.
109
+ │ ├── rk-item.liquid ← Átomo: Item de Lista/Menu
110
+ │ ├── rk-spinner.liquid ← Átomo: Indicador de carregamento animado (Loading)
111
+ │ ├── rk-card.liquid ← Molécula: Container flexível (Header/Body/Footer)
112
+ │ ├── rk-price.liquid ← Molécula: Display de preço
113
+ │ ├── rk-installments.liquid ← Molécula: Parcelamento (global)
114
+ │ ├── rk-pix-discount.liquid ← Molécula: Desconto Pix (global)
115
+ │ ├── rk-quantity.liquid ← Molécula: Seletor de quantidade
116
+ │ ├── rk-accordion.liquid ← Molécula: Accordion/Disclosure
117
+ │ ├── rk-form-field.liquid ← Molécula: Label + Input + Error
118
+ │ ├── rk-modal.liquid ← Molécula: Dialog/Modal base
119
+ │ ├── rk-popover.liquid ← Molécula: Popover flutuante
120
+ │ ├── rk-scroll-area.liquid ← Molécula: Área de scroll customizada
121
+ │ ├── rk-drawer.liquid ← Molécula: Painel deslizante
122
+ │ ├── rk-dialog.liquid ← Molécula: Dialog/Modal (Shadcn/UI)
123
+ │ ├── rk-sheet.liquid ← Molécula: Painel lateral full-viewport
124
+ │ ├── rk-tabs.liquid ← Molécula: Guias (Tabs) alternáveis
125
+ │ ├── rk-table.liquid ← Molécula: Tabela semântica e responsiva
126
+ │ ├── rk-toggle.liquid ← Molécula: Botão de dois estados (Switch/Toggle)
127
+ │ ├── rk-toggle-group.liquid ← Molécula: Agrupamento de toggles
128
+ │ ├── rk-progress.liquid ← Molécula: Barra de progresso visual
129
+ │ ├── rk-collapsible.liquid ← Molécula: Painel ocultável
130
+ │ ├── rk-carousel.liquid ← Molécula: Slider/Carousel (Swiper.js)
131
+ │ ├── rk-bottom-app-bar.liquid ← Molécula: Barra de navegação inferior estilo App
132
+ │ ├── rk-external-assets.liquid ← Serviço: Gerenciador de preconnects, CDNs e scripts externos (GSAP/Animejs)
133
+ │ ├── rk-scripts.liquid ← Serviço: Carregador centralizado dos Web Components JS do framework
134
+ │ └── rk-quick-add.liquid ← Molécula: Add to Cart (⚠️ exceção)
135
+ └── blocks/
136
+ ├── rk-button.liquid ← Block: Botão com customizer
137
+ ├── rk-image.liquid ← Block: Imagem com customizer
138
+ ├── rk-typography.liquid ← Block: Texto com customizer
139
+ ├── rk-price.liquid ← Block: Preço com customizer
140
+ ├── rk-divider.liquid ← Block: Divisor com customizer
141
+ ├── rk-accordion.liquid ← Block: Accordion com customizer
142
+ ├── rk-badge.liquid ← Block: Badge com customizer
143
+ ├── rk-icon.liquid ← Block: Ícone com customizer
144
+ ├── rk-form-field.liquid ← Block: Campo formulário com customizer
145
+ ├── rk-installments.liquid ← Block: Parcelamento com customizer
146
+ ├── rk-pix-discount.liquid ← Block: Desconto Pix com customizer
147
+ ├── rk-quantity.liquid ← Block: Seletor qtd com customizer
148
+ ├── rk-quick-add.liquid ← Block: Add to Cart com customizer
149
+ └── rk-skeleton.liquid ← Block: Skeleton com customizer
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 4. Configuração Global (`rk-settings_schema.json`)
155
+
156
+ O arquivo `rk-settings_schema.json` define uma seção **"⚡ Rook UI Core Framework"** no painel do Shopify com:
157
+
158
+ ### 4.1 Tokens de Cores
159
+ | Setting ID | Tipo | Default | Descrição |
160
+ |---|---|---|---|
161
+ | `rk_color_primary` | color | `#000000` | Cor primária |
162
+ | `rk_color_primary_hover` | color | `#1a1a1a` | Hover da primária |
163
+ | `rk_color_secondary` | color | `#ffffff` | Cor secundária |
164
+ | `rk_color_secondary_hover` | color | `#f5f5f5` | Hover da secundária |
165
+ | `rk_color_success` | color | `#22c55e` | Cor de sucesso |
166
+ | `rk_color_danger` | color | `#ef4444` | Cor de erro/perigo |
167
+ | `rk_color_text` | color | `#1a1a1a` | Cor do texto base |
168
+ | `rk_color_text_muted` | color | `#737373` | Cor texto secundário |
169
+ | `rk_color_border` | color | `#e5e5e5` | Cor de borda |
170
+
171
+ ### 4.2 Tokens de Forma e Transição
172
+ | Setting ID | Tipo | Default | Descrição |
173
+ |---|---|---|---|
174
+ | `rk_border_radius` | range (0-40px) | `8px` | Arredondamento padrão |
175
+ | `rk_border_radius_pill` | range (0-100px) | `50px` | Arredondamento pill |
176
+ | `rk_transition_speed` | range (100-800ms) | `300ms` | Velocidade da transição |
177
+
178
+ ### 4.3 Financeiro: Parcelamento
179
+ | Setting ID | Tipo | Default | Descrição |
180
+ |---|---|---|---|
181
+ | `rk_installments_enabled` | checkbox | `true` | Ativar parcelamento |
182
+ | `rk_installments_max` | number | `12` | Qtd máxima de parcelas |
183
+ | `rk_installments_without_interest` | number | `3` | Parcelas sem juros |
184
+ | `rk_installments_min_value` | text | `500` | Valor mínimo da parcela (centavos) |
185
+ | `rk_installments_interest_rate` | text | `2.99` | Taxa de juros mensal (%) |
186
+
187
+ ### 4.4 Financeiro: Pix
188
+ | Setting ID | Tipo | Default | Descrição |
189
+ |---|---|---|---|
190
+ | `rk_pix_enabled` | checkbox | `true` | Ativar desconto Pix |
191
+ | `rk_pix_discount` | range (0-30%) | `5%` | % desconto no Pix |
192
+ | `rk_pix_label` | text | `no Pix` | Texto exibido ao lado do desconto |
193
+
194
+ ---
195
+
196
+ ## 5. Catálogo de Componentes
197
+
198
+ ---
199
+
200
+ ### 5.1 Átomos
201
+
202
+ #### `rk-button`
203
+ **Arquivo:** `snippets/rk-button.liquid`
204
+ **Tipo:** Factory Pattern
205
+ **Descrição:** Renderiza `<button>` ou `<a>` com estilos configuráveis.
206
+
207
+ | Prop | Tipo | Default | Descrição |
208
+ |---|---|---|---|
209
+ | `text` | string | — | Texto do botão (obrigatório) |
210
+ | `url` | string | — | Se preenchido, renderiza `<a>` |
211
+ | `style` | string | `primary` | `primary` \| `secondary` \| `outline` \| `ghost` \| `link` |
212
+ | `size` | string | `md` | `sm` \| `md` \| `lg` |
213
+ | `type` | string | `button` | `button` \| `submit` |
214
+ | `disabled` | boolean | `false` | Estado desabilitado |
215
+ | `loading` | boolean | `false` | Exibe spinner |
216
+ | `full_width` | boolean | `false` | Largura 100% |
217
+ | `icon` | string | — | Nome do ícone (antes do texto) |
218
+ | `custom_class` | string | — | Classes extras |
219
+ | `open_in_new_tab` | boolean | `false` | `target="_blank"` |
220
+
221
+ **Exemplo:**
222
+ ```liquid
223
+ {% render 'rk-button', text: 'Comprar', style: 'primary', size: 'lg' %}
224
+ {% render 'rk-button', text: 'Ver mais', url: '/colecao', style: 'outline' %}
225
+ {% render 'rk-button', text: 'Enviar', type: 'submit', loading: true %}
226
+ ```
227
+
228
+ ---
229
+
230
+ #### `rk-image`
231
+ **Arquivo:** `snippets/rk-image.liquid`
232
+ **Descrição:** Imagem responsiva com srcset, aspect-ratio para CLS e lazyload.
233
+
234
+ | Prop | Tipo | Default | Descrição |
235
+ |---|---|---|---|
236
+ | `image` | object | — | Objeto imagem do Shopify |
237
+ | `width` / `height` | number | auto | Dimensões |
238
+ | `sizes` | string | `100vw` | Atributo sizes |
239
+ | `loading` | string | `lazy` | `lazy` \| `eager` |
240
+ | `shape` | string | — | `rounded` \| `circle` |
241
+ | `alt` | string | `image.alt` | Texto alternativo |
242
+
243
+ ---
244
+
245
+ #### `rk-icon`
246
+ **Arquivo:** `snippets/rk-icon.liquid`
247
+ **Descrição:** Wrapper SVG para ícones com sizes e acessibilidade.
248
+
249
+ | Prop | Tipo | Default |
250
+ |---|---|---|
251
+ | `icon` | string | — |
252
+ | `size` | string | `md` |
253
+ | `color` | string | `inherit` |
254
+ | `label` | string | — |
255
+
256
+ ---
257
+
258
+ #### `rk-input`
259
+ **Arquivo:** `snippets/rk-input.liquid`
260
+ **Descrição:** Campo de input com estado de erro.
261
+
262
+ | Prop | Tipo | Default |
263
+ |---|---|---|
264
+ | `name` | string | — |
265
+ | `type` | string | `text` |
266
+ | `placeholder` | string | — |
267
+ | `error` | boolean | `false` |
268
+ | `required` | boolean | `false` |
269
+
270
+ ---
271
+
272
+ #### `rk-checkbox`
273
+ **Arquivo:** `snippets/rk-checkbox.liquid`
274
+ **Descrição:** Checkbox acessível com label clicável.
275
+
276
+ ---
277
+
278
+ #### `rk-badge`
279
+ **Arquivo:** `snippets/rk-badge.liquid`
280
+ **Descrição:** Label de status (Novo, Promoção, Esgotado).
281
+
282
+ | Prop | Tipo | Default |
283
+ |---|---|---|
284
+ | `text` | string | — |
285
+ | `style` | string | `primary` |
286
+
287
+ Estilos: `primary` \| `success` \| `danger` \| `outline`
288
+
289
+ ---
290
+
291
+ #### `rk-typography`
292
+ **Arquivo:** `snippets/rk-typography.liquid`
293
+ **Descrição:** Texto com escala tipográfica.
294
+
295
+ | Prop | Tipo | Default |
296
+ |---|---|---|
297
+ | `text` | string | — |
298
+ | `tag` | string | `p` |
299
+ | `size` | string | `md` |
300
+ | `align` | string | — |
301
+ | `bold` | boolean | `false` |
302
+ | `muted` | boolean | `false` |
303
+ | `uppercase` | boolean | `false` |
304
+
305
+ ---
306
+
307
+ #### `rk-divider`
308
+ **Arquivo:** `snippets/rk-divider.liquid`
309
+ **Descrição:** Separador visual com espessura e largura configuráveis.
310
+
311
+ ---
312
+
313
+ #### `rk-skeleton`
314
+ **Arquivo:** `snippets/rk-skeleton.liquid`
315
+ **Descrição:** Placeholder de carregamento com shimmer animation.
316
+
317
+ | Prop | Tipo | Default |
318
+ |---|---|---|
319
+ | `width` | string | `100%` |
320
+ | `height` | string | `1em` |
321
+ | `shape` | string | `text` |
322
+
323
+ Shapes: `text` \| `circle` \| `rect`
324
+
325
+ ---
326
+
327
+ #### `rk-swatch`
328
+ **Arquivo:** `snippets/rk-swatch.liquid`
329
+ **Descrição:** Swatch visual de variante com cor, imagem e estados.
330
+
331
+ ---
332
+
333
+ ### 5.2 Moléculas
334
+
335
+ #### `rk-price`
336
+ **Arquivo:** `snippets/rk-price.liquid`
337
+ **Descrição:** Display de preço com suporte a preço promocional (De/Por) e "A partir de".
338
+
339
+ | Prop | Tipo | Default | Descrição |
340
+ |---|---|---|---|
341
+ | `product` | object | — | Objeto produto Shopify |
342
+ | `from` | boolean | `false` | Exibe prefixo "A partir de" |
343
+ | `show_compare` | boolean | `false` | Força preço comparativo |
344
+ | `compare_position` | string | `before` | `before` \| `after` — posição do preço cortado |
345
+
346
+ **Exemplo:**
347
+ ```liquid
348
+ {% render 'rk-price', product: product, from: true %}
349
+ {% render 'rk-price', product: product, compare_position: 'after' %}
350
+ ```
351
+
352
+ ---
353
+
354
+ #### `rk-installments`
355
+ **Arquivo:** `snippets/rk-installments.liquid`
356
+ **Controller:** Nenhum (cálculo Liquid server-side)
357
+ **Descrição:** Calcula e exibe parcelamento baseado nas **settings globais** do framework.
358
+
359
+ | Prop | Tipo | Descrição |
360
+ |---|---|---|
361
+ | `price` | number | Preço em centavos |
362
+
363
+ **Lógica:** Lê `settings.rk_installments_max`, `settings.rk_installments_without_interest`, `settings.rk_installments_min_value`, `settings.rk_installments_interest_rate` e determina a melhor parcela.
364
+
365
+ ---
366
+
367
+ #### `rk-pix-discount`
368
+ **Arquivo:** `snippets/rk-pix-discount.liquid`
369
+ **Controller:** Nenhum (cálculo Liquid server-side)
370
+ **Descrição:** Calcula e exibe preço com desconto Pix baseado nas **settings globais**.
371
+
372
+ | Prop | Tipo | Descrição |
373
+ |---|---|---|
374
+ | `price` | number | Preço em centavos |
375
+
376
+ **Lógica:** Lê `settings.rk_pix_enabled`, `settings.rk_pix_discount` e `settings.rk_pix_label`.
377
+
378
+ ---
379
+
380
+ #### `rk-quantity`
381
+ **Arquivo:** `snippets/rk-quantity.liquid`
382
+ **Controller:** `assets/rk-quantity.js` → `<rk-quantity-selector>`
383
+ **Descrição:** Seletor de quantidade com botões +/- e input numérico.
384
+
385
+ | Prop | Tipo | Default |
386
+ |---|---|---|
387
+ | `value` | number | `1` |
388
+ | `min` | number | `1` |
389
+ | `max` | number | — |
390
+ | `step` | number | `1` |
391
+ | `name` | string | `quantity` |
392
+
393
+ **Custom Event:** `rk:quantity:change` → `{ value: number, name: string }`
394
+
395
+ ---
396
+
397
+ #### `rk-accordion`
398
+ **Arquivo:** `snippets/rk-accordion.liquid`
399
+ **Controller:** `assets/rk-accordion.js` → `<rk-accordion-element>`
400
+ **Descrição:** Disclosure com animação suave via Web Animations API.
401
+
402
+ | Prop | Tipo | Default |
403
+ |---|---|---|
404
+ | `title` | string | — |
405
+ | `content` | string | — |
406
+ | `open` | boolean | `false` |
407
+
408
+ ---
409
+
410
+ #### `rk-form-field`
411
+ **Arquivo:** `snippets/rk-form-field.liquid`
412
+ **Descrição:** Composição de Label + `rk-input` + mensagem de erro com acessibilidade.
413
+
414
+ | Prop | Tipo | Default |
415
+ |---|---|---|
416
+ | `name` | string | — |
417
+ | `label` | string | — |
418
+ | `type` | string | `text` |
419
+ | `error` | string | — |
420
+ | `required` | boolean | `false` |
421
+
422
+ ---
423
+
424
+ #### `rk-modal`
425
+ **Arquivo:** `snippets/rk-modal.liquid`
426
+ **Controller:** `assets/rk-modal.js` → `<rk-modal-element>`
427
+ **Descrição:** Dialog base com overlay, trap focus, ESC key e scroll lock.
428
+
429
+ | Prop | Tipo | Default |
430
+ |---|---|---|
431
+ | `id` | string | — |
432
+ | `content` | string | — |
433
+ | `title` | string | — |
434
+
435
+ **Para abrir externamente:** Usar `data-modal-open="ID_DO_MODAL"` em qualquer botão.
436
+
437
+ **Custom Events:**
438
+ - `rk:modal:open` → `{ id }`
439
+ - `rk:modal:close` → `{ id }`
440
+
441
+ ---
442
+
443
+ #### `rk-quick-add` ⚠️ EXCEÇÃO
444
+ **Arquivo:** `snippets/rk-quick-add.liquid`
445
+ **Controller:** Usa `quick-add.js` + `events.js` do **Horizon** (acoplamento deliberado)
446
+ **Descrição:** Botão "Adicionar ao Carrinho" com opção de seletor de quantidade.
447
+
448
+ | Prop | Tipo | Default | Descrição |
449
+ |---|---|---|---|
450
+ | `product` | object | — | Produto Shopify |
451
+ | `section_id` | string | — | ID da section |
452
+ | `show_quantity` | boolean | `false` | Exibe `rk-quantity` |
453
+ | `button_text` | string | `Adicionar ao Carrinho` | Texto do botão |
454
+ | `button_style` | string | `primary` | Estilo rk-button |
455
+ | `button_size` | string | `md` | Tamanho rk-button |
456
+
457
+ > **⚠️ Nota de Acoplamento:** Este é o **único componente** do framework que depende de scripts específicos do Horizon (`quick-add.js` e `events.js`) para animações de AJAX cart. Ao portar para outro tema, este componente precisa de adaptação no JS de submit.
458
+
459
+ ---
460
+
461
+ #### `rk-popover`
462
+ **Arquivo:** `snippets/rk-popover.liquid`
463
+ **Controller:** `assets/rk-popover.js` → `<rk-popover-element>`
464
+ **Descrição:** Popover flutuante acionado por clique. Suporta posicionamento inteligente com collision awareness, arrow, trap focus e fechamento por ESC/click-outside.
465
+
466
+ | Prop | Tipo | Default | Descrição |
467
+ |---|---|---|---|
468
+ | `id` | string | — | ID único do popover |
469
+ | `side` | string | `bottom` | `top` \| `bottom` \| `left` \| `right` |
470
+ | `align` | string | `center` | `start` \| `center` \| `end` |
471
+ | `side_offset` | number | `8` | Distância do trigger em px |
472
+ | `align_offset` | number | `0` | Ajuste lateral em px |
473
+ | `show_arrow` | boolean | `true` | Exibir seta indicativa |
474
+ | `title` | string | — | Título do header (opcional) |
475
+ | `description` | string | — | Descrição do header (opcional) |
476
+ | `trigger_content` | string | — | HTML do elemento trigger |
477
+ | `body` | string | — | HTML do corpo do popover |
478
+ | `custom_class` | string | — | Classes CSS extras |
479
+ | `width` | string | — | Largura do container (ex: `320px`) |
480
+
481
+ **Exemplo:**
482
+ ```liquid
483
+ {% capture popover_trigger %}
484
+ {% render 'rk-button', text: 'Opções', style: 'outline', size: 'sm' %}
485
+ {% endcapture %}
486
+ {% capture popover_body %}
487
+ <p>Conteúdo rico aqui</p>
488
+ {% endcapture %}
489
+ {% render 'rk-popover', id: 'my-pop', trigger_content: popover_trigger, body: popover_body, title: 'Configurações' %}
490
+ ```
491
+
492
+ **Custom Events:**
493
+ - `rk:popover:open` → `{ id }`
494
+ - `rk:popover:close` → `{ id }`
495
+
496
+ ---
497
+
498
+ #### `rk-scroll-area`
499
+ **Arquivo:** `snippets/rk-scroll-area.liquid`
500
+ **Controller:** `assets/rk-scroll-area.js` → `<rk-scroll-area>`
501
+ **Descrição:** Área de scroll com barras customizadas. Suporta eixo vertical, horizontal ou ambos. Três modos de visibilidade (auto, always, hover). Oculta scrollbars nativos.
502
+
503
+ | Prop | Tipo | Default | Descrição |
504
+ |---|---|---|---|
505
+ | `id` | string | — | ID único (opcional) |
506
+ | `orientation` | string | `vertical` | `vertical` \| `horizontal` \| `both` |
507
+ | `visibility` | string | `auto` | `auto` \| `always` \| `hover` |
508
+ | `height` | string | `100%` | Altura CSS do container |
509
+ | `width` | string | `100%` | Largura CSS do container |
510
+ | `content` | string | — | HTML do conteúdo interno |
511
+ | `custom_class` | string | — | Classes CSS extras |
512
+
513
+ **Exemplo:**
514
+ ```liquid
515
+ {% capture scroll_content %}
516
+ <ul>
517
+ <li>Item 1</li>
518
+ <li>Item 2</li>
519
+
520
+ </ul>
521
+ {% endcapture %}
522
+ {% render 'rk-scroll-area', height: '300px', content: scroll_content %}
523
+
524
+ {% comment %} Horizontal {% endcomment %}
525
+ {% render 'rk-scroll-area', orientation: 'horizontal', height: '200px', content: cards_html %}
526
+ ```
527
+
528
+ ---
529
+
530
+ #### `rk-drawer`
531
+ **Arquivo:** `snippets/rk-drawer.liquid`
532
+ **Controller:** `assets/rk-drawer.js` → `<rk-drawer-element>`
533
+ **Descrição:** Painel deslizante (overlay) que emerge das bordas da tela. Suporta 4 direções, drag-to-dismiss via handle, overlay click, ESC key, scroll lock e focus trap.
534
+
535
+ | Prop | Tipo | Default | Descrição |
536
+ |---|---|---|---|
537
+ | `id` | string | — | ID único do drawer |
538
+ | `side` | string | `bottom` | `top` \| `bottom` \| `left` \| `right` |
539
+ | `show_handle` | boolean | `true` | Exibir barra de arraste |
540
+ | `title` | string | — | Título do header (opcional) |
541
+ | `description` | string | — | Descrição do header (opcional) |
542
+ | `body` | string | — | HTML do corpo |
543
+ | `footer` | string | — | HTML do footer (botões de ação) |
544
+ | `custom_class` | string | — | Classes CSS extras |
545
+ | `width` | string | — | Largura do painel (left/right) |
546
+ | `height` | string | — | Altura do painel (top/bottom) |
547
+
548
+ **Para abrir externamente:** Usar `data-drawer-open="ID_DO_DRAWER"` em qualquer botão.
549
+
550
+ **Exemplo:**
551
+ ```liquid
552
+ {% capture drawer_body %}
553
+ <p>Conteúdo do drawer</p>
554
+ {% endcapture %}
555
+ {% capture drawer_footer %}
556
+ {% render 'rk-button', text: 'Confirmar', style: 'primary', full_width: true %}
557
+ {% endcapture %}
558
+ {% render 'rk-drawer', id: 'filters', side: 'bottom', title: 'Filtros', body: drawer_body, footer: drawer_footer %}
559
+
560
+ {% comment %} Sidebar à direita {% endcomment %}
561
+ {% render 'rk-drawer', id: 'cart-drawer', side: 'right', title: 'Carrinho', body: cart_html, width: '400px' %}
562
+ ```
563
+
564
+ **Custom Events:**
565
+ - `rk:drawer:open` → `{ id }`
566
+ - `rk:drawer:close` → `{ id }`
567
+
568
+ ---
569
+
570
+ #### `rk-dialog`
571
+ **Arquivo:** `snippets/rk-dialog.liquid`
572
+ **Controller:** `assets/rk-dialog.js` → `<rk-dialog-element>`
573
+ **Descrição:** Dialog/Modal centralizado com anatomia completa (Header/Body/Footer). Suporta overlay dismiss configurável, ESC key, focus trap com Tab wrapping, scroll lock, aria-labelledby/describedby, e comportamento mobile (slide-up).
574
+
575
+ | Prop | Tipo | Default | Descrição |
576
+ |---|---|---|---|
577
+ | `id` | string | — | ID único do dialog |
578
+ | `title` | string | — | Título (obrigatório para a11y) |
579
+ | `description` | string | — | Descrição do header (opcional) |
580
+ | `body` | string | — | HTML do corpo |
581
+ | `footer` | string | — | HTML do footer (botões de ação) |
582
+ | `overlay_close` | boolean | `true` | Fechar ao clicar no overlay |
583
+ | `show_close` | boolean | `true` | Exibir botão X |
584
+ | `width` | string | — | Largura do content (ex: `540px`) |
585
+ | `custom_class` | string | — | Classes CSS extras |
586
+
587
+ **Para abrir externamente:** Usar `data-dialog-open="ID_DO_DIALOG"` em qualquer botão.
588
+
589
+ **Exemplo:**
590
+ ```liquid
591
+ {% capture dialog_body %}
592
+ <p>Formulário ou conteúdo aqui</p>
593
+ {% endcapture %}
594
+ {% capture dialog_footer %}
595
+ <button class="rk-btn rk-btn--secondary rk-btn--md" data-action="close">
596
+ <span class="rk-btn__text">Cancelar</span>
597
+ </button>
598
+ {% render 'rk-button', text: 'Salvar', style: 'primary' %}
599
+ {% endcapture %}
600
+ {% render 'rk-dialog', id: 'edit-profile', title: 'Editar Perfil', description: 'Atualize suas informações.', body: dialog_body, footer: dialog_footer %}
601
+ ```
602
+
603
+ **Custom Events:**
604
+ - `rk:dialog:open` → `{ id }`
605
+ - `rk:dialog:close` → `{ id }`
606
+
607
+ **Responsividade:** Em telas ≤ 749px, converte-se automaticamente em um painel slide-up (estilo Drawer) para melhor UX mobile.
608
+
609
+ ---
610
+
611
+ #### `rk-sheet`
612
+ **Arquivo:** `snippets/rk-sheet.liquid`
613
+ **Controller:** `assets/rk-sheet.js` → `<rk-sheet-element>`
614
+ **Descrição:** Painel lateral full-viewport que desliza das bordas da tela. Diferente do Drawer (compacto), o Sheet ocupa toda a altura/largura da viewport. Ideal para filtros, formulários, navegação e dashboards.
615
+
616
+ | Prop | Tipo | Default | Descrição |
617
+ |---|---|---|---|
618
+ | `id` | string | — | ID único do sheet |
619
+ | `side` | string | `right` | `right` \| `left` \| `top` \| `bottom` |
620
+ | `size` | string | `400px` | Largura (left/right) ou altura (top/bottom) |
621
+ | `title` | string | — | Título (obrigatório para a11y) |
622
+ | `description` | string | — | Descrição do header (opcional) |
623
+ | `body` | string | — | HTML do corpo |
624
+ | `footer` | string | — | HTML do footer (botões de ação) |
625
+ | `overlay_close` | boolean | `true` | Fechar ao clicar no overlay |
626
+ | `custom_class` | string | — | Classes CSS extras |
627
+
628
+ **Para abrir externamente:** Usar `data-sheet-open="ID_DO_SHEET"` em qualquer botão.
629
+
630
+ **Exemplo:**
631
+ ```liquid
632
+ {% capture sheet_body %}
633
+ <form>Filtros aquí…</form>
634
+ {% endcapture %}
635
+ {% capture sheet_footer %}
636
+ {% render 'rk-button', text: 'Aplicar Filtros', style: 'primary', full_width: true %}
637
+ {% endcapture %}
638
+ {% render 'rk-sheet', id: 'filters', side: 'right', size: '420px', title: 'Filtros', body: sheet_body, footer: sheet_footer %}
639
+
640
+ {% comment %} Menu de navegação {% endcomment %}
641
+ {% render 'rk-sheet', id: 'nav-menu', side: 'left', title: 'Menu', body: nav_html %}
642
+ ```
643
+
644
+ **Custom Events:**
645
+ - `rk:sheet:open` → `{ id }`
646
+ - `rk:sheet:close` → `{ id }`
647
+
648
+ **Responsividade:** Sheets left/right ocupam 100vw em mobile (≤ 749px).
649
+
650
+ ---
651
+
652
+ #### `rk-table`
653
+ **Arquivo:** `snippets/rk-table.liquid`
654
+ **Controller:** Nenhum (Apenas CSS)
655
+ **Descrição:** Wrapper responsivo para tabelas de dados que utilizam HTML semântico. Garante rolagem horizontal sem quebra de layout no mobile e inclui estilos padronizados Shadcn/UI (bordas sutis, hover, alinhamentos).
656
+
657
+ | Prop | Tipo | Default | Descrição |
658
+ |---|---|---|---|
659
+ | `content` | string | — | Conteúdo HTML interno da tabela (`thead`, `tbody`) |
660
+ | `striped` | boolean | `false` | Se `true`, intercala as cores de fundo nas linhas |
661
+ | `custom_class`| string | — | Classes extras para o wrapper |
662
+
663
+ **Exemplo:**
664
+ ```liquid
665
+ {% capture table_content %}
666
+ <thead>
667
+ <tr>
668
+ <th>Fatura</th>
669
+ <th>Status</th>
670
+ <th class="rk-text-right">Valor</th>
671
+ </tr>
672
+ </thead>
673
+ <tbody>
674
+ <tr>
675
+ <td>INV001</td>
676
+ <td>Paga</td>
677
+ <td class="rk-text-right">R$ 250,00</td>
678
+ </tr>
679
+ <tr class="rk-table__row--selected">
680
+ <td>INV002</td>
681
+ <td>Pendente</td>
682
+ <td class="rk-text-right">R$ 150,00</td>
683
+ </tr>
684
+ </tbody>
685
+ {% endcapture %}
686
+
687
+ {% render 'rk-table', content: table_content, striped: true %}
688
+ ```
689
+
690
+ ---
691
+
692
+ #### `rk-tabs`
693
+ **Arquivo:** `snippets/rk-tabs.liquid`
694
+ **Controller:** `assets/rk-tabs.js` → `<rk-tabs-element>`
695
+ **Descrição:** Wrapper responsivo de abas (Tabs) que utiliza WAI-ARIA para navegação via teclado (Setas, Home, End).
696
+
697
+ | Prop | Tipo | Default | Descrição |
698
+ |---|---|---|---|
699
+ | `id` | string | `'rk-tabs'` | ID único do wrapper (para acessibilidade) |
700
+ | `triggers` | string | — | Conteúdo HTML com os botões `[role="tab"]` |
701
+ | `content` | string | — | Conteúdo HTML com os painéis `[role="tabpanel"]` |
702
+ | `default_value` | string | — | O ID da aba que inicia aberta |
703
+ | `orientation` | string | `'horizontal'` | Direção (`horizontal` ou `vertical`) |
704
+ | `custom_class` | string | — | Classes CSS extras para o wrapper |
705
+
706
+ **Exemplo:**
707
+ ```liquid
708
+ {% capture tabs_triggers %}
709
+ <button class="rk-tabs__trigger" role="tab" aria-controls="panel-1" id="tab-1">Descrição</button>
710
+ <button class="rk-tabs__trigger" role="tab" aria-controls="panel-2" id="tab-2">Especificações</button>
711
+ {% endcapture %}
712
+
713
+ {% capture tabs_content %}
714
+ <div class="rk-tabs__panel" role="tabpanel" id="panel-1" aria-labelledby="tab-1">
715
+ <p>Texto 1</p>
716
+ </div>
717
+ <div class="rk-tabs__panel" role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
718
+ <p>Texto 2</p>
719
+ </div>
720
+ {% endcapture %}
721
+
722
+ {% render 'rk-tabs', id: 'product-tabs', triggers: tabs_triggers, content: tabs_content, default_value: 'tab-1' %}
723
+ ```
724
+
725
+ **Custom Events:**
726
+ - `rk:tabs:change` → `{ activeTabId }`
727
+
728
+ **Responsividade:** Em `horizontal`, caso exceda a tela no mobile, as abas recebem rolagem lateral nativa (`overflow-x`).
729
+
730
+ ---
731
+
732
+ #### `rk-toggle` e `rk-toggle-group`
733
+ **Arquivo:** `snippets/rk-toggle.liquid` e `snippets/rk-toggle-group.liquid`
734
+ **Controller:** `assets/rk-toggle.js` → `<rk-toggle-element>` e `<rk-toggle-group>`
735
+ **Descrição:** Botões de alternância de estado (Toggle) integrados com acessibilidade via `aria-pressed`. Podem ser utilizados de forma isolada ou agrupados de forma mutuamente exclusiva ou seleção múltipla.
736
+
737
+ **Props (rk-toggle):**
738
+ | Prop | Tipo | Default | Descrição |
739
+ |---|---|---|---|
740
+ | `value` | string | — | Valor representativo do toggle |
741
+ | `id` | string | — | ID único |
742
+ | `text` | string | — | Texto visível |
743
+ | `icon` | string | — | HTML do ícone (SVG) |
744
+ | `variant` | string | `'default'` | `'default'` ou `'outline'` |
745
+ | `size` | string | `'md'` | `'sm'`, `'md'`, `'lg'` |
746
+ | `pressed` | boolean | `false` | Se inicia pressionado |
747
+ | `disabled` | boolean | `false` | Estado desabilitado |
748
+ | `aria_label` | string | — | Necessário caso tenha apenas ícone |
749
+
750
+ **Props (rk-toggle-group):**
751
+ | Prop | Tipo | Default | Descrição |
752
+ |---|---|---|---|
753
+ | `type` | string | `'single'` | `'single'` (rádio/exclusivo) ou `'multiple'` (checkbox) |
754
+ | `toggles` | string | — | O HTML contendo os `<rk-toggle>` |
755
+
756
+ **Exemplo Isolado:**
757
+ ```liquid
758
+ {% render 'rk-toggle', icon: my_svg, aria_label: 'Favoritar', pressed: false, variant: 'outline' %}
759
+ ```
760
+
761
+ **Exemplo em Grupo:**
762
+ ```liquid
763
+ {% capture format_toggles %}
764
+ {% render 'rk-toggle', value: 'bold', icon: icon_bold, aria_label: 'Bold', variant: 'outline' %}
765
+ {% render 'rk-toggle', value: 'italic', icon: icon_italic, aria_label: 'Italic', variant: 'outline' %}
766
+ {% endcapture %}
767
+
768
+ {% render 'rk-toggle-group', type: 'multiple', toggles: format_toggles %}
769
+ ```
770
+
771
+ **Custom Events:**
772
+ - `rk:toggle:change` → `{ pressed, value }`
773
+ - `rk:toggle-group:change` → `{ value }` (Retorna string simples se `single`, ou array se `multiple`)
774
+
775
+ ---
776
+
777
+ #### `rk-progress`
778
+ **Arquivo:** `snippets/rk-progress.liquid`
779
+ **Controller:** `assets/rk-progress.js` → `<rk-progress-element>`
780
+ **Descrição:** Barra de progresso visual (Progress Bar) puramente estética mas com gestão automatizada de `transform` via CSS para 60fps, acoplada as diretrizes técnicas do WAI-ARIA `role="progressbar"`.
781
+
782
+ | Prop | Tipo | Default | Descrição |
783
+ |---|---|---|---|
784
+ | `value` | number | `0` | Progresso atual |
785
+ | `max` | number | `100` | Progresso máximo (Opcional, teto do cálculo) |
786
+ | `id` | string | — | ID único |
787
+ | `aria_label` | string | — | Descrição para leitores de tela |
788
+ | `custom_class`| string | — | Customização de cores e tamanhos via utilitário |
789
+
790
+ **Exemplo:**
791
+ ```liquid
792
+ {% render 'rk-progress', value: 33, aria_label: 'Frete Grátis' %}
793
+ ```
794
+
795
+ ---
796
+
797
+ #### `rk-collapsible`
798
+ **Arquivo:** `snippets/rk-collapsible.liquid`
799
+ **Controller:** `assets/rk-collapsible.js` → `<rk-collapsible-element>`
800
+ **Descrição:** Componente individual que esconde ou revela seu conteúdo (semelhante a um item de Accordion isolado). Utiliza `CSS Grid 0fr` para transições fluídas de `height`.
801
+
802
+ | Prop | Tipo | Default | Descrição |
803
+ |---|---|---|---|
804
+ | `id` | string | — | ID único e identificador ARIA |
805
+ | `trigger` | string | — | O conteúdo do botão de alternância |
806
+ | `content` | string | — | O conteúdo que será mostrado/escondido |
807
+ | `open` | boolean | `false` | Se já inicia aberto |
808
+ | `custom_class` | string | — | Classes CSS extras na raiz |
809
+
810
+ **Custom Events:**
811
+ - `rk:collapsible:change` → `{ isOpen }`
812
+ - Eventos de controle externo:
813
+ - Dispare `rk:collapsible:open` no elemento para abri-lo de fora
814
+ - Dispare `rk:collapsible:close` no elemento para fechá-lo de fora
815
+
816
+ ---
817
+
818
+ #### `rk-carousel`
819
+ **Arquivo:** `snippets/rk-carousel.liquid`
820
+ **Controller:** `assets/rk-carousel.js` → `<rk-carousel-element>`
821
+ **Descrição:** Wrapper responsivo baseado na biblioteca Swiper.js. O Web Component realiza a importação assíncrona da biblioteca e executa tanto a inicialização (`new Swiper`) quanto a limpeza de estado (`destroy`).
822
+
823
+ | Prop | Tipo | Default | Descrição |
824
+ |---|---|---|---|
825
+ | `content` | string | — | Slides dentro do formato `<div class="swiper-slide">...</div>` |
826
+ | `id` | string | — | ID único |
827
+ | `show_arrows` | boolean | `true` | Exibe Setas de Navegação nativas |
828
+ | `show_pagination` | boolean | `true` | Exibe Dots na base |
829
+ | `loop` | boolean | `false` | Loop infinito |
830
+ | `autoplay` | boolean | `false` | Avanço automático |
831
+ | `autoplay_delay` | number | `3000` | Velocidade do autoplay |
832
+ | `gap` | number | `16` | Distância entre os slides |
833
+ | `desktop_items` | number | `3` | Qtde de produtos exibida `(>=768px)` |
834
+ | `mobile_items` | number | `1` | Qtde de produtos exibida `(<768px)` |
835
+ | `options_json` | string | — | String `JSON.stringify` para sobrescrever diretamente as configs nativas do Swiper |
836
+
837
+ **Custom Events:**
838
+ - `rk:carousel:init` → Emite a instância ativa `{ swiper }` de modo que a loja possa registrar callbacks customizados de deslize do slide.
839
+
840
+ ---
841
+
842
+ #### `rk-bottom-app-bar`
843
+ **Arquivo:** `snippets/rk-bottom-app-bar.liquid`
844
+ **Controller:** `assets/rk-bottom-app-bar.js` → `<rk-bottom-app-bar-element>`
845
+ **Descrição:** Componente de App Bar Menubar estilo iOS/Android. Provê navegação WAI-ARIA com _roving tabindex_ entre itens e FAB (Floating Action Button). Baseado nos preceitos de Glassmorphism moderno.
846
+
847
+ | Prop | Tipo | Default | Descrição |
848
+ |---|---|---|---|
849
+ | `content` | string | — | Os `<button role="menuitem">` injetados na barra inferior |
850
+ | `fab` | string | — | Html do Floating Action Button injetável na quebra frontal superior |
851
+ | `alignment` | string | `distributed` | `distributed` (Espaçado pelas pontas) ou `grouped` (Alinhado com gap esquerdo) |
852
+ | `id` | string | `rk-bottom-app-bar` | ID para referências WAI |
853
+ | `custom_class` | string | — | Classes extras p/ overrides |
854
+
855
+ **Custom Events:**
856
+ - (Comportamento de teclado apenas: Setas navegam linearmente entre cada `<button role="menuitem">` filho)
857
+
858
+ ---
859
+
860
+ ### 5.3 Serviços
861
+
862
+ #### `rk-external-assets`
863
+ **Arquivo:** `snippets/rk-external-assets.liquid`
864
+ **Descrição:** Módulo de gerenciamento para injetar CDNs, preconnects e bibliotecas externas (ex. GSAP, Anime.js) no `<head>` e `<body>` escrevendo explicitamente as tags originais do HTML. Garante máxima performance com preconnects organizados sem poluir o `theme.liquid`.
865
+
866
+ | Prop | Tipo | Default | Descrição |
867
+ |---|---|---|---|
868
+ | `location` | string | `head` | Define se imprime os assets do `head` (preconnects, links css) ou `body` (scripts de interação) |
869
+
870
+ **Exemplo:**
871
+ ```liquid
872
+ <head>
873
+ {% render 'rk-external-assets', location: 'head' %}
874
+ </head>
875
+ <body>
876
+ ...
877
+ {% render 'rk-external-assets', location: 'body' %}
878
+ </body>
879
+ ```
880
+
881
+ ---
882
+
883
+ #### `rk-scripts`
884
+ **Arquivo:** `snippets/rk-scripts.liquid`
885
+ **Descrição:** Módulo de carregamento concentrado que itera sobre a lista de todos os Web Components (`.js`) das moléculas do framework e provê inclusão performática usando a diretriz estrutural de desacoplamento SOLID, evitando injeções verbosas no `theme.liquid`.
886
+
887
+ **Exemplo:**
888
+ ```liquid
889
+ {% render 'rk-scripts' %}
890
+ ```
891
+
892
+ ---
893
+
894
+ ## 6. Controllers JavaScript (Web Components)
895
+
896
+ ### 6.1 `rk-quantity.js` → `<rk-quantity-selector>`
897
+
898
+ | Método | Descrição |
899
+ |---|---|
900
+ | `step(direction)` | Incrementa (+1) ou decrementa (-1) o valor |
901
+ | `clampValue()` | Garante que o valor respeita min/max |
902
+ | `updateButtons()` | Habilita/desabilita botões nos limites |
903
+ | `dispatchChange()` | Emite `rk:quantity:change` com o novo valor |
904
+
905
+ ### 6.2 `rk-modal.js` → `<rk-modal-element>`
906
+
907
+ | Método | Descrição |
908
+ |---|---|
909
+ | `open()` | Abre o modal, trava scroll e foca |
910
+ | `close()` | Fecha o modal, restaura scroll e focus |
911
+ | `isOpen()` | Verifica se o modal está ativo |
912
+
913
+ ### 6.3 `rk-accordion.js` → `<rk-accordion-element>`
914
+
915
+ | Método | Descrição |
916
+ |---|---|
917
+ | `open()` | Abre com animação de expansão |
918
+ | `shrink()` | Fecha com animação de contração |
919
+ | `onAnimationFinish(open)` | Cleanup ao fim da animação |
920
+
921
+ ### 6.4 `rk-popover.js` → `<rk-popover-element>`
922
+
923
+ | Método | Descrição |
924
+ |---|---|
925
+ | `open()` | Abre o popover, posiciona e foca |
926
+ | `close()` | Fecha o popover, restaura focus |
927
+ | `toggle()` | Alterna entre aberto/fechado |
928
+ | `isOpen()` | Verifica se o popover está ativo |
929
+ | `_reposition()` | Recalcula posição (collision aware) |
930
+ | `_resolveSide()` | Determina o lado ideal (auto-flip) |
931
+
932
+ ### 6.5 `rk-scroll-area.js` → `<rk-scroll-area>`
933
+
934
+ | Método | Descrição |
935
+ |---|---|
936
+ | `_recalculate()` | Recalcula tamanho dos thumbs |
937
+ | `_syncThumbs()` | Sincroniza posição dos thumbs com scroll |
938
+ | `_onPointerDown()` | Inicia drag no thumb |
939
+ | `_onPointerMove()` | Move scroll durante drag |
940
+ | `_onPointerUp()` | Finaliza drag |
941
+ | `_onTrackClick()` | Jump-to-position no track |
942
+ | `_showScrollbars()` | Exibe scrollbars |
943
+ | `_scheduleHide()` | Agenda ocultar scrollbars (1.2s) |
944
+
945
+ ### 6.6 `rk-drawer.js` → `<rk-drawer-element>`
946
+
947
+ | Método | Descrição |
948
+ |---|---|
949
+ | `open()` | Abre o drawer, trava scroll e foca |
950
+ | `close()` | Fecha o drawer, restaura scroll e focus |
951
+ | `isOpen()` | Verifica se o drawer está ativo |
952
+ | `_onPointerDown()` | Inicia drag-to-dismiss |
953
+ | `_onPointerMove()` | Move painel durante arraste |
954
+ | `_onPointerUp()` | Finaliza arraste (dismiss ou snap-back) |
955
+
956
+ ### 6.7 `rk-dialog.js` → `<rk-dialog-element>`
957
+
958
+ | Método | Descrição |
959
+ |---|---|
960
+ | `open()` | Abre o dialog, trava scroll e foca |
961
+ | `close()` | Fecha o dialog, restaura scroll e focus |
962
+ | `isOpen()` | Verifica se o dialog está ativo |
963
+ | `_trapFocus(e)` | Tab trap: wraps entre first/last focusable |
964
+ | `_onKeyDown(e)` | ESC dismiss + Tab trap handler |
965
+
966
+ ### 6.8 `rk-sheet.js` → `<rk-sheet-element>`
967
+
968
+ | Método | Descrição |
969
+ |---|---|
970
+ | `open()` | Abre o sheet, trava scroll e foca |
971
+ | `close()` | Fecha o sheet, restaura scroll e focus |
972
+ | `isOpen()` | Verifica se o sheet está ativo |
973
+ | `_trapFocus(e)` | Tab trap: wraps entre first/last focusable |
974
+ | `_onKeyDown(e)` | ESC dismiss + Tab trap handler |
975
+
976
+ ### 6.9 `rk-tabs.js` → `<rk-tabs-element>`
977
+
978
+ | Método | Descrição |
979
+ |---|---|
980
+ | `activateTab(id, focus)` | Ativa a tab correspondente e oculta demais painéis |
981
+ | `_onKeyDown()` | Gerencia navegação de teclado (Setas, Home, End) |
982
+
983
+ ### 6.10 `rk-toggle.js` → `<rk-toggle-element>` e `<rk-toggle-group>`
984
+
985
+ | Método (Toggle) | Descrição |
986
+ |---|---|
987
+ | `setPressed(value)` | Define estado manual (`true`/`false`) via `aria-pressed` |
988
+ | `toggle()` | Alterna o estado (on/off) nativo |
989
+
990
+ | Método (ToggleGroup) | Descrição |
991
+ |---|---|
992
+ | `_handleSingle()` | Lógica de rádio (desmarca os outros) |
993
+ | `_handleMultiple()` | Lógica de checkbox |
994
+ | `_emitChange()` | Dispara o valor final atualizado do grupo |
995
+
996
+ ### 6.11 `rk-progress.js` → `<rk-progress-element>`
997
+
998
+ | Método / Getter | Descrição |
999
+ |---|---|
1000
+ | `value` (getter/setter) | Define altera valor current via dataset |
1001
+ | `max` (getter/setter) | Define teto via dataset |
1002
+ | `_updateIndicator()` | Calcula `(value/max)*100` e converte em `transform: translateX()` |
1003
+
1004
+ ### 6.12 `rk-collapsible.js` → `<rk-collapsible-element>`
1005
+
1006
+ | Método | Descrição |
1007
+ |---|---|
1008
+ | `open()` | Expande através de classes do CSS Grid |
1009
+ | `close()` | Oculta adicionando delay de transition antes de display:none |
1010
+ | `toggle()` | Alterna estado atual |
1011
+ | `_syncState()` | Gerencia `<rk-collapsible__content--expanded>`, foca/desfoca tabindex |
1012
+
1013
+ ### 6.13 `rk-carousel.js` → `<rk-carousel-element>`
1014
+
1015
+ | Método / Feature | Descrição |
1016
+ |---|---|
1017
+ | `_loadSwiper()` | Injeta dinamicamente CSS e JS da CDN da Swiper caso não seja achada |
1018
+ | `_initSwiper()` | Combina opções em dataset com o object `this.options` do Swiper |
1019
+ | `ResizeObserver` | Garante que se o Carousel for redimensionado (ex. em tabs) ele ajuste `swiper.update()` |
1020
+
1021
+ ### 6.14 `rk-bottom-app-bar.js` → `<rk-bottom-app-bar-element>`
1022
+
1023
+ | Método / Feature | Descrição |
1024
+ |---|---|
1025
+ | `_onKeyDown(e)` | Ouve Setas Direita/Esquerda para mover Foco entre itens `[role="menuitem"]` |
1026
+ | `Tabindex Manager` | Troca dinamicamente tabindex="-1" e "0" mantendo padrão Roving Tabindex A11y |
1027
+
1028
+ ---
1029
+
1030
+ ## 7. Guia de Integração com o Tema
1031
+
1032
+ ### 7.1 Injetar Settings
1033
+
1034
+ Copiar o conteúdo de `/rook-framework/config/rk-settings_schema.json` e inserir como um novo objeto dentro do array do `config/settings_schema.json` do tema:
1035
+
1036
+ ```json
1037
+ [
1038
+ { "name": "theme_info", ... },
1039
+ { "name": "t:names.colors", ... },
1040
+ // ... seções do tema ...
1041
+ { "name": "⚡ Rook UI Core Framework", "settings": [ ... ] } // ← adicionar aqui
1042
+ ]
1043
+ ```
1044
+
1045
+ ### 7.2 Carregar Assets
1046
+
1047
+ Adicione ao `layout/theme.liquid` (dentro do `<head>`):
1048
+
1049
+ ```liquid
1050
+ {{ 'rk-framework-tokens.css' | asset_url | stylesheet_tag }}
1051
+ {{ 'rk-framework-core.css' | asset_url | stylesheet_tag }}
1052
+
1053
+ {% render 'rk-external-assets', location: 'head' %}
1054
+ ```
1055
+
1056
+ E antes do `</body>`:
1057
+
1058
+ ```liquid
1059
+ {% render 'rk-external-assets', location: 'body' %}
1060
+ {% render 'rk-scripts' %}
1061
+ ```
1062
+
1063
+ ### 7.3 Copiar Snippets
1064
+
1065
+ Mover todos os arquivos de `/rook-framework/snippets/` para `/snippets/` do tema.
1066
+
1067
+ ### 7.4 Copiar Assets
1068
+
1069
+ Mover todos os arquivos de `/rook-framework/assets/` para `/assets/` do tema.
1070
+
1071
+ ---
1072
+
1073
+ ## 8. Extensibilidade — Organismos (Futuro)
1074
+
1075
+ O framework foi projetado para facilmente receber **Organismos** (componentes compostos) no futuro:
1076
+
1077
+ ```
1078
+ /rook-framework/
1079
+ └── snippets/
1080
+ ├── rk-product-card.liquid ← Organismo: Card de produto
1081
+ ├── rk-product-grid.liquid ← Organismo: Grid de produtos
1082
+ ├── rk-header-nav.liquid ← Organismo: Navegação de header
1083
+ └── rk-footer.liquid ← Organismo: Footer completo
1084
+ ```
1085
+
1086
+ Cada Organismo **compõe** Átomos e Moléculas existentes:
1087
+ ```liquid
1088
+ {%- comment -%} Organismo: rk-product-card {%- endcomment -%}
1089
+ {% render 'rk-image', image: product.featured_image %}
1090
+ {% render 'rk-typography', text: product.title, tag: 'h3', size: 'lg' %}
1091
+ {% render 'rk-price', product: product %}
1092
+ {% render 'rk-installments', price: product.selected_or_first_available_variant.price %}
1093
+ {% render 'rk-pix-discount', price: product.selected_or_first_available_variant.price %}
1094
+ {% render 'rk-quick-add', product: product, section_id: section.id %}
1095
+ ```
1096
+
1097
+ ---
1098
+
1099
+ ## 9. Regras de Contribuição
1100
+
1101
+ 1. **Sem `<style>` ou `{% style %}`** dentro de snippets — todo CSS vai no `rk-framework-core.css`
1102
+ 2. **Sem `!important`** — resolver por especificidade BEM
1103
+ 3. **`{% doc %}` obrigatório** em todo snippet com parâmetros documentados
1104
+ 4. **Web Components** devem sempre verificar `if (!customElements.get())` antes de registrar
1105
+ 5. **Custom Events** com prefixo `rk:` seguido do componente (e.g. `rk:quantity:change`)
1106
+ 6. **Nenhum acoplamento** com scripts específicos do tema (exceto `rk-quick-add`)
1107
+ 7. **CSS Variables** para qualquer valor que possa mudar — nunca valores hardcoded
1108
+ 8. **Acessibilidade primeiro**: `aria-label`, `role`, `aria-hidden`, label associados a inputs
1109
+
1110
+ ---
1111
+
1112
+ ## 10. Style Snippets (Sistema de Layout Portável)
1113
+
1114
+ O framework inclui **snippets de estilo** que geram CSS variables inline, equivalentes portáveis dos snippets nativos do Horizon (`size-style.liquid`, `spacing-style.liquid`, `gap-style.liquid`).
1115
+
1116
+ ### 10.1 `rk-size-style.liquid`
1117
+
1118
+ Gera variáveis de largura/altura com suporte a mobile.
1119
+
1120
+ | CSS Variable | Descrição |
1121
+ |---|---|
1122
+ | `--rk-width` | Largura do elemento |
1123
+ | `--rk-height` | Altura do elemento |
1124
+ | `--rk-width-mobile` | Largura mobile override |
1125
+ | `--rk-width-mobile-min` | Largura mínima mobile |
1126
+
1127
+ **Settings esperadas:**
1128
+ - `width`: `fill` | `fit-content` | `custom` | valor CSS
1129
+ - `custom_width`: número (percentual)
1130
+ - `height`: `auto` | `fill` | `custom` | valor CSS
1131
+ - `custom_height`: número (percentual)
1132
+ - `width_mobile`: override mobile (opcional)
1133
+ - `custom_width_mobile`: número (percentual mobile)
1134
+
1135
+ **Exemplo:**
1136
+ ```liquid
1137
+ <div class="rk-size-style" style="{% render 'rk-size-style', settings: block.settings %}">
1138
+ ```
1139
+
1140
+ ### 10.2 `rk-spacing-style.liquid`
1141
+
1142
+ Gera variáveis de padding com **responsive scaling** automático.
1143
+
1144
+ | CSS Variable | Setting Key | Descrição |
1145
+ |---|---|---|
1146
+ | `--rk-pt` | `padding-block-start` | Padding topo |
1147
+ | `--rk-pb` | `padding-block-end` | Padding base |
1148
+ | `--rk-ps` | `padding-inline-start` | Padding esquerda |
1149
+ | `--rk-pe` | `padding-inline-end` | Padding direita |
1150
+
1151
+ Valores acima de 20px são automaticamente escalados via `--rk-spacing-scale`.
1152
+
1153
+ **Exemplo:**
1154
+ ```liquid
1155
+ <div class="rk-spacing-style" style="{% render 'rk-spacing-style', settings: block.settings %}">
1156
+ ```
1157
+
1158
+ ### 10.3 `rk-spacing-padding.liquid`
1159
+
1160
+ Versão simplificada sem responsive scaling (equivalente ao `spacing-padding.liquid` do Horizon).
1161
+
1162
+ ### 10.4 `rk-gap-style.liquid`
1163
+
1164
+ Gera variável de gap com scaling.
1165
+
1166
+ | Param | Tipo | Default | Descrição |
1167
+ |---|---|---|---|
1168
+ | `value` | number | — | Valor do gap em px |
1169
+ | `name` | string | `gap` | Sufixo da variável CSS |
1170
+ | `scale_min` | number | `24` | Threshold para scaling |
1171
+ | `disable_scaling` | boolean | `false` | Desabilita scaling |
1172
+
1173
+ **Exemplo:**
1174
+ ```liquid
1175
+ <div class="rk-gap-style" style="{% render 'rk-gap-style', value: 28 %}">
1176
+ ```
1177
+
1178
+ ### 10.5 `rk-layout-style.liquid`
1179
+
1180
+ Gera variáveis de layout flexbox.
1181
+
1182
+ | CSS Variable | Descrição |
1183
+ |---|---|
1184
+ | `--rk-flex-direction` | Direção do flex |
1185
+ | `--rk-flex-wrap` | Wrap do flex |
1186
+ | `--rk-h-align` | Alinhamento horizontal |
1187
+ | `--rk-v-align` | Alinhamento vertical |
1188
+ | `--rk-gap` | Gap entre itens |
1189
+
1190
+ ### 10.6 Classes CSS Utilitárias
1191
+
1192
+ O `rk-framework-core.css` inclui classes que consomem estas variáveis:
1193
+
1194
+ | Classe | Consome | Descrição |
1195
+ |---|---|---|
1196
+ | `.rk-block` | size + spacing | Bloco genérico com width/height/padding |
1197
+ | `.rk-size-style` | size | Apenas width/height com mobile |
1198
+ | `.rk-spacing-style` | spacing | Apenas padding 4 lados |
1199
+ | `.rk-gap-style` | gap | Apenas gap |
1200
+ | `.rk-layout-style` | layout + gap | Container flex completo |
1201
+
1202
+ ### 10.7 Responsive Scaling
1203
+
1204
+ O sistema de scaling é definido em `rk-framework-tokens.css`:
1205
+
1206
+ | Viewport | `--rk-spacing-scale` | `--rk-gap-scale` |
1207
+ |---|---|---|
1208
+ | > 989px | `1.0` | `1.0` |
1209
+ | 750-989px | `0.85` | `0.85` |
1210
+ | < 750px | `0.7` | `0.7` |
1211
+
1212
+ ---
1213
+
1214
+ *Versão: 1.1.0 — Última atualização: 05/03/2026*