@dloizides/ui-buttons
v1.3.0
Published
Themable, brand-agnostic React Native (RN-web) button kit  one Button with five variants (primary/secondary/outline/ghost/danger) × three sizes (sm/md/lg), promoted from the byte-identical erevna-web/katalogos-web core/Button twins. Shares the
Maintainers
Readme
@dloizides/ui-buttons
Themable, brand-agnostic React Native (RN-web) button kit for the dloizides.com
portfolio. One Button with five variants (primary / secondary / outline / ghost
/ danger) and three sizes (sm / md / lg), promoted from the byte-identical
erevna-web / katalogos-web core/Button twins. Colours come from the shared
@dloizides/ui-feedback UI context (useUi) — mount one UiProvider at your app root
and buttons pick up your theme automatically.
Install
npm install @dloizides/ui-buttons @dloizides/ui-feedbackPeer dependencies: @dloizides/ui-feedback >= 1.2.0, react >= 18, react-native >= 0.74
(use react-native-web on web).
Usage
import { Button } from '@dloizides/ui-buttons';
<Button
variant="primary"
size="md"
label="Save"
onPress={onSave}
loading={isSaving}
testID="save-button"
accessibilityLabel="Save"
accessibilityHint="Saves your changes"
/>
// Optional leading icon — receives the computed foreground colour so it matches the label:
<Button
variant="ghost"
label="Export"
renderIcon={(color) => <SvgIcon name="download" color={color} />}
onPress={onExport}
testID="export-button"
accessibilityLabel="Export"
accessibilityHint="Exports the list"
/>The injected theme needs palette.primary['500'], semantic.error['500'], and
colors.{surface,text,border} — supplied via @dloizides/ui-feedback's provider. Without a
provider the button falls back to that package's neutral default theme.
Async auto-loading
When onPress returns a Promise, the button drives its own loading state — no separate
isSaving boolean needed. It shows the spinner and disables itself while the promise is
pending, then clears in a finally on resolve or reject. Rejections are not swallowed:
any .catch your handler attached still runs.
// The button spins for the duration of the async action, then clears automatically.
<Button
label="Save"
onPress={async () => {
await saveMutation.mutateAsync(values); // spinner shows until this settles
}}
testID="save-button"
accessibilityLabel="Save"
accessibilityHint="Saves your changes"
/>- A synchronous
onPressnever auto-loads (behaves exactly as before). - Pass the explicit
loadingprop to take manual (controlled) control — it wins over the auto-detected state. - Pass
autoLoading={false}to opt out entirely. - Presses are ignored while the button is already busy (no double submit).
Variants
| variant | fill | text / icon |
|---------|------|-------------|
| primary | palette.primary['500'] | white |
| danger | semantic.error['500'] | white |
| secondary | colors.surface + border | colors.text |
| outline | transparent + primary border | primary |
| ghost | transparent | primary |
License
MIT
