@get-asset/sdk

Receipts Threshold

A settings row for the receipt-request rule: a label and its explanation on one side, a money threshold and an on/off switch on the other. ReceiptsThreshold is headless about storage— it neither reads nor writes the setting, it edits the values it's handed and reports every change back through onAmountChange / onEnabledChange. It makes no API request of its own.

Preview

Loading preview…

Anatomy

Import the primitive and compose the parts you need.

<ReceiptsThreshold.Root
title="Auto-request Receipts"
subtitle="You'll be asked for a receipt on anything over this amount."
amount={settings.receiptThreshold}
currency={settings.currency}
enabled={settings.autoRequestReceipts}
onAmountChange={amount => save({ receiptThreshold: amount })}
onEnabledChange={enabled => save({ autoRequestReceipts: enabled })}
>
<ReceiptsThreshold.Title />
<ReceiptsThreshold.Subtitle />
<ReceiptsThreshold.Field>
<ReceiptsThreshold.Currency />
<ReceiptsThreshold.Amount />
</ReceiptsThreshold.Field>
<ReceiptsThreshold.Toggle />
</ReceiptsThreshold.Root>

API reference

Root props

PropTypeDefaultDescription
titlerequiredstringThe row's label, e.g. "Auto-request Receipts". Also the default accessible name of the switch, and the stem of the input's.
subtitlerequiredstringThe line under the label explaining what the threshold does.
amountrequirednumberThe threshold, in whole currency units. Seeds the field and adopts every later change, so the row works controlled or uncontrolled.
enabledrequiredbooleanWhether the rule is on — the setting's own value. Same controlled/uncontrolled handling as amount. While off, the threshold field goes inert, but Toggle stays live so the rule can be turned back on. See States.
onAmountChange(amount: number) => voidCalled with the committed threshold — on blur or Enter, not per keystroke, and only when the value actually moved.
onEnabledChange(enabled: boolean) => voidCalled when the switch flips.
currencyrequiredstringISO-4217 code the threshold is denominated in. Drives both the code the Currency part prints and the sign in front of the amount — "$" for USD and CAD, "€" for EUR, "¥" for JPY. Required: a threshold is a sum of money, and there is no safe default for whose money it is.
disabledbooleanMake the whole row inert (e.g. while the setting saves). Clicking the switch is a no-op while set. Independent of enabled: the row freezes at whichever position the switch is already in. See States.
formatAmount(amount: number, currency: string) => stringOverride the resting display of the threshold. Defaults to the currency's own sign and decimals, formatted for en-US.
parseAmount(text: string) => number | nullOverride how a typed threshold is read back. Return null to reject the draft and revert the field. Defaults to stripping every non-numeric character — a pasted “$1,500.00” reads as 1500, and a typed minus sign is dropped.

Parts

State wrappers

Optional gates for copy or controls that only apply on one side of the switch.

PartDescription
ReceiptsThreshold.OnRendered only while the rule is on.
ReceiptsThreshold.OffRendered only while the rule is off.

Parts

PartDescription
ReceiptsThreshold.Title
asChild?
The row's label, from the Root's title.
ReceiptsThreshold.Subtitle
asChild?
The explanatory line under the label, from the Root's subtitle.
ReceiptsThreshold.Field
asChild?
Wrapper for the currency label + threshold input. Carries data-disabled="true" while the field is inert (the rule is off, or the row is disabled), so the field can dim itself without reading the hook.
ReceiptsThreshold.Currency
asChild?
The ISO-4217 code as text, for the field's leading label. Also sets data-currency.
ReceiptsThreshold.Amount
asChild?
The threshold input. Shows the formatted amount at rest and the bare number while focused; Enter or blur commits, Escape reverts. Disabled while the rule is off. Names itself “{title} amount” — pass your own aria-label to localize it.
ReceiptsThreshold.Toggle
asChild?
The on/off switch: a real role="switch" with aria-checked, plus data-state="on" | "off" for styling. Named for the Root's title, and disabled while the row is.

Hooks

PartDescription
useReceiptsThreshold()Hook returning { title, subtitle, amount, amountText, currency, enabled, disabled, amountDisabled, setEnabled, toggle, beginEdit, editAmount, commitAmount, cancelEdit }. `amountText` is the raw draft while the field is focused and the formatted amount otherwise. Throws when used outside <ReceiptsThreshold.Root>.

States

Two independent props put the row in three states. enabled is the setting itself — whether receipts get requested — and the user flips it. disabled is whether the row can be touched at all, and only the host sets it.

  • On (enabled, not disabled): Toggle carries data-state="on" with aria-checked="true", and Amount is editable.
  • Off (enabled={false}): the rule is switched off, so Amount renders disabled and Field carries data-disabled="true" — a rule that never fires has no threshold to set. Toggle stays live, since turning the rule back on is the only way out of this state.
  • Disabled (disabled): the whole row freezes at whichever setting it currently shows. Amount and Toggle both render disabled, Field carries data-disabled="true", and toggle() from the hook is a no-op — so onEnabledChange can't fire. Note that data-state still reports the setting: a disabled row with enabledshows an on switch that won't move.

ReceiptsThreshold.On / ReceiptsThreshold.Off gate on the setting only, not on disabled — copy that belongs to the on state stays rendered while the row is frozen.

Behavior notes

  • The field prints money at rest and swaps to the bare number on focus, so it's editable as typed rather than as printed. Enter or blur commits; Escape reverts the draft.
  • A draft that parses to nothing — or to the amount already set — reverts the field and calls nothing, so a stray focus/blur never looks like an edit.
  • The amount is signed from the currency, in its plain form rather than the disambiguated one — a CAD threshold reads “$30.00”, not “CA$30.00”, since the ISO code already sits beside the field. Decimals follow the currency too: cents for USD or EUR, none for JPY. A code Intldoesn't know falls back to a plain two-decimal number rather than throwing.
  • Controlled or uncontrolled, both: the row adopts every change to amount / enabled, and still moves on its own when the host only listens.
  • While the rule is off the threshold has nothing to apply to, so ReceiptsThreshold.Amount renders disabled and ReceiptsThreshold.Field carries data-disabled="true".
  • ReceiptsThreshold never fetches — scopesis empty. Where the setting lives, and what saving it costs, is the host's business.