- All SKILL.md files now <500 lines (avg reduction 69%) - Detailed content extracted to references/ subdirectories - Frontmatter standardised: only name + description (Anthropic standard) - New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator - Design skills: anti-slop guidelines, premium-proposals reference - Removed non-standard frontmatter fields (triggers, version, author, category) Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao, core-tools, negocio, perfex-dev, wordpress, design-media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.7 KiB
4.7 KiB
React - Composition Patterns (Vercel Engineering)
Padroes de composicao para componentes React escalaveis. Fonte: Vercel composition-patterns.
Regra #1: Evitar Boolean Props (CRITICAL)
// NAO: Booleans duplicam estados possiveis
<Composer isThread isEditing={false} showAttachments showFormatting={false} />
// SIM: Variantes explicitas
<ThreadComposer channelId="abc" />
<EditMessageComposer messageId="xyz" />
<ForwardMessageComposer messageId="123" />
Cada boolean duplica os estados possiveis. 5 booleans = 32 combinacoes, maioria impossivel.
Regra #2: Compound Components com Context (HIGH)
// Compound Components: context partilhado, composicao explicita
const ComposerContext = createContext<ComposerContextValue | null>(null)
function ComposerFrame({ children }: { children: React.ReactNode }) {
return <form>{children}</form>
}
function ComposerInput() {
const { state, actions: { update }, meta } = use(ComposerContext)
return (
<TextInput
ref={meta.inputRef}
value={state.input}
onChangeText={(text) => update(s => ({ ...s, input: text }))}
/>
)
}
// Exportar como compound
const Composer = {
Frame: ComposerFrame,
Input: ComposerInput,
Submit: ComposerSubmit,
Footer: ComposerFooter,
}
// Uso: composicao clara
<Composer.Frame>
<Composer.Input />
<Composer.Footer>
<Composer.Submit />
</Composer.Footer>
</Composer.Frame>
Regra #3: State em Providers (HIGH)
// NAO: Estado preso dentro do componente
function ForwardComposer() {
const [state, setState] = useState(initialState)
return <Composer.Frame>...</Composer.Frame>
}
// SIM: State lifted para Provider
function ForwardProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = useState(initialState)
const submit = useForwardMessage()
const inputRef = useRef(null)
return (
<Composer.Provider
state={state}
actions={{ update: setState, submit }}
meta={{ inputRef }}
>
{children}
</Composer.Provider>
)
}
// Qualquer componente dentro do Provider acede ao state
function ForwardDialog() {
return (
<ForwardProvider>
<Dialog>
<ForwardComposer />
<MessagePreview />
<ForwardButton />
</Dialog>
</ForwardProvider>
)
}
function ForwardButton() {
const { actions } = use(ComposerContext)
return <Button onPress={actions.submit}>Forward</Button>
}
Principio chave: O boundary do Provider e o que importa, nao o nesting visual.
Regra #4: Interface Generica para Dependency Injection (HIGH)
// Definir interface generica: state + actions + meta
interface ComposerContextValue {
state: { input: string; attachments: Attachment[]; isSubmitting: boolean }
actions: { update: (fn: (s: State) => State) => void; submit: () => void }
meta: { inputRef: React.RefObject<TextInput> }
}
// Multiplos providers implementam a MESMA interface
function ChannelProvider({ channelId, children }) {
const { state, update, submit } = useGlobalChannel(channelId)
return <Composer.Provider state={state} actions={{ update, submit }}>{children}</Composer.Provider>
}
function ForwardProvider({ children }) {
const [state, setState] = useState(initialState)
return <Composer.Provider state={state} actions={{ update: setState, submit: forward }}>{children}</Composer.Provider>
}
// O mesmo Composer.Input funciona com AMBOS os providers
Principio: UI = pecas reutilizaveis. State = injectado pelo provider. Trocar provider, manter UI.
Regra #5: Children > Render Props (MEDIUM)
// NAO: Render props (inflexivel)
<Composer
renderHeader={() => <Header />}
renderFooter={() => <><Formatting /><Emojis /></>}
/>
// SIM: Children (composicao natural)
<Composer.Frame>
<Header />
<Composer.Input />
<Composer.Footer>
<Formatting />
<Emojis />
</Composer.Footer>
</Composer.Frame>
// Excepcao: render props quando parent passa dados
<List data={items} renderItem={({ item }) => <Item item={item} />} />
Regra #6: React 19 APIs (MEDIUM)
// React 19: ref como prop normal (sem forwardRef)
function Input({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />
}
// React 19: use() em vez de useContext()
const value = use(MyContext) // pode ser chamado condicionalmente
Checklist Composicao
- Zero boolean props para variantes (usar componentes explicitos)
- Compound components com context partilhado
- State em Provider (nao dentro do componente UI)
- Interface generica (state/actions/meta)
- Children para composicao, render props so para data passthrough
- React 19:
use()e ref como prop